feat(platform): expose single-source vehicles

This commit is contained in:
lingniu
2026-07-04 04:18:20 +08:00
parent 0b53abf63d
commit 7f9d327f38
4 changed files with 10 additions and 3 deletions

View File

@@ -102,6 +102,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
const kpis: Array<{ label: string; value: string; filters: Record<string, string> }> = [
{ label: '总车辆', value: formatCount(serviceSummary?.totalVehicles), filters: {} },
{ label: '在线车辆', value: formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles), filters: { online: 'online' } },
{ label: '单源车辆', value: formatCount(serviceSummary?.singleSourceVehicles), filters: { coverage: 'single' } },
{ label: '多源车辆', value: formatCount(serviceSummary?.multiSourceVehicles), filters: { coverage: 'multi' } },
{ label: '身份未绑定', value: formatCount(serviceSummary?.identityRequiredVehicles), filters: { serviceStatus: 'identity_required' } }
];

View File

@@ -50,6 +50,7 @@ export function Vehicles({
const items: Array<{ label: string; value: string; filters: Record<string, string> }> = [
{ label: '过滤车辆', value: (summary?.totalVehicles ?? pagination.total).toLocaleString(), filters: {} },
{ label: '在线车辆', value: (summary?.onlineVehicles ?? 0).toLocaleString(), filters: { online: 'online' } },
{ label: '单源车辆', value: (summary?.singleSourceVehicles ?? 0).toLocaleString(), filters: { coverage: 'single' } },
{ label: '多源车辆', value: (summary?.multiSourceVehicles ?? 0).toLocaleString(), filters: { coverage: 'multi' } },
{ label: '待绑定', value: (summary?.unboundVehicles ?? 0).toLocaleString(), filters: { bindingStatus: 'unbound' } }
];

View File

@@ -117,6 +117,8 @@ test('dashboard renders vehicle service summary metrics', async () => {
expect(await screen.findByText('总车辆')).toBeInTheDocument();
expect(screen.getByText('1,033')).toBeInTheDocument();
expect(screen.getByText('单源车辆')).toBeInTheDocument();
expect(screen.getByText('391')).toBeInTheDocument();
expect(screen.getByText('多源车辆')).toBeInTheDocument();
expect(screen.getByText('181')).toBeInTheDocument();
expect(screen.getByText('身份未绑定')).toBeInTheDocument();
@@ -169,12 +171,12 @@ test('opens vehicle list filtered by service summary KPI', async () => {
render(<App />);
fireEvent.click(await screen.findByRole('button', { name: /源车辆/ }));
fireEvent.click(await screen.findByRole('button', { name: /源车辆/ }));
await waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&coverage=multi'), undefined);
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&coverage=single'), undefined);
});
expect(window.location.hash).toBe('#/vehicles?coverage=multi');
expect(window.location.hash).toBe('#/vehicles?coverage=single');
});
test('shows vehicle service result summary on vehicle list filters', async () => {
@@ -258,6 +260,7 @@ test('shows vehicle service result summary on vehicle list filters', async () =>
expect(screen.getByText('过滤车辆')).toBeInTheDocument();
expect(screen.getByText('73')).toBeInTheDocument();
expect(screen.getByText('在线车辆')).toBeInTheDocument();
expect(screen.getByText('单源车辆')).toBeInTheDocument();
expect(screen.getByText('待绑定')).toBeInTheDocument();
expect(screen.getByText('VIN-MULTI-001')).toBeInTheDocument();
expect(screen.getAllByText('来源证据').length).toBeGreaterThanOrEqual(1);

View File

@@ -26,6 +26,8 @@ Vehicle detail and top search context should expose one source-consistency concl
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.
Dashboard and vehicle-list summary cards should expose both `单源车辆` and `多源车辆`. Single-source vehicles are operationally important because they cannot be cross-checked across sources, so they must be one-click filter targets rather than hidden behind the generic coverage filter.
## Interaction Rules
- Tables are the default data surface.