feat: unify track and telemetry workbenches

This commit is contained in:
lingniu
2026-07-19 06:29:55 +08:00
parent 4bd1ad8a85
commit f2fe5404d9
6 changed files with 146 additions and 25 deletions

View File

@@ -3,7 +3,7 @@ import {
IconChevronLeft, IconChevronRight, IconClose, IconDownload, IconEyeClosed,
IconEyeOpened, IconList, IconMapPin, IconPause, IconPlay, IconRefresh, IconSearch
} from '@douyinfe/semi-icons';
import { Button, Card, Descriptions, Empty, Input, List, Select, SideSheet, Slider, Tag } from '@douyinfe/semi-ui';
import { Button, Card, Descriptions, Empty, Input, List, Select, Slider, Tag } from '@douyinfe/semi-ui';
import { FormEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { api } from '../../api/client';
@@ -19,10 +19,10 @@ import { VehicleCandidateList } from '../shared/VehicleCandidateList';
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { WorkspaceSideSheet } from '../shared/WorkspaceSideSheet';
import { QUERY_MEMORY } from '../queryPolicy';
import { monitorReturnFromParams, preserveMonitorReturn } from '../routing/monitorContext';
import { useMobileLayout } from '../hooks/useMobileLayout';
import { useSideSheetA11y } from '../hooks/useSideSheetA11y';
const speedOptions = [0.5, 1, 2, 4] as const;
type PlaybackSpeed = (typeof speedOptions)[number];
@@ -309,7 +309,6 @@ export default function TrackPage() {
const [queryCollapsed, setQueryCollapsed] = useState(() => Boolean(criteria.keyword));
const animationRef = useRef<number>();
const lastFrameRef = useRef(0);
useSideSheetA11y(mobileLayout && !railCollapsed, '.v2-track-detail-sidesheet', 'v2-track-detail-sheet', '轨迹查询与明细', '关闭轨迹查询与明细');
const params = useMemo(() => {
const next = new URLSearchParams({ keyword: criteria.keyword, maxPoints: '1600' });
@@ -394,19 +393,31 @@ export default function TrackPage() {
};
const progress = points.length > 1 ? boundedIndex / (points.length - 1) * 100 : 0;
const trackRail = <TrackRail draft={draft} track={track} loading={query.isFetching} activeStopIndexes={activeStopIndexes} activeEventIndexes={activeEventIndexes} tab={panelTab} queryCollapsed={queryCollapsed} onDraft={setDraft} onSubmit={submit} onTab={setPanelTab} onSelectIndex={selectRailIndex} onToggleQuery={() => setQueryCollapsed((value) => !value)} onCollapse={collapseRail} />;
const mobileSheetTitle = track?.plate || draft.keyword.trim() || '轨迹查询与明细';
const mobileSheetDescription = track
? `${number(track.summary.distanceKm)} km · ${track.stops.length} 个停留 · ${track.events.length} 个事件`
: '选择车辆和时间范围';
const mobileSheetBadge = query.isFetching
? '读取中'
: track
? `${track.points.length.toLocaleString('zh-CN')}`
: '待查询';
return <div className={`v2-track-page${mobileLayout ? ' is-mobile-layout' : ''}${railCollapsed ? ' is-rail-collapsed' : ''}${monitorReturn ? ' has-monitor-return' : ''}`}>
<MonitorReturnBar />
{mobileLayout ? <SideSheet
{mobileLayout ? <WorkspaceSideSheet
className="v2-track-detail-sidesheet"
variant="editor"
visible={!railCollapsed}
ariaLabel="轨迹查询与明细"
placement="bottom"
height={mobileTrackSheetHeight(track, queryCollapsed, panelTab)}
aria-label="轨迹查询与明细"
title={<div className="v2-track-detail-sheet-title"><strong></strong><span>{track ? `${number(track.summary.distanceKm)} km · ${track.stops.length} 个停留 · ${track.events.length} 个事件` : '选择车辆和时间范围'}</span></div>}
footer={null}
title={mobileSheetTitle}
description={mobileSheetDescription}
badge={mobileSheetBadge}
badgeColor={query.isFetching ? 'blue' : track ? 'green' : 'grey'}
onCancel={collapseRail}
>{trackRail}</SideSheet> : trackRail}
>{trackRail}</WorkspaceSideSheet> : trackRail}
<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} />