350 lines
13 KiB
JavaScript
350 lines
13 KiB
JavaScript
/**
|
|
* Admin System Management JavaScript
|
|
* Funktionen für System-Wartung und -Konfiguration
|
|
*/
|
|
|
|
// CSRF Token für AJAX-Anfragen
|
|
function getCsrfToken() {
|
|
const token = document.querySelector('meta[name="csrf-token"]');
|
|
return token ? token.getAttribute('content') : '';
|
|
}
|
|
|
|
// Hilfsfunktion für API-Aufrufe
|
|
async function makeApiCall(url, method = 'GET', data = null) {
|
|
const options = {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCsrfToken()
|
|
}
|
|
};
|
|
|
|
if (data) {
|
|
options.body = JSON.stringify(data);
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, options);
|
|
const result = await response.json();
|
|
|
|
if (response.ok) {
|
|
showNotification(result.message || 'Aktion erfolgreich ausgeführt', 'success');
|
|
return result;
|
|
} else {
|
|
showNotification(result.error || 'Ein Fehler ist aufgetreten', 'error');
|
|
return null;
|
|
}
|
|
} catch (error) {
|
|
showNotification('Netzwerkfehler: ' + error.message, 'error');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Logs laden und anzeigen
|
|
async function loadLogs() {
|
|
const logsContainer = document.getElementById('logs-container');
|
|
if (!logsContainer) return;
|
|
|
|
// Lade-Animation anzeigen
|
|
logsContainer.innerHTML = `
|
|
<div class="flex justify-center items-center py-12">
|
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600 dark:border-indigo-400"></div>
|
|
</div>
|
|
`;
|
|
|
|
try {
|
|
const response = await fetch('/api/logs');
|
|
if (!response.ok) throw new Error('Fehler beim Laden der Logs');
|
|
|
|
const data = await response.json();
|
|
window.logsData = data.logs || [];
|
|
window.filteredLogs = [...window.logsData];
|
|
renderLogs();
|
|
updateLogStatistics();
|
|
scrollLogsToBottom();
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Logs:', error);
|
|
logsContainer.innerHTML = `
|
|
<div class="text-center py-8">
|
|
<div class="text-red-600 dark:text-red-400 text-xl mb-2">Fehler beim Laden der Logs</div>
|
|
<p class="text-gray-600 dark:text-gray-400">${error.message}</p>
|
|
<button onclick="loadLogs()" class="mt-4 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors">
|
|
Erneut versuchen
|
|
</button>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Logs rendern
|
|
function renderLogs() {
|
|
const logsContainer = document.getElementById('logs-container');
|
|
if (!logsContainer || !window.filteredLogs) return;
|
|
|
|
if (window.filteredLogs.length === 0) {
|
|
logsContainer.innerHTML = `
|
|
<div class="text-center py-8">
|
|
<p class="text-gray-600 dark:text-gray-400">Keine Logs gefunden</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
const logsHtml = window.filteredLogs.map(log => {
|
|
const levelColor = getLogLevelColor(log.level);
|
|
return `
|
|
<div class="bg-white/40 dark:bg-slate-700/40 rounded-lg p-4 border ${levelColor.border}">
|
|
<div class="flex items-start space-x-3">
|
|
<span class="inline-block px-2 py-1 text-xs font-semibold rounded-full ${levelColor.bg} ${levelColor.text}">
|
|
${log.level}
|
|
</span>
|
|
<div class="flex-1">
|
|
<div class="flex items-center justify-between mb-1">
|
|
<span class="text-sm font-medium text-slate-600 dark:text-slate-400">${log.category}</span>
|
|
<span class="text-xs text-slate-500 dark:text-slate-500">${log.timestamp}</span>
|
|
</div>
|
|
<p class="text-sm text-slate-900 dark:text-white break-all">${log.message}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
logsContainer.innerHTML = logsHtml;
|
|
}
|
|
|
|
// Log-Level-Farben bestimmen
|
|
function getLogLevelColor(level) {
|
|
const colors = {
|
|
'ERROR': {
|
|
bg: 'bg-red-100 dark:bg-red-900/30',
|
|
text: 'text-red-800 dark:text-red-200',
|
|
border: 'border-red-200 dark:border-red-700'
|
|
},
|
|
'WARNING': {
|
|
bg: 'bg-yellow-100 dark:bg-yellow-900/30',
|
|
text: 'text-yellow-800 dark:text-yellow-200',
|
|
border: 'border-yellow-200 dark:border-yellow-700'
|
|
},
|
|
'INFO': {
|
|
bg: 'bg-blue-100 dark:bg-blue-900/30',
|
|
text: 'text-blue-800 dark:text-blue-200',
|
|
border: 'border-blue-200 dark:border-blue-700'
|
|
},
|
|
'DEBUG': {
|
|
bg: 'bg-gray-100 dark:bg-gray-900/30',
|
|
text: 'text-gray-800 dark:text-gray-200',
|
|
border: 'border-gray-200 dark:border-gray-700'
|
|
}
|
|
};
|
|
|
|
return colors[level.toUpperCase()] || colors['INFO'];
|
|
}
|
|
|
|
// Log-Statistiken aktualisieren
|
|
function updateLogStatistics() {
|
|
if (!window.logsData) return;
|
|
|
|
const stats = {
|
|
total: window.logsData.length,
|
|
errors: window.logsData.filter(log => log.level.toUpperCase() === 'ERROR').length,
|
|
warnings: window.logsData.filter(log => log.level.toUpperCase() === 'WARNING').length,
|
|
info: window.logsData.filter(log => log.level.toUpperCase() === 'INFO').length
|
|
};
|
|
|
|
// Aktualisiere Statistik-Anzeigen falls vorhanden
|
|
const totalElement = document.getElementById('log-stats-total');
|
|
const errorsElement = document.getElementById('log-stats-errors');
|
|
const warningsElement = document.getElementById('log-stats-warnings');
|
|
const infoElement = document.getElementById('log-stats-info');
|
|
|
|
if (totalElement) totalElement.textContent = stats.total;
|
|
if (errorsElement) errorsElement.textContent = stats.errors;
|
|
if (warningsElement) warningsElement.textContent = stats.warnings;
|
|
if (infoElement) infoElement.textContent = stats.info;
|
|
}
|
|
|
|
// Zum Ende der Logs scrollen
|
|
function scrollLogsToBottom() {
|
|
const logsContainer = document.getElementById('logs-container');
|
|
if (logsContainer) {
|
|
logsContainer.scrollTop = logsContainer.scrollHeight;
|
|
}
|
|
}
|
|
|
|
// Notification anzeigen
|
|
function showNotification(message, type = 'info') {
|
|
// Erstelle Notification-Element falls nicht vorhanden
|
|
let notification = document.getElementById('admin-notification');
|
|
if (!notification) {
|
|
notification = document.createElement('div');
|
|
notification.id = 'admin-notification';
|
|
notification.className = 'fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transition-all duration-300 transform translate-x-full';
|
|
document.body.appendChild(notification);
|
|
}
|
|
|
|
// Setze Farbe basierend auf Typ
|
|
const colors = {
|
|
success: 'bg-green-500 text-white',
|
|
error: 'bg-red-500 text-white',
|
|
warning: 'bg-yellow-500 text-white',
|
|
info: 'bg-blue-500 text-white'
|
|
};
|
|
|
|
notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transition-all duration-300 ${colors[type] || colors.info}`;
|
|
notification.textContent = message;
|
|
|
|
// Zeige Notification
|
|
notification.style.transform = 'translateX(0)';
|
|
|
|
// Verstecke nach 5 Sekunden
|
|
setTimeout(() => {
|
|
notification.style.transform = 'translateX(100%)';
|
|
}, 5000);
|
|
}
|
|
|
|
// Cache leeren
|
|
async function clearCache() {
|
|
if (confirm('Möchten Sie wirklich den Cache leeren?')) {
|
|
showNotification('Cache wird geleert...', 'info');
|
|
const result = await makeApiCall('/api/admin/cache/clear', 'POST');
|
|
if (result) {
|
|
setTimeout(() => location.reload(), 2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Datenbank optimieren
|
|
async function optimizeDatabase() {
|
|
if (confirm('Möchten Sie wirklich die Datenbank optimieren? Dies kann einige Minuten dauern.')) {
|
|
showNotification('Datenbank wird optimiert...', 'info');
|
|
const result = await makeApiCall('/api/admin/database/optimize', 'POST');
|
|
if (result) {
|
|
setTimeout(() => location.reload(), 2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Backup erstellen
|
|
async function createBackup() {
|
|
if (confirm('Möchten Sie wirklich ein Backup erstellen?')) {
|
|
showNotification('Backup wird erstellt...', 'info');
|
|
const result = await makeApiCall('/api/admin/backup/create', 'POST');
|
|
}
|
|
}
|
|
|
|
// Drucker aktualisieren
|
|
async function updatePrinters() {
|
|
if (confirm('Möchten Sie alle Drucker-Verbindungen aktualisieren?')) {
|
|
showNotification('Drucker werden aktualisiert...', 'info');
|
|
const result = await makeApiCall('/api/admin/printers/update', 'POST');
|
|
if (result) {
|
|
setTimeout(() => location.reload(), 2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// System neustarten
|
|
async function restartSystem() {
|
|
if (confirm('WARNUNG: Möchten Sie wirklich das System neustarten? Alle aktiven Verbindungen werden getrennt.')) {
|
|
const result = await makeApiCall('/api/admin/system/restart', 'POST');
|
|
if (result) {
|
|
showNotification('System wird neugestartet...', 'warning');
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Einstellungen bearbeiten
|
|
function editSettings() {
|
|
window.location.href = '/settings';
|
|
}
|
|
|
|
// Systemstatus automatisch aktualisieren
|
|
async function updateSystemStatus() {
|
|
if (window.location.search.includes('tab=system')) {
|
|
const result = await makeApiCall('/api/admin/system/status');
|
|
if (result) {
|
|
// Aktualisiere die Anzeige
|
|
updateStatusDisplay('cpu_usage', result.cpu_usage + '%');
|
|
updateStatusDisplay('memory_usage', result.memory_usage + '%');
|
|
updateStatusDisplay('disk_usage', result.disk_usage + '%');
|
|
updateStatusDisplay('uptime', result.uptime);
|
|
updateStatusDisplay('db_size', result.db_size);
|
|
updateStatusDisplay('scheduler_jobs', result.scheduler_jobs);
|
|
updateStatusDisplay('next_job', result.next_job);
|
|
|
|
// Scheduler-Status aktualisieren
|
|
const schedulerStatus = document.querySelector('.scheduler-status');
|
|
if (schedulerStatus) {
|
|
if (result.scheduler_running) {
|
|
schedulerStatus.innerHTML = '<span class="w-2 h-2 mr-1 rounded-full bg-blue-400 animate-pulse"></span>Läuft';
|
|
schedulerStatus.className = 'inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200';
|
|
} else {
|
|
schedulerStatus.innerHTML = '<span class="w-2 h-2 mr-1 rounded-full bg-red-400"></span>Gestoppt';
|
|
schedulerStatus.className = 'inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hilfsfunktion zum Aktualisieren der Status-Anzeige
|
|
function updateStatusDisplay(key, value) {
|
|
const element = document.querySelector(`[data-status="${key}"]`);
|
|
if (element) {
|
|
element.textContent = value;
|
|
}
|
|
}
|
|
|
|
// Datenbankstatus aktualisieren
|
|
async function updateDatabaseStatus() {
|
|
if (window.location.search.includes('tab=system')) {
|
|
const result = await makeApiCall('/api/admin/database/status');
|
|
if (result) {
|
|
const dbStatus = document.querySelector('.database-status');
|
|
if (dbStatus) {
|
|
if (result.connected) {
|
|
dbStatus.innerHTML = '<span class="w-2 h-2 mr-1 rounded-full bg-green-400 animate-pulse"></span>Verbunden';
|
|
dbStatus.className = 'inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200';
|
|
} else {
|
|
dbStatus.innerHTML = '<span class="w-2 h-2 mr-1 rounded-full bg-red-400"></span>Getrennt';
|
|
dbStatus.className = 'inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200';
|
|
}
|
|
}
|
|
|
|
updateStatusDisplay('db_size', result.size);
|
|
updateStatusDisplay('db_connections', result.connected ? 'Aktiv' : 'Getrennt');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Auto-Update alle 30 Sekunden
|
|
setInterval(() => {
|
|
updateSystemStatus();
|
|
updateDatabaseStatus();
|
|
}, 30000);
|
|
|
|
// Initial load
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
updateSystemStatus();
|
|
updateDatabaseStatus();
|
|
});
|
|
|
|
// Export für globale Verwendung
|
|
window.adminSystem = {
|
|
clearCache,
|
|
optimizeDatabase,
|
|
createBackup,
|
|
updatePrinters,
|
|
restartSystem,
|
|
editSettings,
|
|
updateSystemStatus,
|
|
updateDatabaseStatus,
|
|
loadLogs,
|
|
renderLogs,
|
|
updateLogStatistics,
|
|
scrollLogsToBottom
|
|
};
|