Initial commit: ONE-OS project

Made-with: Cursor
This commit is contained in:
王冕
2026-02-27 18:11:40 +08:00
commit 09cc45db36
47 changed files with 17589 additions and 0 deletions

15
src/App.tsx Normal file
View File

@@ -0,0 +1,15 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import VehicleManage from '@/pages/VehicleManage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<VehicleManage />} />
<Route path="/vehicle/:id" element={<VehicleManage />} />
</Routes>
</BrowserRouter>
);
}
export default App;

10
src/main.tsx Normal file
View File

@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@arco-design/web-react/dist/css/arco.css';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@@ -0,0 +1,116 @@
import React, { useState } from 'react';
import { Modal, Form, Input, Upload, Image, Message } from '@arco-design/web-react';
import type { VehicleRecord } from '@/types/vehicle';
type Props = {
visible: boolean;
vehicle: VehicleRecord | null;
onCancel: () => void;
onOk: (vin: string, plateNo: string) => void;
};
export default function VehiclePlateModal({ visible, vehicle, onCancel, onOk }: Props) {
const [ocrLoading, setOcrLoading] = useState(false);
const [licenseImageUrl, setLicenseImageUrl] = useState<string>('');
const [form] = Form.useForm();
const handleUploadChange = (fileList: { file?: File; url?: string }[]) => {
const file = fileList[0]?.file;
if (!file) return;
const url = URL.createObjectURL(file);
setLicenseImageUrl(url);
setOcrLoading(true);
// 模拟 OCR 识别,实际对接 OCR 接口
setTimeout(() => {
form.setFieldsValue({ vin: vehicle?.vin ?? '', plateNo: vehicle?.plateNo ?? '' });
setOcrLoading(false);
}, 1500);
};
const handleOk = () => {
form.validate().then((values) => {
const v = (values.vin ?? '').trim();
const p = (values.plateNo ?? '').trim();
if (!v || !p) {
Message.warning('请填写车辆识别代号与车牌号');
return;
}
if (vehicle && v !== vehicle.vin) {
Message.error('车辆识别代号与该车辆不匹配');
return;
}
onOk(v, p);
reset();
}).catch(() => {});
};
const reset = () => {
setLicenseImageUrl('');
setOcrLoading(false);
form.resetFields();
};
const handleCancel = () => {
reset();
onCancel();
};
return (
<>
<Modal
title="确认上牌信息"
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
okText="确认"
cancelText="取消"
style={{ width: 720 }}
unmountOnExit
afterClose={reset}
>
<div style={{ display: 'flex', gap: 24, minHeight: 280 }}>
<div style={{ flex: '0 0 320px' }}>
<div style={{ marginBottom: 8, color: 'var(--color-text-2)' }}></div>
{licenseImageUrl ? (
<Image
width={320}
height={200}
src={licenseImageUrl}
style={{ objectFit: 'contain', background: 'var(--color-fill-2)', borderRadius: 4 }}
/>
) : (
<Upload
accept="image/*"
listType="picture-card"
limit={1}
onChange={handleUploadChange}
customRequest={(option) => {
const { file } = option;
if (file) handleUploadChange([{ file: file as File }]);
}}
>
<div style={{ padding: 20, textAlign: 'center' }}></div>
</Upload>
)}
</div>
<div style={{ flex: 1 }}>
{ocrLoading ? (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200 }}>
<span style={{ color: 'var(--color-text-2)' }}></span>
</div>
) : (
<Form form={form} layout="vertical" initialValues={{ vin: vehicle?.vin ?? '', plateNo: vehicle?.plateNo ?? '' }}>
<Form.Item label="车辆识别代号VIN" field="vin" rules={[{ required: true, message: '请填写车辆识别代号' }]}>
<Input placeholder="根据行驶证照片反写,可编辑" />
</Form.Item>
<Form.Item label="车牌号" field="plateNo" rules={[{ required: true, message: '请填写车牌号' }]}>
<Input placeholder="根据行驶证照片反写,可编辑" />
</Form.Item>
</Form>
)}
</div>
</div>
</Modal>
</>
);
}

View File

