Plan Checker, Wochenbericht-Fokus-Modus und Wandtafel-Dashboard-Feinschliff

Plan Checker (neues Studenten-Werkzeug, Seitenleiste + Admin → Plan-Checker-
Merkmale): lädt einen Bauplan als PDF hoch und lässt ChatGPT oder Claude ihn
gegen eine gepflegte Merkmalsliste prüfen. PDF-Rendering (pdf.js +
@napi-rs/canvas) berücksichtigt jetzt Ebenen (Optional Content Groups) und
WASM-Decoder korrekt, sendet eine Übersicht plus mehrere hochaufgelöste
Kachel-Ausschnitte statt eines einzelnen, zu groben Bilds, und beide Anbieter
bekommen dasselbe Bildmaterial. Jedes Prüfergebnis kann auf eines der
gesendeten Bilder als Beleg verweisen (bildIndex) — als Screenshot im
Ergebnis anklickbar, öffnet vergrößert in einem Modal statt eines von Chrome
blockierten target=_blank-Links auf eine data:-URL. KI-Modellname ist jetzt
pro Konto überschreibbar (Einstellungen → Mein Konto) für Drittanbieter mit
abweichendem Modell-Katalog.

Wochenbericht: dichte Kartenansicht bekommt einen Fokus-Modus — nur der
Kommentar liegt offen, Leistungsphasen und Beteiligte stecken in
aufklappbaren Abschnitten statt dauerhaft nebeneinander zu stehen.

Projektbereich: Terminplan-Auslastung rechnet jetzt exakt wie der
Auslastungs-Tab/die Wandtafel (statt einer unabhängigen, tageweisen
Schätzung); die LPH-Fortschrittsliste im Dashboard zeigt nur noch die
beauftragten Leistungsphasen.

Wandtafel: Dashboard-Kopf mit Kennzahlen-Reihe und Panel-Reihe neu
strukturiert, in den Blautönen des Firmenlogos; dieselbe Palette wurde
anschließend auf den gesamten App-weiten Dark Mode übernommen.

Dateibereinigung: nicht mehr benötigte Test-Uploads/Backups entfernt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
erikandClaude Sonnet 5 committed 2026-10-05 14:01:41 +02:00
1 parent db63a29365
commit 6ba93b2a92
308 files changed
+64441 -743

No files matched your search

