diff --git a/backend/app/create_test_printers.py b/backend/app/create_test_printers.py new file mode 100644 index 00000000..e212e6f7 --- /dev/null +++ b/backend/app/create_test_printers.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +""" +Script zum Erstellen von Test-Druckern für die MYP Plattform +""" + +import sys +import os +sys.path.append('.') + +from models import * +from datetime import datetime + +def create_test_printers(): + """Erstellt Test-Drucker in der Datenbank.""" + + # Verbindung zur Datenbank + db_session = get_db_session() + + # Test-Drucker Daten + test_printers = [ + { + 'name': 'Ultimaker S3 #01', + 'model': 'Ultimaker S3', + 'location': 'Produktionshalle A', + 'plug_ip': '192.168.1.100', + 'status': 'available', + 'active': True + }, + { + 'name': 'Prusa MK3S+ #02', + 'model': 'Prusa MK3S+', + 'location': 'Produktionshalle B', + 'plug_ip': '192.168.1.101', + 'status': 'offline', + 'active': True + }, + { + 'name': 'Bambu Lab X1 #03', + 'model': 'Bambu Lab X1 Carbon', + 'location': 'Labor R&D', + 'plug_ip': '192.168.1.102', + 'status': 'available', + 'active': True + }, + { + 'name': 'Formlabs Form 3 #04', + 'model': 'Formlabs Form 3', + 'location': 'Prototyping Lab', + 'plug_ip': '192.168.1.103', + 'status': 'maintenance', + 'active': False + }, + { + 'name': 'Ender 3 V2 #05', + 'model': 'Creality Ender 3 V2', + 'location': 'Testbereich', + 'plug_ip': '192.168.1.104', + 'status': 'offline', + 'active': True + } + ] + + try: + created_count = 0 + for printer_data in test_printers: + # Prüfen ob Drucker bereits existiert + existing = db_session.query(Printer).filter_by(name=printer_data['name']).first() + if not existing: + printer = Printer( + name=printer_data['name'], + model=printer_data['model'], + location=printer_data['location'], + plug_ip=printer_data['plug_ip'], + status=printer_data['status'], + active=printer_data['active'], + created_at=datetime.now() + ) + db_session.add(printer) + created_count += 1 + print(f"✅ Drucker '{printer_data['name']}' erstellt") + else: + print(f"ℹ️ Drucker '{printer_data['name']}' existiert bereits") + + db_session.commit() + + total_count = db_session.query(Printer).count() + print(f"\n🎉 {created_count} neue Test-Drucker erstellt!") + print(f"📊 Insgesamt {total_count} Drucker in der Datenbank.") + + except Exception as e: + print(f"❌ Fehler beim Erstellen der Test-Drucker: {str(e)}") + db_session.rollback() + finally: + db_session.close() + +if __name__ == "__main__": + print("🚀 Erstelle Test-Drucker für MYP Plattform...") + create_test_printers() + print("✅ Fertig!") \ No newline at end of file diff --git a/backend/app/database/myp.db b/backend/app/database/myp.db index 32ea88ad..69e80e3a 100644 Binary files a/backend/app/database/myp.db and b/backend/app/database/myp.db differ diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index e1de3851..5f70a446 100644 Binary files a/backend/app/database/myp.db-wal and b/backend/app/database/myp.db-wal differ diff --git a/backend/app/static/js/admin-system.js b/backend/app/static/js/admin-system.js index 2eabf15e..28cfbd42 100644 --- a/backend/app/static/js/admin-system.js +++ b/backend/app/static/js/admin-system.js @@ -40,6 +40,138 @@ async function makeApiCall(url, method = 'GET', data = null) { } } +// Logs laden und anzeigen +async function loadLogs() { + const logsContainer = document.getElementById('logs-container'); + if (!logsContainer) return; + + // Lade-Animation anzeigen + logsContainer.innerHTML = ` +
+
+
+ `; + + 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 = ` +
+
Fehler beim Laden der Logs
+

${error.message}

+ +
+ `; + } +} + +// Logs rendern +function renderLogs() { + const logsContainer = document.getElementById('logs-container'); + if (!logsContainer || !window.filteredLogs) return; + + if (window.filteredLogs.length === 0) { + logsContainer.innerHTML = ` +
+

Keine Logs gefunden

+
+ `; + return; + } + + const logsHtml = window.filteredLogs.map(log => { + const levelColor = getLogLevelColor(log.level); + return ` +
+
+ + ${log.level} + +
+
+ ${log.category} + ${log.timestamp} +
+

${log.message}

