feat(platform): link mileage statistics summary

This commit is contained in:
lingniu
2026-07-04 14:09:27 +08:00
parent a91eefd614
commit 67ebf89db9
2 changed files with 21 additions and 3 deletions

View File

@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
import { api } from '../api/client'; import { api } from '../api/client';
import type { DailyMileageRow, MileageSummary } from '../api/types'; import type { DailyMileageRow, MileageSummary } from '../api/types';
import { PageHeader } from '../components/PageHeader'; import { PageHeader } from '../components/PageHeader';
import { buildAppHash } from '../domain/appRoute';
import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport'; import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport';
const emptySummary: MileageSummary = { const emptySummary: MileageSummary = {
@@ -111,18 +112,26 @@ function exportFileName(filters: Record<string, string>) {
return `daily-mileage-${keyword}-${protocol}.csv`; return `daily-mileage-${keyword}-${protocol}.csv`;
} }
function appURL(hash: string) {
return `${window.location.origin}${window.location.pathname}${hash}`;
}
function mileageSummaryText({ function mileageSummaryText({
filters, filters,
summary, summary,
pageMileageTotal, pageMileageTotal,
anomalyCount, anomalyCount,
peakMileage peakMileage,
statisticsURL,
vehicleURL
}: { }: {
filters: Record<string, string>; filters: Record<string, string>;
summary: MileageSummary; summary: MileageSummary;
pageMileageTotal: number; pageMileageTotal: number;
anomalyCount: number; anomalyCount: number;
peakMileage?: DailyMileageRow; peakMileage?: DailyMileageRow;
statisticsURL: string;
vehicleURL?: string;
}) { }) {
const keyword = filters.keyword?.trim() || '全部车辆'; const keyword = filters.keyword?.trim() || '全部车辆';
const protocol = filters.protocol?.trim() || '全部来源'; const protocol = filters.protocol?.trim() || '全部来源';
@@ -143,7 +152,9 @@ function mileageSummaryText({
`当前页里程:${formatKm(pageMileageTotal)} km`, `当前页里程:${formatKm(pageMileageTotal)} km`,
`异常记录:${anomalyCount.toLocaleString()}`, `异常记录:${anomalyCount.toLocaleString()}`,
`最大单日:${peak}`, `最大单日:${peak}`,
'统计口径:区间总值等于各日里程之和' '统计口径:区间总值等于各日里程之和',
`统计查询:${statisticsURL}`,
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
].join('\n'); ].join('\n');
} }
@@ -259,13 +270,18 @@ export function Mileage({
Toast.success(`已导出 ${rows.length} 条里程明细`); Toast.success(`已导出 ${rows.length} 条里程明细`);
}; };
const copyStatisticsSummary = () => { const copyStatisticsSummary = () => {
const vehicleURL = currentVehicleKeyword
? appURL(buildAppHash({ page: 'detail', keyword: currentVehicleKeyword, protocol: currentProtocol }))
: undefined;
copyText( copyText(
mileageSummaryText({ mileageSummaryText({
filters, filters,
summary, summary,
pageMileageTotal, pageMileageTotal,
anomalyCount: anomalyRows.length, anomalyCount: anomalyRows.length,
peakMileage peakMileage,
statisticsURL: appURL(window.location.hash || buildAppHash({ page: 'mileage', keyword: currentVehicleKeyword, protocol: currentProtocol })),
vehicleURL
}), }),
'统计摘要' '统计摘要'
); );

View File

@@ -5698,6 +5698,8 @@ test('copies mileage statistics summary for operations reporting', async () => {
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录1')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录1'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('最大单日粤A统计2 / 2026-07-02 / 100 km')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('最大单日粤A统计2 / 2026-07-02 / 100 km'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计口径:区间总值等于各日里程之和')); 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 () => { test('exports current mileage page as CSV', async () => {