Paillasse/portail/resources/views/seances/attente.blade.php
Adam Belkacemi f2bca621cd ajoute la surveillance d'examen (chantier vrai cockpit, dernière étape)
Une séance peut être lancée en mode examen avec une durée dédiée.
Réutilise le mécanisme d'expiration déjà en place (labs:expirer-sessions,
expire_a) plutôt que d'en construire un nouveau. Le navigateur de
l'élève signale les changements d'onglet et les sorties de plein écran
(evenements_examen : un type et un horodatage, rien d'autre - pas de
capture d'écran ni de webcam) ; le prof voit le compte par élève et le
temps restant dans le cockpit de sa classe et la salle d'attente.

Choix d'Adam après discussion des options (suivi chronométré simple /
+ détection d'onglet / + tentative de plein écran) : la troisième,
honnêtement présentée - un navigateur ne permet pas de vraiment
empêcher de sortir, seulement de le signaler.

Avec cette étape, les quatre fonctions fictives du tableau de bord
démo (quiz, devoirs, observations, examen) sont maintenant réelles.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 00:35:52 +02:00

80 lines
6 KiB
PHP

@extends('layouts.app')
@section('titre', "Salle d'attente")
@php($etats = \App\Models\LabSession::class)
@section('contenu')
<meta http-equiv="refresh" content="10">
<div class="mx-auto max-w-4xl px-5 py-14 lg:px-10">
<p class="font-mono text-sm font-semibold">{{ $seance->classe->nom }} · {{ $seance->lab->titre }}</p>
<h1 class="mt-1 text-4xl font-extrabold tracking-tight">Salle d'attente
@if ($seance->mode_examen)
<span class="rounded-lg border border-[#A63D2A] bg-[#fce8e6] px-2 py-0.5 align-middle font-mono text-sm font-bold">Mode examen · {{ $seance->duree_examen_min }} min</span>
@endif
</h1>
<p class="mt-2 font-semibold">La page se rafraîchit toutes les 10 secondes.</p>
<p class="mt-4"><a href="{{ route('seances.visio.prof', $seance) }}" class="inline-flex h-11 items-center rounded-full bg-[#0b57d0] px-5 font-bold text-white">{{ $seance->visioOuverte() ? 'Retourner à la visio' : 'Visio de la classe' }}</a></p>
@if ($seance->labSessions->isEmpty())
<p class="mt-8 font-semibold">Personne n'a encore rejoint la séance.</p>
@else
<ul class="mt-8 grid gap-3">
@foreach ($seance->labSessions as $labSession)
<li class="flex flex-wrap items-center justify-between gap-4 rounded-2xl border border-[#e3e5e8] bg-white p-4">
<span class="font-extrabold">{{ $labSession->eleve->nomAffiche() }}</span>
<span class="flex flex-wrap items-center gap-3">
@switch($labSession->etat)
@case($etats::EN_ATTENTE)
<form action="{{ route('seances.admettre', [$seance, $labSession]) }}" method="post">
@csrf
<button type="submit" class="inline-flex h-10 items-center rounded-full bg-[#0b57d0] px-4 font-bold text-white">Admettre</button>
</form>
@break
@case($etats::ADMIS)
<span class="rounded-lg border border-[#dadce0] bg-[#fef7e0] px-3 py-1 font-mono text-sm font-bold">Préparation des VM…</span>
@break
@case($etats::ACTIF)
<span class="rounded-lg border border-[#dadce0] bg-[#e6f4ea] px-3 py-1 font-mono text-sm font-bold">Admis</span>
@if ($labSession->derniereCorrection)
<span class="font-mono text-sm font-bold">
{{ $labSession->derniereCorrection->reussi ? 'Réussi' : 'En cours' }} · {{ $labSession->derniereCorrection->note }}/{{ $labSession->derniereCorrection->note_max }}
</span>
@endif
<a href="{{ route('seances.console.prof.page', [$seance, $labSession]) }}" class="font-bold underline underline-offset-4">Voir sa console</a>
@if ($seance->mode_examen)
<span class="font-mono text-sm font-bold {{ $labSession->evenementsExamen->isNotEmpty() ? 'text-[#A63D2A]' : '' }}">{{ $labSession->evenementsExamen->count() }} sortie(s)</span>
@if ($labSession->minutesRestantes() !== null)
<span class="font-mono text-sm font-bold">{{ $labSession->minutesRestantes() }} min restantes</span>
@endif
@endif
@break
@case($etats::ECHEC)
<span class="rounded-lg border border-[#A63D2A] bg-[#fce8e6] px-3 py-1 font-mono text-sm font-bold" title="{{ $labSession->raison_echec }}">Échec du lancement (3 essais)</span>
<form action="{{ route('seances.admettre', [$seance, $labSession]) }}" method="post">
@csrf
<button type="submit" class="inline-flex h-10 items-center rounded-full bg-black px-4 font-bold text-white">Réessayer</button>
</form>
@break
@default
<span class="rounded-lg border border-[#dadce0] px-3 py-1 font-mono text-sm font-bold">Terminé</span>
@endswitch
</span>
@if ($labSession->etat === $etats::ECHEC && $labSession->raison_echec)
<p class="w-full font-mono text-xs text-[#5f6368]">{{ $labSession->raison_echec }}</p>
@endif
@if ($labSession->etat === $etats::ACTIF)
@foreach ($labSession->machines as $machine)
@if ($machine->sante === \App\Models\LabSessionMachine::IRREPARABLE)
<p class="w-full font-mono text-sm font-bold text-[#A63D2A]">{{ $machine->nom }} ne répond plus malgré deux redémarrages automatiques. L'équipe technique est prévenue.</p>
@elseif ($machine->sante === \App\Models\LabSessionMachine::RELANCEE && $machine->sante_a?->gt(now()->subMinutes(30)))
<p class="w-full font-mono text-xs text-[#5f6368]">{{ $machine->nom }} était bloquée : redémarrée automatiquement à {{ $machine->sante_a->timezone('Europe/Paris')->format('H:i') }} (fichiers conservés).</p>
@endif
@endforeach
@endif
</li>
@endforeach
</ul>
@endif
</div>
@endsection