Aufgaben im Wochenbericht, Meilensteine „Erreicht“, Panels als Planblatt

- Wochenbericht: Abschnitt „Aufgaben“ je Projekt (erledigt seit Vorwoche,
  überfällig, nächste zwei Wochen), rote Zahl in der Tagesordnung,
  Tabelle in der PDF-Akte; Klick öffnet das Aufgaben-Panel
- Meilensteine lassen sich als erreicht markieren (plan_milestones.erreicht);
  nur nicht erreichte vergangene gelten als überfällig
- Aufgabe- und Meilenstein-Panel neu aufgebaut: Stand oben, Lage im
  Terminplan, Angaben als Zeilen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
erikandClaude Opus 5.5 committed 2026-11-10 10:41:44 +01:00
1 parent 4ac3d8d53d
commit e12936444d
13 files changed
+693 -137

No files matched your search

+13 -8
View File
@@ -1250,8 +1250,8 @@ function projektStatements(){
VALUES (?, ?, ?, ?)`);
const insTodoDep = db.prepare(`INSERT OR IGNORE INTO plan_todo_deps (week_label, project_id, todo_id, depends_on_id)
VALUES (?, ?, ?, ?)`);
const insMilestone = db.prepare(`INSERT INTO plan_milestones (week_label, project_id, milestone_id, name, date, position, sort_order, notiz)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
const insMilestone = db.prepare(`INSERT INTO plan_milestones (week_label, project_id, milestone_id, name, date, position, sort_order, notiz, erreicht)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
const insMilestoneDep = db.prepare(`INSERT OR IGNORE INTO plan_milestone_deps (week_label, project_id, milestone_id, depends_on_id)
VALUES (?, ?, ?, ?)`);
@@ -1336,7 +1336,7 @@ function serializeProject(weekLabel, p, idx, nowIso){
(Array.isArray(t.dependsOn) ? t.dependsOn : []).forEach(did => insTodoDep.run(weekLabel, projId, String(t.id || ''), String(did || '')));
});
(Array.isArray(plan.milestones) ? plan.milestones : []).forEach((m, midx) => {
insMilestone.run(weekLabel, projId, String(m.id || ''), String(m.name || ''), String(m.date || ''), String(m.position || ''), midx, String(m.notiz || '').slice(0, 20000));
insMilestone.run(weekLabel, projId, String(m.id || ''), String(m.name || ''), String(m.date || ''), String(m.position || ''), midx, String(m.notiz || '').slice(0, 20000), m.erreicht ? 1 : 0);
(Array.isArray(m.dependsOn) ? m.dependsOn : []).forEach(did => insMilestoneDep.run(weekLabel, projId, String(m.id || ''), String(did || '')));
});
}
@@ -1564,7 +1564,7 @@ function loadWeeks(nurLabel){
const msMap = {};
milestones.forEach(r => {
const k = msKey(r.week_label, r.project_id, r.milestone_id);
msMap[k] = { id: r.milestone_id, name: r.name, date: r.date, position: r.position, dependsOn: [], notiz: r.notiz || '' };
msMap[k] = { id: r.milestone_id, name: r.name, date: r.date, position: r.position, dependsOn: [], notiz: r.notiz || '', erreicht: !!r.erreicht };
});
milestoneDeps.forEach(r => {
const m = msMap[msKey(r.week_label, r.project_id, r.milestone_id)];
@@ -1713,7 +1713,7 @@ function dbTableColumns(conn, table){
// Wiederherstellung geschrieben wird, nach einem Versionssprung nicht mehr
// einspielbar.
const IMPORT_OPTIONAL_COLS = ['updated_at', 'project_uid', 'honorar', 'status_author', 'status_at',
'auftragsstatus', 'besprochen', 'leistungsphase', 'aufwand_stunden', 'notiz'];
'auftragsstatus', 'besprochen', 'leistungsphase', 'aufwand_stunden', 'notiz', 'erreicht'];
// restoreDbFromBackup: validiert die Backup-Datei (muss das bekannte Schema
// mit identischen Spalten wie die Live-DB besitzen) und ersetzt den
@@ -2730,6 +2730,12 @@ function migrateAddPlanTodoNotiz(){
db.exec("ALTER TABLE plan_milestones ADD COLUMN notiz TEXT NOT NULL DEFAULT ''");
console.log('plan_milestones um notiz ergänzt.');
}
// erreicht: Meilenstein als erreicht/abgeschlossen markiert — sonst zählt
// ein vergangener Meilenstein auf "Meine Aufgaben" als überfällig.
if(!msCols.includes('erreicht')){
db.exec("ALTER TABLE plan_milestones ADD COLUMN erreicht INTEGER NOT NULL DEFAULT 0");
console.log('plan_milestones um erreicht ergänzt.');
}
}
// migrateAddPlanTodoShowInGantt: rüstet die Spalte `show_in_gantt` nach
@@ -5621,14 +5627,13 @@ app.get('/my-dashboard', requireAuth, (req, res) => {
AND t.project_id IN (${platzhalter})
`).all(weekLabel, ...meineProjekte);
// Meilensteine: sie tragen kein Erledigt-Kennzeichen, deshalb zählt
// allein das Datum.
// Meilensteine: nur die noch nicht erreichten.
const milestones = db.prepare(`
SELECT m.milestone_id AS id, m.name AS titel, m.date AS datum,
m.project_id AS projectId, p.nr AS projectNr, p.name AS projectName
FROM plan_milestones m
JOIN projects p ON p.week_label = m.week_label AND p.project_id = m.project_id
WHERE m.week_label = ? AND m.date != ''
WHERE m.week_label = ? AND m.date != '' AND m.erreicht = 0
AND m.project_id IN (${platzhalter})
`).all(weekLabel, ...meineProjekte);