diff --git a/apps/ops/src/pages/PlanificationPage.vue b/apps/ops/src/pages/PlanificationPage.vue index 62430c8..d0d1bba 100644 --- a/apps/ops/src/pages/PlanificationPage.vue +++ b/apps/ops/src/pages/PlanificationPage.vue @@ -286,11 +286,13 @@ Occurrences consécutives avant de passer au tech suivant (1 = change à chaque {{ newGardeRule.unit === 'week' ? 'semaine' : 'jour de garde' }})
- Jours : - {{ dw.l }} - - + Plages (hors bureau) : + + + · + {{ dw.l }}
+
Combinables. La garde couvre les heures du shift choisi (hors bureau) ; pour des heures différentes semaine/week-end, crée 2 règles.
@@ -305,6 +307,12 @@ Retirer
+
+
Aperçu (qui est de garde, prochaines semaines) :
+
+ sem. {{ p.week.slice(8) }}/{{ p.week.slice(5, 7) }} → {{ p.name }} +
+
@@ -379,7 +387,7 @@ const activeCell = ref(null) // dernière case cliquée {id, name, iso} — pour const anchor = ref(null) const demand = ref([]); const holidays = ref([]); const weekTemplates = ref([]) const gardeRules = ref([]); const showGarde = ref(false) -const newGardeRule = reactive({ dept: '', shift: '', weekdays: [], periodWeeks: 1, unit: 'occ', techs: [] }) +const newGardeRule = reactive({ dept: '', shift: '', weekdays: [], periodWeeks: 1, unit: 'week', techs: [] }) const GARDE_DOW = [{ v: 1, l: 'L' }, { v: 2, l: 'M' }, { v: 3, l: 'M' }, { v: 4, l: 'J' }, { v: 5, l: 'V' }, { v: 6, l: 'S' }, { v: 0, l: 'D' }] const history = ref([]); const future = ref([]) const search = ref(''); const groupFilter = ref(null); const maxHours = ref(40) @@ -611,7 +619,10 @@ const groupNames = computed(() => [...new Set(techs.value.map(t => t.group).filt const editingGardeId = ref(null); const gardePick = ref(null) function addTechToSeq () { if (gardePick.value) { newGardeRule.techs.push(gardePick.value); gardePick.value = null } } // doublons permis (tours inégaux) function moveTech (i, dir) { const a = newGardeRule.techs; 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) { Object.assign(newGardeRule, { dept: r.dept || '', shift: r.shift, weekdays: [...r.weekdays], periodWeeks: r.periodWeeks || 1, unit: r.unit || 'occ', techs: [...r.techs] }); editingGardeId.value = r.id } +function editGardeRule (r) { Object.assign(newGardeRule, { dept: r.dept || '', shift: r.shift, weekdays: [...r.weekdays], periodWeeks: r.periodWeeks || 1, unit: r.unit || 'week', techs: [...r.techs] }); editingGardeId.value = r.id } +const WD_SEMAINE = [1, 2, 3, 4, 5]; const WD_FINSEM = [6, 0] +function isSetActive (set) { return set.length && set.every(v => newGardeRule.weekdays.includes(v)) } +function toggleWeekdaysSet (set) { if (isSetActive(set)) newGardeRule.weekdays = newGardeRule.weekdays.filter(v => !set.includes(v)); else newGardeRule.weekdays = [...new Set([...newGardeRule.weekdays, ...set])] } function d2ms (iso) { const a = iso.split('-').map(Number); return Date.UTC(a[0], a[1] - 1, a[2]) } function mondayISO (iso) { return addDaysISO(iso, -((dowOf(iso) + 6) % 7)) } function weekIndex (iso) { return Math.round((d2ms(mondayISO(iso)) - d2ms(GARDE_EPOCH)) / (7 * 86400000)) } @@ -624,7 +635,20 @@ function occurrenceIndex (rule, iso) { return cnt } // Index de rotation : par OCCURRENCE de garde (défaut → la séquence continue chaque jour de garde) ou par SEMAINE (bloc). -function gardeIndex (rule, iso) { return Math.floor(((rule.unit || 'occ') === 'week' ? weekIndex(iso) : occurrenceIndex(rule, iso)) / (rule.periodWeeks || 1)) } +function gardeIndex (rule, iso) { return Math.floor(((rule.unit || 'week') === 'week' ? weekIndex(iso) : occurrenceIndex(rule, iso)) / (rule.periodWeeks || 1)) } +// Aperçu : qui est de garde sur les prochaines semaines (depuis la semaine affichée) — reflète la file en cours d'édition +const gardePreview = computed(() => { + const rule = newGardeRule; if (!rule.techs.length || !rule.weekdays.length) return [] + const out = []; const wk0 = mondayISO(start.value) + for (let i = 0; i < 8; i++) { + const ws = addDaysISO(wk0, i * 7); let iso = null + for (let k = 0; k < 7; k++) { const d = addDaysISO(ws, k); if (rule.weekdays.includes(dowOf(d))) { iso = d; break } } + if (!iso) continue + const base = gardeIndex(rule, iso); const id = rule.techs[((base % rule.techs.length) + rule.techs.length) % rule.techs.length] + out.push({ week: ws, name: (techs.value.find(t => t.id === id) || {}).name || id }) + } + return out +}) // Tech de garde pour une date ; saute un tech absent au profit du suivant. function rotationTech (rule, iso) { if (!rule.techs || !rule.techs.length) return null