From 2aa4e6f037a1589d8930035d7a98d816b26ccfb8 Mon Sep 17 00:00:00 2001 From: Carsten Graf Date: Mon, 16 Mar 2026 19:40:43 +0100 Subject: [PATCH] Added Charts im Overtime-breakdown --- ...n_mit_admin-konfiguration_20cdec3c.plan.md | 177 ------- public/js/dashboard.js | 7 + views/dashboard.ejs | 5 +- views/overtime-breakdown.ejs | 435 ++++++++++++++++++ 4 files changed, 446 insertions(+), 178 deletions(-) delete mode 100644 .cursor/plans/mysql-integration_mit_admin-konfiguration_20cdec3c.plan.md diff --git a/.cursor/plans/mysql-integration_mit_admin-konfiguration_20cdec3c.plan.md b/.cursor/plans/mysql-integration_mit_admin-konfiguration_20cdec3c.plan.md deleted file mode 100644 index b6304fd..0000000 --- a/.cursor/plans/mysql-integration_mit_admin-konfiguration_20cdec3c.plan.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -name: MySQL-Integration mit Admin-Konfiguration -overview: Erweitere das System um MySQL-Unterstützung mit einer Admin-Oberfläche zur Konfiguration. Die Datenbank wird in einer Konfigurationsdatei gespeichert und kann im Admin-Bereich geändert werden (erfordert Server-Neustart). -todos: [] ---- - -# MySQL/MariaDB-Integration mit Admin-Konfiguration - -## Übersicht - -Erweitere das System um MySQL/MariaDB-Unterstützung neben SQLite3. Die Datenbank-Konfiguration wird in einer Konfigurationsdatei gespeichert und kann im Admin-Bereich verwaltet werden. Ein Wechsel erfordert einen Server-Neustart. - -**Hinweis:** MariaDB ist vollständig MySQL-kompatibel und funktioniert mit derselben Schnittstelle (`mysql2` Package). - -## Architektur - -### Datenbank-Abstraktionsschicht - -Erstelle eine Abstraktionsschicht, die sowohl SQLite als auch MySQL unterstützt: - -1. **Neue Datei:** `database/db-adapter.js` - - - Abstrahiert `db.get()`, `db.run()`, `db.all()` für beide Datenbanken - - Promise-basierte API (für bessere Kompatibilität) - - Automatische Fehlerbehandlung - - SQL-Dialekt-Anpassung (z.B. `AUTOINCREMENT` vs `AUTO_INCREMENT`) - -2. **Neue Datei:** `database/sqlite-adapter.js` - - - SQLite-spezifische Implementierung - - Wrapper um sqlite3 - -3. **Neue Datei:** `database/mysql-adapter.js` - - - MySQL/MariaDB-spezifische Implementierung - - Verwendet `mysql2` Package (funktioniert mit MySQL und MariaDB) - -4. **Anpassung:** `database.js` - - - Lädt Konfiguration aus `config/database.json` - - Initialisiert entsprechenden Adapter - - Behält `initDatabase()` Funktion bei - -### Konfigurationsdatei - -**Neue Datei:** `config/database.json` - -```json -{ - "type": "sqlite", - "sqlite": { - "path": "./stundenerfassung.db" - }, - "mysql": { - "host": "localhost", - "port": 3306, - "user": "root", - "password": "", - "database": "stundenerfassung", - "charset": "utf8mb4" - } -} -``` - -### Admin-Interface - -**Anpassung:** `routes/admin.js` - -- Neue Route `/admin/database/config` (GET/PUT) -- Zeigt aktuelle Datenbank-Konfiguration -- Formular zum Ändern der Datenbank-Einstellungen -- Warnung bei Wechsel (Server-Neustart erforderlich) - -**Anpassung:** `views/admin.ejs` - -- Neuer Abschnitt "Datenbank-Konfiguration" -- Formular für SQLite/MySQL/MariaDB-Auswahl -- Eingabefelder für MySQL/MariaDB-Verbindungsdaten -- Test-Verbindung Button -- Warnung bei Änderungen -- Hinweis: MariaDB funktioniert mit MySQL-Konfiguration - -### SQL-Anpassungen - -**Unterschiede zwischen SQLite und MySQL:** - -- `INTEGER PRIMARY KEY AUTOINCREMENT` → `INT AUTO_INCREMENT PRIMARY KEY` -- `TEXT` → `VARCHAR(255)` oder `TEXT` -- `REAL` → `DOUBLE` oder `DECIMAL` -- `TEXT` (unbegrenzt) → `TEXT` oder `LONGTEXT` -- `DATETIME DEFAULT CURRENT_TIMESTAMP` → `DATETIME DEFAULT CURRENT_TIMESTAMP` (gleich) -- `INSERT OR IGNORE` → `INSERT IGNORE` -- `COLLATE NOCASE` → `COLLATE utf8mb4_general_ci` (für case-insensitive) -- Foreign Keys müssen in MySQL explizit aktiviert werden - -**Anpassung:** `database.js` - `initDatabase()` - -- SQL-Generierung basierend auf Datenbanktyp -- Separate CREATE TABLE Statements für SQLite und MySQL -- Migrationen anpassen (ALTER TABLE Syntax) - -### Package-Abhängigkeiten - -**Anpassung:** `package.json` - -- `mysql2` hinzufügen (bessere Promise-Unterstützung als `mysql`, funktioniert mit MySQL und MariaDB) - -### Services und Routes - -Alle Dateien, die `db` verwenden, müssen angepasst werden: - -- `routes/*.js` (7 Dateien) -- `services/*.js` (5 Dateien) -- `checkin-server.js` - -**Änderungen:** - -- Promise-basierte Queries verwenden (statt Callbacks) -- Oder: Callback-Wrapper in Adapter - -### Initialisierung - -**Anpassung:** `server.js` - -- Prüft ob `config/database.json` existiert -- Erstellt Standard-Konfiguration falls nicht vorhanden -- Initialisiert Datenbank entsprechend Konfiguration - -## Implementierungsschritte - -1. **Datenbank-Abstraktionsschicht erstellen** - - - `database/db-adapter.js` - Interface - - `database/sqlite-adapter.js` - SQLite-Implementierung - - `database/mysql-adapter.js` - MySQL-Implementierung - -2. **Konfigurationssystem** - - - `config/database.json` Template - - Konfigurations-Loader in `database.js` - -3. **SQL-Anpassungen** - - - `initDatabase()` für beide Datenbanken anpassen - - SQL-Dialekt-Unterschiede behandeln - -4. **Admin-Interface** - - - Route für Datenbank-Konfiguration - - View mit Konfigurationsformular - - Test-Verbindung Funktion - -5. **Alle Queries anpassen** - - - Callbacks zu Promises oder Callback-Wrapper - - SQLite-spezifische Syntax entfernen (z.B. `COLLATE NOCASE`) - -6. **Dokumentation** - - - README.md aktualisieren - - Konfigurationsanleitung - -## Technische Details - -- **MySQL/MariaDB-Package:** `mysql2` (bessere Promise-Unterstützung, funktioniert mit beiden) -- **Kompatibilität:** MariaDB ist vollständig MySQL-kompatibel, verwendet dieselbe Konfiguration -- **Fallback:** Bei Fehler in MySQL/MariaDB-Verbindung auf SQLite zurückfallen -- **Validierung:** Test-Verbindung vor Speichern der Konfiguration -- **Sicherheit:** MySQL/MariaDB-Passwörter verschlüsselt in Config speichern (optional) - -## Dateien die angepasst werden müssen - -- `database.js` → `database/` Ordner mit mehreren Dateien -- `routes/admin.js` - Datenbank-Konfiguration -- `views/admin.ejs` - Konfigurations-UI -- `package.json` - mysql2 Dependency -- `server.js` - Konfigurationspr \ No newline at end of file diff --git a/public/js/dashboard.js b/public/js/dashboard.js index a87b138..c3b98af 100644 --- a/public/js/dashboard.js +++ b/public/js/dashboard.js @@ -92,6 +92,13 @@ async function loadUserStats() { if (totalVacationEl) { totalVacationEl.textContent = (stats.urlaubstage || 0).toFixed(1); } + + // Urlaubstage-Übertrag der Verwaltung anzeigen (Offset) + const vacationOffsetEl = document.getElementById('vacationOffsetDays'); + if (vacationOffsetEl) { + const offset = stats.vacationOffsetDays || 0; + vacationOffsetEl.textContent = (offset >= 0 ? '+' : '-') + offset.toFixed(1); + } // Verplante Urlaubstage anzeigen const plannedVacationEl = document.getElementById('plannedVacation'); diff --git a/views/dashboard.ejs b/views/dashboard.ejs index 2ca8af2..c6e56fa 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -100,8 +100,11 @@ Verbleibende Urlaubstage ? -
-
+
-
Tage
von - Tagen
+
+ Korrektur Verwaltung: - Tage +
diff --git a/views/overtime-breakdown.ejs b/views/overtime-breakdown.ejs index a5a0484..0f08d50 100644 --- a/views/overtime-breakdown.ejs +++ b/views/overtime-breakdown.ejs @@ -105,6 +105,46 @@ .summary-value.overtime-negative { color: #e74c3c !important; } + .overtime-chart-container { + margin-top: 30px; + background: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + padding: 20px; + } + .overtime-chart-header { + display: flex; + justify-content: space-between; + align-items: baseline; + margin-bottom: 10px; + } + .overtime-chart-title { + font-size: 20px; + margin: 0; + color: #2c3e50; + } + .overtime-chart-subtitle { + font-size: 13px; + color: #777; + text-align: right; + } + .overtime-chart-wrapper { + position: relative; + width: 100%; + min-height: 260px; + } + .weekly-overtime-chart-container { + margin-top: 20px; + background: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + padding: 20px; + } + .weekly-overtime-chart-title { + font-size: 18px; + margin: 0 0 10px 0; + color: #2c3e50; + } @@ -185,8 +225,29 @@ + + + +
+