Compare commits

...

10 Commits

Author SHA1 Message Date
Torsten Schulz (local)
6cc8903e06 Enhance frontend components by importing API_BASE_URL for consistent API endpoint usage. This update improves code maintainability and prepares the components for future API integrations. 2025-11-13 15:18:28 +01:00
Torsten Schulz (local)
e71988e0b7 Enhance TimeEntryService with additional debug logging for better traceability of work time calculations. Added logs for netWorkTime and currentlyWorked to provide clearer insights into overtime and weekly totals, improving the debugging process while maintaining existing functionality. 2025-10-20 16:51:26 +02:00
Torsten Schulz (local)
a1b5e191f3 Refactor StatusBox component to improve end time calculations using server data. Update logic to handle elapsed time accurately, including pause states, and enhance display of currently worked hours. Adjust formatting for time outputs to ensure clarity in the user interface. 2025-10-20 16:41:11 +02:00
Torsten Schulz (local)
1eff170a7b Remove debug logging from TimeEntryService to streamline code and enhance performance. This update improves readability by eliminating unnecessary console outputs while maintaining the functionality of time calculations. 2025-10-20 11:50:37 +02:00
Torsten Schulz (local)
dfd169c78d Enhance TimeEntryService to incorporate timefix corrections for start and end times of work and pauses. Update logic to ensure accurate time calculations by integrating timefix data, improving the reliability of time entries. Add debug logging for better traceability of time calculations. 2025-10-20 11:49:33 +02:00
Torsten Schulz (local)
363f4567c2 Refactor deploy script to replace npm ci with npm install for both backend and frontend setups, enhancing reliability when package-lock.json is missing. Implement fallback mechanism to ensure successful dependency installation, improving overall script robustness. 2025-10-20 11:34:08 +02:00
Torsten Schulz (local)
d99aa96270 Remove debug logging from unhashRequest middleware, TimeEntryService, and StatusBox component to clean up code and improve performance. This update enhances readability and maintains functionality without unnecessary console outputs. 2025-10-20 11:28:06 +02:00
Torsten Schulz (local)
0bcdec68ef Refactor TimeEntryService and StatusBox component to integrate missing break minutes into time calculations. Update logic to ensure "Offen" time reflects accurate values, including breaks, and adjust frontend display to clarify time representation without redundant pause indications. Enhance output formatting for improved clarity in time displays. 2025-10-20 11:24:45 +02:00
Torsten Schulz (local)
1f20500b5f Update deploy script to include dev dependencies during npm installation for backend builds, enhancing reliability of npm ci commands. Adjust fallback mechanism to remove --omit=dev flag for consistent dependency management. 2025-10-20 10:00:30 +02:00
Torsten Schulz (local)
b16a09059f Update deploy script to allow dev dependencies during npm installation for frontend builds, ensuring successful execution of npm ci commands. Adjust fallback mechanism to remove --omit=dev flag for improved reliability in dependency management. 2025-10-20 09:57:42 +02:00
7 changed files with 159 additions and 67 deletions

View File

