/** * Mercedes-Benz MYP Admin Dashboard JavaScript * Moderne Administration mit Echtzeit-Updates und eleganter UI */ // Globale Variablen let statsUpdateInterval; let systemStatusInterval; let realTimeChart; let csrfToken; // Dynamische API-Base-URL-Erkennung function detectApiBaseUrl() { const currentHost = window.location.hostname; const currentProtocol = window.location.protocol; const currentPort = window.location.port; console.log('🔍 Admin API URL Detection:', { currentHost, currentProtocol, currentPort }); // Wenn wir bereits auf dem richtigen Port sind, verwende relative URLs if (currentPort === '443' || !currentPort) { console.log('✅ Verwende relative URLs (HTTPS Port 443)'); return ''; } // FĂŒr alle anderen FĂ€lle, verwende HTTPS auf Port 443 const fallbackUrl = `https://${currentHost}`; console.log('🔄 Admin Fallback zu HTTPS:443:', fallbackUrl); return fallbackUrl; } // Globale API-Base-URL const API_BASE_URL = detectApiBaseUrl(); console.log('🔗 Admin API Base URL erkannt:', API_BASE_URL); // Initialisierung beim Laden der Seite document.addEventListener('DOMContentLoaded', function() { // CSRF Token fĂŒr AJAX-Anfragen csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); // Basis-Initialisierung initProgressBars(); initConfirmDialogs(); initFlashMessages(); // Erweiterte Admin-FunktionalitĂ€ten initAdminButtons(); initRealTimeUpdates(); initSystemMonitoring(); initModernAnimations(); initSearchAndFilters(); initDataExport(); // Auto-Refresh fĂŒr Statistiken startStatsUpdate(); console.log('🚀 Mercedes-Benz MYP Admin Dashboard loaded successfully'); }); /** * Initialisiert alle Admin-Button-FunktionalitĂ€ten */ function initAdminButtons() { // Benutzer-Management Buttons initUserManagement(); // Drucker-Management Buttons initPrinterManagement(); // System-Management Buttons initSystemManagement(); // Job-Management Buttons initJobManagement(); } /** * Benutzer-Management FunktionalitĂ€ten */ function initUserManagement() { // Neuer Benutzer Button const addUserBtn = document.getElementById('add-user-btn'); if (addUserBtn) { addUserBtn.addEventListener('click', () => showUserModal()); } // Benutzer bearbeiten Buttons document.querySelectorAll('.edit-user-btn').forEach(btn => { btn.addEventListener('click', (e) => { const userId = e.target.closest('button').dataset.userId; editUser(userId); }); }); // Benutzer löschen Buttons document.querySelectorAll('.delete-user-btn').forEach(btn => { btn.addEventListener('click', (e) => { const userId = e.target.closest('button').dataset.userId; const userName = e.target.closest('button').dataset.userName; deleteUser(userId, userName); }); }); } /** * Drucker-Management FunktionalitĂ€ten */ function initPrinterManagement() { // Drucker hinzufĂŒgen Button const addPrinterBtn = document.getElementById('add-printer-btn'); if (addPrinterBtn) { addPrinterBtn.addEventListener('click', () => showPrinterModal()); } // Drucker verwalten Buttons document.querySelectorAll('.manage-printer-btn').forEach(btn => { btn.addEventListener('click', (e) => { const printerId = e.target.closest('button').dataset.printerId; managePrinter(printerId); }); }); // Drucker-Einstellungen Buttons document.querySelectorAll('.settings-printer-btn').forEach(btn => { btn.addEventListener('click', (e) => { const printerId = e.target.closest('button').dataset.printerId; showPrinterSettings(printerId); }); }); } /** * System-Management FunktionalitĂ€ten */ function initSystemManagement() { // System Status Buttons const systemStatusBtn = document.querySelector('button[onclick*="System Status"]'); if (systemStatusBtn) { systemStatusBtn.onclick = null; systemStatusBtn.addEventListener('click', () => showSystemStatus()); } const analyticsBtn = document.querySelector('button[onclick*="Analytics"]'); if (analyticsBtn) { analyticsBtn.onclick = null; analyticsBtn.addEventListener('click', () => showAnalytics()); } // Cache leeren const clearCacheBtn = document.getElementById('clear-cache-btn'); if (clearCacheBtn) { clearCacheBtn.addEventListener('click', () => clearSystemCache()); } // Datenbank optimieren const optimizeDbBtn = document.getElementById('optimize-db-btn'); if (optimizeDbBtn) { optimizeDbBtn.addEventListener('click', () => optimizeDatabase()); } // Backup erstellen const createBackupBtn = document.getElementById('create-backup-btn'); if (createBackupBtn) { createBackupBtn.addEventListener('click', () => createSystemBackup()); } // Einstellungen bearbeiten const editSettingsBtn = document.getElementById('edit-settings-btn'); if (editSettingsBtn) { editSettingsBtn.addEventListener('click', () => showSystemSettings()); } // Drucker aktualisieren const updatePrintersBtn = document.getElementById('update-printers-btn'); if (updatePrintersBtn) { updatePrintersBtn.addEventListener('click', () => updateAllPrinters()); } // System neustarten const restartSystemBtn = document.getElementById('restart-system-btn'); if (restartSystemBtn) { restartSystemBtn.addEventListener('click', () => restartSystem()); } } /** * Job-Management FunktionalitĂ€ten */ function initJobManagement() { // Job-Aktionen document.querySelectorAll('.job-action-btn').forEach(btn => { btn.addEventListener('click', (e) => { const action = e.target.closest('button').dataset.action; const jobId = e.target.closest('button').dataset.jobId; handleJobAction(action, jobId); }); }); } /** * Echtzeit-Updates fĂŒr Dashboard */ function initRealTimeUpdates() { // Statistiken alle 30 Sekunden aktualisieren statsUpdateInterval = setInterval(() => { updateDashboardStats(); }, 30000); // System-Status alle 10 Sekunden aktualisieren systemStatusInterval = setInterval(() => { updateSystemStatus(); }, 10000); } /** * System-Monitoring initialisieren */ function initSystemMonitoring() { // CPU/RAM Monitoring in Echtzeit if (document.querySelector('.server-status')) { monitorSystemResources(); } } /** * Moderne Animationen initialisieren */ function initModernAnimations() { // Animierte Counters fĂŒr Statistiken animateCounters(); // Progress Bars mit Animation animateProgressBars(); // Hover-Effekte addHoverEffects(); } /** * Such- und Filter-FunktionalitĂ€ten */ function initSearchAndFilters() { // Benutzer-Suche const userSearch = document.querySelector('#user-search'); if (userSearch) { userSearch.addEventListener('input', (e) => { filterUsers(e.target.value); }); } // Job-Filter const jobFilter = document.querySelector('select[onchange*="filter"]'); if (jobFilter) { jobFilter.onchange = null; jobFilter.addEventListener('change', (e) => { filterJobs(e.target.value); }); } } /** * Daten-Export FunktionalitĂ€ten */ function initDataExport() { // Export-Buttons document.querySelectorAll('button[onclick*="export"]').forEach(btn => { btn.onclick = null; btn.addEventListener('click', (e) => { const exportType = btn.textContent.includes('Export') ? 'csv' : 'json'; exportData(exportType); }); }); } /** * Benutzer Modal anzeigen */ function showUserModal(userId = null) { const modal = createModal('Benutzer ' + (userId ? 'bearbeiten' : 'hinzufĂŒgen'), `
`); // Form-Handler mit preventDefault const form = document.getElementById('user-form'); form.addEventListener('submit', (e) => { e.preventDefault(); // Verhindert automatische Weiterleitung const formData = new FormData(e.target); if (userId) { updateUser(userId, formData); } else { createUser(formData); } }); } /** * System Status anzeigen */ function showSystemStatus() { showLoadingOverlay(); const url = `${API_BASE_URL}/api/admin/system/status`; fetch(url) .then(response => response.json()) .then(data => { hideLoadingOverlay(); const modal = createModal('🚀 System Status - Live Monitoring', `

