From 5e482a89e78c2661ce17905929c4f52f30145aa9 Mon Sep 17 00:00:00 2001 From: Jules Date: Sun, 12 Jul 2026 16:41:30 +0200 Subject: [PATCH] Consommables : ajout compteur poses perdues + ratio corrige 0.5 (10/20) - Nouvelle carte 'Poses perdues' dans le panneau consommables - Le ratio ruban optimal pour 10x15 est 0.5 (10cm sur 20cm de panneau) - Diagnostic enrichi : alerte epuisement, ruban avant papier, % gaspille - Reset poses perdues avec le ruban Co-Authored-By: Claude Opus 4.6 --- backend/destinations.py | 22 ++++++++++++++++------ frontend/css/style.css | 2 +- frontend/index.html | 6 ++++++ frontend/js/admin.js | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/backend/destinations.py b/backend/destinations.py index 8242561..1b40830 100644 --- a/backend/destinations.py +++ b/backend/destinations.py @@ -223,10 +223,10 @@ def reset_compteur(): # --- Suivi consommables --- -TAILLE_RUBAN = { - "15x20": 1.0, - "10x15": 0.667, +RATIO_RUBAN_OPTIMAL = { + "10x15": 0.5, "10x15-2up": 1.0, + "15x20": 1.0, "15x20-2up": 1.0, } @@ -241,11 +241,17 @@ def maj_consommables(config: dict, copies: int, format_papier: str | None): conso["papier_utilise"] = conso.get("papier_utilise", 0) + feuilles conso["photos_imprimees"] = conso.get("photos_imprimees", 0) + copies + ratio_optimal = RATIO_RUBAN_OPTIMAL.get(fmt, 1.0) if rembobinage: - ruban_par_feuille = TAILLE_RUBAN.get(fmt, 1.0) + ruban_consomme = feuilles * ratio_optimal else: - ruban_par_feuille = 1.0 - conso["ruban_utilise"] = round(conso.get("ruban_utilise", 0) + feuilles * ruban_par_feuille, 1) + ruban_consomme = feuilles * 1.0 + + conso["ruban_utilise"] = round(conso.get("ruban_utilise", 0) + ruban_consomme, 1) + + # Poses perdues = ruban avance inutilement (difference entre consomme et optimal) + poses_perdues = feuilles * 1.0 - feuilles * ratio_optimal if not rembobinage else 0 + conso["poses_perdues"] = round(conso.get("poses_perdues", 0) + poses_perdues, 1) mettre_a_jour_config({"consommables": conso}) @@ -259,6 +265,7 @@ def consommables_etat() -> dict: papier_used = conso.get("papier_utilise", 0) ruban_used = conso.get("ruban_utilise", 0) photos = conso.get("photos_imprimees", 0) + perdues = conso.get("poses_perdues", 0) return { "papier_capacite": papier_cap, "papier_utilise": papier_used, @@ -267,6 +274,7 @@ def consommables_etat() -> dict: "ruban_utilise": ruban_used, "ruban_restant": max(0, round(ruban_cap - ruban_used, 1)), "photos_imprimees": photos, + "poses_perdues": perdues, } @@ -278,6 +286,8 @@ def reset_consommables(quoi: str): conso["papier_utilise"] = 0 if quoi in ("ruban", "tout"): conso["ruban_utilise"] = 0 + conso["poses_perdues"] = 0 if quoi == "tout": conso["photos_imprimees"] = 0 + conso["poses_perdues"] = 0 mettre_a_jour_config({"consommables": conso}) diff --git a/frontend/css/style.css b/frontend/css/style.css index c8a517b..1c53dd4 100644 --- a/frontend/css/style.css +++ b/frontend/css/style.css @@ -937,7 +937,7 @@ html, body { .conso-grid { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; } diff --git a/frontend/index.html b/frontend/index.html index 376a9b6..c638b11 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -502,6 +502,12 @@
Photos sorties
--
+
+
⚠
+
Poses perdues
+
--
+
ruban gaspille sans rembobinage
+

Capacites

diff --git a/frontend/js/admin.js b/frontend/js/admin.js index 0d1845c..510724b 100644 --- a/frontend/js/admin.js +++ b/frontend/js/admin.js @@ -1424,21 +1424,46 @@ async function chargerConsommables() { barrePapier.style.background = pctPapier < 10 ? '#f44336' : pctPapier < 25 ? '#fb8c00' : '#43a047'; barreRuban.style.background = pctRuban < 10 ? '#f44336' : pctRuban < 25 ? '#fb8c00' : '#43a047'; + const perdues = data.poses_perdues || 0; + document.getElementById('conso-perdues').textContent = perdues; + const cardPerdues = document.getElementById('conso-card-perdues'); + if (perdues > 0) { + document.getElementById('conso-perdues').style.color = '#f44336'; + cardPerdues.style.borderLeft = '3px solid #f44336'; + } else { + document.getElementById('conso-perdues').style.color = '#43a047'; + cardPerdues.style.borderLeft = '3px solid #43a047'; + } + const diag = document.getElementById('conso-diagnostic'); const papierUsed = data.papier_utilise; const rubanUsed = data.ruban_utilise; - let html = 'Diagnostic
'; - html += `Feuilles consommees : ${papierUsed}
`; + const photos = data.photos_imprimees; + let html = 'Diagnostic consommables
'; + html += `Feuilles papier consommees : ${papierUsed}
`; html += `Poses ruban consommees : ${rubanUsed}
`; - html += `Photos imprimees : ${data.photos_imprimees}
`; + html += `Photos imprimees : ${photos}
`; + html += `Poses perdues (gaspillees) : ${perdues}
`; if (papierUsed > 0) { const ratio = (rubanUsed / papierUsed).toFixed(2); - html += `
Ratio ruban/papier : ${ratio}`; + html += `
Ratio ruban/papier : ${ratio}
`; if (parseFloat(ratio) <= 0.75) { - html += ' ✅ Rembobinage actif (economie ruban)'; + html += '✅ Rembobinage efficace — le ruban est economise'; } else if (parseFloat(ratio) >= 0.95) { - html += ' ⚠ Ratio 1:1 — pas d\'economie ruban'; + html += '⚠ Pas d\'economie ruban — activez le rembobinage dans Materiel'; + } else { + html += '🔄 Rembobinage partiel'; } + if (perdues > 0) { + const pctPerdu = ((perdues / (rubanUsed + perdues)) * 100).toFixed(0); + html += `
🔴 ${pctPerdu}% du ruban gaspille (${perdues} poses pour rien)`; + } + } + if (data.papier_restant <= 20 || data.ruban_restant <= 20) { + html += '

🚨 Consommable bientot epuise !'; + } + if (data.ruban_restant < data.papier_restant - 10) { + html += '
⚠ Le ruban va s\'epuiser avant le papier'; } diag.innerHTML = html; } catch (e) {