manage-your-printer/templates/admin_advanced_settings.html
2025-06-04 10:03:22 +02:00

981 lines
46 KiB
HTML

{% 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>
:root {
/* Mercedes-Benz Corporate Colors */
--mb-silver: #c4c4c4;
--mb-dark-silver: #a0a0a0;
--mb-black: #000000;
--mb-white: #ffffff;
--mb-blue: #0f4c75;
--mb-light-blue: #3282b8;
--mb-accent: #00adef;
--mb-success: #00d4aa;
--mb-warning: #ffb800;
--mb-error: #e74c3c;
/* Gradients */
--mb-gradient-primary: linear-gradient(135deg, var(--mb-blue) 0%, var(--mb-light-blue) 100%);
--mb-gradient-silver: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
--mb-gradient-dark: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
/* Shadows */
--mb-shadow-light: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--mb-shadow-medium: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--mb-shadow-large: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.mb-card {
background: var(--mb-gradient-silver);
border: 1px solid rgba(196, 196, 196, 0.3);
border-radius: 20px;
box-shadow: var(--mb-shadow-medium);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.mb-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--mb-gradient-primary);
opacity: 0;
transition: opacity 0.3s ease;
}
.mb-card:hover::before {
opacity: 1;
}
.dark .mb-card {
background: var(--mb-gradient-dark);
border-color: rgba(255, 255, 255, 0.1);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.1);
}
.mb-card:hover {
transform: translateY(-4px);
box-shadow: var(--mb-shadow-large);
}
.dark .mb-card:hover {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.2);
}
.mb-stat-card {
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(196, 196, 196, 0.2);
border-radius: 16px;
padding: 1.5rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
backdrop-filter: blur(10px);
}
.dark .mb-stat-card {
background: rgba(26, 26, 26, 0.9);
border-color: rgba(255, 255, 255, 0.1);
}
.mb-stat-card:hover {
transform: scale(1.02);
box-shadow: var(--mb-shadow-medium);
}
.mb-stat-card .stat-icon {
background: var(--mb-gradient-primary);
border-radius: 12px;
padding: 0.75rem;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--mb-shadow-light);
}
.mb-toggle {
position: relative;
display: inline-block;
width: 64px;
height: 36px;
}
.mb-toggle input {
opacity: 0;
width: 0;
height: 0;
}
.mb-toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--mb-silver);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 36px;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}
.mb-toggle-slider:before {
position: absolute;
content: "";
height: 28px;
width: 28px;
left: 4px;
bottom: 4px;
background: var(--mb-white);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 50%;
box-shadow: var(--mb-shadow-light);
}
.mb-toggle input:checked + .mb-toggle-slider {
background: var(--mb-gradient-primary);
}
.mb-toggle input:checked + .mb-toggle-slider:before {
transform: translateX(28px);
box-shadow: var(--mb-shadow-medium);
}
.mb-btn {
background: var(--mb-gradient-primary);
color: var(--mb-white);
border: none;
border-radius: 12px;
padding: 0.875rem 1.5rem;
font-weight: 600;
font-size: 0.875rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--mb-shadow-light);
position: relative;
overflow: hidden;
}
.mb-btn::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;
}
.mb-btn:hover::before {
left: 100%;
}
.mb-btn:hover {
transform: translateY(-2px);
box-shadow: var(--mb-shadow-medium);
}
.mb-btn:active {
transform: translateY(0);
}
.mb-btn-success {
background: linear-gradient(135deg, var(--mb-success) 0%, #00b894 100%);
}
.mb-btn-warning {
background: linear-gradient(135deg, var(--mb-warning) 0%, #f39c12 100%);
}
.mb-btn-error {
background: linear-gradient(135deg, var(--mb-error) 0%, #c0392b 100%);
}
.mb-btn-secondary {
background: linear-gradient(135deg, var(--mb-silver) 0%, var(--mb-dark-silver) 100%);
color: var(--mb-black);
}
.dark .mb-btn-secondary {
color: var(--mb-white);
}
.mb-input {
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(196, 196, 196, 0.3);
border-radius: 12px;
padding: 0.875rem 1rem;
font-size: 0.875rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(10px);
}
.dark .mb-input {
background: rgba(26, 26, 26, 0.9);
border-color: rgba(255, 255, 255, 0.1);
color: var(--mb-white);
}
.mb-input:focus {
outline: none;
border-color: var(--mb-accent);
box-shadow: 0 0 0 3px rgba(0, 173, 239, 0.1);
transform: translateY(-1px);
}
.mb-select {
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(196, 196, 196, 0.3);
border-radius: 12px;
padding: 0.875rem 1rem;
font-size: 0.875rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(10px);
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
background-position: right 0.5rem center;
background-repeat: no-repeat;
background-size: 1.5em 1.5em;
padding-right: 2.5rem;
}
.dark .mb-select {
background: rgba(26, 26, 26, 0.9);
border-color: rgba(255, 255, 255, 0.1);
color: var(--mb-white);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%9ca3af' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
}
.mb-select:focus {
outline: none;
border-color: var(--mb-accent);
box-shadow: 0 0 0 3px rgba(0, 173, 239, 0.1);
}
.mb-status-indicator {
background: rgba(0, 212, 170, 0.1);
border: 1px solid rgba(0, 212, 170, 0.3);
border-radius: 12px;
padding: 0.75rem 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.mb-status-dot {
width: 8px;
height: 8px;
background: var(--mb-success);
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.mb-header-gradient {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(248, 250, 252, 0.95) 100%);
backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(196, 196, 196, 0.2);
}
.dark .mb-header-gradient {
background: linear-gradient(135deg, rgba(26, 26, 26, 0.95) 0%, rgba(15, 23, 42, 0.95) 100%);
border-bottom-color: rgba(255, 255, 255, 0.1);
}
.mb-page-background {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%);
min-height: 100vh;
}
.dark .mb-page-background {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #334155 100%);
}
.mb-loading-overlay {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(8px);
}
.mb-loading-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 2rem;
box-shadow: var(--mb-shadow-large);
backdrop-filter: blur(20px);
}
.dark .mb-loading-card {
background: rgba(26, 26, 26, 0.95);
}
.mb-spinner {
width: 32px;
height: 32px;
border: 3px solid rgba(0, 173, 239, 0.3);
border-top: 3px solid var(--mb-accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
{% endblock %}
{% block content %}
<div>
<!-- Header -->
<div class="mb-header-gradient sticky top-0 z-40 rounded-t-3xl rounded-b-3xl">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<a href="{{ url_for('admin_page') }}" class="p-3 hover:bg-black/5 dark:hover:bg-white/5 rounded-2xl transition-all duration-300 group">
<svg class="w-6 h-6 text-slate-600 dark:text-slate-400 group-hover:text-slate-900 dark:group-hover:text-white 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-3xl font-bold bg-gradient-to-r from-slate-900 to-slate-700 dark:from-white dark:to-slate-300 bg-clip-text text-transparent">
Erweiterte Einstellungen
</h1>
<p class="text-slate-600 dark:text-slate-400 mt-1 font-medium">System-Optimierung und Wartungsoptionen</p>
</div>
</div>
<!-- Status Indicator -->
<div class="mb-status-indicator rounded-2xl">
<div class="mb-status-dot"></div>
<span class="text-green-700 dark:text-green-400 font-semibold">System Online</span>
</div>
</div>
</div>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- System-Übersicht -->
<div class="mb-card p-8 mb-8">
<div class="flex items-center space-x-3 mb-6">
<div class="p-3 bg-gradient-to-r from-blue-500 to-blue-600 rounded-xl">
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
</div>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">System-Übersicht</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="mb-stat-card">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 font-medium">Registrierte Benutzer</p>
<p class="text-3xl font-bold text-slate-900 dark:text-white mt-1">{{ stats.total_users }}</p>
</div>
<div class="stat-icon">
<svg class="w-6 h-6 text-white" 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="mb-stat-card">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 font-medium">Aktive Drucker</p>
<p class="text-3xl font-bold text-slate-900 dark:text-white mt-1">{{ stats.active_printers }}/{{ stats.total_printers }}</p>
</div>
<div class="stat-icon">
<svg class="w-6 h-6 text-white" 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="mb-stat-card">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-600 dark:text-slate-400 font-medium">Warteschlange</p>
<p class="text-3xl font-bold text-slate-900 dark:text-white mt-1">{{ stats.pending_jobs }}</p>
</div>
<div class="stat-icon">
<svg class="w-6 h-6 text-white" 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 lg:grid-cols-2 gap-8">
<!-- Optimierungs-Einstellungen -->
<div class="mb-card p-8">
<div class="flex items-center space-x-3 mb-6">
<div class="p-3 bg-gradient-to-r from-purple-500 to-purple-600 rounded-xl">
<svg class="w-6 h-6 text-white" 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>
</div>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">Optimierungs-Einstellungen</h2>
</div>
<form id="optimization-form" class="space-y-6">
<!-- Algorithmus-Auswahl -->
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-3">Optimierungs-Algorithmus</label>
<select name="algorithm" id="algorithm" class="mb-select 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-slate-50/50 dark:bg-slate-800/50 rounded-xl">
<div>
<label class="text-sm font-semibold text-slate-700 dark:text-slate-300">Entfernung berücksichtigen</label>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">Drucker-Standort bei Optimierung einbeziehen</p>
</div>
<label class="mb-toggle">
<input type="checkbox" name="consider_distance" {{ 'checked' if optimization_settings.consider_distance else '' }}>
<span class="mb-toggle-slider"></span>
</label>
</div>
<div class="flex items-center justify-between p-4 bg-slate-50/50 dark:bg-slate-800/50 rounded-xl">
<div>
<label class="text-sm font-semibold text-slate-700 dark:text-slate-300">Rüstzeiten minimieren</label>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">Materialwechsel-Zeiten reduzieren</p>
</div>
<label class="mb-toggle">
<input type="checkbox" name="minimize_changeover" {{ 'checked' if optimization_settings.minimize_changeover else '' }}>
<span class="mb-toggle-slider"></span>
</label>
</div>
<div class="flex items-center justify-between p-4 bg-slate-50/50 dark:bg-slate-800/50 rounded-xl">
<div>
<label class="text-sm font-semibold text-slate-700 dark:text-slate-300">Auto-Optimierung</label>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">Automatische Optimierung alle 30 Minuten</p>
</div>
<label class="mb-toggle">
<input type="checkbox" name="auto_optimization_enabled" {{ 'checked' if optimization_settings.auto_optimization_enabled else '' }}>
<span class="mb-toggle-slider"></span>
</label>
</div>
</div>
<!-- Numerische Einstellungen -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm 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="mb-input w-full">
</div>
<div>
<label class="block text-sm 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="mb-input w-full">
</div>
</div>
<!-- Speichern Button -->
<button type="submit" class="mb-btn w-full">
<span class="flex items-center justify-center space-x-2">
<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="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"/>
</svg>
<span>Einstellungen speichern</span>
</span>
</button>
</form>
</div>
<!-- Wartungs-Aktionen -->
<div class="mb-card p-8">
<div class="flex items-center space-x-3 mb-6">
<div class="p-3 bg-gradient-to-r from-orange-500 to-orange-600 rounded-xl">
<svg class="w-6 h-6 text-white" 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>
</div>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">Wartungs-Aktionen</h2>
</div>
<!-- Wartungs-Informationen -->
<div class="bg-gradient-to-r from-slate-50 to-slate-100 dark:from-slate-800 dark:to-slate-700 rounded-xl p-6 mb-6 border border-slate-200 dark:border-slate-600">
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">Wartungs-Status</h3>
<div class="space-y-3 text-sm">
<div class="flex justify-between items-center">
<span class="text-slate-600 dark:text-slate-400 font-medium">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 font-medium">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 font-medium">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-3">
<button id="advanced-clear-cache" class="mb-btn mb-btn-secondary w-full">
<span class="flex items-center justify-center space-x-2">
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
<span>System-Cache leeren</span>
</span>
</button>
<button id="advanced-optimize-db" class="mb-btn mb-btn-success w-full">
<span class="flex items-center justify-center space-x-2">
<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="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"/>
</svg>
<span>Datenbank optimieren</span>
</span>
</button>
<button id="advanced-create-backup" class="mb-btn w-full">
<span class="flex items-center justify-center space-x-2">
<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="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"/>
</svg>
<span>Vollständiges Backup erstellen</span>
</span>
</button>
<button id="advanced-cleanup-logs" class="mb-btn mb-btn-warning w-full">
<span class="flex items-center justify-center space-x-2">
<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="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>
<span>Log-Dateien bereinigen</span>
</span>
</button>
<button id="advanced-system-check" class="mb-btn w-full" style="background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);">
<span class="flex items-center justify-center space-x-2">
<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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>System-Integritätsprüfung</span>
</span>
</button>
</div>
</div>
</div>
<!-- Erweiterte Optionen -->
<div class="mb-card p-8 mt-8">
<div class="flex items-center space-x-3 mb-6">
<div class="p-3 bg-gradient-to-r from-indigo-500 to-indigo-600 rounded-xl">
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
</div>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">Erweiterte Optionen</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Debug-Modus -->
<div class="bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-800 dark:to-slate-700 rounded-xl p-6 border border-slate-200 dark:border-slate-600 transition-all duration-300 hover:shadow-lg">
<div class="flex items-center space-x-3 mb-4">
<div class="p-2 bg-red-500 rounded-lg">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg>
</div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white">Debug-Modus</h3>
</div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">Erweiterte Protokollierung für Fehlerdiagnose aktivieren</p>
<div class="flex items-center justify-between">
<span class="text-sm font-medium text-slate-700 dark:text-slate-300">Status</span>
<label class="mb-toggle">
<input type="checkbox" id="debug-mode">
<span class="mb-toggle-slider"></span>
</label>
</div>
</div>
<!-- Wartungsmodus -->
<div class="bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-800 dark:to-slate-700 rounded-xl p-6 border border-slate-200 dark:border-slate-600 transition-all duration-300 hover:shadow-lg">
<div class="flex items-center space-x-3 mb-4">
<div class="p-2 bg-yellow-500 rounded-lg">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg>
</div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white">Wartungsmodus</h3>
</div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">System für Wartungsarbeiten temporär sperren</p>
<div class="flex items-center justify-between">
<span class="text-sm font-medium text-slate-700 dark:text-slate-300">Status</span>
<label class="mb-toggle">
<input type="checkbox" id="maintenance-mode">
<span class="mb-toggle-slider"></span>
</label>
</div>
</div>
<!-- Performance-Monitoring -->
<div class="bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-800 dark:to-slate-700 rounded-xl p-6 border border-slate-200 dark:border-slate-600 transition-all duration-300 hover:shadow-lg">
<div class="flex items-center space-x-3 mb-4">
<div class="p-2 bg-green-500 rounded-lg">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
</div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white">Performance-Monitoring</h3>
</div>
<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">Detaillierte Leistungsüberwachung und Metriken</p>
<div class="flex items-center justify-between">
<span class="text-sm font-medium text-slate-700 dark:text-slate-300">Status</span>
<label class="mb-toggle">
<input type="checkbox" id="performance-monitoring">
<span class="mb-toggle-slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 mb-loading-overlay z-50 hidden">
<div class="flex items-center justify-center h-full">
<div class="mb-loading-card">
<div class="flex items-center space-x-4">
<div class="mb-spinner"></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();
}
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));
}
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 temporäre Notification mit Mercedes-Benz Design
const notification = document.createElement('div');
notification.className = `fixed top-6 right-6 z-50 p-4 rounded-xl shadow-2xl max-w-sm transition-all duration-500 transform translate-x-full opacity-0 backdrop-blur-xl border ${
type === 'success' ? 'bg-gradient-to-r from-green-500 to-green-600 text-white border-green-400' :
type === 'error' ? 'bg-gradient-to-r from-red-500 to-red-600 text-white border-red-400' :
type === 'warning' ? 'bg-gradient-to-r from-yellow-500 to-yellow-600 text-white border-yellow-400' :
'bg-gradient-to-r from-blue-500 to-blue-600 text-white border-blue-400'
}`;
notification.innerHTML = `
<div class="flex items-center space-x-3">
<div class="flex-shrink-0 p-1 rounded-lg bg-white/20">
${type === 'success' ?
'<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="M5 13l4 4L19 7"/></svg>' :
type === 'error' ?
'<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>' :
type === 'warning' ?
'<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="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/></svg>' :
'<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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>'
}
</div>
<div class="text-sm font-semibold flex-1">${message}</div>
<button onclick="this.parentElement.parentElement.remove()" class="ml-auto p-1 rounded-lg hover:bg-white/20 transition-colors">
<svg class="w-4 h-4" 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 %}