Server Resources

CPU:
${data.cpu_usage || 0}%
RAM:
${data.memory_usage || 0}%
Uptime: ${data.uptime || 'Unbekannt'}

Services

Database: ${data.database_status === 'connected' ? 'Connected' : 'Disconnected'}
Scheduler: ${data.scheduler_running ? 'Running' : 'Stopped'}
`); }) .catch(error => { hideLoadingOverlay(); showNotification('Fehler beim Laden des System Status', 'error'); console.error('System status error:', error); }); } /** * Analytics anzeigen */ function showAnalytics() { const modal = createModal('📊 Live Analytics Dashboard', `

Drucker Auslastung

Erfolgsrate

Echtzeit Monitoring

-
Aktive Jobs
-
Online Drucker
-
Warteschlange
-
Erfolg %
`); // Analytics-Daten laden und Charts initialisieren loadAnalyticsData(); startLiveAnalytics(); } /** * System Cache leeren */ async function clearSystemCache() { if (!confirm('đŸ—‘ïž Möchten Sie wirklich den System-Cache leeren?')) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/cache/clear`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken } }); const data = await response.json(); hideLoadingOverlay(); if (data.success) { showNotification('✅ Cache erfolgreich geleert!', 'success'); // Seite nach 2 Sekunden neu laden setTimeout(() => window.location.reload(), 2000); } else { showNotification('❌ Fehler beim Leeren des Cache: ' + data.message, 'error'); } } catch (error) { hideLoadingOverlay(); showNotification('❌ Netzwerkfehler beim Leeren des Cache', 'error'); console.error('Cache clear error:', error); } } /** * Datenbank optimieren */ async function optimizeDatabase() { if (!confirm('🔧 Möchten Sie die Datenbank optimieren? Dies kann einige Minuten dauern.')) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/database/optimize`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken } }); const data = await response.json(); hideLoadingOverlay(); if (data.success) { showNotification('✅ Datenbank erfolgreich optimiert!', 'success'); } else { showNotification('❌ Fehler bei der Datenbank-Optimierung: ' + data.message, 'error'); } } catch (error) { hideLoadingOverlay(); showNotification('❌ Netzwerkfehler bei der Datenbank-Optimierung', 'error'); console.error('Database optimization error:', error); } } /** * System Backup erstellen */ async function createSystemBackup() { if (!confirm('đŸ’Ÿ Möchten Sie ein System-Backup erstellen?')) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/backup/create`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken } }); 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-backup-${new Date().toISOString().split('T')[0]}.zip`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); hideLoadingOverlay(); showNotification('✅ Backup erfolgreich erstellt und heruntergeladen!', 'success'); } else { throw new Error('Backup failed'); } } catch (error) { hideLoadingOverlay(); showNotification('❌ Fehler beim Erstellen des Backups', 'error'); console.error('Backup error:', error); } } /** * Utility-Funktionen fĂŒr UI */ function createModal(title, content) { const modal = document.createElement('div'); modal.className = 'fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4'; modal.innerHTML = `

${title}

${content}
`; document.body.appendChild(modal); // ESC-Key zum Schließen modal.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeModal(); }); return modal; } function closeModal() { const modal = document.querySelector('.fixed.inset-0.bg-black\\/50'); if (modal) { modal.remove(); } } function showLoadingOverlay() { const overlay = document.getElementById('loading-overlay'); if (overlay) { overlay.classList.remove('hidden'); } } function hideLoadingOverlay() { const overlay = document.getElementById('loading-overlay'); if (overlay) { overlay.classList.add('hidden'); } } function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 px-6 py-4 rounded-xl shadow-2xl z-50 transform transition-all duration-500 translate-x-full ${ type === 'success' ? 'bg-green-500 text-white' : type === 'error' ? 'bg-red-500 text-white' : type === 'warning' ? 'bg-yellow-500 text-black' : 'bg-blue-500 text-white' }`; notification.innerHTML = `
${type === 'success' ? '✅' : type === 'error' ? '❌' : type === 'warning' ? '⚠' : 'â„č'} ${message}
`; document.body.appendChild(notification); // Animation einblenden setTimeout(() => { notification.classList.remove('translate-x-full'); }, 100); // Nach 5 Sekunden entfernen setTimeout(() => { notification.classList.add('translate-x-full'); setTimeout(() => notification.remove(), 500); }, 5000); } /** * Original Basis-Funktionen (erweitert) */ function initProgressBars() { const progressBars = document.querySelectorAll('.progress-bar-fill, [style*="width:"]'); progressBars.forEach((bar, index) => { const width = bar.style.width || bar.getAttribute('data-width') || '0%'; bar.style.width = '0%'; // Animierte Progress Bars setTimeout(() => { bar.style.transition = 'width 1.5s cubic-bezier(0.4, 0, 0.2, 1)'; bar.style.width = width; }, index * 200); }); } function initConfirmDialogs() { // Erweiterte Confirm-Dialoge mit modernem Design document.querySelectorAll('[data-confirm]').forEach(element => { element.addEventListener('click', (e) => { e.preventDefault(); const message = element.dataset.confirm; if (confirm(message)) { // UrsprĂŒngliche Aktion ausfĂŒhren if (element.tagName === 'FORM') { element.submit(); } else if (element.href) { window.location.href = element.href; } } }); }); } function initFlashMessages() { const flashMessages = document.querySelectorAll('.flash-messages .alert, [class*="alert"]'); flashMessages.forEach((message, index) => { // Einblende-Animation message.style.opacity = '0'; message.style.transform = 'translateY(-20px)'; setTimeout(() => { message.style.transition = 'all 0.5s ease'; message.style.opacity = '1'; message.style.transform = 'translateY(0)'; }, index * 100); // Auto-hide nach 7 Sekunden setTimeout(() => { message.style.transition = 'all 0.5s ease'; message.style.opacity = '0'; message.style.transform = 'translateY(-20px)'; setTimeout(() => message.remove(), 500); }, 7000); }); } /** * Dashboard-Updates */ function startStatsUpdate() { updateDashboardStats(); setInterval(updateDashboardStats, 30000); // Alle 30 Sekunden } async function updateDashboardStats() { try { const url = `${API_BASE_URL}/api/admin/stats/live`; const response = await fetch(url); const data = await response.json(); // Stats animiert aktualisieren updateAnimatedCounter('total-users', data.total_users); updateAnimatedCounter('total-printers', data.total_printers); updateAnimatedCounter('active-jobs', data.active_jobs); updateAnimatedCounter('success-rate', data.success_rate); } catch (error) { console.error('Stats update error:', error); } } function updateAnimatedCounter(elementId, newValue) { const element = document.getElementById(elementId) || document.querySelector(`[data-stat="${elementId}"]`); if (!element) return; const currentValue = parseInt(element.textContent) || 0; const difference = newValue - currentValue; const steps = 20; const stepValue = difference / steps; let step = 0; const interval = setInterval(() => { step++; const value = Math.round(currentValue + (stepValue * step)); element.textContent = value + (elementId === 'success-rate' ? '%' : ''); if (step >= steps) { clearInterval(interval); element.textContent = newValue + (elementId === 'success-rate' ? '%' : ''); } }, 50); } // Global verfĂŒgbare Funktionen fĂŒr Modal-Callbacks window.closeModal = closeModal; window.refreshSystemStatus = () => { closeModal(); showSystemStatus(); }; /** * Animierte Counters fĂŒr Statistiken */ function animateCounters() { const counters = document.querySelectorAll('.counter, .stat-number, [data-counter]'); counters.forEach(counter => { const target = parseInt(counter.textContent.replace(/[^\d]/g, '')) || 0; const duration = 2000; // 2 Sekunden const increment = target / (duration / 16); // 60 FPS let current = 0; const updateCounter = () => { if (current < target) { current += increment; counter.textContent = Math.floor(current).toLocaleString('de-DE'); requestAnimationFrame(updateCounter); } else { counter.textContent = target.toLocaleString('de-DE'); } }; // Intersection Observer fĂŒr bessere Performance const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { updateCounter(); observer.unobserve(entry.target); } }); }); observer.observe(counter); }); } /** * Progress Bars mit Animation */ function animateProgressBars() { const progressBars = document.querySelectorAll('.progress-bar, [data-progress]'); progressBars.forEach(bar => { const targetWidth = bar.dataset.progress || bar.style.width || '0%'; const targetValue = parseInt(targetWidth); // Reset width bar.style.width = '0%'; // Animate to target setTimeout(() => { bar.style.transition = 'width 1.5s ease-out'; bar.style.width = targetWidth; }, 100); }); } /** * Hover-Effekte hinzufĂŒgen */ function addHoverEffects() { // Card hover effects const cards = document.querySelectorAll('.card, .stat-card, .dashboard-card'); cards.forEach(card => { card.addEventListener('mouseenter', () => { card.style.transform = 'translateY(-2px)'; card.style.boxShadow = '0 10px 25px rgba(0,0,0,0.1)'; }); card.addEventListener('mouseleave', () => { card.style.transform = 'translateY(0)'; card.style.boxShadow = ''; }); }); // Button hover effects const buttons = document.querySelectorAll('.btn, button:not(.no-hover)'); buttons.forEach(button => { button.addEventListener('mouseenter', () => { button.style.transform = 'scale(1.02)'; }); button.addEventListener('mouseleave', () => { button.style.transform = 'scale(1)'; }); }); } /** * Drucker Modal anzeigen */ function showPrinterModal(printerId = null) { const modal = createModal('Drucker ' + (printerId ? 'bearbeiten' : 'hinzufĂŒgen'), `
`); // Form-Handler mit preventDefault const form = document.getElementById('printer-form'); form.addEventListener('submit', (e) => { e.preventDefault(); // Verhindert automatische Weiterleitung const formData = new FormData(e.target); if (printerId) { updatePrinter(printerId, formData); } else { createPrinter(formData); } }); // Wenn Drucker bearbeitet wird, Daten laden if (printerId) { loadPrinterData(printerId); } } /** * Drucker erstellen */ async function createPrinter(formData) { try { showLoadingOverlay(); const url = `${API_BASE_URL}/api/admin/printers/create`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() }, body: JSON.stringify({ name: formData.get('name'), ip_address: formData.get('ip_address'), location: formData.get('location'), description: formData.get('description'), printer_type: formData.get('printer_type'), is_active: formData.get('is_active') === 'on' }) }); const result = await response.json(); if (response.ok) { showNotification('Drucker erfolgreich hinzugefĂŒgt', 'success'); closeModal(); location.reload(); // Seite neu laden um neue Daten anzuzeigen } else { showNotification(result.error || 'Fehler beim HinzufĂŒgen des Druckers', 'error'); } } catch (error) { console.error('Error creating printer:', error); showNotification('Fehler beim HinzufĂŒgen des Druckers', 'error'); } finally { hideLoadingOverlay(); } } /** * Fehlende Admin-Funktionen */ // System-Einstellungen anzeigen function showSystemSettings() { const modal = createModal('⚙ System-Einstellungen', `

Server-Konfiguration

Scheduler-Einstellungen

`); // Form-Handler const form = document.getElementById('settings-form'); form.addEventListener('submit', async (e) => { e.preventDefault(); await saveSystemSettings(new FormData(e.target)); }); } // System-Einstellungen speichern async function saveSystemSettings(formData) { try { showLoadingOverlay(); const settings = { server: { host: formData.get('host'), port: parseInt(formData.get('port')), ssl_enabled: formData.get('ssl_enabled') === 'on' }, scheduler: { interval_seconds: parseInt(formData.get('scheduler_interval')), enabled: formData.get('scheduler_enabled') === 'on' } }; const url = `${API_BASE_URL}/api/admin/settings`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() }, body: JSON.stringify(settings) }); const result = await response.json(); if (result.success) { showNotification('✅ Einstellungen erfolgreich gespeichert!', 'success'); closeModal(); } else { showNotification('❌ Fehler beim Speichern: ' + result.message, 'error'); } } catch (error) { console.error('Settings save error:', error); showNotification('❌ Fehler beim Speichern der Einstellungen', 'error'); } finally { hideLoadingOverlay(); } } // Alle Drucker aktualisieren async function updateAllPrinters() { if (!confirm('🔄 Möchten Sie den Status aller Drucker aktualisieren?')) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/printers/update-all`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() } }); const result = await response.json(); if (result.success) { showNotification(`✅ ${result.message}`, 'success'); // Seite nach 2 Sekunden neu laden setTimeout(() => location.reload(), 2000); } else { showNotification('❌ Fehler beim Aktualisieren: ' + result.message, 'error'); } } catch (error) { console.error('Printer update error:', error); showNotification('❌ Fehler beim Aktualisieren der Drucker', 'error'); } finally { hideLoadingOverlay(); } } // System neustarten async function restartSystem() { if (!confirm('🔄 Möchten Sie das System wirklich neu starten? Dies kann einige Minuten dauern.')) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/system/restart`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() } }); const result = await response.json(); if (result.success) { showNotification('🔄 System wird neu gestartet...', 'info'); // Nach 5 Sekunden versuchen, die Seite neu zu laden setTimeout(() => { location.reload(); }, 5000); } else { showNotification('❌ Fehler beim Neustart: ' + result.message, 'error'); } } catch (error) { console.error('System restart error:', error); showNotification('❌ Fehler beim System-Neustart', 'error'); } finally { hideLoadingOverlay(); } } // Drucker verwalten function managePrinter(printerId) { window.location.href = `/admin/printers/${printerId}/manage`; } // Drucker-Einstellungen anzeigen function showPrinterSettings(printerId) { window.location.href = `/admin/printers/${printerId}/settings`; } // Benutzer bearbeiten function editUser(userId) { window.location.href = `/admin/users/${userId}/edit`; } // Benutzer löschen async function deleteUser(userId, userName) { if (!confirm(`⚠ Möchten Sie den Benutzer "${userName}" wirklich löschen? Diese Aktion kann nicht rĂŒckgĂ€ngig gemacht werden.`)) return; showLoadingOverlay(); try { const url = `${API_BASE_URL}/api/admin/users/${userId}`; const response = await fetch(url, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() } }); const result = await response.json(); if (response.ok) { showNotification(`✅ Benutzer "${userName}" erfolgreich gelöscht`, 'success'); // Seite nach 2 Sekunden neu laden setTimeout(() => location.reload(), 2000); } else { showNotification('❌ Fehler beim Löschen: ' + result.error, 'error'); } } catch (error) { console.error('User delete error:', error); showNotification('❌ Fehler beim Löschen des Benutzers', 'error'); } finally { hideLoadingOverlay(); } } // Job-Aktionen verarbeiten async function handleJobAction(action, jobId) { let confirmMessage = ''; let url = ''; let method = 'POST'; switch (action) { case 'cancel': confirmMessage = 'Möchten Sie diesen Job wirklich abbrechen?'; url = `${API_BASE_URL}/api/jobs/${jobId}/cancel`; break; case 'delete': confirmMessage = 'Möchten Sie diesen Job wirklich löschen?'; url = `${API_BASE_URL}/api/jobs/${jobId}`; method = 'DELETE'; break; case 'finish': confirmMessage = 'Möchten Sie diesen Job als beendet markieren?'; url = `${API_BASE_URL}/api/jobs/${jobId}/finish`; break; default: showNotification('❌ Unbekannte Aktion', 'error'); return; } if (!confirm(confirmMessage)) return; showLoadingOverlay(); try { const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() } }); const result = await response.json(); if (response.ok) { showNotification('✅ Aktion erfolgreich ausgefĂŒhrt', 'success'); // Seite nach 2 Sekunden neu laden setTimeout(() => location.reload(), 2000); } else { showNotification('❌ Fehler: ' + result.error, 'error'); } } catch (error) { console.error('Job action error:', error); showNotification('❌ Fehler beim AusfĂŒhren der Aktion', 'error'); } finally { hideLoadingOverlay(); } } // Such- und Filter-Funktionen function filterUsers(searchTerm) { const userRows = document.querySelectorAll('tbody tr'); userRows.forEach(row => { const text = row.textContent.toLowerCase(); const matches = text.includes(searchTerm.toLowerCase()); row.style.display = matches ? '' : 'none'; }); } function filterJobs(status) { const jobRows = document.querySelectorAll('.job-row, [data-job-status]'); jobRows.forEach(row => { if (status === 'all') { row.style.display = ''; } else { const jobStatus = row.dataset.jobStatus || row.querySelector('.status')?.textContent?.toLowerCase(); const matches = jobStatus === status.toLowerCase(); row.style.display = matches ? '' : 'none'; } }); } // Daten-Export function exportData(type) { const url = `${API_BASE_URL}/api/admin/export/${type}`; window.open(url, '_blank'); } // Analytics-Daten laden async function loadAnalyticsData() { try { const response = await fetch(`${API_BASE_URL}/api/admin/stats/live`); const data = await response.json(); // Charts mit Chart.js erstellen (falls verfĂŒgbar) if (typeof Chart !== 'undefined') { createPrinterUsageChart(data); createSuccessRateChart(data); } } catch (error) { console.error('Analytics data error:', error); } } // Live-Analytics starten function startLiveAnalytics() { setInterval(async () => { try { const response = await fetch(`${API_BASE_URL}/api/admin/stats/live`); const data = await response.json(); // Live-Werte aktualisieren document.getElementById('live-jobs').textContent = data.jobs?.active || 0; document.getElementById('live-printers').textContent = data.printers?.online || 0; document.getElementById('live-queue').textContent = data.jobs?.queued || 0; document.getElementById('live-success').textContent = (data.jobs?.success_rate || 0) + '%'; } catch (error) { console.error('Live analytics error:', error); } }, 5000); // Alle 5 Sekunden } // System-Status aktualisieren async function updateSystemStatus() { try { const response = await fetch(`${API_BASE_URL}/api/admin/system/status`); const data = await response.json(); // Status-Indikatoren aktualisieren const indicators = document.querySelectorAll('.status-indicator'); indicators.forEach(indicator => { // Aktualisiere basierend auf data }); } catch (error) { console.error('System status update error:', error); } } /** * Drucker aktualisieren */ async function updatePrinter(printerId, formData) { try { showLoadingOverlay(); const url = `${API_BASE_URL}/api/admin/printers/${printerId}/edit`; const response = await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() }, body: JSON.stringify({ name: formData.get('name'), ip_address: formData.get('ip_address'), location: formData.get('location'), description: formData.get('description'), printer_type: formData.get('printer_type'), is_active: formData.get('is_active') === 'on' }) }); const result = await response.json(); if (response.ok) { showNotification('Drucker erfolgreich aktualisiert', 'success'); closeModal(); location.reload(); } else { showNotification(result.error || 'Fehler beim Aktualisieren des Druckers', 'error'); } } catch (error) { console.error('Error updating printer:', error); showNotification('Fehler beim Aktualisieren des Druckers', 'error'); } finally { hideLoadingOverlay(); } } /** * Drucker-Daten laden */ async function loadPrinterData(printerId) { try { const url = `${API_BASE_URL}/api/printers`; const response = await fetch(url); const printers = await response.json(); const printer = printers.find(p => p.id == printerId); if (printer) { const form = document.getElementById('printer-form'); form.name.value = printer.name || ''; form.ip_address.value = printer.ip_address || ''; form.location.value = printer.location || ''; form.description.value = printer.description || ''; form.printer_type.value = printer.printer_type || 'FDM'; form.is_active.checked = printer.is_active; } } catch (error) { console.error('Error loading printer data:', error); showNotification('Fehler beim Laden der Drucker-Daten', 'error'); } } /** * CSRF Token abrufen */ function getCSRFToken() { const token = document.querySelector('meta[name=csrf-token]'); return token ? token.getAttribute('content') : ''; } /** * Benutzer erstellen */ async function createUser(formData) { try { showLoadingOverlay(); const url = `${API_BASE_URL}/api/admin/users/create`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() }, body: JSON.stringify({ email: formData.get('email'), name: formData.get('name'), password: formData.get('password'), role: formData.get('role'), username: formData.get('email').split('@')[0] // Username aus E-Mail ableiten }) }); const result = await response.json(); if (response.ok) { showNotification('Benutzer erfolgreich erstellt', 'success'); closeModal(); location.reload(); // Seite neu laden um neue Daten anzuzeigen } else { showNotification(result.error || 'Fehler beim Erstellen des Benutzers', 'error'); } } catch (error) { console.error('Error creating user:', error); showNotification('Fehler beim Erstellen des Benutzers', 'error'); } finally { hideLoadingOverlay(); } } /** * Benutzer aktualisieren */ async function updateUser(userId, formData) { try { showLoadingOverlay(); const url = `${API_BASE_URL}/api/admin/users/${userId}/edit`; const response = await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() }, body: JSON.stringify({ email: formData.get('email'), name: formData.get('name'), password: formData.get('password'), role: formData.get('role') }) }); const result = await response.json(); if (response.ok) { showNotification('Benutzer erfolgreich aktualisiert', 'success'); closeModal(); location.reload(); } else { showNotification(result.error || 'Fehler beim Aktualisieren des Benutzers', 'error'); } } catch (error) { console.error('Error updating user:', error); showNotification('Fehler beim Aktualisieren des Benutzers', 'error'); } finally { hideLoadingOverlay(); } } console.log('🎉 Mercedes-Benz MYP Admin Dashboard JavaScript vollstĂ€ndig geladen!');