Bilder Rotieren
This commit is contained in:
@@ -1,15 +1,16 @@
|
|||||||
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
||||||
|
import { Enums } from "@ibcornelsen/database/client";
|
||||||
import { addNotification, updateNotification } from "@ibcornelsen/ui";
|
import { addNotification, updateNotification } from "@ibcornelsen/ui";
|
||||||
import { client } from "src/trpc";
|
import { client } from "src/trpc";
|
||||||
|
|
||||||
export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude: GebaeudeClient) {
|
export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude_uid: string) {
|
||||||
if (images.length == 0) {
|
if (images.length == 0) {
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn Bilder hochgeladen werden konvertieren wir sie zu base64, das heißt, dass die base64 Eigenschaft bei diesen Bildern
|
// Wenn Bilder hochgeladen werden konvertieren wir sie zu base64, das heißt, dass die base64 Eigenschaft bei diesen Bildern
|
||||||
// existiert. Das müssen wir TypeScript nur wissen lassen, damit es uns in Ruhe lässt.
|
// existiert. Das müssen wir TypeScript nur wissen lassen, damit es uns in Ruhe lässt.
|
||||||
const imagesToUpload = images.filter(image => !image.uid) as unknown as { base64: string, kategorie: string, uid?: string }[];
|
const imagesToUpload = images.filter(image => !image.uid || image.update) as unknown as { base64: string, kategorie: string, uid?: string, update: boolean }[];
|
||||||
|
|
||||||
if (imagesToUpload.length == 0) {
|
if (imagesToUpload.length == 0) {
|
||||||
return images;
|
return images;
|
||||||
@@ -27,13 +28,21 @@ export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?:
|
|||||||
const image = imagesToUpload[i];
|
const image = imagesToUpload[i];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await client.v1.bilder.upload.mutate({
|
if (image.update) {
|
||||||
base64: image.base64,
|
await client.v1.bilder.update.mutate({
|
||||||
kategorie: image.kategorie,
|
uid: image.uid as string,
|
||||||
gebaeude_uid: gebaeude.uid
|
base64: image.base64,
|
||||||
})
|
kategorie: image.kategorie as Enums.BilderKategorie
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const response = await client.v1.bilder.upload.mutate({
|
||||||
|
base64: image.base64,
|
||||||
|
kategorie: image.kategorie as Enums.BilderKategorie,
|
||||||
|
gebaeude_uid
|
||||||
|
})
|
||||||
|
|
||||||
image.uid = response.uid
|
image.uid = response.uid
|
||||||
|
}
|
||||||
|
|
||||||
updateNotification(notification, {
|
updateNotification(notification, {
|
||||||
dismissable: true,
|
dismissable: true,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export async function verbrauchsausweisWohnenSpeichern(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
images = await bilderHochladen(images, gebaeude);
|
images = await bilderHochladen(images, gebaeude.uid);
|
||||||
|
|
||||||
return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
|
return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -57,7 +57,7 @@ export async function verbrauchsausweisWohnenSpeichern(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
images = await bilderHochladen(images, gebaeude);
|
images = await bilderHochladen(images, response.gebaeude_uid);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|||||||
@@ -270,7 +270,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<span>Verbrauch</span>
|
<span>Verbrauch *</span>
|
||||||
<input
|
<input
|
||||||
name="verbrauch_1"
|
name="verbrauch_1"
|
||||||
type="number"
|
type="number"
|
||||||
@@ -280,7 +280,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<span>Verbrauch</span>
|
<span>Verbrauch *</span>
|
||||||
<input
|
<input
|
||||||
name="verbrauch_2"
|
name="verbrauch_2"
|
||||||
type="number"
|
type="number"
|
||||||
@@ -290,7 +290,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<span>Verbrauch</span>
|
<span>Verbrauch *</span>
|
||||||
<input
|
<input
|
||||||
name="verbrauch_3"
|
name="verbrauch_3"
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { inferProcedureInput, inferProcedureOutput } from "@trpc/server";
|
|||||||
|
|
||||||
export type UploadedGebaeudeBild = inferProcedureOutput<
|
export type UploadedGebaeudeBild = inferProcedureOutput<
|
||||||
AppRouter["v1"]["verbrauchsausweisWohnen"]["get"]
|
AppRouter["v1"]["verbrauchsausweisWohnen"]["get"]
|
||||||
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string };
|
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string, update?: boolean };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import UploadImages from "./UploadImages.svelte";
|
import UploadImages from "./UploadImages.svelte";
|
||||||
import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client";
|
import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client";
|
||||||
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "./Ausweis/types";
|
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "./Ausweis/types";
|
||||||
|
import { RotateCounterClockwise, Trash } from "radix-svelte-icons";
|
||||||
|
|
||||||
export let images: UploadedGebaeudeBild[] = [];
|
export let images: UploadedGebaeudeBild[] = [];
|
||||||
export let max: number = 4;
|
export let max: number = 4;
|
||||||
@@ -10,8 +11,24 @@
|
|||||||
export let gebaeude: GebaeudeClient;
|
export let gebaeude: GebaeudeClient;
|
||||||
export let kategorie: Enums.BilderKategorie
|
export let kategorie: Enums.BilderKategorie
|
||||||
|
|
||||||
console.log(images);
|
async function rotateImage(image: UploadedGebaeudeBild): Promise<UploadedGebaeudeBild> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let img = new Image();
|
||||||
|
img.src = image.base64 ? image.base64 : `/bilder/${image.uid}.webp`;
|
||||||
|
img.onload = () => {
|
||||||
|
let canvas = document.createElement("canvas");
|
||||||
|
let ctx = canvas.getContext("2d");
|
||||||
|
canvas.width = img.height;
|
||||||
|
canvas.height = img.width;
|
||||||
|
ctx?.translate(img.height / 2, img.width / 2);
|
||||||
|
ctx?.rotate((-90 * Math.PI) / 180);
|
||||||
|
ctx?.drawImage(img, -img.width / 2, -img.height / 2);
|
||||||
|
image.base64 = canvas.toDataURL("image/webp");
|
||||||
|
image.update = true;
|
||||||
|
resolve(image)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
@@ -23,18 +40,31 @@
|
|||||||
<img
|
<img
|
||||||
src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
|
src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
|
||||||
alt={kategorie}
|
alt={kategorie}
|
||||||
class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
|
class="h-full max-h-96 w-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
|
||||||
/>
|
/>
|
||||||
<button
|
<div class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-row gap-2">
|
||||||
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] rounded-full w-[30px] h-[30px] p-2 bg-[rgba(0,0,0,0.4)]"
|
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
delete images[i];
|
delete images[i];
|
||||||
images = images.filter((x) => x);
|
images = images.filter((x) => x);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
R
|
<Trash size={20} color="#fff"></Trash>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
|
||||||
|
on:click={async () => {
|
||||||
|
let image = await rotateImage(images[i]);
|
||||||
|
images[i] = image;
|
||||||
|
images = images
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RotateCounterClockwise size={20} color="#fff"></RotateCounterClockwise>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types";
|
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types";
|
||||||
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern";
|
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern";
|
||||||
|
|
||||||
|
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
|
||||||
|
// wenn gebaeude_aufnahme_allgemein oder gebaeude_stammdaten nicht existiert...
|
||||||
export let ausweis: VerbrauchsausweisWohnenClient;
|
export let ausweis: VerbrauchsausweisWohnenClient;
|
||||||
export let user: BenutzerClient = {} as BenutzerClient;
|
export let user: BenutzerClient = {} as BenutzerClient;
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import AusweisLayout from "#layouts/AusweisLayout.astro";
|
import AusweisLayout from "#layouts/AusweisLayout.astro";
|
||||||
import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte";
|
import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte";
|
||||||
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
||||||
import { createCaller } from "#lib/caller";
|
import { createCaller } from "#lib/caller";
|
||||||
|
|
||||||
const uid = Astro.url.searchParams.get("uid");
|
const uid = Astro.url.searchParams.get("uid");
|
||||||
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient;
|
let ausweis: VerbrauchsausweisWohnenClient = {
|
||||||
|
gebaeude_aufnahme_allgemein: { gebaeude_stammdaten: {} },
|
||||||
|
} as VerbrauchsausweisWohnenClient;
|
||||||
|
|
||||||
const caller = createCaller(Astro);
|
const caller = createCaller(Astro);
|
||||||
|
|
||||||
if (uid) {
|
if (uid) {
|
||||||
ausweis = await caller.v1.verbrauchsausweisWohnen.get({
|
ausweis = await caller.v1.verbrauchsausweisWohnen.get({
|
||||||
uid: uid
|
uid: uid,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!ausweis) {
|
if (!ausweis) {
|
||||||
// Der Ausweis scheint nicht zu existieren.
|
// Der Ausweis scheint nicht zu existieren.
|
||||||
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
|
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
|
||||||
return Astro.redirect("/energieausweis-erstellen/verbrauchsausweis-wohnen");
|
return Astro.redirect(
|
||||||
|
"/energieausweis-erstellen/verbrauchsausweis-wohnen"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user