Browse Source

fix: 清理地图 pending 监听并加固 style 守卫

Monitor teardown 取消 load/style.load;Tasks ensure/sync 校验 isStyleLoaded;selected 改 0/1;MapLayer 清理 init timeout。
main
xiaosi 3 weeks ago
parent
commit
3f322b2c1e
  1. 8
      src/layout/MapLayer.vue
  2. 41
      src/views/MonitorView/MonitorView.vue
  3. 11
      src/views/TasksView/TasksView.vue

8
src/layout/MapLayer.vue

@ -7,6 +7,7 @@ import mapHelper from '@/core/mapHelper'
import 'mapbox-gl/dist/mapbox-gl.css'
let map = null
let initTimer = null
function initMap() {
const tk = mapConfig.token
@ -31,7 +32,8 @@ function initMap() {
}
onMounted(() => {
setTimeout(() => {
initTimer = setTimeout(() => {
initTimer = null
try {
initMap()
} catch (error) {
@ -42,6 +44,10 @@ onMounted(() => {
})
onUnmounted(() => {
if (initTimer != null) {
clearTimeout(initTimer)
initTimer = null
}
if (map) {
map.remove()
commonRefs.removeRef('map')

41
src/views/MonitorView/MonitorView.vue

@ -405,6 +405,8 @@ const selectedDockIds = reactive(new Set())
let mapInstance = null
let layersReady = false
let pendingLoadHandler = null
let pendingStyleHandler = null
const mapMode = ref('satellite')
const mapScaleText = ref('2 km')
let suppressMapClick = false
@ -460,7 +462,7 @@ function devicesFeatureCollection() {
assetId: String(asset.id),
name: asset.name || '',
kind: asset.type,
selected,
selected: selected ? 1 : 0,
color: statusColor(asset.statusClass),
radius: asset.type === 'drone' ? (selected ? 10 : 8) : (selected ? 12 : 10),
},
@ -520,7 +522,7 @@ function ensureMonitorLayers() {
'circle-stroke-color': '#fff',
'circle-stroke-width': [
'case',
['to-boolean', ['get', 'selected']],
['==', ['get', 'selected'], 1],
3,
2,
],
@ -605,7 +607,25 @@ function syncBindingLine() {
if (src) src.setData(bindingFeatureCollection())
}
function cancelPendingMapHandlers() {
if (!mapInstance) {
pendingLoadHandler = null
pendingStyleHandler = null
return
}
if (pendingLoadHandler) {
mapInstance.off('load', pendingLoadHandler)
pendingLoadHandler = null
}
if (pendingStyleHandler) {
mapInstance.off('style.load', pendingStyleHandler)
pendingStyleHandler = null
}
}
function rebuildAfterStyle() {
pendingStyleHandler = null
if (!mapInstance) return
layersReady = false
ensureMonitorLayers()
syncMarkers()
@ -623,8 +643,13 @@ function setMapMode(mode) {
}
mapMode.value = mode
layersReady = false
if (pendingStyleHandler) {
mapInstance.off('style.load', pendingStyleHandler)
pendingStyleHandler = null
}
mapInstance.setStyle(MAP_STYLES[mode] || MAP_STYLES.satellite)
mapInstance.once('style.load', rebuildAfterStyle)
pendingStyleHandler = rebuildAfterStyle
mapInstance.once('style.load', pendingStyleHandler)
}
function fitAll() {
@ -698,6 +723,8 @@ async function setupMap() {
mapHelper.toggleMapMode({ is2D: true })
const onReady = () => {
pendingLoadHandler = null
if (!mapInstance) return
ensureMonitorLayers()
syncMarkers()
if (selectedId.value) flyToSelected()
@ -705,8 +732,12 @@ async function setupMap() {
updateMapScale()
}
cancelPendingMapHandlers()
if (map.isStyleLoaded()) onReady()
else map.once('load', onReady)
else {
pendingLoadHandler = onReady
map.once('load', pendingLoadHandler)
}
map.on('click', onMapClick)
map.on('zoom', updateMapScale)
@ -714,6 +745,7 @@ async function setupMap() {
}
function teardownMap() {
cancelPendingMapHandlers()
if (mapInstance) {
mapInstance.off('click', onMapClick)
mapInstance.off('zoom', updateMapScale)
@ -721,6 +753,7 @@ function teardownMap() {
clearMonitorLayers()
}
mapInstance = null
layersReady = false
commonRefs.clearPendingList('map')
}

11
src/views/TasksView/TasksView.vue

@ -479,6 +479,7 @@ function clearTaskLayers(map) {
}
function ensureTaskLayers(map) {
if (!map || !map.isStyleLoaded()) return false
if (!map.getSource(ROUTE_SOURCE)) {
map.addSource(ROUTE_SOURCE, {
type: 'geojson',
@ -529,11 +530,12 @@ function ensureTaskLayers(map) {
paint: { 'text-color': '#fff' },
})
}
return true
}
function syncRouteLayer() {
if (!routeMapInstance) return
ensureTaskLayers(routeMapInstance)
if (!routeMapInstance || !routeMapInstance.isStyleLoaded()) return
if (!ensureTaskLayers(routeMapInstance)) return
const coords = routePoints.value
.map((p) => [Number(p.longitude), Number(p.latitude)])
.filter(([lon, lat]) => Number.isFinite(lon) && Number.isFinite(lat))
@ -608,17 +610,18 @@ async function attachRouteMap() {
mapHelper.replaceMapContainer(host)
mapHelper.toggleMapMode({ is2D: true })
routeMapAttached = true
routeMapReady.value = true
routeMapReady.value = false
const boot = () => {
pendingStyleHandler = null
if (!routeMapAttached || routeMapInstance !== map) return
clearTaskLayers(map)
ensureTaskLayers(map)
if (!ensureTaskLayers(map)) return
map.on('click', onRouteMapClick)
map.on('mousemove', onRouteMapMove)
const c = map.getCenter()
routeCursor.value = formatCoord(c.lng, c.lat)
routeMapReady.value = true
requestAnimationFrame(() => {
map.resize()
syncRouteLayer()

Loading…
Cancel
Save