feat(platform): expose no-data vehicles
This commit is contained in:
@@ -65,6 +65,7 @@ export interface VehicleCoverageSummary {
|
||||
onlineVehicles: number;
|
||||
singleSourceVehicles: number;
|
||||
multiSourceVehicles: number;
|
||||
noDataVehicles: number;
|
||||
unboundVehicles: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ const serviceStatusColor: Record<string, 'green' | 'orange' | 'red' | 'grey'> =
|
||||
healthy: 'green',
|
||||
degraded: 'orange',
|
||||
offline: 'red',
|
||||
no_data: 'orange',
|
||||
identity_required: 'orange'
|
||||
};
|
||||
|
||||
@@ -24,6 +25,7 @@ const serviceStatusTitle: Record<string, string> = {
|
||||
healthy: '服务正常',
|
||||
degraded: '部分来源离线',
|
||||
offline: '车辆离线',
|
||||
no_data: '暂无数据来源',
|
||||
identity_required: '身份未绑定'
|
||||
};
|
||||
|
||||
@@ -104,6 +106,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
|
||||
{ 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?.noDataVehicles), filters: { serviceStatus: 'no_data' } },
|
||||
{ label: '身份未绑定', value: formatCount(serviceSummary?.identityRequiredVehicles), filters: { serviceStatus: 'identity_required' } }
|
||||
];
|
||||
|
||||
@@ -239,6 +242,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on
|
||||
<Select.Option value="healthy">服务正常</Select.Option>
|
||||
<Select.Option value="degraded">部分来源离线</Select.Option>
|
||||
<Select.Option value="offline">车辆离线</Select.Option>
|
||||
<Select.Option value="no_data">暂无数据来源</Select.Option>
|
||||
<Select.Option value="identity_required">身份未绑定</Select.Option>
|
||||
</Form.Select>
|
||||
<Space>
|
||||
|
||||
@@ -52,6 +52,7 @@ export function Vehicles({
|
||||
{ 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?.noDataVehicles ?? 0).toLocaleString(), filters: { serviceStatus: 'no_data' } },
|
||||
{ label: '待绑定', value: (summary?.unboundVehicles ?? 0).toLocaleString(), filters: { bindingStatus: 'unbound' } }
|
||||
];
|
||||
return items;
|
||||
@@ -144,6 +145,7 @@ export function Vehicles({
|
||||
<Select.Option value="healthy">服务正常</Select.Option>
|
||||
<Select.Option value="degraded">部分来源离线</Select.Option>
|
||||
<Select.Option value="offline">车辆离线</Select.Option>
|
||||
<Select.Option value="no_data">暂无数据来源</Select.Option>
|
||||
<Select.Option value="identity_required">身份未绑定</Select.Option>
|
||||
</Form.Select>
|
||||
<Form.Select field="online" label="在线" placeholder="全部" style={{ width: 130 }}>
|
||||
|
||||
@@ -121,6 +121,8 @@ test('dashboard renders vehicle service summary metrics', async () => {
|
||||
expect(screen.getByText('391')).toBeInTheDocument();
|
||||
expect(screen.getByText('多源车辆')).toBeInTheDocument();
|
||||
expect(screen.getByText('181')).toBeInTheDocument();
|
||||
expect(screen.getByText('暂无来源车辆')).toBeInTheDocument();
|
||||
expect(screen.getByText('461')).toBeInTheDocument();
|
||||
expect(screen.getByText('身份未绑定')).toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith('/api/vehicle-service/summary', undefined);
|
||||
});
|
||||
@@ -171,12 +173,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=single'), undefined);
|
||||
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/vehicles/coverage?limit=20&offset=0&serviceStatus=no_data'), undefined);
|
||||
});
|
||||
expect(window.location.hash).toBe('#/vehicles?coverage=single');
|
||||
expect(window.location.hash).toBe('#/vehicles?serviceStatus=no_data');
|
||||
});
|
||||
|
||||
test('shows vehicle service result summary on vehicle list filters', async () => {
|
||||
@@ -261,6 +263,7 @@ test('shows vehicle service result summary on vehicle list filters', async () =>
|
||||
expect(screen.getByText('73')).toBeInTheDocument();
|
||||
expect(screen.getByText('在线车辆')).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);
|
||||
|
||||
Reference in New Issue
Block a user