feat(platform): label source evidence
This commit is contained in:
@@ -51,6 +51,10 @@ function rowServiceStatus(row: { serviceStatus?: { title: string; severity: stri
|
||||
return { label: '服务正常', color: 'green' as const };
|
||||
}
|
||||
|
||||
function sourceEvidenceText(row: { onlineSourceCount: number; sourceCount: number }) {
|
||||
return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`;
|
||||
}
|
||||
|
||||
export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { onOpenVehicle: (vin: string) => void; onOpenQuality: () => void; onOpenVehicles: (filters?: Record<string, string>) => void }) {
|
||||
const [summary, setSummary] = useState<DashboardSummary | null>(null);
|
||||
const [serviceSummary, setServiceSummary] = useState<VehicleServiceSummary | null>(null);
|
||||
@@ -250,7 +254,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
|
||||
{ title: '车牌', dataIndex: 'plate', width: 110 },
|
||||
{ title: 'VIN', dataIndex: 'vin', width: 190 },
|
||||
{
|
||||
title: '来源',
|
||||
title: '来源证据',
|
||||
width: 240,
|
||||
render: (_: unknown, row: VehicleCoverageRow) => (
|
||||
<Space spacing={4} wrap>
|
||||
@@ -259,9 +263,9 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '覆盖',
|
||||
width: 110,
|
||||
render: (_: unknown, row: VehicleCoverageRow) => `${row.onlineSourceCount}/${row.sourceCount}`
|
||||
title: '证据覆盖',
|
||||
width: 130,
|
||||
render: (_: unknown, row: VehicleCoverageRow) => sourceEvidenceText(row)
|
||||
},
|
||||
{
|
||||
title: '服务状态',
|
||||
@@ -303,7 +307,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
|
||||
{ title: '车牌', dataIndex: 'plate' },
|
||||
{ title: 'VIN', dataIndex: 'vin' },
|
||||
{
|
||||
title: '来源',
|
||||
title: '来源证据',
|
||||
render: (_: unknown, row: VehicleRealtimeRow) => (
|
||||
<Space spacing={4} wrap>
|
||||
{row.protocols.map((protocol) => <Tag key={protocol} color={protocol === row.primaryProtocol ? 'blue' : 'grey'}>{protocol}</Tag>)}
|
||||
|
||||
@@ -28,6 +28,10 @@ function vehicleServiceStatus(row: VehicleCoverageRow) {
|
||||
return { label: '服务正常', color: 'green' as const };
|
||||
}
|
||||
|
||||
function sourceEvidenceText(row: VehicleCoverageRow) {
|
||||
return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`;
|
||||
}
|
||||
|
||||
export function Vehicles({
|
||||
onOpenVehicle,
|
||||
onFiltersChange,
|
||||
@@ -100,7 +104,7 @@ export function Vehicles({
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '来源',
|
||||
title: '来源证据',
|
||||
width: 240,
|
||||
render: (_: unknown, row: VehicleCoverageRow) => (
|
||||
<Space spacing={4} wrap>
|
||||
@@ -108,7 +112,7 @@ export function Vehicles({
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
{ title: '覆盖', width: 90, render: (_: unknown, row: VehicleCoverageRow) => `${row.onlineSourceCount}/${row.sourceCount}` },
|
||||
{ title: '证据覆盖', width: 120, render: (_: unknown, row: VehicleCoverageRow) => sourceEvidenceText(row) },
|
||||
{ title: '在线', width: 90, render: (_: unknown, row: VehicleCoverageRow) => <StatusTag status={row.online ? 'ok' : 'offline'} /> },
|
||||
{ title: '最后在线', dataIndex: 'lastSeen', width: 170 },
|
||||
{ title: '绑定', width: 90, render: (_: unknown, row: VehicleCoverageRow) => <Tag color={row.bindingStatus === 'bound' ? 'green' : 'orange'}>{row.bindingStatus === 'bound' ? '已绑定' : '未绑定'}</Tag> },
|
||||
|
||||
@@ -260,6 +260,8 @@ test('shows vehicle service result summary on vehicle list filters', async () =>
|
||||
expect(screen.getByText('在线车辆')).toBeInTheDocument();
|
||||
expect(screen.getByText('待绑定')).toBeInTheDocument();
|
||||
expect(screen.getByText('VIN-MULTI-001')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('来源证据').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getByText('1/2 来源在线')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('filters vehicle list from result summary actions', async () => {
|
||||
@@ -551,6 +553,8 @@ test('shows row service status in dashboard vehicle previews', async () => {
|
||||
render(<App />);
|
||||
|
||||
expect(await screen.findByText('VIN-COVERAGE-WARN')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('来源证据').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('1/2 来源在线').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getByText('覆盖部分离线')).toBeInTheDocument();
|
||||
expect(screen.getByText('VIN-REALTIME-OFFLINE')).toBeInTheDocument();
|
||||
expect(screen.getByText('实时车辆离线')).toBeInTheDocument();
|
||||
|
||||
@@ -24,6 +24,8 @@ Vehicle lists should expose a vehicle-level service status derived from binding
|
||||
|
||||
Vehicle detail and top search context should expose one source-consistency conclusion, such as `来源一致`, `部分来源离线`, or `里程差异偏大`. This diagnosis comes from `sourceConsistency` and turns GB32960, JT808, and Yutong MQTT into explainable evidence under one vehicle service rather than three competing realtime products.
|
||||
|
||||
Vehicle service lists and dashboard previews should label protocol coverage as `来源证据`. The row should make the vehicle service coverage explicit, for example `2/3 来源在线`, while protocol tags remain compact evidence labels underneath the same vehicle row.
|
||||
|
||||
## Interaction Rules
|
||||
|
||||
- Tables are the default data surface.
|
||||
|
||||
Reference in New Issue
Block a user