{% extends "base.html" %} {% block title %}Druckaufträge - MYP API Tester{% endblock %} {% block content %} <div class="row"> <div class="col-md-12 mb-4"> <div class="card"> <div class="card-header d-flex justify-content-between align-items-center"> <h4 class="mb-0">Druckaufträge verwalten</h4> <button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#newJobForm"> Neuen Auftrag erstellen </button> </div> <div class="collapse" id="newJobForm"> <div class="card-body border-bottom"> <form class="api-form" data-url="/api/jobs" data-method="POST" data-response="createJobResponse" data-reload="true"> <div class="mb-3"> <label for="jobPrinterId" class="form-label">Drucker</label> <select class="form-control" id="jobPrinterId" name="printerId" required> <option value="">Drucker auswählen...</option> <!-- Wird dynamisch gefüllt --> </select> </div> <div class="mb-3"> <label for="jobDuration" class="form-label">Dauer (Minuten)</label> <input type="number" class="form-control" id="jobDuration" name="durationInMinutes" min="1" required> </div> <div class="mb-3"> <label for="jobComments" class="form-label">Kommentare</label> <textarea class="form-control" id="jobComments" name="comments" rows="3"></textarea> </div> <div class="mb-3 form-check"> <input type="checkbox" class="form-check-input" id="allowQueuedJobs" name="allowQueuedJobs" value="true"> <label class="form-check-label" for="allowQueuedJobs"> Auftrag in Warteschlange erlauben (wenn Drucker belegt ist) </label> </div> <button type="submit" class="btn btn-success">Auftrag erstellen</button> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="createJobResponse"></pre> </div> </div> </div> <div class="card-body"> <form class="api-form mb-3" data-url="/api/jobs" data-method="GET" data-response="jobsResponse"> <button type="submit" class="btn btn-primary">Aufträge aktualisieren</button> </form> <div class="table-responsive"> <table class="table table-striped table-hover"> <thead> <tr> <th>ID</th> <th>Drucker</th> <th>Benutzer</th> <th>Start</th> <th>Dauer (Min)</th> <th>Verbleibend (Min)</th> <th>Status</th> <th>Kommentare</th> <th>Aktionen</th> </tr> </thead> <tbody id="jobsTableBody"> <!-- Wird dynamisch gefüllt --> </tbody> </table> </div> <div> <h6>API-Antwort:</h6> <pre class="api-response" id="jobsResponse"></pre> </div> </div> </div> </div> </div> <!-- Job abbrechen Modal --> <div class="modal fade" id="abortJobModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Auftrag abbrechen</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Möchten Sie den Auftrag wirklich abbrechen?</p> <form id="abortJobForm" class="api-form" data-method="POST" data-response="abortJobResponse" data-reload="true"> <input type="hidden" id="abortJobId" name="jobId"> <div class="mb-3"> <label for="abortReason" class="form-label">Abbruchgrund</label> <textarea class="form-control" id="abortReason" name="reason" rows="3"></textarea> </div> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="abortJobResponse"></pre> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button> <button type="submit" form="abortJobForm" class="btn btn-danger">Auftrag abbrechen</button> </div> </div> </div> </div> <!-- Job beenden Modal --> <div class="modal fade" id="finishJobModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Auftrag beenden</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Möchten Sie den Auftrag als beendet markieren?</p> <form id="finishJobForm" class="api-form" data-method="POST" data-response="finishJobResponse" data-reload="true"> <input type="hidden" id="finishJobId" name="jobId"> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="finishJobResponse"></pre> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button> <button type="submit" form="finishJobForm" class="btn btn-success">Auftrag beenden</button> </div> </div> </div> </div> <!-- Job verlängern Modal --> <div class="modal fade" id="extendJobModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Auftrag verlängern</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form id="extendJobForm" class="api-form" data-method="POST" data-response="extendJobResponse" data-reload="true"> <input type="hidden" id="extendJobId" name="jobId"> <div class="mb-3"> <label for="extendHours" class="form-label">Stunden</label> <input type="number" class="form-control" id="extendHours" name="hours" min="0" value="0"> </div> <div class="mb-3"> <label for="extendMinutes" class="form-label">Minuten</label> <input type="number" class="form-control" id="extendMinutes" name="minutes" min="0" max="59" value="30"> </div> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="extendJobResponse"></pre> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button> <button type="submit" form="extendJobForm" class="btn btn-primary">Auftrag verlängern</button> </div> </div> </div> </div> <!-- Job Kommentare bearbeiten Modal --> <div class="modal fade" id="editCommentsModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Kommentare bearbeiten</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form id="editCommentsForm" class="api-form" data-method="PUT" data-response="editCommentsResponse" data-reload="true"> <input type="hidden" id="editCommentsJobId" name="jobId"> <div class="mb-3"> <label for="editJobComments" class="form-label">Kommentare</label> <textarea class="form-control" id="editJobComments" name="comments" rows="3"></textarea> </div> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="editCommentsResponse"></pre> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button> <button type="submit" form="editCommentsForm" class="btn btn-primary">Speichern</button> </div> </div> </div> </div> <!-- Job freischalten Modal --> <div class="modal fade" id="approveJobModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Druckauftrag freischalten</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Möchten Sie diesen Druckauftrag jetzt freischalten und starten?</p> <p><strong>Hinweis:</strong> Der Drucker muss verfügbar sein, damit der Auftrag gestartet werden kann.</p> <form id="approveJobForm" class="api-form" data-method="POST" data-response="approveJobResponse" data-reload="true"> <input type="hidden" id="approveJobId" name="jobId"> </form> <div class="mt-3"> <h6>Antwort:</h6> <pre class="api-response" id="approveJobResponse"></pre> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button> <button type="submit" form="approveJobForm" class="btn btn-success">Freischalten</button> </div> </div> </div> </div> {% endblock %} {% block scripts %} <script> document.addEventListener('DOMContentLoaded', function() { // Drucker für Dropdown laden loadPrinters(); // Aufträge laden document.querySelector('form[data-url="/api/jobs"]').dispatchEvent(new Event('submit')); // Tabelle aktualisieren, wenn Aufträge geladen werden const jobsResponse = document.getElementById('jobsResponse'); const observer = new MutationObserver(function(mutations) { try { const jobs = JSON.parse(jobsResponse.textContent); updateJobsTable(jobs); } catch (e) { console.error('Fehler beim Parsen der Auftrags-Daten:', e); } }); observer.observe(jobsResponse, { childList: true, characterData: true, subtree: true }); // Abort-Modal vorbereiten document.getElementById('abortJobModal').addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const jobId = button.getAttribute('data-job-id'); document.getElementById('abortJobId').value = jobId; document.getElementById('abortJobForm').setAttribute('data-url', `/api/jobs/${jobId}/abort`); }); // Finish-Modal vorbereiten document.getElementById('finishJobModal').addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const jobId = button.getAttribute('data-job-id'); document.getElementById('finishJobId').value = jobId; document.getElementById('finishJobForm').setAttribute('data-url', `/api/jobs/${jobId}/finish`); }); // Extend-Modal vorbereiten document.getElementById('extendJobModal').addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const jobId = button.getAttribute('data-job-id'); document.getElementById('extendJobId').value = jobId; document.getElementById('extendJobForm').setAttribute('data-url', `/api/jobs/${jobId}/extend`); }); // Edit-Comments-Modal vorbereiten document.getElementById('editCommentsModal').addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const jobId = button.getAttribute('data-job-id'); const comments = button.getAttribute('data-job-comments'); document.getElementById('editCommentsJobId').value = jobId; document.getElementById('editCommentsForm').setAttribute('data-url', `/api/jobs/${jobId}/comments`); document.getElementById('editJobComments').value = comments || ''; }); // Approve-Modal vorbereiten document.getElementById('approveJobModal').addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const jobId = button.getAttribute('data-job-id'); document.getElementById('approveJobId').value = jobId; document.getElementById('approveJobForm').setAttribute('data-url', `/api/jobs/${jobId}/approve`); }); }); async function loadPrinters() { try { const response = await fetch('/api/printers'); const printers = await response.json(); const selectElement = document.getElementById('jobPrinterId'); selectElement.innerHTML = '<option value="">Drucker auswählen...</option>'; // Drucker anzeigen (alle, da man jetzt auch für belegte Drucker Jobs erstellen kann) printers.forEach(printer => { const option = document.createElement('option'); option.value = printer.id; // Status-Information zum Drucker hinzufügen const statusText = printer.status === 0 ? '(Verfügbar)' : '(Belegt)'; option.textContent = `${printer.name} - ${printer.description} ${statusText}`; // Belegte Drucker visuell unterscheiden if (printer.status !== 0) { option.classList.add('text-muted'); } selectElement.appendChild(option); }); // Hinweis auf die Checkbox für Warteschlange anzeigen oder verstecken const allowQueuedJobsCheckbox = document.getElementById('allowQueuedJobs'); const queueCheckboxContainer = allowQueuedJobsCheckbox.closest('.form-check'); // Prüfen, ob es belegte Drucker gibt const hasBusyPrinters = printers.some(printer => printer.status !== 0); queueCheckboxContainer.style.display = hasBusyPrinters ? 'block' : 'none'; // Event-Listener für die Druckerauswahl hinzufügen selectElement.addEventListener('change', function() { const selectedPrinterId = this.value; const selectedPrinter = printers.find(p => p.id === selectedPrinterId); if (selectedPrinter && selectedPrinter.status !== 0) { // Wenn ein belegter Drucker ausgewählt wird, Checkbox für Warteschlange anzeigen queueCheckboxContainer.style.display = 'block'; allowQueuedJobsCheckbox.checked = true; } else if (selectedPrinter && selectedPrinter.status === 0) { // Wenn ein verfügbarer Drucker ausgewählt wird, Checkbox für Warteschlange verstecken allowQueuedJobsCheckbox.checked = false; } }); } catch (e) { console.error('Fehler beim Laden der Drucker:', e); } } function updateJobsTable(jobs) { const tableBody = document.getElementById('jobsTableBody'); tableBody.innerHTML = ''; jobs.forEach(job => { const row = document.createElement('tr'); const startDate = new Date(job.startAt); const formattedStart = startDate.toLocaleString(); const isActive = !job.aborted && job.remainingMinutes > 0 && !job.waitingApproval; const isWaiting = !job.aborted && job.waitingApproval; let statusText = ''; let statusClass = ''; if (job.aborted) { statusText = 'Abgebrochen'; statusClass = 'text-danger'; } else if (job.waitingApproval) { statusText = 'Wartet auf Freischaltung'; statusClass = 'text-info'; } else if (job.remainingMinutes <= 0) { statusText = 'Abgeschlossen'; statusClass = 'text-success'; } else { statusText = 'Aktiv'; statusClass = 'text-warning'; } // Zeige die verbleibende Zeit an const remainingTime = job.waitingApproval ? '-' : job.remainingMinutes; row.innerHTML = ` <td>${job.id}</td> <td>${job.printerId}</td> <td>${job.userId}</td> <td>${formattedStart}</td> <td>${job.durationInMinutes}</td> <td>${remainingTime}</td> <td><span class="${statusClass}">${statusText}</span></td> <td>${job.comments || '-'}</td> <td> ${isActive ? ` <button type="button" class="btn btn-sm btn-danger mb-1" data-bs-toggle="modal" data-bs-target="#abortJobModal" data-job-id="${job.id}"> Abbrechen </button> <button type="button" class="btn btn-sm btn-success mb-1" data-bs-toggle="modal" data-bs-target="#finishJobModal" data-job-id="${job.id}"> Beenden </button> <button type="button" class="btn btn-sm btn-primary mb-1" data-bs-toggle="modal" data-bs-target="#extendJobModal" data-job-id="${job.id}"> Verlängern </button> ` : ''} ${isWaiting ? ` <button type="button" class="btn btn-sm btn-success mb-1" data-bs-toggle="modal" data-bs-target="#approveJobModal" data-job-id="${job.id}"> Freischalten </button> <button type="button" class="btn btn-sm btn-danger mb-1" data-bs-toggle="modal" data-bs-target="#abortJobModal" data-job-id="${job.id}"> Abbrechen </button> ` : ''} <button type="button" class="btn btn-sm btn-secondary mb-1" data-bs-toggle="modal" data-bs-target="#editCommentsModal" data-job-id="${job.id}" data-job-comments="${job.comments || ''}"> Kommentare </button> </td> `; tableBody.appendChild(row); }); } </script> {% endblock %}