diff --git a/.DS_Store b/.DS_Store
index 4284e7a..b51b8ab 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/node_modules/.DS_Store b/node_modules/.DS_Store
index d040afd..bcda883 100644
Binary files a/node_modules/.DS_Store and b/node_modules/.DS_Store differ
diff --git a/node_modules/math-intrinsics/.DS_Store b/node_modules/math-intrinsics/.DS_Store
index 6f3a30f..54dec05 100644
Binary files a/node_modules/math-intrinsics/.DS_Store and b/node_modules/math-intrinsics/.DS_Store differ
diff --git a/node_modules/object-inspect/.DS_Store b/node_modules/object-inspect/.DS_Store
index b90bf74..9412063 100644
Binary files a/node_modules/object-inspect/.DS_Store and b/node_modules/object-inspect/.DS_Store differ
diff --git a/node_modules/qs/.DS_Store b/node_modules/qs/.DS_Store
index ff34709..1dd3e6d 100644
Binary files a/node_modules/qs/.DS_Store and b/node_modules/qs/.DS_Store differ
diff --git a/node_modules/side-channel-list/.DS_Store b/node_modules/side-channel-list/.DS_Store
index 2936618..09d00f9 100644
Binary files a/node_modules/side-channel-list/.DS_Store and b/node_modules/side-channel-list/.DS_Store differ
diff --git a/node_modules/side-channel-map/.DS_Store b/node_modules/side-channel-map/.DS_Store
index 30ef9c5..15e5e2e 100644
Binary files a/node_modules/side-channel-map/.DS_Store and b/node_modules/side-channel-map/.DS_Store differ
diff --git a/node_modules/side-channel-weakmap/.DS_Store b/node_modules/side-channel-weakmap/.DS_Store
index 0a9be26..138a8bf 100644
Binary files a/node_modules/side-channel-weakmap/.DS_Store and b/node_modules/side-channel-weakmap/.DS_Store differ
diff --git a/node_modules/side-channel/.DS_Store b/node_modules/side-channel/.DS_Store
index 56110b1..4c8e299 100644
Binary files a/node_modules/side-channel/.DS_Store and b/node_modules/side-channel/.DS_Store differ
diff --git a/public/main.v2.js b/public/main.v2.js
index 625ca4d..e3a63d6 100644
--- a/public/main.v2.js
+++ b/public/main.v2.js
@@ -2246,9 +2246,9 @@ async function exportPDF(){
container.style.width = '1200px';
container.style.background = '#fff';
container.style.padding = '20px';
- container.style.fontFamily = 'Arial, sans-serif';
+ container.style.fontFamily = '-apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
container.style.fontSize = '10px';
- container.style.color = '#1a1a1a';
+ container.style.color = 'var(--text)';
document.body.appendChild(container);
const grouped = peopleByRole(w);
@@ -2283,16 +2283,16 @@ async function exportPDF(){
cover.style.flexDirection = 'column';
cover.style.justifyContent = 'center';
cover.style.textAlign = 'center';
- cover.style.fontFamily = 'Arial, sans-serif';
+ cover.style.fontFamily = '-apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
const logoHtml = logoDataUrl
? `

`
: `⚡
`;
cover.innerHTML = `
${logoHtml}
- Projektübersicht ${DEPARTMENTS[currentDepartment].label}
- ${esc(w.label)}
- ${w.date ? `Datum: ${esc(formatWeekDate(w.date))}
` : ''}
- Erstellt am ${new Date().toLocaleDateString('de-DE')}
+ Projektübersicht ${DEPARTMENTS[currentDepartment].label}
+ ${esc(w.label)}
+ ${w.date ? `Datum: ${esc(formatWeekDate(w.date))}
` : ''}
+ Erstellt am ${new Date().toLocaleDateString('de-DE')}
`;
container.appendChild(cover);
@@ -2313,11 +2313,14 @@ async function exportPDF(){
const landscapePageW = pageHeightPx - marginPx * 2;
const landscapePageH = pageWidthPx - marginPx * 2;
+ // JPEG quality (0.1 - 1.0) - lower = smaller file
+ const JPEG_QUALITY = 1;
+
async function addImageToLandscapePage(canvas){
const imgW = landscapePageW;
const imgH = (canvas.height * imgW) / canvas.width;
pdf.addPage([pageHeightPx, pageWidthPx], 'landscape');
- pdf.addImage(canvas.toDataURL('image/png'), 'PNG', marginPx, marginPx, imgW, imgH);
+ pdf.addImage(canvas.toDataURL('image/jpeg', JPEG_QUALITY), 'JPEG', marginPx, marginPx, imgW, imgH);
}
async function drawBlockOnLandscapePage(blockHTML){
@@ -2328,7 +2331,7 @@ async function exportPDF(){
wrapper.style.background = '#fff';
wrapper.innerHTML = blockHTML;
container.appendChild(wrapper);
- const canvas = await html2canvas(wrapper, { scale: 2, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
+ const canvas = await html2canvas(wrapper, { scale: 1.5, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
const imgH = (canvas.height * landscapePageW) / canvas.width;
wrapper.remove();
return { canvas, imgH };
@@ -2336,12 +2339,12 @@ async function exportPDF(){
try {
// Deckblatt (Hochkant) zeichnen
- const coverCanvas = await html2canvas(cover, { scale: 2, useCORS: true, backgroundColor: '#ffffff', width: 595, height: 842 });
+ const coverCanvas = await html2canvas(cover, { scale: 1.5, useCORS: true, backgroundColor: '#ffffff', width: 595, height: 842 });
if(pdf.internal.getNumberOfPages() > 0) pdf.addPage();
const coverW = pageWidthPx - marginPx * 2;
const coverH = (coverCanvas.height * coverW) / coverCanvas.width;
const coverX = marginPx + (coverW - (coverCanvas.width * coverW / coverCanvas.width)) / 2;
- pdf.addImage(coverCanvas.toDataURL('image/png'), 'PNG', marginPx, marginPx + ((pageHeightPx - marginPx * 2 - coverH) / 2), coverW, coverH);
+ pdf.addImage(coverCanvas.toDataURL('image/jpeg', JPEG_QUALITY), 'JPEG', marginPx, marginPx + ((pageHeightPx - marginPx * 2 - coverH) / 2), coverW, coverH);
const headerRows = buildPdfTableHeaderRows(allPeople);
@@ -2356,7 +2359,7 @@ async function exportPDF(){
// Hilfsfunktion: misst Höhe einer Tabelle mit gegebenen Zeilen
async function measureBlockWithRows(titleRow, bodyRows){
const wrapper = renderSinglePdfBlock(container, headerRows, titleRow, bodyRows);
- const canvas = await html2canvas(wrapper, { scale: 2, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
+ const canvas = await html2canvas(wrapper, { scale: 1.5, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
const imgH = (canvas.height * landscapePageW) / canvas.width;
wrapper.remove();
return { canvas, imgH };
@@ -2375,7 +2378,10 @@ async function exportPDF(){
for(let i = 0; i < projects.length; i++){
const rowHTML = buildPdfProjectRow(projects[i], allPeople);
- const testRows = currentRows + rowHTML;
+ // Alternating row background to match project board design
+ const rowBg = i % 2 === 0 ? ' style="background:#fafafc"' : '';
+ const rowHTMLWithBg = rowHTML.replace('', `
`);
+ const testRows = currentRows + rowHTMLWithBg;
const { imgH: testImgH } = await measureBlockWithRows(titleRow, testRows);
// Wenn die aktuelle Seite überschritten würde und wir bereits Zeilen haben,
@@ -2396,7 +2402,7 @@ async function exportPDF(){
// Projektboard-Blöcke zeichnen
for(const block of groupBlocks){
const wrapper = renderSinglePdfBlock(container, headerRows, block.titleRow, block.bodyRows);
- const canvas = await html2canvas(wrapper, { scale: 2, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
+ const canvas = await html2canvas(wrapper, { scale: 1.5, useCORS: true, backgroundColor: '#ffffff', width: 1123 });
await addImageToLandscapePage(canvas);
wrapper.remove();
}
@@ -2424,25 +2430,36 @@ async function exportPDF(){
// buildPdfTableHeaderRows: baut die Kopfzeilen der Projektübersichts-Tabelle als HTML-String (zwei Zeilen).
function buildPdfTableHeaderRows(allPeople){
- let h1 = `
| Pr.-Nr. | Bezeichnung | Status | `;
+ let h1 = `
| Pr.-Nr. | Bezeichnung | Status | `;
const grouped = peopleByRole(currentWeek());
ROLES.forEach(r => {
const count = Math.max(1, grouped[r].length);
- h1 += ``;
+ // Rollen-spezifische Hintergrundfarben aus dem Projektboard
+ let roleBg;
+ if(r === 'Planung') roleBg = 'rgb(212, 245, 224)';
+ else if(r === 'Projektleitung') roleBg = 'rgb(255, 219, 219)';
+ else if(r === 'Bauüberwachung') roleBg = 'rgb(203, 238, 255)';
+ else roleBg = '#f0f0f2';
+ h1 += ``;
});
- h1 += `Leistungsphasen (%) |
`;
+ h1 += `Leistungsphasen (%) | `;
let h2 = ``;
ROLES.forEach(r => {
+ let roleBg;
+ if(r === 'Planung') roleBg = 'rgb(212, 245, 224)';
+ else if(r === 'Projektleitung') roleBg = 'rgb(255, 219, 219)';
+ else if(r === 'Bauüberwachung') roleBg = 'rgb(203, 238, 255)';
+ else roleBg = '#fafafc';
if(grouped[r].length === 0){
- h2 += `| – | `;
+ h2 += `– | `;
} else {
grouped[r].forEach(entry => {
- h2 += `${esc(entry.person.name)} | `;
+ h2 += `${esc(entry.person.name)} | `;
});
}
});
- LPHS.forEach(l => h2 += `${l} | `);
+ LPHS.forEach(l => h2 += `${l} | `);
h2 += `
`;
return h1 + h2;
}
@@ -2450,28 +2467,61 @@ function buildPdfTableHeaderRows(allPeople){
// buildPdfProjectRow: baut eine einzelne Projektzeile als HTML-String.
function buildPdfProjectRow(p, allPeople){
let body = ``;
- body += `| ${esc(p.nr)} | `;
- body += `${esc(p.name)} | `;
+ body += `${esc(p.nr)} | `;
+ body += `${esc(p.name)} | `;
const statusText = pdfStatusText(p.status);
- body += `${statusText} | `;
+ body += `${statusText} | `;
allPeople.forEach(entry => {
const s = p.assign[assignKey(entry.person.id, entry.role)] || 0;
const txt = s === 1 ? 'X' : s === 2 ? '(X)' : '';
- const bg = s === 1 ? '#9ae6b4' : s === 2 ? '#fbd38d' : '#fff';
- body += `${txt} | `;
+ let roleBg = '#fff';
+ if(entry.role === 'Planung') roleBg = 'rgb(212, 245, 224)';
+ else if(entry.role === 'Projektleitung') roleBg = 'rgb(255, 219, 219)';
+ else if(entry.role === 'Bauüberwachung') roleBg = 'rgb(203, 238, 255)';
+ const textColor = (s === 1 || s === 2) ? '#fff' : '#1d1d1f';
+ const cellBg = s === 1 ? '#248a3d' : s === 2 ? '#d18b00' : roleBg;
+ body += `${txt} | `;
});
LPHS.forEach(l => {
const v = (p.lph[l] !== undefined && p.lph[l] !== '') ? String(p.lph[l]).replace('%','') : '';
- body += `${esc(v ? v + '%' : '')} | `;
+ body += `${esc(v ? v + '%' : '')} | `;
});
body += `
`;
return body;
}
+// Build PDF group body rows with alternating background colors
+function buildPdfGroupBodyRows(projectRows, allPeople) {
+ let html = '';
+ projectRows.forEach((pr, i) => {
+ const s = pr.assign ? Object.values(pr.assign)[0] || 0 : 0;
+ const isEven = i % 2 === 0;
+ const rowBg = isEven ? '#fafafc' : '#fff';
+ html += ``;
+ html += `| ${esc(pr.nr)} | `;
+ html += `${esc(pr.name)} | `;
+ const statusText = pdfStatusText(pr.status);
+ html += `${statusText} | `;
+ allPeople.forEach(entry => {
+ const assignKey = `${entry.person.id}-${entry.role}`;
+ const assign = pr.assign ? pr.assign[assignKey] : 0;
+ const txt = assign === 1 ? 'X' : assign === 2 ? '(X)' : '';
+ const bg = assign === 1 ? '#248a3d' : assign === 2 ? '#d18b00' : '#fff';
+ html += `${txt} | `;
+ });
+ LPHS.forEach(l => {
+ const v = (pr.lph && pr.lph[l] !== undefined && pr.lph[l] !== '') ? String(pr.lph[l]).replace('%','') : '';
+ html += `${esc(v ? v + '%' : '')} | `;
+ });
+ html += `
`;
+ });
+ return html;
+}
+
// buildPdfGroupTitleRow: baut die Zeile mit dem Gruppentitel.
function buildPdfGroupTitleRow(groupName, allPeople){
const colCount = 3 + allPeople.length + LPHS.length;
- return `| ${esc(groupName)} |
`;
+ return `| ${esc(groupName)} |
`;
}
// renderSinglePdfBlock: erzeugt einen DOM-Wrapper mit einer einzelnen Tabelle
@@ -2490,7 +2540,7 @@ function renderSinglePdfBlock(container, headerRows, titleRow, bodyRows){
// buildPdfAttendanceBlock: baut den Anwesenheits-Block als HTML-String.
function buildPdfAttendanceBlock(presentList, absentList){
return `
-
Anwesenheit
+
Anwesenheit
Anwesend: ${presentList || '—'}
Abwesend: ${absentList || '—'}
`;
@@ -2545,33 +2595,33 @@ function buildPdfLoadSection(allPeople){
if(l > maxLoad) maxLoad = l;
});
- let html = `Auslastung der Projektbeteiligten (aktuelle Sitzung)
`;
- html += '
| Rolle | Kürzel | Punkte | Balken | Projektdetails |
';
+ let html = `Auslastung der Projektbeteiligten (aktuelle Sitzung)
`;
+ html += '
| Rolle | Kürzel | Punkte | Balken | Projektdetails |
';
ROLES.forEach(r => {
grouped[r].forEach(entry => {
const s = stats[assignKey(entry.person.id, r)];
const load = s.main + s.opt * 0.5 + s.kleine * 0.3;
const pct = Math.round(load / maxLoad * 100);
- const color = pct > 75 ? '#c53030' : pct > 45 ? '#d69e2e' : '#2f855a';
+ const color = pct > 75 ? '#d70015' : pct > 45 ? '#b25000' : '#248a3d';
const detail = Object.keys(s.projects).map(k => `${esc(k)} (${s.projects[k]}×)`).join(', ') || '—';
html += `
- | ${r} |
- ${esc(entry.person.name)} |
- ${load.toString().replace('.',',')} |
-
-
+ ${r} |
+ ${esc(entry.person.name)} |
+ ${load.toString().replace('.',',')} |
+
+
- ${pct}%
+ ${pct}%
|
- ${detail}${s.anbahnung ? ` In Anbahnung: ${s.anbahnung}` : ''} |
+ ${detail}${s.anbahnung ? ` In Anbahnung: ${s.anbahnung}` : ''} |
|
`;
});
});
html += '
';
- html += '
Haupt=1 · Optional=0,5 · Kleine Projekte=0,3 · In Anbahnung wird nicht in der Punktzahl gezählt.
';
+ html += '
Haupt=1 · Optional=0,5 · Kleine Projekte=0,3 · In Anbahnung wird nicht in der Punktzahl gezählt.
';
html += '
';
return html;
}
diff --git a/sessions/.DS_Store b/sessions/.DS_Store
index 3903cb3..0ac5090 100644
Binary files a/sessions/.DS_Store and b/sessions/.DS_Store differ
diff --git a/sessions/ELT/KW_33___2026.csv b/sessions/ELT/KW_33___2026.csv
index 6961169..638bbc4 100644
--- a/sessions/ELT/KW_33___2026.csv
+++ b/sessions/ELT/KW_33___2026.csv
@@ -4,15 +4,15 @@ Pr.-Nr.;Bezeichnung;Status;AP;AK;ED;SK;SE;WS;ED;SP;THK;RR;MK;TW;SG;ED;SK;SP;THK;
ANWESENHEIT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18-4007;Janusz-Korczak-Gesamtsch. Bottrop;- KW 35 NW Raum Planung - KW 44 Möbel
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;90%;;;;;Aktive Projekte;0;"{""start"":"""",""end"":"""",""milestones"":[],""people"":[],""progress"":0}"
21-4030;NSHV Köln Immobilienprüfung in Hof;- Thorsten W. klärt und übernimmt Schriftverkehr - LV liegt zur Sichtung bei T.W.
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;;;;Aktive Projekte;2;
-22-4066;DSW 21, Umbau E-Mobilität;"- Elt-Montagen ab KW 33.";;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;20%;;Aktive Projekte;6;
+22-4066;DSW 21, Umbau E-Mobilität;- Elt-Montagen ab KW 33.;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;20%;;Aktive Projekte;6;
24-4043;S-K ODL-Heim Sanierung Krefeld;- Vorraussichtlich LV-Abgabe XX.XX- LPH5 mündlich freigegeben
- Neuer EG Grundriss mit diversen Änderungen kommt noch von Architekten
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;;;;;Aktive Projekte;10;
-21-4001;Feuerwehrgeräteh. Rodenkirchen;"- KNX muß noch programmiert werden. Abnahme 27.07 - Fertigstellung Ende Juli- Abnahmen laufen bis Ende KW31
- Blackbuilding Test 26.07
";X;;X;;;;X;X;;;;;;X;;;;;;;;;100%;100%;100%;;;Aktive Projekte;1;"{""start"":"""",""end"":"""",""milestones"":[{""id"":""mslrvh7hjau1e"",""name"":""Übergabe"",""date"":""2026-09-12"",""dependsOn"":[""mslv6h76cmx8k""],""position"":""after:mslv6h76cmx8k""}],""people"":[""p_ap"",""p_ak"",""p_sk"",""p_sg""],""progress"":""0"",""todos"":[{""id"":""msluufbp114g1"",""title"":""Test"",""start"":""2026-08-10"",""end"":""2026-08-14"",""done"":false,""dependsOn"":[],""assignees"":[""p_ap"",""p_ed""],""progress"":0},{""id"":""mslv6h76cmx8k"",""title"":""Test 2"",""start"":""2026-08-24"",""end"":""2026-09-04"",""done"":false,""dependsOn"":[""msluufbp114g1""],""assignees"":[""p_ap""],""progress"":41},{""id"":""mslw4l3qp1v18"",""title"":""Test 3"",""start"":""2026-09-14"",""end"":""2026-09-22"",""done"":false,""dependsOn"":[""m_mslrvh7hjau1e""],""assignees"":[],""progress"":0},{""id"":""msoltaa1itx48"",""title"":""Gehen"",""start"":""2026-09-23"",""end"":""2026-09-25"",""done"":false,""progress"":0,""dependsOn"":[""mslw4l3qp1v18""],""assignees"":[""p_ws""]}]}"
+21-4001;Feuerwehrgeräteh. Rodenkirchen;- KNX muß noch programmiert werden. Abnahme 27.07 - Fertigstellung Ende Juli- Abnahmen laufen bis Ende KW31
- Blackbuilding Test 26.07
;X;;X;;;;X;X;;;;;;X;;;;;;;;;100%;100%;100%;;;Aktive Projekte;1;"{""start"":"""",""end"":"""",""milestones"":[{""id"":""mslrvh7hjau1e"",""name"":""Übergabe"",""date"":""2026-09-12"",""dependsOn"":[""mslv6h76cmx8k""],""position"":""after:mslv6h76cmx8k""}],""people"":[""p_ap"",""p_ak"",""p_sk"",""p_sg""],""progress"":""0"",""todos"":[{""id"":""msluufbp114g1"",""title"":""Test"",""start"":""2026-08-10"",""end"":""2026-08-14"",""done"":false,""dependsOn"":[],""assignees"":[""p_ap"",""p_ed""],""progress"":0},{""id"":""mslv6h76cmx8k"",""title"":""Test 2"",""start"":""2026-08-24"",""end"":""2026-09-04"",""done"":false,""dependsOn"":[""msluufbp114g1""],""assignees"":[""p_ap""],""progress"":41},{""id"":""mslw4l3qp1v18"",""title"":""Test 3"",""start"":""2026-09-14"",""end"":""2026-09-22"",""done"":false,""dependsOn"":[""m_mslrvh7hjau1e""],""assignees"":[],""progress"":0},{""id"":""msoltaa1itx48"",""title"":""Gehen"",""start"":""2026-09-23"",""end"":""2026-09-25"",""done"":false,""progress"":0,""dependsOn"":[""mslw4l3qp1v18""],""assignees"":[""p_ws""]}]}"
22-4027;Sporthalle Soest;- SV und VOB Abnahme erfolgt.- Nachprüfung VOB 24.07
- Keine Infos über Nachprüfung
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;90%;;Aktive Projekte;3;
22-4056;Gymnasium Hemer;;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;90%;;Aktive Projekte;4;
22-4056-1;Gymnasium Hemer (Deckensanierung);- Beginn der Arbeiten vorraussichtlich KW 30 (KW 32 Kickoff);;;;;;;;;;;;;;;;;;;;;100%;;100%;100%;;;;Aktive Projekte;5;
-23-4042;GWK Neufelder Straße;"- Nachweis für E-30 Leitungen notwendig. Rechnungen wurden nicht anerkannt. - 22.07 Aufschaltung BMA und Amok
- KW 31 VOB Abnahme
";;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;95%;;Aktive Projekte;7;
+23-4042;GWK Neufelder Straße;- Nachweis für E-30 Leitungen notwendig. Rechnungen wurden nicht anerkannt. - 22.07 Aufschaltung BMA und Amok
- KW 31 VOB Abnahme
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;95%;;Aktive Projekte;7;
23-4070;Umbau Bürogebäude NEW, MV10;"- neue NSHV anbieten(Warten auf Infos), - 28.07 Sachverständiger Abnahme ELT&SiBe
- 30.07 Sachverständigen Abnahme BMA
";;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;90%;;Aktive Projekte;8;
-23-4072;S-K OGS-Kaldenkirchen Schulanbau;"- Feininstallation beginnt, Fertigstellung voraussichtlich 01.08";;;;;;;;;;;;;;;;;;;;;;;;;;70%;;Aktive Projekte;9;
+23-4072;S-K OGS-Kaldenkirchen Schulanbau;- Feininstallation beginnt, Fertigstellung voraussichtlich 01.08;;;;;;;;;;;;;;;;;;;;;;;;;;70%;;Aktive Projekte;9;
24-4049;BMA Remscheid;"- Feuerwehrabnahme organisiert die Errichterfirma. - SV-Abnahmen 15 & 16.07: nicht abgenommen
";;;;;;;;;;;;;;;;;;;100%;100%;100%;;100%;100%;100%;90%;;Aktive Projekte;11;
24-4069;S-K Erw. GS Blankenheim Neubau;- nur backup;;;;;;;;;;;;;;;;;;;;;;;100%;100%;;;;Kleine Projekte;0;
24-4096;Umbau Wohngebäude Kirchhoff;- Position HA wird von uns bestimmt. - Notwendiges Leerrohr für Leuchten im Vordach ist zu klären.
- Abgabe Kostenberechnung bis Ende KW29
- LV Fertig bis Ende KW 32
;;;;;;;;;;;;;;;;;;;100%;100%;100%;;95%;85%;0%;;;Aktive Projekte;12;