diff --git a/src/views/MonitorView/MonitorView.vue b/src/views/MonitorView/MonitorView.vue index 2ea8075..42e2e2e 100644 --- a/src/views/MonitorView/MonitorView.vue +++ b/src/views/MonitorView/MonitorView.vue @@ -137,6 +137,7 @@ const { }) function onPageHide() { + stopDevicePolling() disposeLive({ keepalive: true }) } @@ -146,6 +147,62 @@ const controlExpanded = ref(false) const dockStatusOpen = ref(false) const selectedDockIds = reactive(new Set()) +const DEVICE_POLL_MS = 5000 +let devicePollTimer = null +let devicePollInflight = null +let devicePollGen = 0 +let monitorDisposed = false + +function clearDevicePollTimer() { + window.clearInterval(devicePollTimer) + devicePollTimer = null +} + +async function pollDevices({ toastOnSuccess = false } = {}) { + if (monitorDisposed) return + if (devicePollInflight) return + const gen = devicePollGen + devicePollInflight = devices.load() + try { + await devicePollInflight + if (monitorDisposed || gen !== devicePollGen) return + if (selectedId.value && !devices.record(selectedId.value)) clearSelection() + selectedDockIds.forEach((id) => { + if (!devices.docks.some((dock) => dock.id === id)) selectedDockIds.delete(id) + }) + syncMarkers() + if (toastOnSuccess) ui.toast('设备状态已刷新') + } catch (e) { + if (monitorDisposed || gen !== devicePollGen) return + if (toastOnSuccess) ui.toast(e.message || '刷新设备状态失败') + else console.warn('[monitor] device poll failed', e) + } finally { + devicePollInflight = null + } +} + +function startDevicePolling() { + clearDevicePollTimer() + if (monitorDisposed || document.visibilityState === 'hidden') return + devicePollTimer = window.setInterval(() => { + void pollDevices() + }, DEVICE_POLL_MS) +} + +function stopDevicePolling() { + clearDevicePollTimer() +} + +function onDevicePollVisibility() { + if (monitorDisposed) return + if (document.visibilityState === 'hidden') { + stopDevicePolling() + return + } + void pollDevices() + startDevicePolling() +} + let mapInstance = null let layersReady = false let pendingLoadHandler = null @@ -660,8 +717,10 @@ function teardownMap() { } onMounted(async () => { + monitorDisposed = false window.addEventListener('pagehide', onPageHide) window.addEventListener('keydown', onGlobalKeydown) + document.addEventListener('visibilitychange', onDevicePollVisibility) try { await devices.load() if (route.query.deviceId && devices.record(route.query.deviceId)) selectedId.value = String(route.query.deviceId) @@ -670,6 +729,7 @@ onMounted(async () => { } catch (e) { ui.toast(e.message || '加载设备失败') } + startDevicePolling() try { await setupMap() } catch (e) { @@ -678,6 +738,10 @@ onMounted(async () => { }) onUnmounted(() => { + monitorDisposed = true + devicePollGen += 1 + stopDevicePolling() + document.removeEventListener('visibilitychange', onDevicePollVisibility) window.removeEventListener('pagehide', onPageHide) window.removeEventListener('keydown', onGlobalKeydown) closeCommandProgress() @@ -1042,19 +1106,10 @@ function onGlobalKeydown(event) { async function reload() { - try { - await devices.load() - if (selectedId.value && !devices.record(selectedId.value)) clearSelection() - selectedDockIds.forEach((id) => { - if (!devices.docks.some((dock) => dock.id === id)) selectedDockIds.delete(id) - }) - syncMarkers() - if (selectedId.value) flyToSelected() - else resetOverviewCamera() - ui.toast('设备状态已刷新') - } catch (e) { - ui.toast(e.message || '刷新设备状态失败') - } + await pollDevices({ toastOnSuccess: true }) + if (monitorDisposed) return + if (selectedId.value) flyToSelected() + else resetOverviewCamera() } const groupedDocks = computed(() =>