🎉 Große Änderungen vorgenommen! Die folgenden Dateien wurden aktualisiert:
- backend/logs/admin/admin.log - backend/logs/admin_api/admin_api.log - backend/logs/api/api.log - backend/logs/app/app.log - backend/logs/auth/auth.log - backend/logs/calendar/calendar.log - backend/
This commit is contained in:
@ -11,29 +11,42 @@
|
||||
<meta http-equiv="refresh" content="30">
|
||||
|
||||
<style>
|
||||
/* Spezielle Styles für Monitoring */
|
||||
/* Optimierte Tapo-Monitoring Styles mit Unified CSS Variables */
|
||||
.status-indicator {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.status-online { background-color: #10b981; }
|
||||
.status-offline { background-color: #6b7280; }
|
||||
.status-error { background-color: #ef4444; }
|
||||
.status-online {
|
||||
background-color: var(--text-success);
|
||||
box-shadow: 0 0 6px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
.status-offline {
|
||||
background-color: var(--text-muted);
|
||||
box-shadow: 0 0 6px rgba(107, 114, 128, 0.2);
|
||||
}
|
||||
.status-error {
|
||||
background-color: var(--text-error);
|
||||
box-shadow: 0 0 6px rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.monitoring-card {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
background: var(--gradient-card);
|
||||
border: 1px solid var(--border-primary);
|
||||
box-shadow: var(--shadow-card);
|
||||
backdrop-filter: var(--glass-blur);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.monitoring-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: var(--shadow-card-hover);
|
||||
border-color: var(--border-hover);
|
||||
}
|
||||
|
||||
.pulse-animation {
|
||||
@ -45,72 +58,100 @@
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.health-excellent { border-left: 4px solid #10b981; }
|
||||
.health-good { border-left: 4px solid #f59e0b; }
|
||||
.health-poor { border-left: 4px solid #ef4444; }
|
||||
.health-excellent {
|
||||
border-left: 4px solid var(--text-success);
|
||||
background: linear-gradient(90deg, rgba(16, 185, 129, 0.02) 0%, transparent 15%);
|
||||
}
|
||||
.health-good {
|
||||
border-left: 4px solid var(--text-warning);
|
||||
background: linear-gradient(90deg, rgba(245, 158, 11, 0.02) 0%, transparent 15%);
|
||||
}
|
||||
.health-poor {
|
||||
border-left: 4px solid var(--text-error);
|
||||
background: linear-gradient(90deg, rgba(239, 68, 68, 0.02) 0%, transparent 15%);
|
||||
}
|
||||
|
||||
/* Loading Overlay */
|
||||
/* Loading Overlay mit Unified Variables */
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(4px);
|
||||
background: var(--bg-overlay);
|
||||
backdrop-filter: var(--glass-blur);
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Dark Mode Optimierungen */
|
||||
.dark .status-online {
|
||||
box-shadow: 0 0 8px rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
|
||||
.dark .status-error {
|
||||
box-shadow: 0 0 8px rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
|
||||
.dark .health-excellent {
|
||||
background: linear-gradient(90deg, rgba(16, 185, 129, 0.08) 0%, transparent 15%);
|
||||
}
|
||||
|
||||
.dark .health-good {
|
||||
background: linear-gradient(90deg, rgba(245, 158, 11, 0.08) 0%, transparent 15%);
|
||||
}
|
||||
|
||||
.dark .health-poor {
|
||||
background: linear-gradient(90deg, rgba(239, 68, 68, 0.08) 0%, transparent 15%);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Loading Overlay -->
|
||||
<!-- Loading Overlay mit Unified Variables -->
|
||||
<div id="loading-overlay" class="loading-overlay">
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl p-8 shadow-2xl">
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
||||
<span class="text-lg font-medium text-gray-900 dark:text-white">Tapo-Steckdosen werden überprüft...</span>
|
||||
<div class="modal">
|
||||
<div class="flex items-center space-x-4 p-8">
|
||||
<div class="spinner"></div>
|
||||
<span class="text-lg font-medium" style="color: var(--text-primary);">Tapo-Steckdosen werden überprüft...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero Header -->
|
||||
<div class="relative overflow-hidden bg-gradient-to-r from-orange-600 via-red-600 to-purple-600 text-white rounded-3xl mx-4 mb-8">
|
||||
<div class="absolute inset-0 bg-black/20"></div>
|
||||
<!-- Hero Header mit Mercedes-Branding -->
|
||||
<div class="relative overflow-hidden text-white rounded-3xl mx-4 mb-8" style="background: linear-gradient(135deg, var(--mb-primary) 0%, var(--mb-primary-dark) 50%, var(--mb-black) 100%);">
|
||||
<div class="absolute inset-0" style="background: rgba(0, 0, 0, 0.1);"></div>
|
||||
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div class="text-center">
|
||||
<!-- Icon -->
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 bg-white/10 backdrop-blur-sm rounded-full mb-6 border border-white/20">
|
||||
<!-- Mercedes Icon -->
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full mb-6 border" style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(8px); border-color: rgba(255, 255, 255, 0.2);">
|
||||
<svg class="w-8 h-8 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>
|
||||
|
||||
<h1 class="text-4xl md:text-5xl font-bold mb-4 tracking-tight">
|
||||
<span class="bg-gradient-to-r from-white to-orange-200 bg-clip-text text-transparent">
|
||||
Tapo-Steckdosen-Monitoring
|
||||
</span>
|
||||
<h1 class="text-4xl md:text-5xl font-bold mb-4 tracking-tight text-white">
|
||||
Tapo-Steckdosen-Monitoring
|
||||
</h1>
|
||||
<p class="text-xl text-orange-100 max-w-3xl mx-auto leading-relaxed">
|
||||
<p class="text-xl max-w-3xl mx-auto leading-relaxed" style="color: rgba(255, 255, 255, 0.9);">
|
||||
Real-Time-Überwachung und Verwaltung aller TP-Link Tapo Smart Plugs im TBA Mercedes-Benz System
|
||||
</p>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<!-- Quick Stats mit Mercedes-Styling -->
|
||||
<div class="flex flex-wrap justify-center gap-6 mt-8">
|
||||
<div class="bg-white/10 backdrop-blur-sm border border-white/20 rounded-xl px-4 py-2">
|
||||
<div class="text-2xl font-bold">{{ stats.printers_with_tapo }}</div>
|
||||
<div class="text-sm opacity-90">Konfigurierte Steckdosen</div>
|
||||
<div class="rounded-xl px-4 py-2 border" style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(8px); border-color: rgba(255, 255, 255, 0.2);">
|
||||
<div class="text-2xl font-bold text-white">{{ stats.printers_with_tapo }}</div>
|
||||
<div class="text-sm" style="color: rgba(255, 255, 255, 0.8);">Konfigurierte Steckdosen</div>
|
||||
</div>
|
||||
<div class="bg-white/10 backdrop-blur-sm border border-white/20 rounded-xl px-4 py-2">
|
||||
<div class="text-2xl font-bold text-green-300">{{ stats.online_count }}</div>
|
||||
<div class="text-sm opacity-90">Online</div>
|
||||
<div class="rounded-xl px-4 py-2 border" style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(8px); border-color: rgba(255, 255, 255, 0.2);">
|
||||
<div class="text-2xl font-bold" style="color: var(--text-success);">{{ stats.online_count }}</div>
|
||||
<div class="text-sm" style="color: rgba(255, 255, 255, 0.8);">Online</div>
|
||||
</div>
|
||||
<div class="bg-white/10 backdrop-blur-sm border border-white/20 rounded-xl px-4 py-2">
|
||||
<div class="text-2xl font-bold">{{ stats.coverage_percentage }}%</div>
|
||||
<div class="text-sm opacity-90">Abdeckung</div>
|
||||
<div class="rounded-xl px-4 py-2 border" style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(8px); border-color: rgba(255, 255, 255, 0.2);">
|
||||
<div class="text-2xl font-bold text-white">{{ stats.coverage_percentage }}%</div>
|
||||
<div class="text-sm" style="color: rgba(255, 255, 255, 0.8);">Abdeckung</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -119,89 +160,86 @@
|
||||
|
||||
<!-- Status Overview Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||
<!-- Gesamt-Status -->
|
||||
<div class="monitoring-card rounded-xl p-6 shadow-lg">
|
||||
<!-- Gesamt-Status mit Unified Variables -->
|
||||
<div class="monitoring-card p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="p-3 bg-blue-100 dark:bg-blue-900 rounded-xl">
|
||||
<svg class="w-6 h-6 text-blue-600 dark:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="p-3 rounded-xl" style="background: rgba(0, 115, 206, 0.1); border: 1px solid rgba(0, 115, 206, 0.2);">
|
||||
<svg class="w-6 h-6" style="color: var(--mb-primary);" 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>
|
||||
<div class="text-right">
|
||||
<div class="text-2xl font-bold text-slate-900 dark:text-white">{{ stats.printers_with_tapo }}</div>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400">Smart Plugs</div>
|
||||
<div class="text-2xl font-bold" style="color: var(--text-primary);">{{ stats.printers_with_tapo }}</div>
|
||||
<div class="text-sm" style="color: var(--text-secondary);">Smart Plugs</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="status-indicator {{ 'status-online' if stats.tapo_available else 'status-error' }}"></div>
|
||||
<span class="text-sm font-medium {{ 'text-green-600' if stats.tapo_available else 'text-red-600' }}">
|
||||
<span class="text-sm font-medium" style="color: {{ 'var(--text-success)' if stats.tapo_available else 'var(--text-error)' }};">
|
||||
{{ 'System verfügbar' if stats.tapo_available else 'System offline' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Online Steckdosen -->
|
||||
<div class="monitoring-card rounded-xl p-6 shadow-lg">
|
||||
<!-- Online Steckdosen mit Unified Variables -->
|
||||
<div class="monitoring-card p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="p-3 bg-green-100 dark:bg-green-900 rounded-xl">
|
||||
<svg class="w-6 h-6 text-green-600 dark:text-green-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="p-3 rounded-xl" style="background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.2);">
|
||||
<svg class="w-6 h-6" style="color: var(--text-success);" 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>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-2xl font-bold text-green-600">{{ stats.online_count }}</div>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400">Eingeschaltet</div>
|
||||
<div class="text-2xl font-bold" style="color: var(--text-success);">{{ stats.online_count }}</div>
|
||||
<div class="text-sm" style="color: var(--text-secondary);">Eingeschaltet</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-2">
|
||||
<div class="bg-green-500 h-2 rounded-full transition-all duration-500"
|
||||
style="width: {{ (stats.online_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%"></div>
|
||||
<div class="w-full rounded-full h-2" style="background: var(--bg-tertiary);">
|
||||
<div class="h-2 rounded-full transition-all duration-500" style="background: var(--text-success); width: {{ (stats.online_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Offline Steckdosen -->
|
||||
<div class="monitoring-card rounded-xl p-6 shadow-lg">
|
||||
<!-- Offline Steckdosen mit Unified Variables -->
|
||||
<div class="monitoring-card p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="p-3 bg-gray-100 dark:bg-gray-700 rounded-xl">
|
||||
<svg class="w-6 h-6 text-gray-600 dark:text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="p-3 rounded-xl" style="background: rgba(107, 114, 128, 0.1); border: 1px solid rgba(107, 114, 128, 0.2);">
|
||||
<svg class="w-6 h-6" style="color: var(--text-muted);" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L5.636 5.636"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-2xl font-bold text-gray-600">{{ stats.offline_count }}</div>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400">Ausgeschaltet</div>
|
||||
<div class="text-2xl font-bold" style="color: var(--text-muted);">{{ stats.offline_count }}</div>
|
||||
<div class="text-sm" style="color: var(--text-secondary);">Ausgeschaltet</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-2">
|
||||
<div class="bg-gray-500 h-2 rounded-full transition-all duration-500"
|
||||
style="width: {{ (stats.offline_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%"></div>
|
||||
<div class="w-full rounded-full h-2" style="background: var(--bg-tertiary);">
|
||||
<div class="h-2 rounded-full transition-all duration-500" style="background: var(--text-muted); width: {{ (stats.offline_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fehlerhafte Steckdosen -->
|
||||
<div class="monitoring-card rounded-xl p-6 shadow-lg">
|
||||
<!-- Fehlerhafte Steckdosen mit Unified Variables -->
|
||||
<div class="monitoring-card p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="p-3 bg-red-100 dark:bg-red-900 rounded-xl">
|
||||
<svg class="w-6 h-6 text-red-600 dark:text-red-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="p-3 rounded-xl" style="background: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.2);">
|
||||
<svg class="w-6 h-6" style="color: var(--text-error);" 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.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-2xl font-bold text-red-600">{{ stats.error_count }}</div>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400">Nicht erreichbar</div>
|
||||
<div class="text-2xl font-bold" style="color: var(--text-error);">{{ stats.error_count }}</div>
|
||||
<div class="text-sm" style="color: var(--text-secondary);">Nicht erreichbar</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-2">
|
||||
<div class="bg-red-500 h-2 rounded-full transition-all duration-500"
|
||||
style="width: {{ (stats.error_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%"></div>
|
||||
<div class="w-full rounded-full h-2" style="background: var(--bg-tertiary);">
|
||||
<div class="h-2 rounded-full transition-all duration-500" style="background: var(--text-error); width: {{ (stats.error_count / stats.printers_with_tapo * 100) if stats.printers_with_tapo else 0 }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Control Panel -->
|
||||
<div class="monitoring-card rounded-xl p-6 shadow-lg mb-8">
|
||||
<!-- Control Panel mit Unified Variables -->
|
||||
<div class="monitoring-card p-6 mb-8">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4 mb-6">
|
||||
<h2 class="text-xl font-semibold text-slate-900 dark:text-white">
|
||||
<h2 class="text-xl font-semibold" style="color: var(--text-primary);">
|
||||
<svg class="w-6 h-6 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100-4m0 4v2m0-6V4"/>
|
||||
</svg>
|
||||
@ -223,14 +261,14 @@
|
||||
<span>Gesundheitscheck</span>
|
||||
</button>
|
||||
|
||||
<button id="bulk-on-btn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors">
|
||||
<button id="bulk-on-btn" class="btn-success flex items-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="M13 10V3L4 14h7v7l9-11h-7z"/>
|
||||
</svg>
|
||||
<span>Alle einschalten</span>
|
||||
</button>
|
||||
|
||||
<button id="bulk-off-btn" class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors">
|
||||
<button id="bulk-off-btn" class="btn-danger flex items-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="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L5.636 5.636"/>
|
||||
</svg>
|
||||
@ -239,26 +277,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bulk Selection -->
|
||||
<!-- Bulk Selection mit Unified Variables -->
|
||||
<div class="flex items-center space-x-4 mb-4">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" id="select-all" class="mr-2">
|
||||
<span class="text-sm font-medium">Alle auswählen</span>
|
||||
<span class="text-sm font-medium" style="color: var(--text-primary);">Alle auswählen</span>
|
||||
</label>
|
||||
<span id="selected-count" class="text-sm text-slate-600 dark:text-slate-400">0 Steckdosen ausgewählt</span>
|
||||
<span id="selected-count" class="text-sm" style="color: var(--text-secondary);">0 Steckdosen ausgewählt</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Drucker-Steckdosen-Status -->
|
||||
<div class="monitoring-card rounded-xl shadow-lg overflow-hidden">
|
||||
<div class="p-6 border-b border-slate-200 dark:border-slate-700">
|
||||
<h2 class="text-xl font-semibold text-slate-900 dark:text-white">
|
||||
<!-- Drucker-Steckdosen-Status mit Unified Variables -->
|
||||
<div class="monitoring-card overflow-hidden">
|
||||
<div class="p-6" style="border-bottom: 1px solid var(--border-primary);">
|
||||
<h2 class="text-xl font-semibold" style="color: var(--text-primary);">
|
||||
<svg class="w-6 h-6 inline mr-2" 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>
|
||||
Drucker-Steckdosen-Status
|
||||
</h2>
|
||||
<p class="text-sm text-slate-600 dark:text-slate-400 mt-1">
|
||||
<p class="text-sm mt-1" style="color: var(--text-secondary);">
|
||||
Live-Status aller konfigurierten Tapo-Steckdosen (automatische Aktualisierung alle 30 Sekunden)
|
||||
</p>
|
||||
</div>
|
||||
@ -267,16 +305,15 @@
|
||||
{% if printer_status %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{% for printer in printer_status %}
|
||||
<div class="printer-card border border-slate-200 dark:border-slate-600 rounded-xl p-4 hover:shadow-lg transition-all duration-300
|
||||
{{ 'health-excellent' if printer.plug_reachable and printer.plug_status == 'on' else 'health-good' if printer.plug_reachable else 'health-poor' }}">
|
||||
<div class="printer-card rounded-xl p-4 hover-lift transition-all duration-300 {{ 'health-excellent' if printer.plug_reachable and printer.plug_status == 'on' else 'health-good' if printer.plug_reachable else 'health-poor' }}" style="border: 1px solid var(--border-primary);">
|
||||
|
||||
<!-- Header mit Checkbox -->
|
||||
<div class="flex items-start justify-between mb-3">
|
||||
<div class="flex items-center space-x-3">
|
||||
<input type="checkbox" class="printer-checkbox" value="{{ printer.id }}" data-printer-name="{{ printer.name }}">
|
||||
<div>
|
||||
<h3 class="font-semibold text-slate-900 dark:text-white">{{ printer.name }}</h3>
|
||||
<p class="text-sm text-slate-600 dark:text-slate-400">{{ printer.model }}</p>
|
||||
<h3 class="font-semibold" style="color: var(--text-primary);">{{ printer.name }}</h3>
|
||||
<p class="text-sm" style="color: var(--text-secondary);">{{ printer.model }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -285,8 +322,7 @@
|
||||
<div class="flex items-center space-x-2 mb-1">
|
||||
<div class="status-indicator {{ 'status-online' if printer.plug_status == 'on' else 'status-offline' if printer.plug_status == 'off' else 'status-error' }}
|
||||
{{ 'pulse-animation' if printer.plug_status == 'on' else '' }}"></div>
|
||||
<span class="text-sm font-medium
|
||||
{{ 'text-green-600' if printer.plug_status == 'on' else 'text-gray-600' if printer.plug_status == 'off' else 'text-red-600' }}">
|
||||
<span class="text-sm font-medium" style="color: {% if printer.plug_status == 'on' %}var(--text-success){% elif printer.plug_status == 'off' %}var(--text-muted){% else %}var(--text-error){% endif %};">
|
||||
{% if printer.plug_status == 'on' %}
|
||||
Eingeschaltet
|
||||
{% elif printer.plug_status == 'off' %}
|
||||
@ -296,36 +332,36 @@
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<span class="text-xs text-slate-500">{{ printer.plug_ip }}</span>
|
||||
<span class="text-xs" style="color: var(--text-muted);">{{ printer.plug_ip }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Details -->
|
||||
<!-- Details mit Unified Variables -->
|
||||
<div class="space-y-2 mb-4">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-600 dark:text-slate-400">Standort:</span>
|
||||
<span class="text-slate-900 dark:text-white font-medium">{{ printer.location or 'Nicht angegeben' }}</span>
|
||||
<span style="color: var(--text-secondary);">Standort:</span>
|
||||
<span class="font-medium" style="color: var(--text-primary);">{{ printer.location or 'Nicht angegeben' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-600 dark:text-slate-400">Aktive Jobs:</span>
|
||||
<span class="text-slate-900 dark:text-white font-medium">{{ printer.active_jobs }}</span>
|
||||
<span style="color: var(--text-secondary);">Aktive Jobs:</span>
|
||||
<span class="font-medium" style="color: var(--text-primary);">{{ printer.active_jobs }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-600 dark:text-slate-400">Letzte Prüfung:</span>
|
||||
<span class="text-slate-900 dark:text-white font-medium">{{ printer.last_checked.strftime('%H:%M:%S') }}</span>
|
||||
<span style="color: var(--text-secondary);">Letzte Prüfung:</span>
|
||||
<span class="font-medium" style="color: var(--text-primary);">{{ printer.last_checked.strftime('%H:%M:%S') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Warnungen -->
|
||||
<!-- Warnungen mit Unified Variables -->
|
||||
{% if printer.has_issues %}
|
||||
<div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-3 mb-4">
|
||||
<div class="rounded-lg p-3 mb-4" style="background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.3);">
|
||||
<div class="flex items-start space-x-2">
|
||||
<svg class="w-5 h-5 text-yellow-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" style="color: var(--text-warning);" 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.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z"/>
|
||||
</svg>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-yellow-800 dark:text-yellow-200">Achtung:</p>
|
||||
<ul class="text-sm text-yellow-700 dark:text-yellow-300 mt-1 list-disc list-inside">
|
||||
<p class="text-sm font-medium" style="color: var(--text-warning);">Achtung:</p>
|
||||
<ul class="text-sm mt-1 list-disc list-inside" style="color: var(--text-warning);">
|
||||
{% if not printer.plug_reachable %}
|
||||
<li>Steckdose nicht erreichbar</li>
|
||||
{% endif %}
|
||||
@ -344,9 +380,7 @@
|
||||
<!-- Aktionen -->
|
||||
<div class="flex space-x-2">
|
||||
{% if printer.plug_reachable %}
|
||||
<button class="toggle-single-btn flex-1 px-3 py-2
|
||||
{{ 'bg-red-500 hover:bg-red-600' if printer.plug_status == 'on' else 'bg-green-500 hover:bg-green-600' }}
|
||||
text-white rounded-lg text-sm font-medium transition-colors"
|
||||
<button class="toggle-single-btn flex-1 px-3 py-2 {{ 'btn-danger' if printer.plug_status == 'on' else 'btn-success' }} text-sm font-medium"
|
||||
data-printer-id="{{ printer.id }}"
|
||||
data-action="{{ 'off' if printer.plug_status == 'on' else 'on' }}">
|
||||
{% if printer.plug_status == 'on' %}
|
||||
@ -362,12 +396,12 @@
|
||||
{% endif %}
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="flex-1 px-3 py-2 bg-gray-400 text-white rounded-lg text-sm font-medium cursor-not-allowed" disabled>
|
||||
<button class="flex-1 px-3 py-2 rounded-lg text-sm font-medium cursor-not-allowed" disabled style="background: var(--text-muted); color: white;">
|
||||
Nicht verfügbar
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<button class="configure-btn px-3 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg text-sm transition-colors"
|
||||
<button class="configure-btn px-3 py-2 rounded-lg text-sm" style="background: var(--mb-primary); color: white;"
|
||||
data-printer-id="{{ printer.id }}" title="Konfiguration">
|
||||
<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="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"/>
|
||||
@ -380,11 +414,11 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-12">
|
||||
<svg class="w-16 h-16 text-slate-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<svg class="w-16 h-16 mx-auto mb-4" style="color: var(--text-muted);" 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>
|
||||
<h3 class="text-lg font-medium text-slate-900 dark:text-white mb-2">Keine Tapo-Steckdosen konfiguriert</h3>
|
||||
<p class="text-slate-600 dark:text-slate-400 mb-4">
|
||||
<h3 class="text-lg font-medium mb-2" style="color: var(--text-primary);">Keine Tapo-Steckdosen konfiguriert</h3>
|
||||
<p class="mb-4" style="color: var(--text-secondary);">
|
||||
Es wurden noch keine Drucker mit Tapo-Steckdosen eingerichtet.
|
||||
</p>
|
||||
<a href="{{ url_for('admin.printers_overview') }}" class="btn-primary inline-flex items-center">
|
||||
@ -414,8 +448,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
|
||||
function showNotification(message, type = 'info') {
|
||||
// Notification System (könnte erweitert werden)
|
||||
alert(message); // Temporäre Lösung
|
||||
// Einfaches Notification System mit Toast-Stil
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg z-50 transition-all duration-300`;
|
||||
notification.style.background = type === 'success' ? 'var(--text-success)' :
|
||||
type === 'error' ? 'var(--text-error)' :
|
||||
type === 'warning' ? 'var(--text-warning)' : 'var(--mb-primary)';
|
||||
notification.style.color = 'white';
|
||||
notification.style.maxWidth = '400px';
|
||||
notification.textContent = message;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Auto-remove nach 5 Sekunden
|
||||
setTimeout(() => {
|
||||
notification.style.opacity = '0';
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 5000);
|
||||
|
||||
// Click to dismiss
|
||||
notification.addEventListener('click', () => {
|
||||
notification.style.opacity = '0';
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
});
|
||||
}
|
||||
|
||||
// Checkbox Management
|
||||
|
@ -181,18 +181,16 @@
|
||||
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||
<div class="text-center">
|
||||
<!-- Mercedes-Benz Logo -->
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 bg-white/10 backdrop-blur-sm rounded-full mb-6 border border-white/20">
|
||||
<svg class="w-10 h-10 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.94-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 live-badge rounded-full mb-6 logo-adaptive">
|
||||
<svg class="w-10 h-10" style="color: var(--text-primary);" viewBox="0 0 80 80" fill="currentColor">
|
||||
<path d="M58.6,4.5C53,1.6,46.7,0,40,0c-6.7,0-13,1.6-18.6,4.5v0C8.7,11.2,0,24.6,0,40c0,15.4,8.7,28.8,21.5,35.5C27,78.3,33.3,80,40,80c6.7,0,12.9-1.7,18.5-4.6C71.3,68.8,80,55.4,80,40C80,24.6,71.3,11.2,58.6,4.5z M4,40c0-13.1,7-24.5,17.5-30.9v0C26.6,6,32.5,4.2,39,4l-4.5,32.7L21.5,46.8v0L8.3,57.1C5.6,52,4,46.2,4,40z M58.6,70.8C53.1,74.1,46.8,76,40,76c-6.8,0-13.2-1.9-18.6-5.2c-4.9-2.9-8.9-6.9-11.9-11.7l11.9-4.9v0L40,46.6l18.6,7.5v0l12,4.9C67.6,63.9,63.4,67.9,58.6,70.8z M58.6,46.8L58.6,46.8l-12.9-10L41.1,4c6.3,0.2,12.3,2,17.4,5.1v0C69,15.4,76,26.9,76,40c0,6.2-1.5,12-4.3,17.1L58.6,46.8z"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1 class="text-5xl md:text-6xl font-bold mb-4 tracking-tight">
|
||||
<span class="bg-gradient-to-r from-white to-blue-200 bg-clip-text text-transparent">
|
||||
Energiemonitoring
|
||||
</span>
|
||||
<h1 class="text-5xl md:text-6xl font-bold mb-4 tracking-tight" style="color: var(--text-primary);">
|
||||
Energiemonitoring
|
||||
</h1>
|
||||
<p class="text-xl md:text-2xl text-blue-100 max-w-3xl mx-auto leading-relaxed">
|
||||
<p class="text-xl md:text-2xl max-w-3xl mx-auto leading-relaxed" style="color: var(--text-secondary);">
|
||||
Überwachung des Energieverbrauchs aller 3D-Drucker mit TP-Link Tapo Smart Plugs
|
||||
</p>
|
||||
</div>
|
||||
@ -204,14 +202,14 @@
|
||||
|
||||
{% if stats.error %}
|
||||
<!-- Error State -->
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl p-6 mb-8">
|
||||
<div class="error-card rounded-xl p-6 mb-8">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-6 h-6 text-red-500 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<svg class="w-6 h-6 mr-3" style="color: var(--text-error);" 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.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z"/>
|
||||
</svg>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-red-800 dark:text-red-200">Energiemonitoring nicht verfügbar</h3>
|
||||
<p class="text-red-600 dark:text-red-300 mt-1">{{ stats.error }}</p>
|
||||
<h3 class="text-lg font-semibold" style="color: var(--text-error);">Energiemonitoring nicht verfügbar</h3>
|
||||
<p class="mt-1" style="color: var(--text-error);">{{ stats.error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -258,7 +256,7 @@
|
||||
|
||||
<!-- Power Consumption Over Time -->
|
||||
<div class="energy-card p-6">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-4">Verbrauch der letzten 24 Stunden</h3>
|
||||
<h3 class="text-xl font-bold mb-4" style="color: var(--text-primary);">Verbrauch der letzten 24 Stunden</h3>
|
||||
<div class="relative h-80">
|
||||
<canvas id="powerChart"></canvas>
|
||||
</div>
|
||||
@ -266,7 +264,7 @@
|
||||
|
||||
<!-- Device Comparison -->
|
||||
<div class="energy-card p-6">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-4">Verbrauch nach Gerät</h3>
|
||||
<h3 class="text-xl font-bold mb-4" style="color: var(--text-primary);">Verbrauch nach Gerät</h3>
|
||||
<div class="relative h-80">
|
||||
<canvas id="deviceChart"></canvas>
|
||||
</div>
|
||||
@ -275,20 +273,20 @@
|
||||
|
||||
<!-- Device List -->
|
||||
<div class="energy-card p-6">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-6">Geräteübersicht</h3>
|
||||
<h3 class="text-xl font-bold mb-6" style="color: var(--text-primary);">Geräteübersicht</h3>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800">
|
||||
<table class="energy-table min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Gerät</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Aktuelle Leistung</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Tagesverbrauch</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Aktionen</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Gerät</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Status</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Aktuelle Leistung</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Tagesverbrauch</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="device-table-body" class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<tbody id="device-table-body">
|
||||
<!-- Dynamisch geladen via JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
@ -446,7 +444,7 @@ function updateDeviceTable(devices) {
|
||||
if (devices.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="5" class="px-6 py-4 text-center text-gray-500 dark:text-gray-400">
|
||||
<td colspan="5" class="px-6 py-4 text-center" style="color: var(--text-muted);">
|
||||
Keine Geräte gefunden
|
||||
</td>
|
||||
</tr>
|
||||
@ -456,16 +454,19 @@ function updateDeviceTable(devices) {
|
||||
|
||||
devices.forEach(device => {
|
||||
const row = document.createElement('tr');
|
||||
row.className = 'hover:bg-gray-50 dark:hover:bg-gray-800';
|
||||
row.className = '';
|
||||
row.style.transition = 'background-color 0.2s ease';
|
||||
row.addEventListener('mouseenter', () => row.style.backgroundColor = 'var(--hover-card)');
|
||||
row.addEventListener('mouseleave', () => row.style.backgroundColor = 'transparent');
|
||||
|
||||
const statusClass = device.status === 'online' ? 'text-green-600' : 'text-red-600';
|
||||
const statusClass = device.status === 'online' ? 'status-badge-online' : 'status-badge-offline';
|
||||
const statusText = device.status === 'online' ? 'Online' : 'Offline';
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
<div class="text-sm font-medium text-gray-900 dark:text-white">${device.name}</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">${device.model || ''}</div>
|
||||
<div class="text-sm font-medium" style="color: var(--text-primary);">${device.name}</div>
|
||||
<div class="text-sm" style="color: var(--text-tertiary);">${device.model || ''}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@ -473,14 +474,14 @@ function updateDeviceTable(devices) {
|
||||
${statusText}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm" style="color: var(--text-primary);">
|
||||
${device.current_power || '0.0'} W
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm" style="color: var(--text-primary);">
|
||||
${device.daily_consumption || '0.0'} kWh
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
||||
<a href="/energy/device/${device.id}" class="text-mercedes-blue hover:text-mercedes-blue/80">
|
||||
<a href="/energy/device/${device.id}" style="color: var(--text-accent); transition: color 0.2s ease;" onmouseover="this.style.color='var(--text-link-hover)'" onmouseout="this.style.color='var(--text-accent)'">
|
||||
Details anzeigen
|
||||
</a>
|
||||
</td>
|
||||
|
Reference in New Issue
Block a user