perf: memoize dispatch timeline segments + load/capacity as computed Maps

Before: techDayJobsWithTravel(tech), periodLoadH(tech), techPeriodCapacityH(tech)
were called as functions in the template v-for — recalculated on EVERY render
for every tech (10 techs × 3 functions = 30 expensive recomputations per render).

After: Pre-computed as Vue computed Maps (segmentsMap, loadMap, capMap) that
only recompute when their reactive dependencies actually change. Template
reads from map[tech.id] — instant O(1) lookup, no recalculation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-04-08 18:24:16 -04:00
parent fd326ac52e
commit a9f8d0c7bf

View File

@ -155,6 +155,23 @@ const hourTicks = computed(() => {
const isCalView = computed(() => currentView.value === 'week')
const unassignDropActive = ref(false)
// Pre-compute expensive per-tech data (memoized avoids recalculating on every render)
const segmentsMap = computed(() => {
const map = {}
for (const tech of filteredResources.value) map[tech.id] = techDayJobsWithTravel(tech)
return map
})
const loadMap = computed(() => {
const map = {}
for (const tech of filteredResources.value) map[tech.id] = periodLoadH(tech)
return map
})
const capMap = computed(() => {
const map = {}
for (const tech of filteredResources.value) map[tech.id] = techPeriodCapacityH(tech)
return map
})
const { pushUndo, performUndo } = useUndo(store, invalidateRoutes)
const smartAssign = (job, newTechId, dateStr) => store.smartAssign(job.id, newTechId, dateStr)
@ -501,8 +518,8 @@ provide('onRenameTag', onRenameTag)
provide('onDeleteTag', onDeleteTag)
provide('selectedJob', selectedJob)
provide('hoveredJobId', hoveredJobId)
provide('periodLoadH', periodLoadH)
provide('techPeriodCapacityH', techPeriodCapacityH)
provide('periodLoadH', (tech) => loadMap.value[tech.id] ?? 0)
provide('techPeriodCapacityH', (tech) => capMap.value[tech.id] ?? 8)
provide('techDayEndH', techDayEndH)
provide('isJobMultiSelected', isJobMultiSelected)
provide('btColW', btColW)
@ -766,7 +783,7 @@ onUnmounted(() => { document.removeEventListener('keydown', onKeyDown); document
Aucune ressource. <button class="sbf-primary-btn" style="display:inline-block;margin-left:0.75rem" @click="clearFilters">Réinitialiser</button>
</div>
<TimelineRow v-for="tech in filteredResources" :key="tech.id"
:tech="tech" :segments="techDayJobsWithTravel(tech)"
:tech="tech" :segments="segmentsMap[tech.id] || []"
:hour-ticks="hourTicks" :total-w="totalW" :px-per-hr="pxPerHr"
:h-start="H_START" :h-end="H_END" :row-h="ROW_H"
:is-selected="selectedTechId===tech.id"