Bildupload - UI - Globaler Ausweis

This commit is contained in:
Moritz Utcke
2023-05-08 16:35:36 +04:00
parent 7e13a6da50
commit 2c2c69f2d3
21 changed files with 452 additions and 343 deletions

View File

@@ -15,6 +15,7 @@ services:
- 3000:3000
volumes:
- ./:/online-energieausweis
- ./node_modules/@ibcornelsen/ui:/online-energieausweis/node_modules/@ibcornelsen/ui
networks:
- postgres
db:

View File

@@ -5,6 +5,10 @@
import HelpLabel from "~/components/HelpLabel.svelte";
export let ausweis: Verbrauchsausweis;
import UploadImages from "../UploadImages.svelte";
let images: (File & { data: string })[] = [];
</script>
<div class="grid grid-cols-2 p-4 gap-4">
@@ -21,27 +25,20 @@
<hr class="trenner_form_100" />
</div>
<div class="form-group col-md-12">
<div class="row">
<input
type="file"
class="image_upload"
name="general[]"
/>
<div
class="form-group col-3 image_container"
>
<input
type="hidden"
id="uploaded_images"
name="uploaded_images"
value=""
/>
</div>
<canvas
id="image_canvas"
width="500"></canvas>
<div class="flex flex-col gap-4">
<UploadImages max={1} bind:images></UploadImages>
<div class="grid grid-cols-2 gap-2">
{#each images as image, i}
<div class="relative group">
<img src={image.data} alt={image.name} class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all">
<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)]" on:click={() => {
delete images[i]
images = images.filter(x => x);
}}>
R
</button>
</div>
{/each}
</div>
</div>
</div>

View File

@@ -1,3 +1,9 @@
<script lang="ts">
import UploadImages from "../UploadImages.svelte";
let images: (File & { data: string })[] = [];
</script>
<div class="grid grid-cols-2 gap-4">
<div class="rounded-lg border-4 p-4 bg-white">
<input type="file" class="image_upload" name="daemmung[]" multiple />
@@ -48,6 +54,21 @@
Energieausweis!<br />
<strong>Bitte laden Sie hier mind. 2 Bilder hoch:</strong>
</p>
<div class="image_container"></div>
<div class="flex flex-col gap-4">
<UploadImages max={4} bind:images></UploadImages>
<div class="grid grid-cols-2 gap-2">
{#each images as image, i}
<div class="relative group">
<img src={image.data} alt={image.name} class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all">
<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)]" on:click={() => {
delete images[i]
images = images.filter(x => x);
}}>
R
</button>
</div>
{/each}
</div>
</div>
</div>
</div>

View File

@@ -1,3 +1,9 @@
<script lang="ts">
import UploadImages from "../UploadImages.svelte";
let images: (File & { data: string })[] = [];
</script>
<div class="grid grid-cols-2 gap-4">
<div class="rounded-lg border-4 p-4 bg-white">
<input type="file" class="image_upload" name="fenster[]" multiple />
@@ -45,6 +51,21 @@
Energieausweis!<br />
<strong>Bitte laden Sie hier mind. 1 Bild hoch:</strong>
</p>
<div class="image_container"></div>
<div class="flex flex-col gap-4">
<UploadImages max={4} bind:images></UploadImages>
<div class="grid grid-cols-2 gap-2">
{#each images as image, i}
<div class="relative group">
<img src={image.data} alt={image.name} class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all">
<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)]" on:click={() => {
delete images[i]
images = images.filter(x => x);
}}>
R
</button>
</div>
{/each}
</div>
</div>
</div>
</div>

View File

@@ -1,3 +1,8 @@
<script lang="ts">
import UploadImages from "../UploadImages.svelte";
let images: (File & { data: string })[] = [];
</script>
<div class="grid grid-cols-2 gap-4">
<div class="rounded-lg border-4 p-4 bg-white">
<input type="file" class="image_upload" multiple />
@@ -52,6 +57,21 @@
Energieausweis!<br />
<strong>Bitte laden Sie hier mind. 1 Bild hoch:</strong>
</p>
<div class="image_container"></div>
<div class="flex flex-col gap-4">
<UploadImages max={4} bind:images></UploadImages>
<div class="grid grid-cols-2 gap-2">
{#each images as image, i}
<div class="relative group">
<img src={image.data} alt={image.name} class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all">
<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)]" on:click={() => {
delete images[i]
images = images.filter(x => x);
}}>
R
</button>
</div>
{/each}
</div>
</div>
</div>
</div>

View File

@@ -3,7 +3,7 @@
</script>
<div>
<button type="button" on:click={() => (showHelp = !showHelp)}
<button type="button" class="button" on:click={() => (showHelp = !showHelp)}
>Hilfe anfordern</button
>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
export let verbrauch: number;
export let primär: number;
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
export let ausweis: Verbrauchsausweis;
let maxPerformance = 250;
@@ -32,8 +33,18 @@
return centeredValue;
}
$: translation_1 = Math.min(100, verbrauch / maxPerformance * 100);
$: translation_2 = Math.min(100, primär / maxPerformance * 100);
let translation_1 = 0;
let translation_2 = 0;
$: {
(async () => {
const endEnergieVerbrauch = (await ausweis.end_energie_verbrauch);
const primaerEnergieVerbrauch = (await ausweis.primaer_energie_verbrauch);
translation_1 = Math.min(100, endEnergieVerbrauch / maxPerformance * 100)
translation_2 = Math.min(100, primaerEnergieVerbrauch / maxPerformance * 100)
})()
}
</script>
<div class="w-full rounded-lg border border-[#ffcc03] relative p-2">

View File

