feat(web): 同步交车任务、租赁合同、提车应收款等调整

- 更新多处页面交互与需求说明弹窗文案
- 新增 ETC 管理相关原型页面与需求说明目录内容

Made-with: Cursor
This commit is contained in:
王冕
2026-03-12 16:07:38 +08:00
parent 30e3d9f156
commit 6e149d9373
26 changed files with 3144 additions and 366 deletions

View File

@@ -7,6 +7,7 @@ const Component = function() {
var Select = antd.Select;
var Button = antd.Button;
var DatePicker = antd.DatePicker;
var Modal = antd.Modal;
var message = antd.message;
var Option = Select.Option;
var Checkbox = antd.Checkbox;
@@ -17,14 +18,28 @@ const Component = function() {
var selectedProjectId = projectId[0];
var setSelectedProjectId = projectId[1];
var expectedDelivery = React.useState(null);
var expectedDelivery = React.useState(function() {
if (typeof window !== 'undefined' && window.dayjs) {
return [window.dayjs('2026-03-01'), window.dayjs('2026-03-05')];
}
return null;
});
var expectedDeliveryValue = expectedDelivery[0];
var setExpectedDelivery = expectedDelivery[1];
var billingDate = React.useState(null);
var billingDate = React.useState(function() {
if (typeof window !== 'undefined' && window.dayjs) {
return window.dayjs('2026-03-06');
}
return null;
});
var billingDateValue = billingDate[0];
var setBillingDate = billingDate[1];
var noReturnCarCheckedState = React.useState(false);
var noReturnCarChecked = noReturnCarCheckedState[0];
var setNoReturnCarChecked = noReturnCarCheckedState[1];
var selectedRowKeys = React.useState(['v3', 'v4']);
var checkedRowKeys = selectedRowKeys[0];
var setCheckedRowKeys = selectedRowKeys[1];
@@ -33,11 +48,9 @@ const Component = function() {
var errors = formErrors[0];
var setErrors = formErrors[1];
var reqSpecState = React.useState(false);
var reqSpecOpen = reqSpecState[0];
var setReqSpecOpen = reqSpecState[1];
var reqModalOpen = React.useState(false);
// Mock项目列表及车辆样例。deliveryStatus: 'none' 可选,'submitted' 已提交交车任务不可选,'completed' 已完成交车不显示
// Mock项目列表及车辆(与新增交车任务一致,含续签项目)
var projectList = [
{ id: 'p1', name: '嘉兴某某物流氢能运输项目', contractCode: 'JXZL20260216YW101235A', customerName: '嘉兴某某物流有限公司', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '浙江省嘉兴市南湖区科技大道1号', vehicles: [
{ key: 'v1', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10001', vin: 'LFV2BJCH8K3123456', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '首车', deliveryStatus: 'submitted' },
@@ -46,6 +59,13 @@ const Component = function() {
{ key: 'v4', brand: '重汽', model: '豪沃氢能牵引车', plateNo: '浙F20001', vin: 'ZZ4257N386FZ12345', monthRent: '15000', serviceFee: '1000', deposit: '35000', remark: '', deliveryStatus: 'none' },
{ key: 'v5', brand: '陕汽', model: '德龙氢能自卸', plateNo: '浙F20002', vin: 'SX1313GR456123456', monthRent: '13200', serviceFee: '880', deposit: '32000', remark: '固定线路', deliveryStatus: 'none' }
]},
{ id: 'p1_r', name: '嘉兴某某物流氢能运输项目(续签合同)', isRenewal: true, contractCode: 'JXZL20270116YW101235B', customerName: '嘉兴某某物流有限公司', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '浙江省嘉兴市南湖区科技大道1号', vehicles: [
{ key: 'v1r_1', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10001', vin: 'LFV2BJCH8K3123456', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '续签合同车辆', deliveryStatus: 'none' },
{ key: 'v1r_0', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A09999', vin: 'LFV2BJCH8K3000000', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '续签:已交车车辆样例', deliveryStatus: 'completed' },
{ key: 'v1r_0b', brand: '福田', model: '智蓝氢能轻卡', plateNo: '浙A08888', vin: 'LZYTBACR2M1000001', monthRent: '8500', serviceFee: '500', deposit: '20000', remark: '续签:已交车车辆样例', deliveryStatus: 'completed' },
{ key: 'v1r_0c', brand: '重汽', model: '豪沃氢能牵引车', plateNo: '浙A07777', vin: 'ZZ4257N386FZ00002', monthRent: '15000', serviceFee: '1000', deposit: '35000', remark: '续签:已交车车辆样例', deliveryStatus: 'completed' },
{ key: 'v1r_2', brand: '福田', model: '智蓝氢能轻卡', plateNo: '', vin: 'LZYTBACR2M1234567', monthRent: '8500', serviceFee: '500', deposit: '20000', remark: '续签待上牌', deliveryStatus: 'none' }
]},
{ id: 'p2', name: '上海某某运输氢能租赁项目', contractCode: 'SHZL20260201YW200123A', customerName: '上海某某运输公司', deliveryRegion: '上海市 / 上海市', deliveryLocation: '上海市浦东新区张江高科技园区', vehicles: [
{ key: 'v6', brand: '上汽红岩', model: '杰狮氢能牵引', plateNo: '沪A30003', vin: 'SH1313HY789012345', monthRent: '14500', serviceFee: '950', deposit: '34000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v7', brand: '宇通', model: '氢能公交 ZK6126', plateNo: '沪B40001', vin: 'LZYTAGCF8K4567890', monthRent: '22000', serviceFee: '1200', deposit: '50000', remark: '示范线路', deliveryStatus: 'none' },
@@ -60,13 +80,24 @@ const Component = function() {
];
var selectedProject = projectList.find(function(p) { return p.id === selectedProjectId; });
var isRenewalProject = !!(selectedProject && selectedProject.isRenewal);
var vehicleListRaw = selectedProject ? selectedProject.vehicles : [];
var vehicleList = vehicleListRaw.filter(function(v) { return v.deliveryStatus !== 'completed'; });
var selectableVehicles = vehicleList.filter(function(v) { return v.deliveryStatus !== 'submitted'; });
var vehicleList = vehicleListRaw.filter(function(v) {
if (v.deliveryStatus === 'completed') { if (!isRenewalProject) return false; return true; }
if (v.deliveryStatus === 'submitted') return true;
if (isRenewalProject && !!noReturnCarChecked) return false;
return true;
});
var selectableVehicles = vehicleList.filter(function(v) {
if (v.deliveryStatus === 'submitted') return false;
if (v.deliveryStatus === 'completed') return isRenewalProject && !!noReturnCarChecked;
return true;
});
var handleProjectChange = function(id) {
setSelectedProjectId(id || '');
setCheckedRowKeys([]);
setNoReturnCarChecked(false);
};
var todayStr = (function() {
@@ -84,14 +115,15 @@ const Component = function() {
return null;
};
var expectedDeliveryError = validateExpectedDelivery();
var needExpectedDelivery = !(isRenewalProject && noReturnCarChecked);
var expectedDeliveryError = needExpectedDelivery ? validateExpectedDelivery() : null;
var billingDateError = !billingDateValue ? '请选择开始计费日期' : null;
var handleSubmit = function() {
var err = {};
if (!selectedProjectId) err.projectName = '请选择项目名称';
if (expectedDeliveryError) err.expectedDelivery = expectedDeliveryError;
if (needExpectedDelivery && expectedDeliveryError) err.expectedDelivery = expectedDeliveryError;
if (billingDateError) err.billingDate = billingDateError;
if (checkedRowKeys.length === 0 && selectableVehicles.length > 0) err.vehicles = '请至少选择一辆车';
setErrors(err);
@@ -99,6 +131,17 @@ const Component = function() {
message.success('交车任务已保存。');
};
var onToggleNoReturnCar = function(e) {
var next = !!(e && e.target ? e.target.checked : e);
setNoReturnCarChecked(next);
if (!next) {
setCheckedRowKeys(function(prev) {
var completedKeys = vehicleList.filter(function(v) { return v && v.deliveryStatus === 'completed'; }).map(function(v) { return v.key; });
return prev.filter(function(k) { return completedKeys.indexOf(k) === -1; });
});
}
};
var handleCancel = function() {
message.info('取消');
};
@@ -138,21 +181,7 @@ const Component = function() {
modalBody: { padding: 20, overflow: 'auto', flex: 1 }
};
var reqSpecBlock = { marginBottom: 16 };
var reqSpecH2 = { fontSize: 14, fontWeight: 600, color: '#333', marginBottom: 6 };
var reqSpecLi = { fontSize: 13, color: '#666', marginBottom: 2, paddingLeft: 8 };
var reqSpecDoc = React.createElement('div', { style: { padding: '0 4px' } },
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '1.面包屑:'), React.createElement('div', { style: reqSpecLi }, '1.1.业务管理-交车任务-编辑交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '2.表单:'),
React.createElement('div', { style: reqSpecLi }, '2.1.选择项目名称:已选择禁用,不可修改;'),
React.createElement('div', { style: reqSpecLi }, '2.2.合同编码、客户名称、交车区域、交车地点、预计交车日期、开始计费日期、车辆列表等可修改;'),
React.createElement('div', { style: reqSpecLi }, '预计交车日期:不能早于当前日期'),
React.createElement('div', { style: reqSpecLi }, '2.9.页面底部为提交、取消;')
));
var reqSpecModalContent = reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '需求说明'), React.createElement('div', { style: Object.assign({}, styles.modalBody, { maxHeight: '70vh', padding: '20px 24px' }) }, reqSpecDoc), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement(Button, { onClick: function() { setReqSpecOpen(false); } }, '关闭')))) : null;
var reqSpecText = '编辑交车任务\n一个「数字化资产ONEOS运管平台」中的「交车任务」「编辑」模块\n1.面包屑:\n1.1.业务管理-交车任务-编辑\n\n2.表单:\n2.1.选择项目名称:必选项,反写新增时写入的数据,选择器,默认提示文本:请选择或输入项目名称,支持从输入框内输入内容进行模糊搜索,对应自营合同、租赁合同-「项目名称」字段;;\n2.2.合同编码:输入框(禁用状态),根据所选项目名称自动反写合同编码;\n2.3.客户名称:输入框(禁用状态),根据所选项目名称自动反写客户名称;\n2.4.交车区域:输入框(禁用状态),根据所选项目名称自动反写交车区域。提交时根据交车区域,为对应区域运维人员分配对应交车任务;\n2.5.交车地点:输入框(禁用状态),根据所选项目名称自动反写交车地点;\n2.6.预计交车日期必填项反写新增时写入的数据日期选择器支持某天或某个时间段两种模式格式为YYYY-MM-DD或YYYY-MM-DD至YYYY-MM-DD结束日期不能早于开始日期并且结束日期不能早于当前日期\n 2.6.1.如勾选不需要还车,则预计交车日期隐藏,不需要设置;\n2.7.开始计费日期必填项反写新增时写入的数据日期选择器支持单日选择格式为YYYY-MM-DD\n2.8.已交车辆是否需要还车:勾选框,反写新增时写入的数据,内容为不需要还车,默认不勾选,不勾选时,无法在车辆列表勾选已交未还的车辆,勾选后,已交未还的车辆也可以勾选,但不会生成新交车任务,只是按照开始计费日期生成账单;\n 2.8.1.勾选时,车辆列表只显示已交未还的车辆清单,不能添加新车(避免已交未还部分车辆开始计费日期计算不精确);\n 2.8.2.不勾选时,车辆列表显示已交未还的车辆清单及续签合同新增车辆,但是已交未还部分的车辆不可勾选;\n2.9.下方为列表,列表拉取该车辆租赁合同对应所有车辆信息(该合同下已提交过交车任务的车辆不可选,已完成交车的车辆不显示在列表中),列表字段为:全选/多选、品牌、型号、车牌号、车辆识别代码、车辆月租金、服务费、保证金、备注;\n 2.9.1.全选/多选支持全选、多选模式反写新增时写入的数据选择对应车辆后点击提交自动生成被选中车辆交车任务需要至少选择1辆才能进行提交该合同下已提交过交车任务和已交车的车辆不可选多选框为禁用状态悬浮时提示该车辆已完成交车/该车辆已创建交车任务;\n 2.9.2.品牌:输入框(禁用状态),根据所选项目名称自动反写品牌;\n 2.9.3.型号:输入框(禁用状态),根据所选项目名称自动反写型号;\n 2.9.4.车牌号:输入框(禁用状态),根据所选项目名称自动反写车牌号,车牌号可能为空,为空时显示为-\n 2.9.5.车辆识别代码:输入框(禁用状态),根据所选项目名称自动反写车辆识别代码;\n 2.9.6.车辆月租金:输入框(禁用状态),根据所选项目名称自动反写车辆月租金,后缀为元;\n 2.9.7.服务费:输入框(禁用状态),根据所选项目名称自动反写服务费,后缀为元;\n 2.9.8.保证金:输入框(禁用状态),根据所选项目名称自动反写保证金,后缀为元;\n 2.9.9.备注:输入框(禁用状态),根据所选项目名称自动反写备注信息,备注为空时显示为-\n2.10.页面底部为提交、取消;';
var FormItem = function(props) {
return React.createElement('div', { style: styles.formCol },
@@ -167,7 +196,7 @@ const Component = function() {
var formRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '选择项目名称', required: true, error: errors.projectName },
React.createElement(Select, {
placeholder: '请选择或输入项目名称',
placeholder: '请选择或输入项目名称(对应自营合同、租赁合同-项目名称)',
style: { width: '100%' },
value: selectedProjectId || undefined,
disabled: true,
@@ -182,7 +211,7 @@ const Component = function() {
);
var formRow2 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '预计交车日期', required: true, error: errors.expectedDelivery },
needExpectedDelivery ? React.createElement(FormItem, { label: '预计交车日期', required: true, error: errors.expectedDelivery },
React.createElement(RangePicker, {
style: { width: '100%' },
format: 'YYYY-MM-DD',
@@ -190,7 +219,7 @@ const Component = function() {
value: expectedDeliveryValue,
onChange: function(dates) { setExpectedDelivery(dates && dates.length === 2 ? dates : null); },
status: errors.expectedDelivery ? 'error' : undefined
})),
})) : null,
React.createElement(FormItem, { label: '开始计费日期', required: true, error: errors.billingDate },
React.createElement(DatePicker, {
style: { width: '100%' },
@@ -199,7 +228,17 @@ const Component = function() {
value: billingDateValue,
onChange: function(d, dateStr) { setBillingDate(d); },
status: errors.billingDate ? 'error' : undefined
}))
})),
isRenewalProject ? React.createElement(FormItem, { label: '已交车辆是否需要还车' },
React.createElement('div', { style: { display: 'flex', alignItems: 'flex-start', gap: 8, lineHeight: 1.6 } },
React.createElement(Checkbox, { checked: !!noReturnCarChecked, onChange: onToggleNoReturnCar }, '不需要还车'),
React.createElement('span', { style: { color: '#8c8c8c', fontSize: 12, marginTop: 2 } },
'勾选不需要还车,则车辆无需交车,',
React.createElement('br', null),
'只设置开始计费日期即可重新生成账单'
)
)
) : null
);
var allSelectableChecked = selectableVehicles.length > 0 && selectableVehicles.every(function(v) { return checkedRowKeys.indexOf(v.key) !== -1; });
@@ -225,17 +264,27 @@ const Component = function() {
var tableBody = React.createElement('tbody', null,
vehicleList.length === 0
? React.createElement('tr', null, React.createElement('td', { colSpan: 9, style: Object.assign({}, styles.td, { textAlign: 'center', color: '#999' }) }, '该合同下暂无车辆信息'))
? React.createElement('tr', null, React.createElement('td', { colSpan: 9, style: Object.assign({}, styles.td, { textAlign: 'center', color: '#999' }) }, '请先选择项目名称,将自动带出该合同下车辆信息'))
: vehicleList.map(function(row) {
var isSubmitted = row.deliveryStatus === 'submitted';
var isCompleted = row.deliveryStatus === 'completed';
var completedSelectable = isRenewalProject && !!noReturnCarChecked;
return React.createElement('tr', { key: row.key },
React.createElement('td', { style: styles.td },
isSubmitted
? React.createElement(Tooltip, { title: '该车辆已交车任务' },
React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 6, cursor: 'not-allowed' } },
React.createElement(Checkbox, { disabled: true, checked: false }),
React.createElement('span', { style: { color: '#999', fontSize: 12 } }, '已提交')))
: React.createElement(Checkbox, { checked: checkedRowKeys.indexOf(row.key) !== -1, onChange: function(e) { onSelectRow(row, e.target.checked); } })),
? React.createElement(Tooltip, { title: '该车辆已创建交车任务' },
React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', cursor: 'not-allowed' } },
React.createElement(Checkbox, { disabled: true, checked: false })))
: isCompleted
? React.createElement(Tooltip, { title: '该车辆已完成交车' },
React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center' } },
React.createElement(Checkbox, {
disabled: !completedSelectable,
checked: completedSelectable ? (checkedRowKeys.indexOf(row.key) !== -1) : false,
onChange: function(e) { onSelectRow(row, e.target.checked); }
})
))
: React.createElement(Checkbox, { checked: checkedRowKeys.indexOf(row.key) !== -1, onChange: function(e) { onSelectRow(row, e.target.checked); } })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.brand, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.model, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.plateNo || '-', disabled: true, style: styles.inputDisabled })),
@@ -267,7 +316,7 @@ const Component = function() {
React.createElement('span', null, '交车任务'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { style: { color: '#1890ff' } }, '编辑交车任务')),
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontSize: 14 }, onClick: function() { setReqSpecOpen(true); } }, '查看需求说明')),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function() { reqModalOpen[1](true); } }, '查看需求说明')),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '交车任务')),
React.createElement('div', { style: styles.cardBody },
@@ -275,7 +324,15 @@ const Component = function() {
formRow2,
tableEl)),
React.createElement('div', { style: { height: 60 } }),
reqSpecModalContent,
React.createElement(Modal, {
title: '需求说明',
open: reqModalOpen[0],
onCancel: function() { reqModalOpen[1](false); },
width: 720,
footer: React.createElement(Button, { onClick: function() { reqModalOpen[1](false); } }, '关闭'),
bodyStyle: { maxHeight: '70vh', overflow: 'auto' }
}, React.createElement('div', { style: { padding: '8px 0' } },
React.createElement('div', { style: { whiteSpace: 'pre-wrap', fontSize: 13, lineHeight: 1.6 } }, reqSpecText))),
React.createElement('div', { style: styles.footer },
React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交'),
React.createElement(Button, { onClick: handleCancel }, '取消'))