Visuelle Verbesserungen

Dieser Commit ist enthalten in:
2025-06-08 21:11:44 +02:00
Ursprung 9e0f9ac2d0
Commit ecd621c435
4 geänderte Dateien mit 156 neuen und 51 gelöschten Zeilen

Datei anzeigen

@@ -5,24 +5,68 @@
{% block extra_css %}
<style>
.stat-card {
transition: transform 0.2s;
transition: all 0.3s ease;
cursor: pointer;
border: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
}
.stat-card .card-icon {
font-size: 3rem;
margin-bottom: 0.5rem;
opacity: 0.8;
}
.stat-card .card-value {
font-size: 2.5rem;
font-weight: bold;
margin: 0.5rem 0;
}
.stat-card .card-label {
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
opacity: 0.7;
}
a:hover .stat-card {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
}
.text-decoration-none:hover {
text-decoration: none !important;
}
.status-aktiv { color: #28a745; }
.status-ablaufend { color: #ffc107; }
.status-abgelaufen { color: #dc3545; }
.status-deaktiviert { color: #6c757d; }
/* Session pulse effect */
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.05); opacity: 0.8; }
100% { transform: scale(1); opacity: 1; }
}
.pulse-effect {
animation: pulse 2s infinite;
}
/* Chart styles */
.chart-container {
position: relative;
height: 100px;
margin: 1rem 0;
}
/* Progress bar styles */
.progress-custom {
height: 8px;
background-color: #e9ecef;
border-radius: 4px;
overflow: hidden;
}
.progress-bar-custom {
background-color: #28a745;
transition: width 0.3s ease;
}
</style>
{% endblock %}
@@ -43,9 +87,9 @@
<a href="/customers" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<h5 class="card-title">👥 Kunden</h5>
<h2 class="text-primary">{{ stats.total_customers }}</h2>
<p class="text-muted mb-0">Gesamt</p>
<div class="card-icon text-primary">👥</div>
<div class="card-value text-primary">{{ stats.total_customers }}</div>
<div class="card-label text-muted">Kunden Gesamt</div>
</div>
</div>
</a>
@@ -54,9 +98,12 @@
<a href="/licenses" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<h5 class="card-title">📋 Lizenzen</h5>
<h2 class="text-info">{{ stats.total_licenses }}</h2>
<p class="text-muted mb-0">Gesamt</p>
<div class="card-icon text-info">📋</div>
<div class="card-value text-info">{{ stats.total_licenses }}</div>
<div class="card-label text-muted">Lizenzen Gesamt</div>
<div class="chart-container">
<canvas id="licenseChart"></canvas>
</div>
</div>
</div>
</a>
@@ -65,9 +112,9 @@
<a href="/sessions" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body text-center">
<h5 class="card-title">🟢 Sessions</h5>
<h2 class="text-success">{{ stats.active_sessions }}</h2>
<p class="text-muted mb-0">Aktive Nutzer</p>
<div class="card-icon text-success{% if stats.active_sessions > 0 %} pulse-effect{% endif %}">🟢</div>
<div class="card-value text-success">{{ stats.active_sessions }}</div>
<div class="card-label text-muted">Aktive Sessions</div>
</div>
</div>
</a>
@@ -119,36 +166,34 @@
<!-- Backup-Status und Sicherheit nebeneinander -->
<div class="row g-3 mb-4">
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">💾 Backup-Status</h5>
{% if stats.last_backup %}
{% if stats.last_backup[4] == 'success' %}
<p class="mb-1">
<strong>Letztes Backup:</strong>
<span class="text-success"> Erfolgreich</span>
am {{ stats.last_backup[0].strftime('%d.%m.%Y %H:%M:%S') }}
</p>
<p class="mb-0">
<small class="text-muted">
Größe: {{ (stats.last_backup[1] / 1024 / 1024)|round(2) }} MB |
Dauer: {{ stats.last_backup[2]|round(1) }} Sekunden |
Typ: {{ 'Manuell' if stats.last_backup[3] == 'manual' else 'Automatisch' }}
<a href="/backups" class="text-decoration-none">
<div class="card stat-card h-100">
<div class="card-body">
<h5 class="card-title">💾 Backup-Status</h5>
{% if stats.last_backup %}
{% if stats.last_backup[4] == 'success' %}
<div class="d-flex align-items-center mb-2">
<span class="text-success me-2"></span>
<small>{{ stats.last_backup[0].strftime('%d.%m.%Y %H:%M') }}</small>
</div>
<div class="progress-custom">
<div class="progress-bar-custom" style="width: 100%;"></div>
</div>
<small class="text-muted mt-1 d-block">
{{ (stats.last_backup[1] / 1024 / 1024)|round(1) }} MB • {{ stats.last_backup[2]|round(0)|int }}s
</small>
</p>
{% else %}
<div class="d-flex align-items-center">
<span class="text-danger me-2"></span>
<small>Backup fehlgeschlagen</small>
</div>
{% endif %}
{% else %}
<p class="mb-0">
<strong>Letztes Backup:</strong>
<span class="text-danger">❌ Fehlgeschlagen</span>
am {{ stats.last_backup[0].strftime('%d.%m.%Y %H:%M:%S') }}
</p>
<p class="text-muted mb-0">Noch kein Backup vorhanden</p>
{% endif %}
{% else %}
<p class="text-muted mb-0">Noch kein Backup vorhanden</p>
{% endif %}
<a href="/backups" class="btn btn-sm btn-outline-primary mt-2">Backup-Verwaltung →</a>
</div>
</div>
</div>
</a>
</div>
<!-- Sicherheitsstatus -->
@@ -303,4 +348,46 @@
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
<script>
// Donut Chart für Lizenzen
const ctx = document.getElementById('licenseChart');
if (ctx) {
const licenseChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Aktiv', 'Abgelaufen'],
datasets: [{
data: [{{ stats.active_licenses }}, {{ stats.expired_licenses }}],
backgroundColor: ['#28a745', '#dc3545'],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = context.parsed || 0;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100).toFixed(1);
return label + ': ' + value + ' (' + percentage + '%)';
}
}
}
},
cutout: '70%'
}
});
}
</script>
{% endblock %}