@@ -0,0 +1,384 @@
import React, { useState, useCallback } from 'react';
import {
Breadcrumb,
Form,
Grid,
Select,
Cascader,
Input,
Button,
Space,
Table,
Card,
Message,
Dropdown,
Menu,
Checkbox,
Modal,
Upload,
} from '@arco-design/web-react';
import type { TableColumnProps } from '@arco-design/web-react/es/Table';
import {
IconExport,
IconImport,
IconMore,
IconSearch,
IconRefresh,
} from '@arco-design/web-react/icon';
import {
regionOptions,
vehicleTypeOptions,
brandOptions,
modelOptions,
customerOptions,
businessDeptOptions,
contractNoOptions,
registeredOwnerOptions,
mockVehicleList,
} from '@/services/vehicle';
import type { VehicleRecord, VehicleFilterForm } from '@/types/vehicle';
import VehiclePlateModal from './VehiclePlateModal';
const { Row, Col } = Grid;
const defaultFilter: VehicleFilterForm = {};
export default function VehicleManage() {
const [filter, setFilter] = useState<VehicleFilterForm>(defaultFilter);
const [plateNoQuick, setPlateNoQuick] = useState('');
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const [data, setData] = useState<VehicleRecord[]>([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(20);
const [plateModalVisible, setPlateModalVisible] = useState(false);
const [plateModalVehicle, setPlateModalVehicle] = useState<VehicleRecord | null>(null);
const [form] = Form.useForm();
const loadList = useCallback(
(p = page, ps = pageSize) => {
setLoading(true);
setTimeout(() => {
const res = mockVehicleList({
...filter,
plateNo: plateNoQuick || undefined,
page: p,
pageSize: ps,
});
setData(res.list);
setTotal(res.total);
setLoading(false);
}, 300);
},
[filter, plateNoQuick, page, pageSize]
);
React.useEffect(() => {
loadList();
}, [loadList]);
const onFilterSubmit = (values: VehicleFilterForm) => {
setFilter(values);
setPage(1);
loadList(1, pageSize);
};
const onFilterReset = () => {
form.resetFields();
setFilter(defaultFilter);
setPlateNoQuick('');
setPage(1);
loadList(1, pageSize);
};
const onExport = () => {
if (selectedRowKeys.length === 0) {
Message.warning('请先勾选要导出的车辆');
return;
}
Message.info(`导出 ${selectedRowKeys.length} 条记录(联调时对接导出接口)`);
};
const onBatchImport = () => {
Message.info('批量导入(联调时对接导入接口)');
};
const onView = (record: VehicleRecord) => {
Message.info(`查看车辆详情:${record.plateNo || record.vin}`);
// 实际可: navigate(`/vehicle/detail/${record.id}`);
};
const onPlate = (record: VehicleRecord) => {
setPlateModalVehicle(record);
setPlateModalVisible(true);
};
const onPlateModalOk = (vin: string, plateNo: string) => {
if (plateModalVehicle && (vin !== plateModalVehicle.vin || !plateNo)) {
Message.error('车辆识别代号与该车辆不匹配');
return;
}
Message.success('上牌信息已更新');
setPlateModalVisible(false);
setPlateModalVehicle(null);
loadList();
};
const moreMenu = (record: VehicleRecord) => (
<Menu>
<Menu.Item key="plate" onClick={() => onPlate(record)}></Menu.Item>
<Menu.Item key="transfer"></Menu.Item>
<Menu.Item key="move"></Menu.Item>
<Menu.Item key="allocate"></Menu.Item>
<Menu.Item key="scrap"></Menu.Item>
<Menu.Item key="inspect"></Menu.Item>
<Menu.Item key="sale"></Menu.Item>
<Menu.Item key="fault"></Menu.Item>
</Menu>
);
const columns: TableColumnProps<VehicleRecord>[] = [
{ title: '运营城市', dataIndex: 'operationCity', width: 120, fixed: 'left' },
{ title: '车辆识别代号', dataIndex: 'vin', width: 180, fixed: 'left' },
{ title: '车牌号', dataIndex: 'plateNo', width: 100, fixed: 'left' },
{ title: '车辆编号', dataIndex: 'vehicleNo', width: 100, render: (v) => v || '-' },
{ title: '车辆类型', dataIndex: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', width: 90 },
{ title: '型号', dataIndex: 'model', width: 90 },
{ title: '车身颜色', dataIndex: 'bodyColor', width: 90 },
{ title: '归属停车场', dataIndex: 'parkingLot', width: 110 },
{ title: '客户名称', dataIndex: 'customerName', width: 100 },
{ title: '业务部门', dataIndex: 'businessDept', width: 100 },
{ title: '业务负责人', dataIndex: 'businessOwner', width: 100 },
{ title: '运营状态', dataIndex: 'operationStatus', width: 90 },
{ title: '库位状态', dataIndex: 'libStatus', width: 180 },
{ title: '出库状态', dataIndex: 'outboundStatus', width: 100 },
{ title: '整备状态', dataIndex: 'prepStatus', width: 90 },
{ title: '过户状态', dataIndex: 'transferStatus', width: 120 },
{ title: '维修状态', dataIndex: 'repairStatus', width: 110 },
{ title: '证照状态', dataIndex: 'licenseStatus', width: 90 },
{ title: '报废状态', dataIndex: 'scrapStatus', width: 90 },
{ title: '登记所有权', dataIndex: 'registeredOwner', width: 160 },
{ title: '在线状态', dataIndex: 'onlineStatus', width: 90 },
{ title: '出厂年份', dataIndex: 'manufactureYear', width: 90 },
{ title: '行驶公里数(KM)', dataIndex: 'mileage', width: 120, render: (v) => v?.toFixed(2) ?? '-' },
{ title: '采购入库时间', dataIndex: 'purchaseTime', width: 120 },
{ title: '行驶证注册日期', dataIndex: 'licenseRegisterDate', width: 130 },
{ title: '行驶证检验有效期', dataIndex: 'licenseExpiry', width: 130 },
{ title: '上次交车时间', dataIndex: 'lastDeliveryTime', width: 120 },
{ title: '上次交车里程(KM)', dataIndex: 'lastDeliveryMileage', width: 130, render: (v) => (v ? Number(v).toFixed(2) : '-') },
{ title: '上次还车时间', dataIndex: 'lastReturnTime', width: 120 },
{ title: '上次还车里程(KM)', dataIndex: 'lastReturnMileage', width: 130, render: (v) => (v ? Number(v).toFixed(2) : '-') },
{ title: '强制报废日期', dataIndex: 'forceScrapDate', width: 120 },
{ title: '合同编号', dataIndex: 'contractNo', width: 110 },
{ title: '当前位置', dataIndex: 'currentLocation', width: 300 },
{ title: 'GPS最后上传时间', dataIndex: 'gpsLastTime', width: 160 },
{
title: '操作',
dataIndex: 'op',
width: 140,
fixed: 'right',
render: (_, record) => (
<Space>
<Button type="text" size="small" onClick={() => onView(record)}>
</Button>
<Dropdown trigger="hover" position="br" droplist={moreMenu(record)}>
<Button type="text" size="small" icon={<IconMore />}>
</Button>
</Dropdown>
</Space>
),
},
];
const watchedBrand = Form.useWatch('brand', form);
const modelOptionsByBrand = watchedBrand ? (modelOptions as Record<string, { value: string; label: string }[]>)[watchedBrand] ?? [] : [];
return (
<div style={{ padding: 16, background: 'var(--color-fill-2)', minHeight: '100vh' }}>
<Breadcrumb style={{ marginBottom: 16 }}>
<Breadcrumb.Item></Breadcrumb.Item>
<Breadcrumb.Item></Breadcrumb.Item>
</Breadcrumb>
<Card title="筛选" style={{ marginBottom: 16 }}>
<Form
form={form}
layout="inline"
initialValues={defaultFilter}
onSubmit={onFilterSubmit}
style={{ width: '100%' }}
>
<Row gutter={16}>
<Col span={6}>
<Form.Item label="运营城市" field="operationCity">
<Cascader
allowClear
placeholder="请选择省-市"
options={regionOptions}
style={{ width: '100%' }}
changeOnSelect
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="车辆类型" field="vehicleType">
<Select allowClear placeholder="请选择" options={vehicleTypeOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="品牌" field="brand">
<Select allowClear placeholder="请选择" options={brandOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="型号" field="model">
<Select
allowClear
placeholder="请选择"
options={modelOptionsByBrand}
style={{ width: '100%' }}
disabled={!watchedBrand}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="客户名称" field="customerName">
<Select allowClear placeholder="请选择" options={customerOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="归属业务部门" field="businessDept">
<Select allowClear placeholder="请选择" options={businessDeptOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="合同编号" field="contractNo">
<Select
allowClear
showSearch
placeholder="输入模糊匹配"
options={contractNoOptions}
style={{ width: '100%' }}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="登记所有权" field="registeredOwner">
<Select
allowClear
showSearch
placeholder="输入模糊匹配"
options={registeredOwnerOptions}
style={{ width: '100%' }}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
/>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item style={{ marginBottom: 0 }}>
<Space>
<Button type="primary" htmlType="submit" icon={<IconSearch />}>
</Button>
<Button icon={<IconRefresh />} onClick={onFilterReset}>
</Button>
</Space>
</Form.Item>
</Col>
</Row>
</Form>
</Card>
<Card>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
<Space>
<Input
placeholder="输入车牌号快速筛选"
value={plateNoQuick}
onChange={setPlateNoQuick}
style={{ width: 200 }}
allowClear
onPressEnter={() => loadList(1, pageSize)}
/>
<Button type="primary" icon={<IconSearch />} onClick={() => { setPage(1); loadList(1, pageSize); }}>
</Button>
</Space>
<Space>
<Button icon={<IconExport />} onClick={onExport}>
</Button>
<Button icon={<IconImport />} onClick={onBatchImport}>
</Button>
</Space>
</div>
<Table
rowKey="id"
loading={loading}
data={data}
columns={[
{
title: (
<Checkbox
checked={selectedRowKeys.length === data.length && data.length > 0}
indeterminate={selectedRowKeys.length > 0 && selectedRowKeys.length < data.length}
onChange={(checked) => setSelectedRowKeys(checked ? data.map((r) => r.id) : [])}
/>
),
width: 48,
fixed: 'left',
render: (_, record) => (
<Checkbox
checked={selectedRowKeys.includes(record.id)}
onChange={(checked) =>
setSelectedRowKeys((prev) =>
checked ? [...prev, record.id] : prev.filter((k) => k !== record.id)
)
}
/>
),
},
...columns,
]}
scroll={{ x: 3800 }}
pagination={{
current: page,
pageSize,
total,
showTotal: true,
showJumper: true,
sizeCanChange: true,
pageSizeChange: (ps) => {
setPageSize(ps);
setPage(1);
loadList(1, ps);
},
onChange: (p) => {
setPage(p);
loadList(p, pageSize);
},
}}
/>
</Card>
<VehiclePlateModal
visible={plateModalVisible}
vehicle={plateModalVehicle}
onCancel={() => { setPlateModalVisible(false); setPlateModalVehicle(null); }}
onOk={onPlateModalOk}
/>
</div>
);
}

145
src/services/vehicle.ts Normal file
View File

@@ -0,0 +1,145 @@
import type { VehicleRecord, VehicleFilterForm } from '@/types/vehicle';
/** 模拟省-市二级地区 */
export const regionOptions = [
{
value: 'guangdong',
label: '广东省',
children: [
{ value: 'guangzhou', label: '广州市' },
{ value: 'shenzhen', label: '深圳市' },
{ value: 'dongguan', label: '东莞市' },
],
},
{
value: 'zhejiang',
label: '浙江省',
children: [
{ value: 'hangzhou', label: '杭州市' },
{ value: 'ningbo', label: '宁波市' },
],
},
{
value: 'jiangsu',
label: '江苏省',
children: [
{ value: 'nanjing', label: '南京市' },
{ value: 'suzhou', label: '苏州市' },
],
},
];
/** 车辆类型(从车辆类型表拉取) */
export const vehicleTypeOptions = [
{ value: 'light_truck', label: '轻卡' },
{ value: 'van', label: '厢式车' },
{ value: 'suv', label: 'SUV' },
{ value: 'sedan', label: '轿车' },
];
/** 品牌(从型号参数表拉取) */
export const brandOptions = [
{ value: 'brand_a', label: '品牌A' },
{ value: 'brand_b', label: '品牌B' },
{ value: 'brand_c', label: '品牌C' },
];
/** 型号(从型号参数表拉取,可按品牌联动) */
export const modelOptions: Record<string, { value: string; label: string }[]> = {
brand_a: [
{ value: 'model_a1', label: '型号A1' },
{ value: 'model_a2', label: '型号A2' },
],
brand_b: [
{ value: 'model_b1', label: '型号B1' },
{ value: 'model_b2', label: '型号B2' },
],
brand_c: [
{ value: 'model_c1', label: '型号C1' },
],
};
/** 客户名称(租赁/自营合同客户,含「无」) */
export const customerOptions = [
{ value: '__none__', label: '无' },
{ value: 'customer_1', label: '客户甲' },
{ value: 'customer_2', label: '客户乙' },
{ value: 'customer_3', label: '客户丙' },
];
/** 归属业务部门(含「无」) */
export const businessDeptOptions = [
{ value: '__none__', label: '无' },
{ value: 'dept_1', label: '业务一部' },
{ value: 'dept_2', label: '业务二部' },
{ value: 'dept_3', label: '业务三部' },
];
/** 合同编号列表(支持模糊匹配,此处为示例) */
export const contractNoOptions = [
{ value: 'HT-2024-001', label: 'HT-2024-001' },
{ value: 'HT-2024-002', label: 'HT-2024-002' },
{ value: 'HT-2024-003', label: 'HT-2024-003' },
{ value: 'ZY-2024-001', label: 'ZY-2024-001' },
];
/** 登记所有权列表(支持模糊匹配) */
export const registeredOwnerOptions = [
{ value: 'owner_1', label: '某某物流有限公司' },
{ value: 'owner_2', label: '某某租赁有限公司' },
];
function randomItem<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}
/** 生成模拟列表数据 */
export function mockVehicleList(params: VehicleFilterForm & { plateNo?: string; page?: number; pageSize?: number }): { list: VehicleRecord[]; total: number } {
const total = 48;
const list: VehicleRecord[] = [];
const cities = ['广东省广州市', '广东省深圳市', '浙江省杭州市', '江苏省南京市'];
for (let i = 1; i <= (params.pageSize ?? 20); i++) {
const idx = ((params.page ?? 1) - 1) * (params.pageSize ?? 20) + i;
if (idx > total) break;
list.push({
id: `v-${idx}`,
operationCity: randomItem(cities),
vin: `L${String(idx).padStart(6, '0')}${Math.random().toString(36).slice(2, 11).toUpperCase()}`,
plateNo: `粤A${String(10000 + idx).slice(-5)}`,
vehicleNo: idx <= 10 ? `VN-${idx}` : '',
vehicleType: randomItem(vehicleTypeOptions).label,
brand: randomItem(brandOptions).label,
model: randomItem(modelOptions.brand_a).label,
bodyColor: ['白', '黑', '银', '蓝'][idx % 4],
parkingLot: idx % 3 === 0 ? '-' : `停车场${(idx % 3) + 1}`,
customerName: idx % 4 === 0 ? '-' : `客户${(idx % 4)}`,
businessDept: idx % 4 === 0 ? '-' : `业务${(idx % 4)}`,
businessOwner: idx % 4 === 0 ? '-' : `负责人${idx % 5}`,
operationStatus: randomItem(['待运营', '库存', '租赁', '自营', '退出运营']),
libStatus: randomItem(['库存车-可交付车', '已交付车-租赁交车', '新车入库-待验车']),
outboundStatus: randomItem(['无', '租赁交车', '异动出库']),
preemptStatus: '-',
prepStatus: randomItem(['待整备', '整备中', '正常', '无']),
transferStatus: randomItem(['无', '过户中', '内部过户完成']),
repairStatus: randomItem(['待服务站接单', '维修中', '正常']),
licenseStatus: randomItem(['正常', '异常']),
scrapStatus: randomItem(['无', '报废中', '已报废']),
registeredOwner: '某某物流有限公司',
onlineStatus: randomItem(['在线', '离线']),
manufactureYear: `${2020 + (idx % 5)}`,
mileage: Number((10000 + idx * 500 + Math.random() * 200).toFixed(2)),
purchaseTime: `2022-0${(idx % 9) + 1}-15`,
licenseRegisterDate: `2022-0${(idx % 9) + 1}-01`,
licenseExpiry: `2025-0${(idx % 9) + 1}-01`,
lastDeliveryTime: idx % 2 === 0 ? `2024-01-${String(10 + (idx % 20)).padStart(2, '0')}` : '-',
lastDeliveryMileage: idx % 2 === 0 ? Number((12000 + idx * 100).toFixed(2)) : 0,
lastReturnTime: idx % 2 === 1 ? `2024-02-${String(5 + (idx % 20)).padStart(2, '0')}` : '-',
lastReturnMileage: idx % 2 === 1 ? Number((12500 + idx * 100).toFixed(2)) : 0,
forceScrapDate: `2030-12-31`,
contractNo: idx % 3 === 0 ? '-' : `HT-2024-00${(idx % 3) + 1}`,
currentLocation: `广东省广州市天河区某某路${idx}`,
gpsLastTime: `2024-02-13 ${String(10 + (idx % 12)).padStart(2, '0')}:${String(idx % 60).padStart(2, '0')}`,
});
}
return { list, total };
}

129
src/types/vehicle.ts Normal file
View File

@@ -0,0 +1,129 @@
/** 车辆管理相关类型 */
export type OperationCity = { province: string; city: string };
export type VehicleTypeItem = { value: string; label: string };
export type ModelParamItem = { brand: string; model: string };
export type CustomerItem = { value: string; label: string };
export type DeptItem = { value: string; label: string };
export const OPERATION_STATUS_OPTIONS = [
{ value: 'pending', label: '待运营' },
{ value: 'in_stock', label: '库存' },
{ value: 'lease', label: '租赁' },
{ value: 'self', label: '自营' },
{ value: 'exit', label: '退出运营' },
] as const;
export const LIB_STATUS_OPTIONS = [
{ value: 'new_pending', label: '新车入库-待验车' },
{ value: 'new_license', label: '新车入库-证照办理' },
{ value: 'stock_ok', label: '库存车-可交付车' },
{ value: 'stock_no', label: '库存车-不可交付车' },
{ value: 'stock_slow', label: '库存车-呆滞车' },
{ value: 'out_lease', label: '已交付车-租赁交车' },
{ value: 'out_self', label: '已交付车-自营交车' },
{ value: 'out_replace', label: '已交付车-替换交车' },
{ value: 'exit_scrap', label: '退出运营-报废车' },
{ value: 'exit_third', label: '退出运营-三方退租车' },
{ value: 'exit_sale', label: '退出运营-过户售车' },
] as const;
export const OUTBOUND_STATUS_OPTIONS = [
{ value: 'move', label: '异动出库' },
{ value: 'transfer', label: '调拨出库' },
{ value: 'show', label: '展示出库' },
{ value: 'lease_deliver', label: '租赁交车' },
{ value: 'self_deliver', label: '自营交车' },
{ value: 'replace_deliver', label: '替换交车' },
{ value: 'sale', label: '过户售车' },
{ value: 'lease_return', label: '外租退车' },
{ value: 'scrap', label: '报废出库' },
{ value: 'none', label: '无' },
] as const;
export const PREP_STATUS_OPTIONS = [
{ value: 'pending', label: '待整备' },
{ value: 'doing', label: '整备中' },
{ value: 'normal', label: '正常' },
{ value: 'none', label: '无' },
] as const;
export const TRANSFER_STATUS_OPTIONS = [
{ value: 'doing', label: '过户中' },
{ value: 'internal_done', label: '内部过户完成' },
{ value: 'sale_done', label: '销售过户完成' },
{ value: 'none', label: '无' },
] as const;
export const REPAIR_STATUS_OPTIONS = [
{ value: 'pending', label: '待服务站接单' },
{ value: 'doing', label: '维修中' },
{ value: 'normal', label: '正常' },
] as const;
export const LICENSE_STATUS_OPTIONS = [
{ value: 'normal', label: '正常' },
{ value: 'abnormal', label: '异常' },
] as const;
export const SCRAP_STATUS_OPTIONS = [
{ value: 'doing', label: '报废中' },
{ value: 'done', label: '已报废' },
{ value: 'none', label: '无' },
] as const;
export const ONLINE_STATUS_OPTIONS = [
{ value: 'online', label: '在线' },
{ value: 'offline', label: '离线' },
] as const;
export interface VehicleRecord {
id: string;
operationCity: string;
vin: string;
plateNo: string;
vehicleNo: string;
vehicleType: string;
brand: string;
model: string;
bodyColor: string;
parkingLot: string;
customerName: string;
businessDept: string;
businessOwner: string;
operationStatus: string;
libStatus: string;
outboundStatus: string;
preemptStatus: string;
prepStatus: string;
transferStatus: string;
repairStatus: string;
licenseStatus: string;
scrapStatus: string;
registeredOwner: string;
onlineStatus: string;
manufactureYear: string;
mileage: number;
purchaseTime: string;
licenseRegisterDate: string;
licenseExpiry: string;
lastDeliveryTime: string;
lastDeliveryMileage: number;
lastReturnTime: string;
lastReturnMileage: number;
forceScrapDate: string;
contractNo: string;
currentLocation: string;
gpsLastTime: string;
}
export interface VehicleFilterForm {
operationCity?: string[];
vehicleType?: string;
brand?: string;
model?: string;
customerName?: string;
businessDept?: string;
contractNo?: string;
registeredOwner?: string;
}