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 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>
<canvas
id="image_canvas"
width="500"></canvas>
{/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;
console.log(ausweis);
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
);
}
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,14 +160,24 @@ export class Verbrauchsausweis {
const json = JSON.parse(text.toString());
return json;
} catch (e) {
return null;
}
}
public async endEnergieVerbrauch(): Promise<number> {
const date = this.energieverbrauch_zeitraum
public get primaer_energie_verbrauch(): Promise<number> {
return (async () => {
const Endenergieverbrauch = await this.end_energie_verbrauch;
const brennstoff_1 = getHeizwertfaktorClient(this.energietraeger_1, this.energietraeger_einheit_heizquelle_1);
return Endenergieverbrauch * brennstoff_1.primärenergiefaktor;
})();
}
public get end_energie_verbrauch(): Promise<number> {
return (async () => {
const date = this.energieverbrauch_zeitraum;
const klimafaktoren = await getKlimafaktorenClient(
date,
this.objekt_plz
@@ -196,46 +185,21 @@ export class Verbrauchsausweis {
// 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
);
}
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
);
}
let brennstoff_1 = getHeizwertfaktorClient(this.energietraeger_1, this.energietraeger_einheit_heizquelle_1);
let brennstoff_2 = getHeizwertfaktorClient(this.energietraeger_2, this.energietraeger_einheit_heizquelle_2);
let verbrauch_1_kwh =
(this.energieverbrauch_1_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
(this.energieverbrauch_1_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_2_kwh =
(this.energieverbrauch_2_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
(this.energieverbrauch_2_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_3_kwh =
(this.energieverbrauch_3_heizquelle_1 * umrechnungsfaktor) /
heizwertfaktor;
(this.energieverbrauch_3_heizquelle_1 * brennstoff_1.umrechnungsfaktor)
let verbrauch_4_kwh =
(this.energieverbrauch_1_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
(this.energieverbrauch_1_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
let verbrauch_5_kwh =
(this.energieverbrauch_2_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
(this.energieverbrauch_2_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
let verbrauch_6_kwh =
(this.energieverbrauch_3_heizquelle_2 * umrechnungsfaktor_1) /
heizwertfaktor_1;
(this.energieverbrauch_3_heizquelle_2 * brennstoff_2.umrechnungsfaktor)
let warmwasserZuschlag = 0;
let leerstandsZuschlag = 0;
@@ -259,12 +223,14 @@ export class Verbrauchsausweis {
durchschnittsKlimafaktor;
}
if (this.energiequelle_2_nutzung.isSet(3)) {
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) *
@@ -284,6 +250,8 @@ export class Verbrauchsausweis {
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,18 +105,17 @@ 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,
- 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
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

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: {