feat(platform): preserve customer time window in tasks
This commit is contained in:
@@ -445,13 +445,36 @@ export default function App() {
|
||||
replaceHash('mileage', keyword ?? nextVin, protocol ?? nextProtocol, restFilters);
|
||||
};
|
||||
|
||||
const currentCustomerTaskTimeWindow = () => {
|
||||
const candidates = activePage === 'mileage'
|
||||
? [mileageFilters, historyFilters, qualityFilters]
|
||||
: activePage === 'history' || activePage === 'history-query'
|
||||
? [historyFilters, mileageFilters, qualityFilters]
|
||||
: activePage === 'alert-events' || activePage === 'quality'
|
||||
? [qualityFilters, historyFilters, mileageFilters]
|
||||
: [historyFilters, mileageFilters, qualityFilters];
|
||||
for (const filters of candidates) {
|
||||
const dateFrom = filters.dateFrom?.trim();
|
||||
const dateTo = filters.dateTo?.trim();
|
||||
if (dateFrom || dateTo) {
|
||||
return {
|
||||
...(dateFrom ? { dateFrom } : {}),
|
||||
...(dateTo ? { dateTo } : {})
|
||||
};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
const openCustomerTask = (page: PageKey) => {
|
||||
const keyword = (activeVin || analysisVin).trim();
|
||||
const protocol = activeProtocol.trim();
|
||||
const timeWindow = currentCustomerTaskTimeWindow();
|
||||
if (!keyword) {
|
||||
navigatePage(page);
|
||||
return;
|
||||
}
|
||||
const scopedFilters = { keyword, protocol, ...timeWindow };
|
||||
if (page === 'map') {
|
||||
openMap({ keyword, protocol });
|
||||
return;
|
||||
@@ -461,19 +484,19 @@ export default function App() {
|
||||
return;
|
||||
}
|
||||
if (page === 'history') {
|
||||
openHistoryWithFilters({ keyword, protocol });
|
||||
openHistoryWithFilters(scopedFilters);
|
||||
return;
|
||||
}
|
||||
if (page === 'history-query') {
|
||||
openRawWithFilters({ keyword, protocol, tab: 'raw' });
|
||||
openRawWithFilters({ ...scopedFilters, tab: 'raw' });
|
||||
return;
|
||||
}
|
||||
if (page === 'mileage') {
|
||||
openMileageWithFilters({ keyword, protocol });
|
||||
openMileageWithFilters(scopedFilters);
|
||||
return;
|
||||
}
|
||||
if (page === 'alert-events' || page === 'quality') {
|
||||
openQuality({ keyword, protocol });
|
||||
openQuality(scopedFilters);
|
||||
return;
|
||||
}
|
||||
navigatePage(page);
|
||||
@@ -522,7 +545,9 @@ function qualityFiltersFromRoute(route: ReturnType<typeof parseAppHash>): Record
|
||||
return {
|
||||
...(route.keyword ? { keyword: route.keyword } : {}),
|
||||
...(route.protocol ? { protocol: route.protocol } : {}),
|
||||
...(route.filters?.issueType ? { issueType: route.filters.issueType } : {})
|
||||
...(route.filters?.issueType ? { issueType: route.filters.issueType } : {}),
|
||||
...(route.filters?.dateFrom ? { dateFrom: route.filters.dateFrom } : {}),
|
||||
...(route.filters?.dateTo ? { dateTo: route.filters.dateTo } : {})
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,23 @@ const emptySummary: MileageSummary = {
|
||||
averageMileagePerVin: 0
|
||||
};
|
||||
|
||||
function numberOrZero(value: unknown) {
|
||||
const numeric = Number(value);
|
||||
return Number.isFinite(numeric) ? numeric : 0;
|
||||
}
|
||||
|
||||
function normalizeMileageSummary(summary?: Partial<MileageSummary> | null): MileageSummary {
|
||||
return {
|
||||
...emptySummary,
|
||||
...(summary ?? {}),
|
||||
vehicleCount: numberOrZero(summary?.vehicleCount),
|
||||
recordCount: numberOrZero(summary?.recordCount),
|
||||
sourceCount: numberOrZero(summary?.sourceCount),
|
||||
totalMileageKm: numberOrZero(summary?.totalMileageKm),
|
||||
averageMileagePerVin: numberOrZero(summary?.averageMileagePerVin)
|
||||
};
|
||||
}
|
||||
|
||||
const emptyOnlineSummary: OnlineStatisticsSummary = {
|
||||
vehicleCount: 0,
|
||||
onlineVehicleCount: 0,
|
||||
@@ -940,7 +957,7 @@ export function Mileage({
|
||||
const loadSummary = (values: Record<string, string> = filters) => {
|
||||
setSummaryLoading(true);
|
||||
api.mileageSummary(mileageParams(values))
|
||||
.then((nextSummary) => setSummary(nextSummary ?? emptySummary))
|
||||
.then((nextSummary) => setSummary(normalizeMileageSummary(nextSummary)))
|
||||
.catch((error: Error) => Toast.error(error.message))
|
||||
.finally(() => setSummaryLoading(false));
|
||||
api.onlineStatisticsSummary(mileageParams(values))
|
||||
|
||||
@@ -6488,7 +6488,7 @@ test('shows vehicle context when opening detail from sidebar navigation', async
|
||||
});
|
||||
|
||||
test('applies protocol from shareable history hash to API requests', async () => {
|
||||
window.history.replaceState(null, '', '/#/history?keyword=%E7%B2%A4AG18312&protocol=JT808');
|
||||
window.history.replaceState(null, '', '/#/history?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03');
|
||||
const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input, init) => {
|
||||
const path = String(input);
|
||||
if (path.includes('/api/ops/health')) {
|
||||
@@ -6517,12 +6517,21 @@ test('applies protocol from shareable history hash to API requests', async () =>
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?'), undefined);
|
||||
});
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('protocol=JT808'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateFrom=2026-07-01'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('dateTo=2026-07-03'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/history/raw-frames/query', expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: expect.stringContaining('"protocol":"JT808"')
|
||||
}));
|
||||
expect(screen.getByText('当前车辆:粤AG18312')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('数据通道:JT808').length).toBeGreaterThan(0);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' }));
|
||||
expect(window.location.hash).toBe('#/mileage?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03');
|
||||
fireEvent.click(screen.getByRole('button', { name: '顶部数据导出' }));
|
||||
expect(window.location.hash).toBe('#/history-query?keyword=%E7%B2%A4AG18312&protocol=JT808&tab=raw&dateFrom=2026-07-01&dateTo=2026-07-03');
|
||||
fireEvent.click(await screen.findByRole('button', { name: '顶部告警事件正常' }));
|
||||
expect(window.location.hash).toBe('#/alert-events?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03');
|
||||
});
|
||||
|
||||
test('shows and clears current history filters while keeping vehicle scope', async () => {
|
||||
|
||||
Reference in New Issue
Block a user