Compare commits

...

2 Commits

  1. 1
      main/templates/course_detail.html
  2. 14
      main/templates/dossards.html
  3. 4
      main/templates/scan.html
  4. 123
      main/views.py

1
main/templates/course_detail.html

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
<button type="button" id="btnFinish" class="btn btn-danger">Fin course
<i class="fa-solid fa-stop"></i>
</button>
<a href="{% url 'scan' %}?course_id={{ course.id }}" class="btn btn-info ml-2">Accès au scan <i class="fas fa-qrcode"></i></a>
<!-- Modal confirmation fin de course -->
<div class="modal fade" id="finishModal" tabindex="-1" role="dialog" aria-labelledby="finishModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">

14
main/templates/dossards.html

@ -91,14 +91,22 @@ @@ -91,14 +91,22 @@
</div>
</div>
{% block extra_js %}
<script src="{% static 'jquery/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'jquery/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'bootstrap/dataTables.bootstrap4.min.js' %}"></script>
<script src="{% static 'jquery/datatables.fr.js' %}"></script>
<script>
$(document).ready(function() {
var table = $('#coureursTable').DataTable({
pageLength: 50,
});
// Empêche la double initialisation de DataTables
var table;
if (!$.fn.DataTable.isDataTable('#coureursTable')) {
table = $('#coureursTable').DataTable({
pageLength: 50,
});
} else {
table = $('#coureursTable').DataTable();
}
function updateMainDossardsCount() {
var count = table.rows({search:'applied'}).count();
$('#mainDossardsCountText').text('Générer ' + count + ' dossards');

4
main/templates/scan.html

@ -9,6 +9,9 @@ @@ -9,6 +9,9 @@
<h6 class="m-0 font-weight-bold text-primary">Scanner un coureur</h6>
</div>
<div class="card-body">
{% if course and course.fin %}
<div class="alert alert-danger text-center mb-0">Cette course est terminée. Le scan n'est plus possible.</div>
{% else %}
<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>
@ -22,6 +25,7 @@ @@ -22,6 +25,7 @@
{% if error %}
<div class="alert alert-danger mt-3">{{ error }}</div>
{% endif %}
{% endif %}
</div>
</div>
<div class="card shadow mb-4">

123
main/views.py

@ -273,6 +273,7 @@ def scan_view(request): @@ -273,6 +273,7 @@ def scan_view(request):
error = None
course = None
if request.method == 'POST' and request.headers.get('x-requested-with') == 'XMLHttpRequest':
course_id = request.POST.get('course_id')
qrcode = request.POST.get('qrcode')
@ -281,72 +282,74 @@ def scan_view(request): @@ -281,72 +282,74 @@ def scan_view(request):
else:
# S'assurer que l'utilisateur scanne uniquement ses propres courses
course = get_object_or_404(Course, id=course_id, owner=request.user)
# Le QR code contient maintenant l'identifiant unique du Coureur
coureur = None
try:
coureur = Coureur.objects.get(id=qrcode.strip())
except Coureur.DoesNotExist:
error = "Coureur introuvable pour ce code QR."
if coureur:
# Si la course est de type unique : comportement existant (1 arrivée par coureur)
if course.type == Course.TYPE_UNIQUE:
if Arrivee.objects.filter(course=course, coureur=coureur).exists():
error = "Ce coureur a déjà été scanné."
if course.fin:
error = "Cette course est terminée. Le scan n'est plus possible."
else:
# Le QR code contient maintenant l'identifiant unique du Coureur
coureur = None
try:
coureur = Coureur.objects.get(id=qrcode.strip())
except Coureur.DoesNotExist:
error = "Coureur introuvable pour ce code QR."
if coureur:
# Si la course est de type unique : comportement existant (1 arrivée par coureur)
if course.type == Course.TYPE_UNIQUE:
if Arrivee.objects.filter(course=course, coureur=coureur).exists():
error = "Ce coureur a déjà été scanné."
else:
temps = timezone.now() - course.depart
rang = Arrivee.objects.filter(course=course).count() + 1
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=temps, rang=rang, tour=1)
temps_str = seconds_to_hms(temps)
# nombre total de scans pour cette course
scan_count = Arrivee.objects.filter(course=course).count()
result = {
'nom': coureur.nom,
'prenom': coureur.prenom,
'classe': coureur.classe,
'rang': arr.rang,
'temps': temps_str,
'tour': arr.tour,
'scan_count': scan_count
}
# Pour les courses multi, autoriser plusieurs scans par coureur et calculer le tour/temps de tour
else:
temps = timezone.now() - course.depart
# Compter les arrivées précédentes pour ce coureur sur cette course
previous = Arrivee.objects.filter(course=course, coureur=coureur).order_by('tour', 'date_arrivee')
last_arr = previous.last()
if last_arr:
# prochain tour = dernier tour + 1
next_tour = last_arr.tour + 1
lap_time = timezone.now() - last_arr.date_arrivee
else:
# premier scan pour ce coureur : tour 1, temps depuis le départ de la course
next_tour = 1
lap_time = timezone.now() - course.depart
# rang = nombre d'arrivées global + 1
rang = Arrivee.objects.filter(course=course).count() + 1
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=temps, rang=rang, tour=1)
temps_str = seconds_to_hms(temps)
# nombre total de scans pour cette course
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=lap_time, rang=rang, tour=next_tour)
lap_str = seconds_to_hms(lap_time)
scan_count = Arrivee.objects.filter(course=course).count()
result = {
'nom': coureur.nom,
'prenom': coureur.prenom,
'classe': coureur.classe,
'rang': arr.rang,
'temps': temps_str,
'temps': lap_str,
'tour': arr.tour,
'lap_seconds': int(lap_time.total_seconds()),
'scan_count': scan_count
}
# Pour les courses multi, autoriser plusieurs scans par coureur et calculer le tour/temps de tour
else:
# Compter les arrivées précédentes pour ce coureur sur cette course
previous = Arrivee.objects.filter(course=course, coureur=coureur).order_by('tour', 'date_arrivee')
last_arr = previous.last()
if last_arr:
# prochain tour = dernier tour + 1
next_tour = last_arr.tour + 1
lap_time = timezone.now() - last_arr.date_arrivee
else:
# premier scan pour ce coureur : tour 1, temps depuis le départ de la course
next_tour = 1
lap_time = timezone.now() - course.depart
# rang = nombre d'arrivées global + 1
rang = Arrivee.objects.filter(course=course).count() + 1
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=lap_time, rang=rang, tour=next_tour)
lap_str = seconds_to_hms(lap_time)
scan_count = Arrivee.objects.filter(course=course).count()
result = {
'nom': coureur.nom,
'prenom': coureur.prenom,
'classe': coureur.classe,
'rang': arr.rang,
'temps': lap_str,
'tour': arr.tour,
'lap_seconds': int(lap_time.total_seconds()),
'scan_count': scan_count
}
# Diffuser via le canal websocket
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
f'course_{course.id}',
{
'type': 'send_arrivee',
'data': result
}
)
# Diffuser via le canal websocket
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
f'course_{course.id}',
{
'type': 'send_arrivee',
'data': result
}
)
if result:
return render(request, 'scan_result.html', {'result': result, 'course_type': course.type if course else None})
@ -357,17 +360,19 @@ def scan_view(request): @@ -357,17 +360,19 @@ def scan_view(request):
course_id = request.GET.get('course_id')
if course_id:
course = get_object_or_404(Course, id=course_id, owner=request.user)
if course.fin:
error = "Cette course est terminée. Le scan n'est plus possible."
# Formatage de la date pour affichage JJ/MM/AAAA
date_str = format_date(course.date) if course else ''
date_str = format_date(course.date) if course_id and 'course' in locals() else ''
# nombre actuel de scans pour cette course
scan_count = Arrivee.objects.filter(course=course).count() if course else 0
scan_count = Arrivee.objects.filter(course=course).count() if course_id and 'course' in locals() else 0
return render(request, 'scan.html', {
'title': f'Scan course : {course.nom} ({date_str})' if course else '',
'title': f'Scan course : {course.nom} ({date_str})' if course_id and 'course' in locals() else '',
'courses': courses,
'result': result,
'error': error,
'course': course,
'course': course if course_id and 'course' in locals() else None,
'scan_count': scan_count
})

Loading…
Cancel
Save