Release 1.1.0: QR-Reportimport, Regal-Auswahlmodal, Einlagern/Auslagern-Verknuepfungen aus Reifenlager, Stabilitaetsfixes
This commit is contained in:
1 parent
cba9414e92
commit
3404fb9875
25 files changed
+5106
-744
No files matched your search
@@ -0,0 +1,88 @@
|
||||
// QR code scanner interop (html5-qrcode) for Blazor.
|
||||
// Usage from .NET: qrScanner.start(elementId, dotNetRef) / qrScanner.stop()
|
||||
window.qrScanner = (function () {
|
||||
let scanner = null;
|
||||
let lastText = null;
|
||||
let lastTime = 0;
|
||||
|
||||
async function ensureLib() {
|
||||
if (window.Html5Qrcode) return;
|
||||
await new Promise((resolve, reject) => {
|
||||
const s = document.createElement('script');
|
||||
s.src = 'lib/html5-qrcode/html5-qrcode.min.js';
|
||||
s.onload = resolve;
|
||||
s.onerror = () => reject(new Error('QR-Bibliothek konnte nicht geladen werden.'));
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
}
|
||||
|
||||
async function start(elementId, dotNetRef) {
|
||||
await stop();
|
||||
await ensureLib();
|
||||
|
||||
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||
throw new Error('Kamera wird von diesem Browser nicht unterstützt (HTTPS erforderlich).');
|
||||
}
|
||||
|
||||
scanner = new Html5Qrcode(elementId, {
|
||||
formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
|
||||
verbose: false
|
||||
});
|
||||
|
||||
const config = {
|
||||
fps: 10,
|
||||
qrbox: (w, h) => {
|
||||
const size = Math.max(180, Math.min(w, h) * 0.7);
|
||||
return { width: size, height: size };
|
||||
},
|
||||
aspectRatio: 1.0
|
||||
};
|
||||
|
||||
const onSuccess = (text) => {
|
||||
const now = Date.now();
|
||||
if (text === lastText && now - lastTime < 2500) return;
|
||||
lastText = text;
|
||||
lastTime = now;
|
||||
dotNetRef.invokeMethodAsync('OnQrScanned', text);
|
||||
};
|
||||
|
||||
try {
|
||||
await scanner.start({ facingMode: 'environment' }, config, onSuccess, () => { });
|
||||
} catch (e) {
|
||||
// Fallback: any camera
|
||||
const cams = await Html5Qrcode.getCameras();
|
||||
if (!cams || cams.length === 0) throw new Error('Keine Kamera gefunden.');
|
||||
await scanner.start(cams[0].id, config, onSuccess, () => { });
|
||||
}
|
||||
}
|
||||
|
||||
async function stop() {
|
||||
if (!scanner) return;
|
||||
try {
|
||||
if (scanner.isScanning) await scanner.stop();
|
||||
scanner.clear();
|
||||
} catch (e) { /* ignore */ }
|
||||
scanner = null;
|
||||
lastText = null;
|
||||
}
|
||||
|
||||
// Short audio feedback ("success" | "error") via Web Audio, no asset required.
|
||||
function playSound(type) {
|
||||
try {
|
||||
const Ctx = window.AudioContext || window.webkitAudioContext;
|
||||
if (!Ctx) return;
|
||||
const ctx = new Ctx();
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.type = 'sine';
|
||||
osc.frequency.value = type === 'error' ? 220 : 880;
|
||||
gain.gain.value = 0.08;
|
||||
osc.connect(gain).connect(ctx.destination);
|
||||
osc.start();
|
||||
osc.stop(ctx.currentTime + (type === 'error' ? 0.25 : 0.12));
|
||||
osc.onended = () => ctx.close().catch(() => { });
|
||||
} catch (e) { /* audio is best-effort */ }
|
||||
}
|
||||
|
||||
return { start, stop, playSound };
|
||||
})();
|
||||
Reference in new issue
Block a user