Compare commits

..

No commits in common. '58b9a821de5b2f2d128b092a28a530a6bc0f462e' and '4933eff9426112e73e6b7183bc88b2f5f89ec630' have entirely different histories.

  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,7 +20,6 @@
<button type="button" id="btnFinish" class="btn btn-danger">Fin course <button type="button" id="btnFinish" class="btn btn-danger">Fin course
<i class="fa-solid fa-stop"></i> <i class="fa-solid fa-stop"></i>
</button> </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 --> <!-- Modal confirmation fin de course -->
<div class="modal fade" id="finishModal" tabindex="-1" role="dialog" aria-labelledby="finishModalLabel" aria-hidden="true"> <div class="modal fade" id="finishModal" tabindex="-1" role="dialog" aria-labelledby="finishModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">

14
main/templates/dossards.html

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

4
main/templates/scan.html

@ -9,9 +9,6 @@
<h6 class="m-0 font-weight-bold text-primary">Scanner un coureur</h6> <h6 class="m-0 font-weight-bold text-primary">Scanner un coureur</h6>
</div> </div>
<div class="card-body"> <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 id="reader" style="width:100%; max-width:400px; margin:auto;"></div>
<div class="mt-4 position-relative" style="max-width:400px; margin:auto;"> <div class="mt-4 position-relative" style="max-width:400px; margin:auto;">
<label id="manualCoureurLabel">Saisie manuelle :</label> <label id="manualCoureurLabel">Saisie manuelle :</label>
@ -25,7 +22,6 @@
{% if error %} {% if error %}
<div class="alert alert-danger mt-3">{{ error }}</div> <div class="alert alert-danger mt-3">{{ error }}</div>
{% endif %} {% endif %}
{% endif %}
</div> </div>
</div> </div>
<div class="card shadow mb-4"> <div class="card shadow mb-4">

123
main/views.py

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

Loading…
Cancel
Save