refactor(planif): clic progressbar → timeline éditable Dispatch (tech+jour) au lieu du popup maison
- réutilisation max + cohérence : le clic sur le progressbar ouvre le tableau Dispatch focalisé sur le tech + le jour cliqué (gotoDispatch(t, d.iso)) = LE timeline éditable (drag-drop réordonner, supprimer/désaffecter) - retire le popup cellJobsMenu (réordonner/priorité) → règle aussi le chevauchement avec l'infobulle mouseover - (endpoint /roster/reorder-jobs conservé, réutilisable ; le réordonnancement se fait désormais côté Dispatch) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b7b7da783b
commit
455a66aeb9
|
|
@ -183,7 +183,7 @@
|
||||||
<div class="tl"><div class="tl-absent"></div><q-tooltip class="bg-grey-9">Absent · {{ absenceLabel(t.id, d.iso) }}</q-tooltip></div>
|
<div class="tl"><div class="tl-absent"></div><q-tooltip class="bg-grey-9">Absent · {{ absenceLabel(t.id, d.iso) }}</q-tooltip></div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="hasReg(t.id, d.iso) || onGarde(t.id, d.iso)">
|
<template v-else-if="hasReg(t.id, d.iso) || onGarde(t.id, d.iso)">
|
||||||
<div class="tl tl-click" @mousedown.stop @click.stop="openCellJobs(t, d, $event)">
|
<div class="tl tl-click" @mousedown.stop @click.stop="gotoDispatch(t, d.iso)">
|
||||||
<div v-for="(b, bi) in cellBands(t.id, d.iso)" :key="'b' + bi" class="tl-shift" :class="{ oncall: b.oncall }" :style="{ left: b.left, width: b.width, background: b.bg || undefined }"></div>
|
<div v-for="(b, bi) in cellBands(t.id, d.iso)" :key="'b' + bi" class="tl-shift" :class="{ oncall: b.oncall }" :style="{ left: b.left, width: b.width, background: b.bg || undefined }"></div>
|
||||||
<div v-for="(b, bi) in cellBlocks(t.id, d.iso)" :key="'j' + bi" class="tl-blk" :style="blockStyle(b, cellPct(t.id, d.iso))"></div>
|
<div v-for="(b, bi) in cellBlocks(t.id, d.iso)" :key="'j' + bi" class="tl-blk" :style="blockStyle(b, cellPct(t.id, d.iso))"></div>
|
||||||
<!-- Aperçu d'occupation projetée pendant le drag : barre fantôme + delta -->
|
<!-- Aperçu d'occupation projetée pendant le drag : barre fantôme + delta -->
|
||||||
|
|
@ -658,36 +658,6 @@
|
||||||
</div>
|
</div>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-menu>
|
</q-menu>
|
||||||
|
|
||||||
<!-- Menu « jobs de la cellule » : clic sur le progressbar → détail + réordonner / re-prioriser -->
|
|
||||||
<q-menu v-model="cellJobsMenu.show" :target="cellJobsMenu.target" anchor="bottom left" self="top left" max-height="80vh">
|
|
||||||
<div style="width:340px;padding:6px 8px" @click.stop @mousedown.stop>
|
|
||||||
<div class="row items-center q-mb-xs">
|
|
||||||
<div class="text-weight-bold ellipsis">{{ cellJobsMenu.tech && cellJobsMenu.tech.name }} — {{ cellJobsMenu.day && cellJobsMenu.day.dnum }}</div>
|
|
||||||
<q-space /><span class="text-caption text-grey-6">{{ cellJobsMenu.list.length }} job(s)</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="!cellJobsMenu.list.length" class="text-grey-6 q-pa-sm text-center">Aucun job assigné ce jour.</div>
|
|
||||||
<div v-for="(j, i) in cellJobsMenu.list" :key="j.name" class="cjm-row">
|
|
||||||
<div class="column" style="gap:0">
|
|
||||||
<q-btn flat dense round size="8px" icon="keyboard_arrow_up" :disable="i === 0" @click="moveCellJob(i, -1)" />
|
|
||||||
<q-btn flat dense round size="8px" icon="keyboard_arrow_down" :disable="i === cellJobsMenu.list.length - 1" @click="moveCellJob(i, 1)" />
|
|
||||||
</div>
|
|
||||||
<span class="cjm-ord">{{ i + 1 }}</span>
|
|
||||||
<span class="cjm-dot" :style="{ background: j.skill ? getTagColor(j.skill) : prioColor(j.priority) }"></span>
|
|
||||||
<div class="col" style="min-width:0">
|
|
||||||
<div class="ellipsis" style="font-size:12px;font-weight:500">{{ j.subject }}</div>
|
|
||||||
<div class="ellipsis" style="font-size:10px;color:#888">{{ j.start || '—' }} · {{ j.dur }}h<span v-if="j.customer"> · {{ j.customer }}</span><span v-if="j.skill"> · {{ j.skill }}</span></div>
|
|
||||||
</div>
|
|
||||||
<select :value="j.priority" @change="j.priority = $event.target.value" @click.stop class="cjm-prio" :style="{ borderColor: prioColor(j.priority) }">
|
|
||||||
<option value="urgent">Urgent</option><option value="high">Élevée</option><option value="medium">Moyenne</option><option value="low">Basse</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div v-if="cellJobsMenu.list.length" class="row items-center q-mt-xs">
|
|
||||||
<span class="text-caption text-grey-6">Flèches = ordre du tech · menu = priorité</span><q-space />
|
|
||||||
<q-btn dense unelevated size="sm" color="primary" :loading="cellJobsMenu.saving" label="Enregistrer" @click="saveCellOrder" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-menu>
|
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -986,25 +956,13 @@ function panelUp () { _panelDrag = null; document.removeEventListener('mousemove
|
||||||
// Réutilise les helpers de cellule (cellBands/cellBlocks/cellJobs/cellPct) → 0 nouvel appel réseau.
|
// Réutilise les helpers de cellule (cellBands/cellBlocks/cellJobs/cellPct) → 0 nouvel appel réseau.
|
||||||
const timelineDlg = reactive({ open: false, tech: null })
|
const timelineDlg = reactive({ open: false, tech: null })
|
||||||
function openTimeline (t) { timelineDlg.tech = t; timelineDlg.open = true }
|
function openTimeline (t) { timelineDlg.tech = t; timelineDlg.open = true }
|
||||||
// ── Menu « jobs de la cellule » : détail + réordonner / re-prioriser (clic sur le progressbar) ──
|
// (Clic sur le progressbar → gotoDispatch : on ouvre le timeline ÉDITABLE du tableau Dispatch, drag-drop + suppression,
|
||||||
const cellJobsMenu = reactive({ show: false, target: null, tech: null, day: null, list: [], saving: false })
|
// plutôt qu'un popup maison — réutilisation max + cohérence. Le réordonnancement/priorité se fait là-bas.)
|
||||||
function openCellJobs (t, d, ev) {
|
// Deep-link vers le tableau Dispatch focalisé sur la ressource + le jour cliqué (sinon 1er jour de la semaine).
|
||||||
cellJobsMenu.tech = t; cellJobsMenu.day = d
|
function gotoDispatch (t, dateIso) {
|
||||||
cellJobsMenu.list = cellJobs(t.id, d.iso).map(j => ({ ...j })) // copie ordonnée (route_order → priorité → heure)
|
|
||||||
cellJobsMenu.target = (ev && ev.currentTarget) || null
|
|
||||||
cellJobsMenu.show = true
|
|
||||||
}
|
|
||||||
function moveCellJob (i, dir) { const l = cellJobsMenu.list; const j = i + dir; if (j < 0 || j >= l.length) return; const [x] = l.splice(i, 1); l.splice(j, 0, x) }
|
|
||||||
async function saveCellOrder () {
|
|
||||||
const updates = cellJobsMenu.list.map((j, i) => ({ job: j.name, route_order: i + 1, priority: j.priority }))
|
|
||||||
cellJobsMenu.saving = true
|
|
||||||
try { const r = await roster.reorderJobs(updates); cellJobsMenu.show = false; await loadWeek(); $q.notify({ type: 'positive', message: (r.updated || 0) + ' job(s) réordonné(s)', timeout: 2000 }) } catch (e) { err(e) } finally { cellJobsMenu.saving = false }
|
|
||||||
}
|
|
||||||
// Deep-link vers le tableau Dispatch focalisé sur la ressource + son 1er jour avec jobs (sinon début de semaine).
|
|
||||||
function gotoDispatch (t) {
|
|
||||||
const q = {}
|
const q = {}
|
||||||
if (t) q.tech = t.id
|
if (t) q.tech = t.id
|
||||||
q.date = (timelineDays.value[0] && timelineDays.value[0].iso) || start.value
|
q.date = dateIso || (timelineDays.value[0] && timelineDays.value[0].iso) || start.value
|
||||||
router.push({ path: '/dispatch', query: q })
|
router.push({ path: '/dispatch', query: q })
|
||||||
}
|
}
|
||||||
const timelineDays = computed(() => {
|
const timelineDays = computed(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user