feat(platform): split trajectory replay and history query

This commit is contained in:
lingniu
2026-07-04 17:23:48 +08:00
parent a65db893d2
commit 747894ce1d
11 changed files with 88 additions and 53 deletions

View File

@@ -21,7 +21,7 @@ export default function App() {
const [activeVin, setActiveVin] = useState(initialVehicleKey);
const [analysisVin, setAnalysisVin] = useState(initialVehicleKey);
const [activeProtocol, setActiveProtocol] = useState(initialRoute.protocol ?? '');
const [historyTab, setHistoryTab] = useState(initialRoute.filters?.tab ?? 'location');
const [historyTab, setHistoryTab] = useState(initialRoute.filters?.tab ?? (initialRoute.page === 'history-query' ? 'raw' : 'location'));
const [vehicleFilters, setVehicleFilters] = useState<Record<string, string>>(
initialRoute.page === 'vehicles' ? vehicleFiltersFromRoute(initialRoute) : {}
);
@@ -29,7 +29,7 @@ export default function App() {
initialRoute.page === 'realtime' || initialRoute.page === 'map' ? realtimeFiltersFromRoute(initialRoute) : {}
);
const [historyFilters, setHistoryFilters] = useState<Record<string, string>>(
initialRoute.page === 'history' ? historyFiltersFromRoute(initialRoute) : {}
initialRoute.page === 'history' || initialRoute.page === 'history-query' ? historyFiltersFromRoute(initialRoute) : {}
);
const [mileageFilters, setMileageFilters] = useState<Record<string, string>>(
initialRoute.page === 'mileage' ? mileageFiltersFromRoute(initialRoute) : {}
@@ -104,7 +104,7 @@ export default function App() {
if (route.page === 'detail') {
setActiveVin(route.keyword);
}
if (route.page === 'history' || route.page === 'mileage') {
if (route.page === 'history' || route.page === 'history-query' || route.page === 'mileage') {
setAnalysisVin(route.keyword);
}
}
@@ -114,7 +114,7 @@ export default function App() {
if (route.page === 'realtime' || route.page === 'map') {
setRealtimeFilters(realtimeFiltersFromRoute(route));
}
if (route.page === 'history') {
if (route.page === 'history' || route.page === 'history-query') {
setHistoryFilters(historyFiltersFromRoute(route));
}
if (route.page === 'mileage') {
@@ -124,7 +124,7 @@ export default function App() {
setQualityFilters(qualityFiltersFromRoute(route));
}
setActiveProtocol(route.protocol ?? '');
setHistoryTab(route.filters?.tab ?? 'location');
setHistoryTab(route.filters?.tab ?? (route.page === 'history-query' ? 'raw' : 'location'));
};
window.addEventListener('hashchange', applyHashRoute);
return () => window.removeEventListener('hashchange', applyHashRoute);
@@ -143,9 +143,15 @@ export default function App() {
replaceHash(page, activeVin, activeProtocol);
return;
}
if (page === 'history' || page === 'mileage') {
if (page === 'history' || page === 'history-query' || page === 'mileage') {
if (page === 'history') {
replaceHistoryHash(historyFilters);
setHistoryTab('location');
replaceHistoryHash(historyFilters, 'location', 'history');
return;
}
if (page === 'history-query') {
setHistoryTab('raw');
replaceHistoryHash(historyFilters, 'raw', 'history-query');
return;
}
replaceMileageHash(mileageFilters);
@@ -226,16 +232,16 @@ export default function App() {
if (tab && tab !== 'location') {
routeFilters.tab = tab;
}
replaceHash('history', hasKeywordInput ? keyword : (keyword ?? analysisVin), protocol, routeFilters);
replaceHash(activePage === 'history-query' ? 'history-query' : 'history', hasKeywordInput ? keyword : (keyword ?? analysisVin), protocol, routeFilters);
};
const replaceHistoryHash = (filters: Record<string, string> = {}, tab = historyTab) => {
const replaceHistoryHash = (filters: Record<string, string> = {}, tab = historyTab, page: 'history' | 'history-query' = activePage === 'history-query' ? 'history-query' : 'history') => {
const { keyword, protocol, ...restFilters } = filters;
const routeFilters = { ...restFilters };
if (tab && tab !== 'location') {
routeFilters.tab = tab;
}
replaceHash('history', keyword ?? analysisVin, protocol ?? activeProtocol, routeFilters);
replaceHash(page, keyword ?? analysisVin, protocol ?? activeProtocol, routeFilters);
};
const updateMileageFilters = (filters: Record<string, unknown> = {}) => {
@@ -328,18 +334,19 @@ export default function App() {
const nextVin = nextFilters.keyword?.trim() || analysisVin;
const nextProtocol = nextFilters.protocol?.trim() ?? activeProtocol;
const nextTab = nextFilters.tab === 'raw' ? 'raw' : 'location';
const nextPage = nextTab === 'raw' ? 'history-query' : 'history';
setAnalysisVin(nextVin);
setActiveProtocol(nextProtocol);
setHistoryTab(nextTab);
setHistoryFilters({ ...nextFilters, keyword: nextVin, protocol: nextProtocol });
setActivePage('history');
setActivePage(nextPage);
const { keyword, protocol, ...restFilters } = nextFilters;
if (nextTab === 'raw') {
restFilters.tab = nextTab;
} else {
delete restFilters.tab;
}
replaceHash('history', keyword ?? nextVin, protocol ?? nextProtocol, restFilters);
replaceHash(nextPage, keyword ?? nextVin, protocol ?? nextProtocol, restFilters);
};
const openRawForVehicle = (vin: string, protocol?: string) => {
@@ -352,8 +359,8 @@ export default function App() {
setActiveProtocol(nextProtocol);
setHistoryTab('raw');
setHistoryFilters({ keyword: nextVin, protocol: nextProtocol });
setActivePage('history');
replaceHash('history', nextVin, nextProtocol, { tab: 'raw' });
setActivePage('history-query');
replaceHash('history-query', nextVin, nextProtocol, { tab: 'raw' });
};
const openRawWithFilters = (filters: Record<string, string> = {}) => {
@@ -367,9 +374,9 @@ export default function App() {
setActiveProtocol(nextProtocol);
setHistoryTab('raw');
setHistoryFilters({ ...nextFilters, keyword: nextVin, protocol: nextProtocol });
setActivePage('history');
setActivePage('history-query');
const { keyword, protocol, ...restFilters } = nextFilters;
replaceHash('history', keyword ?? nextVin, protocol ?? nextProtocol, { ...restFilters, tab: 'raw' });
replaceHash('history-query', keyword ?? nextVin, protocol ?? nextProtocol, { ...restFilters, tab: 'raw' });
};
const openRealtimeForVehicle = (vin: string, protocol?: string) => {
@@ -431,7 +438,8 @@ export default function App() {
map: <Realtime title="地图态势" description="以车辆服务为中心查看实时位置、在线状态、来源一致性和高德地图接入状态" onOpenVehicle={openVehicle} onOpenHistory={openHistoryForVehicle} onOpenQuality={openQuality} onFiltersChange={updateMapFilters} initialFilters={realtimeFilters} />,
realtime: <Realtime onOpenVehicle={openVehicle} onOpenHistory={openHistoryForVehicle} onOpenQuality={openQuality} onFiltersChange={updateRealtimeFilters} initialFilters={realtimeFilters} />,
detail: <VehicleDetail vin={activeVin} protocol={activeProtocol} platformRelease={platformRelease} onOpenRealtime={openRealtimeForVehicle} onOpenHistory={openHistoryForVehicle} onOpenRaw={openRawForVehicle} onOpenMileage={openMileageForVehicle} onOpenVehicles={openVehicles} onOpenQuality={openQuality} onOpenHistoryEvidence={openHistoryWithFilters} onOpenRawEvidence={openRawWithFilters} onQueryChange={updateVehicleDetailQuery} />,
history: <History initialVin={analysisVin} initialProtocol={activeProtocol} initialTab={historyTab} initialFilters={historyFilters} onFiltersChange={updateHistoryFilters} onOpenVehicle={openVehicle} onOpenMileage={openMileageWithFilters} onOpenRaw={openRawWithFilters} />,
history: <History mode="trajectory" initialVin={analysisVin} initialProtocol={activeProtocol} initialTab={historyTab} initialFilters={historyFilters} onFiltersChange={updateHistoryFilters} onOpenVehicle={openVehicle} onOpenMileage={openMileageWithFilters} onOpenRaw={openRawWithFilters} />,
'history-query': <History mode="query" initialVin={analysisVin} initialProtocol={activeProtocol} initialTab={historyTab} initialFilters={historyFilters} onFiltersChange={updateHistoryFilters} onOpenVehicle={openVehicle} onOpenMileage={openMileageWithFilters} onOpenRaw={openRawWithFilters} />,
mileage: <Mileage initialVin={analysisVin} initialProtocol={activeProtocol} initialFilters={mileageFilters} onFiltersChange={updateMileageFilters} onOpenVehicle={openVehicle} onOpenHistory={openHistoryWithFilters} onOpenRaw={openRawWithFilters} />,
quality: <Quality onOpenVehicle={openVehicle} onOpenRealtime={openRealtime} onOpenHistory={openHistoryWithFilters} onOpenRaw={openRawWithFilters} onOpenMileage={openMileageWithFilters} onOpenNotificationRules={() => navigatePage('notification-rules')} onHealthLoaded={(health) => {
setLinkIssueCount(health.linkHealth.filter((item) => item.status !== 'ok').length);