🎉 Improved log management system & added advanced settings 🚀

This commit is contained in:
2025-06-01 14:50:01 +02:00
parent 7fa7da74af
commit 61479a1c31
24 changed files with 1272 additions and 3 deletions

View File

@ -855,8 +855,8 @@ class MaintenanceModal {
navigateToSettings() {
try {
// Direkte Navigation zu den Optimierungs-Einstellungen
window.location.href = '/api/optimization/settings';
// Navigation zu den erweiterten Admin-Einstellungen (HTML-Seite)
window.location.href = '/admin/advanced-settings';
} catch (error) {
console.error('Fehler beim Navigieren zu den Einstellungen:', error);
showNotification('Fehler beim Öffnen der Einstellungen', 'error');

View File

@ -0,0 +1,893 @@
{% extends "base.html" %}
{% block title %}Erweiterte Einstellungen - Mercedes-Benz TBA Marienfelde{% endblock %}
{% block head %}
{{ super() }}
<!-- CSRF Token für AJAX-Anfragen -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<style>
/* Glasmorphismus und moderne Effekte */
.glass-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.dark .glass-card {
background: rgba(30, 41, 59, 0.3);
border-color: rgba(148, 163, 184, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.glass-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
border-color: rgba(59, 130, 246, 0.4);
}
.dark .glass-card:hover {
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
/* Gradient Backgrounds */
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.gradient-bg-alt {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.gradient-bg-success {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.gradient-bg-warning {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
/* Stat Cards mit Hover-Effekten */
.stat-card {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.7) 100%);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 20px;
padding: 2rem;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.dark .stat-card {
background: linear-gradient(135deg, rgba(30, 41, 59, 0.9) 0%, rgba(15, 23, 42, 0.7) 100%);
border-color: rgba(148, 163, 184, 0.2);
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.stat-card:hover::before {
left: 100%;
}
.stat-card:hover {
transform: translateY(-12px) rotateX(5deg);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}
/* Moderne Toggle Switches */
.modern-toggle {
position: relative;
display: inline-block;
width: 80px;
height: 40px;
}
.modern-toggle input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, #e2e8f0, #cbd5e1);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 40px;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}
.toggle-slider:before {
position: absolute;
content: "";
height: 32px;
width: 32px;
left: 4px;
bottom: 4px;
background: linear-gradient(135deg, #ffffff, #f8fafc);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 50%;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
input:checked + .toggle-slider {
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
box-shadow: 0 0 20px rgba(59, 130, 246, 0.4);
}
input:checked + .toggle-slider:before {
transform: translateX(40px);
background: linear-gradient(135deg, #ffffff, #f0f9ff);
}
/* Animierte Buttons */
.modern-btn {
position: relative;
overflow: hidden;
border-radius: 16px;
padding: 1rem 2rem;
font-weight: 600;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: none;
cursor: pointer;
text-transform: none;
}
.modern-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
transition: left 0.5s;
}
.modern-btn:hover::before {
left: 100%;
}
.modern-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.btn-primary {
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
color: white;
}
.btn-success {
background: linear-gradient(135deg, #10b981, #059669);
color: white;
}
.btn-warning {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
}
.btn-danger {
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
}
.btn-purple {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
color: white;
}
.btn-indigo {
background: linear-gradient(135deg, #6366f1, #4f46e5);
color: white;
}
/* Floating Animation */
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.floating {
animation: float 3s ease-in-out infinite;
}
/* Pulse Animation für Status */
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 20px rgba(34, 197, 94, 0.4); }
50% { box-shadow: 0 0 30px rgba(34, 197, 94, 0.8); }
}
.pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
/* Form Inputs */
.modern-input {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
padding: 1rem 1.5rem;
transition: all 0.3s ease;
color: inherit;
}
.modern-input:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
background: rgba(255, 255, 255, 0.15);
}
.dark .modern-input {
background: rgba(30, 41, 59, 0.3);
border-color: rgba(148, 163, 184, 0.3);
}
/* Icon Containers */
.icon-container {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
border-radius: 16px;
padding: 1rem;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.icon-container:hover {
transform: scale(1.1) rotate(5deg);
}
/* Loading Overlay Enhancement */
.loading-content {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 24px;
padding: 3rem;
}
.dark .loading-content {
background: rgba(30, 41, 59, 0.3);
border-color: rgba(148, 163, 184, 0.2);
}
/* Notification Enhancement */
.notification {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
</style>
{% endblock %}
{% block content %}
<div class="min-h-screen bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 dark:from-slate-900 dark:via-purple-900 dark:to-slate-800">
<!-- Header mit Glasmorphismus -->
<div class="glass-card mx-4 mt-4 mb-8">
<div class="max-w-7xl mx-auto px-6 py-8">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-6">
<a href="{{ url_for('admin_page') }}" class="p-3 hover:bg-white/20 dark:hover:bg-slate-700/30 rounded-2xl transition-all duration-300 group">
<svg class="w-7 h-7 text-slate-600 dark:text-slate-400 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
</a>
<div>
<h1 class="text-4xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent">
Erweiterte Einstellungen
</h1>
<p class="text-slate-600 dark:text-slate-400 mt-2 text-lg">System-Optimierung und Wartungsoptionen</p>
</div>
</div>
<!-- Status Indicator mit Animation -->
<div class="flex items-center space-x-3 bg-gradient-to-r from-green-400 to-emerald-500 px-6 py-3 rounded-2xl pulse-glow">
<div class="w-4 h-4 bg-white rounded-full animate-pulse"></div>
<span class="text-white font-semibold">System Online</span>
</div>
</div>
</div>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-12">
<!-- System-Übersicht mit verbessertem Design -->
<div class="glass-card p-8 mb-12 floating">
<div class="flex items-center space-x-4 mb-8">
<div class="icon-container">
<span class="text-3xl">📊</span>
</div>
<h2 class="text-3xl font-bold bg-gradient-to-r from-blue-600 to-cyan-600 bg-clip-text text-transparent">
System-Übersicht
</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div class="stat-card group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-2">Registrierte Benutzer</p>
<p class="text-4xl font-bold text-slate-900 dark:text-white">{{ stats.total_users }}</p>
</div>
<div class="icon-container bg-gradient-to-br from-blue-500 to-blue-600 text-white">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
</div>
</div>
</div>
<div class="stat-card group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-2">Aktive Drucker</p>
<p class="text-4xl font-bold text-slate-900 dark:text-white">{{ stats.active_printers }}/{{ stats.total_printers }}</p>
</div>
<div class="icon-container bg-gradient-to-br from-green-500 to-emerald-600 text-white">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/>
</svg>
</div>
</div>
</div>
<div class="stat-card group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-2">Warteschlange</p>
<p class="text-4xl font-bold text-slate-900 dark:text-white">{{ stats.pending_jobs }}</p>
</div>
<div class="icon-container bg-gradient-to-br from-purple-500 to-purple-600 text-white">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-12">
<!-- Optimierungs-Einstellungen -->
<div class="glass-card p-8">
<div class="flex items-center space-x-4 mb-8">
<div class="icon-container">
<span class="text-3xl">⚙️</span>
</div>
<h2 class="text-3xl font-bold bg-gradient-to-r from-orange-600 to-red-600 bg-clip-text text-transparent">
Optimierungs-Einstellungen
</h2>
</div>
<form id="optimization-form" class="space-y-8">
<!-- Algorithmus-Auswahl -->
<div>
<label class="block text-lg font-semibold text-slate-700 dark:text-slate-300 mb-4">Optimierungs-Algorithmus</label>
<select name="algorithm" id="algorithm" class="modern-input w-full">
<option value="round_robin" {{ 'selected' if optimization_settings.algorithm == 'round_robin' else '' }}>Round Robin (Gleichmäßige Verteilung)</option>
<option value="load_balance" {{ 'selected' if optimization_settings.algorithm == 'load_balance' else '' }}>Load Balancing (Lastverteilung)</option>
<option value="priority_based" {{ 'selected' if optimization_settings.algorithm == 'priority_based' else '' }}>Prioritätsbasiert</option>
</select>
</div>
<!-- Toggle-Optionen -->
<div class="space-y-6">
<div class="flex items-center justify-between p-4 bg-white/10 dark:bg-slate-800/30 rounded-2xl backdrop-blur-sm">
<div>
<label class="text-lg font-semibold text-slate-700 dark:text-slate-300">Entfernung berücksichtigen</label>
<p class="text-sm text-slate-500 dark:text-slate-400 mt-1">Drucker-Standort bei Optimierung einbeziehen</p>
</div>
<label class="modern-toggle">
<input type="checkbox" name="consider_distance" {{ 'checked' if optimization_settings.consider_distance else '' }}>
<span class="toggle-slider"></span>
</label>
</div>
<div class="flex items-center justify-between p-4 bg-white/10 dark:bg-slate-800/30 rounded-2xl backdrop-blur-sm">
<div>
<label class="text-lg font-semibold text-slate-700 dark:text-slate-300">Rüstzeiten minimieren</label>
<p class="text-sm text-slate-500 dark:text-slate-400 mt-1">Materialwechsel-Zeiten reduzieren</p>
</div>
<label class="modern-toggle">
<input type="checkbox" name="minimize_changeover" {{ 'checked' if optimization_settings.minimize_changeover else '' }}>
<span class="toggle-slider"></span>
</label>
</div>
<div class="flex items-center justify-between p-4 bg-white/10 dark:bg-slate-800/30 rounded-2xl backdrop-blur-sm">
<div>
<label class="text-lg font-semibold text-slate-700 dark:text-slate-300">Auto-Optimierung</label>
<p class="text-sm text-slate-500 dark:text-slate-400 mt-1">Automatische Optimierung alle 30 Minuten</p>
</div>
<label class="modern-toggle">
<input type="checkbox" name="auto_optimization_enabled" {{ 'checked' if optimization_settings.auto_optimization_enabled else '' }}>
<span class="toggle-slider"></span>
</label>
</div>
</div>
<!-- Numerische Einstellungen -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-lg font-semibold text-slate-700 dark:text-slate-300 mb-3">Max. Batch-Größe</label>
<input type="number" name="max_batch_size" value="{{ optimization_settings.max_batch_size }}" min="1" max="50" class="modern-input w-full">
</div>
<div>
<label class="block text-lg font-semibold text-slate-700 dark:text-slate-300 mb-3">Zeitfenster (Stunden)</label>
<input type="number" name="time_window" value="{{ optimization_settings.time_window }}" min="1" max="168" class="modern-input w-full">
</div>
</div>
<!-- Speichern Button -->
<button type="submit" class="modern-btn btn-primary w-full text-lg py-4">
💾 Einstellungen speichern
</button>
</form>
</div>
<!-- Wartungs-Aktionen -->
<div class="glass-card p-8">
<div class="flex items-center space-x-4 mb-8">
<div class="icon-container">
<span class="text-3xl">🔧</span>
</div>
<h2 class="text-3xl font-bold bg-gradient-to-r from-green-600 to-teal-600 bg-clip-text text-transparent">
Wartungs-Aktionen
</h2>
</div>
<!-- Wartungs-Informationen -->
<div class="bg-white/20 dark:bg-slate-800/40 backdrop-blur-sm rounded-2xl p-6 mb-8">
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-4">Wartungs-Status</h3>
<div class="space-y-3">
<div class="flex justify-between items-center">
<span class="text-slate-600 dark:text-slate-400">Letztes Backup:</span>
<span class="text-slate-900 dark:text-white font-semibold">{{ maintenance_info.last_backup }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-slate-600 dark:text-slate-400">Log-Dateien:</span>
<span class="text-slate-900 dark:text-white font-semibold">{{ maintenance_info.log_files_count }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-slate-600 dark:text-slate-400">Cache-Größe:</span>
<span class="text-slate-900 dark:text-white font-semibold">{{ maintenance_info.cache_size }}</span>
</div>
</div>
</div>
<!-- Wartungs-Buttons -->
<div class="space-y-4">
<button id="advanced-clear-cache" class="modern-btn btn-primary w-full">
🗑️ System-Cache leeren
</button>
<button id="advanced-optimize-db" class="modern-btn btn-success w-full">
🔧 Datenbank optimieren
</button>
<button id="advanced-create-backup" class="modern-btn btn-purple w-full">
💾 Vollständiges Backup erstellen
</button>
<button id="advanced-cleanup-logs" class="modern-btn btn-warning w-full">
📋 Log-Dateien bereinigen
</button>
<button id="advanced-system-check" class="modern-btn btn-indigo w-full">
🔍 System-Integritätsprüfung
</button>
</div>
</div>
</div>
<!-- Erweiterte Optionen -->
<div class="glass-card p-8 mt-12">
<div class="flex items-center space-x-4 mb-8">
<div class="icon-container">
<span class="text-3xl">🚀</span>
</div>
<h2 class="text-3xl font-bold bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
Erweiterte Optionen
</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<!-- Debug-Modus -->
<div class="glass-card p-6 hover:scale-105 transition-all duration-300">
<div class="text-center">
<div class="icon-container mx-auto mb-4 bg-gradient-to-br from-red-500 to-pink-600 text-white">
<span class="text-2xl">🐛</span>
</div>
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-3">Debug-Modus</h3>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-6">Erweiterte Protokollierung für Fehlerdiagnose</p>
<label class="modern-toggle mx-auto">
<input type="checkbox" id="debug-mode">
<span class="toggle-slider"></span>
</label>
</div>
</div>
<!-- Wartungsmodus -->
<div class="glass-card p-6 hover:scale-105 transition-all duration-300">
<div class="text-center">
<div class="icon-container mx-auto mb-4 bg-gradient-to-br from-yellow-500 to-orange-600 text-white">
<span class="text-2xl">🚧</span>
</div>
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-3">Wartungsmodus</h3>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-6">System für Wartungsarbeiten sperren</p>
<label class="modern-toggle mx-auto">
<input type="checkbox" id="maintenance-mode">
<span class="toggle-slider"></span>
</label>
</div>
</div>
<!-- Performance-Monitoring -->
<div class="glass-card p-6 hover:scale-105 transition-all duration-300">
<div class="text-center">
<div class="icon-container mx-auto mb-4 bg-gradient-to-br from-blue-500 to-cyan-600 text-white">
<span class="text-2xl">📈</span>
</div>
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-3">Performance-Monitoring</h3>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-6">Detaillierte Leistungsüberwachung</p>
<label class="modern-toggle mx-auto">
<input type="checkbox" id="performance-monitoring">
<span class="toggle-slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Enhanced Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 hidden">
<div class="flex items-center justify-center h-full">
<div class="loading-content">
<div class="flex items-center space-x-6">
<div class="relative">
<div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-200"></div>
<div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-500 border-t-transparent absolute top-0 left-0"></div>
</div>
<span class="text-slate-900 dark:text-white font-semibold text-lg">Wird verarbeitet...</span>
</div>
</div>
</div>
</div>
<script>
// ===== ERWEITERTE EINSTELLUNGEN JAVASCRIPT =====
class AdvancedSettings {
constructor() {
this.csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
this.initializeEventListeners();
this.initializeAnimations();
}
initializeEventListeners() {
// Optimierungs-Formular
const optimizationForm = document.getElementById('optimization-form');
if (optimizationForm) {
optimizationForm.addEventListener('submit', (e) => {
e.preventDefault();
this.saveOptimizationSettings(new FormData(optimizationForm));
});
}
// Wartungs-Buttons
document.getElementById('advanced-clear-cache')?.addEventListener('click', () => this.clearCache());
document.getElementById('advanced-optimize-db')?.addEventListener('click', () => this.optimizeDatabase());
document.getElementById('advanced-create-backup')?.addEventListener('click', () => this.createBackup());
document.getElementById('advanced-cleanup-logs')?.addEventListener('click', () => this.cleanupLogs());
document.getElementById('advanced-system-check')?.addEventListener('click', () => this.systemCheck());
// Erweiterte Optionen
document.getElementById('debug-mode')?.addEventListener('change', (e) => this.toggleDebugMode(e.target.checked));
document.getElementById('maintenance-mode')?.addEventListener('change', (e) => this.toggleMaintenanceMode(e.target.checked));
document.getElementById('performance-monitoring')?.addEventListener('change', (e) => this.togglePerformanceMonitoring(e.target.checked));
}
initializeAnimations() {
// Intersection Observer für Scroll-Animationen
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
});
document.querySelectorAll('.glass-card').forEach(card => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
observer.observe(card);
});
}
async saveOptimizationSettings(formData) {
try {
this.showLoading(true);
const settings = {
algorithm: formData.get('algorithm'),
consider_distance: formData.get('consider_distance') === 'on',
minimize_changeover: formData.get('minimize_changeover') === 'on',
auto_optimization_enabled: formData.get('auto_optimization_enabled') === 'on',
max_batch_size: parseInt(formData.get('max_batch_size')),
time_window: parseInt(formData.get('time_window'))
};
const response = await fetch('/api/optimization/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify(settings)
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ Optimierungs-Einstellungen erfolgreich gespeichert!', 'success');
} else {
this.showNotification('❌ Fehler beim Speichern der Einstellungen', 'error');
}
} catch (error) {
console.error('Fehler beim Speichern der Optimierungs-Einstellungen:', error);
this.showNotification('❌ Fehler beim Speichern der Einstellungen', 'error');
} finally {
this.showLoading(false);
}
}
async clearCache() {
if (!confirm('🗑️ Möchten Sie wirklich den System-Cache leeren?')) return;
try {
this.showLoading(true);
const response = await fetch('/api/admin/maintenance/clear-cache', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ System-Cache erfolgreich geleert!', 'success');
} else {
this.showNotification('❌ Fehler beim Leeren des Cache', 'error');
}
} catch (error) {
this.showNotification('❌ Fehler beim Leeren des Cache', 'error');
} finally {
this.showLoading(false);
}
}
async optimizeDatabase() {
if (!confirm('🔧 Möchten Sie die Datenbank optimieren? Dies kann einige Minuten dauern.')) return;
try {
this.showLoading(true);
const response = await fetch('/api/admin/maintenance/optimize-database', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ Datenbank erfolgreich optimiert!', 'success');
} else {
this.showNotification('❌ Fehler bei der Datenbank-Optimierung', 'error');
}
} catch (error) {
this.showNotification('❌ Fehler bei der Datenbank-Optimierung', 'error');
} finally {
this.showLoading(false);
}
}
async createBackup() {
if (!confirm('💾 Möchten Sie ein vollständiges System-Backup erstellen?')) return;
try {
this.showLoading(true);
const response = await fetch('/api/admin/maintenance/create-backup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ Backup erfolgreich erstellt!', 'success');
} else {
this.showNotification('❌ Fehler beim Erstellen des Backups', 'error');
}
} catch (error) {
this.showNotification('❌ Fehler beim Erstellen des Backups', 'error');
} finally {
this.showLoading(false);
}
}
async cleanupLogs() {
if (!confirm('📋 Möchten Sie alte Log-Dateien bereinigen? (älter als 30 Tage)')) return;
try {
this.showLoading(true);
const response = await fetch('/api/admin/maintenance/cleanup-logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ Log-Dateien erfolgreich bereinigt!', 'success');
} else {
this.showNotification('❌ Fehler beim Bereinigen der Log-Dateien', 'error');
}
} catch (error) {
this.showNotification('❌ Fehler beim Bereinigen der Log-Dateien', 'error');
} finally {
this.showLoading(false);
}
}
async systemCheck() {
try {
this.showLoading(true);
const response = await fetch('/api/admin/maintenance/system-check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const result = await response.json();
if (result.success) {
this.showNotification('✅ System-Integritätsprüfung abgeschlossen!', 'success');
} else {
this.showNotification('❌ Fehler bei der System-Integritätsprüfung', 'error');
}
} catch (error) {
this.showNotification('❌ Fehler bei der System-Integritätsprüfung', 'error');
} finally {
this.showLoading(false);
}
}
toggleDebugMode(enabled) {
console.log('Debug-Modus:', enabled ? 'aktiviert' : 'deaktiviert');
this.showNotification(`🐛 Debug-Modus ${enabled ? 'aktiviert' : 'deaktiviert'}`, 'info');
}
toggleMaintenanceMode(enabled) {
console.log('Wartungsmodus:', enabled ? 'aktiviert' : 'deaktiviert');
this.showNotification(`🚧 Wartungsmodus ${enabled ? 'aktiviert' : 'deaktiviert'}`, enabled ? 'warning' : 'info');
}
togglePerformanceMonitoring(enabled) {
console.log('Performance-Monitoring:', enabled ? 'aktiviert' : 'deaktiviert');
this.showNotification(`📈 Performance-Monitoring ${enabled ? 'aktiviert' : 'deaktiviert'}`, 'info');
}
showLoading(show) {
const overlay = document.getElementById('loading-overlay');
if (overlay) {
if (show) {
overlay.classList.remove('hidden');
} else {
overlay.classList.add('hidden');
}
}
}
showNotification(message, type = 'info') {
// Erstelle moderne Notification mit Glasmorphismus
const notification = document.createElement('div');
notification.className = `notification fixed top-6 right-6 z-50 p-6 max-w-sm transition-all duration-500 transform translate-x-full opacity-0 ${
type === 'success' ? 'border-green-400' :
type === 'error' ? 'border-red-400' :
type === 'warning' ? 'border-yellow-400' :
'border-blue-400'
}`;
notification.innerHTML = `
<div class="flex items-center space-x-4">
<div class="flex-shrink-0 text-2xl">
${type === 'success' ? '✅' : type === 'error' ? '❌' : type === 'warning' ? '⚠️' : ''}
</div>
<div class="text-slate-900 dark:text-white font-medium">${message}</div>
<button onclick="this.parentElement.parentElement.remove()" class="ml-auto text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
`;
document.body.appendChild(notification);
// Animation einblenden
setTimeout(() => {
notification.style.transform = 'translateX(0)';
notification.style.opacity = '1';
}, 100);
// Automatisch entfernen nach 5 Sekunden
setTimeout(() => {
if (notification.parentNode) {
notification.style.transform = 'translateX(100%)';
notification.style.opacity = '0';
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 500);
}
}, 5000);
}
}
// Initialisierung nach DOM-Laden
document.addEventListener('DOMContentLoaded', function() {
new AdvancedSettings();
});
</script>
{% endblock %}