diff --git a/src/hooks/usePlaybackWebSocket.ts b/src/hooks/usePlaybackWebSocket.ts index dd27c97..bf1eb56 100644 --- a/src/hooks/usePlaybackWebSocket.ts +++ b/src/hooks/usePlaybackWebSocket.ts @@ -151,9 +151,8 @@ export function usePlaybackWebSocket( }; const play = () => { - // 双重保险:在播放前,强制发送一次SEEK指令,确保后端从正确的时间点开始。 - // 这可以防止因后端状态不同步或时序问题导致的播放位置错乱。 - sendCommand(`SEEK:${currentTime.value}`); + // [修复] 移除冗余的 SEEK 指令,避免与后端的时序问题导致日期跳转。 + // SEEK 操作应仅由用户显式触发(如拖动滑块或更改日期)。 sendCommand('PLAY'); isPlaying.value = true; }; diff --git a/src/pages/movement-supervision.vue b/src/pages/movement-supervision.vue index 8a3b18c..f9213fc 100644 --- a/src/pages/movement-supervision.vue +++ b/src/pages/movement-supervision.vue @@ -107,6 +107,7 @@ let doorMockTick = 0; const leftSiderEl = shallowRef(); const isPlaybackControllerVisible = ref(true); const selectedDate = ref(); +const isSceneLoading = ref(false); const playback = usePlaybackWebSocket(editor, async () => { // [关键修复] 只有在收到第一帧机器人数据后才初始化机器人图元 @@ -129,9 +130,14 @@ watch(mode, async (newMode) => { watch(playback.sceneJson, async (newJson) => { if (newJson) { - await editor.value?.load(newJson); - // [移除] 不再需要在这里初始化机器人,交由 onFirstAmrData 回调处理 - // await editor.value?.initRobots(); + isSceneLoading.value = true; + try { + await editor.value?.load(newJson); + // [移除] 不再需要在这里初始化机器人,交由 onFirstAmrData 回调处理 + // await editor.value?.initRobots(); + } finally { + isSceneLoading.value = false; + } } }); @@ -174,9 +180,11 @@ onUnmounted(() => { }); watch(selectedDate, (date) => { + if (isSceneLoading.value) return; if (date) { const startOfDayTimestamp = date.startOf('day').valueOf(); - playback.seek(startOfDayTimestamp); + // [修复] 确保传入的时间戳没有毫秒 + playback.seek(Math.floor(startOfDayTimestamp / 1000) * 1000); // The total duration is now relative to the start of the day playback.totalDuration.value = 24 * 60 * 60 * 1000; // Set current time to the beginning of the selected day for the slider @@ -189,7 +197,8 @@ const handleSeek = (relativeTime: number) => { const absoluteTimestamp = relativeTime + selectedDate.value.startOf('day').valueOf(); // 乐观更新,立即将前端时间状态同步到用户选择的时间点 playback.currentTime.value = absoluteTimestamp; - playback.seek(absoluteTimestamp); + // [修复] 确保传入的时间戳没有毫秒 + playback.seek(Math.floor(absoluteTimestamp / 1000) * 1000); } }; @@ -207,13 +216,6 @@ watch(playback.currentTime, (newTimestamp) => { } }); -watch(playback.sceneJson, async (newJson) => { - if (newJson) { - await editor.value?.load(newJson); - // [移除] 不再需要在这里初始化机器人,交由 onFirstAmrData 回调处理 - // await editor.value?.initRobots(); - } -}); //#endregion @@ -456,10 +458,12 @@ onMounted(async () => { } else { console.log('[回放模式] 初始化回放模式'); playback.connect(props.sid); - // [调试代码] 自动设置回放日期和时间 - const debugDate = dayjs('2025-09-28 09:00:00'); + // [修复] 恢复调试用的日期设置,并更新为指定时间,以确保回放组件可见 + const debugDate = dayjs('2025-10-29 14:50:00'); selectedDate.value = debugDate; - playback.seek(debugDate.valueOf()); + // 直接 seek 到指定的时间点,而不是当天的开始 + // [修复] 确保传入的时间戳没有毫秒 + playback.seek(Math.floor(debugDate.valueOf() / 1000) * 1000); } // [移除] 不再需要在这里初始化机器人,交由 onFirstAmrData 回调处理