Compare commits

..

2 Commits

Author SHA1 Message Date
41d8b98f96 Ajuste les slides 1 et 5 de l'exercice BioCID
- Slide 1 : encadrés '4 exercices' et 'Plateforme BioCID' inversés et mis à la même largeur
- Slide 1 : passage à l'exercice 1 bloqué tant que le nom du groupe n'est pas renseigné (message d'alerte)
- Slide 5 : titre 'Mise en situation réelle' -> 'Mise en situation'
- Slide 5 : reformulation de la mise en situation (restaurant / choix entre plusieurs références)
- Slide 5 : bouton 'Voir les bonnes pratiques' -> 'Terminer l'exercice'
2026-07-19 17:15:34 +02:00
d251782842 Ajoute une page unique de correction des exercices
- Nouvelle page corriger-exercice.html : sélection de l'exercice (BioCID, FDS, TP Nuisibles) + zone de dépôt PDF
- Le PDF déposé est transmis à la page de correction dédiée qui se charge automatiquement (?auto=1)
- Carte 'Corriger un exercice' ajoutée à la section Exercices de l'index
- Slide 6 BioCID : suppression du bouton biocid-anses.fr, alignement des boutons Télécharger / Corriger / Recommencer
- Le bouton 'Corriger un rendu' redirige vers la nouvelle page
2026-07-19 17:08:59 +02:00
6 changed files with 415 additions and 15 deletions

View File

@@ -475,7 +475,11 @@
<div class="section-tag">Avant de commencer</div>
<div class="slide-title">Contexte & accès</div>
<p class="slide-intro">BioCID est la plateforme officielle de l'ANSES pour consulter tous les produits biocides autorisés et déclarés en France. Cet exercice développe votre autonomie dans la consultation des produits.</p>
<div class="resource-card">
<div class="info-card" style="max-width:620px;">
<span>🎯</span>
<div>4 exercices vous attendent : recherche par <strong>nom</strong>, par <strong>type</strong>, par <strong>substance active</strong>, puis un <strong>cas de synthèse</strong>. Durée totale ≈ 30 min.</div>
</div>
<div class="resource-card" style="max-width:620px;margin-top:0.5rem;">
<div class="resource-icon">🌐</div>
<div class="resource-body">
<div class="resource-title">Plateforme BioCID — ANSES</div>
@@ -483,17 +487,14 @@
</div>
<a href="https://biocid-anses.fr/biocid" target="_blank" class="resource-link">Ouvrir ↗</a>
</div>
<div class="info-card" style="margin-top:0.5rem;">
<span>🎯</span>
<div>4 exercices vous attendent : recherche par <strong>nom</strong>, par <strong>type</strong>, par <strong>substance active</strong>, puis un <strong>cas de synthèse</strong>. Durée totale ≈ 30 min.</div>
</div>
<div class="identity-card">
<div class="identity-card" style="max-width:620px;">
<div class="identity-title">👥 Identification du groupe</div>
<div class="identity-fields">
<input type="text" id="idGroupe" placeholder="Nom du groupe / stagiaires (ex : Groupe 3 — Dupont / Martin)" autocomplete="off">
<input type="text" id="idGroupe" placeholder="Nom du groupe / stagiaires (ex : Groupe 3 — Dupont / Martin)" autocomplete="off" oninput="clearGroupeWarning()">
<input type="date" id="idDate">
<input type="text" id="idFormateur" placeholder="Formateur (facultatif)" autocomplete="off">
</div>
<div id="idWarning" style="display:none;margin-top:8px;font-size:12.5px;color:var(--coral);">⚠ Renseignez le nom du groupe pour continuer.</div>
</div>
</div>
@@ -562,10 +563,10 @@
<div class="slide" id="slide-5">
<div class="scroll-area">
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">Exercice 4 / 4 — Cas de synthèse</div>
<div class="slide-title">Mise en situation réelle</div>
<div class="slide-title">Mise en situation</div>
<div class="info-card" style="background:var(--coral-light);color:var(--coral);margin-bottom:1rem;">
<span>📞</span>
<div>Un restaurant vous appelle pour une demande de produit. En utilisant BioCID, présentez une <strong>recommandation argumentée</strong>.</div>
<div>Un restaurant vous appelle au sujet de votre prestation et souhaite choisir le produit entre plusieurs références. En utilisant la plateforme BioCID, présentez une <strong>recommandation argumentée</strong>.</div>
</div>
<ul class="questions-list">
<li class="q-item">
@@ -603,10 +604,7 @@
</ul>
<div class="actions-row">
<button class="btn btn-amber" onclick="exporterPDF()">⬇ Télécharger mes réponses (PDF)</button>
<a href="correction-biocid.html" class="btn btn-outline">✔ Corriger un rendu</a>
</div>
<div class="actions-row" style="margin-top:0.5rem;">
<a href="https://biocid-anses.fr/biocid" target="_blank" class="btn btn-outline">biocid-anses.fr ↗</a>
<a href="corriger-exercice.html?exo=biocid" class="btn btn-outline">✔ Corriger un rendu</a>
<button class="btn btn-outline" onclick="restartAll()">↺ Recommencer</button>
</div>
</div>
@@ -623,7 +621,7 @@ const slideConfig = {
2: { hint: 'ex1', next: 3, nextLabel: 'Exercice suivant →' },
3: { hint: 'ex2', next: 4, nextLabel: 'Exercice suivant →' },
4: { hint: 'ex3', next: 5, nextLabel: 'Cas de synthèse →' },
5: { next: 6, nextLabel: 'Voir les bonnes pratiques' }
5: { next: 6, nextLabel: "Terminer l'exercice" }
};
const hints = {
@@ -673,9 +671,27 @@ function goBack() {
updateUI();
}
function clearGroupeWarning() {
const g = document.getElementById('idGroupe');
if (g) g.style.borderColor = '';
const w = document.getElementById('idWarning');
if (w) w.style.display = 'none';
}
function goNext() {
const cfg = slideConfig[currentSlide];
if (cfg && cfg.next != null) goTo(cfg.next);
if (!cfg || cfg.next == null) return;
// Slide 1 : le nom du groupe est obligatoire pour passer à l'exercice 1
if (currentSlide === 1) {
const g = document.getElementById('idGroupe');
if (!g.value.trim()) {
g.style.borderColor = 'var(--coral)';
document.getElementById('idWarning').style.display = 'block';
g.focus();
return;
}
}
goTo(cfg.next);
}
function showHintCurrent() {

View File

@@ -502,6 +502,24 @@ dropzone.addEventListener("drop", e => {
if (file) handleFile(file);
});
document.getElementById("filePicker").addEventListener("change", e => handleFile(e.target.files?.[0]));
// Chargement automatique depuis la page « Corriger un exercice » (?auto=1)
(function autoLoadFromHub() {
const params = new URLSearchParams(location.search);
if (params.get("auto") !== "1") return;
const dataUrl = localStorage.getItem("correctionFile");
const name = localStorage.getItem("correctionFileName") || "rendu.pdf";
localStorage.removeItem("correctionFile");
localStorage.removeItem("correctionFileName");
localStorage.removeItem("correctionExo");
if (!dataUrl) return;
try {
const bin = atob(dataUrl.split(",").pop());
const bytes = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
handleFile(new File([bytes], name, { type: "application/pdf" }));
} catch (e) { console.error(e); }
})();
</script>
</body>
</html>

View File

@@ -599,6 +599,24 @@ dropzone.addEventListener("drop", e => {
if (file) handleFile(file);
});
document.getElementById("filePicker").addEventListener("change", e => handleFile(e.target.files?.[0]));
// Chargement automatique depuis la page « Corriger un exercice » (?auto=1)
(function autoLoadFromHub() {
const params = new URLSearchParams(location.search);
if (params.get("auto") !== "1") return;
const dataUrl = localStorage.getItem("correctionFile");
const name = localStorage.getItem("correctionFileName") || "rendu.pdf";
localStorage.removeItem("correctionFile");
localStorage.removeItem("correctionFileName");
localStorage.removeItem("correctionExo");
if (!dataUrl) return;
try {
const bin = atob(dataUrl.split(",").pop());
const bytes = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
handleFile(new File([bytes], name, { type: "application/pdf" }));
} catch (e) { console.error(e); }
})();
</script>
</body>
</html>

View File

@@ -645,6 +645,24 @@ dropzone.addEventListener("drop", e => {
if (file) handleFile(file);
});
document.getElementById("filePicker").addEventListener("change", e => handleFile(e.target.files?.[0]));
// Chargement automatique depuis la page « Corriger un exercice » (?auto=1)
(function autoLoadFromHub() {
const params = new URLSearchParams(location.search);
if (params.get("auto") !== "1") return;
const dataUrl = localStorage.getItem("correctionFile");
const name = localStorage.getItem("correctionFileName") || "rendu.pdf";
localStorage.removeItem("correctionFile");
localStorage.removeItem("correctionFileName");
localStorage.removeItem("correctionExo");
if (!dataUrl) return;
try {
const bin = atob(dataUrl.split(",").pop());
const bytes = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
handleFile(new File([bytes], name, { type: "application/pdf" }));
} catch (e) { console.error(e); }
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,317 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Corriger un exercice — Certibiocide</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../header-style.css"/>
<style>
body {
padding: calc(36px + 70px) 20px 80px;
}
.wrap { max-width: 820px; margin: 0 auto; }
.eyebrow {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--amber);
margin-bottom: 6px;
}
h1 {
font-family: 'Syne', sans-serif;
font-size: 28px;
font-weight: 800;
letter-spacing: -0.5px;
margin-bottom: 8px;
}
.lead { color: var(--text-muted); font-size: 14.5px; line-height: 1.6; margin-bottom: 28px; max-width: 620px; }
/* STEP LABEL */
.step-label {
font-family: 'Syne', sans-serif;
font-size: 13px;
font-weight: 700;
color: var(--text);
margin: 0 0 14px;
display: flex;
align-items: center;
gap: 10px;
}
.step-num {
width: 24px; height: 24px;
border-radius: 50%;
background: var(--amber);
color: #fff;
font-size: 12px;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
/* EXERCISE SELECTOR */
.exo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
gap: 12px;
margin-bottom: 36px;
}
.exo-option { position: relative; }
.exo-option input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.exo-option label {
display: flex;
align-items: center;
gap: 14px;
background: #fff;
border: 1.5px solid var(--border);
border-radius: 14px;
padding: 16px 18px;
cursor: pointer;
transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
height: 100%;
}
.exo-option label:hover { border-color: var(--amber); }
.exo-option input:checked + label {
border-color: var(--amber);
background: var(--amber-light);
box-shadow: 0 4px 16px rgba(186,117,23,0.12);
}
.exo-option input:focus-visible + label { outline: 2px solid var(--amber); outline-offset: 2px; }
.exo-icon {
width: 44px; height: 44px;
border-radius: 12px;
background: var(--amber-light);
display: flex; align-items: center; justify-content: center;
font-size: 22px;
flex-shrink: 0;
}
.exo-option input:checked + label .exo-icon { background: #fff; }
.exo-text { flex: 1; min-width: 0; }
.exo-name { display: block; font-family: 'Syne', sans-serif; font-weight: 700; font-size: 14.5px; }
.exo-sub { display: block; font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }
.exo-check {
width: 22px; height: 22px;
border-radius: 50%;
border: 1.5px solid var(--border);
flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
color: #fff;
font-size: 12px;
transition: background 0.15s, border-color 0.15s;
}
.exo-option input:checked + label .exo-check {
background: var(--amber);
border-color: var(--amber);
}
.exo-option input:checked + label .exo-check::after { content: '✓'; }
/* DROPZONE */
#dropzone {
background: #fff;
border: 2px dashed rgba(186,117,23,0.35);
border-radius: 16px;
padding: 56px 24px;
text-align: center;
cursor: pointer;
transition: border-color 0.2s, background 0.2s, opacity 0.2s;
}
#dropzone.drag { border-color: var(--amber); background: var(--amber-light); }
#dropzone.disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
#dropzone .icon { font-size: 40px; margin-bottom: 12px; }
#dropzone p.title { font-family: 'Syne', sans-serif; font-weight: 700; font-size: 16px; margin-bottom: 6px; }
#dropzone p.sub { color: var(--text-muted); font-size: 13.5px; margin-bottom: 20px; }
#filePicker { display: none; }
.btn-pick {
font-family: 'Syne', sans-serif;
display: inline-block;
background: var(--amber);
color: #fff;
font-weight: 700;
font-size: 13px;
padding: 10px 26px;
border-radius: 30px;
cursor: pointer;
border: none;
}
#status { margin-top: 16px; font-size: 13px; min-height: 18px; }
#status.hint { color: var(--text-muted); }
#status.loading { color: var(--amber); }
#status.error { color: var(--coral); }
</style>
</head>
<body>
<header>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="../index.html">Accueil</a>
<a href="../index.html#formations">Exercices</a>
<a href="../index.html#documentation">Documentation</a>
<a href="../index.html#rapports">Rapports</a>
<a href="../index.html#about">À propos</a>
<a href="../index.html#contact">Contact</a>
</nav>
</header>
<div class="wrap">
<div class="eyebrow">Certibiocide — Correction des rendus</div>
<h1>Corriger un exercice</h1>
<p class="lead">Sélectionnez l'exercice concerné, puis déposez le fichier PDF exporté par le groupe. La lecture du rendu s'ouvre automatiquement.</p>
<p class="step-label"><span class="step-num">1</span> Choisissez l'exercice à corriger</p>
<div class="exo-grid" id="exoGrid">
<div class="exo-option">
<input type="radio" name="exo" id="exo-biocid" value="biocid">
<label for="exo-biocid">
<span class="exo-icon">🧪</span>
<span class="exo-text">
<span class="exo-name">Plateforme BioCID</span>
<span class="exo-sub">Recherche de produits biocides</span>
</span>
<span class="exo-check"></span>
</label>
</div>
<div class="exo-option">
<input type="radio" name="exo" id="exo-fds" value="fds">
<label for="exo-fds">
<span class="exo-icon">📋</span>
<span class="exo-text">
<span class="exo-name">FDS, FT &amp; Étiquettes</span>
<span class="exo-sub">Lecture documentaire</span>
</span>
<span class="exo-check"></span>
</label>
</div>
<div class="exo-option">
<input type="radio" name="exo" id="exo-tp" value="tp">
<label for="exo-tp">
<span class="exo-icon">📚</span>
<span class="exo-text">
<span class="exo-name">TP Nuisibles final</span>
<span class="exo-sub">Étude de cas de synthèse</span>
</span>
<span class="exo-check"></span>
</label>
</div>
</div>
<p class="step-label"><span class="step-num">2</span> Déposez le rendu PDF</p>
<div id="dropzone" class="disabled">
<div class="icon">📄</div>
<p class="title">Déposez le PDF du groupe ici</p>
<p class="sub">ou cliquez pour sélectionner le fichier exporté depuis l'exercice</p>
<label class="btn-pick">Choisir un fichier
<input type="file" id="filePicker" accept="application/pdf">
</label>
<div id="status" class="hint">Sélectionnez d'abord un exercice ci-dessus.</div>
</div>
</div>
<footer>
<p>&copy; 2026 Gauthier Chombart &amp; Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide &amp; Techniques — Formateurs indépendants</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés — Gauthier Chombart &amp; Nathan Chauwin — Formateurs indépendants</p>
</footer>
<script>
// Chaque exercice pointe vers sa page de correction dédiée (parseur spécifique).
const CORRECTORS = {
biocid: "correction-biocid.html",
fds: "correction-fds.html",
tp: "correction-tp-nuisibles.html",
};
const dropzone = document.getElementById("dropzone");
const status = document.getElementById("status");
const filePicker = document.getElementById("filePicker");
function selectedExo() {
const el = document.querySelector('input[name="exo"]:checked');
return el ? el.value : null;
}
function refreshDropzone() {
const exo = selectedExo();
if (exo) {
dropzone.classList.remove("disabled");
status.className = "hint";
status.textContent = "Prêt à recevoir le PDF.";
} else {
dropzone.classList.add("disabled");
status.className = "hint";
status.textContent = "Sélectionnez d'abord un exercice ci-dessus.";
}
}
// Préselection via ?exo=biocid|fds|tp
(function preselect() {
const params = new URLSearchParams(location.search);
const exo = params.get("exo");
if (exo && CORRECTORS[exo]) {
const input = document.getElementById("exo-" + exo);
if (input) input.checked = true;
}
})();
document.querySelectorAll('input[name="exo"]').forEach(r =>
r.addEventListener("change", refreshDropzone)
);
refreshDropzone();
function handleFile(file) {
const exo = selectedExo();
if (!exo) {
status.className = "error";
status.textContent = "Choisissez un exercice avant de déposer un fichier.";
return;
}
if (!file) return;
if (file.type !== "application/pdf" && !/\.pdf$/i.test(file.name)) {
status.className = "error";
status.textContent = "Le fichier doit être un PDF.";
return;
}
status.className = "loading";
status.textContent = "Ouverture du correcteur…";
const reader = new FileReader();
reader.onload = () => {
try {
// On transmet le PDF à la page de correction dédiée via localStorage
localStorage.setItem("correctionFile", reader.result);
localStorage.setItem("correctionFileName", file.name);
localStorage.setItem("correctionExo", exo);
window.location.href = CORRECTORS[exo] + "?auto=1";
} catch (e) {
console.error(e);
status.className = "error";
status.textContent = "Fichier trop volumineux pour être transmis. Ouvrez la page de correction dédiée.";
}
};
reader.onerror = () => {
status.className = "error";
status.textContent = "Impossible de lire le fichier.";
};
reader.readAsDataURL(file);
}
dropzone.addEventListener("dragover", e => {
if (dropzone.classList.contains("disabled")) return;
e.preventDefault();
dropzone.classList.add("drag");
});
dropzone.addEventListener("dragleave", () => dropzone.classList.remove("drag"));
dropzone.addEventListener("drop", e => {
if (dropzone.classList.contains("disabled")) return;
e.preventDefault();
dropzone.classList.remove("drag");
handleFile(e.dataTransfer.files && e.dataTransfer.files[0]);
});
filePicker.addEventListener("change", e => handleFile(e.target.files && e.target.files[0]));
</script>
</body>
</html>

View File

@@ -137,6 +137,19 @@
<a href="exercices/memory-pictogrammes/memory.html" class="formation-link">Jouer</a>
</div>
</div>
<!-- Correction : page unique pour tous les exercices -->
<div class="formation-card">
<div class="formation-header">
<div class="formation-icon">✔️</div>
<h3 class="formation-title">Corriger un exercice</h3>
<p class="formation-subtitle">Correction des rendus</p>
</div>
<div class="formation-body">
<p class="formation-description">Déposez le PDF exporté par un groupe et obtenez la lecture de son rendu. Page unique de correction pour l'ensemble des exercices.</p>
<a href="exercices/corriger-exercice.html" class="formation-link">Corriger</a>
</div>
</div>
</div>
</section>