67 lines
16 KiB
JavaScript
67 lines
16 KiB
JavaScript
(function(){'use strict';class JobManager{constructor(){this.jobs=[];this.currentPage=1;this.totalPages=1;this.isLoading=false;this.refreshInterval=null;this.autoRefreshEnabled=false;console.log('🔧 JobManager wird initialisiert...');}
|
|
async init(){try{console.log('🚀 JobManager-Initialisierung gestartet');this.setupEventListeners();this.setupFormHandlers();await this.loadJobs();if(this.autoRefreshEnabled){this.startAutoRefresh();}
|
|
console.log('✅ JobManager erfolgreich initialisiert');}catch(error){console.error('❌ Fehler bei JobManager-Initialisierung:',error);this.showToast('Fehler beim Initialisieren des Job-Managers','error');}}
|
|
setupEventListeners(){console.log('📡 Event-Listener werden eingerichtet...');document.addEventListener('click',(e)=>{const target=e.target.closest('[data-job-action]');if(!target)return;const action=target.getAttribute('data-job-action');const jobId=target.getAttribute('data-job-id');if(!jobId){console.warn('⚠️ Job-ID fehlt für Aktion:',action);return;}
|
|
switch(action){case'start':this.startJob(jobId);break;case'pause':this.pauseJob(jobId);break;case'resume':this.resumeJob(jobId);break;case'stop':this.stopJob(jobId);break;case'delete':this.deleteJob(jobId);break;case'details':this.openJobDetails(jobId);break;default:console.warn('⚠️ Unbekannte Job-Aktion:',action);}});const refreshBtn=document.getElementById('refresh-jobs');if(refreshBtn){refreshBtn.addEventListener('click',()=>this.loadJobs());}
|
|
const autoRefreshToggle=document.getElementById('auto-refresh-toggle');if(autoRefreshToggle){autoRefreshToggle.addEventListener('change',(e)=>{this.autoRefreshEnabled=e.target.checked;if(this.autoRefreshEnabled){this.startAutoRefresh();}else{this.stopAutoRefresh();}});}
|
|
console.log('✅ Event-Listener erfolgreich eingerichtet');}
|
|
setupFormHandlers(){console.log('📝 Formular-Handler werden eingerichtet...');const newJobForm=document.getElementById('new-job-form');if(newJobForm){newJobForm.addEventListener('submit',async(e)=>{e.preventDefault();await this.createNewJob(new FormData(newJobForm));});}
|
|
const editJobForm=document.getElementById('edit-job-form');if(editJobForm){editJobForm.addEventListener('submit',async(e)=>{e.preventDefault();const jobId=editJobForm.getAttribute('data-job-id');await this.updateJob(jobId,new FormData(editJobForm));});}
|
|
console.log('✅ Formular-Handler erfolgreich eingerichtet');}
|
|
async loadJobs(page=1){if(this.isLoading){console.log('⚠️ Jobs werden bereits geladen...');return;}
|
|
this.isLoading=true;this.showLoadingState(true);try{console.log(`📥 Lade Jobs(Seite ${page})...`);const response=await fetch(`/api/jobs?page=${page}`,{headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
const data=await response.json();if(data&&typeof data==='object'){this.jobs=Array.isArray(data.jobs)?data.jobs:[];this.currentPage=Number(data.current_page)||1;this.totalPages=Number(data.total_pages)||1;console.log(`✅ ${this.jobs.length}Jobs erfolgreich geladen`,this.jobs);}else{console.warn('⚠️ Unerwartete API-Response-Struktur:',data);this.jobs=[];this.currentPage=1;this.totalPages=1;}
|
|
this.renderJobs();this.updatePagination();console.log(`✅ ${this.jobs.length}Jobs erfolgreich geladen und gerendert`);}catch(error){console.error('❌ Fehler beim Laden der Jobs:',error);this.showToast('Fehler beim Laden der Jobs','error');this.jobs=[];this.currentPage=1;this.totalPages=1;this.renderJobs();}finally{this.isLoading=false;this.showLoadingState(false);}}
|
|
async startJob(jobId){try{console.log(`▶️ Starte Job ${jobId}...`);const response=await fetch(`/api/jobs/${jobId}/start`,{method:'POST',headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
this.showToast('Job erfolgreich gestartet','success');await this.loadJobs();}catch(error){console.error('❌ Fehler beim Starten des Jobs:',error);this.showToast('Fehler beim Starten des Jobs','error');}}
|
|
async pauseJob(jobId){try{console.log(`⏸️ Pausiere Job ${jobId}...`);const response=await fetch(`/api/jobs/${jobId}/pause`,{method:'POST',headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
this.showToast('Job erfolgreich pausiert','success');await this.loadJobs();}catch(error){console.error('❌ Fehler beim Pausieren des Jobs:',error);this.showToast('Fehler beim Pausieren des Jobs','error');}}
|
|
async resumeJob(jobId){try{console.log(`▶️ Setze Job ${jobId}fort...`);const response=await fetch(`/api/jobs/${jobId}/resume`,{method:'POST',headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
this.showToast('Job erfolgreich fortgesetzt','success');await this.loadJobs();}catch(error){console.error('❌ Fehler beim Fortsetzen des Jobs:',error);this.showToast('Fehler beim Fortsetzen des Jobs','error');}}
|
|
async stopJob(jobId){if(!confirm('Möchten Sie diesen Job wirklich stoppen?')){return;}
|
|
try{console.log(`⏹️ Stoppe Job ${jobId}...`);const response=await fetch(`/api/jobs/${jobId}/stop`,{method:'POST',headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
this.showToast('Job erfolgreich gestoppt','success');await this.loadJobs();}catch(error){console.error('❌ Fehler beim Stoppen des Jobs:',error);this.showToast('Fehler beim Stoppen des Jobs','error');}}
|
|
async deleteJob(jobId){if(!confirm('Möchten Sie diesen Job wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.')){return;}
|
|
try{console.log(`🗑️ Lösche Job ${jobId}...`);const response=await fetch(`/api/jobs/${jobId}`,{method:'DELETE',headers:{'X-CSRFToken':this.getCSRFToken(),'Content-Type':'application/json'}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
this.showToast('Job erfolgreich gelöscht','success');await this.loadJobs();}catch(error){console.error('❌ Fehler beim Löschen des Jobs:',error);this.showToast('Fehler beim Löschen des Jobs','error');}}
|
|
openJobDetails(jobId){console.log(`📄 Öffne Details für Job ${jobId}...`);const detailsUrl=`/jobs/${jobId}`;const detailsModal=document.getElementById(`job-details-${jobId}`);if(detailsModal&&typeof window.MYP!=='undefined'&&window.MYP.UI&&window.MYP.UI.modal){window.MYP.UI.modal.open(`job-details-${jobId}`);}else{window.location.href=detailsUrl;}}
|
|
renderJobs(){const jobsList=document.getElementById('jobs-list');if(!jobsList){console.warn('⚠️ Jobs-Liste Element nicht gefunden');return;}
|
|
if(!Array.isArray(this.jobs)){console.warn('⚠️ this.jobs ist kein Array:',this.jobs);this.jobs=[];}
|
|
if(this.jobs.length===0){jobsList.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>`;return;}
|
|
try{const jobsHTML=this.jobs.map(job=>{if(!job||typeof job!=='object'){console.warn('⚠️ Ungültiges Job-Objekt:',job);return'';}
|
|
return this.renderJobCard(job);}).filter(html=>html!=='').join('');jobsList.innerHTML=jobsHTML;console.log(`📋 ${this.jobs.length}Jobs gerendert`);}catch(error){console.error('❌ Fehler beim Rendern der Jobs:',error);jobsList.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">Es gab einen Fehler beim Darstellen der Jobs.</p><button onclick="window.jobManager.loadJobs()"class="mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Erneut versuchen</button></div>`;}}
|
|
renderJobCard(job){const statusClass=this.getJobStatusClass(job.status);const statusText=this.getJobStatusText(job.status);return`<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"><div class="flex items-start justify-between"><div class="flex-1"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">${job.name||'Unbenannter Job'}</h3><div class="flex items-center space-x-4 text-sm text-gray-500 dark:text-gray-400 mb-4"><span>ID:${job.id}</span><span>•</span><span>Drucker:${job.printer_name||'Unbekannt'}</span><span>•</span><span>Erstellt:${new Date(job.created_at).toLocaleDateString('de-DE')}</span></div><div class="flex items-center space-x-2 mb-4"><span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${statusClass}">${statusText}</span>${job.progress?`<span class="text-sm text-gray-500 dark:text-gray-400">${job.progress}%</span>`:''}</div></div><div class="flex flex-col space-y-2 ml-4">${this.renderJobActions(job)}</div></div></div>`;}
|
|
renderJobActions(job){const actions=[];actions.push(`<button data-job-action="details"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-gray-300 dark:border-gray-600 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">Details</button>`);switch(job.status){case'pending':case'ready':actions.push(`<button data-job-action="start"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">Starten</button>`);break;case'running':case'printing':actions.push(`<button data-job-action="pause"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-yellow-600 hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500">Pausieren</button>`);actions.push(`<button data-job-action="stop"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">Stoppen</button>`);break;case'paused':actions.push(`<button data-job-action="resume"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">Fortsetzen</button>`);actions.push(`<button data-job-action="stop"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">Stoppen</button>`);break;case'completed':case'failed':case'cancelled':actions.push(`<button data-job-action="delete"data-job-id="${job.id}"
|
|
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">Löschen</button>`);break;}
|
|
return actions.join('');}
|
|
getJobStatusClass(status){const statusClasses={'pending':'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300','ready':'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300','running':'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300','printing':'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300','paused':'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300','completed':'bg-emerald-100 text-emerald-800 dark:bg-emerald-900 dark:text-emerald-300','failed':'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300','cancelled':'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'};return statusClasses[status]||statusClasses['pending'];}
|
|
getJobStatusText(status){const statusTexts={'pending':'Wartend','ready':'Bereit','running':'Läuft','printing':'Druckt','paused':'Pausiert','completed':'Abgeschlossen','failed':'Fehlgeschlagen','cancelled':'Abgebrochen'};return statusTexts[status]||'Unbekannt';}
|
|
showLoadingState(show){const loadingEl=document.getElementById('jobs-loading');const jobsList=document.getElementById('jobs-list');if(loadingEl){loadingEl.style.display=show?'block':'none';}
|
|
if(jobsList){jobsList.style.opacity=show?'0.5':'1';jobsList.style.pointerEvents=show?'none':'auto';}}
|
|
getCSRFToken(){const token=document.querySelector('meta[name="csrf-token"]');return token?token.getAttribute('content'):'';}
|
|
showToast(message,type='info'){if(typeof window.showToast==='function'){window.showToast(message,type);}else{console.log(`${type.toUpperCase()}:${message}`);}}
|
|
startAutoRefresh(){this.stopAutoRefresh();this.refreshInterval=setInterval(()=>{if(!this.isLoading){this.loadJobs(this.currentPage);}},30000);console.log('🔄 Auto-Refresh gestartet (30s Intervall)');}
|
|
stopAutoRefresh(){if(this.refreshInterval){clearInterval(this.refreshInterval);this.refreshInterval=null;console.log('⏹️ Auto-Refresh gestoppt');}}
|
|
updatePagination(){const paginationEl=document.getElementById('jobs-pagination');if(!paginationEl)return;if(this.totalPages<=1){paginationEl.style.display='none';return;}
|
|
paginationEl.style.display='flex';let paginationHTML='';if(this.currentPage>1){paginationHTML+=`<button onclick="jobManager.loadJobs(${this.currentPage - 1})"
|
|
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:bg-gray-700">Zurück</button>`;}
|
|
for(let i=1;i<=this.totalPages;i++){const isActive=i===this.currentPage;paginationHTML+=`<button onclick="jobManager.loadJobs(${i})"
|
|
class="px-3 py-2 text-sm font-medium ${isActive
|
|
? 'text-blue-600 bg-blue-50 border-blue-300 dark:bg-blue-900 dark:text-blue-300'
|
|
: 'text-gray-500 bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:bg-gray-700'
|
|
} border">${i}</button>`;}
|
|
if(this.currentPage<this.totalPages){paginationHTML+=`<button onclick="jobManager.loadJobs(${this.currentPage + 1})"
|
|
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:bg-gray-700">Weiter</button>`;}
|
|
paginationEl.innerHTML=paginationHTML;}
|
|
async createNewJob(formData){try{console.log('📝 Erstelle neuen Job...');const response=await fetch('/api/jobs',{method:'POST',headers:{'X-CSRFToken':this.getCSRFToken()},body:formData});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
const result=await response.json();this.showToast('Job erfolgreich erstellt','success');await this.loadJobs();const form=document.getElementById('new-job-form');if(form){form.reset();}
|
|
return result;}catch(error){console.error('❌ Fehler beim Erstellen des Jobs:',error);this.showToast('Fehler beim Erstellen des Jobs','error');throw error;}}
|
|
async updateJob(jobId,formData){try{console.log(`📝 Aktualisiere Job ${jobId}...`);const response=await fetch(`/api/jobs/${jobId}`,{method:'PUT',headers:{'X-CSRFToken':this.getCSRFToken()},body:formData});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);}
|
|
const result=await response.json();this.showToast('Job erfolgreich aktualisiert','success');await this.loadJobs();return result;}catch(error){console.error('❌ Fehler beim Aktualisieren des Jobs:',error);this.showToast('Fehler beim Aktualisieren des Jobs','error');throw error;}}}
|
|
window.JobManager=JobManager;document.addEventListener('DOMContentLoaded',function(){if(typeof window.jobManager==='undefined'){window.jobManager=new JobManager();if(document.getElementById('jobs-list')||document.querySelector('[data-job-action]')){window.jobManager.init();}}});console.log('✅ JobManager-Modul geladen');})(); |