feat(monitor): preserve investigation context

This commit is contained in:
lingniu
2026-07-16 17:08:54 +08:00
parent 38b056f5f1
commit 1cfc9c2bdd
17 changed files with 426 additions and 37 deletions

View File

@@ -10,7 +10,9 @@ import type { TrackPlaybackEvent, TrackPlaybackResponse, VehicleRow } from '../.
import { buildTrackRailSelection, downloadTrackCsv, formatDuration, sampledEventIndex, TRACK_ADDRESS_SETTLE_MS, trackAddressCoordinate, trackPlaybackInterval, type TrackAddressCoordinate } from '../domain/track';
import { TrackMap } from '../map/TrackMap';
import { InlineError } from '../shared/AsyncState';
import { MonitorReturnBar } from '../shared/MonitorReturnBar';
import { QUERY_MEMORY } from '../queryPolicy';
import { monitorReturnFromParams, preserveMonitorReturn } from '../routing/monitorContext';
const speedOptions = [0.5, 1, 2, 4] as const;
type PlaybackSpeed = (typeof speedOptions)[number];
@@ -188,6 +190,7 @@ const SegmentRail = memo(function SegmentRail({ track, onSelectIndex }: { track:
export default function TrackPage() {
const [searchParams, setSearchParams] = useSearchParams();
const monitorReturn = monitorReturnFromParams(searchParams);
const fallback = useMemo(defaultTrackWindow, []);
const routeKey = searchParams.toString();
const criteria = useMemo<Draft>(() => {
@@ -273,8 +276,8 @@ export default function TrackPage() {
if (next.dateFrom) url.set('dateFrom', next.dateFrom);
if (next.dateTo) url.set('dateTo', next.dateTo);
if (next.protocol) url.set('protocol', next.protocol);
setSearchParams(url, { replace: true });
}, [draft, setSearchParams]);
setSearchParams(preserveMonitorReturn(url, monitorReturn), { replace: true });
}, [draft, monitorReturn, setSearchParams]);
const selectIndex = useCallback((index: number) => { setPlaying(false); setActiveIndex(Math.max(0, Math.min(points.length - 1, index))); }, [points.length]);
const collapseRail = useCallback(() => setRailCollapsed(true), []);
const togglePlayback = () => {
@@ -286,6 +289,7 @@ export default function TrackPage() {
const progress = points.length > 1 ? boundedIndex / (points.length - 1) * 100 : 0;
return <div className={`v2-track-page${railCollapsed ? ' is-rail-collapsed' : ''}`}>
<MonitorReturnBar />
<TrackRail draft={draft} track={track} activeStopIndexes={activeStopIndexes} activeEventIndexes={activeEventIndexes} tab={panelTab} onDraft={setDraft} onSubmit={submit} onTab={setPanelTab} onSelectIndex={selectIndex} onCollapse={collapseRail} />
<section className="v2-track-stage">
<TrackMap points={points} stops={track?.stops ?? []} activeIndex={boundedIndex} showStops={showStops} follow={follow} followDurationMs={playing ? Math.max(40, trackPlaybackInterval(playbackSpeed) - 10) : 180} onSelectIndex={selectIndex} onFollowChange={setFollow} />