Browse Source

Ajout saisie manuelle coureur avec autocomplétion

master
scayac 3 months ago
parent
commit
955a936d2a
  1. 49
      main/templates/scan.html
  2. 1
      main/urls.py
  3. 22
      main/views.py

49
main/templates/scan.html

@ -10,6 +10,14 @@ @@ -10,6 +10,14 @@
</div>
<div class="card-body">
<div id="reader" style="width:100%; max-width:400px; margin:auto;"></div>
<div class="mt-4 position-relative" style="max-width:400px; margin:auto;">
<label id="manualCoureurLabel">Saisie manuelle :</label>
<div class="input-group align-items-center">
<input type="text" id="manualCoureurInput" class="form-control" placeholder="Nom ou dossard..." autocomplete="off" aria-label="Saisir un coureur" aria-describedby="manualCoureurLabel">
<!-- plus de bouton OK, déclenchement direct sur sélection -->
</div>
<div id="manualCoureurSuggestions" class="list-group position-absolute w-100" style="z-index:1000;"></div>
</div>
<div id="scanResult" class="mt-3"></div>
{% if error %}
<div class="alert alert-danger mt-3">{{ error }}</div>
@ -56,6 +64,47 @@ @@ -56,6 +64,47 @@
{% block extra_js %}
<script src="{% static 'html5-qrcode/html5-qrcode.min.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
let selectedCoureurId = null;
const input = document.getElementById('manualCoureurInput');
const suggestions = document.getElementById('manualCoureurSuggestions');
if (input) {
input.addEventListener('input', function() {
const val = this.value.trim();
selectedCoureurId = null;
suggestions.innerHTML = '';
if (val.length < 2) return;
fetch('/ajax/coureur_autocomplete/?q=' + encodeURIComponent(val))
.then(r => r.json())
.then(data => {
suggestions.innerHTML = '';
data.forEach(c => {
const item = document.createElement('a');
item.className = 'list-group-item list-group-item-action';
item.textContent = c.label;
item.style.cursor = 'pointer';
item.onclick = function() {
input.value = c.label;
selectedCoureurId = c.id;
suggestions.innerHTML = '';
onScanSuccess(selectedCoureurId, "");
setTimeout(() => { input.value = ''; }, 100);
};
suggestions.appendChild(item);
});
});
});
// Cacher suggestions si clic ailleurs
document.addEventListener('click', function(e) {
if (!input.contains(e.target) && !suggestions.contains(e.target)) {
suggestions.innerHTML = '';
}
});
}
// plus de bouton OK, plus de gestion de clic
});
function beep() {
const ctx = new(window.AudioContext || window.webkitAudioContext)();
const oscillator = ctx.createOscillator();

1
main/urls.py

@ -8,4 +8,5 @@ urlpatterns = [ @@ -8,4 +8,5 @@ urlpatterns = [
path('course/<int:course_id>/export_pdf/', views.export_pdf, name='export_pdf'),
path('scan/', views.scan_view, name='scan'),
path('dossards/', views.dossards_view, name='dossards'),
path('ajax/coureur_autocomplete/', views.coureur_autocomplete, name='coureur_autocomplete'),
]

22
main/views.py

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
from django.http import JsonResponse
from django.views.decorators.http import require_GET
import csv
import io
from datetime import timedelta
@ -15,12 +17,12 @@ from channels.layers import get_channel_layer @@ -15,12 +17,12 @@ from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from .models import Course, Arrivee, Coureur
from django.db import models
from .forms import CourseForm, ScanForm, DossardForm
import qrcode
from PIL import Image
def seconds_to_hms(delta: timedelta) -> str:
if delta is None:
return ''
@ -30,6 +32,24 @@ def seconds_to_hms(delta: timedelta) -> str: @@ -30,6 +32,24 @@ def seconds_to_hms(delta: timedelta) -> str:
seconds = total % 60
return f"{hours}h{minutes:02d}m{seconds:02d}s"
@login_required
@require_GET
def coureur_autocomplete(request):
q = request.GET.get('q', '').strip()
results = []
if len(q) >= 2:
# Recherche sur nom, prénom, classe, dossard (id)
qs = Coureur.objects.filter(
models.Q(nom__icontains=q) |
models.Q(prenom__icontains=q) |
models.Q(classe__icontains=q) |
models.Q(id__icontains=q)
).order_by('nom', 'prenom')[:10]
for c in qs:
label = f"{c.nom} {c.prenom} ({c.classe}) [dossard: {c.id}]"
results.append({'id': c.id, 'label': label})
return JsonResponse(results, safe=False)
@login_required
def main_view(request):
courses = Course.objects.filter(owner=request.user)

Loading…
Cancel
Save