BugFix Projektauswertung

This commit is contained in:
2026-03-12 18:05:02 +01:00
parent af20dc6bd8
commit 8595b099db
2 changed files with 57 additions and 39 deletions

View File

@@ -38,10 +38,15 @@ function registerVerwaltungRoutes(app) {
WHERE wt.status = 'eingereicht'
ORDER BY wt.week_start DESC, wt.user_id, wt.version DESC
`, (err, timesheets) => {
if (err) {
console.error('Fehler beim Laden der Stundenzettel (Verwaltung):', err);
return res.status(500).send('Fehler beim Laden der Verwaltungsdaten. Bitte die Server-Logs prüfen oder die Datenbank-Migrationen ausführen.');
}
// Gruppiere nach Mitarbeiter, dann nach Kalenderwoche
// Struktur: { [user_id]: { user: {...}, weeks: { [week_key]: {...} } } }
const groupedByEmployee = {};
(timesheets || []).forEach(ts => {
const userId = ts.user_id;
const weekKey = `${ts.week_start}_${ts.week_end}`;
@@ -152,37 +157,57 @@ function registerVerwaltungRoutes(app) {
// Projektauswertung nach Mitarbeitern für eine Projektnummer
app.get('/verwaltung/projektauswertung', requireVerwaltung, (req, res) => {
let session;
try {
session = req.session || {};
} catch (e) {
console.error('Fehler beim Zugriff auf die Session (Projektauswertung):', e);
return res.status(500).send('Fehler: Session nicht verfügbar. Bitte erneut anmelden.');
}
const userForView = {
firstname: session.firstname ?? '',
lastname: session.lastname ?? '',
roles: Array.isArray(session.roles) ? session.roles : [],
currentRole: session.currentRole || 'verwaltung'
};
const projectNumberRaw = req.query.project ? String(req.query.project).trim() : '';
const projectNumber = projectNumberRaw || null;
const doRender = (locals) => {
try {
return res.render('projekt-auswertung', locals);
} catch (e) {
console.error('Fehler beim Rendern der Projektauswertung:', e);
if (!res.headersSent) {
res.status(500).send('Fehler beim Anzeigen der Seite. Bitte Server-Logs prüfen.');
}
}
};
if (!projectNumber) {
// Nur Formular anzeigen, noch keine Auswertung
return res.render('projekt-auswertung', {
user: {
firstname: req.session.firstname,
lastname: req.session.lastname,
roles: req.session.roles || [],
currentRole: req.session.currentRole || 'verwaltung'
},
return doRender({
user: userForView,
projectNumber: '',
results: [],
totalProjectHours: 0,
hasResults: false
hasResults: false,
totalProjectHoursFormatted: '0:00',
breakdownByUser: {},
projectNumberError: null
});
}
if (!isValidProjectNumber(projectNumber)) {
return res.render('projekt-auswertung', {
user: {
firstname: req.session.firstname,
lastname: req.session.lastname,
roles: req.session.roles || [],
currentRole: req.session.currentRole || 'verwaltung'
},
return doRender({
user: userForView,
projectNumber: projectNumberRaw,
results: [],
totalProjectHours: 0,
hasResults: false,
totalProjectHoursFormatted: '0:00',
breakdownByUser: {},
projectNumberError: 'Die Projektnummer muss 7 Ziffern haben, mit 5 beginnen, gefolgt vom Jahr (YY) und 4 Ziffern (z.B. 5260001).'
});
}
@@ -224,7 +249,7 @@ function registerVerwaltungRoutes(app) {
db.all(sql, params, (err, rows) => {
if (err) {
console.error('Fehler bei der Projektauswertung:', err);
return res.status(500).send('Fehler bei der Projektauswertung');
return res.status(500).send('Fehler bei der Projektauswertung: ' + (err.message || String(err)));
}
const rawResults = (rows || []).map((row) => {
@@ -247,19 +272,15 @@ function registerVerwaltungRoutes(app) {
const totalProjectHoursFormatted = minutesToHhMm(totalProjectMinutes);
if (results.length === 0) {
return res.render('projekt-auswertung', {
user: {
firstname: req.session.firstname,
lastname: req.session.lastname,
roles: req.session.roles || [],
currentRole: req.session.currentRole || 'verwaltung'
},
return doRender({
user: userForView,
projectNumber: projectNumberRaw,
results,
totalProjectHours,
totalProjectHoursFormatted,
hasResults: false,
breakdownByUser: {}
breakdownByUser: {},
projectNumberError: null
});
}
@@ -343,19 +364,15 @@ function registerVerwaltungRoutes(app) {
pending -= 1;
if (pending === 0) {
res.render('projekt-auswertung', {
user: {
firstname: req.session.firstname,
lastname: req.session.lastname,
roles: req.session.roles || [],
currentRole: req.session.currentRole || 'verwaltung'
},
doRender({
user: userForView,
projectNumber: projectNumberRaw,
results,
totalProjectHours,
totalProjectHoursFormatted,
hasResults: results.length > 0,
breakdownByUser
breakdownByUser,
projectNumberError: null
});
}
}

View File

@@ -289,7 +289,7 @@
</div>
<div class="pdf-viewer-wrapper">
<iframe
src="/api/timesheet/pdf/<%= ts.id %>?inline=true"
data-src="/api/timesheet/pdf/<%= ts.id %>?inline=true"
class="pdf-iframe"
frameborder="0"
type="application/pdf"
@@ -939,7 +939,7 @@
});
});
// PDF-Vorschau ein-/ausblenden
// PDF-Vorschau ein-/ausblenden (PDF erst bei Klick laden)
document.querySelectorAll('.toggle-pdf-btn').forEach(btn => {
btn.addEventListener('click', function() {
const timesheetId = this.dataset.timesheetId;
@@ -965,11 +965,12 @@
arrowIcon.textContent = '▼';
this.classList.add('active');
// Setze iframe src wenn noch nicht gesetzt (für besseres Laden)
// iframe-src erst jetzt setzen (lazy load), falls noch nicht gesetzt
if (iframe) {
const currentSrc = iframe.src || iframe.getAttribute('src');
if (!currentSrc || !currentSrc.includes('inline=true')) {
iframe.src = `/api/timesheet/pdf/${timesheetId}?inline=true`;
const currentSrc = iframe.getAttribute('src');
if (!currentSrc) {
const dataSrc = iframe.getAttribute('data-src') || `/api/timesheet/pdf/${timesheetId}?inline=true`;
iframe.setAttribute('src', dataSrc);
}
}