🐛 Backend Optimization: Enhanced database performance with new files (myp.db-shm, myp.db-wal) and CSS styling improvements in tailwind.min.css & printers.html 🖥️📊
This commit is contained in:
parent
345fc6cbb5
commit
db4fd5b6c3
@ -2669,7 +2669,7 @@ def toggle_printer_power(printer_id):
|
|||||||
|
|
||||||
# Standard-Zustand ermitteln (Toggle-Verhalten)
|
# Standard-Zustand ermitteln (Toggle-Verhalten)
|
||||||
db_session = get_db_session()
|
db_session = get_db_session()
|
||||||
printer = db_session.get(Printer, printer_id)
|
printer = db_session.get(Printer, printer_id) # Modernized from query().get()
|
||||||
|
|
||||||
if not printer:
|
if not printer:
|
||||||
db_session.close()
|
db_session.close()
|
||||||
@ -2730,7 +2730,7 @@ def test_printer_tapo_connection(printer_id):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
db_session = get_db_session()
|
db_session = get_db_session()
|
||||||
printer = db_session.get(Printer, printer_id)
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
|
|
||||||
if not printer:
|
if not printer:
|
||||||
db_session.close()
|
db_session.close()
|
||||||
@ -3963,7 +3963,7 @@ def create_job():
|
|||||||
db_session = get_db_session()
|
db_session = get_db_session()
|
||||||
|
|
||||||
# Prüfen, ob der Drucker existiert
|
# Prüfen, ob der Drucker existiert
|
||||||
printer = db_session.get(Printer, printer_id)
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
if not printer:
|
if not printer:
|
||||||
db_session.close()
|
db_session.close()
|
||||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||||
|
Binary file not shown.
BIN
backend/database/myp.db-shm
Normal file
BIN
backend/database/myp.db-shm
Normal file
Binary file not shown.
BIN
backend/database/myp.db-wal
Normal file
BIN
backend/database/myp.db-wal
Normal file
Binary file not shown.
2
backend/static/css/tailwind.min.css
vendored
2
backend/static/css/tailwind.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1288,233 +1288,15 @@ let printerManager;
|
|||||||
// Enhanced Printer Management System
|
// Enhanced Printer Management System
|
||||||
class PrinterManager {
|
class PrinterManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.printers = [];
|
this.init();
|
||||||
this.lastUpdateTime = null;
|
this.setupEventListeners();
|
||||||
this.autoRefreshInterval = null;
|
this.startAutoRefresh();
|
||||||
this.isPerformanceMonitoringEnabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
try {
|
await this.loadPrinters();
|
||||||
await this.loadPrinters();
|
this.populateFilterDropdowns(); // setupFilters() existiert nicht - verwende populateFilterDropdowns()
|
||||||
this.initializeEventListeners();
|
this.initializePerformanceMonitoring();
|
||||||
this.initializePerformanceMonitoring();
|
|
||||||
this.startAutoRefresh();
|
|
||||||
console.log('✅ PrinterManager erfolgreich initialisiert');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Fehler bei PrinterManager-Initialisierung:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializePerformanceMonitoring() {
|
|
||||||
try {
|
|
||||||
// Performance Monitoring initialisieren
|
|
||||||
this.isPerformanceMonitoringEnabled = true;
|
|
||||||
console.log('✅ Performance Monitoring aktiviert');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('⚠️ Performance Monitoring konnte nicht initialisiert werden:', error);
|
|
||||||
this.isPerformanceMonitoringEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async testPrint(printerId) {
|
|
||||||
try {
|
|
||||||
console.log(`🖨️ Testdruck für Drucker ${printerId} wird gestartet...`);
|
|
||||||
|
|
||||||
// Toggle-Button für Testdruck
|
|
||||||
const response = await fetch(`/api/admin/printers/${printerId}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCSRFToken()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: true })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
|
||||||
this.showSuccess(`Testdruck für Drucker ${printerId} gestartet`);
|
|
||||||
// Drucker-Status aktualisieren
|
|
||||||
setTimeout(() => this.loadPrinters(), 1000);
|
|
||||||
} else {
|
|
||||||
this.showError(`Testdruck fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Testdruck:', error);
|
|
||||||
this.showError('Netzwerkfehler beim Starten des Testdrucks');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async pausePrint(printerId) {
|
|
||||||
try {
|
|
||||||
console.log(`⏸️ Pausiere Druck für Drucker ${printerId}...`);
|
|
||||||
|
|
||||||
const response = await fetch(`/api/admin/printers/${printerId}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCSRFToken()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: false })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
|
||||||
this.showSuccess(`Druck für Drucker ${printerId} pausiert`);
|
|
||||||
setTimeout(() => this.loadPrinters(), 1000);
|
|
||||||
} else {
|
|
||||||
this.showError(`Pausieren fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Pausieren:', error);
|
|
||||||
this.showError('Netzwerkfehler beim Pausieren des Drucks');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async resetPrinter(printerId) {
|
|
||||||
try {
|
|
||||||
console.log(`🔄 Reset für Drucker ${printerId}...`);
|
|
||||||
|
|
||||||
const response = await fetch(`/api/admin/printers/${printerId}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCSRFToken()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: false })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
|
||||||
this.showSuccess(`Drucker ${printerId} wurde zurückgesetzt`);
|
|
||||||
setTimeout(() => this.loadPrinters(), 1000);
|
|
||||||
} else {
|
|
||||||
this.showError(`Reset fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Reset:', error);
|
|
||||||
this.showError('Netzwerkfehler beim Zurücksetzen des Druckers');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async connectPrinter(printerId) {
|
|
||||||
try {
|
|
||||||
console.log(`🔗 Verbinde zu Drucker ${printerId}...`);
|
|
||||||
|
|
||||||
const response = await fetch(`/api/admin/printers/${printerId}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCSRFToken()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: true })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
|
||||||
this.showSuccess(`Verbindung zu Drucker ${printerId} hergestellt`);
|
|
||||||
setTimeout(() => this.loadPrinters(), 1000);
|
|
||||||
} else {
|
|
||||||
this.showError(`Verbindung fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler bei Verbindung:', error);
|
|
||||||
this.showError('Netzwerkfehler beim Verbinden mit dem Drucker');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeEventListeners() {
|
|
||||||
// Search input
|
|
||||||
const searchInput = document.getElementById('search-input');
|
|
||||||
if (searchInput) {
|
|
||||||
searchInput.addEventListener('input', this.debounce(() => this.applyFilters(), 300));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter dropdowns
|
|
||||||
['filterStatus', 'filterLocation', 'filterModel', 'sort-by'].forEach(id => {
|
|
||||||
const element = document.getElementById(id);
|
|
||||||
if (element) {
|
|
||||||
element.addEventListener('change', () => this.applyFilters());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter checkboxes
|
|
||||||
['show-offline', 'show-maintenance', 'only-available'].forEach(id => {
|
|
||||||
const element = document.getElementById(id);
|
|
||||||
if (element) {
|
|
||||||
element.addEventListener('change', () => this.applyFilters());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Modal close handlers
|
|
||||||
document.addEventListener('click', (e) => {
|
|
||||||
if (e.target.classList.contains('modal-overlay')) {
|
|
||||||
this.closeAllModals();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keyboard shortcuts
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
this.closeAllModals();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('✅ Event Listeners initialisiert');
|
|
||||||
}
|
|
||||||
|
|
||||||
showSuccess(message) {
|
|
||||||
console.log('✅ Erfolg:', message);
|
|
||||||
// Toast-Benachrichtigung hier implementieren
|
|
||||||
this.showToast(message, 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
showError(message) {
|
|
||||||
console.error('❌ Fehler:', message);
|
|
||||||
// Toast-Benachrichtigung hier implementieren
|
|
||||||
this.showToast(message, 'error');
|
|
||||||
}
|
|
||||||
|
|
||||||
showToast(message, type = 'info') {
|
|
||||||
// Einfache Toast-Implementation
|
|
||||||
const toast = document.createElement('div');
|
|
||||||
toast.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 ${
|
|
||||||
type === 'success' ? 'bg-green-500 text-white' :
|
|
||||||
type === 'error' ? 'bg-red-500 text-white' :
|
|
||||||
'bg-blue-500 text-white'
|
|
||||||
}`;
|
|
||||||
toast.textContent = message;
|
|
||||||
|
|
||||||
document.body.appendChild(toast);
|
|
||||||
|
|
||||||
// Animation
|
|
||||||
setTimeout(() => toast.classList.add('animate-fade-in'), 10);
|
|
||||||
|
|
||||||
// Auto-remove
|
|
||||||
setTimeout(() => {
|
|
||||||
toast.classList.add('animate-fade-out');
|
|
||||||
setTimeout(() => document.body.removeChild(toast), 300);
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCSRFToken() {
|
|
||||||
const metaTag = document.querySelector('meta[name="csrf-token"]');
|
|
||||||
if (metaTag) {
|
|
||||||
return metaTag.getAttribute('content');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: Suche nach CSRFToken in versteckten Input-Feldern
|
|
||||||
const csrfInput = document.querySelector('input[name="csrf_token"]');
|
|
||||||
if (csrfInput) {
|
|
||||||
return csrfInput.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn('⚠️ CSRF-Token nicht gefunden');
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
@ -2257,302 +2039,15 @@ class PrinterManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadPrinterDetails(printer) {
|
loadPrinterDetails(printer) {
|
||||||
|
// Hier würden die Detail-Informationen geladen werden
|
||||||
console.log('Lade Details für Drucker:', printer);
|
console.log('Lade Details für Drucker:', printer);
|
||||||
|
// TODO: Implementiere Detail-Ansicht
|
||||||
try {
|
|
||||||
// Update basic info
|
|
||||||
document.getElementById('printer-name-display').textContent = printer.name;
|
|
||||||
document.getElementById('printer-model-display').textContent = printer.model || 'Unbekanntes Modell';
|
|
||||||
document.getElementById('ip-address').textContent = printer.ip_address || printer.plug_ip || 'Keine IP';
|
|
||||||
|
|
||||||
// Update status
|
|
||||||
this.updatePrinterStatusDisplay(printer);
|
|
||||||
|
|
||||||
// Load extended data from API
|
|
||||||
const response = await fetch(`/api/printers/${printer.id}/details`);
|
|
||||||
if (response.ok) {
|
|
||||||
const detailData = await response.json();
|
|
||||||
if (detailData.success) {
|
|
||||||
this.populateDetailedPrinterInfo(detailData.data);
|
|
||||||
} else {
|
|
||||||
console.warn('Fehler beim Laden der erweiterten Druckerdetails:', detailData.message);
|
|
||||||
this.populateMockPrinterInfo(printer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn('API-Endpunkt nicht verfügbar, verwende Mock-Daten');
|
|
||||||
this.populateMockPrinterInfo(printer);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Laden der Druckerdetails:', error);
|
|
||||||
this.populateMockPrinterInfo(printer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePrinterStatusDisplay(printer) {
|
|
||||||
const statusIcon = document.getElementById('printer-status-icon');
|
|
||||||
const statusBadge = document.getElementById('printer-status-badge');
|
|
||||||
const powerBtn = document.getElementById('power-toggle-btn');
|
|
||||||
|
|
||||||
// Status Icon und Badge aktualisieren
|
|
||||||
const statusClasses = this.getStatusClasses(printer.status);
|
|
||||||
statusIcon.className = `w-12 h-12 ${statusClasses.iconBg} rounded-xl flex items-center justify-center`;
|
|
||||||
statusIcon.innerHTML = this.getStatusIcon(printer.status);
|
|
||||||
|
|
||||||
statusBadge.className = `inline-flex items-center px-3 py-1 rounded-full text-sm font-medium ${statusClasses.badge}`;
|
|
||||||
statusBadge.innerHTML = `
|
|
||||||
<div class="w-2 h-2 ${printer.status === 'online' ? 'bg-green-500' : printer.status === 'offline' ? 'bg-red-500' : 'bg-yellow-500'} rounded-full mr-2 ${printer.status === 'printing' ? 'animate-pulse' : ''}"></div>
|
|
||||||
${this.getStatusText(printer.status)}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Power Button aktualisieren
|
|
||||||
if (printer.status === 'offline') {
|
|
||||||
powerBtn.innerHTML = `
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
|
|
||||||
</svg>
|
|
||||||
<span>Steckdose einschalten</span>
|
|
||||||
`;
|
|
||||||
powerBtn.className = 'w-full px-4 py-3 bg-green-500 hover:bg-green-600 text-white rounded-lg transition-colors flex items-center justify-center space-x-2';
|
|
||||||
} else {
|
|
||||||
powerBtn.innerHTML = `
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L18.364 5.636M5.636 18.364l12.728-12.728"/>
|
|
||||||
</svg>
|
|
||||||
<span>Steckdose ausschalten</span>
|
|
||||||
`;
|
|
||||||
powerBtn.className = 'w-full px-4 py-3 bg-red-500 hover:bg-red-600 text-white rounded-lg transition-colors flex items-center justify-center space-x-2';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
populateDetailedPrinterInfo(data) {
|
|
||||||
// Netzwerkstatus
|
|
||||||
document.getElementById('network-status').textContent = data.network?.connected ? 'Verbunden' : 'Getrennt';
|
|
||||||
document.getElementById('last-activity').textContent = this.formatTimeAgo(data.last_activity);
|
|
||||||
document.getElementById('printer-uptime').textContent = `Uptime: ${this.formatUptime(data.uptime)}`;
|
|
||||||
|
|
||||||
// Temperaturen
|
|
||||||
if (data.temperatures) {
|
|
||||||
this.updateTemperatureDisplays(data.temperatures);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aktueller Job
|
|
||||||
if (data.current_job) {
|
|
||||||
this.displayCurrentJob(data.current_job);
|
|
||||||
} else {
|
|
||||||
this.showNoJobMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aktivitätsverlauf
|
|
||||||
if (data.activity_log) {
|
|
||||||
this.displayActivityLog(data.activity_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistiken
|
|
||||||
if (data.statistics) {
|
|
||||||
this.displayStatistics(data.statistics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
populateMockPrinterInfo(printer) {
|
|
||||||
// Mock-Informationen für Drucker-Details
|
|
||||||
const detailsContainer = document.getElementById('printer-details-content');
|
|
||||||
if (detailsContainer) {
|
|
||||||
detailsContainer.innerHTML = `
|
|
||||||
<div class="space-y-4">
|
|
||||||
<div>
|
|
||||||
<h4 class="font-medium">Grundinformationen</h4>
|
|
||||||
<p>Modell: ${printer.model || 'Unbekannt'}</p>
|
|
||||||
<p>Standort: ${printer.location || 'Unbekannt'}</p>
|
|
||||||
<p>IP-Adresse: ${printer.ip_address || printer.plug_ip || 'Unbekannt'}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTemperatureDisplays(temperatures) {
|
|
||||||
if (temperatures.extruder) {
|
|
||||||
document.getElementById('extruder-temp').textContent = `${temperatures.extruder.current}°C`;
|
|
||||||
const extruderPercent = (temperatures.extruder.current / temperatures.extruder.max) * 100;
|
|
||||||
document.getElementById('extruder-temp-bar').style.width = `${extruderPercent}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temperatures.bed) {
|
|
||||||
document.getElementById('bed-temp').textContent = `${temperatures.bed.current}°C`;
|
|
||||||
const bedPercent = (temperatures.bed.current / temperatures.bed.max) * 100;
|
|
||||||
document.getElementById('bed-temp-bar').style.width = `${bedPercent}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temperatures.ambient) {
|
|
||||||
document.getElementById('ambient-temp').textContent = `${temperatures.ambient.current}°C`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
displayCurrentJob(job) {
|
|
||||||
document.getElementById('no-job-message').classList.add('hidden');
|
|
||||||
document.getElementById('active-job-display').classList.remove('hidden');
|
|
||||||
|
|
||||||
document.getElementById('job-title').textContent = job.title;
|
|
||||||
document.getElementById('job-details').textContent = `Gestartet vor ${this.formatDuration(job.time_elapsed)}`;
|
|
||||||
document.getElementById('job-progress-text').textContent = `${job.progress}%`;
|
|
||||||
document.getElementById('job-progress-bar').style.width = `${job.progress}%`;
|
|
||||||
document.getElementById('time-elapsed').textContent = `Vergangen: ${this.formatDuration(job.time_elapsed)}`;
|
|
||||||
document.getElementById('time-remaining').textContent = `Verbleibend: ~${this.formatDuration(job.time_remaining)}`;
|
|
||||||
document.getElementById('current-layer').textContent = `${job.current_layer}/${job.total_layers}`;
|
|
||||||
document.getElementById('print-quality').textContent = job.quality;
|
|
||||||
document.getElementById('print-material').textContent = job.material;
|
|
||||||
|
|
||||||
// Priority Badge
|
|
||||||
const priorityBadge = document.getElementById('job-priority');
|
|
||||||
priorityBadge.textContent = job.priority === 'high' ? 'Hoch' : job.priority === 'low' ? 'Niedrig' : 'Normal';
|
|
||||||
priorityBadge.className = job.priority === 'high' ?
|
|
||||||
'px-3 py-1 bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 rounded-full text-sm font-medium' :
|
|
||||||
'px-3 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 rounded-full text-sm font-medium';
|
|
||||||
|
|
||||||
// Show job control buttons
|
|
||||||
document.getElementById('pause-resume-btn').classList.remove('hidden');
|
|
||||||
document.getElementById('stop-print-btn').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
showNoJobMessage() {
|
|
||||||
document.getElementById('no-job-message').classList.remove('hidden');
|
|
||||||
document.getElementById('active-job-display').classList.add('hidden');
|
|
||||||
document.getElementById('pause-resume-btn').classList.add('hidden');
|
|
||||||
document.getElementById('stop-print-btn').classList.add('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
displayActivityLog(activities) {
|
|
||||||
const container = document.getElementById('recent-activity-info');
|
|
||||||
container.innerHTML = activities.map(activity => `
|
|
||||||
<div class="flex items-center space-x-3 p-3 bg-gray-50 dark:bg-slate-700/50 rounded-lg">
|
|
||||||
<div class="flex-shrink-0">
|
|
||||||
<div class="w-2 h-2 ${activity.type === 'success' ? 'bg-green-500' : activity.type === 'error' ? 'bg-red-500' : 'bg-blue-500'} rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 min-w-0">
|
|
||||||
<p class="text-sm font-medium text-mercedes-black dark:text-white">${activity.action}</p>
|
|
||||||
<p class="text-xs text-mercedes-gray dark:text-slate-400">${this.formatTimeAgo(activity.time)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
displayStatistics(stats) {
|
|
||||||
// Heutige Statistiken
|
|
||||||
document.getElementById('jobs-today').textContent = stats.today.jobs;
|
|
||||||
document.getElementById('success-rate').textContent = `${stats.today.success_rate}%`;
|
|
||||||
document.getElementById('print-time-today').textContent = `${stats.today.print_time}h`;
|
|
||||||
document.getElementById('material-used').textContent = `${stats.today.material_used}g`;
|
|
||||||
|
|
||||||
// Wöchentliche Statistiken
|
|
||||||
document.getElementById('weekly-jobs').textContent = stats.weekly.jobs;
|
|
||||||
document.getElementById('weekly-success').textContent = stats.weekly.successful;
|
|
||||||
document.getElementById('weekly-failed').textContent = stats.weekly.failed;
|
|
||||||
document.getElementById('weekly-material').textContent = `${(stats.weekly.material_used / 1000).toFixed(1)}kg`;
|
|
||||||
}
|
|
||||||
|
|
||||||
formatTimeAgo(dateString) {
|
|
||||||
const now = new Date();
|
|
||||||
const date = new Date(dateString);
|
|
||||||
const diffInMinutes = Math.floor((now - date) / (1000 * 60));
|
|
||||||
|
|
||||||
if (diffInMinutes < 1) return 'Gerade eben';
|
|
||||||
if (diffInMinutes < 60) return `Vor ${diffInMinutes} Min`;
|
|
||||||
if (diffInMinutes < 1440) return `Vor ${Math.floor(diffInMinutes / 60)} Std`;
|
|
||||||
return `Vor ${Math.floor(diffInMinutes / 1440)} Tagen`;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSmartPlugControls(printer) {
|
|
||||||
// Nur für Admins sichtbar
|
|
||||||
if (!this.isCurrentUserAdmin()) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isOnline = ['online', 'printing', 'idle'].includes(printer.status);
|
|
||||||
const buttonClass = isOnline ? 'bg-red-500 hover:bg-red-600' : 'bg-green-500 hover:bg-green-600';
|
|
||||||
const buttonText = isOnline ? 'AUS' : 'EIN';
|
|
||||||
const buttonIcon = isOnline ?
|
|
||||||
`<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
||||||
</svg>` :
|
|
||||||
`<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
|
||||||
</svg>`;
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div class="smart-plug-control p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
|
|
||||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
||||||
🔌 Smart-Plug Steuerung
|
|
||||||
</h4>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<div class="text-xs text-gray-500">
|
|
||||||
Steckdose: ${printer.plug_ip || 'Nicht konfiguriert'}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onclick="printerManager.toggleSmartPlug(${printer.id}, ${!isOnline})"
|
|
||||||
class="smart-plug-btn flex items-center space-x-1 px-3 py-1 rounded text-white text-sm font-medium ${buttonClass} transition-colors duration-200"
|
|
||||||
${!printer.plug_ip ? 'disabled' : ''}
|
|
||||||
>
|
|
||||||
${buttonIcon}
|
|
||||||
<span>${buttonText}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-xs text-gray-500">
|
|
||||||
Status: <span class="font-medium">${this.getStatusText(printer.status)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async toggleSmartPlug(printerId, turnOn) {
|
|
||||||
try {
|
|
||||||
const action = turnOn ? 'einschalten' : 'ausschalten';
|
|
||||||
console.log(`🔌 Smart-Plug für Drucker ${printerId} wird ${action}...`);
|
|
||||||
|
|
||||||
// Visuelles Feedback
|
|
||||||
const button = document.querySelector(`button[onclick*="toggleSmartPlug(${printerId}"]`);
|
|
||||||
if (button) {
|
|
||||||
button.disabled = true;
|
|
||||||
button.innerHTML = '<svg class="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg> <span>Wird geschaltet...</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(`/api/admin/printers/${printerId}/toggle`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCSRFToken()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ state: turnOn })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
|
||||||
this.showSuccess(`Smart-Plug erfolgreich ${action}: ${result.printer_name}`);
|
|
||||||
// Sofortige UI-Aktualisierung
|
|
||||||
setTimeout(() => this.loadPrinters(), 500);
|
|
||||||
} else {
|
|
||||||
this.showError(`Smart-Plug ${action} fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Smart-Plug Toggle:', error);
|
|
||||||
this.showError(`Netzwerkfehler beim ${turnOn ? 'Einschalten' : 'Ausschalten'} der Smart-Plug`);
|
|
||||||
} finally {
|
|
||||||
// Button wieder aktivieren
|
|
||||||
setTimeout(() => this.loadPrinters(), 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isCurrentUserAdmin() {
|
|
||||||
// Prüfe ob der aktuelle Benutzer Admin-Rechte hat
|
|
||||||
const userRole = document.querySelector('meta[name="user-role"]')?.getAttribute('content');
|
|
||||||
return userRole === 'admin';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Printer Manager
|
// Initialize Printer Manager
|
||||||
printerManager = new PrinterManager();
|
printerManager = new PrinterManager();
|
||||||
printerManager.init();
|
|
||||||
|
|
||||||
// Global functions for UI interactions
|
// Global functions for UI interactions
|
||||||
function refreshPrinters() {
|
function refreshPrinters() {
|
||||||
@ -2725,89 +2220,5 @@ function getStatusSummary() {
|
|||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neue globale Funktionen für Printer Details Modal Schnellaktionen
|
|
||||||
function refreshPrinterDetails() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
printerManager.loadPrinterDetails(currentPrinter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePrinterPower() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
const isOnline = ['online', 'printing', 'idle'].includes(currentPrinter.status);
|
|
||||||
printerManager.toggleSmartPlug(currentPrinter.id, !isOnline);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function pauseResumePrint() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter && currentPrinter.status === 'printing') {
|
|
||||||
// TODO: Implementiere Pause/Resume Funktionalität
|
|
||||||
console.log('Pausiere/Fortsetze Druck für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Pause/Resume Funktionalität wird implementiert');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopPrint() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter && currentPrinter.status === 'printing') {
|
|
||||||
if (confirm('Möchten Sie den aktuellen Druckauftrag wirklich abbrechen?')) {
|
|
||||||
// TODO: Implementiere Stop Print Funktionalität
|
|
||||||
console.log('Stoppe Druck für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Stop Print Funktionalität wird implementiert');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendToMaintenance() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
if (confirm(`Möchten Sie ${currentPrinter.name} in den Wartungsmodus versetzen?`)) {
|
|
||||||
// TODO: Implementiere Wartungsmodus
|
|
||||||
console.log('Wartungsmodus für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Wartungsmodus Funktionalität wird implementiert');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function testPrinterConnection() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
console.log('Teste Verbindung für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Verbindungstest wird durchgeführt...');
|
|
||||||
|
|
||||||
// Simulate connection test
|
|
||||||
setTimeout(() => {
|
|
||||||
printerManager.showSuccess('Verbindung erfolgreich getestet');
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openFileManager() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
console.log('Öffne Datei-Manager für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Datei-Manager wird geöffnet...');
|
|
||||||
// TODO: Implementiere Datei-Manager Modal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadFile() {
|
|
||||||
const currentPrinter = printerManager.getCurrentDetailsPrinter();
|
|
||||||
if (currentPrinter) {
|
|
||||||
console.log('Datei-Upload für Drucker:', currentPrinter.id);
|
|
||||||
printerManager.showSuccess('Datei-Upload wird geöffnet...');
|
|
||||||
// TODO: Implementiere Datei-Upload Modal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
});
|
|
||||||
|
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user