Merge remote-tracking branch 'origin/main'
Release Inventarsystem / release-docker (push) Successful in 2m15s
Release Inventarsystem / release-docker (push) Successful in 2m15s
This commit is contained in:
+17
-16
@@ -2177,7 +2177,7 @@ def _upload_student_cards_excel():
|
|||||||
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
||||||
try:
|
try:
|
||||||
db = client[cfg.MONGODB_DB]
|
db = client[cfg.MONGODB_DB]
|
||||||
student_cards = db['student_cards']
|
student_cards = list(db['student_cards'].find())
|
||||||
existing_ids.update(
|
existing_ids.update(
|
||||||
str(card.get('AusweisId', '')).strip().upper()
|
str(card.get('AusweisId', '')).strip().upper()
|
||||||
for card in student_cards.find({}, {'AusweisId': 1})
|
for card in student_cards.find({}, {'AusweisId': 1})
|
||||||
@@ -4108,28 +4108,20 @@ def student_cards_admin():
|
|||||||
app.logger.error(f"Error adding student card: {e}")
|
app.logger.error(f"Error adding student card: {e}")
|
||||||
flash('Fehler beim Hinzufügen des Ausweises.', 'error')
|
flash('Fehler beim Hinzufügen des Ausweises.', 'error')
|
||||||
|
|
||||||
# Get all student cards
|
# Get all student cards and decrypt them
|
||||||
all_cards = list(student_cards.find().sort('AusweisId', 1))
|
all_cards = list(student_cards.find().sort('AusweisId', 1))
|
||||||
all_cards = [_decrypt_student_card_doc(card) for card in all_cards]
|
all_cards = [_decrypt_student_card_doc(card) for card in all_cards]
|
||||||
client.close()
|
client.close()
|
||||||
|
|
||||||
# Alle eindeutigen Klassen für das Dropdown ermitteln
|
raw_classes = set(card.get('Klasse', '').strip() for card in all_cards if card.get('Klasse'))
|
||||||
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
available_classes = sorted(list(raw_classes))
|
||||||
db = client[cfg.MONGODB_DB]
|
|
||||||
student_cards_collection = db['student_cards']
|
|
||||||
|
|
||||||
# Extrahiere alle vorhandenen Klassen, entferne leere/None Werte und sortiere sie
|
|
||||||
raw_classes = student_cards_collection.distinct('Klasse')
|
|
||||||
available_classes = sorted([c for c in raw_classes if c])
|
|
||||||
|
|
||||||
client.close()
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'student_cards_admin.html',
|
'student_cards_admin.html',
|
||||||
student_cards=student_cards,
|
student_cards=all_cards, # Hier all_cards übergeben
|
||||||
edit_mode=edit_mode,
|
edit_mode=edit_mode,
|
||||||
form_data=form_data,
|
form_data=form_data,
|
||||||
available_classes=available_classes,
|
available_classes=available_classes, # Enthält nun die lesbaren Klassen
|
||||||
config=cfg.get_school_info()
|
config=cfg.get_school_info()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -4439,10 +4431,19 @@ def student_card_class_barcode_download():
|
|||||||
db = client[cfg.MONGODB_DB]
|
db = client[cfg.MONGODB_DB]
|
||||||
student_cards = db['student_cards']
|
student_cards = db['student_cards']
|
||||||
|
|
||||||
class_cards = list(student_cards.find({'Klasse': class_name}).sort('AusweisId', 1))
|
# 1. Alle Ausweise laden
|
||||||
class_cards = [_decrypt_student_card_doc(card) for card in class_cards]
|
all_cards = list(student_cards.find().sort('AusweisId', 1))
|
||||||
client.close()
|
client.close()
|
||||||
|
|
||||||
|
# 2. Alle entschlüsseln
|
||||||
|
decrypted_cards = [_decrypt_student_card_doc(card) for card in all_cards]
|
||||||
|
|
||||||
|
# 3. Im Speicher nach der Klartext-Klasse filtern
|
||||||
|
class_cards = [
|
||||||
|
card for card in decrypted_cards
|
||||||
|
if card.get('Klasse', '').strip() == class_name
|
||||||
|
]
|
||||||
|
|
||||||
if not class_cards:
|
if not class_cards:
|
||||||
flash(f'Keine Ausweise für die Klasse "{class_name}" gefunden.', 'error')
|
flash(f'Keine Ausweise für die Klasse "{class_name}" gefunden.', 'error')
|
||||||
return redirect(url_for('student_cards_admin'))
|
return redirect(url_for('student_cards_admin'))
|
||||||
|
|||||||
@@ -805,71 +805,92 @@
|
|||||||
deleteLibraryItem(itemId);
|
deleteLibraryItem(itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
async function startScanner(callback = null) {
|
||||||
// 3. CORE SCANNER ROUTING ENGINE (QUAGGA2)
|
if (scannerRunning) {
|
||||||
// =========================================================================
|
console.warn("Scanner is already running. Stopping it first...");
|
||||||
function startScanner(targetCallback) {
|
await stopScanner();
|
||||||
const readerWrap = document.getElementById('scanReaderWrap');
|
}
|
||||||
|
|
||||||
|
activeScannerCallback = callback;
|
||||||
|
|
||||||
|
const scannerWrap = document.querySelector('.library-scan-reader-wrap');
|
||||||
const toggleBtn = document.getElementById('toggleScannerBtn');
|
const toggleBtn = document.getElementById('toggleScannerBtn');
|
||||||
|
|
||||||
activeScannerCallback = targetCallback;
|
// 1. CRITICAL FIX: Make the container visible BEFORE Quagga initializes
|
||||||
|
// Quagga cannot calculate video dimensions if display is 'none'
|
||||||
|
if (scannerWrap) {
|
||||||
|
scannerWrap.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
if (readerWrap) readerWrap.style.display = 'block';
|
setScanStatus('Starte Kamera...', 'warn');
|
||||||
setScanStatus('Initializing camera...', 'warn');
|
|
||||||
|
|
||||||
Quagga.init({
|
// 2. Initialize Quagga with a slight delay to allow the DOM to render the block
|
||||||
inputStream: {
|
setTimeout(() => {
|
||||||
name: "Live",
|
Quagga.init({
|
||||||
type: "LiveStream",
|
inputStream: {
|
||||||
target: document.querySelector('#library-scanner-container'),
|
name: "Live",
|
||||||
constraints: {
|
type: "LiveStream",
|
||||||
width: 640,
|
// This MUST match the inner div where the video should appear
|
||||||
height: 480,
|
target: document.querySelector('.library-scan-reader'),
|
||||||
facingMode: "environment"
|
constraints: {
|
||||||
|
width: 640,
|
||||||
|
height: 480,
|
||||||
|
facingMode: "environment" // Prefer back camera on mobile
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
locator: {
|
||||||
decoder: {
|
patchSize: "medium",
|
||||||
readers: [
|
halfSample: true
|
||||||
"code_128_reader",
|
},
|
||||||
"ean_reader",
|
decoder: {
|
||||||
"code_39_reader",
|
// Keep only the barcode types you actually use to improve performance
|
||||||
"upc_reader",
|
readers: ["code_128_reader", "ean_reader", "code_39_reader"]
|
||||||
"codabar_reader",
|
},
|
||||||
"i2of5_reader"
|
locate: true
|
||||||
]
|
}, function(err) {
|
||||||
}
|
if (err) {
|
||||||
}, function(err) {
|
// This will finally log the actual error (e.g., NotAllowedError) if permissions fail
|
||||||
if (err) {
|
console.error("Quagga initialization failed:", err);
|
||||||
console.error('Scanner start failed:', err);
|
setScanStatus('Kamera-Fehler: ' + (err.name || err), 'error');
|
||||||
if (readerWrap) readerWrap.style.display = 'none';
|
|
||||||
const detail = (err && (err.message || err.name)) ? ` (${err.message || err.name})` : '';
|
|
||||||
setScanStatus(`Scanner konnte nicht gestartet werden${detail}`, 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Quagga.start();
|
if (scannerWrap) scannerWrap.style.display = 'none';
|
||||||
scannerRunning = true;
|
scannerRunning = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!targetCallback && toggleBtn) {
|
Quagga.start();
|
||||||
toggleBtn.textContent = 'Scanner stoppen';
|
scannerRunning = true;
|
||||||
}
|
setScanStatus('Scanner bereit.', 'ok');
|
||||||
setScanStatus('Scanner aktiv. Jetzt Code scannen.', 'warn');
|
|
||||||
});
|
if (toggleBtn) {
|
||||||
|
toggleBtn.textContent = 'Scanner stoppen';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopScanner() {
|
async function stopScanner() {
|
||||||
if (!scannerRunning) return;
|
if (!scannerRunning) return;
|
||||||
|
|
||||||
const readerWrap = document.getElementById('scanReaderWrap');
|
try {
|
||||||
const toggleBtn = document.getElementById('toggleScannerBtn');
|
Quagga.stop();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Error stopping Quagga (it may not have been running):", e);
|
||||||
|
}
|
||||||
|
|
||||||
Quagga.stop();
|
|
||||||
scannerRunning = false;
|
scannerRunning = false;
|
||||||
activeScannerCallback = null;
|
activeScannerCallback = null;
|
||||||
|
|
||||||
if (readerWrap) readerWrap.style.display = 'none';
|
// Hide the container to free up UI space
|
||||||
if (toggleBtn) toggleBtn.textContent = 'Scanner starten';
|
const scannerWrap = document.querySelector('.library-scan-reader-wrap');
|
||||||
setScanStatus('Scanner gestoppt.', 'warn');
|
if (scannerWrap) {
|
||||||
|
scannerWrap.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleBtn = document.getElementById('toggleScannerBtn');
|
||||||
|
if (toggleBtn) {
|
||||||
|
toggleBtn.textContent = 'Kamera Scanner'; // Reset button text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isStudentCardBarcode(code) {
|
async function isStudentCardBarcode(code) {
|
||||||
|
|||||||
Reference in New Issue
Block a user