Files
Pivot/templates/uitdelen.html
2026-10-14 13:34:37 +02:00

159 lines
7.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Uitlenen{% endblock %}
{% block page_title %}Toestel uitdelen{% endblock %}
{% block main_class %}medium{% endblock %}
{% block head %}
<script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script>
{% endblock %}
{% block extra_css %}
<style>
#reader { width: 100%; margin-top: 14px; border: 3px solid var(--primary-color); border-radius: var(--radius); overflow: hidden; display: none; background: #000; }
#reader video { width: 100% !important; height: auto !important; object-fit: cover !important; }
#scan-result-container { display: none; margin-top: 14px; padding: 14px; border: 2px dashed var(--primary-color); border-radius: var(--radius); background: var(--primary-light); }
#scannedText { font-size: 1.2em; color: var(--primary-color); word-break: break-all; }
.scan-actions { display: flex; gap: 8px; margin-top: 10px; }
.scan-actions button { flex: 1; }
</style>
{% endblock %}
{% block content %}
<div class="split">
<div class="card">
<h2 class="card-title">Toestelgegevens</h2>
<form method="POST" action="{{ url_for('devices.uitdelen_submit') }}" onsubmit="showLoader()">
<div class="field zoek-wrap">
<label for="internnummer">Internnummer</label>
<input type="text" id="internnummer" name="internnummer" required autocomplete="off"
placeholder="Zoek op naam of scan/typ internnummer..." role="combobox"
value="{{ request.args.get('internnummer', '') }}"
aria-autocomplete="list" aria-controls="leerlingSuggesties" aria-expanded="false">
<ul class="suggesties" id="leerlingSuggesties" role="listbox"></ul>
{% if request.args.get('naam') %}<p class="field-hint">👤 {{ request.args.get('naam') }}</p>{% endif %}
</div>
<div class="field zoek-wrap">
<label for="serienummer">Toestelnummer</label>
<input type="text" id="serienummer" name="serienummer" required autocomplete="off"
placeholder="Zoek of scan toestelnummer (of serienummer)..." role="combobox"
{{ 'autofocus' if request.args.get('internnummer') }}
aria-autocomplete="list" aria-controls="toestelSuggesties" aria-expanded="false">
<ul class="suggesties" id="toestelSuggesties" role="listbox"></ul>
</div>
<button class="btn-block btn-lg" type="submit" name="action" value="check">✅ Ingeven</button>
<button class="btn-block btn-warning" type="submit" name="action" value="no_check">Zonder nakijken</button>
</form>
</div>
<div class="card order-first-mobile text-center">
<h2 class="card-title">📷 Scanner</h2>
<button type="button" class="btn-block btn-secondary" id="btn-toggle-scan">📷 Open camera-scanner</button>
{# Zonder https geeft de browser geen live camera: dan een foto nemen met de camera-app en de code daaruit lezen #}
<label class="btn btn-block btn-secondary" id="btn-foto" style="display:none">
📷 Foto van de code nemen
<input type="file" id="foto-input" accept="image/*" capture="environment" hidden>
</label>
<p class="muted small" id="scan-hint" style="display:none;margin:8px 0 0"></p>
<div id="reader"></div>
<div id="scan-result-container">
<div class="muted small">Gescande waarde</div>
<strong id="scannedText">-</strong>
<div class="scan-actions">
<button type="button" class="btn-sm" onclick="copyToField('internnummer')">→ Internnr.</button>
<button type="button" class="btn-sm" onclick="copyToField('serienummer')">→ Toestelnr.</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{% set toestel_voorkeur = 'beschikbaar' %}{% include '_toestel_zoekveld.html' %}
<script>
let html5QrCode;
const scanBtn = document.getElementById('btn-toggle-scan');
const readerDiv = document.getElementById('reader');
const resultContainer = document.getElementById('scan-result-container');
const scannedTextElement = document.getElementById('scannedText');
scanBtn.addEventListener('click', () => {
if (!html5QrCode || !html5QrCode.isScanning) startScanner(); else stopScanner();
});
// Live camera kan enkel via https (of localhost). Anders: foto nemen en de code uit de foto lezen.
const fotoBtn = document.getElementById('btn-foto');
const fotoInput = document.getElementById('foto-input');
const scanHint = document.getElementById('scan-hint');
function fotoModus(reden) {
scanBtn.style.display = 'none';
fotoBtn.style.display = '';
scanHint.textContent = reden;
scanHint.style.display = '';
}
if (!window.isSecureContext || !(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) {
fotoModus('Neem een scherpe foto van de streepjes- of QR-code, van dichtbij en recht ervoor.');
}
fotoInput.addEventListener('change', () => {
const bestand = fotoInput.files && fotoInput.files[0];
if (!bestand) return;
scanHint.textContent = 'Code zoeken in de foto...';
scanHint.style.display = '';
const lezer = new Html5Qrcode("reader");
lezer.scanFile(bestand, false)
.then(tekst => {
scannedTextElement.textContent = tekst;
resultContainer.style.display = 'block';
scanHint.textContent = 'Code gevonden. Kies hieronder in welk veld ze moet komen.';
})
.catch(() => { scanHint.textContent = 'Geen code gevonden in de foto. Probeer opnieuw, van dichterbij en zonder schittering.'; })
.finally(() => { fotoInput.value = ''; lezer.clear(); });
});
function startScanner() {
readerDiv.style.display = 'block';
scanBtn.textContent = '❌ Stop scanner';
scanBtn.classList.replace('btn-secondary', 'btn-danger');
html5QrCode = new Html5Qrcode("reader");
const config = { fps: 20, qrbox: { width: 300, height: 150 }, aspectRatio: 1.777778 };
html5QrCode.start(
{ facingMode: "environment" },
config,
(decodedText) => {
scannedTextElement.textContent = decodedText;
resultContainer.style.display = 'block';
},
() => {}
).catch((err) => {
console.error(err);
readerDiv.style.display = 'none';
scanBtn.textContent = '📷 Open camera-scanner';
scanBtn.classList.replace('btn-danger', 'btn-secondary');
fotoModus('De live camera kon niet starten. Neem in de plaats een foto van de code.');
});
}
function stopScanner() {
if (html5QrCode) {
html5QrCode.stop().then(() => {
readerDiv.style.display = 'none';
scanBtn.textContent = '📷 Open camera-scanner';
scanBtn.classList.replace('btn-danger', 'btn-secondary');
}).catch(err => console.error(err));
}
}
function copyToField(fieldId) {
const input = document.getElementById(fieldId);
input.value = scannedTextElement.textContent;
input.style.backgroundColor = '#d1fae5';
setTimeout(() => input.style.backgroundColor = '', 500);
}
</script>
{% endblock %}