diff --git a/apps/ops/src/composables/useMap.js b/apps/ops/src/composables/useMap.js index 417d2b6..1bb8269 100644 --- a/apps/ops/src/composables/useMap.js +++ b/apps/ops/src/composables/useMap.js @@ -411,6 +411,19 @@ export function useMap (deps) { localStorage.setItem('sbv2-mapW', String(mapPanelW.value)) mapVisible.value = true } + // Live GPS wins over the ERPNext-saved home base, so the rep + // sees where the tech actually IS right now if Traccar reports + // them online. Fall back to home coords when offline. We + // flyTo (animated pan+zoom) so the dispatcher gets a clear + // visual cue, instead of a hard jump. + const pos = tech.gpsCoords || tech.coords + if (pos && map && Number.isFinite(pos[0]) && Number.isFinite(pos[1])) { + // Defer one tick so the map panel has time to be visible + // and `map.resize()` has run before the camera animation. + nextTick(() => { + try { map.flyTo({ center: pos, zoom: Math.max(map.getZoom(), 12), speed: 1.2, essential: true }) } catch (_e) {} + }) + } } if (map) { drawMapMarkers(); drawSelectedRoute() } } diff --git a/apps/ops/src/pages/DispatchPage.vue b/apps/ops/src/pages/DispatchPage.vue index 51dba03..eb5d709 100644 --- a/apps/ops/src/pages/DispatchPage.vue +++ b/apps/ops/src/pages/DispatchPage.vue @@ -372,7 +372,12 @@ const bookingOverlay = ref(null) const woModalOpen = ref(false) const woModalCtx = ref({}) const publishModalOpen = ref(false) -const nlpVisible = ref(true) // NLP bar always visible +// NLP bar is hidden by default; toggled from the ⋯ menu (Assistant IA). +// Showing it eagerly bloats the header on narrow laptops and the +// example placeholder text added visual noise. Persist the user's +// preference in localStorage so power users keep it open if they want. +const nlpVisible = ref(localStorage.getItem('sbv2-nlp-visible') === '1') +watch(nlpVisible, v => localStorage.setItem('sbv2-nlp-visible', v ? '1' : '0')) const draftCount = computed(() => store.jobs.filter(j => !j.published && j.status !== 'completed' && j.status !== 'cancelled').length) function onNlpAction (result) { @@ -397,6 +402,7 @@ const periodEndStr = computed(() => { }) const onPublished = jobNames => store.publishJobsLocal(jobNames) const moreMenuOpen = ref(false) // ⋯ dropdown in the top toolbar (right side) +const viewsMenuOpen = ref(false) // "Vue principale ▾" dropdown (left side) const gpsSettingsOpen = ref(false) const gpsShowInactive = ref(false) const gpsFilteredTechs = computed(() => @@ -961,6 +967,7 @@ function onKeyDown (e) { filterPanelOpen.value = false; projectsPanelOpen.value = false selectedJob.value = null; multiSelect.value = [] moreMenuOpen.value = false + viewsMenuOpen.value = false if (geoFixTech.value) cancelTechGeoFix() } if (e.key === 'z' && (e.metaKey || e.ctrlKey) && !e.shiftKey) { @@ -1174,7 +1181,7 @@ onMounted(async () => { loadOffers() loadPresets() document.addEventListener('keydown', onKeyDown) - document.addEventListener('click', () => { closeCtxMenu(); assistCtx.value = null; techCtx.value = null; moreMenuOpen.value = false }) + document.addEventListener('click', () => { closeCtxMenu(); assistCtx.value = null; techCtx.value = null; moreMenuOpen.value = false; viewsMenuOpen.value = false }) if (!document.getElementById('mapbox-css')) { const l = document.createElement('link'); l.id='mapbox-css'; l.rel='stylesheet' l.href='https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css'; document.head.appendChild(l) @@ -1225,9 +1232,23 @@ onUnmounted(() => { -
- - + +
+ +
+ +
+ +