Garde: fix « 0 assignations » — rétrocompat des règles sans steps/anchor

Les règles créées avant le refactor (techs[]+periodWeeks, sans steps/anchor) donnaient 0 assignation
(rotationTech voyait 0 étape) + anchor manquant → toujours step 0. Fix: ruleSteps() convertit techs[]+
periodWeeks en étapes {tech,weeks} (collapse des doublons consécutifs) et ruleAnchor() retombe sur une
référence stable (epoch). rotationTech/gardeSeqLabel/editGardeRule passent par ces helpers → les vieilles
règles génèrent + s'affichent correctement, sans devoir tout recréer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-06-04 22:29:57 -04:00
parent e454e3f276
commit 0320c8716f

View File

@ -642,8 +642,7 @@ function openGarde () { if (!newGardeRule.anchor) newGardeRule.anchor = mondayIS
function addTechToSeq () { if (gardePick.value) { newGardeRule.steps.push({ tech: gardePick.value, weeks: 1 }); gardePick.value = null } }
function moveTech (i, dir) { const a = newGardeRule.steps; const j = i + dir; if (j < 0 || j >= a.length) return; const x = a[i]; a.splice(i, 1); a.splice(j, 0, x) }
function editGardeRule (r) {
const steps = (r.steps && r.steps.length) ? r.steps.map(s => ({ tech: s.tech, weeks: Number(s.weeks) || 1 })) : (r.techs || []).map(t => ({ tech: t, weeks: r.periodWeeks || 1 }))
Object.assign(newGardeRule, { dept: r.dept || '', shift: r.shift, weekdays: [...(r.weekdays || [])], anchor: r.anchor || mondayISO(start.value), steps })
Object.assign(newGardeRule, { dept: r.dept || '', shift: r.shift, weekdays: [...(r.weekdays || [])], anchor: r.anchor || mondayISO(start.value), steps: ruleSteps(r) })
editingGardeId.value = r.id
}
const WD_SEMAINE = [1, 2, 3, 4, 5]; const WD_FINSEM = [6, 0]
@ -653,10 +652,17 @@ function toggleGardeDow (v) { const i = newGardeRule.weekdays.indexOf(v); if (i
// Moteur de rotation : on PARCOURT la séquence semaine par semaine depuis l'ANCRAGE
function cycleWeeks (steps) { return (steps || []).reduce((s, x) => s + (Number(x.weeks) || 1), 0) }
function stepTechAt (steps, w) { for (const s of steps) { const n = Number(s.weeks) || 1; if (w < n) return s.tech; w -= n } return steps[0] && steps[0].tech }
// Rétrocompat : règle au nouveau format (steps) OU à l'ancien (techs[]+periodWeeks). Collapse les doublons consécutifs.
function ruleSteps (r) {
if (r.steps && r.steps.length) return r.steps.map(s => ({ tech: s.tech, weeks: Number(s.weeks) || 1 }))
const p = r.periodWeeks || 1; const out = []
for (const t of (r.techs || [])) { const last = out[out.length - 1]; if (last && last.tech === t) last.weeks += p; else out.push({ tech: t, weeks: p }) }
return out
}
function ruleAnchor (r) { return r.anchor || GARDE_EPOCH } // ancrage stable si non défini (vieilles règles)
function rotationTech (rule, iso) {
const steps = rule.steps || []; const cyc = cycleWeeks(steps); if (!cyc) return null
const anchor = rule.anchor || mondayISO(iso)
const w0 = (((weekNo(iso) - weekNo(anchor)) % cyc) + cyc) % cyc
const steps = ruleSteps(rule); const cyc = cycleWeeks(steps); if (!cyc) return null
const w0 = (((weekNo(iso) - weekNo(ruleAnchor(rule))) % cyc) + cyc) % cyc
for (let k = 0; k < cyc; k++) { const id = stepTechAt(steps, (w0 + k) % cyc); if (id && !isAbsent(id, iso)) return id } // saut d'absent
return stepTechAt(steps, w0)
}
@ -682,7 +688,7 @@ function addGardeRule () {
}
function removeGardeRule (i) { gardeRules.value = gardeRules.value.filter((_, j) => j !== i); saveGarde(); if (editingGardeId.value && !gardeRules.value.some(r => r.id === editingGardeId.value)) editingGardeId.value = null }
function gardeDowLabel (r) { return (r.weekdays || []).map(w => (GARDE_DOW.find(x => x.v === w) || {}).l).join('') }
function gardeSeqLabel (r) { return (r.steps || []).map(s => ((techs.value.find(t => t.id === s.tech) || {}).name || s.tech) + (s.weeks > 1 ? ' ×' + s.weeks : '')).join(' → ') }
function gardeSeqLabel (r) { return ruleSteps(r).map(s => ((techs.value.find(t => t.id === s.tech) || {}).name || s.tech) + (s.weeks > 1 ? ' ×' + s.weeks : '')).join(' → ') }
// Génère les gardes de la semaine affichée selon les règles (rotation par département)
const gardeHorizon = ref(8) // nb de semaines à matérialiser (évènement récurrent)
// Génère la garde sur un HORIZON (plusieurs semaines) et l'écrit directement (publié) navigable semaine par semaine.