47 lines
14 KiB
JavaScript
47 lines
14 KiB
JavaScript
function safeUpdateElement(elementId,value,options={}){const{fallbackValue='-',logWarning=true,attribute='textContent',transform=null}=options;const element=document.getElementById(elementId);if(!element){if(logWarning){console.warn(`🔍 Element mit ID'${elementId}'nicht gefunden`);}
|
||
return false;}
|
||
try{const finalValue=value!==undefined&&value!==null?value:fallbackValue;const displayValue=transform?transform(finalValue):finalValue;element[attribute]=displayValue;return true;}catch(error){console.error(`❌ Fehler beim Aktualisieren von Element'${elementId}':`,error);return false;}}
|
||
function safeBatchUpdate(updates,options={}){const results={};Object.entries(updates).forEach(([elementId,value])=>{results[elementId]=safeUpdateElement(elementId,value,options);});const successful=Object.values(results).filter(Boolean).length;const total=Object.keys(updates).length;console.log(`📊 Batch-Update:${successful}/${total}Elemente erfolgreich aktualisiert`);return results;}
|
||
function elementExists(elementId){return document.getElementById(elementId)!==null;}
|
||
window.refreshDashboard=async function(){const refreshButton=document.getElementById('refreshDashboard');if(refreshButton){refreshButton.disabled=true;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.add('animate-spin');}}
|
||
try{const response=await fetch('/api/dashboard/refresh',{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':getCSRFToken()}});const data=await response.json();if(data.success){updateDashboardStats(data.stats);showToast('✅ Dashboard erfolgreich aktualisiert','success');setTimeout(()=>{window.location.reload();},1000);}else{showToast('❌ Fehler beim Aktualisieren des Dashboards','error');}}catch(error){console.error('Dashboard-Refresh Fehler:',error);showToast('❌ Netzwerkfehler beim Dashboard-Refresh','error');}finally{if(refreshButton){refreshButton.disabled=false;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.remove('animate-spin');}}}};window.refreshStats=async function(){const refreshButton=document.querySelector('button[onclick="refreshStats()"]');if(refreshButton){refreshButton.disabled=true;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.add('animate-spin');}}
|
||
try{if(typeof loadBasicStats==='function'){await loadBasicStats();}else{const response=await fetch('/api/stats');const data=await response.json();if(response.ok){updateStatsCounter('total-jobs-count',data.total_jobs);updateStatsCounter('completed-jobs-count',data.completed_jobs);updateStatsCounter('online-printers-count',data.online_printers);updateStatsCounter('success-rate-percent',data.success_rate+'%');updateStatsCounter('active-jobs-count',data.active_jobs);updateStatsCounter('failed-jobs-count',data.failed_jobs);updateStatsCounter('total-users-count',data.total_users);}else{throw new Error(data.error||'Fehler beim Laden der Statistiken');}}
|
||
if(window.refreshAllCharts){window.refreshAllCharts();}
|
||
showToast('✅ Statistiken erfolgreich aktualisiert','success');}catch(error){console.error('Stats-Refresh Fehler:',error);showToast('❌ Fehler beim Aktualisieren der Statistiken','error');}finally{if(refreshButton){refreshButton.disabled=false;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.remove('animate-spin');}}}};window.refreshJobs=async function(){const refreshButton=document.getElementById('refresh-button');if(refreshButton){refreshButton.disabled=true;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.add('animate-spin');}}
|
||
try{console.log('🔄 Starte Jobs-Refresh...');let refreshSuccess=false;if(typeof window.jobManager!=='undefined'&&window.jobManager&&typeof window.jobManager.loadJobs==='function'){console.log('📝 Verwende window.jobManager.loadJobs()');await window.jobManager.loadJobs();refreshSuccess=true;}else if(typeof jobManager!=='undefined'&&jobManager&&typeof jobManager.loadJobs==='function'){console.log('📝 Verwende lokalen jobManager.loadJobs()');await jobManager.loadJobs();refreshSuccess=true;}else{console.log('📝 JobManager nicht verfügbar - verwende direkten API-Aufruf');const response=await fetch('/api/jobs',{headers:{'Content-Type':'application/json','X-CSRFToken':getCSRFToken()}});if(!response.ok){throw new Error(`API-Fehler:${response.status}${response.statusText}`);}
|
||
const data=await response.json();console.log('📝 API-Response erhalten:',data);if(!data||typeof data!=='object'){throw new Error('Ungültige API-Response: Keine Daten erhalten');}
|
||
let jobs=[];if(Array.isArray(data.jobs)){jobs=data.jobs;}else if(Array.isArray(data)){jobs=data;}else if(data.success&&Array.isArray(data.data)){jobs=data.data;}else{console.warn('⚠️ Keine Jobs-Array in API-Response gefunden:',data);jobs=[];}
|
||
console.log(`📝 ${jobs.length}Jobs aus API extrahiert:`,jobs);const jobsContainers=['.jobs-container','#jobs-container','.job-grid','#jobs-list','#jobs-grid'];let containerFound=false;for(const selector of jobsContainers){const container=document.querySelector(selector);if(container){containerFound=true;console.log(`📝 Container gefunden:${selector}`);if(jobs.length===0){container.innerHTML=`<div class="text-center py-12"><div class="text-gray-400 dark:text-gray-600 text-6xl mb-4">📭</div><h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">Keine Jobs vorhanden</h3><p class="text-gray-500 dark:text-gray-400">Es wurden noch keine Druckaufträge erstellt.</p></div>`;}else{const jobCards=jobs.map(job=>{if(!job||typeof job!=='object'){console.warn('⚠️ Ungültiges Job-Objekt übersprungen:',job);return'';}
|
||
return`<div class="job-card p-4 border rounded-lg bg-white dark:bg-slate-800 shadow-sm hover:shadow-md transition-shadow"><h3 class="font-semibold text-gray-900 dark:text-white mb-2">${job.filename||job.title||job.name||'Unbekannter Job'}</h3><div class="text-sm text-gray-600 dark:text-gray-400 space-y-1"><p><span class="font-medium">ID:</span>${job.id||'N/A'}</p><p><span class="font-medium">Status:</span>${job.status||'Unbekannt'}</p>${job.printer_name?`<p><span class="font-medium">Drucker:</span>${job.printer_name}</p>`:''}
|
||
${job.created_at?`<p><span class="font-medium">Erstellt:</span>${new Date(job.created_at).toLocaleDateString('de-DE')}</p>`:''}</div></div>`;}).filter(card=>card!=='').join('');container.innerHTML=jobCards||`<div class="text-center py-8"><p class="text-gray-500 dark:text-gray-400">Keine gültigen Jobs zum Anzeigen</p></div>`;}
|
||
break;}}
|
||
if(!containerFound){console.warn('⚠️ Kein Jobs-Container gefunden. Verfügbare Container:',jobsContainers);}
|
||
refreshSuccess=true;}
|
||
if(refreshSuccess){showToast('✅ Druckaufträge erfolgreich aktualisiert','success');}}catch(error){console.error('❌ Jobs-Refresh Fehler:',error);let errorMessage;if(error.message.includes('undefined')){errorMessage='Jobs-Daten nicht verfügbar';}else if(error.message.includes('fetch')){errorMessage='Netzwerkfehler beim Laden der Jobs';}else if(error.message.includes('API')){errorMessage='Server-Fehler beim Laden der Jobs';}else{errorMessage=error.message||'Unbekannter Fehler beim Laden der Jobs';}
|
||
showToast(`❌ Fehler:${errorMessage}`,'error');const container=document.querySelector('.jobs-container, #jobs-container, .job-grid, #jobs-list');if(container){container.innerHTML=`<div class="text-center py-12"><div class="text-red-400 dark:text-red-600 text-6xl mb-4">⚠️</div><h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">Fehler beim Laden</h3><p class="text-gray-500 dark:text-gray-400 mb-4">${errorMessage}</p><button onclick="refreshJobs()"class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">Erneut versuchen</button></div>`;}}finally{if(refreshButton){refreshButton.disabled=false;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.remove('animate-spin');}}}};window.refreshCalendar=async function(){const refreshButton=document.getElementById('refresh-button');if(refreshButton){refreshButton.disabled=true;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.add('animate-spin');}}
|
||
try{if(typeof calendar!=='undefined'&&calendar.refetchEvents){calendar.refetchEvents();showToast('✅ Kalender erfolgreich aktualisiert','success');}else{window.location.reload();}}catch(error){console.error('Calendar-Refresh Fehler:',error);showToast('❌ Fehler beim Aktualisieren des Kalenders','error');}finally{if(refreshButton){refreshButton.disabled=false;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.remove('animate-spin');}}}};window.refreshPrinters=async function(){const refreshButton=document.getElementById('refresh-button');if(refreshButton){refreshButton.disabled=true;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.add('animate-spin');}}
|
||
try{if(typeof printerManager!=='undefined'&&printerManager.loadPrinters){await printerManager.loadPrinters();}else{const response=await fetch('/api/printers/status/live',{headers:{'X-CSRFToken':getCSRFToken()}});if(response.ok){window.location.reload();}else{throw new Error('Drucker-Status konnte nicht abgerufen werden');}}
|
||
showToast('✅ Drucker erfolgreich aktualisiert','success');}catch(error){console.error('Printer-Refresh Fehler:',error);showToast('❌ Fehler beim Aktualisieren der Drucker','error');}finally{if(refreshButton){refreshButton.disabled=false;const icon=refreshButton.querySelector('svg');if(icon){icon.classList.remove('animate-spin');}}}};function updateDashboardStats(stats){const activeJobsEl=document.querySelector('[data-stat="active-jobs"]');if(activeJobsEl){activeJobsEl.textContent=stats.active_jobs||0;}
|
||
const availablePrintersEl=document.querySelector('[data-stat="available-printers"]');if(availablePrintersEl){availablePrintersEl.textContent=stats.available_printers||0;}
|
||
const totalJobsEl=document.querySelector('[data-stat="total-jobs"]');if(totalJobsEl){totalJobsEl.textContent=stats.total_jobs||0;}
|
||
const successRateEl=document.querySelector('[data-stat="success-rate"]');if(successRateEl){successRateEl.textContent=(stats.success_rate||0)+'%';}
|
||
console.log('📊 Dashboard-Statistiken aktualisiert:',stats);}
|
||
function updateStatsCounter(elementId,value,animate=true){const element=document.getElementById(elementId);if(!element){console.warn(`Element mit ID'${elementId}'nicht gefunden`);return;}
|
||
if(value===null||value===undefined){console.warn(`Ungültiger Wert für Element'${elementId}':`,value);value=0;}
|
||
if(animate){const currentValue=parseInt(element.textContent.replace(/[^\d]/g,''))||0;const targetValue=parseInt(value.toString().replace(/[^\d]/g,''))||0;if(currentValue!==targetValue){const finalTextValue=value!==null&&value!==undefined?value.toString():'0';animateCounter(element,currentValue,targetValue,finalTextValue);}}else{element.textContent=value!==null&&value!==undefined?value.toString():'0';}}
|
||
function animateCounter(element,start,end,finalText){if(!element){console.warn('animateCounter: Kein gültiges Element übergeben');return;}
|
||
if(typeof finalText!=='string'){if(finalText===null||finalText===undefined||(typeof finalText==='object'&&finalText!==null)){console.warn('animateCounter: Problematischer finalText-Wert:',finalText);}
|
||
finalText=finalText!==null&&finalText!==undefined?String(finalText):'0';}
|
||
start=parseInt(start)||0;end=parseInt(end)||0;const duration=1000;const startTime=performance.now();function updateCounter(currentTime){const elapsed=currentTime-startTime;const progress=Math.min(elapsed/duration,1);const easeOut=1-Math.pow(1-progress,3);const currentValue=Math.round(start+(end-start)*easeOut);try{if(typeof finalText==='string'&&finalText.includes('%')){element.textContent=currentValue+'%';}else{element.textContent=currentValue;}}catch(error){console.warn('animateCounter: Fehler bei finalText.includes:',error,'finalText:',finalText);element.textContent=currentValue;}
|
||
if(progress<1){requestAnimationFrame(updateCounter);}else{try{element.textContent=finalText;}catch(error){console.warn('animateCounter: Fehler bei finaler Zuweisung:',error);element.textContent=String(end);}}}
|
||
requestAnimationFrame(updateCounter);}
|
||
function getCSRFToken(){const token=document.querySelector('meta[name="csrf-token"]');return token?token.getAttribute('content'):'';}
|
||
function showToast(message,type='info'){if(typeof optimizationManager!=='undefined'&&optimizationManager.showToast){optimizationManager.showToast(message,type);return;}
|
||
const emoji={success:'✅',error:'❌',warning:'⚠️',info:'ℹ️'};console.log(`${emoji[type]||'ℹ️'}${message}`);try{const toast=document.createElement('div');toast.className=`fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg transition-all duration-300 transform translate-x-full`;const colors={success:'bg-green-500 text-white',error:'bg-red-500 text-white',warning:'bg-yellow-500 text-black',info:'bg-blue-500 text-white'};toast.className+=`${colors[type]}`;toast.textContent=message;document.body.appendChild(toast);setTimeout(()=>{toast.classList.remove('translate-x-full');},100);setTimeout(()=>{toast.classList.add('translate-x-full');setTimeout(()=>{toast.remove();},300);},3000);}catch(error){console.warn('Toast-Erstellung fehlgeschlagen:',error);}}
|
||
window.universalRefresh=function(){const currentPath=window.location.pathname;if(currentPath.includes('/dashboard')){refreshDashboard();}else if(currentPath.includes('/jobs')){refreshJobs();}else if(currentPath.includes('/calendar')||currentPath.includes('/schichtplan')){refreshCalendar();}else if(currentPath.includes('/printers')||currentPath.includes('/drucker')){refreshPrinters();}else{window.location.reload();}};class AutoRefreshManager{constructor(){this.isEnabled=false;this.interval=null;this.intervalTime=30000;}
|
||
start(){if(this.isEnabled)return;this.isEnabled=true;this.interval=setInterval(()=>{if(!document.hidden){universalRefresh();}},this.intervalTime);console.log('🔄 Auto-Refresh aktiviert (alle 30 Sekunden)');}
|
||
stop(){if(!this.isEnabled)return;this.isEnabled=false;if(this.interval){clearInterval(this.interval);this.interval=null;}
|
||
console.log('⏸️ Auto-Refresh deaktiviert');}
|
||
toggle(){if(this.isEnabled){this.stop();}else{this.start();}}}
|
||
window.autoRefreshManager=new AutoRefreshManager();document.addEventListener('keydown',function(e){if(e.key==='F5'||(e.ctrlKey&&e.key==='r')){e.preventDefault();universalRefresh();}
|
||
if(e.ctrlKey&&e.shiftKey&&e.key==='R'){e.preventDefault();autoRefreshManager.toggle();showToast(autoRefreshManager.isEnabled?'🔄 Auto-Refresh aktiviert':'⏸️ Auto-Refresh deaktiviert','info');}});document.addEventListener('visibilitychange',function(){if(!document.hidden&&autoRefreshManager.isEnabled){setTimeout(universalRefresh,1000);}});console.log('🔄 Globale Refresh-Funktionen geladen'); |