@@ -1,8 +1,9 @@
<script lang="ts">
import HelpLabel from "../HelpLabel.svelte";
import moment from "moment";
import moment, { Moment } from "moment";
import Label from "../Label.svelte";
import fuelList from "./fuelList";
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
let availableYears = [
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
@@ -22,42 +23,7 @@
"Dezember",
];
let month: number = 1;
let year: number = availableYears[0];
export let additionalHeating: boolean = false;
// Verbräuche aller drei Verbrauchsjahre der primären Energiequelle
export let energyConsumption: number[] = [0, 0, 0];
// Verbräuche aller drei Verbrauchsjahre der sekundären Energiequelle
export let additionalEnergyConsumption: number[] = [0, 0, 0];
export let climateFactors: number[];
export let conversionFactor: number;
export let calorificValueFactor: number;
$: conversionFactor =
fuelList.find((x) => {
return x.energietraeger == fuel && x.einheit == unit;
})?.umrechnungsfaktor || 1;
$: calorificValueFactor =
fuelList.find((x) => {
return x.energietraeger == fuel && x.einheit == unit;
})?.heizwertfaktor || 1;
async function fetchClimateFactors() {
const url = `/api/climate_factor?start=${month}.01.${year}&end=${month}.01.${
year + 2
}&accuracy=years&zip=21039`;
fetch(url)
.then((response) => response.json())
.then((result) => {
climateFactors = Object.values(result.data);
});
}
export let ausweis: Verbrauchsausweis;
const fuelMap: Record<string, string[]> = {};
for (const fuel of fuelList) {
@@ -65,12 +31,18 @@
fuelMap[fuel.energietraeger].push(fuel.einheit);
}
let fuel: string = fuelList[0].energietraeger;
let unit: string = fuelList[0].einheit;
let month: string = "01";
let year: string = "2018";
$: {
if (month && year) {
ausweis.energieverbrauch_zeitraum = moment(`${month}.01.${year}`);
}
}
</script>
<div class="w-full flex flex-col gap-4">
<div class="w-full grid grid-cols-[1fr_1fr_1fr_1fr_1fr] gap-6">
<div class="w-full grid grid-cols-[1fr,1fr,1fr,1fr,1fr] gap-6">
<div>
<HelpLabel title="zusätzliche Heizquelle">
Wenn eine zusätzliche Heizquelle vorhanden geben Sie hier drei
@@ -81,7 +53,7 @@
<input
type="checkbox"
class="IGzus1verbrauch1"
bind:checked={additionalHeating}
bind:checked={ausweis.zusaetzliche_heizquelle}
/>
</div>
@@ -113,7 +85,7 @@
<b>Koks:</b> Stark kohlenstoffhaltiger Brennstoff.<br /><br />
</HelpLabel>
<div>
<select name="energietraeger_1" required bind:value={fuel}>
<select name="energietraeger_1" required bind:value={ausweis.energietraeger_1}>
<option>Bitte auswählen</option>
{#each Object.keys(fuelMap) as fuel}
<option value={fuel}>{fuel}</option>
@@ -132,10 +104,10 @@
<select
name="energietraeger_einheit_heizquelle_1"
required
bind:value={unit}
bind:value={ausweis.energietraeger_einheit_heizquelle_1}
>
<option>Bitte auswählen</option>
{#each fuelMap[fuel] as unit}
{#each (fuelMap.hasOwnProperty(ausweis.energietraeger_1) ? fuelMap[ausweis.energietraeger_1] : []) as unit}
<option value={unit}>{unit}</option>
{/each}
</select>
@@ -147,11 +119,14 @@
<div>
<select
name="energietraeger_2"
disabled={!additionalHeating}
bind:value={ausweis.energietraeger_2}
disabled={!ausweis.zusaetzliche_heizquelle}
required
>
<option> Bitte auswählen</option>
<!-- TODO: Energieträger aus Datenbank holen -->
{#each Object.keys(fuelMap) as fuel}
<option value={fuel}>{fuel}</option>
{/each}
</select>
</div>
</div>
@@ -161,15 +136,14 @@
<div>
<select
name="energietraeger_einheit_heizquelle_2"
disabled={!additionalHeating}
disabled={!ausweis.zusaetzliche_heizquelle}
bind:value={ausweis.energietraeger_einheit_heizquelle_2}
required
>
<option>Bitte auswählen</option>
<option value="kWh"> kWh</option>
<option value="m³"></option>
<option value="l">l</option>
<option value="kg">kg</option>
<option value="SRm"> SRm</option>
{#each (fuelMap.hasOwnProperty(ausweis.energietraeger_2) ? fuelMap[ausweis.energietraeger_2] : []) as unit}
<option value={unit}>{unit}</option>
{/each}
</select>
</div>
</div>
@@ -183,7 +157,6 @@
name="energieverbrauch_zeitraum_monat"
class="rounded-tr-none rounded-br-none w-full m-0"
bind:value={month}
on:change={fetchClimateFactors}
required
>
<option>auswählen</option>
@@ -196,7 +169,6 @@
name="energieverbrauch_zeitraum_jahr"
class="rounded-tl-none rounded-bl-none w-full m-0"
bind:value={year}
on:change={fetchClimateFactors}
required
>
<option>auswählen</option>
@@ -209,7 +181,7 @@
<span>von</span>
<input
class="klima"
value={moment(`${month}.01.${year}`)
value={moment(ausweis.energieverbrauch_zeitraum)
.add("1", "year")
.format("MM.Y")}
readonly
@@ -219,7 +191,7 @@
<span>von</span>
<input
class="klima"
value={moment(`${month}.01.${year}`)
value={moment(ausweis.energieverbrauch_zeitraum)
.add("2", "years")
.format("MM.Y")}
readonly
@@ -231,7 +203,7 @@
<span>bis</span>
<input
class="form-control"
value={moment(`${month}.01.${year}`)
value={moment(ausweis.energieverbrauch_zeitraum)
.add("1", "year")
.format("MM.Y")}
readonly
@@ -241,7 +213,7 @@
<span>bis</span>
<input
class="form-control"
value={moment(`${month}.01.${year}`)
value={moment(ausweis.energieverbrauch_zeitraum)
.add("2", "years")
.format("MM.Y")}
readonly
@@ -251,7 +223,7 @@
<span>bis</span>
<input
class="form-control"
value={moment(`${month}.01.${year}`)
value={moment(ausweis.energieverbrauch_zeitraum)
.add("3", "years")
.format("MM.Y")}
readonly
@@ -264,7 +236,7 @@
<input
name="energieverbrauch_1_heizquelle_1"
type="number"
bind:value={energyConsumption[0]}
bind:value={ausweis.energieverbrauch_1_heizquelle_1}
required
/>
</div>
@@ -273,7 +245,7 @@
<input
name="energieverbrauch_2_heizquelle_1"
type="number"
bind:value={energyConsumption[1]}
bind:value={ausweis.energieverbrauch_2_heizquelle_1}
required
/>
</div>
@@ -282,7 +254,7 @@
<input
name="energieverbrauch_3_heizquelle_1"
type="number"
bind:value={energyConsumption[2]}
bind:value={ausweis.energieverbrauch_3_heizquelle_1}
required
/>
</div>
@@ -293,8 +265,8 @@
<input
name="energieverbrauch_1_heizquelle_2"
type="number"
bind:value={additionalEnergyConsumption[0]}
disabled={!additionalHeating}
bind:value={ausweis.energieverbrauch_1_heizquelle_2}
disabled={!ausweis.zusaetzliche_heizquelle}
/>
</div>
<div class="column">
@@ -302,8 +274,8 @@
<input
name="energieverbrauch_2_heizquelle_2"
type="number"
bind:value={additionalEnergyConsumption[1]}
disabled={!additionalHeating}
bind:value={ausweis.energieverbrauch_2_heizquelle_2}
disabled={!ausweis.zusaetzliche_heizquelle}
/>
</div>
<div class="column">
@@ -311,8 +283,8 @@
<input
name="energieverbrauch_3_heizquelle_2"
type="number"
bind:value={additionalEnergyConsumption[2]}
disabled={!additionalHeating}
bind:value={ausweis.energieverbrauch_3_heizquelle_2}
disabled={!ausweis.zusaetzliche_heizquelle}
/>
</div>
</div>

View File

@@ -0,0 +1,58 @@
<script lang="ts">
export let max: number = 2;
// Array of base64 encoded images read into the input.
export let images: (File & { data: string })[] = [];
function getAllImages(this: HTMLInputElement) {
const files = this.files || [];
if (images.length == max) {
this.value = "";
return;
}
for (let i = 0; i < files.length; i++) {
const file = files[i];
console.log(file.type);
if ((file.type !== "image/jpeg") && (file.type !== "image/png")) {
i--;
continue;
}
if (i == max) {
break;
}
const reader = new FileReader();
reader.onload = (ev) => {
if (reader.readyState != reader.DONE) {
return;
}
if (!reader.result) {
return;
}
images.push({ ...file, data: reader.result as string } as (File & { data: string }));
images = images;
if (i == (Math.min(files.length, max) - 1)) {
this.value = "";
}
}
reader.readAsDataURL(file);
}
}
</script>
{#if max > 1}
<input type="file" multiple on:change={getAllImages} />
{:else}
<input type="file" on:change={getAllImages} />
{/if}

View File

@@ -10,33 +10,14 @@
import FensterImage from "~/components/Ausweis/FensterImage.svelte";
import DaemmungImage from "~/components/Ausweis/DaemmungImage.svelte";
import AusweisPreviewContainer from "~/components/Ausweis/AusweisPreviewContainer.svelte";
import { calculateEnergyPerformanceScore } from "./energyPerformanceCalculation";
import ZipSearch from "../ZIPSearch.svelte";
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
import moment from "moment";
const ausweis = new Verbrauchsausweis();
let ausweis = new Verbrauchsausweis();
let conversionFactor: number = 0;
let calorificValueFactor: number = 0;
let energyConsumption = [0, 0, 0];
let additionalEnergyConsumption = [0, 0, 0];
let climateFactors = [0, 0, 0];
let area = 0;
let energyPerformance = 0;
$: {
energyPerformance = calculateEnergyPerformanceScore(
energyConsumption,
additionalEnergyConsumption,
ausweis.anteil_warmwasser_1,
climateFactors,
area * (ausweis.keller_beheizt ? 1.35 : 1.2),
conversionFactor,
calorificValueFactor
);
}
console.log(ausweis);
let needsRequirementCertificate: boolean = false;
@@ -56,11 +37,19 @@
ausweis.objekt_saniert = true;
ausweis.anzahl_einheiten = 1;
ausweis.ausstellgrund = "Vermietung";
energyConsumption = [15000, 14000, 16000];
area = 152;
ausweis.energieverbrauch_1_heizquelle_1 = 15000;
ausweis.energieverbrauch_2_heizquelle_1 = 14000;
ausweis.energieverbrauch_3_heizquelle_1 = 16000;
ausweis.wohnflaeche = 152;
ausweis.keller_beheizt = true;
ausweis.energietraeger_1 = "Erdgas H"
ausweis.energietraeger_einheit_heizquelle_1 = "kWh"
ausweis.warmwasser_enthalten = true;
ausweis.anteil_warmwasser_1 = 18;
ausweis.energieverbrauch_zeitraum = moment("12.01.2019");
ausweis.objekt_plz = "21039";
ausweis.objekt_ort = "Hamburg";
ausweis.objekt_strasse = "Curslacker Deich 170";
}
</script>
@@ -71,8 +60,7 @@
</div>
<PerformanceScore
verbrauch={energyPerformance}
primär={energyPerformance * 1.1}
bind:ausweis={ausweis}
/>
</div>
@@ -84,7 +72,7 @@
<a class="button" href="/speichern">Später Weitermachen</a>
<div class="flex gap-4">
<Hilfe />
<button on:click={automatischAusfüllen}
<button on:click={automatischAusfüllen} type="button" class="button"
>Automatisch Ausfüllen</button
>
</div>
@@ -151,6 +139,7 @@
required
data-msg-minlength="min. 5 Zeichen"
data-msg-maxlength="max. 40 Zeichen"
bind:value={ausweis.objekt_strasse}
/>
</div>
</div>
@@ -196,7 +185,7 @@
autocomplete="off"
data-rule-minlength="2"
data-msg-minlength="min. 2 Zeichen"
bind:value={area}
bind:value={ausweis.wohnflaeche}
/>
</div>
</div>
@@ -240,12 +229,7 @@
<div class="GRB">
<Verbrauch
bind:additionalHeating={ausweis.zusaetzliche_heizquelle}
bind:energyConsumption
bind:additionalEnergyConsumption
bind:climateFactors
bind:conversionFactor
bind:calorificValueFactor
bind:ausweis={ausweis}
/>
</div>
@@ -283,7 +267,7 @@
<input
name="IGwarmwasser"
maxlength="2"
type="text"
type="number"
bind:value={ausweis.anteil_warmwasser_1}
disabled={!ausweis.warmwasser_enthalten}
autocomplete="off"
@@ -299,9 +283,10 @@
<input
name="IGwarmwasser2"
maxlength="3"
type="text"
type="number"
autocomplete="off"
disabled={!ausweis.zusaetzliche_heizquelle}
bind:value={ausweis.anteil_warmwasser_2}
disabled={!ausweis.zusaetzliche_heizquelle || !ausweis.warmwasser_enthalten}
/>
</div>
@@ -319,6 +304,7 @@
><input
type="checkbox"
name="IGversorgungssysteme1"
bind:checked={ausweis.energiequelle_2_nutzung[0]}
value="Heizung"
/>Heizung</label
>
@@ -326,6 +312,7 @@
><input
type="checkbox"
name="IGversorgungssysteme2"
bind:checked={ausweis.energiequelle_2_nutzung[1]}
value="Warmwasser"
/>Warmwasser</label
>
@@ -333,6 +320,7 @@
><input
type="checkbox"
name="IGversorgungssysteme3"
bind:checked={ausweis.energiequelle_2_nutzung[2]}
value="Lüftung"
/>Lüftung</label
>
@@ -340,6 +328,7 @@
><input
type="checkbox"
name="IGversorgungssysteme4"
bind:checked={ausweis.energiequelle_2_nutzung[3]}
value="Kühlung"
/>Kühlung</label
>
@@ -509,6 +498,7 @@
><input
type="checkbox"
name="IGheizungsanlage1"
bind:checked={ausweis.versorgungssysteme[0]}
value="ZH"
/>Zentral/Etage</label
>
@@ -518,6 +508,7 @@
><input
type="checkbox"
name="IGheizungsanlage2"
bind:checked={ausweis.versorgungssysteme[1]}
value="EO"
/>Einzelöfen</label
>
@@ -527,6 +518,7 @@
><input
type="checkbox"
name="IGheizungsanlage3"
bind:checked={ausweis.versorgungssysteme[2]}
value="DH"
/>Durchlauferhitzer</label
>
@@ -536,6 +528,7 @@
><input
type="checkbox"
name="IGheizungsanlage4"
bind:checked={ausweis.versorgungssysteme[3]}
value="SK"
/>Standardkessel</label
>
@@ -545,6 +538,7 @@
><input
type="checkbox"
name="IGheizungsanlage5"
bind:checked={ausweis.versorgungssysteme[4]}
value="SSWW"
/>Solarsystem für Warmwasser</label
>
@@ -554,6 +548,7 @@
><input
type="checkbox"
name="IGheizungsanlage6"
bind:checked={ausweis.versorgungssysteme[5]}
value="WP"
/>Wärmepumpe</label
>
@@ -563,6 +558,7 @@
><input
type="checkbox"
name="IGheizungsanlage7"
bind:checked={ausweis.versorgungssysteme[6]}
value="NK"
/>Niedertemperaturkessel</label
>
@@ -572,6 +568,7 @@
><input
type="checkbox"
name="IGheizungsanlage8"
bind:checked={ausweis.versorgungssysteme[7]}
value="BWK"
/>Brennwertkessel</label
>
@@ -581,6 +578,7 @@
><input
type="checkbox"
name="IGheizungsanlage9"
bind:checked={ausweis.versorgungssysteme[8]}
value="WRGD"
/>Warmwasserrohre gedämmt</label
>
@@ -590,6 +588,7 @@
><input
type="checkbox"
name="IGheizungsanlage10"
bind:checked={ausweis.versorgungssysteme[9]}
value="HRGD"
/>Heizungsrohre gedämmt</label
>
@@ -599,6 +598,7 @@
><input
type="checkbox"
name="IGheizungsanlage11"
bind:checked={ausweis.versorgungssysteme[10]}
value="ZK"
/>Zirkulation</label
>
@@ -608,6 +608,7 @@
><input
type="checkbox"
name="IGheizungsanlage12"
bind:checked={ausweis.versorgungssysteme[11]}
value="RTR"
/>Raumtemperaturregler</label
>
@@ -637,6 +638,7 @@
><input
type="checkbox"
name="IGfensterdach1"
bind:checked={ausweis.fenster_dach[0]}
value="EG"
/>Einfachglas</label
>
@@ -646,6 +648,7 @@
><input
type="checkbox"
name="IGfensterdach2"
bind:checked={ausweis.fenster_dach[1]}
value="DF"
/>Doppelverglasung</label
>
@@ -655,6 +658,7 @@
><input
type="checkbox"
name="IGfensterdach3"
bind:checked={ausweis.fenster_dach[2]}
value="IVG"
/>Isolierverglasung</label
>
@@ -664,6 +668,7 @@
><input
type="checkbox"
name="IGfensterdach4"
bind:checked={ausweis.fenster_dach[3]}
value="PHF"
/>Dreifachverglasung</label
>
@@ -673,6 +678,7 @@
><input
type="checkbox"
name="IGfensterdach5"
bind:checked={ausweis.fenster_dach[4]}
value="FD"
/>Alle Fenster dicht</label
>
@@ -682,6 +688,7 @@
><input
type="checkbox"
name="IGfensterdach6"
bind:checked={ausweis.fenster_dach[5]}
value="FTUD"
/>Fenster teilweise undicht</label
>
@@ -691,6 +698,7 @@
><input
type="checkbox"
name="IGfensterdach7"
bind:checked={ausweis.fenster_dach[6]}
value="TD"
/>Alle Türen dicht</label
>
@@ -700,6 +708,7 @@
><input
type="checkbox"
name="IGfensterdach8"
bind:checked={ausweis.fenster_dach[7]}
value="TUD"
/>Türen teilweise undicht</label
>
@@ -709,6 +718,7 @@
><input
type="checkbox"
name="IGfensterdach9"
bind:checked={ausweis.fenster_dach[8]}
value="RKD"
/>Rollladenkästen gedämmt, luftdicht</label
>
@@ -743,6 +753,7 @@
><input
type="checkbox"
name="IGwaermedaemmung1"
bind:checked={ausweis.daemmung[0]}
value="AWD"
/>Außenwand gedämmt</label
>
@@ -752,6 +763,7 @@
><input
type="checkbox"
name="IGwaermedaemmung2"
bind:checked={ausweis.daemmung[1]}
value="KWD"
/>Kelleraußenwand gedämmt</label
>
@@ -761,6 +773,7 @@
><input
type="checkbox"
name="IGwaermedaemmung3"
bind:checked={ausweis.daemmung[2]}
value="KDD"
/>Kellerdecke gedämmt</label
>
@@ -770,6 +783,7 @@
><input
type="checkbox"
name="IGwaermedaemmung4"
bind:checked={ausweis.daemmung[3]}
value="DGD"
/>Dachgeschoss gedämmt</label
>
@@ -779,6 +793,7 @@
><input
type="checkbox"
name="IGwaermedaemmung5"
bind:checked={ausweis.daemmung[4]}
value="OGDDW"
/>Oberste Geschossdecke gedämmt</label
>
@@ -788,6 +803,7 @@
><input
type="checkbox"
name="IGwaermedaemmung6"
bind:checked={ausweis.daemmung[5]}
value="OGDD"
/>Oberste Geschossdecke min. 12cm gedämmt</label
>
@@ -810,7 +826,7 @@
<div class="flex flex-row justify-between">
<Hilfe />
<button formnovalidate>Weiter</button>
<button class="button">Weiter</button>
</div>
</fieldset>
</form>

View File

@@ -1,40 +0,0 @@
/**
*
* @param energyConsumption Ein Array aus allen Verbräuchen der drei Verbrauchsjahre für die primäre Energiequelle
* @param additionalEnergyConsumption Ein Array aus allen Verbräuchen der drei Verbrauchsjahre für die sekundäre Energiequelle
* @param waterHeatingPortion Der Anteil den Warmwasser am Energieverbrauch ausgemacht hat
* @param climateFactors Ein Array aus drei Klimafaktoren für die Verbrauchsjahre
* @param area Die Nutzfläche des Gebäudes
* @param conversionFactor Der Umrechnungsfaktor des Energieträgers
* @param calorificValueFactor Der Heizwertfaktor des Energieträgers
* @returns Den Performance Wert den das Gebäude erzielt hat.
*/
export function calculateEnergyPerformanceScore(
energyConsumption: number[],
additionalEnergyConsumption: number[],
waterHeatingPortion: number,
climateFactors: number[],
area: number,
conversionFactor: number,
calorificValueFactor: number
): number {
// Alle Werte müssen in kWh umgerechnet werden.
let energyConsumptionKWh = energyConsumption.map((x) => convertEnergyConsumptionToKWh(x, conversionFactor, calorificValueFactor))
let additionalEnergyConsumptionKWh = additionalEnergyConsumption.map((x) => convertEnergyConsumptionToKWh(x, conversionFactor, calorificValueFactor))
let heatingPortion = 1 - (waterHeatingPortion / 100);
return (heatingPortion * (energyConsumptionKWh[0] + additionalEnergyConsumptionKWh[0]) * climateFactors[0] +
(waterHeatingPortion / 100) * (energyConsumptionKWh[0] + additionalEnergyConsumptionKWh[0]) +
heatingPortion * (energyConsumptionKWh[1] + additionalEnergyConsumptionKWh[1]) * climateFactors[1] +
(waterHeatingPortion / 100) * (energyConsumptionKWh[1] + additionalEnergyConsumptionKWh[1]) +
heatingPortion * (energyConsumptionKWh[2] + additionalEnergyConsumptionKWh[2]) * climateFactors[2] +
(waterHeatingPortion / 100) * (energyConsumptionKWh[2] + additionalEnergyConsumptionKWh[2])) /
3 /
(area || 1);
}
function convertEnergyConsumptionToKWh(consumption: number, conversionFactor: number, calorificValueFactor: number): number {
return (consumption * conversionFactor) / calorificValueFactor;
}

View File

@@ -101,7 +101,7 @@ const schema = JSON.stringify({
min-height: 100vh;
}
button, .button, button[type="button"] {
.button {
@apply px-8 py-2 bg-secondary rounded-lg text-white font-medium hover:shadow-lg transition-all hover:underline active:bg-blue-900 text-center;
color: #fff !important;
}

View File

@@ -1,5 +1,9 @@
import { Moment } from "moment";
import { getKlimafaktorenClient } from "../Klimafaktoren";
import { getHeizwertfaktorClient } from "../server/Heizwertfaktor";
import moment from "moment";
import fuelList from "~/components/Ausweis/fuelList";
import { BitChecker } from "../BitChecker";
export enum AusweisType {
VERBRAUCHSAUSWEIS,
@@ -15,40 +19,13 @@ export enum Lueftungskonzept {
}
export type Ausweisart = "VA" | "BA" | "VANW";
export type Ausstellgrund = "Vermietung" | "Neubau" | "Verkauf" | "Modernisierung" | "Sonstiges";
export type Ausstellgrund =
| "Vermietung"
| "Neubau"
| "Verkauf"
| "Modernisierung"
| "Sonstiges";
class BitChecker {
public value: number;
constructor(number: number) {
this.value = number;
}
public isSet(bitIndex: number): boolean {
const bitMask = 1 << bitIndex;
return (this.value & bitMask) !== 0;
}
public set(index: number): number {
if (!this.isSet(index)) {
this.value += 2 ** index;
}
return this.value;
}
public off(index: number) {
if (this.isSet(index)) {
this.value -= 2 ** index;
}
return this.value;
}
public valueOf(): number {
return this.value;
}
}
export class Verbrauchsausweis {
@@ -70,7 +47,7 @@ export class Verbrauchsausweis {
public erstellungsdatum: Date = new Date();
public ausstellgrund: Ausstellgrund = "Vermietung";
public energieverbrauch_zeitraum: Date = new Date();
public energieverbrauch_zeitraum: Moment = moment();
public energieverbrauch_1_heizquelle_1: number = 0;
public energieverbrauch_2_heizquelle_1: number = 0;
public energieverbrauch_3_heizquelle_1: number = 0;
@@ -98,11 +75,13 @@ export class Verbrauchsausweis {
public leerstand: number = 0;
public images: string[] = [];
public versorgungssysteme: number = 0;
public fenster_dach: number = 0;
public energiequelle_2_nutzung: BitChecker = new BitChecker(0);
public daemmung: number = 0;
public energetische_nutzfläche: number = 0;
public versorgungssysteme: boolean[] = BitChecker(0);
public fenster_dach: boolean[] = BitChecker(0);
public energiequelle_2_nutzung: boolean[] = BitChecker(0);
public daemmung: boolean[] = BitChecker(0);
public get energetische_nutzfläche(): number {
return this.wohnflaeche * (this.keller_beheizt ? 1.35 : 1.2);
};
/**
* Bedarfsausweis spezifische Eigenschaften
@@ -181,109 +160,98 @@ export class Verbrauchsausweis {
const json = JSON.parse(text.toString());
return json;
} catch(e) {
} catch (e) {
return null;
}
}
public async endEnergieVerbrauch(): Promise<number> {
const date = this.energieverbrauch_zeitraum
const klimafaktoren = await getKlimafaktorenClient(
date,
this.objekt_plz
);
public get primaer_energie_verbrauch(): Promise<number> {
return (async () => {
const Endenergieverbrauch = await this.end_energie_verbrauch;
// Endenergieverbrauch
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
let [umrechnungsfaktor, primaerfaktor, heizwertfaktor, coe] = [
1, 1, 1, 1,
];
let [umrechnungsfaktor_1, primaerfaktor_1, heizwertfaktor_1, coe_1] = [
1, 1, 1, 1,
];
if (this.energietraeger_1 && this.energietraeger_einheit_heizquelle_1) {
[umrechnungsfaktor, primaerfaktor, heizwertfaktor, coe] =
await getHeizwertfaktorClient(
this.energietraeger_1,
this.energietraeger_einheit_heizquelle_1
);
}
const brennstoff_1 = getHeizwertfaktorClient(this.energietraeger_1, this.energietraeger_einheit_heizquelle_1);
if (this.energietraeger_2 && this.energietraeger_einheit_heizquelle_2) {
[umrechnungsfaktor_1, primaerfaktor_1, heizwertfaktor_1, coe_1] =
await getHeizwertfaktorClient(
this.energietraeger_2,
this.energietraeger_einheit_heizquelle_2
);
}
return Endenergieverbrauch * brennstoff_1.primärenergiefaktor;
})();
}
let verbrauch_1_kwh =
(this.energieverbrauch_1_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
let verbrauch_2_kwh =
(this.energieverbrauch_2_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
let verbrauch_3_kwh =
(this.energieverbrauch_3_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
let verbrauch_4_kwh =
(this.energieverbrauch_1_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
let verbrauch_5_kwh =
(this.energieverbrauch_2_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
let verbrauch_6_kwh =
(this.energieverbrauch_3_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
public get end_energie_verbrauch(): Promise<number> {
return (async () => {
const date = this.energieverbrauch_zeitraum;
const klimafaktoren = await getKlimafaktorenClient(
date,
this.objekt_plz
);
let warmwasserZuschlag = 0;
let leerstandsZuschlag = 0;
let kuehlungsZuschlag = 0;
if (this.anteil_warmwasser_1 == 0) {
warmwasserZuschlag = 20 * this.energetische_nutzfläche * 3;
}
// Endenergieverbrauch
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
let brennstoff_1 = getHeizwertfaktorClient(this.energietraeger_1, this.energietraeger_einheit_heizquelle_1);
let brennstoff_2 = getHeizwertfaktorClient(this.energietraeger_2, this.energietraeger_einheit_heizquelle_2);
if (this.leerstand > 0) {
let durchschnittsKlimafaktor =
klimafaktoren.reduce((a, b) => a + b, 0) / 3;
let verbrauch_1_kwh =
(this.energieverbrauch_1_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_2_kwh =
(this.energieverbrauch_2_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_3_kwh =
(this.energieverbrauch_3_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_4_kwh =
(this.energieverbrauch_1_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
let verbrauch_5_kwh =
(this.energieverbrauch_2_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
let verbrauch_6_kwh =
(this.energieverbrauch_3_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
leerstandsZuschlag =
((verbrauch_1_kwh +
verbrauch_2_kwh +
verbrauch_3_kwh +
verbrauch_4_kwh +
verbrauch_5_kwh +
verbrauch_6_kwh) *
(this.leerstand / 100)) /
durchschnittsKlimafaktor;
}
let warmwasserZuschlag = 0;
let leerstandsZuschlag = 0;
let kuehlungsZuschlag = 0;
if (this.anteil_warmwasser_1 == 0) {
warmwasserZuschlag = 20 * this.energetische_nutzfläche * 3;
}
if (this.energiequelle_2_nutzung.isSet(3)) {
kuehlungsZuschlag = 6 * this.energetische_nutzfläche * 3;
}
if (this.leerstand > 0) {
let durchschnittsKlimafaktor =
klimafaktoren.reduce((a, b) => a + b, 0) / 3;
let anteil_heizung = 1 - this.anteil_warmwasser_1 / 100;
let anteil_warmwasser = this.anteil_warmwasser_1 / 100;
let Energieverbrauchskennwert =
(anteil_heizung *
(verbrauch_1_kwh + verbrauch_4_kwh) *
klimafaktoren[0] +
anteil_warmwasser * (verbrauch_1_kwh + verbrauch_4_kwh) +
anteil_heizung *
(verbrauch_2_kwh + verbrauch_5_kwh) *
klimafaktoren[1] +
anteil_warmwasser * (verbrauch_2_kwh + verbrauch_5_kwh) +
anteil_heizung *
(verbrauch_3_kwh + verbrauch_6_kwh) *
klimafaktoren[2] +
anteil_warmwasser * (verbrauch_3_kwh + verbrauch_6_kwh) +
warmwasserZuschlag +
leerstandsZuschlag +
kuehlungsZuschlag) /
3 /
this.energetische_nutzfläche;
leerstandsZuschlag =
((verbrauch_1_kwh +
verbrauch_2_kwh +
verbrauch_3_kwh +
verbrauch_4_kwh +
verbrauch_5_kwh +
verbrauch_6_kwh) *
(this.leerstand / 100)) /
durchschnittsKlimafaktor;
}
return Energieverbrauchskennwert;
if (this.energiequelle_2_nutzung[3]) {
kuehlungsZuschlag = 6 * this.energetische_nutzfläche * 3;
}
let anteil_heizung = 1 - this.anteil_warmwasser_1 / 100;
let anteil_warmwasser = this.anteil_warmwasser_1 / 100;
let Energieverbrauchskennwert =
(anteil_heizung *
(verbrauch_1_kwh + verbrauch_4_kwh) *
klimafaktoren[0] +
anteil_warmwasser * (verbrauch_1_kwh + verbrauch_4_kwh) +
anteil_heizung *
(verbrauch_2_kwh + verbrauch_5_kwh) *
klimafaktoren[1] +
anteil_warmwasser * (verbrauch_2_kwh + verbrauch_5_kwh) +
anteil_heizung *
(verbrauch_3_kwh + verbrauch_6_kwh) *
klimafaktoren[2] +
anteil_warmwasser * (verbrauch_3_kwh + verbrauch_6_kwh) +
warmwasserZuschlag +
leerstandsZuschlag +
kuehlungsZuschlag) /
3 /
this.energetische_nutzfläche;
return Energieverbrauchskennwert;
})();
}
}

18
src/lib/BitChecker.ts Normal file
View File

@@ -0,0 +1,18 @@
export function BitChecker(initial: number = 0, length: number = 32): boolean[] {
const target: boolean[] = new Array(length).fill(false).map((x, i) => {
return (initial & (1 << i)) !== 0 ? true : false
});
return new Proxy(target, {
get(target, property) {
if (property == "value") {
return target.reduce((a, b, i) => a + (b ? 2 ** i : 0), 0);
}
return Reflect.get(target, property);
},
set(target, property, value) {
return Reflect.set(target, property, value);
}
})
}

View File

@@ -1,11 +1,19 @@
import moment from "moment";
import { memoize } from "./Memoization";
export const getKlimafaktorenClient = memoize<Promise<number[]>>(async (date: Date, zip: string) => {
const response = await fetch(`/api/klimafaktoren?date=${moment(date).format("YYYY-MM-DD")}&zip=${zip}`);
export const getKlimafaktorenClient = memoize<Promise<[number, number, number]>>(async (date: Date, zip: string) => {
if (!zip || !date) {
return [0, 0, 0];
}
const response = await fetch(`/api/klimafaktor?date=${moment(date).format("YYYY-MM-DD")}&accuracy=years&zip=${zip}`);
const json = await response.json();
return json;
if (!json.success) {
return [0, 0, 0];
}
return Object.values(json.data) as [number, number, number];
});
export const getKlimafaktorenServer = memoize(async (date: Date, zip: string) => {

View File

@@ -1,5 +1,23 @@
import { memoize } from "../Memoization";
import fuelList from "~/components/Ausweis/fuelList";
export const getHeizwertfaktorClient = memoize<Promise<[number, number, number, number]>>(async function() {
return [1,1,1,1];
})
export const getHeizwertfaktorClient = function(energietraeger: string, einheit: string): {
coe: number,
energietraeger: string,
einheit: string,
umrechnungsfaktor: number,
primärenergiefaktor: number
} {
for (const fuel of fuelList) {
if (fuel.energietraeger == energietraeger && fuel.einheit == einheit) {
return fuel;
}
}
return {
coe: 0,
energietraeger: "",
einheit: "",
umrechnungsfaktor: 0,
primärenergiefaktor: 0
};
}

View File

@@ -0,0 +1,16 @@
import type { APIRoute } from "astro";
import { success } from "src/lib/APIResponse";
/**
* Erstellt einen Verbrauchsausweis anhand der gegebenen Daten und trägt ihn in die Datenbank ein.
* @param param0
* @returns
*/
export const post: APIRoute = async ({ request }) => {
const body = await request.json();
return success({});
}

View File

@@ -4,10 +4,15 @@ import { ActionFailedError, InvalidDataError, MissingPropertyError, error, succe
import { getClimateFactor } from "src/lib/Klimafaktoren/getClimateFactor";
export const get: APIRoute = async function({ request }) {
const body = Object.fromEntries(new URLSearchParams(request.url.split("?")[1]))
let body;
try {
body = Object.fromEntries(new URLSearchParams(request.url.split("?")[1]))
} catch(e) {
return error(["Failed to parse URL"]);
}
if (!body.start || !body.end) {
return MissingPropertyError(["start", "end"]);
if (!body.date) {
return MissingPropertyError(["date"]);
}
let accuracy = body.accuracy || "months";
@@ -20,8 +25,8 @@ export const get: APIRoute = async function({ request }) {
return error(["Invalid ZIP Code, must be 4 or 5 characters long."])
}
let start = moment(body.start);
let end = moment(body.end);
let start = moment(body.date);
let end = moment(body.date).add("2", "years");
if (!start.isValid()) {
return error(["Invalid start date given."]);

View File

@@ -1,5 +1,5 @@
---
import BoxWithHeading from '../components/BoxWithHeading.astro';
import {BoxWithHeading} from '@ibcornelsen/ui';
import Widget from '../components/Widget.svelte';
import Layout from '../layouts/Layout.astro';
---

View File

@@ -3,7 +3,7 @@ layout: ../layouts/Layout.astro
title: Welcher Energieausweis?
---
import BoxWithHeading from "~/components/BoxWithHeading.astro";
import { BoxWithHeading } from "@ibcornelsen/ui";
import Widget from "~/components/Widget.svelte";
# Welcher Energieausweis ist der richtige?
@@ -54,14 +54,14 @@ eingehalten werden müssen.
---
<BoxWithHeading heading="Folgende Dokumente und Informationen werden für den Bedarfsausweis benötigt:">
- Grundriss- und Ansichtspläne sowie Baubeschreibung.
- Die wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,
Kellerdecke bzw. Boden werden aus den Plänen ermittelt.
- Auch das Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und die
verschiedenen Nutzungszonen werden aus den Plänen erhoben.
- Die verwendete Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper,
Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der Baubeschreibung oder
aus den Angaben des Bauherren herangezogen.
- Grundriss- und Ansichtspläne sowie Baubeschreibung. - Die
wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,
Kellerdecke bzw. Boden werden aus den Plänen ermittelt. - Auch das
Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und die
verschiedenen Nutzungszonen werden aus den Plänen erhoben. - Die verwendete
Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper,
Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der
Baubeschreibung oder aus den Angaben des Bauherren herangezogen.
</BoxWithHeading>
Sollten Sie den Bedarfsausweis nur für Vermietung und Verkauf benötigen, dann
@@ -105,20 +105,19 @@ Anforderungen für Nichtwohngebäude eingehalten werden müssen.
---
<BoxWithHeading heading="Folgende Dokumente und Informationen werden für den Bedarfsausweis benötigt:">
- Grundriss- und Ansichtspläne sowie Baubeschreibung.
- Die wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,
Kellerdecke bzw. Boden werden aus den Plänen ermittelt.
- Auch das Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und
die verschiedenen Nutzungszonen werden aus den Plänen erhoben.
- Die verwendete Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper,
Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der
Baubeschreibung oder aus den Angaben des Bauherren herangezogen.
- Anlagentechnik zu Kühlung und Lüftung der entsprechenden Nutzungszonen müssen
definiert sein.
- Die verwendete Beleuchtung der verschiedenen Nutzungszonen wird ebenfalls
herangezogen
- Grundriss- und Ansichtspläne sowie Baubeschreibung. - Die
wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,
Kellerdecke bzw. Boden werden aus den Plänen ermittelt. - Auch das
Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und die
verschiedenen Nutzungszonen werden aus den Plänen erhoben. - Die verwendete
Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper,
Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der
Baubeschreibung oder aus den Angaben des Bauherren herangezogen. -
Anlagentechnik zu Kühlung und Lüftung der entsprechenden Nutzungszonen
müssen definiert sein. - Die verwendete Beleuchtung der verschiedenen
Nutzungszonen wird ebenfalls herangezogen
</BoxWithHeading>
Sollten Sie den Bedarfsausweis nur für Vermietung und Verkauf benötigen, dann
können Sie den Ausweis bei uns auch online erstellen lassen. Die Eingabedaten
werden dann nach einem vereinfachten Verfahren erhoben.
werden dann nach einem vereinfachten Verfahren erhoben.

View File

@@ -1,6 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}","./node_modules/@ibcornelsen/ui/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
colors: {