+113 -4
View File
@@ -34,8 +34,12 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Projektübersicht</title>
<link rel="stylesheet" href="/styles.css?v=62">
<link rel="stylesheet" href="/styles.css?v=64">
<link rel="stylesheet" href="/plan-styles.css?v=19">
<!-- Fredoka/Nunito Sans: nur für die Wandtafel (js/wand/wand.js), siehe ihren
Dateikopf — fällt ohne Internetzugang automatisch auf die System-Schrift
zurück (font-family-Stack in styles.css), bricht also nichts offline. -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600;700&family=Nunito+Sans:wght@400;600;700;800&display=swap">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.10/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.10/vfs_fonts.js"></script>
</head>
@@ -139,6 +143,16 @@
<span class="nav-icon"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="4" width="17" height="17" rx="2.5"/><line x1="3.5" y1="9.5" x2="20.5" y2="9.5"/><line x1="8" y1="2.5" x2="8" y2="6.5"/><line x1="16" y1="2.5" x2="16" y2="6.5"/><line x1="7" y1="14" x2="12" y2="14"/><line x1="7" y1="17.5" x2="15" y2="17.5"/></svg></span></span><span class="nav-label">Planung</span>
</button>
<!-- Studenten: eigener, dritter Abschnitt (wie "Planung" nicht Teil
von "Navigation") — bislang nur ein Werkzeug, der Plan Checker:
lädt einen Bauplan als PDF hoch und lässt ihn von einer KI gegen
eine Liste von Merkmalen prüfen (Maßketten, Plankopf, ...),
siehe js/planchecker/planchecker.js. -->
<div class="sidebar-section-label">Studenten</div>
<button class="nav-item tab" data-tab="planchecker" onclick="showTab('planchecker')" title="Plan Checker">
<span class="nav-icon"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="m9 12 2 2 4-4"/></svg></span></span><span class="nav-label">Plan Checker</span>
</button>
<hr class="sidebar-nav-divider">
<!-- Einstellungen: seit die firmenweiten Masken in den Admin-Bereich
@@ -196,6 +210,7 @@
<button class="menu-item sidebar-subitem" data-admin-section="termine" onclick="showAdminSection('termine')">Termine &amp; Sitzungen</button>
<button class="menu-item sidebar-subitem" data-admin-section="feiertage" onclick="showAdminSection('feiertage')">Feiertage</button>
<button class="menu-item sidebar-subitem" data-admin-section="vorlagen" onclick="showAdminSection('vorlagen')">Aufgaben-Vorlagen</button>
<button class="menu-item sidebar-subitem" data-admin-section="planchecker" onclick="showAdminSection('planchecker')">Plan-Checker-Merkmale</button>
<button class="menu-item sidebar-subitem" data-admin-section="betrieb" onclick="showAdminSection('betrieb')">Betrieb &amp; Sicherheit</button>
<button class="menu-item sidebar-subitem" data-admin-section="datenbank" onclick="showAdminSection('datenbank')">Datenbank &amp; Sitzungen</button>
</div>
@@ -282,6 +297,69 @@
<div id="planungList"></div>
</div>
<!-- PLAN CHECKER (js/planchecker/planchecker.js) — Studenten-Werkzeug: lädt
einen Bauplan als PDF hoch und lässt eine KI ihn gegen die unter
Admin → Plan-Checker-Merkmale gepflegten Merkmale prüfen. Weder die
Datei noch das Ergebnis werden gespeichert — ein Ad-hoc-Werkzeug, kein
Dokumentenarchiv (siehe POST /plan-checker-pruefen, server.js). -->
<div id="planchecker" style="display:none">
<div class="section-title">Plan Checker</div>
<p class="hint">Lädt einen Bauplan als PDF hoch und prüft ihn mit einer KI gegen die hinterlegten Merkmale.</p>
<div class="pc-layout">
<div class="pc-panel">
<label class="pc-drop" id="planCheckerDrop" for="planCheckerFile"
ondragover="planCheckerDragOver(event)" ondragleave="planCheckerDragLeave(event)" ondrop="planCheckerDrop(event)">
<span id="planCheckerDropText">PDF hierher ziehen oder klicken</span>
<div class="pc-drop-name" id="planCheckerDateiname" hidden></div>
</label>
<input type="file" id="planCheckerFile" accept="application/pdf" hidden onchange="planCheckerDateiGewaehlt(this.files[0])">
<div class="pc-section">
<label class="pc-label">Geprüfte Merkmale</label>
<div id="planCheckerMerkmaleListe"><span class="hint" style="margin:0">Lade Merkmale…</span></div>
<div class="pc-zusatz">
<input type="text" class="pc-input" id="planCheckerZusatz" placeholder="Weiteres Merkmal für diese Prüfung…">
</div>
</div>
<div class="pc-section">
<label class="pc-label">KI-Anbieter</label>
<select id="planCheckerAnbieter" class="pc-select" style="width:100%"></select>
</div>
<div class="pc-section">
<button type="button" class="pc-btn-primary pc-btn" id="planCheckerPruefenBtn" onclick="planCheckerPruefen()" style="width:100%">Plan prüfen</button>
<p class="hint pc-error" id="planCheckerError" hidden></p>
</div>
</div>
<div class="pc-panel pc-results">
<div class="pc-results-empty" id="planCheckerLeer">
<span class="big">Noch kein Plan geprüft</span>
PDF auswählen und auf „Plan prüfen" klicken.
</div>
<div id="planCheckerErgebnis"></div>
</div>
</div>
</div>
<!-- Plan Checker: Planausschnitt-Vorschau (js/planchecker/planchecker.js,
planCheckerZeigeScreenshot()) — zeigt den Screenshot vergrößert, den
die KI für ein Merkmal als Beleg gewählt hat. Ein einfaches In-Page-
Modal statt eines <a target="_blank"> auf die data:-URL: Chrome
blockiert das Öffnen einer data:-URL als Top-Level-Navigation in einem
neuen Tab, ein Link blieb deshalb wirkungslos. -->
<div class="modal-bg" id="pcShotModal" style="display:none">
<div class="modal modal-wide">
<h2 id="pcShotModalTitel">Planausschnitt</h2>
<img id="pcShotModalImg" src="" alt="" style="width:100%;height:auto;border-radius:var(--r-md);display:block">
<div class="toolbar" style="margin-top:16px">
<button class="secondary" onclick="planCheckerSchliesseScreenshot()">Schließen</button>
</div>
</div>
</div>
<!-- DASHBOARD (Begrüßung/Uhr, Meine Aufgaben, Freigaben, Kollegen-Abwesenheiten) -->
<div id="dashboard" style="display:none">
<div id="dashboardContent"></div>
@@ -381,6 +459,18 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 13 10 18 19 7"/></svg>
</button>
</div>
<!-- Modellname: nur nötig, wenn der eigene Server/Anbieter einen
bestimmten Namen erwartet (z. B. ein eigenständiger Anbieter
wie Mammouth.ai mit eigenem Modell-Katalog, bei dem der feste
OpenAI-Name "gpt-4o"/"gpt-4o-mini" nicht existiert) - leer
bedeutet weiterhin die hier hinterlegte Vorgabe. -->
<label>Modellname (optional)</label>
<div class="ai-provider-row">
<input type="text" id="setAiOpenaiModel" placeholder="leer = Vorgabe (gpt-4o-mini / gpt-4o)">
<button class="ai-icon-btn" onclick="saveMyAiModell('chatgpt')" title="Modellname speichern">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 13 10 18 19 7"/></svg>
</button>
</div>
</div>
</div>
@@ -416,6 +506,13 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 13 10 18 19 7"/></svg>
</button>
</div>
<label>Modellname (optional)</label>
<div class="ai-provider-row">
<input type="text" id="setAiClaudeModel" placeholder="leer = Vorgabe (claude-haiku-4-5 / claude-sonnet-5)">
<button class="ai-icon-btn" onclick="saveMyAiModell('claude')" title="Modellname speichern">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 13 10 18 19 7"/></svg>
</button>
</div>
</div>
</div>
@@ -582,6 +679,17 @@
<button class="secondary small" onclick="addTemplateEntry()">+ Schritt</button>
</div>
</section>
<section class="settings-card settings-card-wide" id="adminPlanCheckerCard" data-admin-section="planchecker" style="display:none">
<h3 class="settings-card-title">Plan-Checker-Merkmale <span class="settings-scope">firmenweit · nur Administratoren</span></h3>
<p class="hint">Die Grundliste, gegen die der Plan Checker (Bereich „Studenten") jeden hochgeladenen Plan prüft.
„Prüfanweisung" geht wortwörtlich an die KI — „Titel" ist zugleich die Anzeige-Bezeichnung.</p>
<div id="planCheckerMerkmaleAdminListe" class="template-admin-list"></div>
<div class="template-add-row">
<input type="text" id="merkmalNeuTitel" placeholder="Titel, z. B. „Maßketten vorhanden“">
<input type="text" id="merkmalNeuPrompt" placeholder="Prüfanweisung für die KI" style="flex:2">
<button class="secondary small" onclick="addPlanCheckerMerkmal()">+ Merkmal</button>
</div>
</section>
<section class="settings-card settings-card-wide" id="adminUsersCard" data-admin-section="benutzer" style="display:none">
<h3 class="settings-card-title">Benutzerverwaltung <span class="settings-scope">nur Administratoren</span></h3>
<p class="hint">Konten anlegen, bearbeiten, deaktivieren, Passwoerter zuruecksetzen und
@@ -1618,6 +1726,7 @@
<script src="/js/wochenbericht/wochenbericht.js?v=20"></script>
<script src="/js/people/people.js?v=7"></script>
<script src="/js/planung/planung.js?v=1"></script>
<script src="/js/planchecker/planchecker.js?v=1"></script>
<script src="/js/projects/projects.js?v=7"></script>
<script src="/js/load/load.js?v=18"></script>
<!-- auftrag.js: Auftragsstatus und Dialog "Beauftragung". Nach load.js, weil
@@ -1633,7 +1742,7 @@
relativerTag()/tageBis()/initialsFor() (dashboard.js) — alle laden
bereits vorher, die Reihenfolge hier ist also nur Zuordnung zum
Tab-Ordner, keine neue Abhängigkeit nach vorn. -->
<script src="/js/wand/wand.js?v=11"></script>
<script src="/js/wand/wand.js?v=12"></script>
<script src="/js/settings/settings.js?v=9"></script>
<script src="/js/admin/admin.js?v=11"></script>
<script src="/js/admin-users.js?v=4"></script>
@@ -1647,10 +1756,10 @@
umhuellt. -->
<script src="/js/plan/plan-state.js?v=12"></script>
<script src="/js/plan/plan-sections.js?v=5"></script>
<script src="/js/plan/plan-info.js?v=7"></script>
<script src="/js/plan/plan-info.js?v=8"></script>
<script src="/js/plan/plan-history.js?v=3"></script>
<script src="/js/plan/plan-build-gantt.js?v=7"></script>
<script src="/js/plan/plan-gantt.js?v=9"></script>
<script src="/js/plan/plan-gantt.js?v=10"></script>
<script src="/js/plan/plan-drag.js?v=6"></script>
<script src="/js/plan/plan-modals.js?v=7"></script>
<script src="/js/plan/plan-tasks.js?v=2"></script>