feat(platform): add vehicle data management console
This commit is contained in:
72
vehicle-data-platform/apps/web/src/pages/Vehicles.tsx
Normal file
72
vehicle-data-platform/apps/web/src/pages/Vehicles.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Button, Card, Form, Select, SideSheet, Space, Table, TextArea, Toast } from '@douyinfe/semi-ui';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import type { VehicleRow } from '../api/types';
|
||||
import { DataEmpty } from '../components/DataEmpty';
|
||||
import { PageHeader } from '../components/PageHeader';
|
||||
import { StatusTag } from '../components/StatusTag';
|
||||
|
||||
export function Vehicles() {
|
||||
const [rows, setRows] = useState<VehicleRow[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selected, setSelected] = useState<VehicleRow | null>(null);
|
||||
|
||||
const load = (values?: Record<string, string>) => {
|
||||
setLoading(true);
|
||||
const params = new URLSearchParams({ limit: '20' });
|
||||
if (values?.keyword) params.set('keyword', values.keyword);
|
||||
if (values?.protocol) params.set('protocol', values.protocol);
|
||||
api.vehicles(params)
|
||||
.then((page) => setRows(page.items))
|
||||
.catch((error: Error) => Toast.error(error.message))
|
||||
.finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => load(), []);
|
||||
|
||||
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: '协议', dataIndex: 'protocol', width: 120 },
|
||||
{ title: '在线', render: (_: unknown, row: VehicleRow) => <StatusTag status={row.online ? 'ok' : 'offline'} /> },
|
||||
{ title: '最后在线', dataIndex: 'lastSeen', width: 170 },
|
||||
{ title: '位置', dataIndex: 'locationText' },
|
||||
{ title: '绑定分', dataIndex: 'bindingScore', width: 90 },
|
||||
{ title: '操作', render: (_: unknown, row: VehicleRow) => <Button onClick={() => setSelected(row)}>详情</Button> }
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="vp-page">
|
||||
<PageHeader title="车辆台账" description="车辆身份、协议绑定、车牌、手机号和 OEM 的运营台账" />
|
||||
<Card bordered>
|
||||
<Form layout="horizontal" onSubmit={(values) => load(values as Record<string, string>)}>
|
||||
<Form.Input field="keyword" label="关键词" placeholder="VIN / 车牌 / 手机号" style={{ width: 260 }} />
|
||||
<Form.Select field="protocol" label="协议" placeholder="全部协议" style={{ width: 180 }}>
|
||||
<Select.Option value="GB32960">GB32960</Select.Option>
|
||||
<Select.Option value="JT808">JT808</Select.Option>
|
||||
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>
|
||||
</Form.Select>
|
||||
<Space>
|
||||
<Button htmlType="submit" theme="solid" type="primary">查询</Button>
|
||||
<Button onClick={() => load()}>重置</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card bordered style={{ marginTop: 16 }}>
|
||||
{rows.length === 0 && !loading ? (
|
||||
<DataEmpty />
|
||||
) : (
|
||||
<Table loading={loading} rowKey="vin" dataSource={rows} columns={columns} pagination={false} />
|
||||
)}
|
||||
</Card>
|
||||
<SideSheet title="车辆详情" visible={Boolean(selected)} onCancel={() => setSelected(null)} width={520}>
|
||||
<TextArea value={JSON.stringify(selected, null, 2)} autosize readOnly />
|
||||
</SideSheet>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user