import { Button, Card, Form, Select, Space, Table, Tag, Toast } from '@douyinfe/semi-ui'; import { useEffect, useMemo, useState } from 'react'; import { api } from '../api/client'; import type { VehicleCoverageRow } from '../api/types'; import { DataEmpty } from '../components/DataEmpty'; import { PageHeader } from '../components/PageHeader'; import { StatusTag } from '../components/StatusTag'; function vehicleServiceStatus(row: VehicleCoverageRow) { 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.bindingStatus !== 'bound') { return { label: '身份未绑定', color: 'orange' as const }; } if (row.sourceCount <= 0) { return { label: '暂无数据来源', color: '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 }; } export function Vehicles({ onOpenVehicle, initialFilters = {} }: { onOpenVehicle: (vin: string) => void; initialFilters?: Record }) { const [rows, setRows] = useState([]); const [loading, setLoading] = useState(true); const [filters, setFilters] = useState>(initialFilters); const [pagination, setPagination] = useState({ currentPage: 1, pageSize: 20, 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?.coverage) params.set('coverage', values.coverage); if (values?.online) params.set('online', values.online); if (values?.bindingStatus) params.set('bindingStatus', values.bindingStatus); if (values?.serviceStatus) params.set('serviceStatus', values.serviceStatus); api.vehicleCoverage(params) .then((nextPage) => { setRows(nextPage.items); setPagination({ currentPage: page, pageSize, total: nextPage.total }); }) .catch((error: Error) => Toast.error(error.message)) .finally(() => setLoading(false)); }; useEffect(() => { setFilters(initialFilters); load(initialFilters, 1, pagination.pageSize); }, [JSON.stringify(initialFilters)]); const columns = useMemo( () => [ { title: 'VIN', dataIndex: 'vin', width: 190 }, { title: '车牌', dataIndex: 'plate', width: 120 }, { title: '手机号', dataIndex: 'phone', width: 130 }, { title: 'OEM', dataIndex: 'oem', width: 120 }, { title: '车辆服务状态', width: 130, render: (_: unknown, row: VehicleCoverageRow) => { const status = vehicleServiceStatus(row); return {status.label}; } }, { title: '来源', width: 240, render: (_: unknown, row: VehicleCoverageRow) => ( {row.protocols.map((protocol) => {protocol})} ) }, { title: '覆盖', width: 90, render: (_: unknown, row: VehicleCoverageRow) => `${row.onlineSourceCount}/${row.sourceCount}` }, { title: '在线', width: 90, render: (_: unknown, row: VehicleCoverageRow) => }, { title: '最后在线', dataIndex: 'lastSeen', width: 170 }, { title: '绑定', width: 90, render: (_: unknown, row: VehicleCoverageRow) => {row.bindingStatus === 'bound' ? '已绑定' : '未绑定'} }, { title: '操作', width: 110, render: (_: unknown, row: VehicleCoverageRow) => } ], [onOpenVehicle] ); return (
{ const nextFilters = values as Record; setFilters(nextFilters); load(nextFilters, 1, pagination.pageSize); }}> GB32960 JT808 YUTONG_MQTT 单源 多源 服务正常 部分来源离线 车辆离线 身份未绑定 在线 离线 已绑定 未绑定
{rows.length === 0 && !loading ? ( ) : ( load(filters, page, pagination.pageSize), onPageSizeChange: (pageSize) => load(filters, 1, pageSize) }} /> )} ); }