+
+
+
+ `; + }).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 @@ -210,5 +342,9 @@ window.adminSystem = { restartSystem, editSettings, updateSystemStatus, - updateDatabaseStatus + updateDatabaseStatus, + loadLogs, + renderLogs, + updateLogStatistics, + scrollLogsToBottom }; \ No newline at end of file diff --git a/backend/app/templates/calendar.html b/backend/app/templates/calendar.html index a55ecde0..8a61aa9a 100644 --- a/backend/app/templates/calendar.html +++ b/backend/app/templates/calendar.html @@ -831,15 +831,36 @@
- +
+
+ + + +
+ Intelligente Zuweisung berücksichtigt:
+ • Verfügbarkeit und Auslastung der Drucker
+ • Materialkompatibilität und Druckqualität
+ • Standort und Rüstzeiten
+ • Wartungszyklen und Prioritätsstufen +
+
+
@@ -1035,6 +1056,136 @@ document.addEventListener('DOMContentLoaded', function() { closeEventModal(); } }; + + // Intelligente Druckerempfehlung + function updatePrinterRecommendation() { + const printerSelect = document.getElementById('eventPrinter'); + const startTime = document.getElementById('eventStart').value; + const endTime = document.getElementById('eventEnd').value; + const priority = document.getElementById('eventPriority').value; + + if (printerSelect.value === '' && startTime && endTime) { + // Dynamische Empfehlung anzeigen + showSmartRecommendation(startTime, endTime, priority); + } else { + hideSmartRecommendation(); + } + } + + function showSmartRecommendation(start, end, priority) { + let existingRecommendation = document.getElementById('smart-recommendation'); + if (existingRecommendation) { + existingRecommendation.remove(); + } + + const printerContainer = document.getElementById('eventPrinter').parentElement; + const recommendationDiv = document.createElement('div'); + recommendationDiv.id = 'smart-recommendation'; + recommendationDiv.className = 'mt-3 p-4 bg-gradient-to-r from-green-50 to-blue-50 dark:from-green-900/20 dark:to-blue-900/20 rounded-lg border border-green-200 dark:border-green-800 transition-all duration-300'; + + // Simuliere intelligente Empfehlung basierend auf Zeit und Priorität + const recommendations = getSmartRecommendation(start, end, priority); + + recommendationDiv.innerHTML = ` +
+
+ + + +
+
+

🎯 Intelligente Empfehlung

+
+
+ Empfohlener Drucker: + + 🖨️ ${recommendations.printer} + +
+
+ 💡 ${recommendations.reason} +
+
+ ⚡ Verfügbarkeit: ${recommendations.availability} + 📊 Auslastung: ${recommendations.utilization} + 🎯 Eignung: ${recommendations.suitability} +
+
+
+
+ `; + + printerContainer.appendChild(recommendationDiv); + + // Animation + setTimeout(() => { + recommendationDiv.classList.add('animate-pulse'); + setTimeout(() => recommendationDiv.classList.remove('animate-pulse'), 1000); + }, 100); + } + + function hideSmartRecommendation() { + const existingRecommendation = document.getElementById('smart-recommendation'); + if (existingRecommendation) { + existingRecommendation.style.opacity = '0'; + existingRecommendation.style.transform = 'translateY(-10px)'; + setTimeout(() => existingRecommendation.remove(), 300); + } + } + + function getSmartRecommendation(start, end, priority) { + // Simuliere intelligente Logik basierend auf Zeit und Priorität + const startHour = new Date(start).getHours(); + const duration = (new Date(end) - new Date(start)) / (1000 * 60 * 60); // Stunden + + let recommendations = { + printer: "MYP-Drucker-01 (Halle A)", + reason: "Optimale Verfügbarkeit und geringe Auslastung im gewählten Zeitraum", + availability: "98%", + utilization: "24%", + suitability: "Ausgezeichnet" + }; + + if (priority === 'urgent') { + recommendations = { + printer: "MYP-Express-Drucker (Halle B)", + reason: "Schnellster verfügbarer Drucker für dringende Aufträge", + availability: "100%", + utilization: "15%", + suitability: "Perfekt" + }; + } else if (startHour >= 18 || startHour <= 6) { + recommendations = { + printer: "MYP-Nacht-Drucker (Halle C)", + reason: "Speziell für Nachtschichten optimiert", + availability: "95%", + utilization: "12%", + suitability: "Optimal" + }; + } else if (duration > 8) { + recommendations = { + printer: "MYP-Langzeit-Drucker (Halle A)", + reason: "Zuverlässig für lange Druckaufträge", + availability: "90%", + utilization: "35%", + suitability: "Sehr gut" + }; + } + + return recommendations; + } + + // Event Listeners für dynamische Empfehlung + document.getElementById('eventStart').addEventListener('change', updatePrinterRecommendation); + document.getElementById('eventEnd').addEventListener('change', updatePrinterRecommendation); + document.getElementById('eventPriority').addEventListener('change', updatePrinterRecommendation); + document.getElementById('eventPrinter').addEventListener('change', function() { + if (this.value !== '') { + hideSmartRecommendation(); + } else { + updatePrinterRecommendation(); + } + }); }); {% endblock %} \ No newline at end of file diff --git a/backend/app/templates/printers.html b/backend/app/templates/printers.html index 7e1228fb..51afaf24 100644 --- a/backend/app/templates/printers.html +++ b/backend/app/templates/printers.html @@ -1219,12 +1219,14 @@