import { Button, Card, Form, Select, Space, Table, Tabs, Tag, Toast, Typography } from '@douyinfe/semi-ui'; import { useEffect, useState } from 'react'; import { api } from '../api/client'; import type { VehicleRealtimeRow } from '../api/types'; import { DataEmpty } from '../components/DataEmpty'; import { PageHeader } from '../components/PageHeader'; import { StatusTag } from '../components/StatusTag'; function canOpenVehicle(vin?: string) { const value = vin?.trim(); return Boolean(value && value !== 'unknown'); } function vehicleServiceStatus(row: VehicleRealtimeRow) { if (row.serviceStatus) { return { label: row.serviceStatus.title, color: row.serviceStatus.severity === 'ok' ? 'green' as const : row.serviceStatus.severity === 'error' ? 'red' as const : 'orange' as const }; } if (row.onlineSourceCount <= 0) { return { label: '车辆离线', color: 'red' as const }; } if (row.onlineSourceCount < row.sourceCount) { return { label: '来源异常', color: 'orange' as const }; } return { label: '服务正常', color: 'green' as const }; } function sourceEvidenceText(row: VehicleRealtimeRow) { return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`; } export function Realtime({ onOpenVehicle }: { onOpenVehicle: (vin: string, protocol?: string) => void }) { const [rows, setRows] = useState([]); const [loading, setLoading] = useState(true); const [filters, setFilters] = useState>({}); const [pagination, setPagination] = useState({ currentPage: 1, pageSize: 50, total: 0 }); const load = (values: Record = filters, page = pagination.currentPage, pageSize = pagination.pageSize) => { setLoading(true); const params = new URLSearchParams({ limit: String(pageSize), offset: String((page - 1) * pageSize) }); if (values?.keyword) params.set('keyword', values.keyword); if (values?.protocol) params.set('protocol', values.protocol); if (values?.online) params.set('online', values.online); if (values?.serviceStatus) params.set('serviceStatus', values.serviceStatus); api.vehicleRealtime(params) .then((nextPage) => { setRows(nextPage.items); setPagination({ currentPage: page, pageSize, total: nextPage.total }); }) .catch((error: Error) => Toast.error(error.message)) .finally(() => setLoading(false)); }; useEffect(() => { load({}, 1, pagination.pageSize); }, []); return (
{ const nextFilters = values as Record; setFilters(nextFilters); load(nextFilters, 1, pagination.pageSize); }} style={{ marginBottom: 12 }}> GB32960 JT808 YUTONG_MQTT 在线 离线 服务正常 来源异常 车辆离线 身份未绑定 {rows.length === 0 && !loading ? ( ) : ( load(filters, page, pagination.pageSize), onPageSizeChange: (pageSize) => load(filters, 1, pageSize) }} columns={[ { title: '车牌', dataIndex: 'plate', width: 120 }, { title: 'VIN', dataIndex: 'vin', width: 190 }, { title: '车辆服务状态', width: 130, render: (_: unknown, row: VehicleRealtimeRow) => { const status = vehicleServiceStatus(row); return {status.label}; } }, { title: '车辆核心数据', width: 230, render: (_: unknown, row: VehicleRealtimeRow) => ( {row.speedKmh ?? '-'} km/h SOC {row.socPercent ?? '-'}% {row.totalMileageKm ?? '-'} km ) }, { title: '来源证据', width: 260, render: (_: unknown, row: VehicleRealtimeRow) => ( {row.protocols.map((protocol) => ( {protocol} ))} ) }, { title: '证据覆盖', width: 120, render: (_: unknown, row: VehicleRealtimeRow) => sourceEvidenceText(row) }, { title: '在线', width: 90, render: (_: unknown, row: VehicleRealtimeRow) => }, { title: '最后时间', dataIndex: 'lastSeen', width: 170 }, { title: '操作', width: 110, render: (_: unknown, row: VehicleRealtimeRow) => ( ) } ]} /> )}
{rows.map((row, index) => ( ))}
); }