diff --git a/vehicle-data-platform/apps/web/src/v2/map/TrackMap.test.tsx b/vehicle-data-platform/apps/web/src/v2/map/TrackMap.test.tsx index 013912a9..8f451d98 100644 --- a/vehicle-data-platform/apps/web/src/v2/map/TrackMap.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/map/TrackMap.test.tsx @@ -98,6 +98,68 @@ afterEach(() => { mapInstances.length = 0; }); +test('defers the map runtime until valid track data exists and releases it when data is cleared', async () => { + window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' }; + const load = vi.fn(async () => amapMock()); + window.AMapLoader = { load }; + const view = render( undefined} + onFollowChange={() => undefined} + />); + + expect(load).not.toHaveBeenCalled(); + expect(mapInstances).toHaveLength(0); + expect(view.container.querySelector('.v2-map-state')).not.toBeInTheDocument(); + + view.rerender( undefined} + onFollowChange={() => undefined} + />); + await waitFor(() => expect(mapInstances).toHaveLength(1)); + expect(load).toHaveBeenCalledTimes(1); + + view.rerender( undefined} + onFollowChange={() => undefined} + />); + await waitFor(() => expect(mapDestroy).toHaveBeenCalledTimes(1)); + expect(mapInstances).toHaveLength(1); +}); + +test('does not initialize the map for rows without a valid coordinate', () => { + window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' }; + const load = vi.fn(async () => amapMock()); + window.AMapLoader = { load }; + render( undefined} + onFollowChange={() => undefined} + />); + + expect(load).not.toHaveBeenCalled(); + expect(mapInstances).toHaveLength(0); + expect(document.body).toHaveTextContent('当前轨迹没有可展示的有效坐标'); +}); + test('uses the playback cadence for follow animation and advances the passed path', async () => { window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' }; window.AMapLoader = { load: vi.fn(async () => amapMock()) }; diff --git a/vehicle-data-platform/apps/web/src/v2/map/TrackMap.tsx b/vehicle-data-platform/apps/web/src/v2/map/TrackMap.tsx index 2e3022d7..27013374 100644 --- a/vehicle-data-platform/apps/web/src/v2/map/TrackMap.tsx +++ b/vehicle-data-platform/apps/web/src/v2/map/TrackMap.tsx @@ -28,8 +28,9 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow const pathRef = useRef<[number, number][]>([]); const selectRef = useRef(onSelectIndex); const followChangeRef = useRef(onFollowChange); - const [state, setState] = useState<'loading' | 'ready' | 'fallback' | 'error'>('loading'); const valid = useMemo(() => points.map((point, index) => ({ point, index })).filter(({ point }) => isValidAMapCoordinate(point.longitude, point.latitude)), [points]); + const hasValidPoints = valid.length > 0; + const [state, setState] = useState<'idle' | 'loading' | 'ready' | 'fallback' | 'error'>(() => hasValidPoints ? 'loading' : 'idle'); const passedCountByPoint = useMemo(() => { const counts = new Uint16Array(points.length); let validIndex = 0; @@ -44,6 +45,8 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow useEffect(() => { followChangeRef.current = onFollowChange; }, [onFollowChange]); useEffect(() => { + if (!hasValidPoints) { setState('idle'); return; } + setState('loading'); if (!containerRef.current || !isAMapConfigured(getAMapConfig())) { setState('fallback'); return; } let cancelled = false; let mapInstance: AMapMap | undefined; @@ -81,7 +84,7 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow mapRef.current = null; amapRef.current = null; }; - }, []); + }, [hasValidPoints]); useEffect(() => { const AMap = amapRef.current; @@ -144,8 +147,9 @@ export function TrackMap({ points, stops, activeIndex, showStops, follow, follow return
- {state !== 'ready' ?
+ {state !== 'ready' && (state !== 'idle' || points.length > 0) ?
{state === 'loading' ? <>轨迹地图加载中 : null} + {state === 'idle' ? '当前轨迹没有可展示的有效坐标' : null} {state === 'fallback' ? `地图未配置,已载入 ${valid.length} 个有效轨迹点` : null} {state === 'error' ? '地图加载失败,请检查高德地图配置' : null}
: null}