feat(platform): link mileage statistics summary
This commit is contained in:
@@ -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
|
||||||
}),
|
}),
|
||||||
'统计摘要'
|
'统计摘要'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user