slight fixes
This commit is contained in:
@@ -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';
|
||||||
|
|||||||
Reference in New Issue
Block a user