All new
alle new
This commit is contained in:
1 parent
da64472251
commit
5b20adee48
1605 files changed
+396517
-1674
No files matched your search
+123
-31
@@ -1,64 +1,156 @@
|
||||
// -----------------------------
|
||||
// Projektübersicht — globale Konstanten & Zustand
|
||||
// -----------------------------
|
||||
// Diese Datei wird als Erstes von Test.html und project-plan.html geladen und
|
||||
// Diese Datei wird als Erstes von Test.html geladen und
|
||||
// legt alle zentralen Konstanten (Leistungsphasen, Rollen, Gruppen, Abteilungen,
|
||||
// Farben, Passwort-Hash) sowie den globalen In-Memory-Zustand (db,
|
||||
// currentDepartment, currentTab) fest. Sie stellt keine Funktionen, sondern nur
|
||||
// Daten bereit, auf die alle weiteren Module (js/store.js, js/board/board.js,
|
||||
// js/gantt.js, js/plan/*, ...) zugreifen. Auf dem Plan-Gantt lädt zusätzlich
|
||||
// js/plan/plan-state.js Zustand für die Planungsseite.
|
||||
// Farben, Passwort-Hash) sowie den globalen In-Memory-Zustand (db, currentTab)
|
||||
// fest. Sie stellt keine Funktionen, sondern nur Daten bereit, auf die alle
|
||||
// weiteren Module (js/store.js, js/board/board.js, js/gantt.js, js/plan/*, ...)
|
||||
// zugreifen. Auf dem Plan-Gantt lädt zusätzlich js/plan/plan-state.js Zustand
|
||||
// für die Planungsseite. DEPARTMENTS/DEFAULT_DEPARTMENT bleiben trotz Wegfall
|
||||
// der Abteilungstrennung erhalten — sie werden weiterhin für die
|
||||
// Benutzerverwaltung (users.department, Profil-Anzeige) gebraucht.
|
||||
|
||||
// Konstanten: Leistungsphasen, Rollen und LocalStorage-Key
|
||||
const LPHS = ["LPH 1","LPH 2","LPH 3","LPH 4","LPH 5","LPH 6","LPH 7","LPH 8", "W+M"]; // Spalten für Leistungsphasen
|
||||
// LPHS: alle Leistungsphasen in fachlicher Reihenfolge. "W+M" steht bewusst
|
||||
// AM ENDE und ist keine HOAI-Phase, sondern eine eigene Sammelkategorie —
|
||||
// Stellen, die nur die echten Leistungsphasen brauchen (amtierende Phase,
|
||||
// Aufwandsmodell), filtern deshalb gezielt "W+M" heraus statt nach Index zu
|
||||
// schneiden.
|
||||
const LPHS = ["LPH 1","LPH 2","LPH 3","LPH 4","LPH 5","LPH 6","LPH 7","LPH 8","LPH 9", "W+M"]; // Spalten für Leistungsphasen
|
||||
const ROLES = ["Planung","Projektleitung","Bauüberwachung"]; // Gruppierung der Personen
|
||||
const GROUP_ORDER = ["Aktive Projekte","Kleine Projekte","In Anbahnung","Allgemein"]; // Reihenfolge der Projektgruppen
|
||||
const STORAGE = "projuebersicht_v1"; // Durch lokale UI-State-Persistenz genutzter Key
|
||||
// DEFAULT_DEPARTMENT: Fallback-Abteilung beim ersten Start
|
||||
const DEFAULT_DEPARTMENT = 'ELT';
|
||||
// DEFAULT_TAB: Tab, der beim ersten Start angezeigt wird ('board' = Projektboard)
|
||||
const DEFAULT_TAB = 'board';
|
||||
// DEFAULT_TAB: Tab, der beim ersten Start angezeigt wird ('dashboard' = Meine
|
||||
// Aufgaben, das persönliche Dashboard — Projektboard bleibt über die
|
||||
// Navigation vollständig erreichbar, ist aber nicht mehr die Startansicht)
|
||||
const DEFAULT_TAB = 'dashboard';
|
||||
|
||||
// APP_SETTINGS: die firmenweiten Einstellungen (GET /app-settings). Sie
|
||||
// waren bis zum Ausbau der Einstellungsseite Konstanten im Quelltext —
|
||||
// Aufwandsvorlage, Ampel-Schwellen, Balkenskala, Arbeitsstunden je Tag — und
|
||||
// verschieben allesamt Zahlen, die alle Nutzer sehen. Deshalb sind sie jetzt
|
||||
// firmenweit gepflegt (Admin) statt im Code verteilt.
|
||||
//
|
||||
// Die Werte hier sind die VORGABEN und zugleich die Rückfallebene: Sie
|
||||
// entsprechen APP_SETTING_DEFS in server.js und gelten, solange
|
||||
// loadAppSettings() (js/store.js) noch nicht geantwortet hat oder der Abruf
|
||||
// scheitert. Ohne diese Kopie stünde vor dem ersten Rendern gar kein Wert
|
||||
// bereit und die Auslastung rechnete mit undefined.
|
||||
let APP_SETTINGS = {
|
||||
stundensatz: 135,
|
||||
arbeitsstundenProTag: 8,
|
||||
vollzeitStundenProWoche: 40,
|
||||
auslastungSchwelleGelb: 0.75,
|
||||
auslastungSchwelleRot: 1.0,
|
||||
aufwandVorlage: {
|
||||
'LPH 1': { Planung: 0.4, Projektleitung: 0.2, Bauüberwachung: 0 },
|
||||
'LPH 2': { Planung: 0.4, Projektleitung: 0.2, Bauüberwachung: 0 },
|
||||
'LPH 3': { Planung: 1.0, Projektleitung: 0.3, Bauüberwachung: 0 },
|
||||
'LPH 4': { Planung: 0.0, Projektleitung: 0.3, Bauüberwachung: 0 },
|
||||
'LPH 5': { Planung: 1.0, Projektleitung: 0.4, Bauüberwachung: 0 },
|
||||
'LPH 6': { Planung: 0.2, Projektleitung: 0.7, Bauüberwachung: 0.3 },
|
||||
'LPH 7': { Planung: 0.1, Projektleitung: 0.3, Bauüberwachung: 0.5 },
|
||||
'LPH 8': { Planung: 0, Projektleitung: 0.2, Bauüberwachung: 1.0 },
|
||||
'LPH 9': { Planung: 0, Projektleitung: 0, Bauüberwachung: 0 }
|
||||
},
|
||||
autoLockAktiv: 1,
|
||||
feiertagBundesland: 'NW',
|
||||
maxBackups: 10,
|
||||
sessionTage: 30,
|
||||
loginMaxVersuche: 10,
|
||||
loginSperreMinuten: 10
|
||||
};
|
||||
|
||||
// HONORAR_ANTEILE: firmenweite HOAI-Anteile je Leistungsphase in Prozent
|
||||
// ({ 'LPH 1': 2, … }), gefüllt aus GET /honorar-config beim Start
|
||||
// (loadAppSettings() in js/store.js). Sie sind die Brücke vom Honorar eines
|
||||
// Projekts zum Aufwand einer einzelnen Phase und damit Grundlage der
|
||||
// Auslastungsrechnung in Stunden (berechneAuslastung(), js/load/load.js).
|
||||
// Gepflegt werden sie im Admin-Bereich unter „Honorar"; der Projektbereich
|
||||
// holt sie sich für den Leistungsstand weiterhin selbst (plan-leistung.js),
|
||||
// weil er sie auch nach einer Änderung im laufenden Betrieb neu braucht.
|
||||
// Leer = nicht geladen: Die Auslastung weist dann eine Lücke aus, statt mit
|
||||
// erfundenen Anteilen zu rechnen.
|
||||
let HONORAR_ANTEILE = {};
|
||||
|
||||
// HOLIDAYS: Feiertage und sonstige arbeitsfreie Tage als Menge von
|
||||
// ISO-Datumsangaben ("2026-12-25"), gefüllt aus GET /holidays. Wirkt in
|
||||
// workdaysBetween()/addWorkdays() (js/utils.js) und damit in der
|
||||
// Terminplan-Berechnung aus dem Honorar und in der Ressourcen-Auslastung.
|
||||
let HOLIDAYS = new Set();
|
||||
|
||||
// HOLIDAY_NAMES: Datum -> Bezeichnung, nur für die Pflege-Liste im Bereich
|
||||
// „Admin" (die Rechnung braucht allein die Menge oben).
|
||||
let HOLIDAY_NAMES = {};
|
||||
|
||||
// GERMAN_STATES: Kürzel -> Name der Bundesländer, vom Server mitgeliefert
|
||||
// (GET /holidays). Er ist die eine Stelle, an der die Liste steht; sie wird
|
||||
// nur für die Auswahl beim Berechnen der gesetzlichen Feiertage gebraucht.
|
||||
let GERMAN_STATES = {};
|
||||
|
||||
// Farbpalette für GANTT-Balken (eine pro Projekt, wiederholend)
|
||||
const GANTT_COLORS = ['#0071e3','#248a3d','#b25000','#7c3aed','#d70015','#0ca678','#d9480f','#5f3dc4'];
|
||||
|
||||
// Passwortschutz: SHA256-Hash des erlaubten Passworts.
|
||||
// Wenn Sie das Passwort ändern möchten, generieren Sie den SHA256-Hash (https://emn178.github.io/online-tools/sha256.html)
|
||||
// des neuen Passworts und ersetzen Sie den Wert hier.
|
||||
const PROTECTED_PASSWORD_HASH = "107bab579e8500e459690cf48ba77de32be43cadb8421bbe79fad20a55b39b6f";
|
||||
|
||||
// requestedAction speichert die Aktion, die nach erfolgreicher Passwort-Eingabe ausgeführt wird.
|
||||
let requestedAction = null;
|
||||
// saveSyncTimer: Handle für den debounced Speicher-Timer (Sync auf Server)
|
||||
let saveSyncTimer = null;
|
||||
// isAuthenticated: Merkt sich, ob das Passwort-Schutz-Modal bereits erfolgreich bestätigt wurde
|
||||
let isAuthenticated = false;
|
||||
|
||||
// In-memory Datenbank: Sitzungen (weeks) und aktuell ausgewählte Sitzung
|
||||
let db = { weeks: [], currentWeek: null, globalPeople: {} };
|
||||
// In-memory Datenbank: Sitzungen (weeks) und aktuell ausgewählte Sitzung.
|
||||
// globalPeople ist ein flaches Array (keine Abteilungstrennung mehr).
|
||||
let db = { weeks: [], currentWeek: null, globalPeople: [],
|
||||
// sandboxWeek: Platzhalter bis zum ersten erfolgreichen load() (js/store.js)
|
||||
// befüllt ihn — leer statt undefined, damit ein Zugriff vor dem Laden nicht
|
||||
// crasht, sondern nur eine leere Planung-Liste zeigt.
|
||||
sandboxWeek: { id: 'sandbox', label: '__sandbox__', date: '', people: [], projects: [], attendance: {}, locked: false, updatedAt: '' }
|
||||
};
|
||||
|
||||
// Aktuelle Abteilung (ELT, HLS, ARCH). Daten werden in sessions/<DEPT>/ getrennt gespeichert.
|
||||
let currentDepartment = DEFAULT_DEPARTMENT;
|
||||
// currentTab: aktuell aktiver Tab der Hauptseite (z. B. 'board')
|
||||
let currentTab = DEFAULT_TAB;
|
||||
// previousTab: der davor angezeigte Bereich. Gebraucht vom "Schließen"-Knopf
|
||||
// des Projektbereichs (closePlanPage() in js/gantt.js), der damit dorthin
|
||||
// zurückführt, von wo aus das Projekt geöffnet wurde — früher erledigte das
|
||||
// die Browser-Historie, weil der Projektbereich ein eigenes Dokument war.
|
||||
let previousTab = DEFAULT_TAB;
|
||||
// DEPARTMENTS: Auflistung der gültigen Abteilungen mit Anzeigename und Icon
|
||||
// (nur noch für users.department/Benutzerverwaltung relevant, keine
|
||||
// App-weite Datentrennung mehr)
|
||||
const DEPARTMENTS = {
|
||||
ELT: { label: 'Elektro', icon: '' },
|
||||
HLS: { label: 'HLS', icon: '' },
|
||||
ARCH: { label: 'Architektur', icon: '' }
|
||||
};
|
||||
|
||||
// TAB_SLUGS / TAB_BY_SLUG: sprechende URL-Abschnitte für die Tabs, damit jede
|
||||
// Abteilungs-/Tab-Kombination eine eigene Seite hat (z. B. "/HLS/Auslastung").
|
||||
// Wird von js/ui.js (applyUrlRoute/updateRouteUrl) und dem Server genutzt.
|
||||
// SANDBOX_WEEK_LABEL: die eine, dauerhaft reservierte "Sitzung", in der alle
|
||||
// Planung-Terminpläne liegen (CLAUDE.md, "Planung — projektunabhängige
|
||||
// Terminplan-Sandbox"). MUSS mit der gleichnamigen Konstante in server.js
|
||||
// übereinstimmen — kein gemeinsames Modulsystem zwischen Server und Client.
|
||||
const SANDBOX_WEEK_LABEL = '__sandbox__';
|
||||
|
||||
// TAB_SLUGS / TAB_BY_SLUG: sprechende URL-Abschnitte für die Tabs, damit jeder
|
||||
// Tab eine eigene Seite hat (z. B. "/Auslastung"). Wird von js/ui.js
|
||||
// (applyUrlRoute/updateRouteUrl) und dem Server genutzt.
|
||||
const TAB_SLUGS = {
|
||||
board: 'Projektübersicht',
|
||||
load: 'Auslastung',
|
||||
projects:'Projekte',
|
||||
people: 'Projektbeteiligte'
|
||||
board: 'Projektübersicht',
|
||||
wochenbericht: 'Wochenbericht',
|
||||
load: 'Auslastung',
|
||||
people: 'Projektbeteiligte',
|
||||
planung: 'Planung',
|
||||
dashboard:'MeineAufgaben',
|
||||
settings: 'Einstellungen',
|
||||
admin: 'Admin'
|
||||
};
|
||||
const TAB_BY_SLUG = Object.fromEntries(Object.entries(TAB_SLUGS).map(([k,v]) => [v,k]));
|
||||
// Der Bereich "Projekte" ist in der Projektliste aufgegangen (siehe
|
||||
// renderBoard() in js/board/board.js). Sein Adressabschnitt bleibt gültig und
|
||||
// führt dorthin, damit weitergegebene Links nicht ins Leere zeigen — er wird
|
||||
// aber nicht mehr erzeugt, weil er in TAB_SLUGS fehlt.
|
||||
TAB_BY_SLUG['Projekte'] = 'board';
|
||||
|
||||
// PLAN_SLUG: URL-Schlüssel für die Projektplan-Seite (project-plan.html), im
|
||||
// gleichen Deep-Link-Schema wie die Tabs: "/<Abteilung>/Projektplan".
|
||||
// PLAN_SLUG: URL-Schlüssel des Projektbereichs (Bereich #plan von Test.html),
|
||||
// im gleichen Deep-Link-Schema wie die Tabs: "/Projektplan/<Projektname>",
|
||||
// dazu ?weekLabel=…&projNr=… als Parameter. Steht nicht in TAB_SLUGS, weil
|
||||
// die Adresse das geöffnete Projekt mitträgt und deshalb nicht fest ist —
|
||||
// gebaut wird sie in updateRouteUrl() (js/ui.js).
|
||||
const PLAN_SLUG = 'Projektplan';
|
||||
Reference in new issue
Block a user