feat(platform): link records to vehicle service

This commit is contained in:
lingniu
2026-07-03 23:32:19 +08:00
parent 73d32d3b0e
commit 05c0643a69
3 changed files with 40 additions and 7 deletions

View File

@@ -50,8 +50,8 @@ export default function App() {
vehicles: <Vehicles onOpenVehicle={openVehicle} />, vehicles: <Vehicles onOpenVehicle={openVehicle} />,
realtime: <Realtime />, realtime: <Realtime />,
detail: <VehicleDetail vin={activeVin} />, detail: <VehicleDetail vin={activeVin} />,
history: <History />, history: <History onOpenVehicle={openVehicle} />,
mileage: <Mileage />, mileage: <Mileage onOpenVehicle={openVehicle} />,
quality: <Quality onHealthLoaded={(health) => setLinkIssueCount(health.linkHealth.filter((item) => item.status !== 'ok').length)} /> quality: <Quality onHealthLoaded={(health) => setLinkIssueCount(health.linkHealth.filter((item) => item.status !== 'ok').length)} />
}; };

View File

@@ -21,7 +21,12 @@ const defaultFilters: HistoryFilters = {
const defaultPage = { items: [], total: 0, limit: 10, offset: 0 }; const defaultPage = { items: [], total: 0, limit: 10, offset: 0 };
export function History() { function canOpenVehicle(vin?: string) {
const value = vin?.trim();
return Boolean(value && value !== 'unknown');
}
export function History({ onOpenVehicle }: { onOpenVehicle: (vin: string) => void }) {
const [filters, setFilters] = useState<HistoryFilters>(defaultFilters); const [filters, setFilters] = useState<HistoryFilters>(defaultFilters);
const [locations, setLocations] = useState<Page<HistoryLocationRow>>(defaultPage); const [locations, setLocations] = useState<Page<HistoryLocationRow>>(defaultPage);
const [rawFrames, setRawFrames] = useState<Page<RawFrameRow>>(defaultPage); const [rawFrames, setRawFrames] = useState<Page<RawFrameRow>>(defaultPage);
@@ -143,7 +148,14 @@ export function History() {
{ title: '速度 km/h', dataIndex: 'speedKmh', width: 120 }, { title: '速度 km/h', dataIndex: 'speedKmh', width: 120 },
{ title: '总里程 km', dataIndex: 'totalMileageKm', width: 130 }, { title: '总里程 km', dataIndex: 'totalMileageKm', width: 130 },
{ title: '设备时间', dataIndex: 'deviceTime', width: 190 }, { title: '设备时间', dataIndex: 'deviceTime', width: 190 },
{ title: '入库时间', dataIndex: 'serverTime', width: 190 } { title: '入库时间', dataIndex: 'serverTime', width: 190 },
{
title: '操作',
width: 110,
render: (_: unknown, row: HistoryLocationRow) => (
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin)}></Button>
)
}
]} ]}
/> />
</Tabs.TabPane> </Tabs.TabPane>
@@ -169,7 +181,16 @@ export function History() {
{ title: '大小 B', dataIndex: 'rawSizeBytes', width: 100 }, { title: '大小 B', dataIndex: 'rawSizeBytes', width: 100 },
{ title: '设备时间', dataIndex: 'deviceTime', width: 190 }, { title: '设备时间', dataIndex: 'deviceTime', width: 190 },
{ title: '入库时间', dataIndex: 'serverTime', width: 190 }, { title: '入库时间', dataIndex: 'serverTime', width: 190 },
{ title: '操作', width: 100, render: (_: unknown, row: RawFrameRow) => <Button onClick={() => setSelectedRaw(row)}></Button> } {
title: '操作',
width: 200,
render: (_: unknown, row: RawFrameRow) => (
<Space>
<Button onClick={() => setSelectedRaw(row)}></Button>
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin)}></Button>
</Space>
)
}
]} ]}
/> />
</Tabs.TabPane> </Tabs.TabPane>

View File

@@ -27,7 +27,12 @@ function formatKm(value: number) {
return Number.isFinite(value) ? value.toLocaleString(undefined, { maximumFractionDigits: 1 }) : '0'; return Number.isFinite(value) ? value.toLocaleString(undefined, { maximumFractionDigits: 1 }) : '0';
} }
export function Mileage() { function canOpenVehicle(vin?: string) {
const value = vin?.trim();
return Boolean(value && value !== 'unknown');
}
export function Mileage({ onOpenVehicle }: { onOpenVehicle: (vin: string) => void }) {
const [rows, setRows] = useState<DailyMileageRow[]>([]); const [rows, setRows] = useState<DailyMileageRow[]>([]);
const [summary, setSummary] = useState<MileageSummary>(emptySummary); const [summary, setSummary] = useState<MileageSummary>(emptySummary);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -121,7 +126,14 @@ export function Mileage() {
{ title: '结束里程', dataIndex: 'endMileageKm' }, { title: '结束里程', dataIndex: 'endMileageKm' },
{ title: '日里程', dataIndex: 'dailyMileageKm' }, { title: '日里程', dataIndex: 'dailyMileageKm' },
{ title: '来源', dataIndex: 'source' }, { title: '来源', dataIndex: 'source' },
{ title: '异常', render: (_: unknown, row: DailyMileageRow) => row.anomalySeverity ? <Tag color="orange">{row.anomalySeverity}</Tag> : <Tag color="green"></Tag> } { title: '异常', render: (_: unknown, row: DailyMileageRow) => row.anomalySeverity ? <Tag color="orange">{row.anomalySeverity}</Tag> : <Tag color="green"></Tag> },
{
title: '操作',
width: 110,
render: (_: unknown, row: DailyMileageRow) => (
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin)}></Button>
)
}
]} ]}
/> />
</Card> </Card>