Files
projektuebersicht/public/js/store.js
T

178 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// -----------------------------
// Projektübersicht — Daten laden, Speichern, Abteilung wechseln
// -----------------------------
// Diese Datei bildet die Schnittstelle zum Server: Sie lädt alle Sitzungs-CSVs
// beim Start, speichert den kompletten Datenbestand (alle Wochen + globale
// Personenliste) und verwaltet den Wechsel zwischen Abteilungen (ELT/HLS/ARCH).
// Sie wird von `Test.html` nach `js/csv.js` und `js/server.js` geladen und stellt
// die globalen Funktionen `save()`, `syncAllToServer()`, `switchDepartment()`,
// `load()`, `seed()` und `demoProj()` bereit. Aufrufer sind u.a. `js/weeks.js`,
// `js/board.js`, `js/people.js`, `js/projects.js` und `js/load.js`; das Speichern
// ist über `saveSyncTimer` (in `js/globals.js` deklariert) um 500 ms debounced.
// save: synchronisiert die aktuellen Daten als CSV-Dateien zum Server.
// Jede Sitzung wird als eigene CSV-Datei gespeichert. Personen und Rollen werden
// in der Sitzungscsv selbst abgelegt.
function save(){
scheduleSessionSync();
}
// scheduleSessionSync: plant den Speichervorgang für alle Wochen und Personen
// über einen 500-ms-Timer (Debounce). Bei erneutem Aufruf wird ein laufender
// Timer zurückgesetzt, damit aufeinanderfolgende Änderungen in einem Sync enden.
function scheduleSessionSync(){
if(saveSyncTimer){ clearTimeout(saveSyncTimer); }
saveSyncTimer = setTimeout(() => { syncAllToServer(); saveSyncTimer = null; }, 500);
}
// syncAllToServer: schreibt die gesamte Datenbank als CSV-Dateien zum Server.
// Zuerst wird die globale Personenliste (`_people.csv`) gespeichert, danach jede
// Sitzung einzeln über `filenameForWeek()`/`weekToCsv()` und `sendCsvToServer()`.
// Gibt nichts zurück; Fehler werden nur per console.error protokolliert.
function syncAllToServer(){
// Zuerst globale Personenliste speichern
saveGlobalPeopleToServer();
// Dann jede Sitzung speichern
db.weeks.forEach(w => {
const filename = filenameForWeek(w.label);
const csv = weekToCsv(w);
sendCsvToServer(filename, csv)
.then(res => { if(res && res.ok) console.log('Sitzung gespeichert:', filename); })
.catch(err => { console.error('Sitzung konnte nicht gespeichert werden:', filename, err.message || err); });
});
}
// saveGlobalPeopleToServer: serialisiert die globale Personenliste der aktuellen
// Abteilung per `globalPeopleToCsv()` und speichert sie als `_people.csv`.
// Leere Personenlisten werden übersprungen (kein Schreibvorgang).
function saveGlobalPeopleToServer(){
const people = db.globalPeople[currentDepartment] || [];
if(people.length === 0) return;
const csv = globalPeopleToCsv(people);
sendCsvToServer('_people.csv', csv)
.then(res => { if(res && res.ok) console.log('Globale Personenliste gespeichert'); })
.catch(err => { console.error('Globale Personenliste konnte nicht gespeichert werden:', err.message || err); });
}
// switchDepartment: wechselt die aktive Abteilung (z.B. "ELT") und lädt deren
// Daten neu. Parameter `dept` ist der Abteilungsschlüssel aus `DEPARTMENTS`.
// Aktualisiert Tab-Markierung und Seitentitel und ruft anschließend `load()`.
// Gibt nichts zurück.
function switchDepartment(dept){
if(!DEPARTMENTS[dept]) return;
currentDepartment = dept;
saveUiState();
// UI-Status der Abteilungs-Tabs aktualisieren
document.querySelectorAll('.dept-tab').forEach(btn => {
btn.classList.toggle('active', btn.dataset.dept === dept);
});
// Seitentitel anpassen
const info = DEPARTMENTS[dept];
document.title = 'Projektübersicht ' + info.label;
const titleEl = document.getElementById('pageTitle');
if(titleEl) titleEl.textContent = info.icon + ' Projektübersicht ' + info.label;
// Datenbank leeren und neu laden
db = { weeks: [], currentWeek: null, globalPeople: db.globalPeople || {} };
load();
}
// load: liest alle CSV-Dateien der aktuellen Abteilung über `/load-all` vom
// Server ein, parst Personen und Sitzungen (mit `parseSessionCsv()`) und baut
// daraus `db.weeks` auf. Sortiert nach `weekSortKey()`, wendet `applyAutoLock()`
// an und rendert die Ansicht. Kein Parameter, keine Rückgabe; bei Fehlern oder
// fehlenden Daten werden Beispieldaten über `seed()` geladen.
function load(){
if(!window.fetch){
alert('Ihr Browser unterstützt keine Netzwerk-Anfragen. Bitte verwenden Sie einen aktuellen Browser.');
seed(); return;
}
const url = baseUrl() + '/load-all' + departmentParam();
console.log('Loading from', url);
fetch(url)
.then(r => { if(!r.ok) throw new Error('Server HTTP '+r.status); return r.json(); })
.then(data => {
// Globale Personenliste laden
db.globalPeople[currentDepartment] = parseGlobalPeopleCsv(data.people);
const parsedSessions = (data.sessions || []).map(s => ({ filename: s.filename, rows: parseCsvText(s.content) }));
db.weeks = [];
parsedSessions.forEach(s => {
const w = parseSessionCsv(s.filename, s.rows);
if(w) db.weeks.push(w);
});
if(db.weeks.length === 0){
console.warn('Server lieferte 0 Sitzungsdateien. Es werden Beispieldaten (seed) angezeigt. Pruefen Sie, ob der Ordner sessions/ mitkopiert wurde.');
seed();
}
else {
db.weeks.sort((a,b) => weekSortKey(a.label).localeCompare(weekSortKey(b.label)));
applyAutoLock();
const latest = db.weeks[db.weeks.length - 1];
if(!db.currentWeek || !db.weeks.some(w => w.id === db.currentWeek)){
db.currentWeek = latest.id;
}
console.log(`Server-Load erfolgreich: ${db.weeks.length} Sitzung(en).`);
}
// Geschützte Tabs dürfen nicht ohne Passwort angezeigt werden, auch wenn
// sie im UI-State gespeichert waren.
if(currentTab === 'projects' || currentTab === 'people') currentTab = DEFAULT_TAB;
renderAll();
showTab(currentTab, true);
})
.catch(err => {
console.error('Laden vom Server fehlgeschlagen:', err);
const serverUrl = baseUrl();
const msg = 'Server unter ' + serverUrl + ' nicht erreichbar.\n\n' +
'Mögliche Ursachen:\n' +
'- Der Server wurde nicht gestartet\n' +
'- Der Server läuft auf einem anderen Port (Standard: 3003)\n' +
'- Firewall/Antivirus blockiert ' + serverUrl + '\n\n' +
'Es werden jetzt die Beispieldaten angezeigt.';
alert(msg);
seed(); renderAll();
});
}
// seed: initialisiert Beispiel-Daten (Personen + eine Woche mit Projekten).
// Wird als Fallback verwendet, wenn der Server nicht erreichbar ist oder keine
// Sitzungsdateien liefert.
function seed(){
const people = [
{id:personIdForName('AP'), name:"AP", fullName:"Anton Peters", role:["Planung"]},
{id:personIdForName('SK'), name:"SK", fullName:"Stefan Krause", role:["Planung"]},
{id:personIdForName('AK'), name:"AK", fullName:"Alexander Klein", role:["Planung"]},
{id:personIdForName('ED'), name:"ED", fullName:"Eva Dreyer", role:["Planung"]},
{id:personIdForName('SE'), name:"SE", fullName:"Stefan Eschweiler", role:["Planung"]},
{id:personIdForName('THK'), name:"THK", fullName:"Thorsten H. Klein", role:["Projektleitung"]},
{id:personIdForName('SP'), name:"SP", fullName:"Sven Peschke", role:["Projektleitung"]},
{id:personIdForName('SG'), name:"SG", fullName:"Sandra Gloag", role:["Projektleitung"]},
{id:personIdForName('TW'), name:"TW", fullName:"Thorsten Wörster", role:["Projektleitung"]},
{id:personIdForName('RR'), name:"RR", fullName:"Robert Rahn", role:["Bauüberwachung"]},
{id:personIdForName('MK'), name:"MK", fullName:"Martin Kluge", role:["Bauüberwachung"]},
{id:personIdForName('HR'), name:"HR", fullName:"Hartwig Rauch", role:["Bauüberwachung"]},
];
db.globalPeople[currentDepartment] = JSON.parse(JSON.stringify(people));
const wid = uid();
db.weeks = [{
id: wid, label:"KW 30 / 2026", date:"2026-07-24", attendance:{}, people, projects: [
demoProj("18-4007","Janusz-Korczak-Gesamtsch. Bottrop","Aktive Projekte","LPH5 als Vorabzug raus. NW-Räume vorauss. August.",{"LPH 1":100,"LPH 2":100,"LPH 3":100,"LPH 5":100,"LPH 6":100,"LPH 7":100,"LPH 8":95}),
demoProj("21-4030","NSHV Köln Immobilienprüfung in Hof","Aktive Projekte","Thorsten W. klärt und übernimmt Schriftverkehr. LV liegt zur Sichtung bei T.W.",{"LPH 1":100,"LPH 2":100,"LPH 3":100,"LPH 5":100,"LPH 6":100}),
demoProj("22-4056","Gymnasium Hemer","Aktive Projekte","",{"LPH 1":100,"LPH 2":100,"LPH 3":100,"LPH 5":100,"LPH 6":100,"LPH 7":100,"LPH 8":90}),
demoProj("22-4066","DSW 21 – Umbau E-Mobilität","Aktive Projekte","Elt-Montagen ab KW 33.",{"LPH 1":100,"LPH 2":100,"LPH 3":100,"LPH 5":100,"LPH 6":100,"LPH 7":100,"LPH 8":20}),
demoProj("24-4043","S-K ODL-Heim Sanierung Krefeld","Aktive Projekte","Voraussichtlich LV-Abgabe.",{"LPH 1":100,"LPH 2":100,"LPH 3":100,"LPH 5":100}),
]
}];
db.currentWeek = wid;
save();
}
// demoProj: Helfer zum Erzeugen eines Projekt-Objekts (für seed/Tests)
function demoProj(nr,name,group,status,lph){
return {id:uid(), nr, name, group, status, lph: {...lph}, assign:{}, plan: null, aufwandProLP: undefined, aktuelleLP: undefined};
}