feat: Implement frontend production deployment and enhance admin dashboard functionality
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
|
||||
{% block title %}Admin-Einstellungen - Mercedes-Benz MYP Platform{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-50 dark:from-slate-900 dark:via-slate-800 dark:to-slate-900">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
@@ -10,39 +15,362 @@
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-slate-900 dark:text-white">System-Einstellungen</h1>
|
||||
<p class="text-slate-600 dark:text-slate-400 mt-2">Konfiguration des MYP-Systems</p>
|
||||
<h1 class="text-3xl font-bold text-slate-900 dark:text-white">Admin-Einstellungen</h1>
|
||||
<p class="text-slate-600 dark:text-slate-400 mt-2">Systemkonfiguration und Verwaltungsoptionen</p>
|
||||
</div>
|
||||
<a href="{{ url_for('admin_page', tab='system') }}" class="inline-flex items-center px-4 py-2 bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl hover:bg-slate-300 dark:hover:bg-slate-600 transition-all duration-300">
|
||||
<a href="{{ url_for('admin_page') }}" class="inline-flex items-center px-4 py-2 bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl hover:bg-slate-300 dark:hover:bg-slate-600 transition-all duration-300">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
</svg>
|
||||
Zurück
|
||||
Zurück zum Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="bg-white/80 dark:bg-slate-800/80 backdrop-blur-xl rounded-3xl border border-white/20 dark:border-slate-700/50 shadow-xl p-8">
|
||||
<div class="text-center py-12">
|
||||
<svg class="w-16 h-16 mx-auto text-slate-400 dark:text-slate-500 mb-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"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
</svg>
|
||||
<h3 class="text-lg font-medium text-slate-900 dark:text-white mb-2">System-Einstellungen</h3>
|
||||
<p class="text-slate-500 dark:text-slate-400 mb-6">Diese Funktion wird in einer zukünftigen Version implementiert.</p>
|
||||
<div class="space-y-2 text-sm text-slate-600 dark:text-slate-400">
|
||||
<p>Hier können Sie verschiedene Systemeinstellungen konfigurieren:</p>
|
||||
<ul class="list-disc list-inside space-y-1 mt-4">
|
||||
<li>Allgemeine Systemkonfiguration</li>
|
||||
<li>Sicherheitseinstellungen</li>
|
||||
<li>Netzwerkeinstellungen</li>
|
||||
<li>Backup-Konfiguration</li>
|
||||
<li>Logging-Einstellungen</li>
|
||||
</ul>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- System-Wartung -->
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-6">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">System-Wartung</h3>
|
||||
<div class="space-y-4">
|
||||
<button onclick="clearCache()"
|
||||
class="w-full px-4 py-3 bg-blue-500 text-white rounded-xl hover:bg-blue-600 transition-all duration-300">
|
||||
Cache leeren
|
||||
</button>
|
||||
<button onclick="optimizeDatabase()"
|
||||
class="w-full px-4 py-3 bg-green-500 text-white rounded-xl hover:bg-green-600 transition-all duration-300">
|
||||
Datenbank optimieren
|
||||
</button>
|
||||
<button onclick="createBackup()"
|
||||
class="w-full px-4 py-3 bg-purple-500 text-white rounded-xl hover:bg-purple-600 transition-all duration-300">
|
||||
Backup erstellen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Drucker-Verwaltung -->
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-6">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">Drucker-Verwaltung</h3>
|
||||
<div class="space-y-4">
|
||||
<button onclick="updatePrinters()"
|
||||
class="w-full px-4 py-3 bg-orange-500 text-white rounded-xl hover:bg-orange-600 transition-all duration-300">
|
||||
Drucker-Status aktualisieren
|
||||
</button>
|
||||
<button onclick="testAllPrinters()"
|
||||
class="w-full px-4 py-3 bg-teal-500 text-white rounded-xl hover:bg-teal-600 transition-all duration-300">
|
||||
Alle Drucker testen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System-Informationen -->
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-6">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">System-Informationen</h3>
|
||||
<div class="space-y-3" id="system-info">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-slate-600 dark:text-slate-400">Server-Status:</span>
|
||||
<span class="text-slate-900 dark:text-white font-semibold" id="server-status">Lade...</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-slate-600 dark:text-slate-400">Datenbank:</span>
|
||||
<span class="text-slate-900 dark:text-white font-semibold" id="db-status">Lade...</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-slate-600 dark:text-slate-400">Uptime:</span>
|
||||
<span class="text-slate-900 dark:text-white font-semibold" id="uptime">Lade...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logs und Überwachung -->
|
||||
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-6">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">Logs und Überwachung</h3>
|
||||
<div class="space-y-4">
|
||||
<button onclick="downloadLogs()"
|
||||
class="w-full px-4 py-3 bg-slate-500 text-white rounded-xl hover:bg-slate-600 transition-all duration-300">
|
||||
Logs herunterladen
|
||||
</button>
|
||||
<button onclick="runMaintenance()"
|
||||
class="w-full px-4 py-3 bg-indigo-500 text-white rounded-xl hover:bg-indigo-600 transition-all duration-300">
|
||||
Wartung ausführen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Erweiterte Einstellungen -->
|
||||
<div class="mt-8 bg-white dark:bg-slate-800 rounded-2xl shadow-xl p-6">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">Erweiterte Einstellungen</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Automatische Backup-Intervall (Stunden)
|
||||
</label>
|
||||
<input type="number" id="backup-interval" min="1" max="168" value="24"
|
||||
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-slate-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Maximale Job-Laufzeit (Stunden)
|
||||
</label>
|
||||
<input type="number" id="max-job-time" min="1" max="72" value="12"
|
||||
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-slate-700 dark:text-white">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button onclick="saveSettings()"
|
||||
class="px-6 py-3 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl hover:from-blue-600 hover:to-blue-700 transition-all duration-300 shadow-lg">
|
||||
Einstellungen speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// CSRF Token
|
||||
function getCsrfToken() {
|
||||
const token = document.querySelector('meta[name="csrf-token"]');
|
||||
return token ? token.getAttribute('content') : '';
|
||||
}
|
||||
|
||||
// Notification anzeigen
|
||||
function showNotification(message, type = 'info') {
|
||||
if (type === 'success') {
|
||||
alert('✓ ' + message);
|
||||
} else if (type === 'error') {
|
||||
alert('✗ ' + message);
|
||||
} else {
|
||||
alert('ℹ ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache leeren
|
||||
async function clearCache() {
|
||||
if (!confirm('Möchten Sie den Cache wirklich leeren?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/cache/clear', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
}
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Cache erfolgreich geleert', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler beim Leeren des Cache', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Datenbank optimieren
|
||||
async function optimizeDatabase() {
|
||||
if (!confirm('Möchten Sie die Datenbank optimieren? Dies kann einige Minuten dauern.')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/database/optimize', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
}
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Datenbank erfolgreich optimiert', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler bei der Datenbankoptimierung', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Backup erstellen
|
||||
async function createBackup() {
|
||||
if (!confirm('Möchten Sie ein Backup erstellen?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/backup/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
}
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Backup erfolgreich erstellt', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler beim Erstellen des Backups', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Drucker aktualisieren
|
||||
async function updatePrinters() {
|
||||
try {
|
||||
const response = await fetch('/api/admin/printers/update', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
}
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Drucker-Status erfolgreich aktualisiert', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler beim Aktualisieren der Drucker', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Alle Drucker testen
|
||||
async function testAllPrinters() {
|
||||
try {
|
||||
const response = await fetch('/api/printers/status');
|
||||
const printers = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
const onlineCount = printers.filter(p => p.status === 'available').length;
|
||||
showNotification(`${onlineCount} von ${printers.length} Druckern sind online`, 'info');
|
||||
} else {
|
||||
showNotification('Fehler beim Testen der Drucker', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Logs herunterladen
|
||||
async function downloadLogs() {
|
||||
try {
|
||||
const response = await fetch('/api/admin/logs/download');
|
||||
|
||||
if (response.ok) {
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'myp-logs.zip';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
showNotification('Logs werden heruntergeladen', 'success');
|
||||
} else {
|
||||
showNotification('Fehler beim Herunterladen der Logs', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Wartung ausführen
|
||||
async function runMaintenance() {
|
||||
if (!confirm('Möchten Sie die Systemwartung ausführen?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/maintenance/run', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
}
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Wartung erfolgreich ausgeführt', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler bei der Wartung', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Einstellungen speichern
|
||||
async function saveSettings() {
|
||||
const backupInterval = document.getElementById('backup-interval').value;
|
||||
const maxJobTime = document.getElementById('max-job-time').value;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/admin/settings', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCsrfToken()
|
||||
},
|
||||
body: JSON.stringify({
|
||||
backup_interval: parseInt(backupInterval),
|
||||
max_job_time: parseInt(maxJobTime)
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
showNotification('Einstellungen erfolgreich gespeichert', 'success');
|
||||
} else {
|
||||
showNotification(result.error || 'Fehler beim Speichern der Einstellungen', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// System-Informationen laden
|
||||
async function loadSystemInfo() {
|
||||
try {
|
||||
const [systemResponse, dbResponse] = await Promise.all([
|
||||
fetch('/api/admin/system/status'),
|
||||
fetch('/api/admin/database/status')
|
||||
]);
|
||||
|
||||
const systemData = await systemResponse.json();
|
||||
const dbData = await dbResponse.json();
|
||||
|
||||
if (systemResponse.ok) {
|
||||
document.getElementById('server-status').textContent = systemData.status || 'Online';
|
||||
document.getElementById('uptime').textContent = systemData.uptime || 'Unbekannt';
|
||||
}
|
||||
|
||||
if (dbResponse.ok) {
|
||||
document.getElementById('db-status').textContent = dbData.connected ? 'Verbunden' : 'Getrennt';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der System-Informationen:', error);
|
||||
document.getElementById('server-status').textContent = 'Fehler';
|
||||
document.getElementById('db-status').textContent = 'Fehler';
|
||||
document.getElementById('uptime').textContent = 'Fehler';
|
||||
}
|
||||
}
|
||||
|
||||
// Beim Laden der Seite
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadSystemInfo();
|
||||
|
||||
// Alle 30 Sekunden aktualisieren
|
||||
setInterval(loadSystemInfo, 30000);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user