diff --git a/vehicle-data-platform/apps/web/src/domain/vehicleLookup.test.ts b/vehicle-data-platform/apps/web/src/domain/vehicleLookup.test.ts new file mode 100644 index 00000000..864a9b89 --- /dev/null +++ b/vehicle-data-platform/apps/web/src/domain/vehicleLookup.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, test } from 'vitest'; +import type { QualityIssueRow } from '../api/types'; +import { qualityIssueVehicleLookup } from './vehicleLookup'; + +function issue(row: Partial): QualityIssueRow { + return { + vin: '', + plate: '', + phone: '', + sourceEndpoint: '', + protocol: 'JT808', + issueType: 'VIN_MISSING', + severity: 'warning', + lastSeen: '', + detail: '', + ...row + }; +} + +describe('qualityIssueVehicleLookup', () => { + test('prefers a valid VIN', () => { + expect(qualityIssueVehicleLookup(issue({ vin: 'VIN001', plate: '粤A12345', phone: '13300000001' }))).toEqual({ + key: 'VIN001', + label: '车辆服务' + }); + }); + + test('uses plate when VIN is missing', () => { + expect(qualityIssueVehicleLookup(issue({ vin: 'unknown', plate: '粤A12345', phone: '13300000001' }))).toEqual({ + key: '粤A12345', + label: '按车牌查车' + }); + }); + + test('uses phone when VIN and plate are missing', () => { + expect(qualityIssueVehicleLookup(issue({ vin: 'unknown', phone: '13300000001' }))).toEqual({ + key: '13300000001', + label: '按手机号查车' + }); + }); +}); diff --git a/vehicle-data-platform/apps/web/src/domain/vehicleLookup.ts b/vehicle-data-platform/apps/web/src/domain/vehicleLookup.ts new file mode 100644 index 00000000..f854eb52 --- /dev/null +++ b/vehicle-data-platform/apps/web/src/domain/vehicleLookup.ts @@ -0,0 +1,22 @@ +import type { QualityIssueRow } from '../api/types'; + +export type VehicleLookup = { + key: string; + label: string; +}; + +export function qualityIssueVehicleLookup(row: QualityIssueRow): VehicleLookup { + const vin = row.vin?.trim(); + if (vin && vin !== 'unknown') { + return { key: vin, label: '车辆服务' }; + } + const plate = row.plate?.trim(); + if (plate) { + return { key: plate, label: '按车牌查车' }; + } + const phone = row.phone?.trim(); + if (phone) { + return { key: phone, label: '按手机号查车' }; + } + return { key: '', label: '车辆服务' }; +} diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index d9620b01..1dd8c831 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -4,6 +4,7 @@ import { api } from '../api/client'; import type { DashboardSummary, LinkHealth, ProtocolStat, QualityIssueRow, VehicleCoverageRow, VehicleRealtimeRow } from '../api/types'; import { PageHeader } from '../components/PageHeader'; import { StatusTag } from '../components/StatusTag'; +import { qualityIssueVehicleLookup } from '../domain/vehicleLookup'; const statusColor: Record = { ok: 'green', @@ -15,22 +16,6 @@ function formatLag(value?: number | null) { return value == null ? '未接入' : value.toLocaleString(); } -function qualityVehicleLookup(row: QualityIssueRow) { - const vin = row.vin?.trim(); - if (vin && vin !== 'unknown') { - return { key: vin, label: '车辆服务' }; - } - const plate = row.plate?.trim(); - if (plate) { - return { key: plate, label: '按车牌查车' }; - } - const phone = row.phone?.trim(); - if (phone) { - return { key: phone, label: '按手机号查车' }; - } - return { key: '', label: '车辆服务' }; -} - export function Dashboard({ onOpenVehicle, onOpenQuality }: { onOpenVehicle: (vin: string) => void; onOpenQuality: () => void }) { const [summary, setSummary] = useState(null); const [coverage, setCoverage] = useState([]); @@ -148,7 +133,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality }: { onOpenVehicle: (vi title: '操作', width: 130, render: (_: unknown, row: QualityIssueRow) => { - const lookup = qualityVehicleLookup(row); + const lookup = qualityIssueVehicleLookup(row); return ; } } diff --git a/vehicle-data-platform/apps/web/src/pages/Quality.tsx b/vehicle-data-platform/apps/web/src/pages/Quality.tsx index 2e8f98aa..32863c4b 100644 --- a/vehicle-data-platform/apps/web/src/pages/Quality.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Quality.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'; import { api } from '../api/client'; import type { OpsHealth, QualitySummary, QualityIssueRow } from '../api/types'; import { PageHeader } from '../components/PageHeader'; +import { qualityIssueVehicleLookup } from '../domain/vehicleLookup'; const statusColor: Record = { ok: 'green', @@ -49,22 +50,6 @@ async function copyText(value: string, label: string) { } } -function vehicleLookup(row: QualityIssueRow) { - const vin = row.vin?.trim(); - if (vin && vin !== 'unknown') { - return { key: vin, label: '车辆服务' }; - } - const plate = row.plate?.trim(); - if (plate) { - return { key: plate, label: '按车牌查车' }; - } - const phone = row.phone?.trim(); - if (phone) { - return { key: phone, label: '按手机号查车' }; - } - return { key: '', label: '车辆服务' }; -} - export function Quality({ onOpenVehicle, onHealthLoaded @@ -194,7 +179,7 @@ export function Quality({ title: '操作', width: 250, render: (_: unknown, row: QualityIssueRow) => { - const lookup = vehicleLookup(row); + const lookup = qualityIssueVehicleLookup(row); return (