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:
1 parent
db63a29365
commit
6ba93b2a92
308 files changed
+64441
-743
No files matched your search
+52
-21
@@ -28,6 +28,22 @@
|
||||
// persistiert — jede Sitzung startet mit eingeklappten Zeilen.
|
||||
let boardRowOpen = {};
|
||||
|
||||
// berichtDisclosureState: merkt sich je Abschnitt (Leistungsphasen, Beteiligte,
|
||||
// Anwesenheit), ob er im Wochenbericht (Fokus-Modus — Eriks Wahl "C" aus dem
|
||||
// Darstellungs-Vergleich: renderBoardDrawer()s dichte Fassung weiter unten +
|
||||
// renderAttendance() in js/wochenbericht/wochenbericht.js) gerade auf- oder
|
||||
// zugeklappt ist. Ohne dieses Gedächtnis klappte jeder Abschnitt bei jedem
|
||||
// Neu-Rendern wieder auf seinen Vorgabewert zurück — und JEDE Änderung in der
|
||||
// Schublade (eine Zuordnung, ein LPH-Wert) baut den ganzen Bericht neu auf.
|
||||
// 'toggle' bubbelt nicht, ein Lauscher in der Capture-Phase sieht das
|
||||
// Ereignis trotzdem auf dem Weg nach unten (gleiches Muster wie der
|
||||
// scroll-Lauscher der Wandtafel).
|
||||
const berichtDisclosureState = { lph: true, beteiligte: false, anwesenheit: false };
|
||||
document.addEventListener('toggle', function(e){
|
||||
const key = e.target && e.target.dataset && e.target.dataset.berichtAbschnitt;
|
||||
if(key) berichtDisclosureState[key] = e.target.open;
|
||||
}, true);
|
||||
|
||||
// toggleBoardRow: klappt das Detailpanel einer Projekt-Zeile auf bzw. zu.
|
||||
// Parameter: pid (Projekt-ID). Keine Rückgabe.
|
||||
function toggleBoardRow(pid){
|
||||
@@ -500,34 +516,49 @@ function renderBoardDrawer(p, allPeople, locked, weekLabel, opts){
|
||||
return `<div class="board-role-row"><span class="board-role-label ${roleClass(r)}">${esc(r)}</span><div class="board-role-chips">${chips}</div></div>`;
|
||||
}).join('');
|
||||
|
||||
// Dichte Fassung: zwei Spalten — links der Kommentar, rechts die
|
||||
// Leistungsphasen-Leiste und darunter die Beteiligten.
|
||||
//
|
||||
// Zwischenzeitlich waren es drei Spalten, weil die gestapelten Beteiligten
|
||||
// die Karte höher machten und damals 29 Karten untereinander standen. Seit
|
||||
// der Wochenbericht eine Tagesordnung ist, ist immer nur EIN Projekt
|
||||
// geöffnet — die Höhe der Karte kostet nichts mehr, während die Breite
|
||||
// knapp ist: Neben der Projektliste blieben für drei Spalten nur noch
|
||||
// 137 px für die Beteiligten, zu wenig für Rollenname und Kürzel.
|
||||
// Dichte Fassung (Wochenbericht): erst zwei, dann drei Spalten nebeneinander
|
||||
// — bei 29 Projekten mit allem gleichzeitig sichtbar kam von Erik die
|
||||
// Rückmeldung "zu überladen". Jetzt (Fokus-Modus, Eriks Wahl "C" aus dem
|
||||
// Darstellungs-Vergleich) liegt nur der Kommentar offen, Leistungsphasen
|
||||
// und Beteiligte stecken in aufklappbaren Abschnitten untereinander.
|
||||
//
|
||||
// Die Beteiligten behalten ihre Zeile je Rolle — anders als im Entwurf, wo
|
||||
// sie zu einer flachen Reihe zusammengefasst waren: Ein Kürzel kann in
|
||||
// mehreren Rollen vorkommen, und cycleAssign() braucht die Rolle. Ohne sie
|
||||
// wäre beim Klicken nicht erkennbar, welche Zuordnung man durchschaltet.
|
||||
if(opts && opts.dicht){
|
||||
// Fokus-Modus (Eriks Wahl "C" aus dem Darstellungs-Vergleich): nur der
|
||||
// Kommentar liegt offen, Leistungsphasen und Beteiligte stecken in
|
||||
// aufklappbaren Abschnitten (<details>, Zustand in berichtDisclosureState)
|
||||
// statt dauerhaft nebeneinander zu stehen. Die Leistungsphasen stehen hier
|
||||
// als Balkenzeilen (bericht-lph-row) statt als Kästchen-Leiste
|
||||
// (board-lph-leiste bleibt die Darstellung des Projektboards, unverändert).
|
||||
const lphBarRows = sichtbareLphs.map(l=>{
|
||||
const v = (p.lph[l]!==undefined && p.lph[l]!="") ? p.lph[l] : "";
|
||||
const aktiv = l === aktLp;
|
||||
const inputAttr = starr ? 'readonly tabindex="-1"' : `onchange="editLph('${p.id}','${l}',this.value)"`;
|
||||
const pct = v !== "" ? Math.min(100, parseFloat(v)||0) : 0;
|
||||
return `<div class="bericht-lph-row${aktiv ? ' is-aktiv' : ''}">
|
||||
<span class="bericht-lph-label">${esc(l.replace('LPH ', 'LP '))}</span>
|
||||
<span class="bericht-lph-track"><i style="width:${pct}%"></i></span>
|
||||
<span class="bericht-lph-pct"><input type="text" class="bericht-lph-input${locked ? ' locked-cell' : ''}" value="${esc(v)}" ${inputAttr} placeholder="-">%</span>
|
||||
</div>`;
|
||||
}).join('');
|
||||
const lphInfo = aktLp
|
||||
? esc(aktLp.replace('LPH ', 'LP ')) + ' aktiv' + (p.lph[aktLp] !== undefined && p.lph[aktLp] !== '' ? ' · ' + esc(p.lph[aktLp]) + '%' : '')
|
||||
: 'Keine aktive Leistungsphase';
|
||||
const zugeordnetAnzahl = allPeople.filter(e => (p.assign[assignKey(e.person.id, e.role)] || 0) > 0).length;
|
||||
|
||||
return `<div class="board-drawer board-drawer-dicht">
|
||||
<div class="board-drawer-grid">
|
||||
<div class="drawer-col drawer-col-comment">
|
||||
<h4>Kommentar${weekLabel ? ' zur Sitzung ' + esc(weekLabel) : ''}</h4>
|
||||
${renderCommentEditor(p, weekLabel, locked, true)}
|
||||
</div>
|
||||
<div class="drawer-col drawer-col-kompakt">
|
||||
<h4>${nurBeauftragte ? 'Beauftragte Leistungsphasen' : 'Leistungsphasen'}</h4>
|
||||
<div class="board-lph-leiste">${lphLeiste}</div>
|
||||
<h4 class="drawer-h4-zweit">Beteiligte</h4>
|
||||
<div class="board-role-mini">${roleRows}</div>
|
||||
</div>
|
||||
</div>
|
||||
${renderCommentEditor(p, weekLabel, locked, true)}
|
||||
<details class="bericht-disclosure" data-bericht-abschnitt="lph" ${berichtDisclosureState.lph ? 'open' : ''}>
|
||||
<summary><span>${nurBeauftragte ? 'Beauftragte Leistungsphasen' : 'Leistungsphasen'}</span><span class="count">${lphInfo}</span><span class="chev">${icon('chevronRight')}</span></summary>
|
||||
<div class="bericht-disclosure-body">${lphBarRows}</div>
|
||||
</details>
|
||||
<details class="bericht-disclosure" data-bericht-abschnitt="beteiligte" ${berichtDisclosureState.beteiligte ? 'open' : ''}>
|
||||
<summary><span>Beteiligte</span><span class="count">${zugeordnetAnzahl} zugeordnet</span><span class="chev">${icon('chevronRight')}</span></summary>
|
||||
<div class="bericht-disclosure-body"><div class="board-role-mini">${roleRows}</div></div>
|
||||
</details>
|
||||
${typeof renderProjektVerlauf === 'function' ? renderProjektVerlauf(p, weekLabel, locked) : ''}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user