@@ -16,9 +16,7 @@ const unhashRequestIds = (req, res, next) => {
// Route-Parameter verarbeiten // Route-Parameter verarbeiten
if (req.params && typeof req.params === 'object') { if (req.params && typeof req.params === 'object') {
console.log('DEBUG unhashRequest: req.params before =', req.params);
req.params = unhashRequestData(req.params); req.params = unhashRequestData(req.params);
console.log('DEBUG unhashRequest: req.params after =', req.params);
} }
next(); next();

View File

@@ -232,6 +232,10 @@ class TimeEntryService {
// Hole alle Einträge von heute (wird auch für Pausen verwendet) // Hole alle Einträge von heute (wird auch für Pausen verwendet)
allEntries = await worklogRepository.findByDateRange(uid, todayStart, todayEnd); allEntries = await worklogRepository.findByDateRange(uid, todayStart, todayEnd);
// Hole Timefixes für alle Einträge von heute
const allEntryIds = allEntries.map(e => e.id);
const timefixMap = await worklogRepository.getTimefixesByWorklogIds(allEntryIds);
// Finde alle Start-Work-Paare von heute // Finde alle Start-Work-Paare von heute
const workBlocks = []; const workBlocks = [];
const startWorks = {}; const startWorks = {};
@@ -249,14 +253,22 @@ class TimeEntryService {
const action = state?.action || state; const action = state?.action || state;
if (action === 'start work') { if (action === 'start work') {
// Prüfe auf Timefix-Korrektur
const startFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'start work');
const startTime = startFix?.fix_date_time || entry.tstamp;
startWorks[entry.id] = { startWorks[entry.id] = {
id: entry.id, id: entry.id,
startTime: entry.tstamp, startTime: startTime,
endTime: null, endTime: null,
pauses: [] pauses: []
}; };
} else if (action === 'stop work' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) { } else if (action === 'stop work' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) {
startWorks[entry.relatedTo_id].endTime = entry.tstamp; // Prüfe auf Timefix-Korrektur
const endFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'stop work');
const endTime = endFix?.fix_date_time || entry.tstamp;
startWorks[entry.relatedTo_id].endTime = endTime;
} }
}); });
@@ -274,9 +286,13 @@ class TimeEntryService {
const action = state?.action || state; const action = state?.action || state;
if (action === 'start pause' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) { if (action === 'start pause' && entry.relatedTo_id && startWorks[entry.relatedTo_id]) {
// Prüfe auf Timefix-Korrektur
const pauseStartFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'start pause');
const pauseStartTime = pauseStartFix?.fix_date_time || entry.tstamp;
startWorks[entry.relatedTo_id].pauses.push({ startWorks[entry.relatedTo_id].pauses.push({
id: entry.id, id: entry.id,
startTime: entry.tstamp, startTime: pauseStartTime,
endTime: null endTime: null
}); });
} else if (action === 'stop pause' && entry.relatedTo_id) { } else if (action === 'stop pause' && entry.relatedTo_id) {
@@ -284,7 +300,9 @@ class TimeEntryService {
Object.values(startWorks).forEach(block => { Object.values(startWorks).forEach(block => {
const pause = block.pauses.find(p => p.id === entry.relatedTo_id); const pause = block.pauses.find(p => p.id === entry.relatedTo_id);
if (pause) { if (pause) {
pause.endTime = entry.tstamp; // Prüfe auf Timefix-Korrektur
const pauseEndFix = timefixMap.get(entry.id)?.find(f => f.fix_type === 'stop pause');
pause.endTime = pauseEndFix?.fix_date_time || entry.tstamp;
} }
}); });
} }
@@ -324,6 +342,8 @@ class TimeEntryService {
} }
// Berechne "Offen" basierend auf timewish (oder Standard: 8 Stunden) // Berechne "Offen" basierend auf timewish (oder Standard: 8 Stunden)
// WICHTIG: Diese Zeit wird OHNE fehlende Pausen berechnet
// Das Frontend addiert die fehlenden Pausen dann zur "Normales Arbeitsende" Berechnung
let open = null; let open = null;
const { Timewish } = database.getModels(); const { Timewish } = database.getModels();
@@ -458,6 +478,21 @@ class TimeEntryService {
// Fehlende Pausenzeit // Fehlende Pausenzeit
const missingBreakMinutes = Math.max(0, requiredBreakMinutes - alreadyTakenBreakMinutes); const missingBreakMinutes = Math.max(0, requiredBreakMinutes - alreadyTakenBreakMinutes);
// Addiere fehlende Pausen zur "Offen" Zeit
if (open && open !== '—' && open !== 'Arbeitsende erreicht') {
const openParts = open.split(':');
const openH = parseInt(openParts[0]);
const openM = parseInt(openParts[1]);
const openS = parseInt(openParts[2] || 0);
const openMinutes = openH * 60 + openM + missingBreakMinutes;
const newOpenH = Math.floor(openMinutes / 60);
const newOpenM = openMinutes % 60;
const newOpenS = openS;
open = `${newOpenH.toString().padStart(2, '0')}:${newOpenM.toString().padStart(2, '0')}:${newOpenS.toString().padStart(2, '0')}`;
}
// Berechne Überstunden über den gesamten Zeitraum (alle Wochen) // Berechne Überstunden über den gesamten Zeitraum (alle Wochen)
// Neue Berechnung: Timewish-basiert // Neue Berechnung: Timewish-basiert
const totalOvertimeResult = await this._calculateTotalOvertime(uid, runningEntry); const totalOvertimeResult = await this._calculateTotalOvertime(uid, runningEntry);
@@ -465,6 +500,8 @@ class TimeEntryService {
// Berechne Überstunden für die aktuelle Woche // Berechne Überstunden für die aktuelle Woche
const weekData = await this.getWeekOverview(uid, 0); const weekData = await this.getWeekOverview(uid, 0);
console.log(`🔍 Wochenüberstunden-Berechnung START: userDailyHours=${userDailyHours}`);
let weekSollMinutes = 0; // Soll-Arbeitszeit für die Woche let weekSollMinutes = 0; // Soll-Arbeitszeit für die Woche
let weekIstMinutes = 0; // Ist-Arbeitszeit für die Woche let weekIstMinutes = 0; // Ist-Arbeitszeit für die Woche
@@ -549,13 +586,17 @@ class TimeEntryService {
}); });
let daySollHours = userDailyHours; // Fallback: User's daily_hours let daySollHours = userDailyHours; // Fallback: User's daily_hours
console.log(` Tag ${day.date}: userDailyHours=${userDailyHours}, applicableTimewish=${applicableTimewish ? applicableTimewish.hours + 'h' : 'keine'}`);
if (applicableTimewish && applicableTimewish.wishtype === 2 && applicableTimewish.hours) { if (applicableTimewish && applicableTimewish.wishtype === 2 && applicableTimewish.hours) {
daySollHours = applicableTimewish.hours; daySollHours = applicableTimewish.hours;
console.log(` → Verwende Timewish: ${daySollHours}h`);
} }
// Bei halbem Urlaubstag: Soll halbiert // Bei halbem Urlaubstag: Soll halbiert
if (day.vacation && day.vacation.halfDay) { if (day.vacation && day.vacation.halfDay) {
daySollHours = daySollHours / 2; daySollHours = daySollHours / 2;
console.log(` → Halber Urlaubstag: ${daySollHours}h`);
} }
weekSollMinutes += daySollHours * 60; weekSollMinutes += daySollHours * 60;
@@ -564,11 +605,15 @@ class TimeEntryService {
if (day.netWorkTime) { if (day.netWorkTime) {
const [h, m] = day.netWorkTime.split(':').map(Number); const [h, m] = day.netWorkTime.split(':').map(Number);
weekIstMinutes += h * 60 + m; weekIstMinutes += h * 60 + m;
console.log(` Tag ${day.date}: netWorkTime=${day.netWorkTime}, Soll=${daySollHours}h, Ist=${h}:${m}`);
} }
}); });
// Überstunden = Ist - Soll // Überstunden = Ist - Soll
const overtimeMinutes = weekIstMinutes - weekSollMinutes; const overtimeMinutes = weekIstMinutes - weekSollMinutes;
console.log(`🔍 Wochenüberstunden: weekIst=${weekIstMinutes}min (${Math.floor(weekIstMinutes/60)}:${weekIstMinutes%60}), weekSoll=${weekSollMinutes}min (${Math.floor(weekSollMinutes/60)}:${weekSollMinutes%60}), overtime=${overtimeMinutes}min`);
const overtimeHours = Math.floor(Math.abs(overtimeMinutes) / 60); const overtimeHours = Math.floor(Math.abs(overtimeMinutes) / 60);
const overtimeMins = Math.abs(overtimeMinutes) % 60; const overtimeMins = Math.abs(overtimeMinutes) % 60;
const overtimeSign = overtimeMinutes >= 0 ? '+' : '-'; const overtimeSign = overtimeMinutes >= 0 ? '+' : '-';
@@ -650,14 +695,18 @@ class TimeEntryService {
const [h, m, s] = currentlyWorked.split(':').map(Number); const [h, m, s] = currentlyWorked.split(':').map(Number);
dayIstMinutes = h * 60 + m; dayIstMinutes = h * 60 + m;
weekIstMinutesTotal += dayIstMinutes; weekIstMinutesTotal += dayIstMinutes;
console.log(` HEUTE ${day.date}: currentlyWorked=${currentlyWorked}, Soll=${daySollHours}h, Ist=${h}:${m}`);
} else if (!isToday && day.netWorkTime) { } else if (!isToday && day.netWorkTime) {
// Für vergangene Tage: Verwende netWorkTime // Für vergangene Tage: Verwende netWorkTime
const [h, m] = day.netWorkTime.split(':').map(Number); const [h, m] = day.netWorkTime.split(':').map(Number);
dayIstMinutes = h * 60 + m; dayIstMinutes = h * 60 + m;
weekIstMinutesTotal += dayIstMinutes; weekIstMinutesTotal += dayIstMinutes;
console.log(` Vergangener Tag ${day.date}: netWorkTime=${day.netWorkTime}, Soll=${daySollHours}h, Ist=${h}:${m}`);
} }
}); });
console.log(`🔍 Offen für Woche: weekIstTotal=${weekIstMinutesTotal}min, weekSollTotal=${weekSollMinutesTotal}min`);
// Offen für Woche = Wochensoll - Wochenist (bisher) // Offen für Woche = Wochensoll - Wochenist (bisher)
const openForWeekMinutes = weekSollMinutesTotal - weekIstMinutesTotal; const openForWeekMinutes = weekSollMinutesTotal - weekIstMinutesTotal;
@@ -699,9 +748,10 @@ class TimeEntryService {
const currentTime = new Date(); const currentTime = new Date();
// ===== GENERELL ===== // ===== GENERELL =====
// Verbleibende Zeit = Offen - Gesamt-Überstunden + fehlende Pausen // Verbleibende Zeit = Offen - Gesamt-Überstunden
// WICHTIG: "open" enthält bereits die fehlenden Pausen!
const generalOvertimeMinutes = totalOvertimeResult.minutes || 0; const generalOvertimeMinutes = totalOvertimeResult.minutes || 0;
const generalRemainingMinutes = openMinutes - generalOvertimeMinutes + missingBreakMinutes; const generalRemainingMinutes = openMinutes - generalOvertimeMinutes;
if (generalRemainingMinutes <= 0) { if (generalRemainingMinutes <= 0) {
adjustedEndTodayGeneral = 'Arbeitsende erreicht'; adjustedEndTodayGeneral = 'Arbeitsende erreicht';
@@ -714,9 +764,10 @@ class TimeEntryService {
} }
// ===== WOCHE ===== // ===== WOCHE =====
// Verbleibende Zeit = Offen - Wochen-Über/Unterstunden + fehlende Pausen // Verbleibende Zeit = Offen - Wochen-Über/Unterstunden
// WICHTIG: "open" enthält bereits die fehlenden Pausen!
const weekOvertimeMinutes = overtimeMinutes; // Bereits berechnet const weekOvertimeMinutes = overtimeMinutes; // Bereits berechnet
const weekRemainingMinutes = openMinutes - weekOvertimeMinutes + missingBreakMinutes; const weekRemainingMinutes = openMinutes - weekOvertimeMinutes;
if (weekRemainingMinutes <= 0) { if (weekRemainingMinutes <= 0) {
adjustedEndTodayWeek = 'Arbeitsende erreicht'; adjustedEndTodayWeek = 'Arbeitsende erreicht';

View File

@@ -202,13 +202,8 @@ setup_backend() {
npm config set audit false >/dev/null 2>&1 || true npm config set audit false >/dev/null 2>&1 || true
npm config set progress false >/dev/null 2>&1 || true npm config set progress false >/dev/null 2>&1 || true
npm config set loglevel warn >/dev/null 2>&1 || true npm config set loglevel warn >/dev/null 2>&1 || true
# Schnelle, reproduzierbare Installation nur Prod-Dependencies # Backend braucht alle Dependencies (auch dev für Build-Tools)
timeout 600 bash -lc "npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress" || { npm install --no-audit --no-fund --loglevel=warn
print_warning "npm ci ist fehlgeschlagen oder hat zu lange gedauert. Versuche fallback ohne timeout..."
npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress || {
print_error "npm ci (Backend) fehlgeschlagen"; exit 1;
}
}
if [ ! -f .env ]; then if [ ! -f .env ]; then
print_warning ".env Datei nicht gefunden!" print_warning ".env Datei nicht gefunden!"
@@ -239,12 +234,8 @@ setup_frontend() {
npm config set audit false >/dev/null 2>&1 || true npm config set audit false >/dev/null 2>&1 || true
npm config set progress false >/dev/null 2>&1 || true npm config set progress false >/dev/null 2>&1 || true
npm config set loglevel warn >/dev/null 2>&1 || true npm config set loglevel warn >/dev/null 2>&1 || true
timeout 600 bash -lc "npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress" || { # Frontend braucht dev-Dependencies für den Build (vite, etc.)
print_warning "npm ci ist fehlgeschlagen oder hat zu lange gedauert. Versuche fallback ohne timeout..." npm install --no-audit --no-fund --loglevel=warn
npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress || {
print_error "npm ci (Frontend) fehlgeschlagen"; exit 1;
}
}
# .env.production erstellen falls nicht vorhanden # .env.production erstellen falls nicht vorhanden
if [ ! -f ".env.production" ]; then if [ ! -f ".env.production" ]; then
@@ -486,16 +477,27 @@ do_update() {
# Backend aktualisieren # Backend aktualisieren
print_info "Aktualisiere Backend Dependencies..." print_info "Aktualisiere Backend Dependencies..."
cd $BACKEND_DIR cd $BACKEND_DIR
# Prüfe ob package-lock.json existiert
if [ ! -f "package-lock.json" ]; then
print_warning "package-lock.json fehlt! Verwende npm install statt npm ci"
npm install --no-audit --no-fund --loglevel=warn
else
npm config set fund false >/dev/null 2>&1 || true npm config set fund false >/dev/null 2>&1 || true
npm config set audit false >/dev/null 2>&1 || true npm config set audit false >/dev/null 2>&1 || true
npm config set progress false >/dev/null 2>&1 || true npm config set progress false >/dev/null 2>&1 || true
npm config set loglevel warn >/dev/null 2>&1 || true npm config set loglevel warn >/dev/null 2>&1 || true
timeout 600 bash -lc "npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress" || {
print_warning "npm ci ist fehlgeschlagen oder hat zu lange gedauert. Versuche fallback ohne timeout..." # Backend braucht alle Dependencies (auch dev für Build-Tools)
npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress || { if ! npm ci --no-audit --no-fund --loglevel=warn 2>&1; then
print_error "npm ci (Backend Update) fehlgeschlagen"; exit 1; print_warning "npm ci fehlgeschlagen. Fallback auf npm install..."
} rm -rf node_modules
npm install --no-audit --no-fund --loglevel=warn || {
print_error "npm install (Backend Update) fehlgeschlagen"
exit 1
} }
fi
fi
# Frontend aktualisieren # Frontend aktualisieren
print_info "Aktualisiere Frontend..." print_info "Aktualisiere Frontend..."
@@ -510,16 +512,26 @@ VITE_API_URL=/api
EOF EOF
fi fi
# Prüfe ob package-lock.json existiert
if [ ! -f "package-lock.json" ]; then
print_warning "package-lock.json fehlt! Verwende npm install statt npm ci"
npm install --no-audit --no-fund --loglevel=warn
else
npm config set fund false >/dev/null 2>&1 || true npm config set fund false >/dev/null 2>&1 || true
npm config set audit false >/dev/null 2>&1 || true npm config set audit false >/dev/null 2>&1 || true
npm config set progress false >/dev/null 2>&1 || true npm config set progress false >/dev/null 2>&1 || true
npm config set loglevel warn >/dev/null 2>&1 || true npm config set loglevel warn >/dev/null 2>&1 || true
timeout 600 bash -lc "npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress" || {
print_warning "npm ci ist fehlgeschlagen oder hat zu lange gedauert. Versuche fallback ohne timeout..." # Frontend braucht dev-Dependencies für den Build (vite, etc.)
npm ci --omit=dev --no-audit --no-fund --silent --loglevel=warn --no-progress || { if ! npm ci --no-audit --no-fund --loglevel=warn 2>&1; then
print_error "npm ci (Frontend Update) fehlgeschlagen"; exit 1; print_warning "npm ci fehlgeschlagen. Fallback auf npm install..."
} rm -rf node_modules
npm install --no-audit --no-fund --loglevel=warn || {
print_error "npm install (Frontend Update) fehlgeschlagen"
exit 1
} }
fi
fi
# Sauberer Build # Sauberer Build
rm -rf dist/ rm -rf dist/

View File

@@ -117,16 +117,12 @@ const fetchWorklogData = async () => {
if (response.ok) { if (response.ok) {
const result = await response.json() const result = await response.json()
console.log('DEBUG fetchWorklogData: result =', result)
console.log('DEBUG fetchWorklogData: currentState =', currentState.value)
// Das Backend gibt direkt das Entry-Objekt zurück, nicht { entry: ... } // Das Backend gibt direkt das Entry-Objekt zurück, nicht { entry: ... }
if (result && result.startTime && (currentState.value === 'start work' || currentState.value === 'stop pause')) { if (result && result.startTime && (currentState.value === 'start work' || currentState.value === 'stop pause')) {
// Arbeit läuft // Arbeit läuft
workStartTime.value = new Date(result.startTime).getTime() workStartTime.value = new Date(result.startTime).getTime()
pauseDurations.value = result.pauses || [] pauseDurations.value = result.pauses || []
lastPauseStartTime.value = null lastPauseStartTime.value = null
console.log('DEBUG: Arbeit läuft, startTime:', result.startTime, 'pauses:', pauseDurations.value.length)
} else if (result && result.startTime && currentState.value === 'start pause') { } else if (result && result.startTime && currentState.value === 'start pause') {
// In Pause // In Pause
workStartTime.value = new Date(result.startTime).getTime() workStartTime.value = new Date(result.startTime).getTime()
@@ -135,13 +131,11 @@ const fetchWorklogData = async () => {
if (result.currentPauseStart) { if (result.currentPauseStart) {
lastPauseStartTime.value = new Date(result.currentPauseStart).getTime() lastPauseStartTime.value = new Date(result.currentPauseStart).getTime()
} }
console.log('DEBUG: In Pause, startTime:', result.startTime, 'currentPauseStart:', result.currentPauseStart)
} else { } else {
// Nicht am Arbeiten // Nicht am Arbeiten
workStartTime.value = null workStartTime.value = null
lastPauseStartTime.value = null lastPauseStartTime.value = null
pauseDurations.value = [] pauseDurations.value = []
console.log('DEBUG: Nicht am Arbeiten')
} }
} }
} catch (error) { } catch (error) {
@@ -247,19 +241,46 @@ const updateOpenTime = () => {
openTime.value = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` openTime.value = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
// Berechne "Normales Arbeitsende" = Jetzt + Offen + fehlende Pausen // Berechne "Normales Arbeitsende" = Jetzt + Offen (Pausen sind bereits in Offen enthalten)
const totalRemainingSeconds = remainingSeconds + (missingBreakMinutes.value * 60) const totalRemainingSeconds = remainingSeconds
const endTimestamp = now + (totalRemainingSeconds * 1000) const endTimestamp = now + (totalRemainingSeconds * 1000)
const endDate = new Date(endTimestamp) const endDate = new Date(endTimestamp)
const endHours = endDate.getHours() const endHours = endDate.getHours()
const endMinutes = endDate.getMinutes() const endMinutes = endDate.getMinutes()
const endSeconds = endDate.getSeconds() const endSeconds = endDate.getSeconds()
// Zeige auch fehlende Pausen an (falls vorhanden) // Ausgabe ohne zusätzlichen Pausen-Hinweis; Zeit stammt bereits inkl. Pausen aus Backend
if (missingBreakMinutes.value > 0) { regularEndTime.value = `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}:${endSeconds.toString().padStart(2, '0')} Uhr`
regularEndTime.value = `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}:${endSeconds.toString().padStart(2, '0')} (+${missingBreakMinutes.value}min Pause)`
// Override: Berechne Normales Arbeitsende aus Server "open" Zeit
// Nur überschreiben wenn wir Server-Daten haben
if (serverOpenTime.value && serverTimestamp.value) {
// Parse Server-Offen-Zeit
const openParts = serverOpenTime.value.split(':')
const openSeconds = parseInt(openParts[0]) * 3600 + parseInt(openParts[1]) * 60 + parseInt(openParts[2] || 0)
// Berechne vergangene Zeit seit Server-Timestamp
const now = Date.now()
const elapsedMs = now - serverTimestamp.value
let elapsedSeconds = Math.floor(elapsedMs / 1000)
// Wenn in Pause, zähle die Zeit nicht
if (currentState.value === 'start pause') {
elapsedSeconds = 0
}
const remainingSeconds = openSeconds - elapsedSeconds
if (remainingSeconds > 0) {
const endTs = now + (remainingSeconds * 1000)
const endDt = new Date(endTs)
const eh = endDt.getHours()
const em = endDt.getMinutes()
const es = endDt.getSeconds()
regularEndTime.value = `${eh.toString().padStart(2, '0')}:${em.toString().padStart(2, '0')}:${es.toString().padStart(2, '0')} Uhr`
} else { } else {
regularEndTime.value = `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}:${endSeconds.toString().padStart(2, '0')}` regularEndTime.value = 'Erreicht'
}
} }
} else { } else {
openTime.value = 'Arbeitsende erreicht' openTime.value = 'Arbeitsende erreicht'
@@ -297,11 +318,9 @@ const handleAction = async (action) => {
} }
// Aktualisiere Status und Worklog-Daten sofort // Aktualisiere Status und Worklog-Daten sofort
console.log('DEBUG: Lade Daten nach Stempel-Aktion neu...')
await fetchCurrentState() await fetchCurrentState()
await fetchWorklogData() await fetchWorklogData()
await fetchStats() await fetchStats()
console.log('DEBUG: Daten neu geladen, stats =', stats.value)
// Event auslösen für andere Komponenten (z.B. WeekOverview) // Event auslösen für andere Komponenten (z.B. WeekOverview)
window.dispatchEvent(new CustomEvent('worklog-updated')) window.dispatchEvent(new CustomEvent('worklog-updated'))
@@ -347,7 +366,6 @@ const rightButton = computed(() => {
// Event-Handler für Login // Event-Handler für Login
const handleLoginCompleted = async () => { const handleLoginCompleted = async () => {
console.log('DEBUG: Login completed, lade Daten neu...')
await fetchCurrentState() await fetchCurrentState()
await fetchWorklogData() await fetchWorklogData()
await fetchStats() await fetchStats()
@@ -383,17 +401,21 @@ onBeforeUnmount(() => {
}) })
const displayRows = computed(() => { const displayRows = computed(() => {
// Verwende Server-Wert für "Derzeit gearbeitet" wenn verfügbar (zeigt gesamte Tagesarbeitszeit)
const workedDisplay = (stats.value?.currentlyWorked && stats.value.currentlyWorked !== '—')
? stats.value.currentlyWorked + ' h'
: (currentlyWorkedTime.value === '—' ? currentlyWorkedTime.value : currentlyWorkedTime.value + ' h');
const rows = { const rows = {
'Derzeit gearbeitet': currentlyWorkedTime.value, // Verwende berechneten Wert 'Derzeit gearbeitet': workedDisplay,
'Offen': openTime.value, // Verwende berechneten Wert 'Offen': openTime.value === '—' || openTime.value.includes('erreicht') ? openTime.value : openTime.value + ' h',
'Normales Arbeitsende': regularEndTime.value // Verwende berechneten Wert 'Normales Arbeitsende': regularEndTime.value // Verwende berechneten Wert (hat bereits "Uhr")
} }
// Füge andere Stats hinzu // Füge andere Stats hinzu
const map = [ const map = [
['overtime', 'overtime'], // Label wird dynamisch gesetzt ['overtime', 'overtime'], // Label wird dynamisch gesetzt
['totalOvertime', 'totalOvertime'], // Label wird dynamisch gesetzt ['totalOvertime', 'totalOvertime'], // Label wird dynamisch gesetzt
// ['Überstunden (Alt-Style)', 'totalOvertimeOldStyle'], // DEBUG: Versteckt, da getWeekOverview nicht korrekte Zeiten liefert
['Wochenarbeitszeit', 'weekWorktime'], ['Wochenarbeitszeit', 'weekWorktime'],
['Arbeitsfreie Stunden', 'nonWorkingHours'], ['Arbeitsfreie Stunden', 'nonWorkingHours'],
['Offen für Woche', 'openForWeek'], ['Offen für Woche', 'openForWeek'],
@@ -416,16 +438,19 @@ const displayRows = computed(() => {
if (key === 'overtime') { if (key === 'overtime') {
const isNegative = val.startsWith('-'); const isNegative = val.startsWith('-');
const displayLabel = isNegative ? 'Fehlzeit (Woche)' : 'Überstunden (Woche)'; const displayLabel = isNegative ? 'Fehlzeit (Woche)' : 'Überstunden (Woche)';
const displayValue = isNegative ? val.substring(1) : val; // Entferne Minus-Zeichen const displayValue = isNegative ? val.substring(1) + ' h' : val + ' h'; // Entferne Minus-Zeichen, füge " h" hinzu
rows[displayLabel] = displayValue; rows[displayLabel] = displayValue;
} else if (key === 'totalOvertime') { } else if (key === 'totalOvertime') {
const isNegative = val.startsWith('-'); const isNegative = val.startsWith('-');
const displayLabel = isNegative ? 'Fehlzeit (Gesamt)' : 'Überstunden (Gesamt)'; const displayLabel = isNegative ? 'Fehlzeit (Gesamt)' : 'Überstunden (Gesamt)';
const displayValue = isNegative ? val.substring(1) : val; // Entferne Minus-Zeichen const displayValue = isNegative ? val.substring(1) + ' h' : val + ' h'; // Entferne Minus-Zeichen, füge " h" hinzu
rows[displayLabel] = displayValue; rows[displayLabel] = displayValue;
} else if (key === 'adjustedEndTodayGeneral' || key === 'adjustedEndTodayWeek') { } else if (key === 'adjustedEndTodayGeneral' || key === 'adjustedEndTodayWeek') {
// Füge " Uhr" zu Uhrzeiten hinzu // Füge " Uhr" zu Uhrzeiten hinzu (außer bei "Arbeitsende erreicht")
rows[label] = val + ' Uhr'; rows[label] = val.includes('erreicht') ? val : val + ' Uhr';
} else if (key === 'weekWorktime' || key === 'openForWeek' || key === 'nonWorkingHours') {
// Füge " h" zu Zeiten hinzu (außer bei "—")
rows[label] = val === '—' ? val : val + ' h';
} else { } else {
rows[label] = val; rows[label] = val;
} }

View File

@@ -76,7 +76,9 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useAuthStore } from '../stores/authStore' import { useAuthStore } from '../stores/authStore'
import { API_BASE_URL } from '@/config/api'
const API_URL = API_BASE_URL
const authStore = useAuthStore() const authStore = useAuthStore()
const now = new Date() const now = new Date()
const selectedMonth = ref(now.getMonth() + 1) const selectedMonth = ref(now.getMonth() + 1)

View File

@@ -89,7 +89,9 @@ import { ref } from 'vue'
import { useAuthStore } from '../stores/authStore' import { useAuthStore } from '../stores/authStore'
import { useModal } from '../composables/useModal' import { useModal } from '../composables/useModal'
import Modal from '../components/Modal.vue' import Modal from '../components/Modal.vue'
import { API_BASE_URL } from '@/config/api'
const API_URL = API_BASE_URL
const authStore = useAuthStore() const authStore = useAuthStore()
const loading = ref(false) const loading = ref(false)

View File

@@ -48,7 +48,9 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useAuthStore } from '../stores/authStore' import { useAuthStore } from '../stores/authStore'
import { API_BASE_URL } from '@/config/api'
const API_URL = API_BASE_URL
const authStore = useAuthStore() const authStore = useAuthStore()
const selectedYear = ref(new Date().getFullYear()) const selectedYear = ref(new Date().getFullYear())
const statistics = ref(null) const statistics = ref(null)