Files
ONE-OS/web端/运维管理/车辆业务/备车管理.jsx
王冕 09cc45db36 Initial commit: ONE-OS project
Made-with: Cursor
2026-02-27 18:11:40 +08:00

653 lines
43 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 【重要】必须使用 const Component 作为组件变量名
// 备车管理 - 车辆资产管理后台(按 antd 规范)
const Component = function () {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var DatePicker = antd.DatePicker;
var Select = antd.Select;
var Button = antd.Button;
var Tabs = antd.Tabs;
var Table = antd.Table;
var Modal = antd.Modal;
var Steps = antd.Steps;
var Input = antd.Input;
var Radio = antd.Radio;
var Space = antd.Space;
var Row = antd.Row;
var Col = antd.Col;
var message = antd.message;
var RangePicker = DatePicker.RangePicker;
// 当前视图:'list' | 'add'
var viewState = useState('list');
var currentView = viewState[0];
var setCurrentView = viewState[1];
var filterState = useState({
dateStart: '',
dateEnd: '',
operator: undefined,
plateNo: undefined,
vehicleType: undefined,
parkingLot: undefined
});
var filters = filterState[0];
var setFilters = filterState[1];
// 实际参与列表筛选的条件(点击查询后与 filters 同步)
var appliedFilterState = useState({
dateStart: '',
dateEnd: '',
operator: undefined,
plateNo: undefined,
vehicleType: undefined,
parkingLot: undefined
});
var appliedFilters = appliedFilterState[0];
var setAppliedFilters = appliedFilterState[1];
var activeTabState = useState('completed');
var activeTab = activeTabState[0];
var setActiveTab = activeTabState[1];
var defaultInspection = [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '5.2mm', remark: '' }, { checkType: '车身', checkItem: '车身外观', result: '正常', treadDepth: '', remark: '' }];
var completedListState = useState([
{ id: '1', completeDate: '2025-02-10 09:30', operator: '张三', vehicleType: '厢式货车', plateNo: '京A12345', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M1234567', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=1', 'https://picsum.photos/200/150?random=2', 'https://picsum.photos/200/150?random=3'], tailboard: '有', hasTrailer: '有', trailerPlate: '京B67890', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=4', 'https://picsum.photos/200/150?random=5'], inspectionList: [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '5.2mm', remark: '' }, { checkType: '车身', checkItem: '车身外观', result: '异常', treadDepth: '', remark: '有划痕' }] },
{ id: '2', completeDate: '2025-02-09 10:15', operator: '李四', vehicleType: '平板货车', plateNo: '京C11111', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M7654321', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=6'], inspectionList: [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '异常', treadDepth: '3.1mm', remark: '需更换' }] },
{ id: '3', completeDate: '2025-02-08 11:00', operator: '王五', vehicleType: '厢式货车', plateNo: '京D22222', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M8888888', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=7', 'https://picsum.photos/200/150?random=8'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '4', completeDate: '2025-02-07 13:45', operator: '赵六', vehicleType: '栏板货车', plateNo: '京E33333', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M7777777', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '有', trailerPlate: '京E33334', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=9'], inspectionList: defaultInspection },
{ id: '5', completeDate: '2025-02-06 08:20', operator: '张三', vehicleType: '平板货车', plateNo: '京A23456', brand: '东风', model: 'DFH1190', vin: 'LGHXCAE28M6666666', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=10'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '6', completeDate: '2025-02-05 14:30', operator: '李四', vehicleType: '厢式货车', plateNo: '京B34567', brand: '福田', model: 'BJ1190', vin: 'LGHXCAE28M5555555', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=11', 'https://picsum.photos/200/150?random=12'], inspectionList: defaultInspection },
{ id: '7', completeDate: '2025-02-04 16:00', operator: '王五', vehicleType: '栏板货车', plateNo: '京C45678', brand: '江淮', model: 'HFC1190', vin: 'LGHXCAE28M4444444', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=13', 'https://picsum.photos/200/150?random=14'], tailboard: '有', hasTrailer: '有', trailerPlate: '京C45679', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '8', completeDate: '2025-02-03 09:00', operator: '赵六', vehicleType: '厢式货车', plateNo: '京D56789', brand: '重汽', model: 'ZZ1190', vin: 'LGHXCAE28M3333333', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=15'], inspectionList: defaultInspection },
{ id: '9', completeDate: '2025-02-02 10:30', operator: '张三', vehicleType: '平板货车', plateNo: '京E67890', brand: '东风', model: 'DFH1200', vin: 'LGHXCAE28M2222222', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=16', 'https://picsum.photos/200/150?random=17', 'https://picsum.photos/200/150?random=18'], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '10', completeDate: '2025-02-01 15:45', operator: '李四', vehicleType: '厢式货车', plateNo: '京A78901', brand: '福田', model: 'BJ1200', vin: 'LGHXCAE28M1111111', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '有', hasTrailer: '有', trailerPlate: '京A78902', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection }
]);
var completedList = completedListState[0];
var setCompletedList = completedListState[1];
var pendingListState = useState([
{ id: 'p1', operateDate: '2025-02-10 14:30', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10001', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M9990001', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=19', 'https://picsum.photos/200/150?random=20'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p2', operateDate: '2025-02-09 09:15', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10002', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M9990002', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=21'] },
{ id: 'p3', operateDate: '2025-02-08 11:45', operator: '张三', vehicleType: '栏板货车', plateNo: '京F10003', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M9990003', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=22'], tailboard: '有', hasTrailer: '有', trailerPlate: '京F10004', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p4', operateDate: '2025-02-07 08:00', operator: '李四', vehicleType: '厢式货车', plateNo: '京F10005', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M9990004', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p5', operateDate: '2025-02-06 13:20', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10006', brand: '江淮', model: 'HFC1190', vin: 'LGHXCAE28M9990005', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=23', 'https://picsum.photos/200/150?random=24', 'https://picsum.photos/200/150?random=25'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=26', 'https://picsum.photos/200/150?random=27'] },
{ id: 'p6', operateDate: '2025-02-05 15:30', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10007', brand: '重汽', model: 'ZZ1190', vin: 'LGHXCAE28M9990006', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '有', trailerPlate: '京F10008', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p7', operateDate: '2025-02-04 10:00', operator: '张三', vehicleType: '厢式货车', plateNo: '京F10009', brand: '东风', model: 'DFH1190', vin: 'LGHXCAE28M9990007', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=28', 'https://picsum.photos/200/150?random=29'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p8', operateDate: '2025-02-03 16:45', operator: '李四', vehicleType: '栏板货车', plateNo: '京F10010', brand: '福田', model: 'BJ1190', vin: 'LGHXCAE28M9990008', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=30'] },
{ id: 'p9', operateDate: '2025-02-02 09:30', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10011', brand: '江淮', model: 'HFC1200', vin: 'LGHXCAE28M9990009', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=31'], tailboard: '有', hasTrailer: '有', trailerPlate: '京F10012', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p10', operateDate: '2025-02-01 14:00', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10013', brand: '重汽', model: 'ZZ1200', vin: 'LGHXCAE28M9990010', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] }
]);
var pendingList = pendingListState[0];
var setPendingList = pendingListState[1];
var pageState = useState(1);
var page = pageState[0];
var setPage = pageState[1];
var pageSizeState = useState(10);
var pageSize = pageSizeState[0];
var setPageSize = pageSizeState[1];
var operatorOptions = useMemo(function () { return [{ value: '张三', label: '张三' }, { value: '李四', label: '李四' }, { value: '王五', label: '王五' }, { value: '赵六', label: '赵六' }]; }, []);
var plateOptions = useMemo(function () { return [{ value: '京A12345', label: '京A12345' }, { value: '京C11111', label: '京C11111' }, { value: '京D22222', label: '京D22222' }, { value: '京E33333', label: '京E33333' }]; }, []);
var vehicleTypeOptions = useMemo(function () { return [{ value: '厢式货车', label: '厢式货车' }, { value: '平板货车', label: '平板货车' }, { value: '栏板货车', label: '栏板货车' }]; }, []);
var parkingOptions = useMemo(function () { return [{ value: '朝阳停车场', label: '朝阳停车场' }, { value: '海淀停车场', label: '海淀停车场' }, { value: '丰台停车场', label: '丰台停车场' }, { value: '西城停车场', label: '西城停车场' }]; }, []);
var reqDocOpenState = useState(false);
var photoModalState = useState({ open: false, photos: [], currentIndex: 0 });
var addStepState = useState(1);
var addFormState = useState({
plateNo: '',
vehicleType: '',
brand: '',
vin: '',
bodyAd: '无',
adPhotos: [],
tailboard: '无',
hasTrailer: '',
trailerPlate: '',
flawPhotos: [],
inspectionList: [
{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' },
{ checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' },
{ checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '', remark: '' },
{ checkType: '车身', checkItem: '车身外观', result: '正常', treadDepth: '', remark: '' }
]
});
var filteredCompleted = useMemo(function () {
var list = completedList.slice();
if (appliedFilters.operator) list = list.filter(function (r) { return r.operator.indexOf(appliedFilters.operator) !== -1; });
if (appliedFilters.plateNo) list = list.filter(function (r) { return r.plateNo.indexOf(appliedFilters.plateNo) !== -1; });
if (appliedFilters.vehicleType) list = list.filter(function (r) { return r.vehicleType.indexOf(appliedFilters.vehicleType) !== -1; });
if (appliedFilters.parkingLot) list = list.filter(function (r) { return r.parkingLot.indexOf(appliedFilters.parkingLot) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.completeDate || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.completeDate || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
return list.sort(function (a, b) { return (b.completeDate || '').localeCompare(a.completeDate || ''); });
}, [completedList, appliedFilters]);
var filteredPending = useMemo(function () {
var list = pendingList.slice();
if (appliedFilters.operator) list = list.filter(function (r) { return r.operator.indexOf(appliedFilters.operator) !== -1; });
if (appliedFilters.plateNo) list = list.filter(function (r) { return r.plateNo.indexOf(appliedFilters.plateNo) !== -1; });
if (appliedFilters.vehicleType) list = list.filter(function (r) { return r.vehicleType.indexOf(appliedFilters.vehicleType) !== -1; });
if (appliedFilters.parkingLot) list = list.filter(function (r) { return r.parkingLot.indexOf(appliedFilters.parkingLot) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.operateDate || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.operateDate || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
return list.sort(function (a, b) { return (b.operateDate || '').localeCompare(a.operateDate || ''); });
}, [pendingList, appliedFilters]);
var displayCompleted = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredCompleted.slice(start, start + pageSize);
}, [filteredCompleted, page, pageSize]);
var displayPending = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredPending.slice(start, start + pageSize);
}, [filteredPending, page, pageSize]);
var totalCompleted = filteredCompleted.length;
var totalPending = filteredPending.length;
var totalCount = activeTab === 'completed' ? totalCompleted : totalPending;
var handleQuery = useCallback(function () {
setAppliedFilters({ dateStart: filters.dateStart, dateEnd: filters.dateEnd, operator: filters.operator, plateNo: filters.plateNo, vehicleType: filters.vehicleType, parkingLot: filters.parkingLot });
setPage(1);
}, [filters.dateStart, filters.dateEnd, filters.operator, filters.plateNo, filters.vehicleType, filters.parkingLot]);
var handleReset = useCallback(function () {
var empty = { dateStart: '', dateEnd: '', operator: undefined, plateNo: undefined, vehicleType: undefined, parkingLot: undefined };
setFilters(empty);
setAppliedFilters(empty);
setPage(1);
}, []);
var handleExport = useCallback(function () {
if (activeTab !== 'completed') {
message.warning('请在「已完成」Tab 下导出');
return;
}
var rows = filteredCompleted;
var headers = ['备车时间', '备车人', '车辆类型', '车牌号', '品牌', '型号', '车辆识别代码', '停车场', '车身广告', '广告照片', '尾板', '是否有挂', '挂车牌号', '瑕疵照片'];
var csv = headers.join(',') + '\n';
rows.forEach(function (r) {
csv += [r.completeDate, r.operator, r.vehicleType, r.plateNo, r.brand, r.model, r.vin, r.parkingLot, r.bodyAd, (r.adPhotoCount || 0) + '张', r.tailboard, r.hasTrailer, r.trailerPlate || '', (r.flawPhotoCount || 0) + '张'].join(',') + '\n';
});
var blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = '备车管理导出_' + new Date().getTime() + '.csv';
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
}, [activeTab, filteredCompleted]);
var openPhotoModal = useCallback(function (photos, index) {
if (!photos || photos.length === 0) return;
photoModalState[1]({ open: true, photos: photos, currentIndex: index || 0 });
}, []);
var addForm = addFormState[0];
var setAddForm = addFormState[1];
var addStep = addStepState[0];
var setAddStep = addStepState[1];
var handleAddSave = useCallback(function () {
var d = new Date();
var pad = function (n) { return String(n).padStart(2, '0'); };
var dateTimeStr = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
var item = {
id: 'p' + Date.now(),
operateDate: dateTimeStr,
operator: '当前用户',
vehicleType: addForm.vehicleType || '厢式货车',
plateNo: addForm.plateNo,
brand: addForm.brand || '-',
model: addForm.model || '-',
vin: addForm.vin,
parkingLot: addForm.parkingLot || '朝阳停车场',
bodyAd: addForm.bodyAd,
adPhotoCount: (addForm.adPhotos && addForm.adPhotos.length) || 0,
adPhotos: addForm.adPhotos || [],
tailboard: addForm.tailboard,
hasTrailer: addForm.trailerPlate ? '有' : '无',
trailerPlate: addForm.trailerPlate || '',
flawPhotoCount: (addForm.flawPhotos && addForm.flawPhotos.length) || 0,
flawPhotos: addForm.flawPhotos || []
};
setPendingList(pendingList.concat([item]));
setCurrentView('list');
setActiveTab('pending');
setAddForm({ plateNo: '', vehicleType: '', brand: '', vin: '', bodyAd: '无', adPhotos: [], tailboard: '无', hasTrailer: '', trailerPlate: '', flawPhotos: [], inspectionList: addForm.inspectionList });
setAddStep(1);
message.success('已保存至待提交列表');
}, [addForm, pendingList]);
var handleAddNext = useCallback(function () {
if (!addForm.plateNo) {
message.warning('请选择车牌号');
return;
}
setAddStep(2);
}, [addForm.plateNo]);
var handleAddSubmit = useCallback(function () {
var d = new Date();
var pad = function (n) { return String(n).padStart(2, '0'); };
var dateTimeStr = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
var item = {
id: String(Date.now()),
completeDate: dateTimeStr,
operator: '当前用户',
vehicleType: addForm.vehicleType || '厢式货车',
plateNo: addForm.plateNo,
brand: addForm.brand || '-',
model: addForm.model || '-',
vin: addForm.vin,
parkingLot: addForm.parkingLot || '朝阳停车场',
bodyAd: addForm.bodyAd,
adPhotoCount: (addForm.adPhotos && addForm.adPhotos.length) || 0,
adPhotos: addForm.adPhotos || [],
tailboard: addForm.tailboard,
hasTrailer: addForm.trailerPlate ? '有' : '无',
trailerPlate: addForm.trailerPlate || '',
flawPhotoCount: (addForm.flawPhotos && addForm.flawPhotos.length) || 0,
flawPhotos: addForm.flawPhotos || [],
inspectionList: addForm.inspectionList || []
};
setCompletedList(completedList.concat([item]));
setCurrentView('list');
setActiveTab('completed');
setAddForm({ plateNo: '', vehicleType: '', brand: '', vin: '', bodyAd: '无', adPhotos: [], tailboard: '无', hasTrailer: '', trailerPlate: '', flawPhotos: [], inspectionList: addForm.inspectionList });
setAddStep(1);
message.success('提交成功');
}, [addForm, completedList]);
var onPlateSelect = useCallback(function (plateNo) {
setAddForm(function (prev) {
var next = {};
for (var k in prev) next[k] = prev[k];
next.plateNo = plateNo;
next.vehicleType = '厢式货车';
next.brand = '东风';
next.vin = 'LGHXCAE28M' + Math.floor(Math.random() * 10000000);
return next;
});
}, []);
var requirementDocContent = '#.面包屑:运维管理-车辆业务-备车管理,支持点击对应模块跳转\n\n#筛选:支持通过备车日期、备车人、车牌号、车辆类型、停车场等方式进行筛选;\n1.备车日期日期选择器点击显示两个日历控件支持选择开始和结束时间时间格式为YYYY-MM-DD;\n2.备车人:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n3.车牌号:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n4.车辆类型:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n5.停车场:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n6.右侧显示查询、重置按钮,点击查询按钮按筛选条件显示列表内容,点击重置清除筛选条件并按默认条件显示列表内容;\n\n#列表:\n列表分为两个tab分别为已完成、待检查已完成列表右侧包含新增、导出按钮,下方增加分页功能,支持选择单页显示数据记录条数;\n1.已完成tab显示完成车辆记录及备车检查两个步骤表单并点击提交的记录\n2.待检查tab显示新增备车时只点击保存但未提交的记录\n3.点击新增按钮,打开新页面进行新增表单页;\n4.导出需全选/多选对应数据记录再点击导出下载csv\n5.列表以区域进行数据权限划分,用户表中对应区域的用户只能查询自己区域的数据;';
// 日期范围变化antd RangePicker 返回 dayjs 或 [string, string] 依项目而定,此处用字符串存)
function onDateRangeChange(dates, dateStrings) {
setFilters(function (f) {
var g = {};
for (var k in f) g[k] = f[k];
g.dateStart = (dateStrings && dateStrings[0]) || '';
g.dateEnd = (dateStrings && dateStrings[1]) || '';
return g;
});
}
var dateRangeValue = useMemo(function () {
if (!filters.dateStart && !filters.dateEnd) return null;
try {
if (typeof window.dayjs === 'function' && filters.dateStart && filters.dateEnd) {
return [window.dayjs(filters.dateStart), window.dayjs(filters.dateEnd)];
}
} catch (e) {}
return null;
}, [filters.dateStart, filters.dateEnd]);
// 已完成表格列(含多选、照片链接、操作列查看按钮,点击不打开新页面)
function getCompletedColumns(openPhoto) {
return [
{ title: '备车时间', dataIndex: 'completeDate', key: 'completeDate', width: 160 },
{ title: '备车人', dataIndex: 'operator', key: 'operator', width: 90 },
{ title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 },
{ title: '型号', dataIndex: 'model', key: 'model', width: 100 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 },
{ title: '车辆识别代码', dataIndex: 'vin', key: 'vin', width: 180 },
{ title: '停车场', dataIndex: 'parkingLot', key: 'parkingLot', width: 110 },
{ title: '车身广告', dataIndex: 'bodyAd', key: 'bodyAd', width: 90 },
{ title: '广告照片', key: 'adPhotos', width: 90, render: function (_, r) {
var photos = r.adPhotos && r.adPhotos.length > 0 ? r.adPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '尾板', dataIndex: 'tailboard', key: 'tailboard', width: 70 },
{ title: '是否有挂', dataIndex: 'hasTrailer', key: 'hasTrailer', width: 90 },
{ title: '挂车牌号', dataIndex: 'trailerPlate', key: 'trailerPlate', width: 100, render: function (v) { return v || '-'; } },
{ title: '瑕疵照片', key: 'flawPhotos', width: 90, render: function (_, r) {
var photos = r.flawPhotos && r.flawPhotos.length > 0 ? r.flawPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () {} }, '查看');
}}
];
}
function getPendingColumns(openPhoto, onEdit) {
return [
{ title: '创建时间', dataIndex: 'operateDate', key: 'operateDate', width: 160 },
{ title: '备车人', dataIndex: 'operator', key: 'operator', width: 90 },
{ title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 },
{ title: '型号', dataIndex: 'model', key: 'model', width: 100 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 },
{ title: '车辆识别代码', dataIndex: 'vin', key: 'vin', width: 180 },
{ title: '停车场', dataIndex: 'parkingLot', key: 'parkingLot', width: 110 },
{ title: '车身广告', dataIndex: 'bodyAd', key: 'bodyAd', width: 90 },
{ title: '广告照片', key: 'adPhotos', width: 90, render: function (_, r) {
var photos = (r.adPhotos && r.adPhotos.length > 0) ? r.adPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '尾板', dataIndex: 'tailboard', key: 'tailboard', width: 70 },
{ title: '是否有挂', dataIndex: 'hasTrailer', key: 'hasTrailer', width: 90 },
{ title: '挂车牌号', dataIndex: 'trailerPlate', key: 'trailerPlate', width: 100, render: function (v) { return v || '-'; } },
{ title: '瑕疵照片', key: 'flawPhotos', width: 90, render: function (_, r) {
var photos = (r.flawPhotos && r.flawPhotos.length > 0) ? r.flawPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () {
setAddForm(function (prev) {
var n = {};
for (var k in prev) n[k] = prev[k];
n.plateNo = r.plateNo; n.vehicleType = r.vehicleType; n.brand = r.brand; n.vin = r.vin;
n.bodyAd = r.bodyAd; n.adPhotos = r.adPhotos || []; n.tailboard = r.tailboard;
n.trailerPlate = r.trailerPlate || ''; n.flawPhotos = r.flawPhotos || [];
return n;
});
setAddStep(1);
setCurrentView('add');
} }, '编辑');
}}
];
}
var tablePagination = useMemo(function () {
return {
current: page,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
showTotal: function (t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50'],
onChange: function (p, size) {
setPage(p);
if (size !== pageSize) setPageSize(size);
}
};
}, [page, pageSize, totalCount]);
// —————— 列表页 ——————
function ListView() {
var breadcrumbItems = [
{ title: '运维管理' },
{ title: '车辆业务' },
{ title: '备车管理' }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } },
React.createElement(Breadcrumb, { items: breadcrumbItems }),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { reqDocOpenState[1](true); } }, '查看需求说明')
),
React.createElement(Modal, {
title: '需求说明',
open: reqDocOpenState[0],
onCancel: function () { reqDocOpenState[1](false); },
footer: null,
width: 720,
styles: { body: { maxHeight: '70vh', overflow: 'auto', whiteSpace: 'pre-wrap', fontSize: 14 } }
}, requirementDocContent.split('\n').map(function (line, idx) {
var trimmed = line;
if (trimmed.indexOf('#') === 0) {
return React.createElement('div', { key: idx, style: { fontWeight: 'bold', marginTop: idx === 0 ? 0 : 16, marginBottom: 8, paddingBottom: 4, borderBottom: '1px solid #f0f0f0' } }, trimmed.replace(/^#\.?/, '').trim());
}
if (/^\d+\./.test(trimmed)) return React.createElement('div', { key: idx, style: { marginLeft: 12, marginBottom: 4 } }, trimmed);
if (trimmed === '') return React.createElement('div', { key: idx, style: { height: 12 } });
return React.createElement('div', { key: idx, style: { marginBottom: 8 } }, trimmed);
})),
React.createElement(Card, { style: { marginBottom: 16 } },
React.createElement('div', {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
gap: '16px 24px',
alignItems: 'start',
flex: 1,
minWidth: 0
}
},
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '备车日期'),
React.createElement(RangePicker, {
value: dateRangeValue,
onChange: onDateRangeChange,
style: { width: '100%' },
placeholder: ['开始日期', '结束日期']
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '备车人'),
React.createElement(Select, {
placeholder: '请选择备车人',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.operator,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.operator = v; return g; }); },
style: { width: '100%' },
options: operatorOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '车牌号'),
React.createElement(Select, {
placeholder: '请选择车牌号',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.plateNo,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.plateNo = v; return g; }); },
style: { width: '100%' },
options: plateOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '车辆类型'),
React.createElement(Select, {
placeholder: '请选择车辆类型',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.vehicleType,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.vehicleType = v; return g; }); },
style: { width: '100%' },
options: vehicleTypeOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '停车场'),
React.createElement(Select, {
placeholder: '请选择停车场',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.parkingLot,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.parkingLot = v; return g; }); },
style: { width: '100%' },
options: parkingOptions
})
)
),
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16 } },
React.createElement(Button, { onClick: handleReset }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleQuery }, '查询')
)
),
React.createElement(Card, null,
React.createElement(Tabs, {
activeKey: activeTab,
onChange: function (k) { setActiveTab(k); setPage(1); },
tabBarExtraContent: React.createElement('div', { style: { display: 'flex', gap: 8 } },
React.createElement(Button, { type: 'primary', onClick: function () {} }, '新增'),
activeTab === 'completed' ? React.createElement(Button, { onClick: handleExport }, '导出') : null
),
items: [
{
key: 'completed',
label: '已完成',
children: React.createElement(Table, {
columns: getCompletedColumns(openPhotoModal),
dataSource: displayCompleted,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1400 },
size: 'middle'
})
},
{
key: 'pending',
label: '待提交',
children: React.createElement(Table, {
columns: getPendingColumns(openPhotoModal),
dataSource: displayPending,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1400 },
size: 'middle'
})
}
]
})
),
// 照片预览:全屏遮罩 + 放大图片,点击遮罩关闭
photoModalState[0].open && photoModalState[0].photos && photoModalState[0].photos.length > 0 ? React.createElement('div', {
style: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.75)',
zIndex: 1000,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer'
},
onClick: function () { photoModalState[1]({ open: false, photos: [], currentIndex: 0 }); }
}, React.createElement('div', {
style: { position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center', cursor: 'default', maxWidth: '100%', maxHeight: '100%' },
onClick: function (e) { if (e) e.stopPropagation(); }
},
React.createElement('img', {
src: photoModalState[0].photos[photoModalState[0].currentIndex] || photoModalState[0].photos[0],
alt: '',
style: { maxWidth: '90vw', maxHeight: '85vh', objectFit: 'contain' }
}),
photoModalState[0].photos.length > 1 ? React.createElement('div', { style: { marginTop: 16, display: 'flex', alignItems: 'center', gap: 16 } },
React.createElement(Button, {
disabled: photoModalState[0].currentIndex === 0,
onClick: function (e) { e.stopPropagation(); photoModalState[1]({ open: true, photos: photoModalState[0].photos, currentIndex: Math.max(0, photoModalState[0].currentIndex - 1) }); }
}, '上一张'),
React.createElement('span', { style: { color: '#fff' } }, (photoModalState[0].currentIndex + 1) + ' / ' + photoModalState[0].photos.length),
React.createElement(Button, {
disabled: photoModalState[0].currentIndex >= photoModalState[0].photos.length - 1,
onClick: function (e) { e.stopPropagation(); photoModalState[1]({ open: true, photos: photoModalState[0].photos, currentIndex: Math.min(photoModalState[0].photos.length - 1, photoModalState[0].currentIndex + 1) }); }
}, '下一张')
) : null
)) : null
);
}
// —————— 新增页 ——————
function AddView() {
var form = addFormState[0];
var setForm = addFormState[1];
var step = addStepState[0];
var addBreadcrumbItems = [
{ title: '运维管理' },
{ title: '车辆业务' },
{ title: '备车管理' },
{ title: '新增备车' }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement(Breadcrumb, { items: addBreadcrumbItems, style: { marginBottom: 16 } }),
React.createElement(Card, null,
React.createElement(Steps, { current: step - 1, style: { marginBottom: 24 }, items: [
{ title: '步骤1 车辆记录' },
{ title: '步骤2 备车检查' }
] }),
step === 1 ? React.createElement(Row, { gutter: [16, 16] },
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车牌号 *'), React.createElement(Select, { placeholder: '请选择车牌号(仅库存车辆)', allowClear: true, showSearch: true, optionFilterProp: 'label', value: form.plateNo || undefined, onChange: onPlateSelect, style: { width: 200 }, options: plateOptions })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车辆类型'), React.createElement(Input, { value: form.vehicleType, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '品牌'), React.createElement(Input, { value: form.brand, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车架号'), React.createElement(Input, { value: form.vin, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车身广告 *'), React.createElement(Radio.Group, { value: form.bodyAd, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.bodyAd = e.target.value; return n; }); }, options: [{ value: '无', label: '无' }, { value: '有', label: '有' }] })),
form.bodyAd === '有' ? React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '广告照片最多5张'), React.createElement(Space, null, (form.adPhotos || []).slice(0, 5).map(function (url, i) { return React.createElement('img', { key: i, src: url, alt: '', style: { width: 60, height: 60, objectFit: 'cover', borderRadius: 4 } }); }), (form.adPhotos || []).length < 5 ? React.createElement(Button, { onClick: function () { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.adPhotos = (p.adPhotos || []).concat(['https://picsum.photos/200/150?r=' + Date.now()]); return n; }); } }, '上传') : null)) : null,
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '尾板 *'), React.createElement(Radio.Group, { value: form.tailboard, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.tailboard = e.target.value; return n; }); }, options: [{ value: '无', label: '无' }, { value: '有', label: '有' }] })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '挂车牌号(有挂时填写)'), React.createElement(Input, { value: form.trailerPlate, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.trailerPlate = e.target.value; return n; }); }, placeholder: '不填视为无挂', style: { width: 200 } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '瑕疵照片最多5张'), React.createElement(Space, null, (form.flawPhotos || []).slice(0, 5).map(function (url, i) { return React.createElement('img', { key: i, src: url, alt: '', style: { width: 60, height: 60, objectFit: 'cover', borderRadius: 4 } }); }), (form.flawPhotos || []).length < 5 ? React.createElement(Button, { onClick: function () { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.flawPhotos = (p.flawPhotos || []).concat(['https://picsum.photos/200/150?f=' + Date.now()]); return n; }); } }, '上传') : null)),
React.createElement(Col, { span: 24 }, React.createElement(Space, null, React.createElement(Button, { type: 'primary', onClick: handleAddNext }, '下一步'), React.createElement(Button, { onClick: handleAddSave }, '保存'), React.createElement(Button, { onClick: function () { setCurrentView('list'); } }, '取消')))
) : React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 16, fontWeight: 600 } }, '备车检查'),
React.createElement(Table, {
dataSource: form.inspectionList || [],
rowKey: function (_, i) { return i; },
pagination: false,
columns: [
{ title: '检查类型', dataIndex: 'checkType', width: 100 },
{ title: '检查项', dataIndex: 'checkItem', width: 120 },
{ title: '检查项结果', dataIndex: 'result', width: 120, render: function (val, record, i) {
return React.createElement(Select, { value: val, onChange: function (v) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { result: v }); n.inspectionList = list; return n; }); }, style: { width: '100%' }, options: [{ value: '正常', label: '正常' }, { value: '异常', label: '异常' }] });
}},
{ title: '胎纹深度(轮胎时)', key: 'treadDepth', width: 140, render: function (_, record, i) {
if (record.checkItem && record.checkItem.indexOf('胎') !== -1) {
return React.createElement(Input, { value: record.treadDepth, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { treadDepth: e.target.value }); n.inspectionList = list; return n; }); }, placeholder: '胎纹深度' });
}
return '-';
}},
{ title: '备注', dataIndex: 'remark', render: function (val, record, i) {
return React.createElement(Input, { value: val, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { remark: e.target.value }); n.inspectionList = list; return n; }); }, placeholder: '备注' });
}}
]
}),
React.createElement('div', { style: { marginTop: 16 } }, React.createElement(Space, null, React.createElement(Button, { type: 'primary', onClick: handleAddSubmit }, '提交'), React.createElement(Button, { onClick: handleAddSave }, '保存'), React.createElement(Button, { onClick: function () { setCurrentView('list'); } }, '取消')))
)
)
);
}
return ListView();
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}