diff --git a/Web/templates/library_table.html b/Web/templates/library_table.html index 2a0a261..e6c05ad 100644 --- a/Web/templates/library_table.html +++ b/Web/templates/library_table.html @@ -637,7 +637,7 @@ ×
Scanner ist bereit. Bitte den angezeigten Code scannen.
- +Warte auf Scan...
@@ -873,7 +873,7 @@ let keyboardScanBuffer = ''; let keyboardLastKeyAt = 0; let physicalScannerModalOpen = false; - const KEYBOARD_SCAN_INTERCHAR_MS = 100; // max time between keystrokes to consider them one scan + const KEYBOARD_SCAN_INTERCHAR_MS = 500; // max time between slower scanner keystrokes const physicalScanQueue = []; let keyboardScanProcessing = false; let editLibraryState = { @@ -1249,7 +1249,7 @@ modal.style.display = 'flex'; updatePhysicalScannerModal('Warte auf Scan...', 'warn'); document.addEventListener('keydown', keyboardScanKeydownHandler); - document.getElementById('closePhysicalScannerBtn')?.focus(); + document.getElementById('physicalScannerCode')?.focus(); } function closePhysicalScannerModal() { @@ -1287,13 +1287,13 @@ // Scanner keystrokes must not be submitted into the focused form field. const displayCode = document.getElementById('physicalScannerCode'); if (displayCode) displayCode.textContent = code; - updatePhysicalScannerModal('Code empfangen. Verarbeitung läuft...', 'warn'); + updatePhysicalScannerModal('Enter erkannt. Code wird verarbeitet...', 'warn'); processPhysicalScan(code); return; } - // Physical scanners in this workflow emit numeric codes only. - if (e.key.length === 1 && /\d/.test(e.key)) { + // Accept all printable scanner characters, including letters and punctuation. + if (e.key.length === 1) { // If time gap too big, start new buffer if (keyboardLastKeyAt && (now - keyboardLastKeyAt) > KEYBOARD_SCAN_INTERCHAR_MS) { keyboardScanBuffer = ''; @@ -1316,7 +1316,8 @@ while (physicalScanQueue.length > 0) { await handleScanSuccess(physicalScanQueue.shift()); if (physicalScannerModalOpen) { - updatePhysicalScannerModal('Aktion abgeschlossen. Bereit für den nächsten Scan.', 'ok'); + const displayCode = document.getElementById('physicalScannerCode'); + if (displayCode) displayCode.textContent = ''; } } } finally { @@ -1349,6 +1350,7 @@ setActiveStudentCard(scannedCode); setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}. Bitte den nächsten Ausweis scannen.`, 'ok'); showSmallConfirm(`Ausweis erkannt: ${activeStudentCardId}. Sie können den nächsten scannen.`, 'ok'); + updatePhysicalScannerModal(`Ausweis erkannt. Bereit für den nächsten Scan.`, 'ok'); return; } @@ -1374,6 +1376,7 @@ setActiveStudentCard(scannedCode); setScanStatus(`Neuer Ausweis gesetzt: ${activeStudentCardId}. Bitte Medien scannen.`, 'ok'); showSmallConfirm(`Benutzer gewechselt zu: ${activeStudentCardId}`, 'ok'); + updatePhysicalScannerModal('Ausweis erkannt. Jetzt Mediencodes scannen.', 'ok'); setTimeout(() => { if (document.getElementById('scanModeSelect').value === 'continuous') { @@ -1386,6 +1389,7 @@ if (!activeStudentCardId) { setScanStatus('Kein Ausweis aktiv! Bitte zuerst einen Schülerausweis scannen.', 'error'); showSmallConfirm('Bitte zuerst Ausweis scannen', 'error'); + updatePhysicalScannerModal('Kein Ausweis aktiv. Bitte zuerst den Ausweis scannen.', 'error'); setTimeout(() => { if (document.getElementById('scanModeSelect').value === 'continuous') { @@ -1414,15 +1418,19 @@ if (!response.ok || !result.ok) { setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); showSmallConfirm(result.message || 'Aktion fehlgeschlagen.', 'error'); + updatePhysicalScannerModal(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); } else if (result.action === 'borrowed') { setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok'); showSmallConfirm(`Ausgeliehen: ${result.item_name}`, 'ok'); + updatePhysicalScannerModal('Ausleihe erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } else if (result.action === 'returned') { setScanStatus(`Zurückgegeben: ${result.item_name}`, 'ok'); showSmallConfirm(`Zurückgegeben: ${result.item_name}`, 'ok'); + updatePhysicalScannerModal('Rückgabe erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } else { setScanStatus(result.message || 'Aktion durchgeführt.', 'ok'); showSmallConfirm(result.message || 'Erfolgreich', 'ok'); + updatePhysicalScannerModal('Aktion erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } // Tabellen-Ansicht aktualisieren @@ -1433,6 +1441,7 @@ console.error('Continuous scan action failed:', err); setScanStatus('Fehler beim Verarbeiten des Scans.', 'error'); showSmallConfirm('Fehler im Netzwerk/System', 'error'); + updatePhysicalScannerModal('Fehler beim Verarbeiten. Bitte erneut scannen.', 'error'); } setTimeout(() => { @@ -1449,6 +1458,7 @@ setActiveStudentCard(scannedCode); setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}. Bitte den nächsten Mediencode scannen.`, 'ok'); showSmallConfirm(`Ausweis erkannt: ${activeStudentCardId}. Bitte jetzt den nächsten Mediencode scannen.`, 'ok'); + updatePhysicalScannerModal('Ausweis erkannt. Jetzt den Mediencode scannen.', 'ok'); return; } @@ -1457,7 +1467,11 @@ setScanStatus('Verarbeite Mediencode...', 'warn'); const response = await fetch('/api/library_scan_action', { method: 'POST', - headers: {'Content-Type': 'application/json'}, + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token }}', + 'X-CSRF-Token': '{{ csrf_token }}' + }, body: JSON.stringify({ student_card_id: activeStudentCardId, item_code: scannedCode @@ -1467,24 +1481,29 @@ const result = await response.json(); if (!response.ok || !result.ok) { setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); + updatePhysicalScannerModal(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); return; } if (result.action === 'borrowed') { setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok'); showSmallConfirm(`Ausgeliehen: ${result.item_name}`, 'ok'); + updatePhysicalScannerModal('Ausleihe erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } else if (result.action === 'returned') { setScanStatus(`Zurückgegeben: ${result.item_name}`, 'ok'); showSmallConfirm(`Zurückgegeben: ${result.item_name}`, 'ok'); + updatePhysicalScannerModal('Rückgabe erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } else { setScanStatus(result.message || 'Aktion durchgeführt.', 'ok'); showSmallConfirm(result.message || 'Aktion durchgeführt.', 'ok'); + updatePhysicalScannerModal('Aktion erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); } await loadLibraryItems(); } catch (err) { console.error('Quick scan action failed:', err); setScanStatus('Fehler beim Verarbeiten des Scans.', 'error'); + updatePhysicalScannerModal('Fehler beim Verarbeiten. Bitte erneut scannen.', 'error'); } } @@ -1501,16 +1520,19 @@ if (!resp.ok || !result.ok) { setScanStatus(result.message || 'Rückgabe fehlgeschlagen.', 'error'); showSmallConfirm(result.message || 'Rückgabe fehlgeschlagen.', 'error'); + updatePhysicalScannerModal(result.message || 'Rückgabe fehlgeschlagen.', 'error'); return false; } setScanStatus(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); showSmallConfirm(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); + updatePhysicalScannerModal('Rückgabe erfolgreich. Bereit für den nächsten Mediencode.', 'ok'); await loadLibraryItems(); return true; } catch (err) { console.error('Return by code failed:', err); setScanStatus('Fehler bei Rückgabe.', 'error'); showSmallConfirm('Fehler bei Rückgabe.', 'error'); + updatePhysicalScannerModal('Fehler bei Rückgabe. Bitte erneut scannen.', 'error'); return false; } }