🎯 Fix: Vollständige Behebung der JavaScript exportStats-Funktion und Admin-System-Optimierungen

 **Stats Export API implementiert**:
- Neuer /api/stats/export Endpunkt für CSV-Download
- Umfassende Systemstatistiken mit Drucker-Details
- Zeitbasierte Metriken und Erfolgsraten-Berechnung
- Sichere Authentifizierung und Fehlerbehandlung

 **API-Datenkompatibilität verbessert**:
- Frontend-Aliases hinzugefügt: online_printers, active_jobs, success_rate
- Einheitliche Datenstruktur für Stats-Anzeige
- Korrekte Erfolgsraten-Berechnung mit Null-Division-Schutz

 **Admin-System erweitert**:
- Erweiterte CRUD-Funktionalität für Benutzerverwaltung
- Verbesserte Template-Integration und Formular-Validierung
- Optimierte Datenbankabfragen und Session-Management

🔧 **Technische Details**:
- CSV-Export mit strukturierten Headers und Zeitstempel
- Defensive Programmierung mit umfassender Fehlerbehandlung
- Performance-optimierte Datenbankabfragen
- Vollständige API-Kompatibilität zu bestehender Frontend-Logik

Das MYP-System ist jetzt vollständig funktionsfähig mit korrekter Statistik-Export-Funktionalität.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-06-20 01:32:01 +02:00
parent 321626e9d3
commit 02d18f7f1e
890 changed files with 3592 additions and 31 deletions

View File

@ -165,7 +165,7 @@
<!-- Hauptformular -->
<div class="admin-form-container rounded-2xl p-8 transition-all duration-300">
<form id="userForm" action="{{ url_for('admin.add_user_page') }}" method="POST" class="space-y-8">
<form id="userForm" action="{{ url_for('admin.create_user') }}" method="POST" class="space-y-8">
<!-- CSRF Token -->
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
@ -305,6 +305,144 @@
</div>
</div>
<!-- Erweiterte Profil-Informationen (Optional) -->
<div class="form-field-premium mt-8">
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-6 flex items-center">
<svg class="w-5 h-5 mr-3 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
Erweiterte Profil-Informationen <span class="text-sm font-normal text-slate-500">(Optional)</span>
</h3>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Abteilung -->
<div class="form-field-premium">
<label for="department" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
<svg class="w-4 h-4 inline mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-4m-5 0H9m0 0H5m4 0V9a2 2 0 012-2h2a2 2 0 012 2v12"/>
</svg>
Abteilung
</label>
<input type="text"
id="department"
name="department"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400"
placeholder="z.B. TBA Marienfelde, Produktion, IT">
</div>
<!-- Position -->
<div class="form-field-premium">
<label for="position" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
<svg class="w-4 h-4 inline mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m8 0H8m8 0v6a2 2 0 01-2 2H10a2 2 0 01-2-2V6m8 0V4a2 2 0 00-2-2H10a2 2 0 00-2 2v2"/>
</svg>
Position/Rolle
</label>
<input type="text"
id="position"
name="position"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400"
placeholder="z.B. Ausbilder, Auszubildender, Techniker">
</div>
<!-- Telefonnummer -->
<div class="form-field-premium">
<label for="phone" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
<svg class="w-4 h-4 inline mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/>
</svg>
Telefonnummer
</label>
<input type="tel"
id="phone"
name="phone"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400"
placeholder="+49 30 7566-8000">
</div>
<!-- Bio/Beschreibung -->
<div class="form-field-premium">
<label for="bio" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
<svg class="w-4 h-4 inline mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Kurze Beschreibung
</label>
<textarea id="bio"
name="bio"
rows="3"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 resize-none"
placeholder="Kurze Beschreibung des Benutzers, Verantwortlichkeiten, etc."></textarea>
</div>
</div>
</div>
<!-- Benutzereinstellungen (Optional) -->
<div class="form-field-premium mt-8">
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-6 flex items-center">
<svg class="w-5 h-5 mr-3 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
Benutzereinstellungen <span class="text-sm font-normal text-slate-500">(Optional)</span>
</h3>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Theme Preference -->
<div class="form-field-premium">
<label for="theme_preference" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
Theme-Präferenz
</label>
<select id="theme_preference"
name="theme_preference"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white">
<option value="auto">🔄 Automatisch (System)</option>
<option value="light">☀️ Hell</option>
<option value="dark">🌙 Dunkel</option>
</select>
</div>
<!-- Language Preference -->
<div class="form-field-premium">
<label for="language_preference" class="block text-sm font-medium text-slate-900 dark:text-white mb-3">
Sprache
</label>
<select id="language_preference"
name="language_preference"
class="input-premium w-full px-4 py-3 rounded-xl focus:outline-none transition-all duration-300 text-slate-900 dark:text-white">
<option value="de">🇩🇪 Deutsch</option>
<option value="en">🇺🇸 English</option>
</select>
</div>
<!-- Email Notifications -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="email_notifications"
name="email_notifications"
checked
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="email_notifications" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">E-Mail-Benachrichtigungen</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Benutzer erhält E-Mail-Benachrichtigungen</div>
</label>
</div>
<!-- Browser Notifications -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="browser_notifications"
name="browser_notifications"
checked
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="browser_notifications" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Browser-Benachrichtigungen</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Push-Benachrichtigungen im Browser</div>
</label>
</div>
</div>
</div>
<!-- Granulare Berechtigungen -->
<div class="form-field-premium mt-8" id="permissionsSection">
<label class="block text-sm font-semibold text-slate-900 dark:text-white mb-3 transition-colors duration-300">
@ -350,6 +488,66 @@
<div class="text-sm text-slate-600 dark:text-slate-400">Benutzer kann Gastanfragen bearbeiten und genehmigen/ablehnen</div>
</label>
</div>
<!-- Can Manage Printers -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="can_manage_printers"
name="can_manage_printers"
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="can_manage_printers" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Kann Drucker verwalten</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Drucker hinzufügen, bearbeiten, Smart Plugs steuern</div>
</label>
</div>
<!-- Can View All Jobs -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="can_view_all_jobs"
name="can_view_all_jobs"
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="can_view_all_jobs" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Kann alle Aufträge einsehen</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Zugriff auf alle Druckaufträge, nicht nur eigene</div>
</label>
</div>
<!-- Can Access Admin Panel -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="can_access_admin_panel"
name="can_access_admin_panel"
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="can_access_admin_panel" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Kann Admin Panel einsehen</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Zugriff auf System-Statistiken und Monitoring</div>
</label>
</div>
<!-- Can Manage Users -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="can_manage_users"
name="can_manage_users"
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="can_manage_users" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Kann Benutzer verwalten</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Benutzer erstellen, bearbeiten und löschen</div>
</label>
</div>
<!-- Can Access Energy Monitoring -->
<div class="flex items-center space-x-3">
<input type="checkbox"
id="can_access_energy_monitoring"
name="can_access_energy_monitoring"
class="w-5 h-5 text-blue-600 bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-blue-500 dark:focus:ring-blue-600 focus:ring-2">
<label for="can_access_energy_monitoring" class="flex-1 cursor-pointer">
<div class="font-medium text-slate-900 dark:text-white">Kann Energiemonitoring einsehen</div>
<div class="text-sm text-slate-600 dark:text-slate-400">Zugriff auf Stromverbrauch und Smart Plug Daten</div>
</label>
</div>
</div>
</div>
</div>