From 67ebf89db9b834ec45fd5b514864ddf092adaf5f Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 4 Jul 2026 14:09:27 +0800 Subject: [PATCH] feat(platform): link mileage statistics summary --- .../apps/web/src/pages/Mileage.tsx | 22 ++++++++++++++++--- .../apps/web/src/test/App.test.tsx | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/pages/Mileage.tsx b/vehicle-data-platform/apps/web/src/pages/Mileage.tsx index 42004247..4e4d8a94 100644 --- a/vehicle-data-platform/apps/web/src/pages/Mileage.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Mileage.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import { api } from '../api/client'; import type { DailyMileageRow, MileageSummary } from '../api/types'; import { PageHeader } from '../components/PageHeader'; +import { buildAppHash } from '../domain/appRoute'; import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport'; const emptySummary: MileageSummary = { @@ -111,18 +112,26 @@ function exportFileName(filters: Record) { return `daily-mileage-${keyword}-${protocol}.csv`; } +function appURL(hash: string) { + return `${window.location.origin}${window.location.pathname}${hash}`; +} + function mileageSummaryText({ filters, summary, pageMileageTotal, anomalyCount, - peakMileage + peakMileage, + statisticsURL, + vehicleURL }: { filters: Record; summary: MileageSummary; pageMileageTotal: number; anomalyCount: number; peakMileage?: DailyMileageRow; + statisticsURL: string; + vehicleURL?: string; }) { const keyword = filters.keyword?.trim() || '全部车辆'; const protocol = filters.protocol?.trim() || '全部来源'; @@ -143,7 +152,9 @@ function mileageSummaryText({ `当前页里程:${formatKm(pageMileageTotal)} km`, `异常记录:${anomalyCount.toLocaleString()}`, `最大单日:${peak}`, - '统计口径:区间总值等于各日里程之和' + '统计口径:区间总值等于各日里程之和', + `统计查询:${statisticsURL}`, + ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -259,13 +270,18 @@ export function Mileage({ Toast.success(`已导出 ${rows.length} 条里程明细`); }; const copyStatisticsSummary = () => { + const vehicleURL = currentVehicleKeyword + ? appURL(buildAppHash({ page: 'detail', keyword: currentVehicleKeyword, protocol: currentProtocol })) + : undefined; copyText( mileageSummaryText({ filters, summary, pageMileageTotal, anomalyCount: anomalyRows.length, - peakMileage + peakMileage, + statisticsURL: appURL(window.location.hash || buildAppHash({ page: 'mileage', keyword: currentVehicleKeyword, protocol: currentProtocol })), + vehicleURL }), '统计摘要' ); diff --git a/vehicle-data-platform/apps/web/src/test/App.test.tsx b/vehicle-data-platform/apps/web/src/test/App.test.tsx index 0fcc0f05..f70aecd2 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -5698,6 +5698,8 @@ test('copies mileage statistics summary for operations reporting', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录:1')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('最大单日:粤A统计2 / 2026-07-02 / 100 km')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计口径:区间总值等于各日里程之和')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage?keyword=VIN-MILEAGE-COPY&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-MILEAGE-COPY&protocol=JT808')); }); test('exports current mileage page as CSV', async () => {