feat(platform): copy vehicle diagnostic summary

This commit is contained in:
lingniu
2026-07-04 13:52:57 +08:00
parent c4d25593c1
commit 1365ce2a30
2 changed files with 184 additions and 4 deletions

View File

@@ -6,6 +6,7 @@ import type { QualityIssueRow, RealtimeLocationRow, VehicleDetail as VehicleDeta
import { PageHeader } from '../components/PageHeader';
import { SourceStatusTags } from '../components/SourceStatusTags';
import { StatusTag } from '../components/StatusTag';
import { buildAppHash } from '../domain/appRoute';
import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport';
import { isLikelyVIN } from '../domain/vehicleLookup';
import { summarizeVehicleService } from '../domain/vehicleService';
@@ -93,12 +94,12 @@ function vehicleReportFileName(vin: string, protocol?: string) {
return `vehicle-service-${vin || 'unknown'}-${protocol || 'all-source'}.csv`;
}
async function copyVehicleServiceURL() {
async function copyText(value: string, label: string) {
try {
await navigator.clipboard.writeText(`${window.location.origin}${window.location.pathname}${window.location.hash}`);
Toast.success('已复制服务链接');
await navigator.clipboard.writeText(value);
Toast.success(`已复制${label}`);
} catch {
Toast.error('复制服务链接失败');
Toast.error(`复制${label}失败`);
}
}
@@ -266,6 +267,45 @@ export function VehicleDetail({
keyword: resolvedVIN,
...(activeProtocol ? { protocol: activeProtocol } : {})
});
const vehicleServiceURL = (hash: string) => `${window.location.origin}${window.location.pathname}${hash}`;
const vehicleServiceHash = (page: 'detail' | 'realtime' | 'history' | 'mileage', filters?: Record<string, string>) => buildAppHash({
page,
keyword: resolvedVIN,
protocol: activeProtocol,
filters
});
const copyVehicleServiceURL = () => copyText(vehicleServiceURL(window.location.hash), '服务链接');
const copyVehicleDiagnosticSummary = () => {
if (!detail) {
Toast.warning('当前没有可复制的诊断摘要');
return;
}
const vehicleName = [archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey;
const lines = [
'【车辆服务诊断摘要】',
`车辆:${vehicleName}`,
`查询关键词:${reportText(displayLookupKey)}`,
`当前范围:${scopeText}`,
`服务状态:${serviceStatus?.title ?? serviceConclusion.status}`,
`服务说明:${serviceStatus?.detail ?? '-'}`,
`服务判断:${serviceConclusion.status}`,
`主要风险:${serviceConclusion.risk}`,
`下一步:${serviceConclusion.nextStep}`,
`来源证据:${evidenceSourceCount > 0 ? `${evidenceOnlineSourceCount}/${evidenceSourceCount} 来源在线` : '-'}`,
`定位证据:${evidenceLocatedSourceCount > 0 ? `${evidenceLocatedSourceCount} 个来源有位置` : '暂无位置'}`,
`里程差异:${formatCompactNumber(evidenceMileageDelta, ' km')}`,
`时间差异:${formatSeconds(evidenceTimeDeltaSeconds)}`,
`数据规模:实时 ${overview?.realtimeCount ?? detail.realtime.length} / 历史 ${overview?.historyCount ?? detail.history.total ?? 0} / RAW ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0} / 质量 ${overview?.qualityIssueCount ?? qualityCount}`,
`一致性:${consistencyTitle}`,
`一致性说明:${consistencyDetail}`,
`车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`,
`实时:${vehicleServiceURL(vehicleServiceHash('realtime'))}`,
`轨迹:${vehicleServiceURL(vehicleServiceHash('history'))}`,
`RAW${vehicleServiceURL(vehicleServiceHash('history', { tab: 'raw', includeFields: 'true' }))}`,
`里程:${vehicleServiceURL(vehicleServiceHash('mileage'))}`
];
copyText(lines.join('\n'), '诊断摘要');
};
const qualityIssueAction = (count: number) => {
if (count <= 0) {
return <Tag color="green"></Tag>;
@@ -404,6 +444,7 @@ export function VehicleDetail({
<Button icon={<IconSearch />} htmlType="submit" theme="solid" type="primary"></Button>
<Button icon={<IconRefresh />} onClick={() => load(query)} loading={loading}></Button>
<Button icon={<IconCopy />} onClick={copyVehicleServiceURL}></Button>
<Button disabled={!detail} icon={<IconCopy />} onClick={copyVehicleDiagnosticSummary}></Button>
<Button disabled={!detail} icon={<IconDownload />} onClick={exportVehicleReport}> CSV</Button>
<Button disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}></Button>
<Button disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}></Button>