slight fixes

This commit is contained in:
2026-06-07 00:03:21 +02:00
parent 1b38d1f0c8
commit 8e478aeba4
+47 -47
View File
@@ -849,28 +849,28 @@
document.getElementById('detailModal').style.display = 'none'; document.getElementById('detailModal').style.display = 'none';
} }
// Keep track of the scanner state globally/outer scope // Keep track of the scanner state globally/outer scope
let scannerRunning = false; let scannerRunning = false;
let lastScanValue = null; let lastScanValue = null;
let lastScanAt = 0; let lastScanAt = 0;
let activeStudentCardId = ''; // Managed globally by your system let activeStudentCardId = ''; // Managed globally by your system
function borrowItem(itemId) { function borrowItem(itemId) {
const selectedItem = (libraryItems || []).find(item => item._id === itemId); const selectedItem = (libraryItems || []).find(item => item._id === itemId);
if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') { if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') {
alert('Dieses Medium ist als defekt/zerstör markiert und kann nicht ausgeliehen werden.'); alert('Dieses Medium ist als defekt/zerstört markiert und kann nicht ausgeliehen werden.');
return; return;
} }
const defaultCardId = activeStudentCardId || ''; const defaultCardId = activeStudentCardId || '';
const cardId = (window.prompt('Bitte Schülerausweis-ID eingeben:', defaultCardId) || '').trim().toUpperCase(); const cardId = (window.prompt('Bitte Schülerausweis-ID eingeben:', defaultCardId) || '').trim().toUpperCase();
if (!cardId) { if (!cardId) {
alert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Schülerausweis-ID erforderlich.'); alert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Schülerausweis-ID erforderlich.');
return; return;
} }
setActiveStudentCard(cardId); setActiveStudentCard(cardId);
const durationInput = (window.prompt('Ausleihdauer in Tagen (optional):') || '').trim(); const durationInput = (window.prompt('Ausleihdauer in Tagen (optional):') || '').trim();
const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1); const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1);
const countPrompt = (window.prompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1') || '').trim(); const countPrompt = (window.prompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1') || '').trim();
@@ -882,29 +882,29 @@
alert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`); alert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`);
return; return;
} }
const form = document.createElement('form'); const form = document.createElement('form');
form.method = 'POST'; form.method = 'POST';
form.action = `/ausleihen/${itemId}`; form.action = `/ausleihen/${itemId}`;
const csrfField = document.createElement('input'); const csrfField = document.createElement('input');
csrfField.type = 'hidden'; csrfField.type = 'hidden';
csrfField.name = 'csrf_token'; csrfField.name = 'csrf_token';
csrfField.value = '{{ csrf_token }}'; csrfField.value = '{{ csrf_token }}';
form.appendChild(csrfField); form.appendChild(csrfField);
const cardField = document.createElement('input'); const cardField = document.createElement('input');
cardField.type = 'hidden'; cardField.type = 'hidden';
cardField.name = 'borrower_card_id'; cardField.name = 'borrower_card_id';
cardField.value = cardId; cardField.value = cardId;
form.appendChild(cardField); form.appendChild(cardField);
const returnTargetField = document.createElement('input'); const returnTargetField = document.createElement('input');
returnTargetField.type = 'hidden'; returnTargetField.type = 'hidden';
returnTargetField.name = 'return_to'; returnTargetField.name = 'return_to';
returnTargetField.value = 'library'; returnTargetField.value = 'library';
form.appendChild(returnTargetField); form.appendChild(returnTargetField);
if (durationInput) { if (durationInput) {
const durationField = document.createElement('input'); const durationField = document.createElement('input');
durationField.type = 'hidden'; durationField.type = 'hidden';
@@ -912,17 +912,17 @@
durationField.value = durationInput; durationField.value = durationInput;
form.appendChild(durationField); form.appendChild(durationField);
} }
const countField = document.createElement('input'); const countField = document.createElement('input');
countField.type = 'hidden'; countField.type = 'hidden';
countField.name = 'exemplare_count'; countField.name = 'exemplare_count';
countField.value = String(borrowCount || 1); countField.value = String(borrowCount || 1);
form.appendChild(countField); form.appendChild(countField);
document.body.appendChild(form); document.body.appendChild(form);
form.submit(); form.submit();
} }
function setScanStatus(message, kind = '') { function setScanStatus(message, kind = '') {
const el = document.getElementById('scanStatus'); const el = document.getElementById('scanStatus');
if (!el) return; if (!el) return;
@@ -932,7 +932,7 @@
el.classList.add(kind); el.classList.add(kind);
} }
} }
function setActiveStudentCard(cardId) { function setActiveStudentCard(cardId) {
activeStudentCardId = (cardId || '').trim().toUpperCase(); activeStudentCardId = (cardId || '').trim().toUpperCase();
const input = document.getElementById('activeStudentCard'); const input = document.getElementById('activeStudentCard');
@@ -940,18 +940,18 @@
input.value = activeStudentCardId; input.value = activeStudentCardId;
} }
} }
function normalizeScannedCode(code) { function normalizeScannedCode(code) {
return (code || '').trim(); return (code || '').trim();
} }
async function processQuickToggleScan(scannedCode) { async function processQuickToggleScan(scannedCode) {
if (!activeStudentCardId) { if (!activeStudentCardId) {
setActiveStudentCard(scannedCode); setActiveStudentCard(scannedCode);
setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok');
return; return;
} }
try { try {
setScanStatus('Verarbeite Mediencode...', 'warn'); setScanStatus('Verarbeite Mediencode...', 'warn');
const response = await fetch('/api/library_scan_action', { const response = await fetch('/api/library_scan_action', {
@@ -962,13 +962,13 @@
item_code: scannedCode item_code: scannedCode
}) })
}); });
const result = await response.json(); const result = await response.json();
if (!response.ok || !result.ok) { if (!response.ok || !result.ok) {
setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error');
return; return;
} }
if (result.action === 'borrowed') { if (result.action === 'borrowed') {
setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok'); setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok');
} else if (result.action === 'returned') { } else if (result.action === 'returned') {
@@ -976,72 +976,72 @@
} else { } else {
setScanStatus(result.message || 'Aktion durchgeführt.', 'ok'); setScanStatus(result.message || 'Aktion durchgeführt.', 'ok');
} }
await loadLibraryItems(); await loadLibraryItems();
} catch (err) { } catch (err) {
console.error('Quick scan action failed:', err); console.error('Quick scan action failed:', err);
setScanStatus('Fehler beim Verarbeiten des Scans.', 'error'); setScanStatus('Fehler beim Verarbeiten des Scans.', 'error');
} }
} }
function handleScanSuccess(decodedText) { function handleScanSuccess(decodedText) {
const scannedCode = normalizeScannedCode(decodedText); const scannedCode = normalizeScannedCode(decodedText);
if (!scannedCode) return; if (!scannedCode) return;
const now = Date.now(); const now = Date.now();
if (scannedCode === lastScanValue && (now - lastScanAt) < 1500) { if (scannedCode === lastScanValue && (now - lastScanAt) < 1500) {
return; return;
} }
lastScanValue = scannedCode; lastScanValue = scannedCode;
lastScanAt = now; lastScanAt = now;
const mode = (document.getElementById('scanModeSelect') || {}).value || 'card_only'; const mode = (document.getElementById('scanModeSelect') || {}).value || 'card_only';
if (mode === 'card_only') { if (mode === 'card_only') {
setActiveStudentCard(scannedCode); setActiveStudentCard(scannedCode);
setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok'); setScanStatus(`Ausweis gesetzt: ${activeStudentCardId}`, 'ok');
return; return;
} }
processQuickToggleScan(scannedCode); processQuickToggleScan(scannedCode);
} }
// Global Quagga reader hook // Global Quagga reader hook
Quagga.onDetected(function(data) { Quagga.onDetected(function(data) {
if (data && data.codeResult && data.codeResult.code) { if (data && data.codeResult && data.codeResult.code) {
handleScanSuccess(data.codeResult.code); handleScanSuccess(data.codeResult.code);
} }
}); });
async function startScanner() { async function startScanner() {
if (scannerRunning) return; if (scannerRunning) return;
const readerWrap = document.getElementById('scanReaderWrap'); const readerWrap = document.getElementById('scanReaderWrap');
const toggleBtn = document.getElementById('toggleScannerBtn'); const toggleBtn = document.getElementById('toggleScannerBtn');
if (readerWrap) readerWrap.style.display = 'block'; if (readerWrap) readerWrap.style.display = 'block';
setScanStatus('Initializing camera...', 'warn'); setScanStatus('Initializing camera...', 'warn');
Quagga.init({ Quagga.init({
inputStream: { inputStream: {
name: "Live", name: "Live",
type: "LiveStream", type: "LiveStream",
// Points to the interior viewport layout box // Corrected to target your relative viewport wrapper child element
target: document.querySelector('#libraryQrReader'), target: document.querySelector('#library-scanner-container'),
constraints: { constraints: {
width: 640, width: 640,
height: 480, height: 480,
facingMode: "environment" // Force rear mobile lenses facingMode: "environment" // Force rear camera lenses
}, },
}, },
decoder: { decoder: {
// Limited down precisely to standard library/ID configurations // Limited precisely down to your standard barcode layouts
readers: [ readers: [
"code_128_reader", "code_128_reader",
"ean_reader", "ean_reader",
"code_39_reader", "code_39_reader",
"upc_reader", "upc_reader",
"codabar_reader", "codabar_reader",
"i2of5_reader" // Matches original 'ITF' format mapping "i2of5_reader" // Replaces old ITF layout configuration mapping
] ]
} }
}, function(err) { }, function(err) {
@@ -1052,32 +1052,32 @@
setScanStatus(`Scanner konnte nicht gestartet werden${detail}`, 'error'); setScanStatus(`Scanner konnte nicht gestartet werden${detail}`, 'error');
return; return;
} }
Quagga.start(); Quagga.start();
scannerRunning = true; scannerRunning = true;
if (toggleBtn) toggleBtn.textContent = 'Scanner stoppen'; if (toggleBtn) toggleBtn.textContent = 'Scanner stoppen';
setScanStatus('Scanner aktiv. Jetzt Code scannen.', 'warn'); setScanStatus('Scanner aktiv. Jetzt Code scannen.', 'warn');
}); });
} }
async function stopScanner() { async function stopScanner() {
if (!scannerRunning) return; if (!scannerRunning) return;
const readerWrap = document.getElementById('scanReaderWrap'); const readerWrap = document.getElementById('scanReaderWrap');
const toggleBtn = document.getElementById('toggleScannerBtn'); const toggleBtn = document.getElementById('toggleScannerBtn');
Quagga.stop(); Quagga.stop();
scannerRunning = false; scannerRunning = false;
if (readerWrap) readerWrap.style.display = 'none'; if (readerWrap) readerWrap.style.display = 'none';
if (toggleBtn) toggleBtn.textContent = 'Scanner starten'; if (toggleBtn) toggleBtn.textContent = 'Scanner starten';
setScanStatus('Scanner gestoppt.', 'warn'); setScanStatus('Scanner gestoppt.', 'warn');
} }
function wireScannerUi() { function wireScannerUi() {
const toggleBtn = document.getElementById('toggleScannerBtn'); const toggleBtn = document.getElementById('toggleScannerBtn');
const resetBtn = document.getElementById('resetCardBtn'); const resetBtn = document.getElementById('resetCardBtn');
const modeSelect = document.getElementById('scanModeSelect'); const modeSelect = document.getElementById('scanModeSelect');
if (toggleBtn) { if (toggleBtn) {
toggleBtn.addEventListener('click', async () => { toggleBtn.addEventListener('click', async () => {
if (scannerRunning) { if (scannerRunning) {
@@ -1087,14 +1087,14 @@
} }
}); });
} }
if (resetBtn) { if (resetBtn) {
resetBtn.addEventListener('click', () => { resetBtn.addEventListener('click', () => {
setActiveStudentCard(''); setActiveStudentCard('');
setScanStatus('Ausweis zurückgesetzt. Bitte neu scannen.', 'warn'); setScanStatus('Ausweis zurückgesetzt. Bitte neu scannen.', 'warn');
}); });
} }
if (modeSelect) { if (modeSelect) {
modeSelect.addEventListener('change', () => { modeSelect.addEventListener('change', () => {
if (modeSelect.value === 'quick_toggle' && !activeStudentCardId) { if (modeSelect.value === 'quick_toggle' && !activeStudentCardId) {
@@ -1107,18 +1107,18 @@
}); });
} }
} }
function getLibraryItemById(itemId) { function getLibraryItemById(itemId) {
return libraryItems.find(i => String(i._id) === String(itemId)); return libraryItems.find(i => String(i._id) === String(itemId));
} }
function openEditLibraryItem(itemId) { function openEditLibraryItem(itemId) {
const item = getLibraryItemById(itemId); const item = getLibraryItemById(itemId);
if (!item) { if (!item) {
alert('Element nicht gefunden.'); alert('Element nicht gefunden.');
return; return;
} }
const modal = document.getElementById('editLibraryModal'); const modal = document.getElementById('editLibraryModal');
document.getElementById('editLibraryItemId').value = item._id || ''; document.getElementById('editLibraryItemId').value = item._id || '';
document.getElementById('editLibraryName').value = item.Name || ''; document.getElementById('editLibraryName').value = item.Name || '';
@@ -1130,7 +1130,7 @@
document.getElementById('editLibraryType').value = (item.ItemType || 'book'); document.getElementById('editLibraryType').value = (item.ItemType || 'book');
modal.style.display = 'flex'; modal.style.display = 'flex';
} }
function closeEditLibraryModal() { function closeEditLibraryModal() {
const modal = document.getElementById('editLibraryModal'); const modal = document.getElementById('editLibraryModal');
modal.style.display = 'none'; modal.style.display = 'none';