Wandtafel-Dashboard, Dateibereinigung und Auslastungs-Vereinfachung

Neue Wandtafel (Touch-Dashboard für Kiosk-Anzeige): Auslastung/Besprochen je
Gewerk, Aufgaben-Kennzahlen, Ereignis-Feed nach Art gruppiert, vollständige
Projektliste zum Scrollen, automatischer Rücksprung nach Untätigkeit mit
sichtbarem Countdown. Eigene Kiosk-Rolle ohne Fachrolle und ohne Schreibrechte.
Auslastung: Möglichkeit zum Wechsel der ausgewerteten Sitzung entfernt.
Aufräumen nicht mehr benötigter Dateien, README auf aktuellen Stand gebracht.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
erikandClaude Sonnet 5 committed 2026-10-02 15:14:47 +02:00
1 parent bc30f2900b
commit db63a29365
47 files changed
+16486 -3768

No files matched your search

+8 -27
View File
@@ -1,14 +1,14 @@
// -----------------------------
// Projektübersicht — Auslastung (Load) & Aufwand je Leistungsphase
// -----------------------------
// Modul für den Auslastungs-Tab der Hauptseite (Test.html, Ladereihenfolge:
// Modul für den Auslastungs-Tab der Hauptseite (App.html, Ladereihenfolge:
// globals → utils → ui → date-picker → csv → server → store → weeks → board →
// people → projects → load → gantt → …). Es stellt renderLoad(), das LP-
// Aufwand-Modal und das Neues-Projekt-Modal bereit. Genutzt werden LPHS/ROLES
// aus js/globals.js, currentWeek()/save() aus js/store.js, guardWeekLocked()
// aus js/weeks.js sowie peopleByRole()/assignKey() aus js/utils.js.
// Die Auslastungs-Logik (berechneAuslastung, lpActiveList, faktorFormat,
// pdfLoadAmpelColor, stundenFormat) wird zusätzlich von js/pdf.js für den
// stundenFormat) wird zusätzlich von js/pdf.js für den
// PDF-Export wiederverwendet.
//
// Datenmodell je Projekt (rollen- und leistungsphasenspezifisch):
@@ -313,20 +313,6 @@ function berechneAuslastung(mitarbeiter, projekt, aktuelleLP, rolle, status, all
return { stunden, load: stunden / vollzeit, quelle: basis.quelle, wochen, phase };
}
// groesseText: beschriftet die Projektgröße für die Eingabemasken.
//
// Nur die Zahl, KEIN Eurobetrag daneben. Intern wird die Größe zwar über das
// Referenzhonorar in einen Betrag umgerechnet (projektBasisHonorar()) — die
// Zahl neben dem Feld auszuweisen, gäbe der Schätzung aber eine Genauigkeit,
// die sie nicht hat: "0,40 · rund 100.000 €" liest sich wie ein Honorar,
// obwohl es ein grober Umfang ist.
// Parameter: wert (0–1). Rückgabe: String.
function groesseText(wert){
const n = Math.max(0, Math.min(1, parseFloat(wert) || 0));
if(n <= 0) return '— keine Angabe';
return n.toFixed(2).replace('.', ',');
}
// stundenFormat: Wochenstunden in deutscher Schreibweise, eine
// Nachkommastelle. Ab 100 h ohne Nachkomma — die Genauigkeit einer
// Hochrechnung reicht dort nicht für Zehntel.
@@ -359,16 +345,12 @@ function loadAmpelColor(x){
// nicht mehr nur einen Balken, sondern die große Zahl am Zeilenende. Die
// früheren Festwerte (#c53030/#d69e2e/#2f855a) waren für den hellen Grund
// gewählt und standen im dunklen Thema zu dunkel; --red/--amber/--green
// sind dort hellere Töne (siehe styles.css). Für den PDF-Export gilt
// weiterhin pdfLoadAmpelColor() mit druckfreundlichen Festwerten — ein PDF
// hat kein Thema.
// sind dort hellere Töne (siehe styles.css). Ein Gegenstück mit
// druckfreundlichen Festwerten gab es für den PDF-Export (pdfLoadAmpelColor);
// es ist mit dem gewerkeübergreifenden Sitzungs-PDF entfallen — die
// verbliebenen Exporte zeigen keine Auslastung mehr.
return x >= schwelleRot() ? 'var(--red)' : x >= schwelleGelb() ? 'var(--amber)' : 'var(--green)';
}
// pdfLoadAmpelColor: Ampel-Farbe für den PDF-Export (js/pdf.js) mit gleichen
// Schwellen wie loadAmpelColor, aber dunkleren, druckfreundlichen Farbtönen.
function pdfLoadAmpelColor(x){
return x >= schwelleRot() ? '#D70015' : x >= schwelleGelb() ? '#B25000' : '#248A3D';
}
// ---------- LP-Aufwand Eingabemaske ----------
@@ -531,14 +513,13 @@ function projektFarbe(name){
// Mittelwert: geteilt wird durch die Zahl der Sitzungen, in denen die Person
// überhaupt im Teilnehmerkreis stand — nicht durch alle vorhandenen.
function renderLoad(){
const scope = document.getElementById('loadScope').value;
const selectedWeek = currentWeek();
const weeks = scope==='all' ? db.weeks : (selectedWeek ? [selectedWeek] : []);
const weeks = selectedWeek ? [selectedWeek] : [];
if(weeks.length === 0){
document.getElementById('loadGrid').innerHTML = '<div class="hint">Keine Sitzung ausgewählt oder die Daten werden noch geladen.</div>';
return;
}
const grouped = scope==='all' ? peopleByRole(db.weeks) : peopleByRole(selectedWeek);
const grouped = peopleByRole(selectedWeek);
const stats = {};
const personen = {}; // fullName -> { person, stunden, rollen:Set }
ROLES.forEach(r=>{