feat: enhance timer metrics and workday calculations to include entries and running timer status
This commit is contained in:
21
README.md
21
README.md
@@ -25,6 +25,14 @@ Eine Full-Stack-Zeiterfassungsanwendung, entwickelt mit Node.js, Express, SQLite
|
||||
- Timer persistiert über Seiten-Reloads
|
||||
- Manuelle Startzeit-Eingabe möglich
|
||||
- Visueller Indikator (blinkendes Uhr-Icon) bei laufendem Timer
|
||||
- **Timer-Metriken** bei laufendem Timer:
|
||||
- Läuft seit: Startzeit mit Icon-Styling
|
||||
- Soll erreicht: Uhrzeit wann Tagesziel erreicht wird (inkl. Pausen)
|
||||
- Zeit bis Soll: Live-Countdown zur Zielzeit
|
||||
- Saldo bei Soll: Prognostizierter Gesamtsaldo nach Erreichen der geplanten Zeit
|
||||
- **Anpassbare Arbeitszeit**: Dropdown 4h-10h für flexible Arbeitstage
|
||||
- Einstellung bleibt über Reloads erhalten (nur während Timer läuft)
|
||||
- Wird bei Timer-Stop auf 8h zurückgesetzt
|
||||
- **Flexible Eingabemodi**:
|
||||
- Manuelle Eingabe (Datum, Start, Ende, Pause)
|
||||
- Inline-Bearbeitung direkt in der Tabelle
|
||||
@@ -38,10 +46,16 @@ Eine Full-Stack-Zeiterfassungsanwendung, entwickelt mit Node.js, Express, SQLite
|
||||
- **Automatische Pausenberechnung** (deutsches Arbeitszeitgesetz)
|
||||
- **10-Stunden-Cap** für maximale Nettoarbeitszeit pro Tag
|
||||
- **Live-Statistiken** mit laufendem Timer:
|
||||
- Soll-Stunden (basierend auf Arbeitstagen)
|
||||
- Soll-Stunden (basierend auf Arbeitstagen mit Einträgen)
|
||||
- Ist-Stunden (inkl. aktuell laufender Timer)
|
||||
- Monatssaldo + Gesamtsaldo mit Vormonatsübertrag
|
||||
- Arbeitstage-Zählung
|
||||
- **Intelligente Soll-Berechnung**: Berücksichtigt nur Tage mit Einträgen oder laufendem Timer
|
||||
- **Laufendes Saldo** in Monatsansicht:
|
||||
- Spalte "Saldo" zeigt kumulatives Saldo bis zu jedem Tag
|
||||
- Live-Updates während Timer läuft
|
||||
- Farbcodierung: Grün (positiv) / Rot (negativ)
|
||||
- Berücksichtigt Flextime-Tage korrekt (-8h)
|
||||
- **Urlaubsverwaltung**:
|
||||
- Konfigurierbares Jahres-Kontingent
|
||||
- Tracking: Genommen, Geplant, Verfügbar
|
||||
@@ -50,6 +64,10 @@ Eine Full-Stack-Zeiterfassungsanwendung, entwickelt mit Node.js, Express, SQLite
|
||||
### 🗓️ Bundesland-spezifische Feiertage
|
||||
- **16 Bundesländer** mit korrekten regionalen Feiertagen
|
||||
- **Persistente Einstellung** (gespeichert in Datenbank)
|
||||
- **Betriebsfreie Tage**: Wählbar zwischen Heiligabend (24.12.) oder Silvester (31.12.)
|
||||
- Toggle in Einstellungen
|
||||
- Wird als "Betriebsfrei" markiert
|
||||
- Verhindert doppelte Einträge an diesen Tagen
|
||||
- **Kollisionserkennung**: Warnung bei Feiertagen mit bestehenden Einträgen
|
||||
- **Alle Feiertage**: Bundeseinheitlich + regional (z.B. Fronleichnam, Reformationstag)
|
||||
|
||||
@@ -62,6 +80,7 @@ Eine Full-Stack-Zeiterfassungsanwendung, entwickelt mit Node.js, Express, SQLite
|
||||
- 🔴 Rot: Fehlende Arbeitstage
|
||||
- ⚫ Grau: Wochenenden
|
||||
- 🔵 Blau: Feiertage (mit Namen)
|
||||
- 💙 Blauer Rand: Heutiger Tag
|
||||
- **Navigation**: Vor/Zurück-Buttons zum Monatswechsel
|
||||
- **Auto-Fill**: Automatisches Befüllen des Monats mit Standard-Arbeitszeiten (9:00-17:30)
|
||||
- **Quick-Actions**: Plus-Buttons für schnelles Hinzufügen von Einträgen
|
||||
|
||||
@@ -1162,6 +1162,15 @@ async function updateStatistics(entries) {
|
||||
|
||||
let futureFlextimeDays = 0; // Count future flextime days in current month
|
||||
|
||||
// Create a map to check if a day has an entry
|
||||
const entriesMap = {};
|
||||
entries.forEach(entry => {
|
||||
entriesMap[entry.date] = entry;
|
||||
});
|
||||
|
||||
const todayISO = getTodayISO();
|
||||
const isCurrentMonth = currentYear === today.getFullYear() && currentMonth === today.getMonth();
|
||||
|
||||
for (let day = 1; day <= lastDay; day++) {
|
||||
const dateObj = new Date(currentYear, currentMonth, day);
|
||||
const year = dateObj.getFullYear();
|
||||
@@ -1172,31 +1181,35 @@ async function updateStatistics(entries) {
|
||||
const isVacation = vacationDays.has(dateISO);
|
||||
const isFlextime = flextimeDays.has(dateISO);
|
||||
const isWeekendHoliday = isWeekendOrHoliday(dateObj);
|
||||
const hasEntry = entriesMap[dateISO];
|
||||
const isToday = dateISO === todayISO;
|
||||
|
||||
// For today: only count as workday if there's an entry OR timer is running
|
||||
const shouldCountToday = !isToday || hasEntry || (timerStartTime && isCurrentMonth);
|
||||
|
||||
if (!isWeekendHoliday && !isVacation && !isFlextime) {
|
||||
// Normal workday (excluding vacation and flextime days)
|
||||
totalWorkdaysInMonth++;
|
||||
workdaysCount++;
|
||||
if (dateObj <= today) {
|
||||
if (dateObj <= today && shouldCountToday) {
|
||||
workdaysPassed++;
|
||||
}
|
||||
} else if (!isWeekendHoliday && !isVacation && isFlextime) {
|
||||
// Flextime on a workday - still counts as workday in calendar
|
||||
totalWorkdaysInMonth++;
|
||||
workdaysCount++;
|
||||
if (dateObj <= today) {
|
||||
if (dateObj <= today && shouldCountToday) {
|
||||
workdaysPassed++;
|
||||
} else {
|
||||
// Future flextime in current month
|
||||
const isCurrentMonth = currentYear === today.getFullYear() && currentMonth === today.getMonth();
|
||||
if (isCurrentMonth) {
|
||||
if (isCurrentMonth && dateObj > today) {
|
||||
futureFlextimeDays++;
|
||||
}
|
||||
}
|
||||
} else if (isFlextime && isWeekendHoliday) {
|
||||
// Flextime on weekend/holiday counts as additional workday
|
||||
totalWorkdaysInMonth++;
|
||||
if (new Date(dateISO) <= today) {
|
||||
if (new Date(dateISO) <= today && shouldCountToday) {
|
||||
workdaysPassed++;
|
||||
}
|
||||
}
|
||||
@@ -1212,7 +1225,6 @@ async function updateStatistics(entries) {
|
||||
.reduce((sum, entry) => sum + entry.netHours, 0);
|
||||
|
||||
// Add currently running timer hours to actual hours (only for current month)
|
||||
const isCurrentMonth = currentYear === today.getFullYear() && currentMonth === today.getMonth();
|
||||
if (timerStartTime && isCurrentMonth) {
|
||||
const now = Date.now();
|
||||
let elapsedSeconds;
|
||||
|
||||
Reference in New Issue
Block a user