diff --git a/apps/ops/src/pages/PlanificationPage.vue b/apps/ops/src/pages/PlanificationPage.vue index 61dd7ed..13321f2 100644 --- a/apps/ops/src/pages/PlanificationPage.vue +++ b/apps/ops/src/pages/PlanificationPage.vue @@ -92,7 +92,8 @@
{{ cellClipboard.length }} copié(s) Légende : - matin → soir + dispo (matin → soir) + occupation garde Ppause ·libre @@ -402,8 +403,8 @@ const axisTicks = computed(() => { return out }) function pos (s, e) { const b = axisBounds.value; const span = (b.max - b.min) || 24; const L = Math.max(0, (s - b.min) / span * 100); const R = Math.min(100, (e - b.min) / span * 100); return { left: L + '%', width: Math.max(1.5, R - L) + '%' } } -// Couleur selon l'heure : bleu pâle le matin → violet le soir -function todColor (h) { const t = Math.max(0, Math.min(1, (h - 6) / 15)); return 'hsl(' + Math.round(210 + t * 60) + ',' + Math.round(62 - t * 6) + '%,' + Math.round(83 - t * 22) + '%)' } +// Barre de temps PÂLE : bleu très pâle le matin → violet pâle le soir (repère discret du « quand ») +function todColor (h) { const t = Math.max(0, Math.min(1, (h - 6) / 15)); return 'hsl(' + Math.round(210 + t * 60) + ',45%,' + Math.round(91 - t * 8) + '%)' } function bandGradient (s, e) { return 'linear-gradient(to right, ' + todColor(s) + ', ' + todColor(e) + ')' } // Bandes = chaque shift. Régulier = dégradé matin→soir ; garde (on_call) = hachuré (réserve). function cellBands (techId, iso) { @@ -417,8 +418,9 @@ function cellBands (techId, iso) { } return out } -// Occupé = assombrit la dispo (clair = libre/offrable) ; rouge si surbooké. -function blockStyle (blk, pct) { return { ...pos(blk.s, Math.min(blk.e, 24)), background: (pct != null && pct >= 100) ? 'rgba(229,57,53,.6)' : 'rgba(0,0,0,.28)' } } +// Barre de statut OPAQUE selon l'occupation : vert (peu) → orange (plein) → rouge (surbooké). +function occColor (pct) { if (pct == null) return '#9e9e9e'; if (pct >= 100) return '#e53935'; const t = Math.max(0, Math.min(1, pct / 100)); return 'hsl(' + Math.round(122 - t * 90) + ',68%,44%)' } +function blockStyle (blk, pct) { return { ...pos(blk.s, Math.min(blk.e, 24)), background: occColor(pct) } } // Fenêtre des shifts (garde=true → seulement les quarts de garde ; garde=false → réguliers) function winOf (techId, iso, garde) { let s = Infinity; let e = -Infinity; for (const a of cellsOf(techId, iso)) { const t = tplByName.value[a.shift]; if (!t || (!!t.on_call) !== garde) continue; const st = hToNum(t.start_time); const en = hToNum(t.end_time); if (st != null) s = Math.min(s, st); if (en != null) e = Math.max(e, en) } return isFinite(s) ? { s, e } : null } const occCells = computed(() => { @@ -681,7 +683,8 @@ th.clk, td.clk { cursor: pointer; } .tl-shift { position: absolute; top: 0; bottom: 0; background: #ccd2d8; border-radius: 1px; } /* fenêtre dispo = neutre */ .tl-shift.oncall { background: repeating-linear-gradient(45deg, #d7ccc8 0, #d7ccc8 2px, transparent 2px, transparent 4px); box-shadow: inset 0 0 0 1px #a1887f; } /* garde = hachuré (réserve, non offrable) */ .tl-blk { position: absolute; top: 0; bottom: 0; border-radius: 1px; } /* occupé = assombrit la dispo */ -.tod-leg { display: inline-block; width: 46px; height: 9px; border-radius: 2px; vertical-align: middle; background: linear-gradient(to right, hsl(210,62%,83%), hsl(270,56%,61%)); } +.tod-leg { display: inline-block; width: 46px; height: 9px; border-radius: 2px; vertical-align: middle; background: linear-gradient(to right, hsl(210,45%,91%), hsl(270,45%,83%)); } +.occ-leg { display: inline-block; width: 46px; height: 9px; border-radius: 2px; vertical-align: middle; background: linear-gradient(to right, hsl(122,68%,44%), hsl(32,68%,44%)); } .tod-garde { display: inline-block; width: 24px; height: 9px; border-radius: 2px; vertical-align: middle; background: repeating-linear-gradient(45deg,#d7ccc8 0,#d7ccc8 2px,transparent 2px,transparent 4px); box-shadow: inset 0 0 0 1px #a1887f; } tr.paused .tech-col { color: #aaa; } tfoot .sum td { background: #fafafa; font-size: 11px; color: #555; font-weight: 600; }