Termin aus Mail, Rollen & Rechte, Abwesenheiten, Glas-Darstellung und Pi-Betrieb
- Termin aus Mail: Mailtext oder .eml per Drag & Drop/Strg+V auf Terminplan oder Aufgaben, KI schlägt Aufgaben vor, Prüfung im Aufgaben-Panel; neues Notizfeld je Aufgabe (plan_todos.notiz) - Terminplan: Meilensteine ohne Aufgabenbezug je in eigener Zeile, "+ Neu"-Menü klappt neben schmaler Seitenleiste nach rechts, Leistungsphasen - Rollen & Rechte, Abwesenheiten-Seite, Benachrichtigungen, Rundgang - Glas-Darstellung, Logo als Favicon - Pi-Betrieb: PDF-Arbeit im Kindprozess, Wächter, Einrichtungs- und Prüfskript inkl. WLAN-Wächter Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4fb3c550b
commit
b7e0bd0d92
56 files changed
+12265
-2974
No files matched your search
+136
-6
@@ -70,9 +70,109 @@
|
||||
// amtierende Leistungsphase, LPH-Prozentliste) aus app.project auf. Wird
|
||||
// nach jedem Laden (renderPlanPage(), plan-state.js) sowie nach jeder
|
||||
// Änderung hier selbst erneut aufgerufen. Keine Parameter, keine Rückgabe.
|
||||
// ---------------------------------------------------------------------------
|
||||
// Kommentar-Verlauf im Projekt-Dashboard
|
||||
// ---------------------------------------------------------------------------
|
||||
// planKommentarDaten: sucht über alle Sitzungen dieses Projekts (bis
|
||||
// einschließlich der angezeigten) den jüngsten Kommentar und listet die
|
||||
// früheren je Gewerk. Ein Eintrag im Verlauf entsteht nur, wenn sich der
|
||||
// Text eines Gewerks gegenüber der Sitzung davor geändert hat — ein
|
||||
// unverändert mitgeführter Kommentar stünde sonst jede Woche erneut da.
|
||||
// Rückgabe: { letzter: {week, k, aktuell} | null, verlauf: [{week, gewerk, html, autor, at}] }
|
||||
function planKommentarDaten(p, week){
|
||||
const bisKey = week && week.label ? weekSortKey(week.label) : null;
|
||||
let versionen = (typeof projectVersionsForUid === 'function' && p.projectUid)
|
||||
? projectVersionsForUid(p.projectUid).filter(v => !bisKey || weekSortKey(v.week.label) <= bisKey)
|
||||
: [];
|
||||
// Angezeigte Sitzung immer mit dem lebenden Projektobjekt (Sandbox, oder
|
||||
// ein Projekt, das in db.weeks noch nicht steht).
|
||||
versionen = versionen.filter(v => !week || v.week.label !== week.label);
|
||||
versionen.push({ week: week || { label: '' }, project: p });
|
||||
|
||||
let letzter = null;
|
||||
for(let i = versionen.length - 1; i >= 0; i--){
|
||||
const k = kommentarVon(versionen[i].project, null);
|
||||
if(statusPlainText(k.status)){
|
||||
letzter = { week: versionen[i].week, k, aktuell: i === versionen.length - 1 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const gewerke = (typeof DEPARTMENTS === 'object' && DEPARTMENTS) ? Object.keys(DEPARTMENTS) : ['ELT','HLS','ARCH'];
|
||||
const verlauf = [];
|
||||
gewerke.forEach(g => {
|
||||
let vorher = '';
|
||||
versionen.forEach(v => {
|
||||
const k = kommentarVon(v.project, g);
|
||||
const text = statusPlainText(k.status);
|
||||
if(text && text !== vorher && !(letzter && v.week === letzter.week)){
|
||||
verlauf.push({ week: v.week, gewerk: g, html: sanitizeStatusHtml(k.status), autor: k.statusAuthor || '', at: k.statusAt || '' });
|
||||
}
|
||||
vorher = text;
|
||||
});
|
||||
});
|
||||
// Derselbe Text in mehreren Gewerken derselben Sitzung (Altbestand: die
|
||||
// Umstellung auf Kommentare je Gewerk hat ihn in jedes kopiert) wird ein
|
||||
// Eintrag mit allen Gewerken, statt zweimal untereinander zu stehen.
|
||||
const zusammen = [];
|
||||
verlauf.forEach(e => {
|
||||
const gleich = zusammen.find(z => z.week === e.week && statusPlainText(z.html) === statusPlainText(e.html));
|
||||
if(gleich){ gleich.gewerk += ', ' + e.gewerk; if(!gleich.autor) gleich.autor = e.autor; }
|
||||
else zusammen.push(Object.assign({}, e));
|
||||
});
|
||||
zusammen.sort((a, b) => weekSortKey(b.week.label).localeCompare(weekSortKey(a.week.label))
|
||||
|| String(b.at).localeCompare(String(a.at)));
|
||||
return { letzter, verlauf: zusammen };
|
||||
}
|
||||
|
||||
// "KW 43 / 2026" -> "KW 43" (das Jahr nur, wenn es nicht das laufende ist)
|
||||
function kurzKw(label){
|
||||
const m = /^(KW\s*\d+)\s*\/\s*(\d{4})$/.exec(String(label || '').trim());
|
||||
if(!m) return label || '';
|
||||
return m[2] === String(new Date().getFullYear()) ? m[1] : m[1] + ' / ' + m[2];
|
||||
}
|
||||
|
||||
const PLAN_VERLAUF_KURZ = 3;
|
||||
let planVerlaufAlle = false;
|
||||
let planVerlaufProjekt = null;
|
||||
|
||||
function renderPlanKommentarVerlauf(verlauf){
|
||||
const el = document.getElementById('planStatusVerlauf');
|
||||
if(!el) return;
|
||||
const uid = app.project && (app.project.projectUid || app.project.id);
|
||||
if(uid !== planVerlaufProjekt){ planVerlaufProjekt = uid; planVerlaufAlle = false; }
|
||||
if(!verlauf.length){ el.hidden = true; el.innerHTML = ''; return; }
|
||||
el.hidden = false;
|
||||
const zeigen = planVerlaufAlle ? verlauf : verlauf.slice(0, PLAN_VERLAUF_KURZ);
|
||||
const zeilen = zeigen.map((e, i) => `
|
||||
<li class="plan-verlauf-eintrag${i === 0 ? ' ist-juengster' : ''}">
|
||||
<span class="plan-verlauf-kw">${esc(kurzKw(e.week.label))}</span>
|
||||
<span class="plan-verlauf-punkt" aria-hidden="true"></span>
|
||||
<div class="plan-verlauf-inhalt">
|
||||
<div class="plan-verlauf-text">${e.html}</div>
|
||||
<div class="plan-verlauf-meta">${esc(e.gewerk)}${e.autor ? ' · ' + esc(e.autor) : ''}</div>
|
||||
</div>
|
||||
</li>`).join('');
|
||||
const mehr = verlauf.length > PLAN_VERLAUF_KURZ
|
||||
? `<button type="button" class="plan-verlauf-mehr" onclick="planVerlaufUmschalten()">${planVerlaufAlle ? 'Weniger anzeigen' : 'Alle ' + verlauf.length + ' anzeigen'}</button>`
|
||||
: '';
|
||||
el.innerHTML = `
|
||||
<div class="plan-verlauf-kopf">
|
||||
<span class="plan-verlauf-titel">Verlauf</span>
|
||||
<span class="plan-verlauf-anzahl">${verlauf.length === 1 ? '1 früherer Kommentar' : verlauf.length + ' frühere Kommentare'}</span>
|
||||
</div>
|
||||
<ol class="plan-verlauf-liste">${zeilen}</ol>${mehr}`;
|
||||
}
|
||||
|
||||
window.planVerlaufUmschalten = function(){
|
||||
planVerlaufAlle = !planVerlaufAlle;
|
||||
window.renderPlanInfo();
|
||||
};
|
||||
|
||||
|
||||
window.renderPlanInfo = function(){
|
||||
const p = app.project;
|
||||
const locked = app.isLocked();
|
||||
const locked = app.stammGesperrt();
|
||||
|
||||
// Kommentar, Fortschritt und Zuordnung sind hier NUR ZU SEHEN.
|
||||
//
|
||||
@@ -83,15 +183,42 @@
|
||||
// Personen konnten dasselbe Feld an verschiedenen Stellen pflegen.
|
||||
// Was hier bleibt, sind die Stammdaten des Projekts (Bereich
|
||||
// "Einstellungen", siehe plan-settings.js).
|
||||
// Gezeigt wird der ZULETZT GESCHRIEBENE Kommentar (Eriks Wunsch, Entwurf
|
||||
// "A"): Hat die Sitzung noch keinen, der jüngste aus einer früheren — mit
|
||||
// Hinweis, aus welcher. Darunter der Verlauf der früheren Kommentare.
|
||||
const kom = planKommentarDaten(p, app.week);
|
||||
const editEl = document.getElementById('planStatusEdit');
|
||||
if(editEl){
|
||||
editEl.className = 'status-edit is-ansicht';
|
||||
editEl.contentEditable = 'false';
|
||||
const text = sanitizeStatusHtml(p.status || '');
|
||||
editEl.innerHTML = text || '<span class="hint" style="margin:0">Für diese Sitzung ist noch kein Kommentar erfasst.</span>';
|
||||
// Alle Gewerke zusammen, je mit Gewerk davor (kommentarVon(), js/utils.js).
|
||||
const text = kom.letzter ? sanitizeStatusHtml(kom.letzter.k.status) : '';
|
||||
editEl.innerHTML = text || '<span class="hint" style="margin:0">Zu diesem Projekt ist noch kein Kommentar erfasst.</span>';
|
||||
}
|
||||
const hinweisEl = document.getElementById('planStatusHinweis');
|
||||
if(hinweisEl){
|
||||
const aelter = kom.letzter && !kom.letzter.aktuell;
|
||||
hinweisEl.hidden = !aelter;
|
||||
hinweisEl.innerHTML = aelter
|
||||
? `In dieser Sitzung noch kein Kommentar — angezeigt wird der letzte aus <b>${esc(kurzKw(kom.letzter.week.label))}</b>.`
|
||||
: '';
|
||||
}
|
||||
// Wer den Kommentar wann geschrieben hat (jüngster Eintrag aller Gewerke).
|
||||
const autorEl = document.getElementById('planStatusAutor');
|
||||
if(autorEl){
|
||||
const k = kom.letzter ? kom.letzter.k : {};
|
||||
autorEl.innerHTML = k.status && k.statusAuthor
|
||||
? `<span class="plan-autor-ava">${esc(initialsForName(k.statusAuthor))}</span>${esc(k.statusAuthor)}`
|
||||
+ (k.statusAt && typeof formatCommentStamp === 'function' ? ', ' + esc(formatCommentStamp(k.statusAt)) : '')
|
||||
: '';
|
||||
}
|
||||
renderPlanKommentarVerlauf(kom.verlauf);
|
||||
const statusWrap = document.getElementById('planStatusWrap');
|
||||
if(statusWrap) statusWrap.classList.add('locked-cell');
|
||||
// Nicht mehr als gesperrt markieren: .locked-cell dimmt auf 55 % und legt im
|
||||
// Dunkelmodus ein Grau darunter — der Kommentar war dadurch kaum lesbar.
|
||||
// Dass er hier nur angezeigt wird, zeigen schon .is-ansicht und der
|
||||
// Verweis "Im Wochenbericht bearbeiten".
|
||||
if(statusWrap) statusWrap.classList.remove('locked-cell');
|
||||
setzeBerichtVerweis('planStatusVerweis', locked);
|
||||
|
||||
// Gruppe — Stammdatum, bleibt hier pflegbar
|
||||
@@ -176,7 +303,7 @@
|
||||
// setPlanGroup: ändert die Gruppe des Projekts. Parameter: val (String).
|
||||
// Keine Rückgabe; bei gesperrter Woche abgebrochen.
|
||||
window.setPlanGroup = function(val){
|
||||
if(app.isLocked()) return;
|
||||
if(app.stammGesperrt()) return;
|
||||
app.project.group = val;
|
||||
app.savePlan();
|
||||
};
|
||||
@@ -185,11 +312,14 @@
|
||||
// Projekts auf. Parameter: val (LPH-Name oder leer). Rendert das
|
||||
// Infopanel neu, damit die Markierung in der LPH-Liste sofort mitzieht.
|
||||
window.setPlanActiveLp = function(val){
|
||||
if(app.isLocked()) return;
|
||||
if(app.stammGesperrt()) return;
|
||||
if(val) app.project.aktuelleLP = [val];
|
||||
else delete app.project.aktuelleLP;
|
||||
app.savePlan();
|
||||
window.renderPlanInfo();
|
||||
// Abschnitt "Leistungsphasen" der Einstellungen: Kennzeichen "läuft"
|
||||
// und die Kurzfassung in der Unternavigation nachziehen.
|
||||
if(typeof renderPlanSettings === 'function') renderPlanSettings();
|
||||
};
|
||||
|
||||
// Die Schreibfunktionen setPlanLph()/setPlanAssign()/planStatusBlur() sind
|
||||
|
||||
Reference in new issue
Block a user