Verwaltung: Backend auf Lazyloading der Kalenderwochen umgestellt
This commit is contained in:
@@ -44,7 +44,7 @@ function registerVerwaltungRoutes(app) {
|
||||
}
|
||||
|
||||
// Gruppiere nach Mitarbeiter, dann nach Kalenderwoche
|
||||
// Struktur: { [user_id]: { user: {...}, weeks: { [week_key]: {...} } } }
|
||||
// Struktur intern: { [user_id]: { user: {...}, weeks: { [week_key]: {...} } } }
|
||||
const groupedByEmployee = {};
|
||||
|
||||
(timesheets || []).forEach(ts => {
|
||||
@@ -86,7 +86,6 @@ function registerVerwaltungRoutes(app) {
|
||||
// Prüfe für jede Woche, ob nach dem letzten Download eine neue Version eingereicht wurde
|
||||
Object.values(groupedByEmployee).forEach(employee => {
|
||||
Object.values(employee.weeks).forEach(week => {
|
||||
// Finde die neueste Version mit pdf_downloaded_at (letzter Download)
|
||||
let lastDownloadTime = null;
|
||||
week.versions.forEach(version => {
|
||||
if (version.pdf_downloaded_at) {
|
||||
@@ -96,8 +95,7 @@ function registerVerwaltungRoutes(app) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Prüfe, ob es eine Version gibt, die nach dem letzten Download eingereicht wurde
|
||||
|
||||
let hasNewVersionAfterDownload = false;
|
||||
if (lastDownloadTime) {
|
||||
week.versions.forEach(version => {
|
||||
@@ -109,26 +107,29 @@ function registerVerwaltungRoutes(app) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Setze Flag auf dem week-Objekt
|
||||
|
||||
week.has_new_version_after_download = hasNewVersionAfterDownload;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Sortierung: Mitarbeiter nach Name, Wochen nach Datum (neueste zuerst)
|
||||
const sortedEmployees = Object.values(groupedByEmployee).map(employee => {
|
||||
// Wochen innerhalb jedes Mitarbeiters sortieren
|
||||
// Für das Initial-Rendering der Verwaltung werden nur Mitarbeiter-Header-Daten
|
||||
// benötigt. Wochen-/Versionslisten werden per AJAX nachgeladen.
|
||||
const employeesForView = Object.values(groupedByEmployee).map(employee => {
|
||||
const sortedWeeks = Object.values(employee.weeks).sort((a, b) => {
|
||||
return new Date(b.week_start) - new Date(a.week_start);
|
||||
});
|
||||
|
||||
// Flag: Gibt es in irgendeiner Woche eine neue Version nach Download?
|
||||
const hasNewVersionAfterDownload = sortedWeeks.some(w => w.has_new_version_after_download);
|
||||
|
||||
const weekCount = sortedWeeks.length;
|
||||
const latestWeek = weekCount > 0 ? sortedWeeks[0] : null;
|
||||
|
||||
return {
|
||||
...employee,
|
||||
user: employee.user,
|
||||
has_new_version_after_download: hasNewVersionAfterDownload,
|
||||
weeks: sortedWeeks
|
||||
weekCount,
|
||||
latest_week_start: latestWeek ? latestWeek.week_start : null,
|
||||
latest_week_end: latestWeek ? latestWeek.week_end : null
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
// Mitarbeiter nach Nachname, dann Vorname sortieren
|
||||
@@ -138,7 +139,7 @@ function registerVerwaltungRoutes(app) {
|
||||
});
|
||||
|
||||
res.render('verwaltung', {
|
||||
groupedByEmployee: sortedEmployees,
|
||||
groupedByEmployee: employeesForView,
|
||||
user: {
|
||||
firstname: req.session.firstname,
|
||||
lastname: req.session.lastname,
|
||||
@@ -149,6 +150,122 @@ function registerVerwaltungRoutes(app) {
|
||||
});
|
||||
});
|
||||
|
||||
// API: Wochen + Versionen für einen Mitarbeiter (für Lazy-Loading in der Verwaltung)
|
||||
app.get('/api/verwaltung/employee/:id/weeks', requireVerwaltung, (req, res) => {
|
||||
const userId = parseInt(req.params.id, 10);
|
||||
if (!Number.isFinite(userId)) {
|
||||
return res.status(400).send('Ungültige User-ID');
|
||||
}
|
||||
|
||||
db.all(`
|
||||
SELECT wt.*, u.firstname, u.lastname, u.username, u.personalnummer, u.wochenstunden, u.urlaubstage, u.overtime_offset_hours, u.vacation_offset_days, u.arbeitstage,
|
||||
dl.firstname as downloaded_by_firstname,
|
||||
dl.lastname as downloaded_by_lastname,
|
||||
(SELECT COUNT(*) FROM weekly_timesheets wt2
|
||||
WHERE wt2.user_id = wt.user_id
|
||||
AND wt2.week_start = wt.week_start
|
||||
AND wt2.week_end = wt.week_end) as total_versions
|
||||
FROM weekly_timesheets wt
|
||||
JOIN users u ON wt.user_id = u.id
|
||||
LEFT JOIN users dl ON wt.pdf_downloaded_by = dl.id
|
||||
WHERE wt.status = 'eingereicht'
|
||||
AND wt.user_id = ?
|
||||
ORDER BY wt.week_start DESC, wt.user_id, wt.version DESC
|
||||
`, [userId], (err, timesheets) => {
|
||||
if (err) {
|
||||
console.error('Fehler beim Laden der Stundenzettel (Verwaltung-API /employee/:id/weeks):', err);
|
||||
return res.status(500).send('Fehler beim Laden der Verwaltungsdaten.');
|
||||
}
|
||||
|
||||
if (!timesheets || timesheets.length === 0) {
|
||||
// Kein Inhalt, aber 200, damit das Frontend eine leere Anzeige darstellen kann
|
||||
return res.send('');
|
||||
}
|
||||
|
||||
// Gruppierung wie in /verwaltung, aber nur für einen Mitarbeiter
|
||||
const groupedByEmployee = {};
|
||||
|
||||
timesheets.forEach(ts => {
|
||||
const uid = ts.user_id;
|
||||
const weekKey = `${ts.week_start}_${ts.week_end}`;
|
||||
|
||||
if (!groupedByEmployee[uid]) {
|
||||
groupedByEmployee[uid] = {
|
||||
user: {
|
||||
id: ts.user_id,
|
||||
firstname: ts.firstname,
|
||||
lastname: ts.lastname,
|
||||
username: ts.username,
|
||||
personalnummer: ts.personalnummer,
|
||||
wochenstunden: ts.wochenstunden,
|
||||
urlaubstage: ts.urlaubstage,
|
||||
overtime_offset_hours: ts.overtime_offset_hours,
|
||||
vacation_offset_days: ts.vacation_offset_days
|
||||
},
|
||||
weeks: {}
|
||||
};
|
||||
}
|
||||
|
||||
if (!groupedByEmployee[uid].weeks[weekKey]) {
|
||||
groupedByEmployee[uid].weeks[weekKey] = {
|
||||
week_start: ts.week_start,
|
||||
week_end: ts.week_end,
|
||||
total_versions: ts.total_versions,
|
||||
versions: []
|
||||
};
|
||||
}
|
||||
|
||||
groupedByEmployee[uid].weeks[weekKey].versions.push(ts);
|
||||
});
|
||||
|
||||
const employee = Object.values(groupedByEmployee)[0];
|
||||
if (!employee) {
|
||||
return res.send('');
|
||||
}
|
||||
|
||||
// Prüfe für jede Woche, ob nach dem letzten Download eine neue Version eingereicht wurde
|
||||
Object.values(employee.weeks).forEach(week => {
|
||||
let lastDownloadTime = null;
|
||||
week.versions.forEach(version => {
|
||||
if (version.pdf_downloaded_at) {
|
||||
const downloadTime = new Date(version.pdf_downloaded_at).getTime();
|
||||
if (!lastDownloadTime || downloadTime > lastDownloadTime) {
|
||||
lastDownloadTime = downloadTime;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let hasNewVersionAfterDownload = false;
|
||||
if (lastDownloadTime) {
|
||||
week.versions.forEach(version => {
|
||||
if (version.submitted_at) {
|
||||
const submittedTime = new Date(version.submitted_at).getTime();
|
||||
if (submittedTime > lastDownloadTime) {
|
||||
hasNewVersionAfterDownload = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
week.has_new_version_after_download = hasNewVersionAfterDownload;
|
||||
});
|
||||
|
||||
const weeks = Object.values(employee.weeks).sort((a, b) => {
|
||||
return new Date(b.week_start) - new Date(a.week_start);
|
||||
});
|
||||
|
||||
const viewUser = {
|
||||
firstname: req.session.firstname,
|
||||
lastname: req.session.lastname
|
||||
};
|
||||
|
||||
res.render('verwaltung-weeks-partial', {
|
||||
employee: { user: employee.user, weeks },
|
||||
user: viewUser
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Plausibilitätsprüfung Projektnummer: 7 Ziffern, beginnt mit 5, dann YY, dann 4 Ziffern
|
||||
function isValidProjectNumber(value) {
|
||||
if (!value || String(value).trim() === '') return false;
|
||||
|
||||
Reference in New Issue
Block a user