diff --git a/apps/ops/src/pages/PlanificationPage.vue b/apps/ops/src/pages/PlanificationPage.vue index 8b524cf..dc32b68 100644 --- a/apps/ops/src/pages/PlanificationPage.vue +++ b/apps/ops/src/pages/PlanificationPage.vue @@ -272,13 +272,17 @@ {{ r.dept }} · {{ shiftName(r.shift) }} {{ gardeDowLabel(r) }} · toutes les {{ r.periodWeeks }} sem. · rotation : {{ r.techs.map(id => (techs.find(t => t.id === id) || {}).name || id).join(' → ') }} - + + Modifier (ordre, techs, période) + + +
{{ editingGardeId ? 'Modifier la règle' : 'Nouvelle règle' }}
- + - + 2 = chaque tech fait 2 semaines de suite avant de passer au suivant
Jours : @@ -286,9 +290,19 @@
- + +
+
Ordre de rotation :
+
+ {{ i + 1 }}. + {{ techName(id) }} + + +
+
- + +
@@ -588,7 +602,11 @@ function loadLS () { try { demand.value = JSON.parse(localStorage.getItem(LS_DEM // ── Rotation de garde par département (récurrence + rotation) ──────────────── const GARDE_EPOCH = '2026-01-05' // lundi de référence pour l'index de semaine const gardeTemplateOptions = computed(() => templates.value.slice().sort((a, b) => (b.on_call ? 1 : 0) - (a.on_call ? 1 : 0)).map(t => ({ label: t.template_name + (t.on_call ? ' 🛡️' : ''), value: t.name }))) -const deptTechs = computed(() => techs.value.filter(t => !newGardeRule.dept || t.group === newGardeRule.dept).map(t => ({ label: t.name, value: t.id }))) +const groupNames = computed(() => [...new Set(techs.value.map(t => t.group).filter(Boolean))].sort()) +const editingGardeId = ref(null) +function techName (id) { const t = techs.value.find(x => x.id === id); return t ? t.name : id } +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, techs: [...r.techs] }); editingGardeId.value = r.id } 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)) } @@ -602,11 +620,14 @@ function rotationTech (rule, iso) { function toggleGardeDow (v) { const i = newGardeRule.weekdays.indexOf(v); if (i >= 0) newGardeRule.weekdays.splice(i, 1); else newGardeRule.weekdays.push(v) } function saveGarde () { localStorage.setItem(LS_GARDE, JSON.stringify(gardeRules.value)) } function addGardeRule () { - if (!newGardeRule.dept || !newGardeRule.shift || !newGardeRule.techs.length || !newGardeRule.weekdays.length) { $q.notify({ type: 'warning', message: 'Département, shift, jours et techs requis' }); return } - gardeRules.value = [...gardeRules.value, { id: Date.now(), dept: newGardeRule.dept, shift: newGardeRule.shift, weekdays: [...newGardeRule.weekdays], periodWeeks: newGardeRule.periodWeeks || 1, techs: [...newGardeRule.techs] }] - saveGarde(); newGardeRule.techs = []; $q.notify({ type: 'positive', message: 'Règle de garde ajoutée' }) + if (!newGardeRule.shift || !newGardeRule.techs.length || !newGardeRule.weekdays.length) { $q.notify({ type: 'warning', message: 'Shift, jours et techs requis (département optionnel)' }); return } + const rule = { id: editingGardeId.value || Date.now(), dept: newGardeRule.dept || '—', shift: newGardeRule.shift, weekdays: [...newGardeRule.weekdays], periodWeeks: newGardeRule.periodWeeks || 1, techs: [...newGardeRule.techs] } + if (editingGardeId.value) gardeRules.value = gardeRules.value.map(r => r.id === editingGardeId.value ? rule : r) + else gardeRules.value = [...gardeRules.value, rule] + saveGarde(); editingGardeId.value = null; newGardeRule.techs = []; newGardeRule.weekdays = [] + $q.notify({ type: 'positive', message: 'Règle de garde enregistrée' }) } -function removeGardeRule (i) { gardeRules.value = gardeRules.value.filter((_, j) => j !== i); saveGarde() } +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('') } // Génère les gardes de la semaine affichée selon les règles (rotation par département) function applyGardeRules () {