From e70342e8fee7c2f16b2a3236685416d1450bb121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=86=95?= Date: Wed, 4 Mar 2026 20:38:06 +0800 Subject: [PATCH] =?UTF-8?q?web=E7=AB=AF=EF=BC=9A=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=8F=90=E8=BD=A6=E5=BA=94=E6=94=B6=E6=AC=BE?= =?UTF-8?q?-=E6=94=B6=E6=AC=BE=E3=80=81=E8=BD=A6=E8=BE=86=E7=A7=9F?= =?UTF-8?q?=E8=B5=81=E5=90=88=E5=90=8C=E4=B8=8E=E6=9B=BF=E6=8D=A2=E8=BD=A6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=94=B9=E5=8A=A8=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 财务管理:新增提车应收款-收款.jsx,移除旧提车应收款/收费明细/首付款页面;项目信息与开票信息改为直接展示 - 车辆租赁合同:列表租赁车辆数/已交车辆数及气泡列调整;续签/转正式合同去除合同编码,交车区域·交车地点·合同原件布局调整 - 运维-车辆业务:新增替换车管理、替换车管理-新增/查看/编辑 Made-with: Cursor --- web端/财务管理/提车应收款-收款.jsx | 599 ++++++++++ web端/财务管理/提车应收款.jsx | 432 ------- web端/财务管理/提车收款-收费明细.jsx | 278 ----- web端/财务管理/提车首付款.jsx | 1048 ----------------- web端/车辆租赁合同/车辆租赁合同-新增.jsx | 29 +- web端/车辆租赁合同/车辆租赁合同-新增车辆.jsx | 117 +- web端/车辆租赁合同/车辆租赁合同-续签合同.jsx | 75 +- .../车辆租赁合同/车辆租赁合同-转正式合同.jsx | 59 +- web端/车辆租赁合同/车辆租赁合同.jsx | 93 +- web端/运维管理/车辆业务/替换车管理-新增.jsx | 344 ++++++ web端/运维管理/车辆业务/替换车管理-查看.jsx | 203 ++++ web端/运维管理/车辆业务/替换车管理-编辑.jsx | 322 +++++ web端/运维管理/车辆业务/替换车管理.jsx | 493 ++++++++ 13 files changed, 2209 insertions(+), 1883 deletions(-) create mode 100644 web端/财务管理/提车应收款-收款.jsx delete mode 100644 web端/财务管理/提车应收款.jsx delete mode 100644 web端/财务管理/提车收款-收费明细.jsx delete mode 100644 web端/财务管理/提车首付款.jsx create mode 100644 web端/运维管理/车辆业务/替换车管理-新增.jsx create mode 100644 web端/运维管理/车辆业务/替换车管理-查看.jsx create mode 100644 web端/运维管理/车辆业务/替换车管理-编辑.jsx create mode 100644 web端/运维管理/车辆业务/替换车管理.jsx diff --git a/web端/财务管理/提车应收款-收款.jsx b/web端/财务管理/提车应收款-收款.jsx new file mode 100644 index 0000000..3c56e0a --- /dev/null +++ b/web端/财务管理/提车应收款-收款.jsx @@ -0,0 +1,599 @@ +// 【重要】必须使用 const Component 作为组件变量名 +// 财务管理 - 提车应收款 - 收款(2026年3月4日版本) + +const Component = function () { + var useState = React.useState; + var useCallback = React.useCallback; + var useMemo = React.useMemo; + var useEffect = React.useEffect; + var useRef = React.useRef; + + var antd = window.antd; + var Breadcrumb = antd.Breadcrumb; + var Card = antd.Card; + var Input = antd.Input; + var Button = antd.Button; + var Select = antd.Select; + var Table = antd.Table; + var Popover = antd.Popover; + var Modal = antd.Modal; + var message = antd.message; + var Option = Select.Option; + + var requirementModalVisible = useState(false); + var setRequirementModalVisible = requirementModalVisible[1]; + var edited = useState(false); + var setEdited = edited[1]; + var submitConfirmVisible = useState(false); + var setSubmitConfirmVisible = submitConfirmVisible[1]; + var cancelConfirmVisible = useState(false); + var setCancelConfirmVisible = cancelConfirmVisible[1]; + var servicePopoverRowIndex = useState(null); + var setServicePopoverRowIndex = servicePopoverRowIndex[1]; + + // 模拟:项目信息(实际由路由/接口拉取) + var projectInfo = useMemo(function () { + return { + contractCode: 'HT-ZL-2025-001', + contractType: '正式合同', + projectName: '嘉兴氢能示范项目', + customerName: '嘉兴某某物流有限公司', + paymentMethod: '预付', + paymentCycle: '6个月', + contractStart: '2025-01-15', + contractEnd: '2026-01-14', + businessDept: '业务1部', + businessPerson: '张经理' + }; + }, []); + + // 模拟:车辆应收款明细(租赁合同中所有车辆),付款周期 6 个月 => 应收月租金 = 月租金*6 + var paymentCycleMonths = 6; + var vehicleRows = useState([ + { + key: 'v1', + index: 1, + brand: '东风', + model: 'DFH1180', + plateNo: '浙A12345', + monthRent: 5000, + receivableRent: 30000, + actualRent: '30000.00', + rentRemark: '', + receivableDeposit: 10000, + serviceItems: [ + { name: '代处理费用', receivable: 200, actual: '200.00', discount: '0.00', remark: '' }, + { name: '保险上浮', receivable: 500, actual: '500.00', discount: '0.00', remark: '' } + ], + receivableService: 700, + actualService: '700.00', + discountAmount: '0.00', + discountRemark: '', + discountProof: [], + selected: true + }, + { + key: 'v2', + index: 2, + brand: '福田', + model: 'BJ1180', + plateNo: '', + monthRent: 4500, + receivableRent: 27000, + actualRent: '27000.00', + rentRemark: '', + receivableDeposit: 8000, + serviceItems: [{ name: '保养费用', receivable: 300, actual: '300.00', discount: '0.00', remark: '' }], + receivableService: 300, + actualService: '300.00', + discountAmount: '0.00', + discountRemark: '', + discountProof: [], + selected: true + } + ]); + var vehicles = vehicleRows[0]; + var setVehicles = vehicleRows[1]; + + // 氢费预付款(非预付款模式时不显示) + var hasHydrogenPrepay = true; + var hydrogenRow = useState({ + receivable: '3580.00', + actual: '3580.00', + discount: '0.00', + discountRemark: '' + }); + var hydrogen = hydrogenRow[0]; + var setHydrogen = hydrogenRow[1]; + + var invoiceMethod = useState('先开票后付款'); + var setInvoiceMethod = invoiceMethod[1]; + var invoiceRemark = useState(''); + var setInvoiceRemark = invoiceRemark[1]; + + // 开票信息(客户信息 + 开票时间/附件/开票人) + var invoiceInfo = useMemo(function () { + return { + customerName: '嘉兴某某物流有限公司', + taxId: '91330400MA2XXXXX1', + address: '浙江省嘉兴市南湖区科技大道1号', + phone: '0571-88888888', + account: '6222021234567890123', + bank: '中国工商银行嘉兴分行', + mailingAddress: '浙江省嘉兴市南湖区科技大道1号', + invoiceTime: '', + invoiceFile: '', + invoicePerson: '-' + }; + }, []); + + var toggleVehicleSelected = useCallback(function (key) { + setEdited(true); + setVehicles(function (prev) { + return prev.map(function (r) { + if (r.key === key) return Object.assign({}, r, { selected: !r.selected }); + return r; + }); + }); + }, []); + + var toggleAllSelected = useCallback(function (checked) { + setEdited(true); + setVehicles(function (prev) { + return prev.map(function (r) { return Object.assign({}, r, { selected: !!checked }); }); + }); + }, []); + + var updateVehicle = useCallback(function (key, field, value) { + setEdited(true); + setVehicles(function (prev) { + return prev.map(function (r) { + if (r.key !== key) return r; + var next = Object.assign({}, r); + next[field] = value; + if (field === 'serviceItems') { + var total = 0; + (value || []).forEach(function (s) { total += parseFloat(s.actual) || 0; }); + next.actualService = total.toFixed(2); + } + return next; + }); + }); + }, []); + + var updateServiceItem = useCallback(function (vehicleKey, itemIndex, field, value) { + setEdited(true); + setVehicles(function (prev) { + return prev.map(function (r) { + if (r.key !== vehicleKey) return r; + var items = (r.serviceItems || []).slice(); + if (!items[itemIndex]) return r; + items[itemIndex] = Object.assign({}, items[itemIndex], { [field]: value }); + var total = 0; + items.forEach(function (s) { total += parseFloat(s.actual) || 0; }); + return Object.assign({}, r, { serviceItems: items, actualService: total.toFixed(2) }); + }); + }); + }, []); + + var totals = useMemo(function () { + var selected = vehicles.filter(function (v) { return v.selected; }); + var receivableRent = 0, actualRent = 0, receivableDeposit = 0, receivableService = 0, actualService = 0, discountTotal = 0; + selected.forEach(function (v) { + receivableRent += Number(v.receivableRent) || 0; + actualRent += parseFloat(v.actualRent) || 0; + receivableDeposit += Number(v.receivableDeposit) || 0; + receivableService += Number(v.receivableService) || 0; + actualService += parseFloat(v.actualService) || 0; + discountTotal += parseFloat(v.discountAmount) || 0; + }); + return { + receivableRent: receivableRent.toFixed(2), + actualRent: actualRent.toFixed(2), + receivableDeposit: receivableDeposit.toFixed(2), + receivableService: receivableService.toFixed(2), + actualService: actualService.toFixed(2), + discountTotal: discountTotal.toFixed(2) + }; + }, [vehicles]); + + var receivableTotal = useMemo(function () { + return (parseFloat(totals.receivableRent) + parseFloat(totals.receivableDeposit) + parseFloat(totals.receivableService)).toFixed(2); + }, [totals]); + + var actualTotal = useMemo(function () { + return (parseFloat(totals.actualRent) + parseFloat(totals.receivableDeposit) + parseFloat(totals.actualService) - parseFloat(totals.discountTotal)).toFixed(2); + }, [totals]); + + var receivablePopoverContent = useMemo(function () { + return React.createElement('div', { style: { padding: 8, minWidth: 220 } }, + React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } }, + React.createElement('thead', null, + React.createElement('tr', null, + React.createElement('th', { style: { textAlign: 'left', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '项目'), + React.createElement('th', { style: { textAlign: 'right', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '金额') + ) + ), + React.createElement('tbody', null, + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计应收车辆月租金'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.receivableRent + ' 元')), + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计应收车辆保证金'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.receivableDeposit + ' 元')), + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计应收服务费'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.receivableService + ' 元')) + ) + ) + ); + }, [totals]); + + var actualPopoverContent = useMemo(function () { + return React.createElement('div', { style: { padding: 8, minWidth: 220 } }, + React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } }, + React.createElement('thead', null, + React.createElement('tr', null, + React.createElement('th', { style: { textAlign: 'left', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '项目'), + React.createElement('th', { style: { textAlign: 'right', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '金额') + ) + ), + React.createElement('tbody', null, + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计实收车辆月租金'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.actualRent + ' 元')), + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计应收车辆保证金'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.receivableDeposit + ' 元')), + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计实收服务费'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.actualService + ' 元')), + React.createElement('tr', null, React.createElement('td', { style: { padding: '6px 8px' } }, '总计减免金额'), React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, totals.discountTotal + ' 元')) + ) + ) + ); + }, [totals]); + + var handleSubmit = useCallback(function () { + setSubmitConfirmVisible(true); + }, []); + + var handleSubmitConfirm = useCallback(function () { + message.success('提车应收款已提交审核'); + setSubmitConfirmVisible(false); + if (window.__receivableSubmit) window.__receivableSubmit(); + }, []); + + var handleSave = useCallback(function () { + message.success('保存成功'); + if (window.__receivableBack) window.__receivableBack(); else message.info('跳转至提车应收款列表页(原型)'); + }, []); + + var handleCancel = useCallback(function () { + if (edited[0]) { + setCancelConfirmVisible(true); + } else { + if (window.__receivableBack) window.__receivableBack(); else message.info('返回提车应收款列表(原型)'); + } + }, [edited[0]]); + + var handleCancelConfirm = useCallback(function () { + setCancelConfirmVisible(false); + if (window.__receivableBack) window.__receivableBack(); else message.info('返回提车应收款列表(原型)'); + }, []); + + var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; + var cardStyle = { marginBottom: 16 }; + var labelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; + var formRowStyle = { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', marginBottom: 16 }; + var formItemStyle = { marginBottom: 12 }; + var highlightStyle = { color: '#1890ff', fontWeight: 600, cursor: 'pointer' }; + var valueStyle = { color: 'rgba(0,0,0,0.85)', fontSize: 14, lineHeight: '22px', minHeight: 22 }; + + var requirementContent = '提车应收款(2026年3月4日版本)\n一个「数字化资产ONEOS运管平台」中的「财务管理」「提车应收款」「收款」模块\n#面包屑:财务管理-提车应收款-收款;\n\n页面分为3个卡片。\n1.项目信息:合同编码、合同类型、项目名称、客户名称、付款方式、付款周期、合同生效时间、合同结束时间、业务部门、业务负责人。\n2.提车应收款信息:应收款总额/实收款总额(点击弹出气泡卡片);车辆应收款明细表(全选/多选、序号、品牌、型号、车牌号、应收/实收车辆月租金、车辆租金备注、应收车辆保证金、服务费项目、应收/实收服务费、减免金额、减免金额备注、减免证明);总计行;氢费预付款(可选);开票方式、开票备注。\n3.开票信息:客户名称、纳税人识别号、地址、电话、账户、开户行、邮寄地址、开票时间、发票附件、开票人。\n4.底部:提交审核、保存、取消及二次确认。'; + + var allSelected = vehicles.length > 0 && vehicles.every(function (v) { return v.selected; }); + var indeterminate = vehicles.some(function (v) { return v.selected; }) && !allSelected; + var headerCheckRef = useRef(null); + useEffect(function () { + if (headerCheckRef.current) headerCheckRef.current.indeterminate = indeterminate; + }, [indeterminate]); + + return React.createElement('div', { style: layoutStyle }, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, + React.createElement(Breadcrumb, { + items: [ + { title: '财务管理' }, + { title: '提车应收款' }, + { title: '收款' } + ] + }), + React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { setRequirementModalVisible(true); } }, '查看需求说明') + ), + React.createElement(Card, { title: '项目信息', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同编码'), + React.createElement('div', { style: valueStyle }, projectInfo.contractCode || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同类型'), + React.createElement('div', { style: valueStyle }, projectInfo.contractType || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '项目名称'), + React.createElement('div', { style: valueStyle }, projectInfo.projectName || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户名称'), + React.createElement('div', { style: valueStyle }, projectInfo.customerName || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '付款方式'), + React.createElement('div', { style: valueStyle }, projectInfo.paymentMethod || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '付款周期'), + React.createElement('div', { style: valueStyle }, projectInfo.paymentCycle || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同生效时间'), + React.createElement('div', { style: valueStyle }, projectInfo.contractStart || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同结束时间'), + React.createElement('div', { style: valueStyle }, projectInfo.contractEnd || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务部门'), + React.createElement('div', { style: valueStyle }, projectInfo.businessDept || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务负责人'), + React.createElement('div', { style: valueStyle }, projectInfo.businessPerson || '-') + ) + ) + ), + React.createElement(Card, { title: '提车应收款信息', style: cardStyle }, + React.createElement('div', { style: { marginBottom: 16, display: 'flex', gap: 24, alignItems: 'center' } }, + React.createElement(Popover, { content: receivablePopoverContent, title: '应收款明细', trigger: 'click' }, + React.createElement('span', { style: highlightStyle }, '应收款总额:', receivableTotal, ' 元') + ), + React.createElement(Popover, { content: actualPopoverContent, title: '实收款明细', trigger: 'click' }, + React.createElement('span', { style: highlightStyle }, '实收款总额:', actualTotal, ' 元') + ) + ), + React.createElement('div', { style: { overflowX: 'auto', marginBottom: 16 } }, + React.createElement('table', { style: { width: '100%', minWidth: 1400, borderCollapse: 'collapse', fontSize: 13 } }, + React.createElement('thead', null, + React.createElement('tr', { style: { backgroundColor: '#fafafa' } }, + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 48 } }, + React.createElement('input', { type: 'checkbox', checked: allSelected, ref: headerCheckRef, onChange: function (e) { toggleAllSelected(e.target.checked); } }) + ), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 50 } }, '序号'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 80 } }, '品牌'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 90 } }, '型号'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 100 } }, '车牌号'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'right', border: '1px solid #f0f0f0', width: 120 } }, '应收车辆月租金'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 120 } }, '实收车辆月租金'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 100 } }, '车辆租金备注'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 90 } }, '减免金额'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 90 } }, '减免金额备注'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'right', border: '1px solid #f0f0f0', width: 110 } }, '应收车辆保证金'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 90 } }, '服务费项目'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'right', border: '1px solid #f0f0f0', width: 90 } }, '应收服务费'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'right', border: '1px solid #f0f0f0', width: 90 } }, '实收服务费'), + React.createElement('th', { style: { padding: '10px 12px', textAlign: 'left', border: '1px solid #f0f0f0', width: 100 } }, '减免证明') + ) + ), + React.createElement('tbody', null, + vehicles.map(function (row) { + var disabled = !row.selected; + var servicePopover = React.createElement('div', { style: { padding: 8, minWidth: 360 } }, + React.createElement('div', { style: { fontWeight: 600, marginBottom: 8 } }, '服务费项目'), + React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12 } }, + React.createElement('thead', null, + React.createElement('tr', null, + React.createElement('th', { style: { textAlign: 'left', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '服务项目'), + React.createElement('th', { style: { textAlign: 'right', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '应收费用'), + React.createElement('th', { style: { textAlign: 'right', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '实收费用'), + React.createElement('th', { style: { textAlign: 'right', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '减免费用'), + React.createElement('th', { style: { textAlign: 'left', padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, '备注') + ) + ), + React.createElement('tbody', null, + (row.serviceItems || []).map(function (s, si) { + return React.createElement('tr', { key: si }, + React.createElement('td', { style: { padding: '6px 8px' } }, s.name), + React.createElement('td', { style: { textAlign: 'right', padding: '6px 8px' } }, (s.receivable != null ? s.receivable : '') + ' 元'), + React.createElement('td', { style: { padding: '6px 8px' } }, + React.createElement(Input, { size: 'small', value: s.actual, disabled: disabled, suffix: '元', onChange: function (e) { updateServiceItem(row.key, si, 'actual', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '6px 8px' } }, + React.createElement(Input, { size: 'small', value: s.discount, disabled: disabled, suffix: '元', onChange: function (e) { updateServiceItem(row.key, si, 'discount', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '6px 8px' } }, + React.createElement(Input, { size: 'small', value: s.remark, disabled: disabled, placeholder: '备注', onChange: function (e) { updateServiceItem(row.key, si, 'remark', e.target.value); } }) + ) + ); + }) + ) + ) + ); + var proofList = row.discountProof || []; + var onProofUpload = function (e) { + var files = e.target.files; + if (!files || !files.length) return; + setEdited(true); + var next = proofList.slice(); + for (var i = 0; i < files.length; i++) { next.push({ name: files[i].name }); } + updateVehicle(row.key, 'discountProof', next); + e.target.value = ''; + }; + var removeProof = function (idx) { + setEdited(true); + var next = (row.discountProof || []).slice(); + next.splice(idx, 1); + updateVehicle(row.key, 'discountProof', next); + }; + return React.createElement('tr', { key: row.key }, + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement('input', { type: 'checkbox', checked: row.selected, onChange: function () { toggleVehicleSelected(row.key); } }) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, row.index), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, row.brand), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, row.model), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, row.plateNo || '-'), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, (row.receivableRent || 0) + ' 元'), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement(Input, { size: 'small', value: row.actualRent, disabled: disabled, suffix: '元', onChange: function (e) { updateVehicle(row.key, 'actualRent', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement(Input, { size: 'small', value: row.rentRemark, disabled: disabled, onChange: function (e) { updateVehicle(row.key, 'rentRemark', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement(Input, { size: 'small', value: row.discountAmount, disabled: disabled, suffix: '元', onChange: function (e) { updateVehicle(row.key, 'discountAmount', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement(Input, { size: 'small', value: row.discountRemark, disabled: disabled, onChange: function (e) { updateVehicle(row.key, 'discountRemark', e.target.value); } }) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, (row.receivableDeposit || 0) + ' 元'), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + React.createElement(Popover, { content: servicePopover, title: null, trigger: 'click' }, + React.createElement(Button, { type: 'link', size: 'small', disabled: disabled }, '管理') + ) + ), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, (row.receivableService || 0) + ' 元'), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, (row.actualService || '0.00') + ' 元'), + React.createElement('td', { style: { padding: '8px 12px', border: '1px solid #f0f0f0' } }, + disabled ? '-' : React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 4 } }, + proofList.map(function (p, pidx) { + return React.createElement('div', { key: pidx, style: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 12 } }, + React.createElement('span', { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' } }, p.name || '附件'), + React.createElement(Button, { type: 'link', size: 'small', danger: true, style: { padding: 0, minWidth: 'auto' }, onClick: function () { removeProof(pidx); } }, '删除') + ); + }), + React.createElement('span', null, + React.createElement('input', { type: 'file', multiple: true, accept: '.jpg,.jpeg,.png,.pdf', style: { display: 'none' }, id: 'proof-' + row.key, onChange: onProofUpload }), + React.createElement(Button, { type: 'link', size: 'small', onClick: function () { var el = document.getElementById('proof-' + row.key); if (el) el.click(); } }, '上传') + ) + ) + ) + ); + }) + ), + React.createElement('tfoot', null, + React.createElement('tr', { style: { backgroundColor: '#fafafa', fontWeight: 500 } }, + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0' }, colSpan: 5 }, '总计'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.receivableRent + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.actualRent + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0' } }), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.discountTotal + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0' } }), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.receivableDeposit + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0' } }), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.receivableService + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0', textAlign: 'right' } }, totals.actualService + ' 元'), + React.createElement('td', { style: { padding: '10px 12px', border: '1px solid #f0f0f0' } }) + ) + ) + ) + ), + hasHydrogenPrepay ? React.createElement('div', { style: { marginBottom: 16 } }, + React.createElement('div', { style: { fontSize: 14, fontWeight: 500, marginBottom: 8 } }, '氢费预付款情况'), + React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 16, maxWidth: 800 } }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '氢费预付款应收金额'), + React.createElement(Input, { value: hydrogen.receivable + ' 元', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '氢费预付款实收金额'), + React.createElement(Input, { value: hydrogen.actual, suffix: '元', onChange: function (e) { setHydrogen(function (p) { return Object.assign({}, p, { actual: e.target.value }); }); } }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '减免金额'), + React.createElement(Input, { value: hydrogen.discount, suffix: '元', onChange: function (e) { setHydrogen(function (p) { return Object.assign({}, p, { discount: e.target.value }); }); } }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '减免金额备注'), + React.createElement(Input, { value: hydrogen.discountRemark, onChange: function (e) { setHydrogen(function (p) { return Object.assign({}, p, { discountRemark: e.target.value }); }); } }) + ) + ) + ) : null, + React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px 24px', marginTop: 16 } }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '开票方式'), + React.createElement(Select, { style: { width: '100%' }, value: invoiceMethod[0], onChange: function (v) { setInvoiceMethod(v); }, placeholder: '请选择' }, + React.createElement(Option, { value: '先开票后付款' }, '先开票后付款'), + React.createElement(Option, { value: '先付款后开票' }, '先付款后开票') + ) + ), + React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: '1 / -1' }) }, + React.createElement('div', { style: labelStyle }, '开票备注'), + React.createElement(Input.TextArea, { value: invoiceRemark[0], onChange: function (e) { setInvoiceRemark(e.target.value); setEdited(true); }, rows: 3, placeholder: '请输入开票项目、税率以及其他备注信息,财务将以此进行开票', style: { width: '100%' } }) + ) + ) + ), + React.createElement(Card, { title: '开票信息', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户名称'), + React.createElement('div', { style: valueStyle }, invoiceInfo.customerName || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '纳税人识别号'), + React.createElement('div', { style: valueStyle }, invoiceInfo.taxId || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '地址'), + React.createElement('div', { style: valueStyle }, invoiceInfo.address || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '电话'), + React.createElement('div', { style: valueStyle }, invoiceInfo.phone || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '账户'), + React.createElement('div', { style: valueStyle }, invoiceInfo.account || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '开户行'), + React.createElement('div', { style: valueStyle }, invoiceInfo.bank || '-') + ), + React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: '1 / -1' }) }, + React.createElement('div', { style: labelStyle }, '邮寄地址'), + React.createElement('div', { style: valueStyle }, invoiceInfo.mailingAddress || '-') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '开票时间'), + React.createElement('div', { style: valueStyle }, invoiceInfo.invoiceTime || '未上传') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '发票附件'), + React.createElement('div', { style: valueStyle }, invoiceInfo.invoiceFile || '未上传') + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '开票人'), + React.createElement('div', { style: valueStyle }, invoiceInfo.invoicePerson || '-') + ) + ) + ), + React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 24 } }, + React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'), + React.createElement(Button, { onClick: handleSave }, '保存'), + React.createElement(Button, { onClick: handleCancel }, '取消') + ), + React.createElement(Modal, { + title: '确认', + open: submitConfirmVisible[0], + onCancel: function () { setSubmitConfirmVisible(false); }, + onOk: handleSubmitConfirm, + okText: '确认', + cancelText: '取消' + }, React.createElement('div', null, '请仔细核对提车首付款实收金额,点击确认则进入工作流')), + React.createElement(Modal, { + title: '确认取消', + open: cancelConfirmVisible[0], + onCancel: function () { setCancelConfirmVisible(false); }, + onOk: handleCancelConfirm, + okText: '确认', + cancelText: '取消' + }, React.createElement('div', null, '取消将会丢失所有已填写数据,是否确认?')), + React.createElement(Modal, { + title: '需求说明', + open: requirementModalVisible[0], + onCancel: function () { setRequirementModalVisible(false); }, + width: 720, + footer: React.createElement(Button, { onClick: function () { setRequirementModalVisible(false); } }, '关闭'), + bodyStyle: { maxHeight: '70vh', overflow: 'auto' } + }, React.createElement('div', { style: { padding: '8px 0', whiteSpace: 'pre-wrap', fontSize: 13, lineHeight: 1.6 } }, requirementContent)) + ); +}; diff --git a/web端/财务管理/提车应收款.jsx b/web端/财务管理/提车应收款.jsx deleted file mode 100644 index 2a823cf..0000000 --- a/web端/财务管理/提车应收款.jsx +++ /dev/null @@ -1,432 +0,0 @@ -// 【重要】必须使用 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 Select = antd.Select; - var Button = antd.Button; - var Table = antd.Table; - var Card = antd.Card; - var DatePicker = antd.DatePicker; - var Modal = antd.Modal; - var Space = antd.Space; - var message = antd.message; - var App = antd.App; - - var RangePicker = DatePicker.RangePicker; - var dayjs = window.dayjs || null; - - // 筛选条件(表单输入) - var _contractCode = useState(undefined); - var _projectName = useState(undefined); - var _customerName = useState(undefined); - var _auditStatus = useState(undefined); - var _chargeOperator = useState(undefined); - var _chargeTimeRange = useState(null); - var _invoiceTimeRange = useState(null); - var _invoiceOperator = useState(undefined); - // 已生效筛选(点击查询后) - var _appliedFilter = useState({ - contractCode: undefined, - projectName: undefined, - customerName: undefined, - auditStatus: undefined, - chargeOperator: undefined, - chargeTimeRange: null, - invoiceTimeRange: null, - invoiceOperator: undefined - }); - // 列表多选(默认全选由 Table rowSelection 控制) - var _selectedRowKeys = useState([]); - // 撤回二次确认 - var _withdrawModalVisible = useState(false); - var _withdrawRecord = useState(null); - // 筛选展开(默认只显示第一行,点击更多展开、收起关闭) - var _filterExpanded = useState(false); - // 查看需求说明弹窗 - var _requirementModalVisible = useState(false); - - // 需求说明文案 - var requirementContent = '「车辆管理系统」中的「财务管理」模块下「提车应收款」模块\n1.面包屑:\n1.1.运维管理-财务管理-提车应收款\n页面由筛选卡片、列表卡片组成;\n\n2.筛选:\n2.1.合同编码:用来通过提车应收款筛选车辆租赁合同编码;选择器,支持从输入框输入内容模糊搜索,选择器支持点击删除,下拉显示匹配项;\n2.2.项目名称:用来通过提车应收款筛选车辆租赁合同对应项目名称;选择器,支持从输入框输入内容模糊搜索,选择器支持点击删除,下拉显示匹配项;\n2.3.客户名称:用来通过提车应收款筛选车辆租赁合同对应客户名称,选择器,支持从输入框输入内容模糊搜索,选择器支持点击删除,下拉显示匹配项;\n2.4.审核状态:用来通过审核状态筛选对应提车应收款数据,选择器,选项为:全部、待提交、审批中、审批完成、审批驳回、撤回;\n2.5.收费情况操作人:用来通过收费情况操作人筛选对应提车应收款数据,选择器,支持从输入框输入内容模糊搜索,选择器支持点击删除,下拉显示匹配项,选项为:全部、所有操作人;\n2.6.收费情况提交时间:日期选择器,支持单输入框双日历选择开始-结束时间,提示信息为:请选择开始时间、请选择结束时间;\n2.7.开票时间:日期选择器,支持单输入框双日历选择开始-结束时间,提示信息为:请选择开始时间、请选择结束时间;\n2.8.开票操作人:用来通过收费情况操作人筛选对应提车应收款数据,选择器,支持从输入框输入内容模糊搜索,选择器支持点击删除,下拉显示匹配项,选项为:全部、所有操作人;\n2.9.右侧为查询和重置按钮,筛选条件以且的模式进行筛选,点击重置清空条件,点击查询与列表进行联动;\n\n3.列表:\n合同到达生效日期立刻生成提车应收款数据,以列表进行显示,列表第一列为多选框,默认全选,可手动取消选择某行数据,配合导出按钮进行对应数据导出;\n列表字段依次为:合同编码、项目名称、客户名称、业务部门、业务负责人、合同生效日期、应收总金额、减免总金额、审核状态、收费情况操作人、收费情况提交时间、开票时间、开票操作人、操作;\n右上角为导出按钮,支持筛选后多选行数据进行导出;\n3.1.合同编码:显示该笔提车应收款对应车辆租赁合同-合同编码;\n3.2.项目名称:显示该笔提车应收款对应车辆租赁合同-项目名称;\n3.3.客户名称:显示该笔提车应收款对应车辆租赁合同-客户名称;\n3.4.业务部门:显示该笔提车应收款对应车辆租赁合同-业务部门;\n3.5.业务负责人:显示该笔提车应收款对应车辆租赁合同-业务负责人;\n3.6.合同生效日期:显示该笔提车应收款对应车辆租赁合同-合同生效日期;\n3.7.应收总金额:显示该笔提车提车应收款总金额,格式为:xx.xx元。从收费明细中计算(业务提交审核前会根据业务实际填写金额重新计算),计算方式为:提车应收款总额+氢费预付款总额;\n3.8.减免总金额:显示收费明细中所有减免总金额总额,无则显示为0.00元;\n3.9.审核状态:分为待提交、审批中、审批完成、审批驳回、撤回;\n 3.9.1.待提交:生成提车应收款后收费明细未修改或仅保存,且未提交审批;操作可:查看、收费明细;\n 3.9.2.审批中:生成提车应收款后收费明细已提交审批,但未完成最终节点审批;操作可:查看、撤回;\n 3.9.3.审批完成:提车应收款已完成最终节点审批,最终节点审批后不可撤回;操作可:查看、开票信息;\n 3.9.4.审批驳回:提车应收款在任意审批节点被驳回,被驳回后显示为审批驳回,可重新编辑后再次提交审批;操作可:查看、收费明细;\n 3.9.5.撤回:提车应收款在状态为审批中时可自行撤回,撤回后显示为撤回,可重新编辑后再次提交审批;操作可:查看、收费明细;\n3.10.收费情况操作人:提车应收款中点击收费明细,并点击提交审核的操作人,如撤回或驳回后由其他操作人提交审核,则显示最后一次操作的操作人;\n3.14.收费情况提交时间:提车应收款收费明细最后一次提交时间,格式为:YYYY-MM-DD HH:MM;\n3.15.开票时间:提车应收款完成审批后,在开票信息中填报的开票时间,格式为:YYYY-MM-DD,如未开票则显示:待开票;\n3.16.开票操作人:提车应收款开票信息开票时间、发票附件提交时,记录提交人,如未开票则显示为-;\n3.17.操作:查看、收费明细、撤回、开票信息;\n 3.17.1.查看:点击跳转查看提车应收款页;\n 3.17.2.收费明细:点击跳转收费明细页;\n 3.17.3.撤回:点击弹出气泡卡片进行二次确认,提示内容:是否确认撤回该流程。点击确认后提示撤回成功/失败(撤回过程中已完成最终节点审批则提示撤回失败);\n 3.17.4.开票信息:点击跳转开票信息页;\n3.18.分页:列表右下角为分页功能,支持选择单页显示数据条目数;'; - - // 选项 - var contractCodeOptions = [ - { value: 'HT-ZL-2025-001', label: 'HT-ZL-2025-001' }, - { value: 'HT-ZL-2025-002', label: 'HT-ZL-2025-002' }, - { value: 'HT-ZL-2025-003', label: 'HT-ZL-2025-003' }, - { value: 'HT-ZL-2024-088', label: 'HT-ZL-2024-088' } - ]; - var projectNameOptions = [ - { value: '北京朝阳区租赁项目', label: '北京朝阳区租赁项目' }, - { value: '上海浦东车辆租赁', label: '上海浦东车辆租赁' }, - { value: '广州天河运营项目', label: '广州天河运营项目' } - ]; - var customerNameOptions = [ - { value: '某某科技有限公司', label: '某某科技有限公司' }, - { value: '某某物流有限公司', label: '某某物流有限公司' }, - { value: '某某制造有限公司', label: '某某制造有限公司' } - ]; - var auditStatusOptions = [ - { value: '全部', label: '全部' }, - { value: '待提交', label: '待提交' }, - { value: '审批中', label: '审批中' }, - { value: '审批完成', label: '审批完成' }, - { value: '审批驳回', label: '审批驳回' }, - { value: '撤回', label: '撤回' } - ]; - var operatorOptions = [ - { value: '全部', label: '全部' }, - { value: '张三', label: '张三' }, - { value: '李四', label: '李四' }, - { value: '王五', label: '王五' } - ]; - - var auditStatusMap = { draft: '待提交', auditing: '审批中', completed: '审批完成', rejected: '审批驳回', withdrawn: '撤回' }; - var rawList = useMemo(function() { - var list = []; - var contracts = ['HT-ZL-2025-001', 'HT-ZL-2025-002', 'HT-ZL-2025-003', 'HT-ZL-2024-088']; - var projects = ['北京朝阳区租赁项目', '上海浦东车辆租赁', '广州天河运营项目']; - var customers = ['某某科技有限公司', '某某物流有限公司', '某某制造有限公司']; - var depts = ['运营部', '业务1部', '业务2部']; - var owners = ['张三', '李四', '王五']; - var statuses = ['draft', 'auditing', 'completed', 'rejected', 'withdrawn']; - for (var i = 1; i <= 25; i++) { - var audit = statuses[i % 5]; - list.push({ - id: 'AR' + i, - contractCode: contracts[i % contracts.length], - projectName: projects[i % projects.length], - customerName: customers[i % customers.length], - department: depts[i % 3], - responsible: owners[i % 3], - effectiveDate: '2025-' + (String((i % 12) + 1)).padStart(2, '0') + '-' + (String((i % 28) + 1)).padStart(2, '0'), - receivableTotal: (12000 + i * 500).toFixed(2), - discountTotal: (i % 4 === 0 ? 200 : 0).toFixed(2), - auditStatus: audit, - chargeOperator: audit === 'draft' || audit === 'withdrawn' ? '-' : '张三', - chargeSubmitTime: audit === 'draft' || audit === 'withdrawn' ? '-' : '2025-02-20 14:30', - invoiceTime: audit === 'completed' ? '2025-02-25' : '待开票', - invoiceOperator: audit === 'completed' ? '李四' : '-' - }); - } - return list; - }, []); - - var appliedFilter = _appliedFilter[0]; - var filteredList = useMemo(function() { - var list = rawList.slice(); - var f = appliedFilter; - if (f.contractCode) list = list.filter(function(r) { return r.contractCode === f.contractCode; }); - if (f.projectName) list = list.filter(function(r) { return r.projectName === f.projectName; }); - if (f.customerName) list = list.filter(function(r) { return r.customerName === f.customerName; }); - if (f.auditStatus && f.auditStatus !== '全部') { - var statusKey = null; - for (var k in auditStatusMap) { if (auditStatusMap[k] === f.auditStatus) { statusKey = k; break; } } - if (statusKey) list = list.filter(function(r) { return r.auditStatus === statusKey; }); - } - if (f.chargeOperator && f.chargeOperator !== '全部') { - list = list.filter(function(r) { return r.chargeOperator === f.chargeOperator; }); - } - if (f.chargeTimeRange && f.chargeTimeRange.length === 2 && f.chargeTimeRange[0] && f.chargeTimeRange[1]) { - var startStr = f.chargeTimeRange[0].format ? f.chargeTimeRange[0].format('YYYY-MM-DD') : ''; - var endStr = f.chargeTimeRange[1].format ? f.chargeTimeRange[1].format('YYYY-MM-DD') : ''; - if (startStr || endStr) { - list = list.filter(function(r) { - var t = (r.chargeSubmitTime || '').split(' ')[0]; - if (!t || t === '-') return false; - if (startStr && t < startStr) return false; - if (endStr && t > endStr) return false; - return true; - }); - } - } - if (f.invoiceTimeRange && f.invoiceTimeRange.length === 2 && f.invoiceTimeRange[0] && f.invoiceTimeRange[1]) { - var isStart = f.invoiceTimeRange[0].format ? f.invoiceTimeRange[0].format('YYYY-MM-DD') : ''; - var ieEnd = f.invoiceTimeRange[1].format ? f.invoiceTimeRange[1].format('YYYY-MM-DD') : ''; - if (isStart || ieEnd) { - list = list.filter(function(r) { - var t = r.invoiceTime === '待开票' ? '' : r.invoiceTime; - if (!t) return false; - if (isStart && t < isStart) return false; - if (ieEnd && t > ieEnd) return false; - return true; - }); - } - } - if (f.invoiceOperator && f.invoiceOperator !== '全部') { - list = list.filter(function(r) { return r.invoiceOperator === f.invoiceOperator; }); - } - return list; - }, [rawList, appliedFilter]); - - var handleQuery = useCallback(function() { - _appliedFilter[1]({ - contractCode: _contractCode[0], - projectName: _projectName[0], - customerName: _customerName[0], - auditStatus: _auditStatus[0], - chargeOperator: _chargeOperator[0], - chargeTimeRange: _chargeTimeRange[0], - invoiceTimeRange: _invoiceTimeRange[0], - invoiceOperator: _invoiceOperator[0] - }); - }, []); - var handleReset = useCallback(function() { - _contractCode[1](undefined); - _projectName[1](undefined); - _customerName[1](undefined); - _auditStatus[1](undefined); - _chargeOperator[1](undefined); - _chargeTimeRange[1](null); - _invoiceTimeRange[1](null); - _invoiceOperator[1](undefined); - _appliedFilter[1]({ - contractCode: undefined, - projectName: undefined, - customerName: undefined, - auditStatus: undefined, - chargeOperator: undefined, - chargeTimeRange: null, - invoiceTimeRange: null, - invoiceOperator: undefined - }); - _selectedRowKeys[1]([]); - }, []); - var handleExport = useCallback(function() { - var keys = _selectedRowKeys[0].length > 0 ? _selectedRowKeys[0] : filteredList.map(function(r) { return r.id; }); - message.info('导出已选数据,共 ' + keys.length + ' 条'); - }, [_selectedRowKeys[0], filteredList]); - var handleWithdraw = useCallback(function(record) { - _withdrawRecord[1](record); - _withdrawModalVisible[1](true); - }, []); - var handleWithdrawOk = useCallback(function() { - message.success('撤回成功'); - _withdrawModalVisible[1](false); - _withdrawRecord[1](null); - }, []); - - var filterLabelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; - var filterItemStyle = { marginBottom: 12 }; - var filterControlStyle = { width: '100%' }; - var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; - - var filterItems = [ - React.createElement('div', { key: 'contractCode', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '合同编码'), - React.createElement(Select, { - placeholder: '请选择或输入合同编码', - style: filterControlStyle, - value: _contractCode[0], - onChange: function(v) { _contractCode[1](v); }, - allowClear: true, - showSearch: true, - options: contractCodeOptions, - filterOption: function(input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } - })), - React.createElement('div', { key: 'projectName', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '项目名称'), - React.createElement(Select, { - placeholder: '请选择或输入项目名称', - style: filterControlStyle, - value: _projectName[0], - onChange: function(v) { _projectName[1](v); }, - allowClear: true, - showSearch: true, - options: projectNameOptions, - filterOption: function(input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } - })), - React.createElement('div', { key: 'customerName', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '客户名称'), - React.createElement(Select, { - placeholder: '请选择或输入客户名称', - style: filterControlStyle, - value: _customerName[0], - onChange: function(v) { _customerName[1](v); }, - allowClear: true, - showSearch: true, - options: customerNameOptions, - filterOption: function(input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } - })), - React.createElement('div', { key: 'auditStatus', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '审核状态'), - React.createElement(Select, { - placeholder: '请选择', - style: filterControlStyle, - value: _auditStatus[0], - onChange: function(v) { _auditStatus[1](v); }, - allowClear: true, - options: auditStatusOptions - })), - React.createElement('div', { key: 'chargeOperator', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '收费情况操作人'), - React.createElement(Select, { - placeholder: '请选择或输入操作人', - style: filterControlStyle, - value: _chargeOperator[0], - onChange: function(v) { _chargeOperator[1](v); }, - allowClear: true, - showSearch: true, - options: operatorOptions, - filterOption: function(input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } - })), - React.createElement('div', { key: 'chargeTimeRange', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '收费情况提交时间'), - React.createElement(RangePicker, { - style: filterControlStyle, - placeholder: ['请选择开始时间', '请选择结束时间'], - value: _chargeTimeRange[0], - onChange: function(v) { _chargeTimeRange[1](v); } - })), - React.createElement('div', { key: 'invoiceTimeRange', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '开票时间'), - React.createElement(RangePicker, { - style: filterControlStyle, - placeholder: ['请选择开始时间', '请选择结束时间'], - value: _invoiceTimeRange[0], - onChange: function(v) { _invoiceTimeRange[1](v); } - })), - React.createElement('div', { key: 'invoiceOperator', style: filterItemStyle }, - React.createElement('div', { style: filterLabelStyle }, '开票操作人'), - React.createElement(Select, { - placeholder: '请选择或输入操作人', - style: filterControlStyle, - value: _invoiceOperator[0], - onChange: function(v) { _invoiceOperator[1](v); }, - allowClear: true, - showSearch: true, - options: operatorOptions, - filterOption: function(input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } - })) - ]; - - var columns = [ - { title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 130, fixed: 'left' }, - { title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 160 }, - { title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 140 }, - { title: '业务部门', dataIndex: 'department', key: 'department', width: 100 }, - { title: '业务负责人', dataIndex: 'responsible', key: 'responsible', width: 100 }, - { title: '合同生效日期', dataIndex: 'effectiveDate', key: 'effectiveDate', width: 120 }, - { title: '应收总金额', key: 'receivableTotal', width: 110, render: function(_, r) { return (r.receivableTotal || '0.00') + ' 元'; } }, - { title: '减免总金额', key: 'discountTotal', width: 110, render: function(_, r) { return (r.discountTotal || '0.00') + ' 元'; } }, - { title: '审核状态', key: 'auditStatus', width: 100, render: function(_, r) { return auditStatusMap[r.auditStatus] || '-'; } }, - { title: '收费情况操作人', dataIndex: 'chargeOperator', key: 'chargeOperator', width: 120 }, - { title: '收费情况提交时间', dataIndex: 'chargeSubmitTime', key: 'chargeSubmitTime', width: 160 }, - { title: '开票时间', dataIndex: 'invoiceTime', key: 'invoiceTime', width: 110 }, - { title: '开票操作人', dataIndex: 'invoiceOperator', key: 'invoiceOperator', width: 110 }, - { - title: '操作', - key: 'action', - width: 200, - fixed: 'right', - render: function(_, record) { - var audit = record.auditStatus; - var showCharge = audit === 'draft' || audit === 'rejected' || audit === 'withdrawn'; - var showWithdraw = audit === 'auditing'; - var showInvoice = audit === 'completed'; - return React.createElement(Space, { size: 4, wrap: true }, - React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('跳转查看提车应收款页'); } }, '查看'), - showCharge ? React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('跳转收费明细页'); } }, '收费明细') : null, - showWithdraw ? React.createElement(Button, { type: 'link', size: 'small', onClick: function() { handleWithdraw(record); } }, '撤回') : null, - showInvoice ? React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('跳转开票信息页'); } }, '开票信息') : null - ); - } - } - ]; - - // 默认全选当前页:在 pagination 变化时把当前页 id 加入 selectedRowKeys(仅做初始化倾向,实际由 Table 受控) - // 筛选结果变化后默认全选(查询/重置后与列表联动) - React.useEffect(function() { - _selectedRowKeys[1](filteredList.map(function(r) { return r.id; })); - }, [filteredList]); - - var rowSelection = { - selectedRowKeys: _selectedRowKeys[0], - onChange: function(keys) { _selectedRowKeys[1](keys); }, - getCheckboxProps: function(record) { return { name: record.id }; }, - fixed: true - }; - - // 筛选默认第一行(3 项),展开显示全部 8 项 - var filterCount = _filterExpanded[0] ? 8 : 3; - var filterNodes = []; - for (var fi = 0; fi < filterCount && fi < filterItems.length; fi++) { - filterNodes.push(filterItems[fi]); - } - - // 多选选中时列表行不添加选中样式(选中行与未选中行背景一致) - var tableRowClassStyle = '.receivable-list-table .ant-table-tbody .ant-table-row-selected > td { background: #fff !important; }'; - - return React.createElement(App, null, - React.createElement('div', { style: layoutStyle }, - React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, - React.createElement(Breadcrumb, { - items: [ - { title: '运维管理' }, - { title: '财务管理' }, - { title: '提车应收款' } - ] - }), - React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function() { _requirementModalVisible[1](true); } }, '查看需求说明') - ), - React.createElement(Card, { style: { marginBottom: 16 } }, - React.createElement('div', { - style: { - display: 'grid', - gridTemplateColumns: '1fr 1fr 1fr', - gap: '16px 24px', - alignItems: 'start' - } - }, filterNodes), - 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(Button, { type: 'link', size: 'small', onClick: function() { _filterExpanded[1](!_filterExpanded[0]); } }, _filterExpanded[0] ? '收起' : '更多') - ) - ), - React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'flex-end' } }, - React.createElement(Button, { onClick: handleExport }, '导出') - ), - React.createElement(Card, null, - React.createElement(React.Fragment, null, - React.createElement('style', null, tableRowClassStyle), - React.createElement('div', { className: 'receivable-list-table' }, - React.createElement(Table, { - rowKey: 'id', - rowSelection: rowSelection, - columns: columns, - dataSource: filteredList, - scroll: { x: 1800 }, - size: 'small', - pagination: { - showSizeChanger: true, - showQuickJumper: true, - showTotal: function(t) { return '共 ' + t + ' 条'; } - } - }) - ) - ) - ), - React.createElement(Modal, { - title: '提示', - open: _withdrawModalVisible[0], - onCancel: function() { _withdrawModalVisible[1](false); _withdrawRecord[1](null); }, - onOk: handleWithdrawOk, - okText: '确认', - cancelText: '取消' - }, React.createElement('div', { style: { fontSize: 14, color: 'rgba(0,0,0,0.65)' } }, '是否确认撤回该流程?')), - React.createElement(Modal, { - title: '需求说明', - open: _requirementModalVisible[0], - onCancel: function() { _requirementModalVisible[1](false); }, - width: 720, - footer: React.createElement(Button, { onClick: function() { _requirementModalVisible[1](false); } }, '关闭'), - bodyStyle: { maxHeight: '70vh', overflow: 'auto' } - }, React.createElement('div', { style: { padding: '8px 0', whiteSpace: 'pre-wrap', fontSize: 14, lineHeight: 1.6, color: 'rgba(0,0,0,0.85)' } }, requirementContent)) - ) - ); -}; diff --git a/web端/财务管理/提车收款-收费明细.jsx b/web端/财务管理/提车收款-收费明细.jsx deleted file mode 100644 index 0f92dc0..0000000 --- a/web端/财务管理/提车收款-收费明细.jsx +++ /dev/null @@ -1,278 +0,0 @@ -// 【重要】必须使用 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 Input = antd.Input; - var Button = antd.Button; - var Table = antd.Table; - var Modal = antd.Modal; - var message = antd.message; - var App = antd.App; - - var mockProject = useMemo(function() { - return { contractCode: 'HT-ZL-2025-001', contractType: '正式合同', projectName: '北京朝阳区租赁项目', customerName: '某某科技有限公司', paymentMethod: '预付', paymentCycle: '1个月', department: '运营部', responsible: '张三' }; - }, []); - var mockVehicleList = useMemo(function() { - return [ - { brand: '奔驰', model: 'E300L', plateNo: '京A12345', monthlyRent: '8000.00', deposit: '2000.00', serviceItems: [{ name: '保养服务', fee: '300.00', remark: '' }, { name: '保险', fee: '200.00', remark: '' }] }, - { brand: '宝马', model: '530Li', plateNo: '京B67890', monthlyRent: '7000.00', deposit: '1500.00', serviceItems: [{ name: '保养服务', fee: '250.00', remark: '' }] } - ]; - }, []); - var mockHydrogen = useMemo(function() { - return { bearer: '客户', paymentMethod: '预付', prepaymentAmount: '3580.00' }; - }, []); - var mockInvoice = useMemo(function() { - return { customerName: '某某科技有限公司', taxId: '91330400MA2XXXXX1', address: '浙江省嘉兴市南湖区科技大道1号', phone: '0571-88888888', account: '6222021234567890123', bank: '中国工商银行嘉兴分行', mailingAddress: '浙江省嘉兴市南湖区科技大道1号' }; - }, []); - - var vehicleRowsState = useState([]); - var vehicleRows = vehicleRowsState[0]; - var setVehicleRows = vehicleRowsState[1]; - var serviceModalRowState = useState(null); - var serviceModalRow = serviceModalRowState[0]; - var setServiceModalRow = serviceModalRowState[1]; - var requirementVisibleState = useState(false); - var requirementVisible = requirementVisibleState[0]; - var setRequirementVisible = requirementVisibleState[1]; - var cancelConfirmVisibleState = useState(false); - var cancelConfirmVisible = cancelConfirmVisibleState[0]; - var setCancelConfirmVisible = cancelConfirmVisibleState[1]; - - var requirementContent = '「车辆管理系统」中的「租赁费用管理」模块下「提车应收款」中「收费明细」模块,第一步由业务填写;\n\n#提车应收款-收款明细\n\n整个页面从上至下为项目信息、车辆首付款、氢费预付款、开票信息4个卡片模块组成;\n\n1.项目信息:\n1.1.上方为表单,显示合同编码、合同类型、项目名称、客户名称、付款方式、付款周期、业务部门、业务负责人;\n1.1.1.合同编码:显示租赁合同编号;\n1.1.2.合同类型:显示租赁合同类型,类型有正式合同/试用合同;\n1.1.3.项目名称:显示租赁合同项目名称;\n1.1.4.客户名称:显示租赁合同客户名称;\n1.1.5.付款方式:显示租赁合同付款方式,类型有预付/后付;\n1.1.6.付款周期:显示付款周期,类型有1个月-12个月;\n1.1.7.业务部门:显示租赁合同对应业务部门;\n1.1.8.业务负责人:显示租赁合同对应业务负责人;\n\n2.提车应收款:\n2.1.上方为提车应收款应收总额;\n2.1.1.提车应收款总额:显示总金额,格式为xx.xx元,计算方式为:所有应付车辆租金+所有应付保证金+所有应付服务费-所有减免金额;\n2.2.车辆账单:品牌/型号/车牌号/应收车辆租金/车辆租金备注/应收保证金/服务费项目/应收服务费/减免金额/减免金额备注\n2.2.1.-2.2.7. 品牌至服务费项目(点击管理弹出卡片);\n2.1.8.应收服务费:根据服务费项目计算总和;\n2.1.9.减免金额:选填,默认为0;\n2.1.10.减免金额备注:选填;\n\n3.氢费预付款:\n3.1.氢费应收总额(=应收金额-减免金额);氢费预付款应收金额、减免金额、减免金额备注;\n\n4.开票信息:\n4.1.开票金额(=提车应收款总额+氢费应收总额);\n4.2.客户名称、纳税人识别号、地址、电话、账户、开户行、邮寄地址、开票时间(待开票)、发票附件(待上传)、备注(无);\n\n5.页面底部:提交审核、取消;取消二次确认;\n\n6.审批流程:标准/非标情况说明。'; - - var hydrogenFormState = useState(function() { - var isCustomerPrepay = (mockHydrogen.bearer === '客户' && mockHydrogen.paymentMethod === '预付'); - var paid = isCustomerPrepay ? (mockHydrogen.prepaymentAmount || '0.00') : '0.00'; - return { paidTotal: paid, discount: '0.00', discountRemark: '' }; - }); - var hydrogenForm = hydrogenFormState[0]; - var setHydrogenForm = hydrogenFormState[1]; - var hydrogenPayableTotal = useMemo(function() { - var paid = parseFloat(hydrogenForm.paidTotal) || 0; - var discount = parseFloat(hydrogenForm.discount) || 0; - var v = paid - discount; - return (v >= 0 ? v : 0).toFixed(2); - }, [hydrogenForm.paidTotal, hydrogenForm.discount]); - - function formatTwoDecimals(val) { - var n = parseFloat(String(val).replace(/[^\d.-]/g, '')); - if (isNaN(n)) return '0.00'; - return n.toFixed(2); - } - - React.useEffect(function() { - var rows = mockVehicleList.map(function(v) { - var serviceItems = (v.serviceItems || []).map(function(s) { - return { name: s.name, fee: s.fee || '', remark: s.remark || '' }; - }); - return { - brand: v.brand, - model: v.model, - plateNo: v.plateNo || '-', - payableRent: v.monthlyRent || '', - rentRemark: '', - deposit: v.deposit || '', - serviceItems: serviceItems, - discount: '0', - discountRemark: '' - }; - }); - setVehicleRows(rows); - }, [mockVehicleList]); - - function getRowServiceTotal(row) { - var total = 0; - var list = row.serviceItems || []; - for (var i = 0; i < list.length; i++) { - var n = parseFloat(list[i].fee); - if (!isNaN(n)) total += n; - } - return total.toFixed(2); - } - var totalPayable = useMemo(function() { - var rentSum = 0, depositSum = 0, serviceSum = 0, discountSum = 0; - for (var i = 0; i < vehicleRows.length; i++) { - var r = vehicleRows[i]; - rentSum += parseFloat(r.payableRent) || 0; - depositSum += parseFloat(r.deposit) || 0; - serviceSum += parseFloat(getRowServiceTotal(r)) || 0; - discountSum += parseFloat(r.discount) || 0; - } - return (rentSum + depositSum + serviceSum - discountSum).toFixed(2); - }, [vehicleRows]); - var invoiceAmount = useMemo(function() { - return (parseFloat(totalPayable) + parseFloat(hydrogenPayableTotal)).toFixed(2); - }, [totalPayable, hydrogenPayableTotal]); - - var handleVehicleChange = useCallback(function(rowIndex, field, value) { - setVehicleRows(function(prev) { - var next = prev.slice(); - var row = next[rowIndex] ? Object.assign({}, next[rowIndex]) : next[rowIndex]; - row[field] = value; - next[rowIndex] = row; - return next; - }); - }, []); - var handleServiceItemChange = useCallback(function(rowIndex, itemIndex, field, value) { - setVehicleRows(function(prev) { - var next = prev.slice(); - var row = next[rowIndex] ? Object.assign({}, next[rowIndex]) : next[rowIndex]; - var items = (row.serviceItems || []).slice(); - var item = items[itemIndex] ? Object.assign({}, items[itemIndex]) : items[itemIndex]; - item[field] = value; - items[itemIndex] = item; - row.serviceItems = items; - next[rowIndex] = row; - return next; - }); - }, []); - var handleSubmit = useCallback(function() { - var err = []; - for (var i = 0; i < vehicleRows.length; i++) { - var r = vehicleRows[i]; - if (!r.payableRent || String(r.payableRent).trim() === '') err.push('第' + (i + 1) + '行应收车辆租金'); - if (!r.deposit || String(r.deposit).trim() === '') err.push('第' + (i + 1) + '行应收保证金'); - var items = r.serviceItems || []; - for (var j = 0; j < items.length; j++) { - if (!items[j].fee || String(items[j].fee).trim() === '') err.push('第' + (i + 1) + '行服务费项「' + (items[j].name || '') + '」应收费用'); - } - } - if (!hydrogenForm.paidTotal || String(hydrogenForm.paidTotal).trim() === '') err.push('氢费预付款应收金额'); - if (!hydrogenForm.discount || String(hydrogenForm.discount).trim() === '') err.push('氢费减免金额'); - if (err.length > 0) { - message.warning('请填写必填项:' + err.join('、')); - return; - } - message.success('提交成功,该条记录已移至审核中心,审核状态为待审核'); - }, [vehicleRows, hydrogenForm]); - var handleCancelClick = useCallback(function() { setCancelConfirmVisible(true); }, []); - var handleCancelConfirm = useCallback(function(confirmed) { - setCancelConfirmVisible(false); - if (confirmed) message.info('已返回提车应收款列表'); - }, []); - - var layoutStyle = { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 }; - var formRowStyle = { display: 'flex', flexWrap: 'wrap', marginBottom: 16 }; - var formColStyle = { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 }; - var labelStyle = { display: 'block', marginBottom: 6, color: 'rgba(0,0,0,0.85)' }; - var labelRequiredStyle = { color: '#ff4d4f', marginRight: 4 }; - var totalLineStyle = { marginBottom: 16, fontSize: 14 }; - var totalAmountStyle = { color: '#1890ff', fontWeight: 600, fontSize: 16 }; - var footerStyle = { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, zIndex: 99 }; - - var FormItem = function(props) { - return React.createElement('div', { style: props.colStyle || formColStyle }, - React.createElement('label', { style: labelStyle }, props.required ? React.createElement('span', { style: labelRequiredStyle }, '*') : null, props.label), - props.children - ); - }; - - var projectFields = React.createElement('div', { style: formRowStyle }, - React.createElement(FormItem, { label: '合同编码' }, React.createElement(Input, { value: mockProject.contractCode, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '合同类型' }, React.createElement(Input, { value: mockProject.contractType, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '项目名称' }, React.createElement(Input, { value: mockProject.projectName, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '客户名称' }, React.createElement(Input, { value: mockProject.customerName, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '付款方式' }, React.createElement(Input, { value: mockProject.paymentMethod, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '付款周期' }, React.createElement(Input, { value: mockProject.paymentCycle, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '业务部门' }, React.createElement(Input, { value: mockProject.department, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '业务负责人' }, React.createElement(Input, { value: mockProject.responsible, disabled: true, style: { width: '100%' } })) - ); - - var vehicleColumns = [ - { title: '品牌', dataIndex: 'brand', key: 'brand', width: 90 }, - { title: '型号', dataIndex: 'model', key: 'model', width: 100 }, - { title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 }, - { title: '应收车辆租金', key: 'payableRent', width: 120, render: function(_, r, idx) { return React.createElement(Input, { value: r.payableRent, onChange: function(e) { handleVehicleChange(idx, 'payableRent', e.target.value); }, style: { width: '100%' }, addonAfter: '元' }); } }, - { title: '车辆租金备注', key: 'rentRemark', width: 110, render: function(_, r, idx) { return React.createElement(Input, { value: r.rentRemark || '', onChange: function(e) { handleVehicleChange(idx, 'rentRemark', e.target.value); }, placeholder: '选填', style: { width: '100%' } }); } }, - { title: '应收保证金', dataIndex: 'deposit', key: 'deposit', width: 100 }, - { title: '服务费项目', key: 'service', width: 90, render: function(_, r, idx) { return React.createElement(Button, { type: 'link', size: 'small', onClick: function() { setServiceModalRow(idx); } }, '管理'); } }, - { title: '应收服务费', key: 'serviceTotal', width: 100, render: function(_, r) { return getRowServiceTotal(r); } }, - { title: '减免金额', key: 'discount', width: 100, render: function(_, r, idx) { return React.createElement(Input, { value: r.discount, onChange: function(e) { handleVehicleChange(idx, 'discount', e.target.value); }, placeholder: '0', style: { width: '100%' } }); } }, - { title: '减免金额备注', key: 'discountRemark', width: 110, render: function(_, r, idx) { return React.createElement(Input, { value: r.discountRemark || '', onChange: function(e) { handleVehicleChange(idx, 'discountRemark', e.target.value); }, placeholder: '选填', style: { width: '100%' } }); } } - ]; - var vehicleTable = React.createElement(Table, { - rowKey: function(_, i) { return String(i); }, - columns: vehicleColumns, - dataSource: vehicleRows, - pagination: false, - size: 'small', - scroll: { x: 1000 } - }); - - var hydrogenFields = React.createElement('div', { style: formRowStyle }, - React.createElement(FormItem, { label: '氢费预付款应收金额', required: true }, React.createElement(Input, { value: hydrogenForm.paidTotal, onChange: function(e) { setHydrogenForm(function(prev) { return Object.assign({}, prev, { paidTotal: e.target.value }); }); }, onBlur: function() { setHydrogenForm(function(prev) { return Object.assign({}, prev, { paidTotal: formatTwoDecimals(prev.paidTotal) }); }); }, placeholder: '0.00', addonAfter: '元', style: { width: '100%' } })), - React.createElement(FormItem, { label: '减免金额', required: true }, React.createElement(Input, { value: hydrogenForm.discount, onChange: function(e) { setHydrogenForm(function(prev) { return Object.assign({}, prev, { discount: e.target.value }); }); }, onBlur: function() { setHydrogenForm(function(prev) { return Object.assign({}, prev, { discount: formatTwoDecimals(prev.discount) }); }); }, placeholder: '0.00', addonAfter: '元', style: { width: '100%' } })), - React.createElement(FormItem, { label: '减免金额备注' }, React.createElement(Input, { value: hydrogenForm.discountRemark || '', onChange: function(e) { setHydrogenForm(function(prev) { return Object.assign({}, prev, { discountRemark: e.target.value }); }); }, placeholder: '选填', style: { width: '100%' } })) - ); - - var invoiceFields = React.createElement('div', { style: formRowStyle }, - React.createElement(FormItem, { label: '客户名称' }, React.createElement(Input, { value: mockInvoice.customerName, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '纳税人识别号' }, React.createElement(Input, { value: mockInvoice.taxId, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '地址' }, React.createElement(Input, { value: mockInvoice.address, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '电话' }, React.createElement(Input, { value: mockInvoice.phone, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '账户' }, React.createElement(Input, { value: mockInvoice.account, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '开户行' }, React.createElement(Input, { value: mockInvoice.bank, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '邮寄地址' }, React.createElement(Input, { value: mockInvoice.mailingAddress, disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '开票时间' }, React.createElement(Input, { value: '待开票', disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '发票附件' }, React.createElement(Input, { value: '待上传', disabled: true, style: { width: '100%' } })), - React.createElement(FormItem, { label: '备注' }, React.createElement(Input, { value: '无', disabled: true, style: { width: '100%' } })) - ); - - var serviceModalDataSource = serviceModalRow !== null && vehicleRows[serviceModalRow] ? (vehicleRows[serviceModalRow].serviceItems || []) : []; - var serviceModalColumns = [ - { title: '服务项目', dataIndex: 'name', key: 'name', width: 140 }, - { title: '应收费用', key: 'fee', width: 140, render: function(_, item, itemIndex) { return React.createElement(Input, { value: item.fee, onChange: function(e) { handleServiceItemChange(serviceModalRow, itemIndex, 'fee', e.target.value); }, style: { width: '100%' } }); } }, - { title: '服务费用备注', key: 'remark', width: 180, render: function(_, item, itemIndex) { return React.createElement(Input, { value: item.remark || '', onChange: function(e) { handleServiceItemChange(serviceModalRow, itemIndex, 'remark', e.target.value); }, placeholder: '选填', style: { width: '100%' } }); } } - ]; - - var serviceModalOpen = serviceModalRow !== null; - var serviceModalContent = serviceModalOpen ? React.createElement(Table, { rowKey: function(_, i) { return String(i); }, columns: serviceModalColumns, dataSource: serviceModalDataSource, pagination: false, size: 'small' }) : null; - var serviceModalFooter = React.createElement(Button, { onClick: function() { setServiceModalRow(null); } }, '关闭'); - var requirementModalFooter = React.createElement(Button, { onClick: function() { setRequirementVisible(false); } }, '关闭'); - var cancelModalOk = function() { handleCancelConfirm(true); }; - var cancelModalCancel = function() { setCancelConfirmVisible(false); }; - - return React.createElement(App, null, - React.createElement('div', { style: layoutStyle }, - React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, - React.createElement(Breadcrumb, { items: [{ title: '租赁费用管理' }, { title: '提车应收款' }, { title: '收费明细' }] }), - React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function() { setRequirementVisible(true); } }, '查看需求说明') - ), - React.createElement(Card, { title: '项目信息', style: { marginBottom: 16 } }, projectFields), - React.createElement(Card, { title: '提车应收款', style: { marginBottom: 16 } }, - React.createElement('div', { style: totalLineStyle }, - React.createElement('span', { style: { marginRight: 8 } }, '提车应收款总额:'), - React.createElement('span', { style: totalAmountStyle }, totalPayable + ' 元') - ), - vehicleTable - ), - React.createElement(Card, { title: '氢费预付款', style: { marginBottom: 16 } }, - React.createElement('div', { style: totalLineStyle }, - React.createElement('span', { style: { marginRight: 8 } }, '氢费应收总额:'), - React.createElement('span', { style: totalAmountStyle }, hydrogenPayableTotal + ' 元') - ), - hydrogenFields - ), - React.createElement(Card, { title: '开票信息', style: { marginBottom: 80 } }, - React.createElement('div', { style: totalLineStyle }, - React.createElement('span', { style: { marginRight: 8 } }, '开票金额:'), - React.createElement('span', { style: totalAmountStyle }, invoiceAmount + ' 元') - ), - invoiceFields - ), - React.createElement('div', { style: footerStyle }, - React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'), - React.createElement(Button, { onClick: handleCancelClick }, '取消') - ), - React.createElement(Modal, { title: '服务费项目', open: serviceModalOpen, onCancel: function() { setServiceModalRow(null); }, footer: serviceModalFooter, destroyOnClose: true }, serviceModalContent), - React.createElement(Modal, { title: '需求说明', open: requirementVisible, onCancel: function() { setRequirementVisible(false); }, width: 720, footer: requirementModalFooter, bodyStyle: { maxHeight: '70vh', overflow: 'auto' } }, React.createElement('div', { style: { whiteSpace: 'pre-wrap', fontSize: 14, lineHeight: 1.6 } }, requirementContent)), - React.createElement(Modal, { title: '提示', open: cancelConfirmVisible, onCancel: cancelModalCancel, onOk: cancelModalOk, okText: '是', cancelText: '否' }, React.createElement('div', { style: { fontSize: 14 } }, '取消将会丢失所有已添加数据,是否确认取消?')) - ) - ); -}; diff --git a/web端/财务管理/提车首付款.jsx b/web端/财务管理/提车首付款.jsx deleted file mode 100644 index 0817308..0000000 --- a/web端/财务管理/提车首付款.jsx +++ /dev/null @@ -1,1048 +0,0 @@ -// 【重要】必须使用 const Component 作为组件变量名 -// 提车首付款 - 车辆资产管理后台(运维管理-财务管理-提车首付款) - -const Component = function() { - var useState = React.useState; - var useCallback = React.useCallback; - var useMemo = React.useMemo; - - // 分页 - var pageState = useState(1); - var currentPage = pageState[0]; - var setCurrentPage = pageState[1]; - var pageSizeState = useState(10); - var pageSize = pageSizeState[0]; - var setPageSize = pageSizeState[1]; - - // 筛选:表单输入值(用户填写) - var contractInputState = useState(''); - var contractInput = contractInputState[0]; - var setContractInput = contractInputState[1]; - var projectInputState = useState(''); - var projectInput = projectInputState[0]; - var setProjectInput = projectInputState[1]; - var customerInputState = useState(''); - var customerInput = customerInputState[0]; - var setCustomerInput = customerInputState[1]; - var statusInputState = useState([]); - var statusInput = statusInputState[0]; - var setStatusInput = statusInputState[1]; - // 可搜索选择器下拉展开:contract | project | customer | null - var filterDropdownOpenState = useState(null); - var filterDropdownOpen = filterDropdownOpenState[0]; - var setFilterDropdownOpen = filterDropdownOpenState[1]; - // 付款状态多选下拉展开 - var statusDropdownOpenState = useState(false); - var statusDropdownOpen = statusDropdownOpenState[0]; - var setStatusDropdownOpen = statusDropdownOpenState[1]; - // 筛选:已生效条件(点击查询后与列表联动) - var appliedFilterState = useState({ - contract: '', - project: '', - customer: '', - status: [] - }); - var appliedFilter = appliedFilterState[0]; - var setAppliedFilter = appliedFilterState[1]; - - // 查看页:当前视图 list | detail - var currentViewState = useState('list'); - var currentView = currentViewState[0]; - var setCurrentView = currentViewState[1]; - // 详情模式:view 查看 | payment 付款 - var detailModeState = useState('view'); - var detailMode = detailModeState[0]; - var setDetailMode = detailModeState[1]; - // 付款表单(付款模式可编辑) - var paymentFormState = useState({ - discountAmount: '', - discountReason: '', - hydrogenPaidAmount: '', - vehicleList: [], - hydrogenList: [], - violationList: [], - returnFeeList: [] - }); - var paymentForm = paymentFormState[0]; - var setPaymentForm = paymentFormState[1]; - // 服务费明细弹窗 - var popoverState = useState({ type: null, data: null }); - var popover = popoverState[0]; - var setPopover = popoverState[1]; - // 照片查看器 - var photoViewerState = useState({ visible: false, photos: [], currentIndex: 0 }); - var photoViewer = photoViewerState[0]; - var setPhotoViewer = photoViewerState[1]; - // 当前查看/付款的账单 id - var viewingBillIdState = useState(null); - var viewingBillId = viewingBillIdState[0]; - var setViewingBillId = viewingBillIdState[1]; - // 审核状态覆盖(id -> draft|pending|auditing|completed|withdrawn|rejected)待提交|审核中|审核完成|撤回|审核驳回 - var approvalStatusMapState = useState({}); - var approvalStatusMap = approvalStatusMapState[0]; - var setApprovalStatusMap = approvalStatusMapState[1]; - // 撤回二次确认:待撤回的 row id - var withdrawConfirmIdState = useState(null); - var withdrawConfirmId = withdrawConfirmIdState[0]; - var setWithdrawConfirmId = withdrawConfirmIdState[1]; - // 查看需求明细弹窗 - var requirementDetailVisibleState = useState(false); - var requirementDetailVisible = requirementDetailVisibleState[0]; - var setRequirementDetailVisible = requirementDetailVisibleState[1]; - - // 需求明细文案(提车首付款) - var requirementDetailContent = '提车首付款\n\n1.面包屑:\n1.1.运维管理-财务管理-提车首付款\n\n2.筛选:\n2.1.合同编码:合同编码显示租赁合同编码;选择器,支持从输入框进行内容模糊搜索;\n2.2.项目名称:项目名称显示租赁合同对应项目名称;选择器,支持从输入框输入内容模糊搜索;\n2.3.客户名称:客户名称显示租赁合同对应客户名称,选择器,支持从输入框输入内容模糊搜索;\n2.4.付款状态:显示合同提车首付款付款状态,选择器,支持多选;选项为全部、部分付款、未付款、已付款;\n2.5.右侧为查询和重置按钮,筛选条件以且的模式进行筛选,点击重置清空条件;\n\n3.列表:\n3.1.列表下方为分页器,支持选择单页数据条数;\n3.2.列表字段按照以下排序:付款状态、合同编码、项目名称、客户名称、合同生效日期、首期应付金额、实付金额、减免金额、未付金额、备注、操作;\n3.3.审核状态:分为待提交、审核中、审核完成、审核驳回、撤回;\n 流程流转为:待提交(交车任务生效/完成收费补充保存) → 完成收费补充提交 → 审核中(可撤回,撤回后显示为撤回)→ 审核完成(最终节点审核完成) / 审核驳回(驳回显示为审核驳回);\n a.待提交:交车单交车成功时系统会自动生成提车首付款,状态为「待提交」;业务人员点击收费补充信息点击保存,状态也为「待提交」,同时操作可:查看、收费;\n b.审核中:提车首付款完成收费信息填写,点击提交审核,状态变更为「审核中」,同时操作可:查看、撤回;\n c.审核完成:提车首付款完成审核后,显示为审核完成,同时操作可:查看;\n d.审核驳回:提车首付款在任意审核节点被驳回时,显示为审核驳回,同时操作可:查看、收费;\n e.撤回:提车首付款在审核中时,发起人可进行撤回,撤回后可重新补充收费信息并再次提交;操作可:查看、收费;\n3.4.付款状态:显示付款状态,状态分为:已付款、部分付款、未付款;\n a.已付款:应付金额为0时,显示为已付款;\n b.部分付款:未付金额>0且<应付金额时,显示为部分付款;\n c.未付款:实付金额为0时,显示为未付款;\n3.5.合同编码:显示租赁合同-合同编码;\n3.6.项目名称:显示该项目租赁合同-项目名称;\n3.7.客户名称:显示该项目租赁合同-客户名称;\n3.8.合同生效日期:显示该项目租赁合同-生效日期,格式为YYYY-MM-DD;\n3.9.首期应付金额:显示该笔账单首期应付金额,精确至2位小数,计算方式为:应付款总额=车辆月租金总计+服务费总计+保证金总计+氢气预付款金额;\n3.10.实付金额:显示该笔账单实付金额,精确至2位小数,如未付则显示为0;如已上传付款信息,则显示金额,计算方式为:实付款金额=实付月租金总计+实付服务费总计+实付保证金总计+氢气实付款金额\n3.11.减免金额:显示该笔账单减免金额,精确至2位小数,如无则显示为0;\n3.12.未付金额:显示该笔账单未付金额,精确至2位小数,如无则显示为0;未付款金额=应付款总额-实付金额-减免金额\n3.13.减免原因:显示减免金额添加原因;\n3.14.操作:查看、收费、撤回;\n a.查看:点击查看进入查看页;\n b.收费:点击收费,录入收费信息;\n c.撤回:审核状态为审核中时,点击撤回,进行二次提示,确认后该条数据审核状态显示为撤回,可重新进行收费操作;'; - - // 模拟数据:合同编码、项目、客户选项(用于选择器展示,可选) - var contractOptions = useMemo(function() { - return [ - { value: 'HT-ZL-2025-001', label: 'HT-ZL-2025-001' }, - { value: 'HT-ZL-2025-002', label: 'HT-ZL-2025-002' }, - { value: 'HT-ZL-2025-003', label: 'HT-ZL-2025-003' }, - { value: 'HT-ZL-2024-088', label: 'HT-ZL-2024-088' }, - { value: 'HT-ZL-2024-099', label: 'HT-ZL-2024-099' } - ]; - }, []); - var projectOptions = useMemo(function() { - return [ - { value: '北京朝阳区租赁项目', label: '北京朝阳区租赁项目' }, - { value: '上海浦东车辆租赁', label: '上海浦东车辆租赁' }, - { value: '广州天河运营项目', label: '广州天河运营项目' }, - { value: '深圳南山首期项目', label: '深圳南山首期项目' } - ]; - }, []); - var customerOptions = useMemo(function() { - return [ - { value: '某某科技有限公司', label: '某某科技有限公司' }, - { value: '某某物流有限公司', label: '某某物流有限公司' }, - { value: '某某制造有限公司', label: '某某制造有限公司' }, - { value: '某某出行服务公司', label: '某某出行服务公司' } - ]; - }, []); - - // 模拟列表数据 - var mockList = useMemo(function() { - var list = []; - var statuses = ['paid', 'partial', 'unpaid']; - var approvalStatuses = ['draft', 'pending', 'auditing', 'completed', 'withdrawn', 'rejected']; - var contracts = ['HT-ZL-2025-001', 'HT-ZL-2025-002', 'HT-ZL-2025-003', 'HT-ZL-2024-088', 'HT-ZL-2024-099']; - var projects = ['北京朝阳区租赁项目', '上海浦东车辆租赁', '广州天河运营项目', '深圳南山首期项目']; - var customers = ['某某科技有限公司', '某某物流有限公司', '某某制造有限公司', '某某出行服务公司']; - for (var i = 1; i <= 28; i++) { - var status = statuses[i % 3]; - var approvalStatus = approvalStatuses[i % 6]; - var firstPayable = 15000 + i * 800; - var paid = 0; - var discount = 0; - if (status === 'paid') { - paid = firstPayable; - discount = i % 4 === 0 ? 200 : 0; - } else if (status === 'partial') { - paid = Math.floor(firstPayable * 0.5); - discount = i % 5 === 0 ? 100 : 0; - } - var unpaid = Math.max(0, firstPayable - paid - discount); - var remark = status !== 'unpaid' ? '已上传付款凭证,备注编号' + i : '-'; - var discountReason = discount > 0 ? (i % 4 === 0 ? '长期合作客户优惠' : '首期减免') : '-'; - list.push({ - id: 'FP' + i, - paymentStatus: status, - approvalStatus: approvalStatus, - contractCode: contracts[i % contracts.length], - projectName: projects[i % projects.length], - customerName: customers[i % customers.length], - contractEffectiveDate: '2025-' + (String((i % 12) + 1)).padStart(2, '0') + '-' + (String((i % 28) + 1)).padStart(2, '0'), - firstPayableAmount: firstPayable, - paidAmount: paid, - discountAmount: discount, - unpaidAmount: unpaid, - discountReason: discountReason, - remark: remark - }); - } - return list; - }, []); - - // 查看页 mock 数据(按 查看页面需求说明 结构) - var mockBillDetail = useMemo(function() { - return { - startDate: '2025-01-01', - endDate: '2025-01-31', - contractCode: 'HT-ZL-2025-001', - projectName: '北京朝阳区租赁项目', - customerName: '某某科技有限公司', - department: '运营部', - responsible: '张三', - paymentCycle: '先付(付款周期:1个月)', - discountTotal: '200.00', - discountReason: '长期合作客户优惠,首期账单减免部分金额' - }; - }, []); - var mockVehicleList = useMemo(function() { - return [ - { brand: '奔驰', model: 'E300L', plateNo: '京A12345', planDelivery: '2024-12-25', planDeliveryEnd: '2024-12-31', actualDelivery: '2024-12-28', billStart: '2025-01-01', billEnd: '2025-01-31', monthlyRent: '8000.00', paidMonthlyRent: '7600.00', serviceFee: '500.00', paidServiceFee: '480.00', deposit: '2000.00', paidDeposit: '2000.00', serviceItems: [{ name: '保养服务', price: '300.00', effectiveDate: '2025-01-01' }, { name: '保险', price: '200.00', effectiveDate: '2025-01-01' }] }, - { brand: '宝马', model: '530Li', plateNo: '京B67890', planDelivery: '2024-12-20', planDeliveryEnd: '2024-12-26', actualDelivery: '2024-12-22', billStart: '2025-01-01', billEnd: '2025-01-31', monthlyRent: '7000.00', paidMonthlyRent: '7000.00', serviceFee: '400.00', paidServiceFee: '380.00', deposit: '1500.00', paidDeposit: '1500.00', serviceItems: [{ name: '保养服务', price: '250.00', effectiveDate: '2025-01-01' }] } - ]; - }, []); - // 氢费账单:氢费付款方式、氢气预付款、氢气实付款金额(元,两位小数) - var mockHydrogenData = useMemo(function() { - return { - paymentMethod: '预付', - prepaymentAmount: '3580.00', - paidAmount: '3200.00' - }; - }, []); - var mockViolationData = useMemo(function() { - return { - violationCount: 3, - totalAmount: '650.00', - paidTotalAmount: '600.00', - list: [ - { violationTime: '2025-01-10 08:30:00', plateNo: '京A12345', violationType: '违停', location: '北京市朝阳区xxx路', fineAmount: '200.00', paidFineAmount: '200.00' }, - { violationTime: '2025-01-18 14:20:00', plateNo: '京B67890', violationType: '超速', location: '北京市海淀区xxx大道', fineAmount: '200.00', paidFineAmount: '180.00' }, - { violationTime: '2025-01-25 09:15:00', plateNo: '京A12345', violationType: '闯红灯', location: '北京市东城区xxx路口', fineAmount: '250.00', paidFineAmount: '220.00' } - ] - }; - }, []); - var mockReturnFeeData = useMemo(function() { - return { - totalAmount: '2850.00', - paidTotalAmount: '2700.00', - list: [ - { feeName: '车辆外观损伤费', amount: '800.00', paidAmount: '760.00', photos: ['https://picsum.photos/80/80?random=1', 'https://picsum.photos/80/80?random=2'], attachments: [{ name: '外观损伤说明.pdf' }] }, - { feeName: '轮胎磨损费', amount: '1200.00', paidAmount: '1150.00', photos: ['https://picsum.photos/80/80?random=3'], attachments: [{ name: '轮胎检测报告.pdf' }, { name: '维修单据.pdf' }] }, - { feeName: '内饰清洁费', amount: '450.00', paidAmount: '430.00', photos: ['https://picsum.photos/80/80?random=4', 'https://picsum.photos/80/80?random=5', 'https://picsum.photos/80/80?random=6'], attachments: [] }, - { feeName: '油量补充费', amount: '400.00', paidAmount: '360.00', photos: [], attachments: [{ name: '加油凭证.jpg' }] } - ] - }; - }, []); - var vehicleBillTotals = useMemo(function() { - var list = mockVehicleList || []; - var monthlyRentTotal = 0, paidRentTotal = 0, serviceFeeTotal = 0, paidServiceFeeTotal = 0, depositTotal = 0, paidDepositTotal = 0; - list.forEach(function(v) { - monthlyRentTotal += parseFloat(v.monthlyRent || 0); - paidRentTotal += parseFloat(v.paidMonthlyRent || 0); - serviceFeeTotal += parseFloat(v.serviceFee || 0); - paidServiceFeeTotal += parseFloat(v.paidServiceFee || 0); - depositTotal += parseFloat(v.deposit || 0); - paidDepositTotal += parseFloat(v.paidDeposit || 0); - }); - return { - monthlyRentTotal: monthlyRentTotal.toFixed(2), - paidRentTotal: paidRentTotal.toFixed(2), - serviceFeeTotal: serviceFeeTotal.toFixed(2), - paidServiceFeeTotal: paidServiceFeeTotal.toFixed(2), - depositTotal: depositTotal.toFixed(2), - paidDepositTotal: paidDepositTotal.toFixed(2) - }; - }, [mockVehicleList]); - var vehicleTotals = useMemo(function() { - var monthlyRentTotal = parseFloat(vehicleBillTotals.monthlyRentTotal || 0); - var serviceFeeTotal = parseFloat(vehicleBillTotals.serviceFeeTotal || 0); - var depositTotal = parseFloat(vehicleBillTotals.depositTotal || 0); - var hydrogenTotal = parseFloat(mockHydrogenData.prepaymentAmount || 0); - var violationTotal = parseFloat(mockViolationData.totalAmount || 0); - var returnFeeTotal = parseFloat(mockReturnFeeData.totalAmount || 0); - var payableTotal = monthlyRentTotal + serviceFeeTotal + depositTotal + hydrogenTotal + violationTotal + returnFeeTotal; - var paidTotal = 0; - (mockVehicleList || []).forEach(function(v) { - paidTotal += parseFloat(v.paidMonthlyRent || 0) + parseFloat(v.paidServiceFee || 0) + parseFloat(v.paidDeposit || 0); - }); - var discountTotal = parseFloat(mockBillDetail.discountTotal || 0); - var unpaidTotal = payableTotal - paidTotal - discountTotal; - if (unpaidTotal < 0) unpaidTotal = 0; - return { - payableTotal: payableTotal.toFixed(2), - paidTotal: paidTotal.toFixed(2), - unpaidTotal: unpaidTotal.toFixed(2) - }; - }, [vehicleBillTotals, mockHydrogenData, mockViolationData, mockReturnFeeData, mockVehicleList, mockBillDetail]); - - // 筛选后的列表(使用已生效条件,点击查询后才与选择器联动) - var filteredList = useMemo(function() { - var list = mockList; - var af = appliedFilter; - // 合同编码选择器:与列表 contractCode 精确匹配 - if (af.contract && af.contract.trim()) { - var cf = af.contract.trim(); - list = list.filter(function(item) { - return (item.contractCode || '') === cf; - }); - } - // 项目名称选择器:与列表 projectName 精确匹配 - if (af.project && af.project.trim()) { - var pf = af.project.trim(); - list = list.filter(function(item) { - return (item.projectName || '') === pf; - }); - } - // 客户名称选择器:与列表 customerName 精确匹配 - if (af.customer && af.customer.trim()) { - var cuf = af.customer.trim(); - list = list.filter(function(item) { - return (item.customerName || '') === cuf; - }); - } - if (af.status && af.status.length > 0) { - list = list.filter(function(item) { - return af.status.indexOf(item.paymentStatus) >= 0; - }); - } - return list; - }, [mockList, appliedFilter]); - - var totalCount = filteredList.length; - var totalPages = Math.ceil(totalCount / pageSize) || 1; - var paginatedList = useMemo(function() { - var start = (currentPage - 1) * pageSize; - return filteredList.slice(start, start + pageSize); - }, [filteredList, currentPage, pageSize]); - - var getStatusText = function(status) { - if (status === 'paid') return '已付款'; - if (status === 'partial') return '部分付款'; - return '未付款'; - }; - var getStatusColor = function(status) { - if (status === 'paid') return '#52c41a'; - if (status === 'partial') return '#faad14'; - return '#ff4d4f'; - }; - - var formatAmount = function(num) { - var n = typeof num === 'number' ? num : parseFloat(num); - if (isNaN(n)) return '0.00'; - return n.toFixed(2); - }; - - var handleQuery = useCallback(function() { - setAppliedFilter({ - contract: contractInput, - project: projectInput, - customer: customerInput, - status: statusInput - }); - setCurrentPage(1); - }, [contractInput, projectInput, customerInput, statusInput]); - var handleReset = useCallback(function() { - setContractInput(''); - setProjectInput(''); - setCustomerInput(''); - setStatusInput([]); - setAppliedFilter({ contract: '', project: '', customer: '', status: [] }); - setCurrentPage(1); - }, []); - var getApprovalStatus = useCallback(function(row) { - return approvalStatusMap[row.id] != null ? approvalStatusMap[row.id] : row.approvalStatus; - }, [approvalStatusMap]); - var getApprovalStatusText = function(s) { - if (s === 'draft') return '待提交'; - if (s === 'pending' || s === 'auditing') return '审核中'; - if (s === 'completed') return '审核完成'; - if (s === 'withdrawn') return '撤回'; - if (s === 'rejected') return '审核驳回'; - return s || '-'; - }; - var handleView = useCallback(function(id) { - setViewingBillId(id); - setDetailMode('view'); - setCurrentView('detail'); - }, []); - var handlePayment = useCallback(function(id) { - setViewingBillId(id); - setDetailMode('payment'); - var vl = mockVehicleList.map(function(v) { - return { paidMonthlyRent: v.paidMonthlyRent || '', paidServiceFee: v.paidServiceFee || '', paidDeposit: v.paidDeposit || '' }; - }); - var hl = []; - var viol = mockViolationData.list.map(function(item) { return { paidFineAmount: item.paidFineAmount || '' }; }); - var rfl = mockReturnFeeData.list.map(function(item) { return { paidAmount: item.paidAmount || '' }; }); - setPaymentForm({ - discountAmount: mockBillDetail.discountTotal || '', - discountReason: mockBillDetail.discountReason || '', - hydrogenPaidAmount: mockHydrogenData.paidAmount || '', - vehicleList: vl, - hydrogenList: hl, - violationList: viol, - returnFeeList: rfl - }); - setCurrentView('detail'); - }, []); - var handleBackToList = useCallback(function() { - setCurrentView('list'); - setDetailMode('view'); - setViewingBillId(null); - }, []); - var handleSave = useCallback(function() { - if (viewingBillId) { - setApprovalStatusMap(function(prev) { - var next = {}; - for (var k in prev) { if (prev.hasOwnProperty(k)) next[k] = prev[k]; } - next[viewingBillId] = 'draft'; - return next; - }); - } - alert('保存成功'); - handleBackToList(); - }, [viewingBillId, handleBackToList]); - var handleWithdraw = useCallback(function(rowId) { - setWithdrawConfirmId(rowId); - }, []); - var handleWithdrawConfirm = useCallback(function() { - if (withdrawConfirmId) { - setApprovalStatusMap(function(prev) { - var next = {}; - for (var k in prev) { if (prev.hasOwnProperty(k)) next[k] = prev[k]; } - next[withdrawConfirmId] = 'draft'; - return next; - }); - setWithdrawConfirmId(null); - alert('已撤回,可重新编辑后提交'); - } - }, [withdrawConfirmId]); - var handlePaymentFormChange = useCallback(function(section, index, field, value) { - setPaymentForm(function(prev) { - var next = { - discountAmount: prev.discountAmount, - discountReason: prev.discountReason, - hydrogenPaidAmount: prev.hydrogenPaidAmount, - vehicleList: prev.vehicleList.slice(), - hydrogenList: prev.hydrogenList.slice(), - violationList: prev.violationList.slice(), - returnFeeList: prev.returnFeeList.slice() - }; - if (section === 'bill') { - if (field === 'discountAmount') next.discountAmount = value; - if (field === 'discountReason') next.discountReason = value; - if (field === 'hydrogenPaidAmount') next.hydrogenPaidAmount = value; - } else if (section === 'vehicle' && index >= 0 && index < next.vehicleList.length) { - next.vehicleList[index] = Object.assign({}, next.vehicleList[index]); - next.vehicleList[index][field] = value; - } else if (section === 'hydrogen' && index >= 0 && index < next.hydrogenList.length) { - next.hydrogenList[index] = Object.assign({}, next.hydrogenList[index]); - next.hydrogenList[index][field] = value; - } else if (section === 'violation' && index >= 0 && index < next.violationList.length) { - next.violationList[index] = Object.assign({}, next.violationList[index]); - next.violationList[index][field] = value; - } else if (section === 'returnFee' && index >= 0 && index < next.returnFeeList.length) { - next.returnFeeList[index] = Object.assign({}, next.returnFeeList[index]); - next.returnFeeList[index][field] = value; - } - return next; - }); - }, []); - var handleSubmit = useCallback(function() { - var errors = []; - if (!paymentForm.discountAmount || String(paymentForm.discountAmount).trim() === '') errors.push('减免金额'); - if (!paymentForm.discountReason || String(paymentForm.discountReason).trim() === '') errors.push('减免原因'); - if (!paymentForm.hydrogenPaidAmount || String(paymentForm.hydrogenPaidAmount).trim() === '') errors.push('氢气实付款金额'); - paymentForm.vehicleList.forEach(function(v, i) { - if (!v.paidMonthlyRent || String(v.paidMonthlyRent).trim() === '') errors.push('车辆账单-实付月租金(第' + (i + 1) + '行)'); - if (!v.paidServiceFee || String(v.paidServiceFee).trim() === '') errors.push('车辆账单-实付服务费(第' + (i + 1) + '行)'); - if (!v.paidDeposit || String(v.paidDeposit).trim() === '') errors.push('车辆账单-实付保证金(第' + (i + 1) + '行)'); - }); - paymentForm.violationList.forEach(function(v, i) { - if (!v.paidFineAmount || String(v.paidFineAmount).trim() === '') errors.push('违章费用-实付罚款金额(第' + (i + 1) + '行)'); - }); - paymentForm.returnFeeList.forEach(function(r, i) { - if (!r.paidAmount || String(r.paidAmount).trim() === '') errors.push('还车费用-实付金额(第' + (i + 1) + '行)'); - }); - if (errors.length > 0) { - alert('请填写必填项:' + errors.join('、')); - return; - } - if (viewingBillId) { - setApprovalStatusMap(function(prev) { - var next = {}; - for (var k in prev) { if (prev.hasOwnProperty(k)) next[k] = prev[k]; } - next[viewingBillId] = 'pending'; - return next; - }); - } - alert('提交成功'); - handleBackToList(); - }, [paymentForm, handleBackToList, viewingBillId]); - - // 样式 - var styles = { - page: { - padding: '24px', - backgroundColor: '#f5f5f5', - minHeight: '100vh', - fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif' - }, - breadcrumb: { - marginBottom: '16px', - fontSize: '14px', - color: '#666' - }, - breadcrumbSep: { color: '#bfbfbf', margin: '0 8px' }, - content: { - backgroundColor: '#fff', - borderRadius: '8px', - padding: '24px', - boxShadow: '0 1px 2px rgba(0,0,0,0.03)', - overflowX: 'auto' - }, - filterRow: { - display: 'flex', - flexWrap: 'nowrap', - gap: '16px', - marginBottom: '20px', - alignItems: 'center', - overflowX: 'auto' - }, - filterItem: { - display: 'flex', - alignItems: 'center', - gap: '8px' - }, - label: { fontSize: '14px', color: '#333', minWidth: '80px' }, - input: { - padding: '8px 12px', - border: '1px solid #d9d9d9', - borderRadius: '4px', - fontSize: '14px', - width: '200px' - }, - select: { - padding: '8px 12px', - border: '1px solid #d9d9d9', - borderRadius: '4px', - fontSize: '14px', - width: '200px' - }, - filterSelectWrap: { position: 'relative', width: '200px' }, - filterDropdown: { - position: 'absolute', - top: '100%', - left: 0, - right: 0, - marginTop: '2px', - maxHeight: '200px', - overflowY: 'auto', - backgroundColor: '#fff', - border: '1px solid #d9d9d9', - borderRadius: '4px', - boxShadow: '0 2px 8px rgba(0,0,0,0.15)', - zIndex: 10 - }, - filterDropdownItem: { - padding: '8px 12px', - fontSize: '14px', - cursor: 'pointer', - borderBottom: '1px solid #f0f0f0' - }, - selectMultiple: { - padding: '8px 12px', - border: '1px solid #d9d9d9', - borderRadius: '4px', - fontSize: '14px', - minWidth: '200px', - minHeight: '36px' - }, - statusMultiWrap: { position: 'relative', display: 'inline-block' }, - statusMultiDisplay: { - padding: '8px 12px', - border: '1px solid #d9d9d9', - borderRadius: '4px', - fontSize: '14px', - width: '200px', - backgroundColor: '#fff', - cursor: 'pointer', - minHeight: '36px', - boxSizing: 'border-box' - }, - statusDropdownPanel: { - position: 'absolute', - left: 0, - top: '100%', - marginTop: '2px', - width: '100%', - maxHeight: '220px', - overflowY: 'auto', - backgroundColor: '#fff', - border: '1px solid #d9d9d9', - borderRadius: '4px', - boxShadow: '0 2px 8px rgba(0,0,0,0.15)', - zIndex: 10 - }, - statusDropdownOption: { - padding: '8px 12px', - fontSize: '14px', - cursor: 'pointer', - borderBottom: '1px solid #f0f0f0' - }, - table: { width: '100%', borderCollapse: 'collapse', fontSize: '14px' }, - th: { - textAlign: 'left', - padding: '12px 16px', - backgroundColor: '#fafafa', - borderBottom: '1px solid #f0f0f0', - fontWeight: 600, - color: '#333', - whiteSpace: 'nowrap' - }, - td: { - padding: '12px 16px', - borderBottom: '1px solid #f0f0f0', - color: '#333', - whiteSpace: 'nowrap' - }, - actionColTh: { - position: 'sticky', - right: 0, - backgroundColor: '#fafafa', - boxShadow: '-2px 0 4px rgba(0,0,0,0.06)', - zIndex: 1 - }, - actionColTd: { - position: 'sticky', - right: 0, - backgroundColor: '#fff', - boxShadow: '-2px 0 4px rgba(0,0,0,0.06)', - zIndex: 1 - }, - actionBtn: { - padding: '4px 12px', - marginRight: '8px', - borderRadius: '4px', - border: 'none', - cursor: 'pointer', - fontSize: '13px' - }, - viewBtn: { backgroundColor: '#e6f7ff', color: '#1890ff' }, - payBtn: { backgroundColor: '#f6ffed', color: '#52c41a' }, - withdrawBtn: { backgroundColor: '#fff7e6', color: '#fa8c16' }, - pagination: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginTop: '20px', - flexWrap: 'wrap', - gap: '12px' - }, - pageSizeSelect: { - padding: '6px 10px', - border: '1px solid #d9d9d9', - borderRadius: '4px', - fontSize: '13px' - }, - pageInfo: { fontSize: '14px', color: '#666' }, - pageHeader: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px', flexWrap: 'wrap', gap: '12px' }, - requirementLink: { color: '#1890ff', cursor: 'pointer', fontSize: '14px', textDecoration: 'none' }, - requirementModalBody: { maxHeight: '70vh', overflowY: 'auto', whiteSpace: 'pre-wrap', fontSize: '14px', lineHeight: 1.6, color: '#333', padding: '0 4px' }, - queryBtn: { - padding: '8px 20px', - backgroundColor: '#1890ff', - color: '#fff', - border: 'none', - borderRadius: '4px', - cursor: 'pointer', - fontSize: '14px' - }, - resetBtn: { - padding: '8px 20px', - backgroundColor: '#fff', - color: '#666', - border: '1px solid #d9d9d9', - borderRadius: '4px', - cursor: 'pointer', - fontSize: '14px' - }, - // 查看页样式(按 查看页面需求说明) - detailPage: { padding: '24px', backgroundColor: '#f5f5f5', minHeight: '100vh', width: '100%', boxSizing: 'border-box' }, - backBtn: { marginBottom: '16px', padding: '8px 16px', backgroundColor: '#fff', border: '1px solid #d9d9d9', borderRadius: '4px', cursor: 'pointer', fontSize: '14px' }, - detailContent: { display: 'flex', flexDirection: 'column', gap: '24px', width: '100%' }, - detailCard: { backgroundColor: '#fff', borderRadius: '8px', padding: '24px', boxShadow: '0 1px 2px rgba(0,0,0,0.03)', width: '100%', boxSizing: 'border-box' }, - detailCardTitle: { fontSize: '16px', fontWeight: 600, marginBottom: '16px', paddingBottom: '12px', borderBottom: '1px solid #f0f0f0' }, - detailRow: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '24px', marginBottom: '12px', fontSize: '14px' }, - detailItem: {}, - detailItemInline: { display: 'flex', alignItems: 'center' }, - detailItemInputRight: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, - detailLabel: { color: '#666', marginRight: '8px' }, - amountInputWrap: { display: 'flex', alignItems: 'center', gap: '8px' }, - amountInput: { padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: '4px', fontSize: '14px', width: '120px' }, - amountSuffix: { color: '#666', fontSize: '14px' }, - detailTextarea: { padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: '4px', fontSize: '14px', width: '100%', minWidth: '200px', minHeight: '60px', resize: 'vertical' }, - vehicleTable: { width: '100%', borderCollapse: 'collapse', fontSize: '14px' }, - hydrogenSummary: { display: 'flex', gap: '48px', marginBottom: '16px', fontSize: '14px' }, - hydrogenSummaryItem: { color: '#333' }, - photoThumb: { width: '40px', height: '40px', objectFit: 'cover', borderRadius: '4px', cursor: 'pointer', marginRight: '4px', verticalAlign: 'middle' }, - attachmentLink: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none', marginRight: '8px', fontSize: '14px' }, - amountLink: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, - photoViewerOverlay: { position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.85)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1001 }, - photoViewerContent: { position: 'relative', textAlign: 'center' }, - photoViewerImg: { maxWidth: '90vw', maxHeight: '85vh', objectFit: 'contain' }, - photoViewerBtn: { position: 'absolute', top: '50%', marginTop: '-20px', padding: '10px 16px', backgroundColor: 'rgba(255,255,255,0.9)', border: 'none', borderRadius: '4px', cursor: 'pointer', fontSize: '14px' }, - photoViewerPrev: { left: '20px' }, - photoViewerNext: { right: '20px' }, - photoViewerClose: { position: 'absolute', top: '-40px', right: '0', padding: '8px 16px', backgroundColor: 'rgba(255,255,255,0.9)', border: 'none', borderRadius: '4px', cursor: 'pointer', fontSize: '14px' }, - photoViewerCounter: { color: '#fff', marginTop: '16px', fontSize: '14px' }, - popover: { position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000 }, - popoverCard: { backgroundColor: '#fff', borderRadius: '8px', padding: '24px', maxWidth: '90%', maxHeight: '80vh', overflow: 'auto' }, - popoverHeader: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px', whiteSpace: 'nowrap' }, - popoverTitle: { fontSize: '16px', fontWeight: 600, whiteSpace: 'nowrap' }, - popoverClose: { padding: '4px 12px', backgroundColor: '#f5f5f5', border: 'none', borderRadius: '4px', cursor: 'pointer' }, - popoverTable: { width: '100%', borderCollapse: 'collapse', fontSize: '14px' }, - popoverTh: { textAlign: 'left', padding: '12px 16px', backgroundColor: '#fafafa', borderBottom: '1px solid #f0f0f0', fontWeight: 600, color: '#333', whiteSpace: 'nowrap' }, - popoverTd: { padding: '12px 16px', borderBottom: '1px solid #f0f0f0', color: '#333', whiteSpace: 'nowrap' }, - modalFooter: { marginTop: '24px', textAlign: 'right', display: 'flex', justifyContent: 'center', gap: '12px' } - }; - - // 查看页:按 查看页面需求说明 渲染(租赁账单详情) - if (currentView === 'detail') { - return ( - React.createElement('div', { style: styles.detailPage }, - React.createElement('div', { style: Object.assign({}, styles.breadcrumb, { marginBottom: '16px' }) }, - React.createElement('span', null, '财务管理'), - React.createElement('span', { style: styles.breadcrumbSep }, '>'), - React.createElement('span', null, '提车首付款'), - React.createElement('span', { style: styles.breadcrumbSep }, '>'), - React.createElement('span', null, detailMode === 'payment' ? '收费' : '查看') - ), - React.createElement('div', { style: styles.detailContent }, - React.createElement('div', { style: styles.detailCard }, - React.createElement('div', { style: styles.detailCardTitle }, '账单信息'), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '账单开始日期:'), React.createElement('span', null, mockBillDetail.startDate)), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '账单结束日期:'), React.createElement('span', null, mockBillDetail.endDate)) - ), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '合同编码:'), React.createElement('span', null, mockBillDetail.contractCode)), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '项目名称:'), React.createElement('span', null, mockBillDetail.projectName)), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '客户名称:'), React.createElement('span', null, mockBillDetail.customerName)) - ), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '业务部门:'), React.createElement('span', null, mockBillDetail.department)), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '业务负责人:'), React.createElement('span', null, mockBillDetail.responsible)), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '付款周期:'), React.createElement('span', null, mockBillDetail.paymentCycle)) - ), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '首期应付金额:'), React.createElement('span', { style: { color: '#1890ff', fontWeight: 600 } }, vehicleTotals.payableTotal + ' 元')), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '实付款总额:'), React.createElement('span', { style: { color: '#52c41a', fontWeight: 600 } }, vehicleTotals.paidTotal + ' 元')), - React.createElement('div', { style: Object.assign({}, styles.detailItem, styles.detailItemInline) }, React.createElement('span', { style: styles.detailLabel }, '减免金额:'), detailMode === 'payment' ? React.createElement('div', { style: styles.amountInputWrap }, React.createElement('input', { type: 'text', style: styles.amountInput, value: paymentForm.discountAmount, onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountAmount', e.target.value); }, placeholder: '0.00' }), React.createElement('span', { style: styles.amountSuffix }, '元')) : React.createElement('span', { style: { fontWeight: 600 } }, mockBillDetail.discountTotal + ' 元')), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '未付款总额:'), React.createElement('span', { style: { color: '#ff4d4f', fontWeight: 600 } }, vehicleTotals.unpaidTotal + ' 元')) - ), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: Object.assign({}, styles.detailItem, { gridColumn: '1 / -1' }) }, React.createElement('span', { style: styles.detailLabel }, '减免原因:'), detailMode === 'payment' ? React.createElement('textarea', { style: styles.detailTextarea, value: paymentForm.discountReason, onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountReason', e.target.value); }, placeholder: '请输入减免原因' }) : React.createElement('span', null, mockBillDetail.discountReason || '-')) - ) - ), - React.createElement('div', { style: styles.detailCard }, - React.createElement('div', { style: styles.detailCardTitle }, '车辆账单'), - React.createElement('table', { style: styles.vehicleTable }, - React.createElement('thead', null, React.createElement('tr', null, - React.createElement('th', { style: styles.th }, '品牌'), React.createElement('th', { style: styles.th }, '型号'), React.createElement('th', { style: styles.th }, '车牌号'), React.createElement('th', { style: styles.th }, '计划交车日期'), React.createElement('th', { style: styles.th }, '实际交车日期'), React.createElement('th', { style: styles.th }, '账单开始日期'), React.createElement('th', { style: styles.th }, '计费结束日期'), React.createElement('th', { style: styles.th }, '车辆月租金'), React.createElement('th', { style: styles.th }, '实付月租金'), React.createElement('th', { style: styles.th }, '服务费'), React.createElement('th', { style: styles.th }, '实付服务费'), React.createElement('th', { style: styles.th }, '保证金'), React.createElement('th', { style: styles.th }, '实付保证金') - )), - React.createElement('tbody', null, mockVehicleList.map(function(v, idx) { - var pf = paymentForm.vehicleList[idx] || {}; - return React.createElement('tr', { key: v.plateNo }, - React.createElement('td', { style: styles.td }, v.brand), React.createElement('td', { style: styles.td }, v.model), React.createElement('td', { style: styles.td }, v.plateNo), - React.createElement('td', { style: styles.td }, (v.planDelivery && v.planDeliveryEnd) ? (v.planDelivery + '至' + v.planDeliveryEnd) : (v.planDelivery || '未设置')), React.createElement('td', { style: styles.td }, v.actualDelivery || '未交车'), React.createElement('td', { style: styles.td }, v.billStart || '未设置'), React.createElement('td', { style: styles.td }, v.billEnd || '未设置'), - React.createElement('td', { style: styles.td }, v.monthlyRent), - React.createElement('td', { style: styles.td }, detailMode === 'payment' ? React.createElement('div', { style: styles.amountInputWrap }, React.createElement('input', { type: 'text', style: styles.amountInput, value: pf.paidMonthlyRent || '', onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidMonthlyRent', e.target.value); }, placeholder: '0.00' }), React.createElement('span', { style: styles.amountSuffix }, '元')) : (parseFloat(v.paidMonthlyRent || 0)).toFixed(2)), - React.createElement('td', { style: styles.td }, detailMode === 'payment' ? v.serviceFee : React.createElement('span', { style: styles.amountLink, onClick: function() { setPopover({ type: 'service', data: v.serviceItems }); } }, v.serviceFee)), - React.createElement('td', { style: styles.td }, detailMode === 'payment' ? React.createElement('div', { style: styles.amountInputWrap }, React.createElement('input', { type: 'text', style: styles.amountInput, value: pf.paidServiceFee || '', onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidServiceFee', e.target.value); }, placeholder: '0.00' }), React.createElement('span', { style: styles.amountSuffix }, '元')) : (parseFloat(v.paidServiceFee || 0)).toFixed(2)), - React.createElement('td', { style: styles.td }, v.deposit), - React.createElement('td', { style: styles.td }, detailMode === 'payment' ? React.createElement('div', { style: styles.amountInputWrap }, React.createElement('input', { type: 'text', style: styles.amountInput, value: pf.paidDeposit || '', onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidDeposit', e.target.value); }, placeholder: '0.00' }), React.createElement('span', { style: styles.amountSuffix }, '元')) : (parseFloat(v.paidDeposit || 0)).toFixed(2)) - ); - })), - React.createElement('tfoot', null, React.createElement('tr', { style: { backgroundColor: '#fafafa', fontWeight: 600 } }, React.createElement('td', { style: styles.td, colSpan: 7 }, '总计'), React.createElement('td', { style: styles.td }, vehicleBillTotals.monthlyRentTotal), React.createElement('td', { style: styles.td }, vehicleBillTotals.paidRentTotal), React.createElement('td', { style: styles.td }, vehicleBillTotals.serviceFeeTotal), React.createElement('td', { style: styles.td }, vehicleBillTotals.paidServiceFeeTotal), React.createElement('td', { style: styles.td }, vehicleBillTotals.depositTotal), React.createElement('td', { style: styles.td }, vehicleBillTotals.paidDepositTotal))) - ) - ), - React.createElement('div', { style: styles.detailCard }, - React.createElement('div', { style: styles.detailCardTitle }, '氢费账单'), - React.createElement('div', { style: styles.detailRow }, - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '氢费付款方式:'), React.createElement('span', null, mockHydrogenData.paymentMethod || '-')), - React.createElement('div', { style: styles.detailItem }, React.createElement('span', { style: styles.detailLabel }, '氢气预付款:'), React.createElement('span', null, (parseFloat(mockHydrogenData.prepaymentAmount || 0)).toFixed(2) + ' 元')), - React.createElement('div', { style: Object.assign({}, styles.detailItem, styles.detailItemInline) }, React.createElement('span', { style: styles.detailLabel }, '氢气实付款金额:'), detailMode === 'payment' ? React.createElement('div', { style: styles.amountInputWrap }, React.createElement('input', { type: 'text', style: styles.amountInput, value: paymentForm.hydrogenPaidAmount, onChange: function(e) { handlePaymentFormChange('bill', -1, 'hydrogenPaidAmount', e.target.value); }, placeholder: '0.00' }), React.createElement('span', { style: styles.amountSuffix }, '元')) : React.createElement('span', null, (parseFloat(mockHydrogenData.paidAmount || 0)).toFixed(2) + ' 元')) - ) - ) - ), - React.createElement('div', { style: { marginTop: '24px', textAlign: 'center', display: 'flex', justifyContent: 'center', gap: '16px' } }, - detailMode === 'payment' && React.createElement('button', { type: 'button', style: Object.assign({}, styles.backBtn, { backgroundColor: '#1890ff', color: '#fff', border: 'none' }), onClick: handleSubmit }, '提交审核'), - detailMode === 'payment' && React.createElement('button', { type: 'button', style: styles.backBtn, onClick: handleSave }, '保存'), - React.createElement('button', { type: 'button', style: styles.backBtn, onClick: handleBackToList }, '取消') - ), - photoViewer.visible && photoViewer.photos.length > 0 && React.createElement('div', { style: styles.photoViewerOverlay, onClick: function() { setPhotoViewer({ visible: false, photos: [], currentIndex: 0 }); } }, - React.createElement('div', { style: styles.photoViewerContent, onClick: function(e) { e.stopPropagation(); } }, - React.createElement('button', { style: Object.assign({}, styles.photoViewerBtn, styles.photoViewerClose), onClick: function() { setPhotoViewer({ visible: false, photos: [], currentIndex: 0 }); } }, '关闭'), - photoViewer.currentIndex > 0 ? React.createElement('button', { style: Object.assign({}, styles.photoViewerBtn, styles.photoViewerPrev), onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex - 1 }); } }, '上一张') : null, - React.createElement('img', { style: styles.photoViewerImg, src: photoViewer.photos[photoViewer.currentIndex].replace('80/80', '600/600'), alt: '' }), - photoViewer.currentIndex < photoViewer.photos.length - 1 ? React.createElement('button', { style: Object.assign({}, styles.photoViewerBtn, styles.photoViewerNext), onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex + 1 }); } }, '下一张') : null, - React.createElement('div', { style: styles.photoViewerCounter }, (photoViewer.currentIndex + 1) + ' / ' + photoViewer.photos.length) - ) - ), - (popover.type === 'service' && React.createElement('div', { style: styles.popover, onClick: function() { setPopover({ type: null, data: null }); } }, - React.createElement('div', { style: styles.popoverCard, onClick: function(e) { e.stopPropagation(); } }, - React.createElement('div', { style: styles.popoverHeader }, React.createElement('span', { style: styles.popoverTitle }, '服务费明细'), React.createElement('button', { style: styles.popoverClose, onClick: function() { setPopover({ type: null, data: null }); } }, '关闭')), - React.createElement('table', { style: styles.table }, React.createElement('thead', null, React.createElement('tr', null, React.createElement('th', { style: styles.th }, '服务项'), React.createElement('th', { style: styles.th }, '价格'), React.createElement('th', { style: styles.th }, '服务生效日期'))), React.createElement('tbody', null, popover.data ? popover.data.map(function(s, i) { return React.createElement('tr', { key: i }, React.createElement('td', { style: styles.td }, s.name), React.createElement('td', { style: styles.td }, s.price), React.createElement('td', { style: styles.td }, s.effectiveDate)); }) : null)) - ) - )) - ) - ); - } - - - return ( - React.createElement('div', { style: styles.page }, - React.createElement('div', { style: styles.pageHeader }, - React.createElement('div', { style: styles.breadcrumb }, - React.createElement('span', null, '财务管理'), - React.createElement('span', { style: styles.breadcrumbSep }, '>'), - React.createElement('span', null, '提车首付款') - ), - React.createElement('a', { style: styles.requirementLink, onClick: function() { setRequirementDetailVisible(true); }, role: 'button', tabIndex: 0, onKeyDown: function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setRequirementDetailVisible(true); } } }, '查看需求明细') - ), - React.createElement('div', { style: styles.content }, - // 筛选:合同编码、项目名称、客户名称(选择器+输入搜索)、付款状态(多选);右侧 查询、重置 - React.createElement('div', { style: styles.filterRow }, - React.createElement('div', { style: styles.filterItem }, - React.createElement('span', { style: styles.label }, '合同编码:'), - React.createElement('div', { style: styles.filterSelectWrap }, - React.createElement('input', { - style: styles.input, - placeholder: '请输入合同编码', - value: contractInput, - onChange: function(e) { setContractInput(e.target.value); }, - onFocus: function() { setFilterDropdownOpen('contract'); }, - onBlur: function() { setTimeout(function() { setFilterDropdownOpen(null); }, 200); } - }), - filterDropdownOpen === 'contract' && React.createElement('div', { style: styles.filterDropdown }, - contractOptions.filter(function(opt) { - var kw = (contractInput || '').toLowerCase(); - if (!kw) return true; - return (opt.label || '').toLowerCase().indexOf(kw) >= 0 || (opt.value || '').toLowerCase().indexOf(kw) >= 0; - }).map(function(opt) { - return React.createElement('div', { - key: opt.value, - style: styles.filterDropdownItem, - onMouseDown: function(e) { e.preventDefault(); setContractInput(opt.value); setFilterDropdownOpen(null); } - }, opt.label); - }) - ) - ) - ), - React.createElement('div', { style: styles.filterItem }, - React.createElement('span', { style: styles.label }, '项目名称:'), - React.createElement('div', { style: styles.filterSelectWrap }, - React.createElement('input', { - style: styles.input, - placeholder: '请输入项目名称', - value: projectInput, - onChange: function(e) { setProjectInput(e.target.value); }, - onFocus: function() { setFilterDropdownOpen('project'); }, - onBlur: function() { setTimeout(function() { setFilterDropdownOpen(null); }, 200); } - }), - filterDropdownOpen === 'project' && React.createElement('div', { style: styles.filterDropdown }, - projectOptions.filter(function(opt) { - var kw = (projectInput || '').toLowerCase(); - if (!kw) return true; - return (opt.label || '').toLowerCase().indexOf(kw) >= 0 || (opt.value || '').toLowerCase().indexOf(kw) >= 0; - }).map(function(opt) { - return React.createElement('div', { - key: opt.value, - style: styles.filterDropdownItem, - onMouseDown: function(e) { e.preventDefault(); setProjectInput(opt.value); setFilterDropdownOpen(null); } - }, opt.label); - }) - ) - ) - ), - React.createElement('div', { style: styles.filterItem }, - React.createElement('span', { style: styles.label }, '客户名称:'), - React.createElement('div', { style: styles.filterSelectWrap }, - React.createElement('input', { - style: styles.input, - placeholder: '请输入客户名称', - value: customerInput, - onChange: function(e) { setCustomerInput(e.target.value); }, - onFocus: function() { setFilterDropdownOpen('customer'); }, - onBlur: function() { setTimeout(function() { setFilterDropdownOpen(null); }, 200); } - }), - filterDropdownOpen === 'customer' && React.createElement('div', { style: styles.filterDropdown }, - customerOptions.filter(function(opt) { - var kw = (customerInput || '').toLowerCase(); - if (!kw) return true; - return (opt.label || '').toLowerCase().indexOf(kw) >= 0 || (opt.value || '').toLowerCase().indexOf(kw) >= 0; - }).map(function(opt) { - return React.createElement('div', { - key: opt.value, - style: styles.filterDropdownItem, - onMouseDown: function(e) { e.preventDefault(); setCustomerInput(opt.value); setFilterDropdownOpen(null); } - }, opt.label); - }) - ) - ) - ), - React.createElement('div', { style: styles.filterItem }, - React.createElement('span', { style: styles.label }, '付款状态:'), - React.createElement('div', { - style: styles.statusMultiWrap, - tabIndex: 0, - onBlur: function() { setTimeout(function() { setStatusDropdownOpen(false); }, 200); } - }, - React.createElement('div', { - style: styles.statusMultiDisplay, - onClick: function() { setStatusDropdownOpen(!statusDropdownOpen); } - }, statusInput.length === 0 ? '全部' : statusInput.map(function(s) { return getStatusText(s); }).join('、')), - statusDropdownOpen ? React.createElement('div', { style: styles.statusDropdownPanel }, - ['partial', 'unpaid', 'paid'].map(function(s) { - var checked = statusInput.indexOf(s) >= 0; - return React.createElement('div', { - key: s, - style: styles.statusDropdownOption, - onMouseDown: function(e) { - e.preventDefault(); - var idx = statusInput.indexOf(s); - var next = statusInput.slice(); - if (idx >= 0) next.splice(idx, 1); - else next.push(s); - setStatusInput(next); - } - }, React.createElement('label', { style: { cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '6px' } }, - React.createElement('input', { type: 'checkbox', checked: checked, readOnly: true }), - getStatusText(s) - )); - }) - ) : null - ) - ), - React.createElement('div', { style: { display: 'flex', gap: '8px', marginLeft: 'auto' } }, - React.createElement('button', { type: 'button', style: styles.queryBtn, onClick: handleQuery }, '查询'), - React.createElement('button', { type: 'button', style: styles.resetBtn, onClick: handleReset }, '重置') - ) - ), - // 列表:审核状态、付款状态、合同编码、项目名称、客户名称、合同生效日期、首期应付金额、实付款总额、减免金额、未付款总额、减免原因、操作(固定右侧) - React.createElement('table', { style: styles.table }, - React.createElement('thead', null, - React.createElement('tr', null, - React.createElement('th', { style: styles.th }, '审核状态'), - React.createElement('th', { style: styles.th }, '付款状态'), - React.createElement('th', { style: styles.th }, '合同编码'), - React.createElement('th', { style: styles.th }, '项目名称'), - React.createElement('th', { style: styles.th }, '客户名称'), - React.createElement('th', { style: styles.th }, '合同生效日期'), - React.createElement('th', { style: styles.th }, '首期应付金额'), - React.createElement('th', { style: styles.th }, '实付款总额'), - React.createElement('th', { style: styles.th }, '减免金额'), - React.createElement('th', { style: styles.th }, '未付款总额'), - React.createElement('th', { style: styles.th }, '减免原因'), - React.createElement('th', { style: Object.assign({}, styles.th, styles.actionColTh) }, '操作') - ) - ), - React.createElement('tbody', null, - paginatedList.map(function(row) { - var approvalStatus = getApprovalStatus(row); - var showPay = approvalStatus === 'draft' || approvalStatus === 'withdrawn' || approvalStatus === 'rejected'; - var showWithdraw = approvalStatus === 'auditing' || approvalStatus === 'pending'; - return React.createElement('tr', { key: row.id }, - React.createElement('td', { style: styles.td }, getApprovalStatusText(approvalStatus)), - React.createElement('td', { style: styles.td }, - React.createElement('span', { style: { color: getStatusColor(row.paymentStatus) } }, getStatusText(row.paymentStatus)) - ), - React.createElement('td', { style: styles.td }, row.contractCode), - React.createElement('td', { style: styles.td }, row.projectName), - React.createElement('td', { style: styles.td }, row.customerName), - React.createElement('td', { style: styles.td }, row.contractEffectiveDate), - React.createElement('td', { style: styles.td }, formatAmount(row.firstPayableAmount)), - React.createElement('td', { style: styles.td }, formatAmount(row.paidAmount)), - React.createElement('td', { style: styles.td }, formatAmount(row.discountAmount)), - React.createElement('td', { style: styles.td }, formatAmount(row.unpaidAmount)), - React.createElement('td', { style: styles.td }, row.discountReason || '-'), - React.createElement('td', { style: Object.assign({}, styles.td, styles.actionColTd) }, - React.createElement('button', { - type: 'button', - style: Object.assign({}, styles.actionBtn, styles.viewBtn), - onClick: function() { handleView(row.id); } - }, '查看'), - showPay && React.createElement('button', { - type: 'button', - style: Object.assign({}, styles.actionBtn, styles.payBtn), - onClick: function() { handlePayment(row.id); } - }, '收费'), - showWithdraw && React.createElement('button', { - type: 'button', - style: Object.assign({}, styles.actionBtn, styles.withdrawBtn), - onClick: function() { handleWithdraw(row.id); } - }, '撤回') - ) - ); - }) - ) - ), - // 分页:支持选择单页数据条数 - React.createElement('div', { style: styles.pagination }, - React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, - React.createElement('span', { style: styles.pageInfo }, '共 ' + totalCount + ' 条'), - React.createElement('select', { - style: styles.pageSizeSelect, - value: pageSize, - onChange: function(e) { - setPageSize(Number(e.target.value)); - setCurrentPage(1); - } - }, - React.createElement('option', { value: 10 }, '10 条/页'), - React.createElement('option', { value: 20 }, '20 条/页'), - React.createElement('option', { value: 50 }, '50 条/页') - ) - ), - React.createElement('div', { style: { display: 'flex', gap: '8px', alignItems: 'center' } }, - React.createElement('button', { - type: 'button', - style: Object.assign({}, styles.actionBtn, { padding: '6px 12px' }), - disabled: currentPage <= 1, - onClick: function() { setCurrentPage(currentPage - 1); } - }, '上一页'), - React.createElement('span', { style: styles.pageInfo }, currentPage + ' / ' + totalPages), - React.createElement('button', { - type: 'button', - style: Object.assign({}, styles.actionBtn, { padding: '6px 12px' }), - disabled: currentPage >= totalPages, - onClick: function() { setCurrentPage(currentPage + 1); } - }, '下一页') - ) - ), - withdrawConfirmId && React.createElement('div', { style: styles.popover, onClick: function() { setWithdrawConfirmId(null); } }, - React.createElement('div', { style: styles.popoverCard, onClick: function(e) { e.stopPropagation(); } }, - React.createElement('div', { style: styles.popoverTitle }, '确认撤回?'), - React.createElement('p', { style: { margin: '16px 0', fontSize: '14px', color: '#666' } }, '确认后将撤回该数据,审核状态变为撤回。'), - React.createElement('div', { style: styles.modalFooter }, - React.createElement('button', { type: 'button', style: styles.backBtn, onClick: function() { setWithdrawConfirmId(null); } }, '取消'), - React.createElement('button', { type: 'button', style: Object.assign({}, styles.backBtn, { backgroundColor: '#fa8c16', color: '#fff', border: 'none' }), onClick: handleWithdrawConfirm }, '确认') - ) - ) - ), - requirementDetailVisible && React.createElement('div', { style: styles.popover, onClick: function() { setRequirementDetailVisible(false); } }, - React.createElement('div', { style: Object.assign({}, styles.popoverCard, { maxWidth: '720px', width: '90%' }), onClick: function(e) { e.stopPropagation(); } }, - React.createElement('div', { style: styles.popoverHeader }, - React.createElement('span', { style: styles.popoverTitle }, '需求明细'), - React.createElement('button', { style: styles.popoverClose, onClick: function() { setRequirementDetailVisible(false); } }, '关闭') - ), - React.createElement('div', { style: styles.requirementModalBody }, requirementDetailContent) - ) - ) - ) - ) - ); -}; - -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)); - } - } -} diff --git a/web端/车辆租赁合同/车辆租赁合同-新增.jsx b/web端/车辆租赁合同/车辆租赁合同-新增.jsx index 9da57db..7278aa8 100644 --- a/web端/车辆租赁合同/车辆租赁合同-新增.jsx +++ b/web端/车辆租赁合同/车辆租赁合同-新增.jsx @@ -65,6 +65,7 @@ const Component = function() { var deliveryRegionOpen = bs10b[0]; var setDeliveryRegionOpen = bs10b[1]; var deliveryRegionClickInsideRef = React.useRef(false); + var nextRentalRowIdRef = React.useRef(2); var bs11 = React.useState(''); var deliveryLocation = bs11[0]; var setDeliveryLocation = bs11[1]; @@ -76,7 +77,7 @@ const Component = function() { var authorizedList = as1[0]; var setAuthorizedList = as1[1]; - var emptyRentalRow = { brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }; + var emptyRentalRow = { id: 1, brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }; var os1 = React.useState([emptyRentalRow]); var rentalOrders = os1[0]; var setRentalOrders = os1[1]; @@ -282,12 +283,23 @@ const Component = function() { }; var addRentalRow = function() { - setRentalOrders(rentalOrders.concat([{ brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }])); + setRentalOrders(rentalOrders.concat([{ id: nextRentalRowIdRef.current++, brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }])); }; var removeRentalRow = function(index) { var next = rentalOrders.slice(0); next.splice(index, 1); - setRentalOrders(next.length ? next : [{ brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }]); + setRentalOrders(next.length ? next : [Object.assign({}, emptyRentalRow)]); + }; + var copyRentalRow = function(index) { + var row = rentalOrders[index]; + if (!row) return; + var serviceItemsCopy = (row.serviceItems || []).map(function(si) { return { project: si.project || '', fee: si.fee || '', effectiveDate: si.effectiveDate || '' }; }); + if (serviceItemsCopy.length === 0) serviceItemsCopy = [{ project: '', fee: '', effectiveDate: '' }]; + var newRow = { id: nextRentalRowIdRef.current++, brand: row.brand || '', model: row.model || '', plateNo: '', vin: '', monthRent: row.monthRent || '', serviceItems: serviceItemsCopy, deposit: row.deposit || '', remark: row.remark || '' }; + var next = rentalOrders.slice(0); + next.splice(index + 1, 0, newRow); + setRentalOrders(next); + if (typeof message !== 'undefined' && message.success) message.success('已复制该行(车牌号已清空)'); }; var updateRentalOrder = function(index, field, value) { var next = rentalOrders.slice(0); @@ -379,7 +391,7 @@ const Component = function() { }, [plateNoFocusRow]); var styles = { - page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 }, + page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '"PingFang SC", "苹方-简", -apple-system, BlinkMacSystemFont, "Microsoft YaHei", sans-serif', fontSize: 14 }, breadcrumb: { marginBottom: 16, color: '#666' }, breadcrumbSep: { margin: '0 8px', color: '#999' }, anchorWrap: { position: 'fixed', top: 80, right: 24, zIndex: 100, backgroundColor: '#fff', borderRadius: 8, boxShadow: '0 2px 8px rgba(0,0,0,0.12)', padding: '12px 16px', minWidth: 160 }, @@ -535,7 +547,8 @@ const Component = function() { var plateNoOptions = vehicleList.map(function(v) { return React.createElement(Option, { key: v.plateNo, value: v.plateNo }, v.plateNo); }); var rentalTableBody = rentalOrders.map(function(row, idx) { var modelOpts = row.brand ? (modelByBrand[row.brand] || []) : []; - return React.createElement('tr', { key: idx }, + var rowId = row.id != null ? row.id : idx; + return React.createElement('tr', { key: rowId }, React.createElement('td', { style: styles.rentalTdCenter }, idx + 1), React.createElement('td', { style: styles.rentalTd }, React.createElement(Select, { style: { width: '100%', minWidth: 90 }, value: row.brand || undefined, onChange: function(v) { updateRentalOrder(idx, 'brand', v || ''); }, placeholder: '请选择' }, brandList.map(function(b, i) { return React.createElement(Option, { key: i, value: b }, b); }))), React.createElement('td', { style: styles.rentalTd }, React.createElement(Select, { style: { width: '100%', minWidth: 90 }, value: row.model || undefined, onChange: function(v) { updateRentalOrder(idx, 'model', v || ''); }, disabled: !row.brand, placeholder: '请选择' }, modelOpts.map(function(m, i) { return React.createElement(Option, { key: i, value: m }, m); }))), @@ -546,7 +559,7 @@ const Component = function() { React.createElement('td', { style: styles.rentalTdCenter }, calcRowServiceFee(row) + ' 元'), React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: { display: 'flex', alignItems: 'center' } }, React.createElement(Input, { placeholder: '0.00', value: row.deposit || '', onChange: function(e) { updateRentalOrder(idx, 'deposit', e.target.value); }, style: styles.rentalInput }), React.createElement('span', { style: { marginLeft: 4, whiteSpace: 'nowrap' } }, '元'))), React.createElement('td', { style: styles.rentalTd }, React.createElement(Input, { placeholder: '备注', value: row.remark || '', onChange: function(e) { updateRentalOrder(idx, 'remark', e.target.value); }, style: Object.assign({}, styles.rentalInput, { width: '100%' }) })), - React.createElement('td', { style: styles.rentalTdCenter }, React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeRentalRow(idx); } }, '删除')) + React.createElement('td', { style: styles.rentalTdCenter }, React.createElement('div', { style: { display: 'inline-flex', gap: 4, alignItems: 'center' } }, React.createElement(Button, { type: 'link', size: 'small', onClick: function() { copyRentalRow(idx); } }, '复制'), React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeRentalRow(idx); } }, '删除'))) ); }); @@ -568,7 +581,7 @@ const Component = function() { var rentalTh8 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 90, verticalAlign: 'middle' }) }, '服务费'); var rentalTh9 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 100 }) }, reqStar, '保证金'); var rentalTh10 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 80 }) }, '备注'); - var rentalTh11 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 60, verticalAlign: 'middle' }) }, '操作'); + var rentalTh11 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 90, verticalAlign: 'middle' }) }, '操作'); var rentalTableThead = React.createElement('thead', null, React.createElement('tr', null, rentalTh1, rentalTh2, rentalTh3, rentalTh4, rentalTh5, rentalTh6, rentalTh7, rentalTh8, rentalTh9, rentalTh10, rentalTh11)); var rentalTableTbody = React.createElement('tbody', null, rentalTableBody); var rentalTableEl = React.createElement('table', { style: styles.rentalTable }, rentalTableThead, rentalTableTbody); @@ -624,7 +637,7 @@ const Component = function() { var serviceModalRows = serviceModalRowIndex !== null && rentalOrders[serviceModalRowIndex] ? rentalOrders[serviceModalRowIndex].serviceItems : []; var serviceModalContent = serviceModalRowIndex !== null ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) closeServiceModal(); } }, React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '服务项目'), React.createElement('div', { style: styles.modalBody }, React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '服务项目'), React.createElement('th', { style: styles.rentalTh }, '费用'), React.createElement('th', { style: styles.rentalTh }, '生效时间'), React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 80 }) }, '操作'))), React.createElement('tbody', null, serviceModalRows.map(function(si, siIdx) { var filteredServiceOpts = serviceItemOptions.filter(function(o) { return !serviceItemSearch || o.indexOf(serviceItemSearch) !== -1; }); return React.createElement('tr', { key: siIdx }, React.createElement('td', { style: styles.rentalTd }, React.createElement(Select, { style: { width: '100%' }, placeholder: '请选择服务项目', value: si.project || undefined, onChange: function(v) { updateServiceItem(siIdx, 'project', v || ''); }, showSearch: true, filterOption: function(input, opt) { return opt && opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; }, allowClear: true }, serviceItemOptions.map(function(opt, oi) { return React.createElement(Option, { key: oi, value: opt }, opt); }))), React.createElement('td', { style: styles.rentalTd }, React.createElement(Input, { placeholder: '0.00', value: si.fee || '', onChange: function(e) { updateServiceItem(siIdx, 'fee', e.target.value); }, addonAfter: '元', style: { width: '100%' } })), React.createElement('td', { style: styles.rentalTd }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择生效时间', value: si.effectiveDate && window.moment ? window.moment(si.effectiveDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { updateServiceItem(siIdx, 'effectiveDate', dateStr || ''); } })), React.createElement('td', { style: styles.rentalTd }, React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeServiceItem(siIdx); } }, '删除'))); }))), React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addServiceItem }, '添加一行')), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right', display: 'flex', gap: 12, justifyContent: 'flex-end' } }, React.createElement(Button, { type: 'primary', onClick: function() { closeServiceModal(); } }, '保存'), React.createElement(Button, { onClick: closeServiceModal }, '关闭')))) : null; - var requirementContent = '租赁合同\n\n「数字化资产ONE-OS运管平台」中的「车辆租赁合同」-「新增租赁合同」模块,点击车辆租赁合同右上角「新增」进行创建;\n1.面包屑:\n#业务管理-车辆租赁合同-新增合同\n\n2.客户基本信息卡片:\n#用于从客户列表中选择客户,并将该合同绑定到业务部门及业务负责人(绑定业务部门/业务负责人主要为了后期从部门/业务负责人维度进行数据统计);\n2.1.客户名称:必选项,选择器,支持从输入框内输入内容进行模糊搜索,从客户信息列表中选择对应客户(只显示已通过审核的客户);\n2.2.客户统一信用代码:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「信用代码」字段;\n2.3.客户地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户地址」字段;\n2.4.客户联系人:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户联系人」字段;\n2.5.客户电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电话」字段;\n2.6.客户电子邮箱:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电子邮箱」字段;\n2.7.企业名称:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业名称」字段;\n2.8.企业电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业电话」字段;\n2.9.邮寄地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「邮寄地址」字段;\n2.10.开户银行:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「开户银行」字段;\n2.11.银行账号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「银行账号」字段;\n2.12.纳税人识别号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「纳税人识别号」字段;\n2.13.业务部门:必选项,选择器,从部门表中选择该租赁合同对应部门;\n2.14.业务负责人:必选项,选择器,从已选业务部门下拉取对应业务负责人,未选择业务部门时,业务负责人字段不可选;\n\n3.合同基本信息卡片:\n#用于定义租赁合同基本情况和付款方式;\n3.1.项目名称:必填项,输入框,用于定义该合同项目名称,默认提示信息"请输入项目名称";\n3.2.合同类型:必选项,选择器,合同类型分为「正式合同」「试用合同」;\n3.3.生效日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天,默认为点击新增日期;\n3.4.付款方式:必选项,付款方式分为「预付」「后付」两种;\n 3.4.1.如果选择预付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成就列入业务待办(工作台功能),同时以消息通知对应用户;\n 3.4.2.如果选择后付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成时,将前一期账单列入业务待办(工作台功能),同时以消息通知对应用户;\n3.5.主要车型:输入框(禁用状态),根据租赁订单信息中所有所选车型,自动反写入输入框并以标签形式显示,支持多车型显示,标签显示:型号名称;\n3.6.结束日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天;\n 3.6.1.合同结束日期前30天将以消息提醒方式提醒(消息中心、工作台);\n 3.6.2.到达合同结束日期时,租赁账单将会立刻停止计算,作为最后一期账单;\n 3.6.3.续签合同/转正式合同将重新生成账单,不会对旧合同账单做任何继承处理;\n3.7.付款周期:必选项,选择器,支持1个月-12个月 12种付款周期,账单将以此周期和账单计算方式规则,从交车任务形成的交车单进行完整交车后,定时自动生成账单;\n3.8.签约公司:必选项,选择器,从组织机构表中获取所有根组织机构(如嘉兴羚牛、上海羚牛、广东羚牛等),默认显示新增用户当前机构,可手动修改;\n3.9.交车区域:必选项,地区选择器,支持省-市2级,选择区域后,该任务生成交车任务时会自动推送至该区域负责运维人员;\n3.10.交车地点:必填项,输入框,支持自定义输入交车地点;\n3.11.合同原件:必填项,按钮,按钮文字为:上传附件,支持多个附件上传(doc/docx/pdf格式);\n3.12.备注:文本域,支持自定义输入备注信息;\n\n4.被授权人信息卡片:\n#用于定义租赁合同相关被授权人相关信息,被授权人在交车单完成时,需要选择被授权人,并通过被授权人手机短信,在E签宝进行签字确认;\n4.1.被授权人:必填项,输入框,用于输入被授权人信息;\n4.2.被授权人联系电话:必填项,输入框,用于输入被授权人联系电话,该电话后续需要接收E签宝签字链接;\n4.3.被授权人身份证:必填项,输入框,用于输入被授权人身份证信息;\n4.4.支持通过新增/删除一行的方式,创建或管理多个授权人,后续交车单完成时可从多个授权人中选择接收授权人;\n\n5.租赁订单信息卡片:\n#用于定义租赁合同对应车辆明细费用、氢费明细费用等相关信息;\n5.1.上方为租赁车辆总计数据,包括租赁车辆数、租金及服务费合计、保证金总额、氢气预付款金额等相关信息;\n 5.1.1.租赁车辆数:显示下方租赁订单信息包含多少辆车;\n 5.1.2.租金及服务费合计:显示下方租赁订单信息中车辆租金总额及服务费总额;\n 5.1.3.保证金总额:显示下方租赁订单信息中车辆保证金总额;\n 5.1.4.氢气预付款金额:显示氢气预付款金额,如客户选择自行承担氢费或羚牛承担氢费,则该处为0不计入氢气预付款金额;\n5.2.下方为列表,显示序号、品牌、型号、车牌号、车辆识别代码、车辆月租金(元)、服务费项目、服务费、保证金、备注,默认且至少显示一行空数据;\n 5.2.1.序号:自动按照条数生成,规则为1、2、3....以此类推;\n 5.2.2.品牌:必选项,选择器,从型号参数库中「品牌」字段拉取所有品牌;\n 5.2.3.型号:必选项,选择器,与品牌存在级联关系,未选择品牌则无法选择型号;\n 5.2.4.车牌号:选填项,选择器(支持从输入框输入车牌号关键字下拉匹配),可通过选择车牌号对品牌、型号进行反写;\n 5.2.5.车辆识别代码:输入框(禁用),显示该车辆对应车辆识别代码,根据所选车牌号从车辆表直接拉取进行反写;\n 5.2.6.车辆月租金:输入框,支持两位小数,用于输入该车辆月租金金额,输入框后缀为元,如还车时账单周期不满1个月,则按照:(车辆月租金/30)* 实际天数进行计算;\n 5.2.7.服务费项目:点击管理按钮弹出卡片,卡片标题为:服务项目,下方列表显示服务项目、费用、生效时间、操作;\n 5.2.7.1.服务项目:必选项,选择器(支持输入框输入服务项目关键字进行下拉匹配),选项包含:代处理费用、罚款、违章处理违约金、未参加安全培训、车辆出险、年检年审违约、停车费、设备损坏金(包含易损件)、清洗费、上门收车人工费、上门收车送车行驶费、上门收车基础服务费、保险上浮、保养费用、补办驾驶证、补办牌照、补办营运证、补办加氢证、借用备用钥匙、补配钥匙、租金、氢气费-客、退还车氢量差、能源费补缴、能源费退款、送车上门人工费、送车上门送车行驶费、送车上门基础服务费、保证金、氢气预付费、维修费用、ETC-客、ETC卡缺损费、ETC设备缺损费、电费-客、未结算保养费、未结算维修费、车损费、工具损坏或丢失费、证件费、广告损坏费、送车服务费、接车服务费、补办行驶证、超赔险、轮胎磨损费、无忧包、轮胎保、养护保、尾板;\n 5.2.7.2.费用:必填项,输入框,支持2位小数,输入框后缀为元;\n 5.2.7.3.生效时间:必选项,日期选择器,格式为YYYY-MM-DD;\n 5.2.7.4.操作:删除,点击删除直接删除该行数据;\n 5.2.7.5.新增一行数据:点击添加一行服务项目;\n #在提车应收款中,车辆的交车日期和服务费生效日期可能会存在不同的情况,所以服务费需要单独以生效时间进行计算,例如:\n 交车后车辆从1月1日开始计费,付款周期为2个月,则提车应收款租金会计算到3月1日,但是服务费生效时间为1月30日,此情况下需要以3月1日-1月30日,计算出服务费具体收费天数为30天,然后根据:(服务费费用/30)* 服务费收费天数30)进行计算;\n 5.2.8.服务费:自动根据添加的所有服务费项目计算总额,支持2位小数,格式为:xx.xx元;\n 5.2.9.保证金:必填项,输入框,支持2位小数,后缀为元,用于填写车辆需要支付的保证金金额,保证金为提车应收款一次性支付,还车时需要计入退还费用中;\n 5.2.10.备注:选填项,输入框,用于备注车辆复杂情况;\n 5.2.11.操作:删除,点击删除删除该行数据;\n 5.2.12.添加一行:点击后列表新增一行,用于填写一条新的车辆租金费用信息;\n5.3.氢费承担方:必选项,选择器,选项为:「我方」、「客户」,默认选择「客户」;\n 5.3.1.选择「我方」:不显示付款方式、氢气预付款;\n 5.3.2.选择「客户」:付款方式字段默认为预付,可手动修改;\n5.4.付款方式:必选项,选择器,选项为:「预付」、「月付款」、「自行结算」,默认为:「预付」;\n 5.4.1.预付:选择「预付」,需要填写:「氢气预付款」,氢气预付款指合同签署时客户就需预先付出的氢费款项,该部分款项会自动计入提车应收款中氢气预付款金额;\n 5.4.2.月付款:选择「月付款」,提车应收款中不进行收费,而是由业务人员按照实际情况,通过氢费账单功能生成对应氢费账单,单独与客户进行结算;\n 5.4.3.自行结算:选择「自行结算」,指合同签署后,所有氢气费用由客户自行承担;\n5.5.氢气预付款:选择「客户」「预付」时显示,必填项,输入框,支持2位小数,氢气预付款金额会计算入该合同交车应收款中,并计入5.1.4.氢气预付款金额中;\n5.6.退还车氢气单价:必填项,输入框,支持2位小数,后缀为元,不管氢费承担方和付款方式选择任何选项都需要进行维护,该金额主要用于与客户约定还车时,与交车时氢气差值以此费用进行自动计算和结算;\n\n6.其他费用信息卡片:\n#用于选择对应租赁费用模板,选择后展示证照补办费用、违约金费用、易损件费用、其他费用等信息,租赁费用模板管理功能位于「车辆租赁合同」列表左上角;\n6.1.选择费用模板:必选项,从「租赁费用模板」中拉取,选择后自动将该费用模板所有环节费用显示在合同中;\n 6.1.1.证照补办费用:单独标题显示,内容为列表,列表中包括项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.2.违约金费用:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.3.易损件信息:单独标题显示,内容为列表,列表中包含类别、损坏部位、配件、数量、费用明细,选择费用模板后自动反显;\n 6.1.4.其他费用信息:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n\n7.账单计算方式卡片:\n#必选项,填充按钮组,默认为按自然月结算,可手动修改,用于定义租赁合同的账单计算方式,分为「按自然月结算」、「按付款周期天数结算」两种方式;\n7.1.按付款周期天数结算:账单按照合同基本信息卡片中每隔付款周期*30天形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款从交车任务配置的开始计费时间开始,根据60天收取车辆租金,此后每隔60天生成一期租赁账单;\n7.2.按自然月结算:账单按照第一个月计费开始日期到当月最后一天为第一期,之后按照付款周期所选月份间隔,从开始月份第一天到间隔月份最后一天的自然月方式形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款车辆租金需要收取≥2个月租金作为标准流程,<2个月租金作为非标流程;\n 租赁账单首期从交车任务配置的开始计费时间开始,如付款周期为2个月,则首期账单结束时间为第二个月最后一天,付款周期为3个月,则首期账单结束时间为第三个月最后一天,此后每一期按照实际自然月开始-结束形成账单,例如付款周期为2个月,则第二期账单从2月1日-3月31日,以此类推;\n\n8.最下方为提交并审核、保存、取消三个按钮;\n8.1.点击提交并审核,toast提示:租赁合同已提交审核。同时该租赁合同进入租赁合同审核列表中;\n8.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中,该条数据只能保存人自己查看并编辑,其他人无法操作;\n8.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回车辆租赁合同列表页;\n\n所有卡片支持收起/展开功能,通过点击卡片右侧收起/展开实现;并增加锚点功能,锚点固定于页面右上角,点击锚点对应卡片名称,页面自动跳转至该卡片所在区域;'; + var requirementContent = '车辆租赁合同-新增(2026年3月3日版本)\n「数字化资产ONE-OS运管平台」中的「车辆租赁合同」-「新增租赁合同」模块,点击车辆租赁合同右上角「新增」进行创建;\n1.面包屑:\n#业务管理-车辆租赁合同-新增合同\n\n2.客户基本信息卡片:\n#用于从客户列表中选择客户,并将该合同绑定到业务部门及业务负责人(绑定业务部门/业务负责人主要为了后期从部门/业务负责人维度进行数据统计);\n2.1.客户名称:必选项,选择器,支持从输入框内输入内容进行模糊搜索,从客户信息列表中选择对应客户(只显示已通过审核的客户);\n2.2.客户统一信用代码:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「信用代码」字段;\n2.3.客户地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户地址」字段;\n2.4.客户联系人:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户联系人」字段;\n2.5.客户电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电话」字段;\n2.6.客户电子邮箱:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电子邮箱」字段;\n2.7.企业名称:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业名称」字段;\n2.8.企业电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业电话」字段;\n2.9.邮寄地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「邮寄地址」字段;\n2.10.开户银行:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「开户银行」字段;\n2.11.银行账号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「银行账号」字段;\n2.12.纳税人识别号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「纳税人识别号」字段;\n2.13.业务部门:必选项,选择器,从部门表中选择该租赁合同对应部门;\n2.14.业务负责人:必选项,选择器,从已选业务部门下拉取对应业务负责人,未选择业务部门时,业务负责人字段不可选;\n\n3.合同基本信息卡片:\n#用于定义租赁合同基本情况和付款方式;\n3.1.项目名称:必填项,输入框,用于定义该合同项目名称,默认提示信息"请输入项目名称";\n3.2.合同类型:必选项,选择器,合同类型分为「正式合同」「试用合同」;\n3.3.生效日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天,默认为点击新增日期;\n3.4.付款方式:必选项,付款方式分为「预付」「后付」两种;\n 3.4.1.如果选择预付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成就列入业务待办(工作台功能),同时以消息通知对应用户;\n 3.4.2.如果选择后付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成时,将前一期账单列入业务待办(工作台功能),同时以消息通知对应用户;\n3.5.主要车型:输入框(禁用状态),根据租赁订单信息中所有所选车型,自动反写入输入框并以标签形式显示,支持多车型显示,标签显示:型号名称;\n3.6.结束日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天;\n 3.6.1.合同结束日期前30天将以消息提醒方式提醒(消息中心、工作台);\n 3.6.2.到达合同结束日期时,租赁账单将会立刻停止计算,作为最后一期账单;\n 3.6.3.续签合同/转正式合同将重新生成账单,不会对旧合同账单做任何继承处理;\n3.7.付款周期:必选项,选择器,支持1个月-12个月 12种付款周期,账单将以此周期和账单计算方式规则,从交车任务形成的交车单进行完整交车后,定时自动生成账单;\n3.8.签约公司:必选项,选择器,从组织机构表中获取所有根组织机构(如嘉兴羚牛、上海羚牛、广东羚牛等),默认显示新增用户当前机构,可手动修改,后期需要考虑从签约公司维度统计合同相关数据;\n3.9.交车区域:必选项,地区选择器,支持省-市2级,选择区域后,该任务生成交车任务时会自动推送至该区域负责运维人员;\n3.10.交车地点:必填项,输入框,支持自定义输入交车地点;\n3.11.合同原件:必填项,按钮,按钮文字为:上传附件,支持多个附件上传(doc/docx/pdf格式);\n3.12.备注:文本域,支持自定义输入备注信息;\n\n4.被授权人信息卡片:\n#用于定义租赁合同相关被授权人相关信息,被授权人在交车单完成时,需要选择被授权人,并通过被授权人手机短信,在E签宝进行签字确认;\n4.1.被授权人:必填项,输入框,用于输入被授权人信息;\n4.2.被授权人联系电话:必填项,输入框,用于输入被授权人联系电话,该电话后续需要接收E签宝签字链接;\n4.3.被授权人身份证:必填项,输入框,用于输入被授权人身份证信息;\n4.4.支持通过新增/删除一行的方式,创建或管理多个授权人,后续交车单完成时可从多个授权人中选择接收授权人;\n\n5.租赁订单信息卡片:\n#用于定义租赁合同对应车辆明细费用、氢费明细费用等相关信息;\n5.1.上方为租赁车辆总计数据,包括租赁车辆数、租金及服务费合计、保证金总额、氢气预付款金额等相关信息;\n 5.1.1.租赁车辆数:显示下方租赁订单信息包含多少辆车;\n 5.1.2.租金及服务费合计:显示下方租赁订单信息中车辆租金总额及服务费总额;\n 5.1.3.保证金总额:显示下方租赁订单信息中车辆保证金总额;\n 5.1.4.氢气预付款金额:显示氢气预付款金额,如客户选择自行承担氢费或羚牛承担氢费,则该处为0不计入氢气预付款金额;\n5.2.下方为列表,显示序号、品牌、型号、车牌号、车辆识别代码、车辆月租金(元)、服务费项目、服务费、保证金、备注,默认且至少显示一行空数据;\n 5.2.1.序号:自动按照条数生成,规则为1、2、3....以此类推;\n 5.2.2.品牌:必选项,选择器,从型号参数库中「品牌」字段拉取所有品牌;\n 5.2.3.型号:必选项,选择器,与品牌存在级联关系,未选择品牌则无法选择型号;\n 5.2.4.车牌号:选填项,选择器(支持从输入框输入车牌号关键字下拉匹配),可通过选择车牌号对品牌、型号进行反写;\n 5.2.5.车辆识别代码:输入框(禁用),显示该车辆对应车辆识别代码,根据所选车牌号从车辆表直接拉取进行反写;\n 5.2.6.车辆月租金:输入框,支持两位小数,用于输入该车辆月租金金额,输入框后缀为元,如还车时账单周期不满1个月,则按照:(车辆月租金/30)* 实际天数进行计算;\n 5.2.7.服务费项目:点击管理按钮弹出卡片,卡片标题为:服务项目,下方列表显示服务项目、费用、生效时间、操作;\n 5.2.7.1.服务项目:必选项,选择器(支持输入框输入服务项目关键字进行下拉匹配),选项包含:代处理费用、罚款、违章处理违约金、未参加安全培训、车辆出险、年检年审违约、停车费、设备损坏金(包含易损件)、清洗费、上门收车人工费、上门收车送车行驶费、上门收车基础服务费、保险上浮、保养费用、补办驾驶证、补办牌照、补办营运证、补办加氢证、借用备用钥匙、补配钥匙、租金、氢气费-客、退还车氢量差、能源费补缴、能源费退款、送车上门人工费、送车上门送车行驶费、送车上门基础服务费、保证金、氢气预付费、维修费用、ETC-客、ETC卡缺损费、ETC设备缺损费、电费-客、未结算保养费、未结算维修费、车损费、工具损坏或丢失费、证件费、广告损坏费、送车服务费、接车服务费、补办行驶证、超赔险、轮胎磨损费、无忧包、轮胎保、养护保、尾板;\n 5.2.7.2.费用:必填项,输入框,支持2位小数,输入框后缀为元;\n 5.2.7.3.生效时间:必选项,日期选择器,格式为YYYY-MM-DD;\n 5.2.7.4.操作:删除,点击删除直接删除该行数据;\n 5.2.7.5.新增一行数据:点击添加一行服务项目;\n #在提车应收款中,车辆的交车日期和服务费生效日期可能会存在不同的情况,所以服务费需要单独以生效时间进行计算,例如:\n 交车后车辆从1月1日开始计费,付款周期为2个月,则提车应收款租金会计算到3月1日,但是服务费生效时间为1月30日,此情况下需要以3月1日-1月30日,计算出服务费具体收费天数为30天,然后根据:(服务费费用/30)* 服务费收费天数30)进行计算;\n 5.2.8.服务费:自动根据添加的所有服务费项目计算总额,支持2位小数,格式为:xx.xx元;\n 5.2.9.保证金:必填项,输入框,支持2位小数,后缀为元,用于填写车辆需要支付的保证金金额,保证金为提车应收款一次性支付,还车时需要计入退还费用中;\n 5.2.10.备注:选填项,输入框,用于备注车辆复杂情况;\n 5.2.11.操作:删除,点击删除删除该行数据;\n 5.2.12.添加一行:点击后列表新增一行,用于填写一条新的车辆租金费用信息;\n5.3.氢费承担方:必选项,选择器,选项为:「我方」、「客户」,默认选择「客户」;\n 5.3.1.选择「我方」:不显示付款方式、氢气预付款;\n 5.3.2.选择「客户」:付款方式字段默认为预付,可手动修改;\n5.4.付款方式:必选项,选择器,选项为:「预付」、「月付款」、「自行结算」,默认为:「预付」;\n 5.4.1.预付:选择「预付」,需要填写:「氢气预付款」,氢气预付款指合同签署时客户就需预先付出的氢费款项,该部分款项会自动计入提车应收款中氢气预付款金额;\n 5.4.2.月付款:选择「月付款」,提车应收款中不进行收费,而是由业务人员按照实际情况,通过氢费账单功能生成对应氢费账单,单独与客户进行结算;\n 5.4.3.自行结算:选择「自行结算」,指合同签署后,所有氢气费用由客户自行承担;\n5.5.氢气预付款:选择「客户」「预付」时显示,必填项,输入框,支持2位小数,氢气预付款金额会计算入该合同交车应收款中,并计入5.1.4.氢气预付款金额中;\n5.6.退还车氢气单价:必填项,输入框,支持2位小数,后缀为元,不管氢费承担方和付款方式选择任何选项都需要进行维护,该金额主要用于与客户约定还车时,与交车时氢气差值以此费用进行自动计算和结算;\n\n6.其他费用信息卡片:\n#用于选择对应租赁费用模板,选择后展示证照补办费用、违约金费用、易损件费用、其他费用等信息,租赁费用模板管理功能位于「车辆租赁合同」列表左上角;\n6.1.选择费用模板:必选项,从「租赁费用模板」中拉取,选择后自动将该费用模板所有环节费用显示在合同中;\n 6.1.1.证照补办费用:单独标题显示,内容为列表,列表中包括项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.2.违约金费用:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.3.易损件信息:单独标题显示,内容为列表,列表中包含类别、损坏部位、配件、数量、费用明细,选择费用模板后自动反显;\n 6.1.4.其他费用信息:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n\n7.账单计算方式卡片:\n#必选项,填充按钮组,默认为按自然月结算,可手动修改,用于定义租赁合同的账单计算方式,分为「按自然月结算」、「按付款周期天数结算」两种方式;\n7.1.按付款周期天数结算:账单按照合同基本信息卡片中每隔付款周期*30天形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款从交车任务配置的开始计费时间开始,根据60天收取车辆租金,此后每隔60天生成一期租赁账单;\n7.2.按自然月结算:账单按照第一个月计费开始日期到当月最后一天为第一期,之后按照付款周期所选月份间隔,从开始月份第一天到间隔月份最后一天的自然月方式形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款车辆租金需要收取≥2个月租金作为标准流程,<2个月租金作为非标流程;\n 租赁账单首期从交车任务配置的开始计费时间开始,如付款周期为2个月,则首期账单结束时间为第二个月最后一天,付款周期为3个月,则首期账单结束时间为第三个月最后一天,此后每一期按照实际自然月开始-结束形成账单,例如付款周期为2个月,则第二期账单从2月1日-3月31日,以此类推;\n\n8.最下方为提交并审核、保存、取消三个按钮;\n8.1.点击提交并审核,toast提示:租赁合同已提交审核。同时该租赁合同进入租赁合同审核列表中;\n8.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中,该条数据只能保存人自己查看并编辑,其他人无法操作;\n8.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回车辆租赁合同列表页;\n\n所有卡片支持收起/展开功能,通过点击卡片右侧收起/展开实现;并增加锚点功能,锚点固定于页面右上角,点击锚点对应卡片名称,页面自动跳转至该卡片所在区域;'; var reqSpecModalContent = reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, React.createElement('div', { style: Object.assign({}, styles.modalBox, { maxWidth: 720 }), onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '需求说明'), React.createElement('div', { style: Object.assign({}, styles.modalBody, { maxHeight: '70vh', padding: '20px 24px', overflow: 'auto' }) }, React.createElement('div', { style: { whiteSpace: 'pre-wrap', fontSize: 13, lineHeight: 1.6, color: 'rgba(0,0,0,0.85)' } }, requirementContent)), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement(Button, { onClick: function() { setReqSpecOpen(false); } }, '关闭')))) : null; return React.createElement('div', { style: styles.page }, diff --git a/web端/车辆租赁合同/车辆租赁合同-新增车辆.jsx b/web端/车辆租赁合同/车辆租赁合同-新增车辆.jsx index 8a2df2f..70ee8c6 100644 --- a/web端/车辆租赁合同/车辆租赁合同-新增车辆.jsx +++ b/web端/车辆租赁合同/车辆租赁合同-新增车辆.jsx @@ -58,6 +58,10 @@ const Component = function() { var _newVehicleRows = useState([Object.assign({}, emptyNewRow)]); var newVehicleRows = _newVehicleRows[0]; var setNewVehicleRows = _newVehicleRows[1]; + var _newVehicleContractOriginals = useState([]); + var newVehicleContractOriginals = _newVehicleContractOriginals[0]; + var setNewVehicleContractOriginals = _newVehicleContractOriginals[1]; + var newVehicleContractInputRef = React.useRef(null); var _serviceModalRowIndex = useState(null); var serviceModalRowIndex = _serviceModalRowIndex[0]; var setServiceModalRowIndex = _serviceModalRowIndex[1]; @@ -86,6 +90,20 @@ const Component = function() { return next; }); }, []); + var copyNewVehicleRow = useCallback(function(index) { + setEdited(true); + var row = newVehicleRows[index]; + if (!row) return; + var serviceItemsCopy = (row.serviceItems || []).map(function(si) { return { project: si.project || '', fee: si.fee || '', effectiveDate: si.effectiveDate || '' }; }); + if (serviceItemsCopy.length === 0) serviceItemsCopy = [{ project: '', fee: '', effectiveDate: '' }]; + var newRow = { brand: row.brand || '', model: row.model || '', plateNo: '', vin: '', monthRent: row.monthRent || '', serviceItems: serviceItemsCopy, deposit: row.deposit || '', remark: row.remark || '' }; + setNewVehicleRows(function(prev) { + var next = prev.slice(); + next.splice(index + 1, 0, newRow); + return next; + }); + message.success('已复制该行(车牌号已清空)'); + }, [newVehicleRows]); var updateNewVehicleRow = useCallback(function(index, field, value) { setEdited(true); setNewVehicleRows(function(prev) { @@ -249,14 +267,13 @@ const Component = function() { { name: '租赁合同-原件.pdf', size: '1.2 MB', uploadTime: '2026-02-16 14:30' }, { name: '租赁合同-补充协议.pdf', size: '0.6 MB', uploadTime: '2026-02-16 14:35' } ]; - var stampedContractFiles = [ - { name: '盖章合同-租赁合同-盖章版.pdf', size: '1.2 MB', uploadTime: '2026-02-18 10:30' }, - { name: '盖章合同-补充协议-盖章版.pdf', size: '0.6 MB', uploadTime: '2026-02-18 10:35' } - ]; if (isThreePartyContract) { contractOriginalFiles = contractOriginalFiles.concat([{ name: '三方合同-原件.pdf', size: '0.8 MB', uploadTime: '2026-03-02 16:10' }]); - stampedContractFiles = stampedContractFiles.concat([{ name: '三方盖章合同-盖章版.pdf', size: '1.1 MB', uploadTime: '2026-03-03 09:50' }]); } + var _contractBasicOriginals = useState(contractOriginalFiles.slice()); + var contractBasicOriginals = _contractBasicOriginals[0]; + var setContractBasicOriginals = _contractBasicOriginals[1]; + var contractBasicInputRef = React.useRef(null); var addVehicleDate = '2026-03-15'; var mockContract = { projectName: '嘉兴氢能运输项目', contractCode: 'JXZL20260216YW101235A', contractType: '正式合同', effectiveDate: '2026-02-16', paymentMethod: '预付', mainVehicleModels: '型号A1、型号A2', endDate: '2027-02-16', paymentPeriod: '1个月', signingCompany: '嘉兴羚牛', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '嘉兴市南湖区科技大道1号', remarks: '' }; var mockAuthorized = [{ name: '张三', phone: '13800138001', idCard: '330102199001011234' }]; @@ -332,17 +349,29 @@ const Component = function() { React.createElement(FormItemReadOnly, { label: '交车区域', value: mockContract.deliveryRegion }), React.createElement('div', null, React.createElement('label', { style: styles.label }, '合同原件'), - React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { padding: '8px 12px' }) }, - contractOriginalFiles && contractOriginalFiles.length - ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } }, - contractOriginalFiles.map(function(f, i) { - return React.createElement('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } }, - React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); window.open('#', '_blank'); } }, f.name), - (f.size || f.uploadTime) ? React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size || '') + (f.size && f.uploadTime ? ' · ' : '') + (f.uploadTime || '')) : null - ); - }) - ) - : '—' + contractBasicOriginals && contractBasicOriginals.length > 0 + ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, + contractBasicOriginals.map(function(f, i) { + return React.createElement('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', padding: '8px 12px', backgroundColor: '#fafafa', borderRadius: 4, border: '1px solid #e8e8e8' } }, + React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); if (f.file && typeof URL !== 'undefined') { var u = URL.createObjectURL(f.file); window.open(u); } else { window.open('#', '_blank'); } } }, f.name), + (f.size || f.uploadTime) ? React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size || '') + (f.size && f.uploadTime ? ' · ' : '') + (f.uploadTime || '')) : null, + f.file ? React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { setContractBasicOriginals(function(prev) { var n = prev.slice(); n.splice(i, 1); return n; }); } }, '删除') : null + ); + }) + ) + : null, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } }, + React.createElement('input', { ref: contractBasicInputRef, type: 'file', style: { display: 'none' }, accept: '.doc,.docx,.pdf', onChange: function(e) { + var f = e.target.files && e.target.files[0]; + if (f) { + var sizeDisplay = f.size >= 1024 * 1024 ? (f.size / 1024 / 1024).toFixed(1) + ' MB' : (f.size / 1024).toFixed(1) + ' KB'; + var now = window.moment ? window.moment() : new Date(); + var uploadTimeStr = window.moment ? now.format('YYYY-MM-DD HH:mm') : now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0'); + setContractBasicOriginals(function(prev) { return prev.concat([{ name: f.name, file: f, size: sizeDisplay, uploadTime: uploadTimeStr }]); }); + } + e.target.value = ''; + } }), + React.createElement(Button, { type: 'default', onClick: function() { if (contractBasicInputRef.current) contractBasicInputRef.current.click(); } }, '上传附件') ) ) ), @@ -418,8 +447,8 @@ const Component = function() { { title: '服务费项目', key: 'serviceItems', width: 80, render: function(_, row, i) { return React.createElement(Button, { type: 'link', size: 'small', onClick: function() { openServiceModal(i); } }, '管理'); } }, { title: '服务费', key: 'serviceFee', width: 90, render: function(_, row, i) { return calcRowServiceFee(row) + ' 元'; } }, { title: '保证金', key: 'deposit', width: 100, render: function(_, row, i) { return React.createElement(Input, { placeholder: '0.00', value: row.deposit || '', onChange: function(e) { updateNewVehicleRow(i, 'deposit', e.target.value); }, addonAfter: '元' }); } }, - { title: '操作', key: 'action', width: 80, render: function(_, row, i) { return React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeNewVehicleRow(i); } }, '删除'); } }, - { title: '备注', key: 'remark', width: 120, render: function(_, row, i) { return React.createElement(Input, { placeholder: '选填', value: row.remark || '', onChange: function(e) { updateNewVehicleRow(i, 'remark', e.target.value); } }); } } + { title: '备注', key: 'remark', width: 120, render: function(_, row, i) { return React.createElement(Input, { placeholder: '选填', value: row.remark || '', onChange: function(e) { updateNewVehicleRow(i, 'remark', e.target.value); } }); } }, + { title: '操作', key: 'action', width: 100, render: function(_, row, i) { return React.createElement('span', { style: { display: 'inline-flex', gap: 4, alignItems: 'center' } }, React.createElement(Button, { type: 'link', size: 'small', onClick: function() { copyNewVehicleRow(i); } }, '复制'), React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeNewVehicleRow(i); } }, '删除')); } } ]; var newOrderSummaryEl = React.createElement('div', { style: styles.summaryList }, @@ -453,8 +482,41 @@ const Component = function() { ) ) : null; + var openNewVehicleContract = function(item) { + if (item && item.file && typeof URL !== 'undefined') { var url = URL.createObjectURL(item.file); window.open(url); } + }; + var newVehicleContractSection = React.createElement('div', { style: styles.formRow }, + React.createElement('div', { style: styles.formColFull }, + React.createElement('label', { style: styles.label }, '合同原件'), + newVehicleContractOriginals && newVehicleContractOriginals.length > 0 + ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, + newVehicleContractOriginals.map(function(f, i) { + return React.createElement('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', padding: '8px 12px', backgroundColor: '#f5f5f5', borderRadius: 4, border: '1px solid #d9d9d9' } }, + React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); openNewVehicleContract(f); } }, f.name), + (f.size || f.uploadTime) ? React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size || '') + (f.size && f.uploadTime ? ' · ' : '') + (f.uploadTime || '')) : null, + React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { setEdited(true); setNewVehicleContractOriginals(function(prev) { var n = prev.slice(); n.splice(i, 1); return n; }); } }, '删除') + ); + }) + ) + : null, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } }, + React.createElement('input', { ref: newVehicleContractInputRef, type: 'file', style: { display: 'none' }, accept: '.doc,.docx,.pdf', onChange: function(e) { + var f = e.target.files && e.target.files[0]; + if (f) { + setEdited(true); + var sizeDisplay = f.size >= 1024 * 1024 ? (f.size / 1024 / 1024).toFixed(1) + ' MB' : (f.size / 1024).toFixed(1) + ' KB'; + var now = window.moment ? window.moment() : new Date(); + var uploadTimeStr = window.moment ? now.format('YYYY-MM-DD HH:mm') : now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0'); + setNewVehicleContractOriginals(function(prev) { return prev.concat([{ name: f.name, file: f, size: sizeDisplay, uploadTime: uploadTimeStr }]); }); + } + e.target.value = ''; + } }), + React.createElement(Button, { type: 'default', onClick: function() { if (newVehicleContractInputRef.current) newVehicleContractInputRef.current.click(); } }, '上传附件') + ) + ) + ); var newVehicleCardContent = React.createElement('div', null, - React.createElement('div', { style: styles.sectionTitle }, '新增车辆信息'), + newVehicleContractSection, newOrderSummaryEl, React.createElement(Table, { rowKey: function(_, i) { return String(i); }, size: 'small', columns: newVehicleColumns, dataSource: newVehicleRows, pagination: false, scroll: { x: 1100 } }), React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addNewVehicleRow }, '添加一行') @@ -462,17 +524,6 @@ const Component = function() { var feeContent = React.createElement('div', null, React.createElement('div', { style: styles.formRow }, React.createElement(FormItemReadOnly, { label: '选择费用模板', value: mockFeeTemplate })), feeTemplateBody); var billingContent = React.createElement('div', null, React.createElement('div', { style: { padding: '12px 16px', border: '1px solid #e8e8e8', borderRadius: 4, backgroundColor: '#fafafa', fontSize: 14, color: '#333' } }, mockBillingMethod)); - var stampedAttachmentInner = stampedContractFiles && stampedContractFiles.length - ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 10 } }, - stampedContractFiles.map(function(f, i) { - return React.createElement('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', padding: '8px 12px', backgroundColor: '#f5f5f5', borderRadius: 4, border: '1px solid #d9d9d9' } }, - React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); window.open('#', '_blank'); } }, f.name), - React.createElement('span', { style: { color: '#999', fontSize: 12 } }, f.size + ' · ' + f.uploadTime) - ); - }) - ) - : React.createElement('div', { style: { color: '#999', fontSize: 13 } }, '暂无附件'); - var changeHistoryRaw = [ { changeTime: '2026-03-03 10:20', opType: '保存', operator: '张三', remark: '无' }, { changeTime: '2026-03-02 16:10', opType: '变更为三方合同', operator: '李四', remark: '增加丙方客户“客户名称杭州某某供应链有限公司”' }, @@ -508,7 +559,7 @@ const Component = function() { React.createElement('tbody', null, historyTableRows) ); - var requirementContent = '车辆租赁合同-新增车辆(2026年3月3日版本)\n「数字化资产ONE-OS运管平台」中的「车辆租赁合同」-「新增车辆」模块,在车辆租赁合同操作列点击「新增车辆」进行新增;\n1.面包屑:\n#业务管理-车辆租赁合同-新增车辆\n\n2.客户基本信息卡片:\n#显示已审批合同实际信息,不可修改,当客户信息产生变更时,对该条历史合同数据不作更新,合同变更为三方合同时不在原有客户基本信息做修改,而是增加三方客户基本信息卡片;\n2.1.客户名称:从该条合同自动反查;\n2.2.客户统一信用代码:从该条合同自动反查;\n2.3.客户地址:从该条合同自动反查;\n2.4.客户联系人:从该条合同自动反查;\n2.5.客户电话:从该条合同自动反查;\n2.6.客户电子邮箱:从该条合同自动反查;\n2.7.企业名称:从该条合同自动反查;\n2.8.企业电话:从该条合同自动反查;\n2.9.邮寄地址:从该条合同自动反查;\n2.10.开户银行:从该条合同自动反查;\n2.11.银行账号:从该条合同自动反查;\n2.12.纳税人识别号:从该条合同自动反查;\n2.13.业务部门:从该条合同自动反查;\n2.14.业务负责人:从该条合同自动反查;\n\n3.丙方客户基本信息卡片(当合同转三方合同时显示):\n#显示已审批合同丙方实际信息,不可修改;;\n3.1.客户名称:从该条合同自动反查;\n3.2.客户统一信用代码:从该条合同自动反查;\n3.3.客户地址:从该条合同自动反查;\n3.4.客户联系人:从该条合同自动反查;\n3.5.客户电话:从该条合同自动反查;\n3.6.客户电子邮箱:从该条合同自动反查;\n3.7.企业名称:从该条合同自动反查;\n3.8.企业电话:从该条合同自动反查;\n3.9.邮寄地址:从该条合同自动反查;\n3.10.开户银行:从该条合同自动反查;\n3.11.银行账号:从该条合同自动反查;\n3.12.纳税人识别号:从该条合同自动反查;\n3.13.业务部门:从该条合同自动反查;\n3.14.业务负责人:从该条合同自动反查;\n\n4.合同基本信息卡片:\n#显示合同基本信息,不可修改;\n4.1.项目名称:从该条合同自动反查;\n4.2.合同编码:从该条合同自动反查,在新增租赁合同点击提交审核时生成;\n 合同编码由:[城市简写][合同类型][签约时间][业务部门代码][顺序流水号][签署状态]组成;\n 4.2.1.地区简写:如上海为SH,嘉兴为JX;\n 4.2.2.合同类型:采购合同为CG、租赁合同为ZL、自营合同为ZY;\n 4.2.3.签约时间:显示合同签约时间,如20260216\n 4.2.4.业务部门代码:显示合同签约业务部门信息,如YW1代表业务1部,YW2代表业务2部;\n 4.2.5.顺序流水号:实施5位编号补零规则,如01235,代表是集团编号为1235的合同;\n 4.2.6.签署状态:A为正式合同,B为试用合同;\n 如编号为:JXZL20260216YW101235A,则代表嘉兴业务1部在2026年2月16日签署的租赁正式合同,在集团中编号为1235,也可以理解为第1235份合同;\n 4.2.7.如果该合同为续签合同,则自动在新合同编码后额外添加:(续签自:旧合同合同编码xxx);\n 4.2.8.如果该合同为转正式合同,则自动在新合同编码后额外添加:(转正式合同自:旧合同合同编码xxx);\n4.3.合同类型:从该条合同自动反查;\n4.4.生效日期:从该条合同自动反查;\n4.5.付款方式:从该条合同自动反查;\n4.6.主要车型:从该条合同自动反查;\n4.7.结束日期:从该条合同自动反查;\n 4.7.1.合同结束日期前30天将以消息提醒方式提醒(消息中心、工作台);\n 4.7.2.到达合同结束日期时,租赁账单将会立刻停止计算,作为最后一期账单;\n 4.7.3.续签合同/转正式合同将重新生成账单,不会对旧合同账单做任何继承处理;\n4.8.付款周期:从该条合同自动反查;\n4.9.签约公司:从该条合同自动反查;\n4.10.交车区域:从该条合同自动反查;\n4.11.交车地点:从该条合同自动反查;\n4.12.合同原件:从该条合同自动反查,显示「合同原件名称.格式」「文件大小」「上传时间」,可能会存在多个附件,显示为一列,如果转为三方合同,则会显示新附件,显示「三方合同原件名称.格式」「文件大小」「上传时间」;\n4.13.备注:从该条合同自动反查;\n 4.13.1.如果该合同为续签合同,则自动在已填备注信息上方额外添加:续签自:旧合同合同编码xxx;\n 4.13.2.如果该合同为转正式合同,则自动在已填备注信息上方额外添加:转正式合同自:旧合同合同编码xxx;\n\n5.被授权人信息卡片:\n#显示所有被授权人信息,不可修改,如要新增被授权人,需要在列表中点击添加被授权人进行处理;\n5.1.被授权人:从该条合同自动反查;\n5.2.被授权人联系电话:从该条合同自动反查;\n5.3.被授权人身份证:从该条合同自动反查;\n\n6.租赁订单信息卡片:\n#显示租赁合同对应车辆明细费用、氢费明细费用等相关信息;\n6.1.上方为租赁车辆总计数据,包括租赁车辆数、租金及服务费合计、保证金总额、氢气预付款金额等相关信息;\n 6.1.1.租赁车辆数:显示下方租赁订单信息包含多少辆车;\n 6.1.2.租金及服务费合计:显示下方租赁订单信息中车辆租金总额及服务费总额;\n 6.1.3.保证金总额:显示下方租赁订单信息中车辆保证金总额;\n 6.1.4.氢气预付款金额:显示氢气预付款金额,如客户选择自行承担氢费或羚牛承担氢费,则该处为0不计入氢气预付款金额;\n6.2.下方为列表,显示序号、品牌、型号、车牌号、车辆识别代码、车辆月租金(元)、服务费项目、服务费、保证金、备注;\n 6.2.1.序号:从该条合同自动反查;\n 6.2.2.品牌:从该条合同自动反查;\n 6.2.3.型号:从该条合同自动反查;\n 6.2.4.车牌号:从该条合同自动反查;\n 6.2.5.车辆识别代码:从该条合同自动反查;\n 6.2.6.车辆月租金:从该条合同自动反查;\n 6.2.7.服务费项目:点击查看按钮弹出卡片,卡片标题为:服务项目,下方列表显示服务项目、费用、生效时间;\n 6.2.7.1.服务项目:从该条合同自动反查;\n 6.2.7.2.费用:从该条合同自动反查;\n 6.2.7.3.生效时间:从该条合同自动反查;\n #在提车应收款中,车辆的交车日期和服务费生效日期可能会存在不同的情况,所以服务费需要单独以生效时间进行计算,例如:\n 交车后车辆从1月1日开始计费,付款周期为2个月,则提车应收款租金会计算到3月1日,但是服务费生效时间为1月30日,此情况下需要以3月1日-1月30日,计算出服务费具体收费天数为30天,然后根据:(服务费费用/30)* 服务费收费天数30)进行计算;\n 6.2.8.服务费:从该条合同自动反查;\n 6.2.9.保证金:从该条合同自动反查;\n 6.2.10.备注:从该条合同自动反查;\n6.3.氢费承担方:从该条合同自动反查;\n6.4.付款方式:从该条合同自动反查;\n6.5.氢气预付款:从该条合同自动反查;\n6.6.退还车氢气单价:从该条合同自动反查,该金额主要用于与客户约定还车时,与交车时氢气差值以此费用进行自动计算和结算;\n\n7.新增车辆信息卡片(用户每次为合同新增车辆时,都会生成一个新增车辆信息卡片):\n#显示租赁合同对应新增车辆的明细费用、氢费明细费用等相关信息;\n7.1.卡片标题显示为:新增车辆信息(YYYY-MM-DD)\n7.2.上方为租赁车辆总计数据,包括租赁车辆数、租金及服务费合计、保证金总额等相关信息;\n 7.2.1.租赁车辆数:显示下方租赁订单信息包含多少辆车;\n 7.2.2.租金及服务费合计:显示下方租赁订单信息中车辆租金总额及服务费总额;\n 7.2.3.保证金总额:显示下方租赁订单信息中车辆保证金总额;\n7.3.下方为列表,显示序号、品牌、型号、车牌号、车辆识别代码、车辆月租金(元)、服务费项目、服务费、保证金、操作、备注;\n 7.3.1.序号:自动按照条数生成,规则为1、2、3....以此类推;\n 7.3.2.品牌:必选项,选择器,从型号参数库中「品牌」字段拉取所有品牌;\n 7.3.3.型号:必选项,选择器,与品牌存在级联关系,未选择品牌则无法选择型号;\n 7.3.4.车牌号:选填项,选择器(支持从输入框输入车牌号关键字下拉匹配),可通过选择车牌号对品牌、型号进行反写;\n 7.3.5.车辆识别代码:输入框(禁用),显示该车辆对应车辆识别代码,根据所选车牌号从车辆表直接拉取进行反写;\n 7.3.6.车辆月租金:输入框,支持两位小数,用于输入该车辆月租金金额,输入框后缀为元,如还车时账单周期不满1个月,则按照:(车辆月租金/30)* 实际天数进行计算;\n 7.3.7.服务费项目:点击管理按钮弹出卡片,卡片标题为:服务项目,下方列表显示服务项目、费用、生效时间、操作;\n 7.3.7.1.服务项目:必选项,选择器(支持输入框输入服务项目关键字进行下拉匹配),选项包含:代处理费用、罚款、违章处理违约金、未参加安全培训、车辆出险、年检年审违约、停车费、设备损坏金(包含易损件)、清洗费、上门收车人工费、上门收车送车行驶费、上门收车基础服务费、保险上浮、保养费用、补办驾驶证、补办牌照、补办营运证、补办加氢证、借用备用钥匙、补配钥匙、租金、氢气费-客、退还车氢量差、能源费补缴、能源费退款、送车上门人工费、送车上门送车行驶费、送车上门基础服务费、保证金、氢气预付费、维修费用、ETC-客、ETC卡缺损费、ETC设备缺损费、电费-客、未结算保养费、未结算维修费、车损费、工具损坏或丢失费、证件费、广告损坏费、送车服务费、接车服务费、补办行驶证、超赔险、轮胎磨损费、无忧包、轮胎保、养护保、尾板;\n 7.3.7.2.费用:必填项,输入框,支持2位小数,输入框后缀为元;\n 7.3.7.3.生效时间:必选项,日期选择器,格式为YYYY-MM-DD;\n 7.3.7.4.操作:删除,点击删除直接删除该行数据;\n 7.3.7.5.新增一行数据:点击添加一行服务项目;\n #在提车应收款中,车辆的交车日期和服务费生效日期可能会存在不同的情况,所以服务费需要单独以生效时间进行计算,例如:\n 交车后车辆从1月1日开始计费,付款周期为2个月,则提车应收款租金会计算到3月1日,但是服务费生效时间为1月30日,此情况下需要以3月1日-1月30日,计算出服务费具体收费天数为30天,然后根据:(服务费费用/30)* 服务费收费天数30)进行计算;\n 7.3.8.服务费:自动根据添加的所有服务费项目计算总额,支持2位小数,格式为:xx.xx元;\n 7.3.9.保证金:必填项,输入框,支持2位小数,后缀为元,用于填写车辆需要支付的保证金金额,保证金为提车应收款一次性支付,还车时需要计入退还费用中;\n 7.3.10.备注:选填项,输入框,用于备注车辆复杂情况;\n 7.3.11.操作:删除,点击删除删除该行数据;\n 7.3.12.添加一行:点击后列表新增一行,用于填写一条新的车辆租金费用信息;\n\n8.其他费用信息卡片:\n#显示对应租赁费用模板证照补办费用、违约金费用、易损件费用、其他费用等信息;\n8.1.选择费用模板:必选项,从「租赁费用模板」中拉取,选择后自动将该费用模板所有环节费用显示在合同中;\n 8.1.1.证照补办费用:单独标题显示,内容为列表,列表中包括项目、收费标准、服务费,从该条合同自动反查;\n 8.1.2.违约金费用:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,从该条合同自动反查;\n 8.1.3.易损件信息:单独标题显示,内容为列表,列表中包含类别、损坏部位、配件、数量、费用明细,从该条合同自动反查;\n 8.1.4.其他费用信息:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,从该条合同自动反查;\n\n9.账单计算方式卡片:\n#显示实际结算方式;\n\n10.盖章合同附件:\n#显示财务审核完成后,由法务上传的盖章版合同文件,显示「盖章合同名称.格式」「文件大小」「上传时间」,可能会存在多个附件,显示为一列;如果转为三方合同,则会重新审批,法务上传显示新附件,显示「三方盖章合同名称.格式」「文件大小」「上传时间」\n\n11.合同变更历史记录:\n#显示合同变更历史,包括序号、变更时间、操作类型、操作人、原始记录、备注;\n11.1.序号:显示变更历史序号,按照变更时间倒序(从近到远)进行排序;\n11.2.变更时间:显示变更时间,格式为:YYYY-MM-DD HH:MM;\n11.3.操作类型:包括变更为三方合同、添加车辆、添加授权人、续签合同、撤回合同、终止合同、转正式合同、保存;\n11.4.操作人:显示对应操作类型操作人员;\n11.5.原始记录:显示查看变更前记录,点击打开新页面至查看原始合同快照;\n11.6.备注:备注改动内容,包括:\n 11.6.1.变更为三方合同时:增加丙方客户“客户名称xxxxxx”;\n 11.6.2.添加车辆时:添加车辆“车牌号xxx”、“车牌号xxx”、“车牌号xxx”,每辆车单独一行显示;\n 11.6.3.添加授权人时:添加授权人“授权人xxxx”、“授权人xxx”,每个授权人单独一行显示;\n 11.6.4.续签合同时:续签自”原合同编码xxxxxx“;\n 11.6.5.撤回合同时:主动撤回;\n 11.6.6.终止合同时:主动终止;\n 11.6.7.转正式合同时:转正式合同自“原合同编码xxxx”;\n 11.6.8.保存:无;\n\n12.最下方为提交并审核、保存、取消三个按钮;\n12.1.点击提交并审核,toast提示:租赁合同已提交审核。同时该租赁合同重新触发审核流程;\n12.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中,该条数据只能保存人自己查看并编辑,其他人无法操作;\n12.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回车辆租赁合同列表页;\n\n所有卡片支持收起/展开功能,通过点击卡片右侧收起/展开实现;并增加锚点功能,锚点固定于页面右上角,点击锚点对应卡片名称,页面自动跳转至该卡片所在区域;'; + var requirementContent = '车辆租赁合同-新增(2026年3月3日版本)\n「数字化资产ONE-OS运管平台」中的「车辆租赁合同」-「新增租赁合同」模块,点击车辆租赁合同右上角「新增」进行创建;\n1.面包屑:\n#业务管理-车辆租赁合同-新增合同\n\n2.客户基本信息卡片:\n#用于从客户列表中选择客户,并将该合同绑定到业务部门及业务负责人(绑定业务部门/业务负责人主要为了后期从部门/业务负责人维度进行数据统计);\n2.1.客户名称:必选项,选择器,支持从输入框内输入内容进行模糊搜索,从客户信息列表中选择对应客户(只显示已通过审核的客户);\n2.2.客户统一信用代码:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「信用代码」字段;\n2.3.客户地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户地址」字段;\n2.4.客户联系人:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户联系人」字段;\n2.5.客户电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电话」字段;\n2.6.客户电子邮箱:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「客户电子邮箱」字段;\n2.7.企业名称:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业名称」字段;\n2.8.企业电话:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「企业电话」字段;\n2.9.邮寄地址:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「邮寄地址」字段;\n2.10.开户银行:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「开户银行」字段;\n2.11.银行账号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「银行账号」字段;\n2.12.纳税人识别号:输入框(禁用状态),根据所选客户自动从客户信息列表中拉取对应客户-「纳税人识别号」字段;\n2.13.业务部门:必选项,选择器,从部门表中选择该租赁合同对应部门;\n2.14.业务负责人:必选项,选择器,从已选业务部门下拉取对应业务负责人,未选择业务部门时,业务负责人字段不可选;\n\n3.合同基本信息卡片:\n#用于定义租赁合同基本情况和付款方式;\n3.1.项目名称:必填项,输入框,用于定义该合同项目名称,默认提示信息"请输入项目名称";\n3.2.合同类型:必选项,选择器,合同类型分为「正式合同」「试用合同」;\n3.3.生效日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天,默认为点击新增日期;\n3.4.付款方式:必选项,付款方式分为「预付」「后付」两种;\n 3.4.1.如果选择预付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成就列入业务待办(工作台功能),同时以消息通知对应用户;\n 3.4.2.如果选择后付,以对应「付款方式」和「付款周期」规则,在每一期新账单生成时,将前一期账单列入业务待办(工作台功能),同时以消息通知对应用户;\n3.5.主要车型:输入框(禁用状态),根据租赁订单信息中所有所选车型,自动反写入输入框并以标签形式显示,支持多车型显示,标签显示:型号名称;\n3.6.结束日期:必选项,日期选择器,格式为YYYY-MM-DD,精确至天;\n 3.6.1.合同结束日期前30天将以消息提醒方式提醒(消息中心、工作台);\n 3.6.2.到达合同结束日期时,租赁账单将会立刻停止计算,作为最后一期账单;\n 3.6.3.续签合同/转正式合同将重新生成账单,不会对旧合同账单做任何继承处理;\n3.7.付款周期:必选项,选择器,支持1个月-12个月 12种付款周期,账单将以此周期和账单计算方式规则,从交车任务形成的交车单进行完整交车后,定时自动生成账单;\n3.8.签约公司:必选项,选择器,从组织机构表中获取所有根组织机构(如嘉兴羚牛、上海羚牛、广东羚牛等),默认显示新增用户当前机构,可手动修改,后期需要考虑从签约公司维度统计合同相关数据;\n3.9.交车区域:必选项,地区选择器,支持省-市2级,选择区域后,该任务生成交车任务时会自动推送至该区域负责运维人员;\n3.10.交车地点:必填项,输入框,支持自定义输入交车地点;\n3.11.合同原件:必填项,按钮,按钮文字为:上传附件,支持多个附件上传(doc/docx/pdf格式);\n3.12.备注:文本域,支持自定义输入备注信息;\n\n4.被授权人信息卡片:\n#用于定义租赁合同相关被授权人相关信息,被授权人在交车单完成时,需要选择被授权人,并通过被授权人手机短信,在E签宝进行签字确认;\n4.1.被授权人:必填项,输入框,用于输入被授权人信息;\n4.2.被授权人联系电话:必填项,输入框,用于输入被授权人联系电话,该电话后续需要接收E签宝签字链接;\n4.3.被授权人身份证:必填项,输入框,用于输入被授权人身份证信息;\n4.4.支持通过新增/删除一行的方式,创建或管理多个授权人,后续交车单完成时可从多个授权人中选择接收授权人;\n\n5.租赁订单信息卡片:\n#用于定义租赁合同对应车辆明细费用、氢费明细费用等相关信息;\n5.1.上方为租赁车辆总计数据,包括租赁车辆数、租金及服务费合计、保证金总额、氢气预付款金额等相关信息;\n 5.1.1.租赁车辆数:显示下方租赁订单信息包含多少辆车;\n 5.1.2.租金及服务费合计:显示下方租赁订单信息中车辆租金总额及服务费总额;\n 5.1.3.保证金总额:显示下方租赁订单信息中车辆保证金总额;\n 5.1.4.氢气预付款金额:显示氢气预付款金额,如客户选择自行承担氢费或羚牛承担氢费,则该处为0不计入氢气预付款金额;\n5.2.下方为列表,显示序号、品牌、型号、车牌号、车辆识别代码、车辆月租金(元)、服务费项目、服务费、保证金、备注,默认且至少显示一行空数据;\n 5.2.1.序号:自动按照条数生成,规则为1、2、3....以此类推;\n 5.2.2.品牌:必选项,选择器,从型号参数库中「品牌」字段拉取所有品牌;\n 5.2.3.型号:必选项,选择器,与品牌存在级联关系,未选择品牌则无法选择型号;\n 5.2.4.车牌号:选填项,选择器(支持从输入框输入车牌号关键字下拉匹配),可通过选择车牌号对品牌、型号进行反写;\n 5.2.5.车辆识别代码:输入框(禁用),显示该车辆对应车辆识别代码,根据所选车牌号从车辆表直接拉取进行反写;\n 5.2.6.车辆月租金:输入框,支持两位小数,用于输入该车辆月租金金额,输入框后缀为元,如还车时账单周期不满1个月,则按照:(车辆月租金/30)* 实际天数进行计算;\n 5.2.7.服务费项目:点击管理按钮弹出卡片,卡片标题为:服务项目,下方列表显示服务项目、费用、生效时间、操作;\n 5.2.7.1.服务项目:必选项,选择器(支持输入框输入服务项目关键字进行下拉匹配),选项包含:代处理费用、罚款、违章处理违约金、未参加安全培训、车辆出险、年检年审违约、停车费、设备损坏金(包含易损件)、清洗费、上门收车人工费、上门收车送车行驶费、上门收车基础服务费、保险上浮、保养费用、补办驾驶证、补办牌照、补办营运证、补办加氢证、借用备用钥匙、补配钥匙、租金、氢气费-客、退还车氢量差、能源费补缴、能源费退款、送车上门人工费、送车上门送车行驶费、送车上门基础服务费、保证金、氢气预付费、维修费用、ETC-客、ETC卡缺损费、ETC设备缺损费、电费-客、未结算保养费、未结算维修费、车损费、工具损坏或丢失费、证件费、广告损坏费、送车服务费、接车服务费、补办行驶证、超赔险、轮胎磨损费、无忧包、轮胎保、养护保、尾板;\n 5.2.7.2.费用:必填项,输入框,支持2位小数,输入框后缀为元;\n 5.2.7.3.生效时间:必选项,日期选择器,格式为YYYY-MM-DD;\n 5.2.7.4.操作:删除,点击删除直接删除该行数据;\n 5.2.7.5.新增一行数据:点击添加一行服务项目;\n #在提车应收款中,车辆的交车日期和服务费生效日期可能会存在不同的情况,所以服务费需要单独以生效时间进行计算,例如:\n 交车后车辆从1月1日开始计费,付款周期为2个月,则提车应收款租金会计算到3月1日,但是服务费生效时间为1月30日,此情况下需要以3月1日-1月30日,计算出服务费具体收费天数为30天,然后根据:(服务费费用/30)* 服务费收费天数30)进行计算;\n 5.2.8.服务费:自动根据添加的所有服务费项目计算总额,支持2位小数,格式为:xx.xx元;\n 5.2.9.保证金:必填项,输入框,支持2位小数,后缀为元,用于填写车辆需要支付的保证金金额,保证金为提车应收款一次性支付,还车时需要计入退还费用中;\n 5.2.10.备注:选填项,输入框,用于备注车辆复杂情况;\n 5.2.11.操作:删除,点击删除删除该行数据;\n 5.2.12.添加一行:点击后列表新增一行,用于填写一条新的车辆租金费用信息;\n5.3.氢费承担方:必选项,选择器,选项为:「我方」、「客户」,默认选择「客户」;\n 5.3.1.选择「我方」:不显示付款方式、氢气预付款;\n 5.3.2.选择「客户」:付款方式字段默认为预付,可手动修改;\n5.4.付款方式:必选项,选择器,选项为:「预付」、「月付款」、「自行结算」,默认为:「预付」;\n 5.4.1.预付:选择「预付」,需要填写:「氢气预付款」,氢气预付款指合同签署时客户就需预先付出的氢费款项,该部分款项会自动计入提车应收款中氢气预付款金额;\n 5.4.2.月付款:选择「月付款」,提车应收款中不进行收费,而是由业务人员按照实际情况,通过氢费账单功能生成对应氢费账单,单独与客户进行结算;\n 5.4.3.自行结算:选择「自行结算」,指合同签署后,所有氢气费用由客户自行承担;\n5.5.氢气预付款:选择「客户」「预付」时显示,必填项,输入框,支持2位小数,氢气预付款金额会计算入该合同交车应收款中,并计入5.1.4.氢气预付款金额中;\n5.6.退还车氢气单价:必填项,输入框,支持2位小数,后缀为元,不管氢费承担方和付款方式选择任何选项都需要进行维护,该金额主要用于与客户约定还车时,与交车时氢气差值以此费用进行自动计算和结算;\n\n6.其他费用信息卡片:\n#用于选择对应租赁费用模板,选择后展示证照补办费用、违约金费用、易损件费用、其他费用等信息,租赁费用模板管理功能位于「车辆租赁合同」列表左上角;\n6.1.选择费用模板:必选项,从「租赁费用模板」中拉取,选择后自动将该费用模板所有环节费用显示在合同中;\n 6.1.1.证照补办费用:单独标题显示,内容为列表,列表中包括项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.2.违约金费用:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n 6.1.3.易损件信息:单独标题显示,内容为列表,列表中包含类别、损坏部位、配件、数量、费用明细,选择费用模板后自动反显;\n 6.1.4.其他费用信息:单独标题显示,内容为列表,列表中包含项目、收费标准、服务费,选择费用模板后自动反显;\n\n7.账单计算方式卡片:\n#必选项,填充按钮组,默认为按自然月结算,可手动修改,用于定义租赁合同的账单计算方式,分为「按自然月结算」、「按付款周期天数结算」两种方式;\n7.1.按付款周期天数结算:账单按照合同基本信息卡片中每隔付款周期*30天形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款从交车任务配置的开始计费时间开始,根据60天收取车辆租金,此后每隔60天生成一期租赁账单;\n7.2.按自然月结算:账单按照第一个月计费开始日期到当月最后一天为第一期,之后按照付款周期所选月份间隔,从开始月份第一天到间隔月份最后一天的自然月方式形成一期账单;\n 例如付款周期为2个月,则交车任务交车成功时,提车应收款车辆租金需要收取≥2个月租金作为标准流程,<2个月租金作为非标流程;\n 租赁账单首期从交车任务配置的开始计费时间开始,如付款周期为2个月,则首期账单结束时间为第二个月最后一天,付款周期为3个月,则首期账单结束时间为第三个月最后一天,此后每一期按照实际自然月开始-结束形成账单,例如付款周期为2个月,则第二期账单从2月1日-3月31日,以此类推;\n\n8.最下方为提交并审核、保存、取消三个按钮;\n8.1.点击提交并审核,toast提示:租赁合同已提交审核。同时该租赁合同进入租赁合同审核列表中;\n8.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中,该条数据只能保存人自己查看并编辑,其他人无法操作;\n8.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回车辆租赁合同列表页;\n\n所有卡片支持收起/展开功能,通过点击卡片右侧收起/展开实现;并增加锚点功能,锚点固定于页面右上角,点击锚点对应卡片名称,页面自动跳转至该卡片所在区域;'; return React.createElement('div', { style: styles.page }, React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } }, @@ -525,8 +576,6 @@ const Component = function() { React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-new-vehicle'); } }, '新增车辆信息(' + addVehicleDate + ')'), React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-fee'); } }, '其他费用信息'), React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-billing'); } }, '账单计算方式'), - React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-attachment'); } }, '盖章合同附件'), - React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-history'); } }, '合同变更历史记录') ), React.createElement('div', { id: 'card-customer' }, React.createElement(CardBlock, { title: '客户基本信息', collapsed: cc1, setCollapsed: setCc1 }, customerFields)), isThreePartyContract ? React.createElement('div', { id: 'card-third-party', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '丙方客户基本信息', collapsed: cc1b, setCollapsed: setCc1b }, thirdPartyCustomerFields)) : null, @@ -536,8 +585,6 @@ const Component = function() { React.createElement('div', { id: 'card-new-vehicle', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '新增车辆信息(' + addVehicleDate + ')', collapsed: cc7, setCollapsed: setCc7 }, newVehicleCardContent)), React.createElement('div', { id: 'card-fee', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '其他费用信息', collapsed: cc5, setCollapsed: setCc5 }, feeContent)), React.createElement('div', { id: 'card-billing', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '账单计算方式', collapsed: cc6, setCollapsed: setCc6 }, billingContent)), - React.createElement('div', { id: 'card-attachment', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '盖章合同附件', collapsed: cc8, setCollapsed: setCc8 }, stampedAttachmentInner)), - React.createElement('div', { id: 'card-history', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同变更历史记录', collapsed: cc9, setCollapsed: setCc9 }, React.createElement('div', { style: { overflowX: 'auto' } }, historyTable))), React.createElement('div', { style: { height: 60 } }), serviceModalContent, reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, diff --git a/web端/车辆租赁合同/车辆租赁合同-续签合同.jsx b/web端/车辆租赁合同/车辆租赁合同-续签合同.jsx index 650eac6..fe67f74 100644 --- a/web端/车辆租赁合同/车辆租赁合同-续签合同.jsx +++ b/web端/车辆租赁合同/车辆租赁合同-续签合同.jsx @@ -394,6 +394,18 @@ const Component = function() { next.splice(index, 1); setRentalOrders(next.length ? next : [{ brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }]); }; + var copyRentalRow = function(index) { + setEdited(true); + var row = rentalOrders[index]; + if (!row) return; + var serviceItemsCopy = (row.serviceItems || []).map(function(si) { return { project: si.project || '', fee: si.fee || '', effectiveDate: si.effectiveDate || '' }; }); + if (serviceItemsCopy.length === 0) serviceItemsCopy = [{ project: '', fee: '', effectiveDate: '' }]; + var newRow = { brand: row.brand || '', model: row.model || '', plateNo: '', vin: '', monthRent: row.monthRent || '', serviceItems: serviceItemsCopy, deposit: row.deposit || '', remark: row.remark || '' }; + var next = rentalOrders.slice(0); + next.splice(index + 1, 0, newRow); + setRentalOrders(next); + if (typeof message !== 'undefined' && message.success) message.success('已复制该行(车牌号已清空)'); + }; var updateRentalOrder = function(index, field, value) { setEdited(true); var next = rentalOrders.slice(0); @@ -578,7 +590,6 @@ const Component = function() { var contractFormRow1 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '项目名称', required: true, error: formErrors.projectName }, React.createElement(Input, { placeholder: '请输入项目名称', value: projectName, onChange: function(e) { setEdited(true); setProjectName(e.target.value); }, status: formErrors.projectName ? 'error' : undefined, style: { width: '100%' } })), - React.createElement(FormItem, { label: '合同编码' }, React.createElement(Input, { value: contractCodeDisplay, disabled: true, style: { width: '100%' } })), React.createElement(FormItem, { label: '合同类型', required: true, error: formErrors.contractType }, React.createElement(Select, { placeholder: '请选择合同类型', style: { width: '100%' }, value: contractType || undefined, onChange: function(v) { setEdited(true); setContractType(v || ''); }, status: formErrors.contractType ? 'error' : undefined }, React.createElement(Option, { value: '正式合同' }, '正式合同'), React.createElement(Option, { value: '试用合同' }, '试用合同'))), React.createElement(FormItem, { label: '生效日期', required: true, error: formErrors.effectiveDate }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择生效日期', value: effectiveDate && window.moment ? window.moment(effectiveDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { setEdited(true); setEffectiveDate(dateStr || ''); }, status: formErrors.effectiveDate ? 'error' : undefined })), React.createElement(FormItem, { label: '付款方式', required: true, error: formErrors.paymentMethod }, React.createElement(Select, { placeholder: '请选择付款方式', style: { width: '100%' }, value: paymentMethod || undefined, onChange: function(v) { setEdited(true); setPaymentMethod(v || ''); }, status: formErrors.paymentMethod ? 'error' : undefined }, React.createElement(Option, { value: '预付' }, '预付'), React.createElement(Option, { value: '后付' }, '后付'))), @@ -586,35 +597,37 @@ const Component = function() { React.createElement(FormItem, { label: '结束日期', required: true, error: formErrors.endDate }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择结束日期', value: endDate && window.moment ? window.moment(endDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { setEdited(true); setEndDate(dateStr || ''); }, status: formErrors.endDate ? 'error' : undefined })), React.createElement(FormItem, { label: '付款周期', required: true, error: formErrors.paymentPeriod }, React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: paymentPeriod || undefined, onChange: function(v) { setEdited(true); setPaymentPeriod(v || ''); }, status: formErrors.paymentPeriod ? 'error' : undefined }, [1,2,3,4,5,6,7,8,9,10,11,12].map(function(n) { return React.createElement(Option, { key: n, value: String(n) }, n + '个月'); }))), React.createElement(FormItem, { label: '签约公司', required: true, error: formErrors.signingCompany }, React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: signingCompany || undefined, onChange: function(v) { setEdited(true); setSigningCompany(v || ''); }, status: formErrors.signingCompany ? 'error' : undefined }, orgList.map(function(o, i) { return React.createElement(Option, { key: i, value: o }, o); }))), - React.createElement('div', { style: styles.formCol }, - React.createElement(FormItem, { label: '交车区域', required: true, error: formErrors.deliveryRegion }, React.createElement('div', { id: 'delivery-region-wrap', style: { position: 'relative' } }, React.createElement(Input, { style: Object.assign({}, formErrors.deliveryRegion ? { borderColor: '#ff4d4f' } : {}, { cursor: 'pointer', caretColor: 'transparent', width: '100%' }), placeholder: '请选择省-市', value: deliveryRegionDisplay, readOnly: true, onClick: function() { setDeliveryRegionOpen(!deliveryRegionOpen); } }), deliveryRegionOpen ? React.createElement('div', { style: styles.regionCascader, onMouseDown: function() { deliveryRegionClickInsideRef.current = true; } }, React.createElement('div', { style: styles.regionCascaderCol }, regionList.map(function(r, i) { var isActive = r.province === deliveryProvince; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); setEdited(true); setDeliveryProvince(r.province); setDeliveryCity(''); } }, r.province); })), React.createElement('div', { style: styles.regionCascaderColLast }, deliveryProvince ? (regionList.find(function(x) { return x.province === deliveryProvince; }) || { cities: [] }).cities.map(function(c, i) { var isActive = c === deliveryCity; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); selectDeliveryRegion(deliveryProvince, c); } }, c); }) : React.createElement('div', { style: { padding: 16, color: '#999', fontSize: 13 } }, '请先选择省'))) : null)), - React.createElement(FormItem, { label: '合同原件', required: true, error: formErrors.contractOriginal }, - React.createElement('div', null, - React.createElement('div', { style: { color: '#999', fontSize: 12, marginBottom: 8 } }, '支持多个附件上传(doc/docx/pdf)'), - contractOriginalFiles && contractOriginalFiles.length - ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, - contractOriginalFiles.map(function(f, fi) { - return React.createElement('div', { key: fi, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', padding: '8px 12px', border: '1px solid #f0f0f0', borderRadius: 6, backgroundColor: '#fafafa' } }, - React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 2 } }, - React.createElement('a', { href: '#', style: { color: '#1890ff' }, onClick: function(e) { e.preventDefault(); openContractOriginalFile(fi); } }, f.name), - React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size ? f.size : '-') + ' · ' + (f.uploadTime ? f.uploadTime : '-')) - ), - React.createElement(Button, { type: 'link', danger: true, onClick: function() { removeContractOriginalFile(fi); } }, '删除') - ); - }) - ) - : null, - React.createElement('input', { ref: contractOriginalRef, type: 'file', multiple: true, accept: '.doc,.docx,.pdf', style: { display: 'none' }, onChange: function(e) { - var files = e.target.files ? Array.prototype.slice.call(e.target.files) : []; - addContractOriginalFiles(files); - e.target.value = ''; - } }), - React.createElement(Button, { type: 'default', style: { padding: '8px 16px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#fff', color: '#333', cursor: 'pointer', fontSize: 14 }, onClick: function() { if (contractOriginalRef.current) contractOriginalRef.current.click(); } }, '上传附件') - ) - ) - ), + React.createElement(FormItem, { label: '交车区域', required: true, error: formErrors.deliveryRegion }, React.createElement('div', { id: 'delivery-region-wrap', style: { position: 'relative' } }, React.createElement(Input, { style: Object.assign({}, formErrors.deliveryRegion ? { borderColor: '#ff4d4f' } : {}, { cursor: 'pointer', caretColor: 'transparent', width: '100%' }), placeholder: '请选择省-市', value: deliveryRegionDisplay, readOnly: true, onClick: function() { setDeliveryRegionOpen(!deliveryRegionOpen); } }), deliveryRegionOpen ? React.createElement('div', { style: styles.regionCascader, onMouseDown: function() { deliveryRegionClickInsideRef.current = true; } }, React.createElement('div', { style: styles.regionCascaderCol }, regionList.map(function(r, i) { var isActive = r.province === deliveryProvince; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); setEdited(true); setDeliveryProvince(r.province); setDeliveryCity(''); } }, r.province); })), React.createElement('div', { style: styles.regionCascaderColLast }, deliveryProvince ? (regionList.find(function(x) { return x.province === deliveryProvince; }) || { cities: [] }).cities.map(function(c, i) { var isActive = c === deliveryCity; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); selectDeliveryRegion(deliveryProvince, c); } }, c); }) : React.createElement('div', { style: { padding: 16, color: '#999', fontSize: 13 } }, '请先选择省'))) : null)) + ); + var contractFormRow4 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '交车地点', required: true, error: formErrors.deliveryLocation }, React.createElement(Input, { placeholder: '请输入交车地点', value: deliveryLocation, onChange: function(e) { setEdited(true); setDeliveryLocation(e.target.value); }, status: formErrors.deliveryLocation ? 'error' : undefined, style: { width: '100%' } })) ); + var contractFormRow5 = React.createElement('div', { style: styles.formRow }, + React.createElement(FormItem, { label: '合同原件', required: true, error: formErrors.contractOriginal }, + React.createElement('div', null, + React.createElement('div', { style: { color: '#999', fontSize: 12, marginBottom: 8 } }, '支持多个附件上传(doc/docx/pdf)'), + contractOriginalFiles && contractOriginalFiles.length + ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, + contractOriginalFiles.map(function(f, fi) { + return React.createElement('div', { key: fi, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', padding: '8px 12px', border: '1px solid #f0f0f0', borderRadius: 6, backgroundColor: '#fafafa' } }, + React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 2 } }, + React.createElement('a', { href: '#', style: { color: '#1890ff' }, onClick: function(e) { e.preventDefault(); openContractOriginalFile(fi); } }, f.name), + React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size ? f.size : '-') + ' · ' + (f.uploadTime ? f.uploadTime : '-')) + ), + React.createElement(Button, { type: 'link', danger: true, onClick: function() { removeContractOriginalFile(fi); } }, '删除') + ); + }) + ) + : null, + React.createElement('input', { ref: contractOriginalRef, type: 'file', multiple: true, accept: '.doc,.docx,.pdf', style: { display: 'none' }, onChange: function(e) { + var files = e.target.files ? Array.prototype.slice.call(e.target.files) : []; + addContractOriginalFiles(files); + e.target.value = ''; + } }), + React.createElement(Button, { type: 'default', style: { padding: '8px 16px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#fff', color: '#333', cursor: 'pointer', fontSize: 14 }, onClick: function() { if (contractOriginalRef.current) contractOriginalRef.current.click(); } }, '上传附件') + ) + ) + ); var contractFormRow2 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '备注', fullWidth: true }, React.createElement(Input.TextArea, { placeholder: '请输入备注信息', value: remarks, onChange: function(e) { setEdited(true); setRemarks(e.target.value); }, style: styles.textarea, rows: 4 }))); var authorizedContent = React.createElement('div', null, @@ -649,7 +662,7 @@ const Component = function() { React.createElement('td', { style: styles.rentalTdCenter }, calcRowServiceFee(row) + ' 元'), React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: { display: 'flex', alignItems: 'center' } }, React.createElement(Input, { placeholder: '0.00', value: row.deposit || '', onChange: function(e) { updateRentalOrder(idx, 'deposit', e.target.value); }, style: styles.rentalInput }), React.createElement('span', { style: { marginLeft: 4, whiteSpace: 'nowrap' } }, '元'))), React.createElement('td', { style: styles.rentalTd }, React.createElement(Input, { placeholder: '备注', value: row.remark || '', onChange: function(e) { updateRentalOrder(idx, 'remark', e.target.value); }, style: Object.assign({}, styles.rentalInput, { width: '100%' }) })), - React.createElement('td', { style: styles.rentalTdCenter }, React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeRentalRow(idx); } }, '删除')) + React.createElement('td', { style: styles.rentalTdCenter }, React.createElement('div', { style: { display: 'inline-flex', gap: 4, alignItems: 'center' } }, React.createElement(Button, { type: 'link', size: 'small', onClick: function() { copyRentalRow(idx); } }, '复制'), React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeRentalRow(idx); } }, '删除'))) ); }); @@ -671,7 +684,7 @@ const Component = function() { var rentalTh8 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 90, verticalAlign: 'middle' }) }, '服务费'); var rentalTh9 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 100 }) }, reqStar, '保证金'); var rentalTh10 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 80 }) }, '备注'); - var rentalTh11 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 60, verticalAlign: 'middle' }) }, '操作'); + var rentalTh11 = React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 90, verticalAlign: 'middle' }) }, '操作'); var rentalTableThead = React.createElement('thead', null, React.createElement('tr', null, rentalTh1, rentalTh2, rentalTh3, rentalTh4, rentalTh5, rentalTh6, rentalTh7, rentalTh8, rentalTh9, rentalTh10, rentalTh11)); var rentalTableTbody = React.createElement('tbody', null, rentalTableBody); var rentalTableEl = React.createElement('table', { style: styles.rentalTable }, rentalTableThead, rentalTableTbody); @@ -758,7 +771,7 @@ const Component = function() { React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-billing'); } }, '账单计算方式') ), React.createElement('div', { id: 'card-customer' }, React.createElement(CardBlock, { id: 'card-customer', title: '客户基本信息', collapsed: cc1, setCollapsed: setCc1 }, customerFields)), - React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow2))), + React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow4, contractFormRow5, contractFormRow2))), React.createElement('div', { id: 'card-authorized', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '被授权人信息', collapsed: cc3, setCollapsed: setCc3 }, authorizedContent)), React.createElement('div', { id: 'card-rental', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '租赁订单信息', collapsed: cc4, setCollapsed: setCc4 }, rentalContent)), React.createElement('div', { id: 'card-fee', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '其他费用信息', collapsed: cc5, setCollapsed: setCc5 }, feeContent)), diff --git a/web端/车辆租赁合同/车辆租赁合同-转正式合同.jsx b/web端/车辆租赁合同/车辆租赁合同-转正式合同.jsx index 1bb1fea..967913f 100644 --- a/web端/车辆租赁合同/车辆租赁合同-转正式合同.jsx +++ b/web端/车辆租赁合同/车辆租赁合同-转正式合同.jsx @@ -569,7 +569,6 @@ const Component = function() { var contractFormRow1 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '项目名称', required: true, error: formErrors.projectName }, React.createElement(Input, { placeholder: '请输入项目名称', value: projectName, onChange: function(e) { setEdited(true); setProjectName(e.target.value); }, status: formErrors.projectName ? 'error' : undefined, style: { width: '100%' } })), - React.createElement(FormItem, { label: '合同编码' }, React.createElement(Input, { value: contractCodeDisplay, disabled: true, style: { width: '100%' } })), React.createElement(FormItem, { label: '合同类型', required: true }, React.createElement(Select, { placeholder: '请选择合同类型', style: { width: '100%' }, value: '正式合同', disabled: true }, React.createElement(Option, { value: '正式合同' }, '正式合同'))), React.createElement(FormItem, { label: '生效日期', required: true, error: formErrors.effectiveDate }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择生效日期', value: effectiveDate && window.moment ? window.moment(effectiveDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { setEdited(true); setEffectiveDate(dateStr || ''); }, status: formErrors.effectiveDate ? 'error' : undefined })), React.createElement(FormItem, { label: '付款方式', required: true, error: formErrors.paymentMethod }, React.createElement(Select, { placeholder: '请选择付款方式', style: { width: '100%' }, value: paymentMethod || undefined, onChange: function(v) { setEdited(true); setPaymentMethod(v || ''); }, status: formErrors.paymentMethod ? 'error' : undefined }, React.createElement(Option, { value: '预付' }, '预付'), React.createElement(Option, { value: '后付' }, '后付'))), @@ -577,35 +576,37 @@ const Component = function() { React.createElement(FormItem, { label: '结束日期', required: true, error: formErrors.endDate }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择结束日期', value: endDate && window.moment ? window.moment(endDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { setEdited(true); setEndDate(dateStr || ''); }, status: formErrors.endDate ? 'error' : undefined })), React.createElement(FormItem, { label: '付款周期', required: true, error: formErrors.paymentPeriod }, React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: paymentPeriod || undefined, onChange: function(v) { setEdited(true); setPaymentPeriod(v || ''); }, status: formErrors.paymentPeriod ? 'error' : undefined }, [1,2,3,4,5,6,7,8,9,10,11,12].map(function(n) { return React.createElement(Option, { key: n, value: String(n) }, n + '个月'); }))), React.createElement(FormItem, { label: '签约公司', required: true, error: formErrors.signingCompany }, React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: signingCompany || undefined, onChange: function(v) { setEdited(true); setSigningCompany(v || ''); }, status: formErrors.signingCompany ? 'error' : undefined }, orgList.map(function(o, i) { return React.createElement(Option, { key: i, value: o }, o); }))), - React.createElement('div', { style: styles.formCol }, - React.createElement(FormItem, { label: '交车区域', required: true, error: formErrors.deliveryRegion }, React.createElement('div', { id: 'delivery-region-wrap', style: { position: 'relative' } }, React.createElement(Input, { style: Object.assign({}, formErrors.deliveryRegion ? { borderColor: '#ff4d4f' } : {}, { cursor: 'pointer', caretColor: 'transparent', width: '100%' }), placeholder: '请选择省-市', value: deliveryRegionDisplay, readOnly: true, onClick: function() { setDeliveryRegionOpen(!deliveryRegionOpen); } }), deliveryRegionOpen ? React.createElement('div', { style: styles.regionCascader, onMouseDown: function() { deliveryRegionClickInsideRef.current = true; } }, React.createElement('div', { style: styles.regionCascaderCol }, regionList.map(function(r, i) { var isActive = r.province === deliveryProvince; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); setEdited(true); setDeliveryProvince(r.province); setDeliveryCity(''); } }, r.province); })), React.createElement('div', { style: styles.regionCascaderColLast }, deliveryProvince ? (regionList.find(function(x) { return x.province === deliveryProvince; }) || { cities: [] }).cities.map(function(c, i) { var isActive = c === deliveryCity; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); selectDeliveryRegion(deliveryProvince, c); } }, c); }) : React.createElement('div', { style: { padding: 16, color: '#999', fontSize: 13 } }, '请先选择省'))) : null)), - React.createElement(FormItem, { label: '合同原件', required: true, error: formErrors.contractOriginal }, - React.createElement('div', null, - React.createElement('div', { style: { color: '#999', fontSize: 12, marginBottom: 8 } }, '从原合同自动反写,支持多个附件上传(doc/docx/pdf)'), - contractOriginalFiles && contractOriginalFiles.length - ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, - contractOriginalFiles.map(function(f, fi) { - return React.createElement('div', { key: fi, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', padding: '8px 12px', border: '1px solid #f0f0f0', borderRadius: 6, backgroundColor: '#fafafa' } }, - React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 2 } }, - React.createElement('a', { href: '#', style: { color: '#1890ff' }, onClick: function(e) { e.preventDefault(); openContractOriginalFile(fi); } }, f.name), - React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size ? f.size : '—') + ' · ' + (f.uploadTime ? f.uploadTime : '—')) - ), - f.isOriginal ? null : React.createElement(Button, { type: 'link', danger: true, onClick: function() { removeContractOriginalFile(fi); } }, '删除') - ); - }) - ) - : null, - React.createElement('input', { ref: contractOriginalRef, type: 'file', multiple: true, accept: '.doc,.docx,.pdf', style: { display: 'none' }, onChange: function(e) { - var files = e.target.files ? Array.prototype.slice.call(e.target.files) : []; - addContractOriginalFiles(files); - e.target.value = ''; - } }), - React.createElement(Button, { type: 'default', style: { padding: '8px 16px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#fff', color: '#333', cursor: 'pointer', fontSize: 14 }, onClick: function() { if (contractOriginalRef.current) contractOriginalRef.current.click(); } }, '上传附件') - ) - ) - ), + React.createElement(FormItem, { label: '交车区域', required: true, error: formErrors.deliveryRegion }, React.createElement('div', { id: 'delivery-region-wrap', style: { position: 'relative' } }, React.createElement(Input, { style: Object.assign({}, formErrors.deliveryRegion ? { borderColor: '#ff4d4f' } : {}, { cursor: 'pointer', caretColor: 'transparent', width: '100%' }), placeholder: '请选择省-市', value: deliveryRegionDisplay, readOnly: true, onClick: function() { setDeliveryRegionOpen(!deliveryRegionOpen); } }), deliveryRegionOpen ? React.createElement('div', { style: styles.regionCascader, onMouseDown: function() { deliveryRegionClickInsideRef.current = true; } }, React.createElement('div', { style: styles.regionCascaderCol }, regionList.map(function(r, i) { var isActive = r.province === deliveryProvince; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); setEdited(true); setDeliveryProvince(r.province); setDeliveryCity(''); } }, r.province); })), React.createElement('div', { style: styles.regionCascaderColLast }, deliveryProvince ? (regionList.find(function(x) { return x.province === deliveryProvince; }) || { cities: [] }).cities.map(function(c, i) { var isActive = c === deliveryCity; return React.createElement('div', { key: i, style: Object.assign({}, styles.regionCascaderItem, isActive ? { backgroundColor: '#e6f7ff', color: '#1890ff' } : {}), onMouseEnter: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function(e) { if (!isActive) e.currentTarget.style.backgroundColor = 'transparent'; }, onMouseDown: function(e) { e.preventDefault(); selectDeliveryRegion(deliveryProvince, c); } }, c); }) : React.createElement('div', { style: { padding: 16, color: '#999', fontSize: 13 } }, '请先选择省'))) : null)) + ); + var contractFormRow4 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '交车地点', required: true, error: formErrors.deliveryLocation }, React.createElement(Input, { placeholder: '请输入交车地点', value: deliveryLocation, onChange: function(e) { setEdited(true); setDeliveryLocation(e.target.value); }, status: formErrors.deliveryLocation ? 'error' : undefined, style: { width: '100%' } })) ); + var contractFormRow5 = React.createElement('div', { style: styles.formRow }, + React.createElement(FormItem, { label: '合同原件', required: true, error: formErrors.contractOriginal }, + React.createElement('div', null, + React.createElement('div', { style: { color: '#999', fontSize: 12, marginBottom: 8 } }, '从原合同自动反写,支持多个附件上传(doc/docx/pdf)'), + contractOriginalFiles && contractOriginalFiles.length + ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 12 } }, + contractOriginalFiles.map(function(f, fi) { + return React.createElement('div', { key: fi, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', padding: '8px 12px', border: '1px solid #f0f0f0', borderRadius: 6, backgroundColor: '#fafafa' } }, + React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 2 } }, + React.createElement('a', { href: '#', style: { color: '#1890ff' }, onClick: function(e) { e.preventDefault(); openContractOriginalFile(fi); } }, f.name), + React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (f.size ? f.size : '—') + ' · ' + (f.uploadTime ? f.uploadTime : '—')) + ), + f.isOriginal ? null : React.createElement(Button, { type: 'link', danger: true, onClick: function() { removeContractOriginalFile(fi); } }, '删除') + ); + }) + ) + : null, + React.createElement('input', { ref: contractOriginalRef, type: 'file', multiple: true, accept: '.doc,.docx,.pdf', style: { display: 'none' }, onChange: function(e) { + var files = e.target.files ? Array.prototype.slice.call(e.target.files) : []; + addContractOriginalFiles(files); + e.target.value = ''; + } }), + React.createElement(Button, { type: 'default', style: { padding: '8px 16px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#fff', color: '#333', cursor: 'pointer', fontSize: 14 }, onClick: function() { if (contractOriginalRef.current) contractOriginalRef.current.click(); } }, '上传附件') + ) + ) + ); var contractFormRow2 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItem, { label: '备注', fullWidth: true }, React.createElement(Input.TextArea, { placeholder: '请输入备注信息', value: remarks, onChange: function(e) { setEdited(true); setRemarks(e.target.value); }, style: styles.textarea, rows: 4 }))); var authorizedContent = React.createElement('div', null, @@ -841,7 +842,7 @@ const Component = function() { React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-billing'); } }, '账单计算方式') ), React.createElement('div', { id: 'card-customer' }, React.createElement(CardBlock, { id: 'card-customer', title: '客户基本信息', collapsed: cc1, setCollapsed: setCc1 }, customerFields)), - React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow2))), + React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow4, contractFormRow5, contractFormRow2))), React.createElement('div', { id: 'card-authorized', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '被授权人信息', collapsed: cc3, setCollapsed: setCc3 }, authorizedContent)), React.createElement('div', { id: 'card-rental', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '租赁订单信息', collapsed: cc4, setCollapsed: setCc4 }, rentalContent)), React.createElement('div', { id: 'card-fee', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '其他费用信息', collapsed: cc5, setCollapsed: setCc5 }, feeContent)), diff --git a/web端/车辆租赁合同/车辆租赁合同.jsx b/web端/车辆租赁合同/车辆租赁合同.jsx index d446de9..eafcf1d 100644 --- a/web端/车辆租赁合同/车辆租赁合同.jsx +++ b/web端/车辆租赁合同/车辆租赁合同.jsx @@ -51,6 +51,7 @@ const Component = function() { }); var _vehiclePopoverRecord = useState(null); + var _deliveredPopoverRecord = useState(null); var _authorizedModalVisible = useState(false); var _authorizedModalRecord = useState(null); var _authorizedList = useState([{ name: '', phone: '', idCard: '' }]); @@ -140,8 +141,8 @@ const Component = function() { projectName: '嘉兴氢能示范项目', vehicleCount: 2, vehicles: [ - { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '浙A12345', actualDelivery: '2025-01-10 09:00' }, - { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '-', actualDelivery: '2025-01-12 14:30' } + { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '浙A12345', actualDelivery: '2025-01-10 09:00', deliveryPerson: '张运维' }, + { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '-', actualDelivery: '2025-01-12 14:30', deliveryPerson: '李运维' } ], approvalStatus: '未提交', contractStatus: '草稿', @@ -166,7 +167,7 @@ const Component = function() { projectName: '上海物流租赁项目', vehicleCount: 1, vehicles: [ - { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C1', plateNo: '沪D66666', actualDelivery: '2025-02-01 11:00' } + { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C1', plateNo: '沪D66666', actualDelivery: '2025-02-01 11:00', deliveryPerson: '王运维' } ], approvalStatus: '未提交', contractStatus: '草稿', @@ -191,7 +192,7 @@ const Component = function() { projectName: '杭州城配租赁项目', vehicleCount: 1, vehicles: [ - { vehicleType: '4.5吨货车-轻型厢式货车', brand: '品牌A', model: '型号A2', plateNo: '浙B20002', actualDelivery: '2025-02-15 08:30' } + { vehicleType: '4.5吨货车-轻型厢式货车', brand: '品牌A', model: '型号A2', plateNo: '浙B20002', actualDelivery: '2025-02-15 08:30', deliveryPerson: '赵运维' } ], approvalStatus: '待审批', contractStatus: '已提交审批', @@ -216,8 +217,8 @@ const Component = function() { projectName: '宁波冷链运输项目', vehicleCount: 2, vehicles: [ - { vehicleType: '18吨双飞翼货车-重型厢式货车', brand: '品牌B', model: '型号B2', plateNo: '-', actualDelivery: '2025-02-16 10:00' }, - { vehicleType: '49吨牵引车头-重型半挂牵引车', brand: '品牌D', model: '型号D1', plateNo: '浙C30003', actualDelivery: '2025-02-18 14:00' } + { vehicleType: '18吨双飞翼货车-重型厢式货车', brand: '品牌B', model: '型号B2', plateNo: '-', actualDelivery: '2025-02-16 10:00', deliveryPerson: '钱运维' }, + { vehicleType: '49吨牵引车头-重型半挂牵引车', brand: '品牌D', model: '型号D1', plateNo: '浙C30003', actualDelivery: '2025-02-18 14:00', deliveryPerson: '孙运维' } ], approvalStatus: '审批中', contractStatus: '已提交审批', @@ -242,7 +243,7 @@ const Component = function() { projectName: '苏州城配试点项目', vehicleCount: 1, vehicles: [ - { vehicleType: '重型平板半挂车-重型平板半挂车', brand: '品牌D', model: '型号D2', plateNo: '苏E50005', actualDelivery: '2025-02-20 09:00' } + { vehicleType: '重型平板半挂车-重型平板半挂车', brand: '品牌D', model: '型号D2', plateNo: '苏E50005', actualDelivery: '2025-02-20 09:00', deliveryPerson: '周运维' } ], approvalStatus: '审批中', contractStatus: '变更', @@ -267,9 +268,9 @@ const Component = function() { projectName: '南京氢能示范项目', vehicleCount: 3, vehicles: [ - { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '苏A60006', actualDelivery: '2025-01-20 08:00' }, - { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '苏A60007', actualDelivery: '2025-01-21 10:00' }, - { vehicleType: '35吨牵引车头-重型半挂牵引车', brand: '品牌D', model: '型号D1', plateNo: '苏A60008', actualDelivery: '2025-01-22 14:00' } + { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '苏A60006', actualDelivery: '2025-01-20 08:00', deliveryPerson: '吴运维' }, + { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '苏A60007', actualDelivery: '2025-01-21 10:00', deliveryPerson: '郑运维' }, + { vehicleType: '35吨牵引车头-重型半挂牵引车', brand: '品牌D', model: '型号D1', plateNo: '苏A60008', actualDelivery: '2025-01-22 14:00', deliveryPerson: '冯运维' } ], approvalStatus: '审批通过', contractStatus: '合同进行中', @@ -294,7 +295,7 @@ const Component = function() { projectName: '无锡试用租赁项目', vehicleCount: 1, vehicles: [ - { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C2', plateNo: '苏B70007', actualDelivery: '2025-02-01 09:30' } + { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C2', plateNo: '苏B70007', actualDelivery: '2025-02-01 09:30', deliveryPerson: '陈运维' } ], approvalStatus: '审批通过', contractStatus: '合同进行中', @@ -345,8 +346,8 @@ const Component = function() { projectName: '南通去年到期项目', vehicleCount: 2, vehicles: [ - { vehicleType: '18吨双飞翼货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '苏F90009', actualDelivery: '2024-03-01 09:00' }, - { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '苏F90010', actualDelivery: '2024-03-02 10:00' } + { vehicleType: '18吨双飞翼货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '苏F90009', actualDelivery: '2024-03-01 09:00', deliveryPerson: '褚运维' }, + { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '苏F90010', actualDelivery: '2024-03-02 10:00', deliveryPerson: '卫运维' } ], approvalStatus: '审批通过', contractStatus: '到期合同', @@ -371,7 +372,7 @@ const Component = function() { projectName: '镇江到期合同项目', vehicleCount: 1, vehicles: [ - { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C1', plateNo: '苏L00100', actualDelivery: '2024-06-01 11:00' } + { vehicleType: '公务用车/小客车-小型普通客车', brand: '品牌C', model: '型号C1', plateNo: '苏L00100', actualDelivery: '2024-06-01 11:00', deliveryPerson: '蒋运维' } ], approvalStatus: '审批通过', contractStatus: '已结束', @@ -602,12 +603,21 @@ const Component = function() { var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; var tableSingleLineStyle = '.contract-list-table .ant-table-thead th,.contract-list-table .ant-table-tbody td{white-space:nowrap;}'; - var vehicleColumns = [ + // 租赁车辆数气泡:不含实际交车日期 + var vehicleColumnsRental = [ + { title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 180 }, + { title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 }, + { title: '型号', dataIndex: 'model', key: 'model', width: 100 }, + { title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 } + ]; + // 已交车辆数气泡:含实际交车日期,后方增加交车人 + var vehicleColumnsDelivered = [ { title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 180 }, { title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 }, { title: '型号', dataIndex: 'model', key: 'model', width: 100 }, { title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 }, - { title: '实际交车日期', dataIndex: 'actualDelivery', key: 'actualDelivery', width: 140 } + { title: '实际交车日期', dataIndex: 'actualDelivery', key: 'actualDelivery', width: 140 }, + { title: '交车人', dataIndex: 'deliveryPerson', key: 'deliveryPerson', width: 100 } ]; function getMoreMenuItems(record) { @@ -681,19 +691,19 @@ const Component = function() { { title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 140, fixed: 'left' }, { title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, fixed: 'left' }, { - title: '车辆数', + title: '租赁车辆数', key: 'vehicleCount', - width: 90, + width: 100, render: function(_, record) { var open = _vehiclePopoverRecord[0] && _vehiclePopoverRecord[0].id === record.id; var content = React.createElement('div', { style: { padding: 8 } }, React.createElement(Table, { size: 'small', rowKey: function(r, i) { return String(i); }, - columns: vehicleColumns, + columns: vehicleColumnsRental, dataSource: record.vehicles || [], pagination: false, - scroll: { x: 600 } + scroll: { x: 460 } }) ); return React.createElement( @@ -712,6 +722,43 @@ const Component = function() { ); } }, + { + title: '已交车辆数', + key: 'deliveredCount', + width: 100, + render: function(_, record) { + var deliveredVehicles = (record.vehicles || []).filter(function(v) { + var d = v.actualDelivery; + return d && String(d).trim() && d !== '-'; + }); + var deliveredCount = deliveredVehicles.length; + var open = _deliveredPopoverRecord[0] && _deliveredPopoverRecord[0].id === record.id; + var content = React.createElement('div', { style: { padding: 8 } }, + React.createElement(Table, { + size: 'small', + rowKey: function(r, i) { return String(i); }, + columns: vehicleColumnsDelivered, + dataSource: deliveredVehicles, + pagination: false, + scroll: { x: 700 } + }) + ); + return React.createElement( + Popover, + { + content: content, + title: '已交车列表', + open: open, + onOpenChange: function(visible) { + if (!visible) _deliveredPopoverRecord[1](null); + else _deliveredPopoverRecord[1](record); + }, + trigger: 'click' + }, + React.createElement('a', { style: { cursor: 'pointer', color: '#1890ff', fontWeight: 500 } }, deliveredCount) + ); + } + }, { title: '审批状态', dataIndex: 'approvalStatus', key: 'approvalStatus', width: 100 }, { title: '合同状态', dataIndex: 'contractStatus', key: 'contractStatus', width: 110 }, { title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 140 }, @@ -1028,10 +1075,11 @@ const Component = function() { React.createElement('div', { style: reqItemStyle }, '2.1.10.创建人:选择器,支持全选或多选,拉取所有业务相关部门下所有用户姓名;'), React.createElement('div', { style: reqItemStyle }, '2.1.11.合同结束日期:日期选择器,支持单输入框内双日历选择开始-结束时间;'), React.createElement('div', { style: reqSectionStyle }, '3.列表:'), - React.createElement('div', { style: reqSubStyle }, '3.1.列表展示所有租赁合同信息,字段依次为:合同编码、项目名称、车辆数、审批状态、合同状态、客户名称、签约公司、业务部门、业务负责人、合同类型、合同结束日期、客户联系人、联系电话、创建人、创建时间、更新人、最后更新时间、备注、操作;列表右上角为新增、导出;'), + React.createElement('div', { style: reqSubStyle }, '3.1.列表展示所有租赁合同信息,字段依次为:合同编码、项目名称、租赁车辆数、已交车辆数、审批状态、合同状态、客户名称、签约公司、业务部门、业务负责人、合同类型、合同结束日期、客户联系人、联系电话、创建人、创建时间、更新人、最后更新时间、备注、操作;列表右上角为新增、导出;'), React.createElement('div', { style: reqItemStyle }, '3.1.1.合同编码:显示租赁合同对应合同编码;'), React.createElement('div', { style: reqItemStyle }, '3.1.2.项目名称:显示租赁合同对应项目名称;'), - React.createElement('div', { style: reqItemStyle }, '3.1.3.车辆数:显示车辆数,点击车辆数,显示气泡卡片,卡片中列表显示:车辆类型、品牌、型号、车牌号、实际交车日期;'), + React.createElement('div', { style: reqItemStyle }, '3.1.3.租赁车辆数:显示租赁车辆数,点击显示气泡卡片,卡片中列表显示:车辆类型、品牌、型号、车牌号、实际交车日期;'), + React.createElement('div', { style: reqItemStyle }, '3.1.4.已交车辆数:显示已交车辆数,样式与交互同租赁车辆数,点击显示气泡卡片,卡片中显示已交车列表(同租赁车辆数列表结构);'), React.createElement('div', { style: reqSubItemStyle }, '3.1.3.1.车辆类型:4.5吨冷链车-轻型厢式货车、18吨双飞翼货车-重型厢式货车、49吨牵引车头-重型半挂牵引车、4.5吨货车-轻型厢式货车、18吨厢式货车-重型厢式货车、重型集装箱半挂车-重型集装箱半挂车、公务用车/小客车-小型普通客车、35吨牵引车头-重型半挂牵引车、重型平板半挂车-重型平板半挂车;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.3.2.品牌:显示租赁合同中对应车辆品牌;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.3.3.型号:显示租赁合同中对应车辆型号;'), @@ -1043,6 +1091,7 @@ const Component = function() { React.createElement('div', { style: reqSubItemStyle }, '3.1.4.3.审批通过:发起人已提交,最终节点完成审批;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.4.4.审批驳回:发起人已提交,任意流程节点驳回,该状态下操作列支持编辑和重新提交;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.4.5.未提交:发起人仅保存,但未提交审批;'), + React.createElement('div', { style: reqSubItemStyle }, '3.1.4.6.撤回:发起人主动撤回审批流程;'), React.createElement('div', { style: reqItemStyle }, '3.1.5.合同状态:显示租赁合同状态,状态分为:草稿、变更、合同进行中、到期合同、已提交审批、已结束;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.5.1.草稿:发起人仅保存,但未提交审批;'), React.createElement('div', { style: reqSubItemStyle }, '3.1.5.2.变更:发起人提交后,合同已通过审批的基础上,进行了「变更内容」操作,且已提交审批,但未完成最终节点审批;'), diff --git a/web端/运维管理/车辆业务/替换车管理-新增.jsx b/web端/运维管理/车辆业务/替换车管理-新增.jsx new file mode 100644 index 0000000..a2296ea --- /dev/null +++ b/web端/运维管理/车辆业务/替换车管理-新增.jsx @@ -0,0 +1,344 @@ +// 【重要】必须使用 const Component 作为组件变量名 +// 运维管理 - 车辆业务 - 替换车管理 - 新增(2026年3月3日版本) + +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 Select = antd.Select; + var Input = antd.Input; + var Button = antd.Button; + var Modal = antd.Modal; + var message = antd.message; + + // 模拟:进行中的车辆租赁合同列表(选项目后反写合同信息) + var contractList = [ + { projectId: 'p1', projectName: '嘉兴氢能示范项目', contractCode: 'HT-ZL-2025-001', customerName: '嘉兴某某物流有限公司', contactPerson: '张三', signDate: '2025-01-15', contactPhone: '13800138001', businessDept: '业务1部', businessPerson: '张经理' }, + { projectId: 'p2', projectName: '上海物流租赁项目', contractCode: 'HT-ZL-2025-002', customerName: '上海某某运输公司', contactPerson: '李四', signDate: '2025-02-01', contactPhone: '13800138002', businessDept: '业务2部', businessPerson: '李专员' }, + { projectId: 'p3', projectName: '杭州城配租赁项目', contractCode: 'HT-ZL-2025-003', customerName: '杭州某某租赁有限公司', contactPerson: '王五', signDate: '2025-02-10', contactPhone: '13800138003', businessDept: '业务3部', businessPerson: '王专员' } + ]; + + // 模拟:按合同对应的已交车未还车车辆(项目 p1 下) + var originalPlateByProject = { + p1: [ + { plateNo: '浙A12345', vin: 'LGHXCAE28M1234567', brand: '东风', model: 'DFH1180' }, + { plateNo: '浙A55555', vin: 'LGHXCAE28M5555555', brand: '重汽', model: 'ZZ1160' } + ], + p2: [ + { plateNo: '浙B11111', vin: 'LGHXCAE28M7654321', brand: '江淮', model: 'HFC1180' } + ], + p3: [ + { plateNo: '浙C33333', vin: 'LGHXCAE28M8888888', brand: '东风', model: 'DFH1190' } + ] + }; + + // 模拟:当前人员权限下已备车车辆 + var replacePlateOptions = [ + { plateNo: '浙A67890', vin: 'LGHXCAE28M6789012', brand: '福田', model: 'BJ1180' }, + { plateNo: '浙B22222', vin: 'LGHXCAE28M2222222', brand: '重汽', model: 'ZZ1180' }, + { plateNo: '浙C44444', vin: 'LGHXCAE28M4444444', brand: '福田', model: 'BJ1190' }, + { plateNo: '浙A66666', vin: 'LGHXCAE28M6666666', brand: '江淮', model: 'HFC1190' }, + { plateNo: '浙F88888', vin: 'LGHXCAE28M8888888', brand: '东风', model: 'DFH1180' } + ]; + + var projectOptions = contractList.map(function (c) { + return { value: c.projectId, label: c.projectName }; + }); + + var formState = useState({ + projectId: undefined, + contractCode: '', + customerName: '', + contactPerson: '', + signDate: '', + contactPhone: '', + businessDept: '', + businessPerson: '', + replaceType: undefined, + replaceReason: undefined, + replaceReasonDesc: '', + originalPlate: undefined, + originalVin: '', + originalBrand: '', + originalModel: '', + replacePlate: undefined, + replaceVin: '', + replaceBrand: '', + replaceModel: '' + }); + var form = formState[0]; + var setForm = formState[1]; + var editedState = useState(false); + var setEdited = editedState[1]; + var cancelModalVisible = useState(false); + var setCancelModalVisible = cancelModalVisible[1]; + var requirementModalVisible = useState(false); + var setRequirementModalVisible = requirementModalVisible[1]; + + var selectedContract = useMemo(function () { + if (!form.projectId) return null; + return contractList.find(function (c) { return c.projectId === form.projectId; }) || null; + }, [form.projectId]); + + var originalPlateList = useMemo(function () { + if (!form.projectId) return []; + return (originalPlateByProject[form.projectId] || []).map(function (v) { return { value: v.plateNo, label: v.plateNo }; }); + }, [form.projectId]); + + var replacePlateSelectOptions = useMemo(function () { + return replacePlateOptions.map(function (v) { return { value: v.plateNo, label: v.plateNo }; }); + }, []); + + var onProjectChange = useCallback(function (projectId) { + setEdited(true); + var contract = contractList.find(function (c) { return c.projectId === projectId; }); + setForm(function (prev) { + var next = {}; + for (var k in prev) next[k] = prev[k]; + next.projectId = projectId; + next.contractCode = contract ? contract.contractCode : ''; + next.customerName = contract ? contract.customerName : ''; + next.contactPerson = contract ? contract.contactPerson : ''; + next.signDate = contract ? contract.signDate : ''; + next.contactPhone = contract ? contract.contactPhone : ''; + next.businessDept = contract ? contract.businessDept : ''; + next.businessPerson = contract ? contract.businessPerson : ''; + next.originalPlate = undefined; + next.originalVin = ''; + next.originalBrand = ''; + next.originalModel = ''; + return next; + }); + }, []); + + var onOriginalPlateChange = useCallback(function (plateNo) { + setEdited(true); + var list = form.projectId ? (originalPlateByProject[form.projectId] || []) : []; + var vehicle = list.find(function (v) { return v.plateNo === plateNo; }); + setForm(function (prev) { + var next = {}; + for (var k in prev) next[k] = prev[k]; + next.originalPlate = plateNo; + next.originalVin = vehicle ? vehicle.vin : ''; + next.originalBrand = vehicle ? vehicle.brand : ''; + next.originalModel = vehicle ? vehicle.model : ''; + return next; + }); + }, [form.projectId]); + + var onReplacePlateChange = useCallback(function (plateNo) { + setEdited(true); + var vehicle = replacePlateOptions.find(function (v) { return v.plateNo === plateNo; }); + setForm(function (prev) { + var next = {}; + for (var k in prev) next[k] = prev[k]; + next.replacePlate = plateNo; + next.replaceVin = vehicle ? vehicle.vin : ''; + next.replaceBrand = vehicle ? vehicle.brand : ''; + next.replaceModel = vehicle ? vehicle.model : ''; + return next; + }); + }, []); + + var handleSubmit = useCallback(function () { + message.success('替换车申请已提交审核'); + }, []); + + var handleSave = useCallback(function () { + message.success('已保存,该条数据仅您可查看并编辑(原型)'); + }, []); + + var handleCancel = useCallback(function () { + if (editedState[0]) { + setCancelModalVisible(true); + } else { + message.info('返回替换车管理列表(原型)'); + } + }, [editedState[0]]); + + var confirmCancel = useCallback(function () { + setCancelModalVisible(false); + message.info('已取消,返回替换车管理列表(原型)'); + }, []); + + var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; + var cardStyle = { marginBottom: 16 }; + var labelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; + var formRowStyle = { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', marginBottom: 16 }; + var formItemStyle = { marginBottom: 12 }; + + var requirementContent = '替换车管理-新增(2026年3月3日版本)\n一个「数字化资产ONEOS运管平台」中的「运维管理」「车辆业务」「替换车管理」「新增」模块\n\n1.面包屑:\n#运维管理-车辆业务-替换车管理-新增\n页面由选择项目、替换车详情、两个单独卡片组成;\n\n2.选择项目:\n#可通过选择进行中的车辆租赁合同,拉取租赁合同中对应车辆进行替换;\n2.1.项目名称:选择器,可选择所有进行中的合同,支持输入框中输入关键词进行模糊搜索,下拉显示对应项;\n2.2.合同编码:根据项目名称自动反查,不可编辑;\n2.3.客户名称:根据项目名称自动反查,不可编辑;\n2.4.对接人:根据项目名称自动反查,不可编辑;\n2.5.合同签订时间:根据项目名称自动反查,不可编辑;\n2.6.客户联系电话:根据项目名称自动反查,不可编辑;\n2.7.业务部门:根据项目名称自动反查,不可编辑;\n2.8.业务人员:根据项目名称自动反查,不可编辑;\n\n3.替换车详情:\n3.1.替换类型:选择器,分为「永久替换」「临时替换」两个选项;\n 3.1.1.类型为永久替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),由运维手动将被替换车进行还车;\n 3.1.2.类型为临时替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),被替换车不用还车,在被替换车重新交付客户时,由运维手动将替换车进行还车;\n 重新生成交车任务时,交车地点会自动继承自合同,由对应区域运维人员才能操作;\n 交车任务完成后,所有涉及到被替换车辆显示(例如车辆租赁合同、租赁账单、提车应收款等功能)会替换为新替换车的对应信息,如果是临时替换,在新替换车完成还车后,对应车辆记录会恢复为原有车辆数据。如果是永久替换,则由运维自主进行被替换车辆还车;\n3.2.替换原因:选择器,分为「客户原因」「车辆原因」;\n3.3.替换原因说明:文本域,默认提示信息为:请说明替换原因;\n3.4.被替换车牌号:选择器,只能选择该租赁合同当前对应的已交车但未还车车牌号;\n3.5.被替换车识别代码:输入框(禁用),选择被替换车车牌号后自动反写该车识别代码;\n3.6.被替换车品牌:输入框(禁用),选择被替换车车牌号后自动反写该车品牌;\n3.7.被替换车型号:输入框(禁用),选择被替换车车牌号后自动反写该车型号;\n3.8.替换车车牌号:选择器,只能选择该人员权限下所有已备车车辆,在选择项目名称前,不能选择替换车车牌号;\n3.9.替换车识别代码:输入框(禁用),选择替换车车牌号后自动反写该车识别代码;\n3.10.替换车品牌:输入框(禁用),选择替换车车牌号后自动反写该车品牌;\n3.11.替换车型号:输入框(禁用),选择替换车车牌号后自动反写该车型号;\n\n下方为提交审核、保存、取消按钮;\n4.1.点击提交并审核,toast提示:替换车申请已提交审核;\n4.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中(待审批),该条数据只能保存人自己查看并编辑,其他人无法操作;\n4.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回替换车管理列表页;'; + + return React.createElement('div', { style: layoutStyle }, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, + React.createElement(Breadcrumb, { + items: [ + { title: '运维管理' }, + { title: '车辆业务' }, + { title: '替换车管理' }, + { title: '新增' } + ] + }), + React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { setRequirementModalVisible(true); } }, '查看需求说明') + ), + React.createElement(Card, { title: '选择项目', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '项目名称'), + React.createElement(Select, { + placeholder: '请选择或输入项目名称', + style: { width: '100%' }, + value: form.projectId, + onChange: onProjectChange, + allowClear: true, + showSearch: true, + options: projectOptions, + filterOption: function (input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同编码'), + React.createElement(Input, { value: form.contractCode || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户名称'), + React.createElement(Input, { value: form.customerName || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '对接人'), + React.createElement(Input, { value: form.contactPerson || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同签订时间'), + React.createElement(Input, { value: form.signDate || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户联系电话'), + React.createElement(Input, { value: form.contactPhone || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务部门'), + React.createElement(Input, { value: form.businessDept || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务人员'), + React.createElement(Input, { value: form.businessPerson || '', disabled: true, placeholder: '根据项目名称自动反查' }) + ) + ) + ), + React.createElement(Card, { title: '替换车详情', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换类型'), + React.createElement(Select, { + placeholder: '请选择', + style: { width: '100%' }, + value: form.replaceType, + onChange: function (v) { setEdited(true); setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.replaceType = v; return n; }); }, + allowClear: true, + options: [{ value: '永久替换', label: '永久替换' }, { value: '临时替换', label: '临时替换' }] + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换原因'), + React.createElement(Select, { + placeholder: '请选择', + style: { width: '100%' }, + value: form.replaceReason, + onChange: function (v) { setEdited(true); setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.replaceReason = v; return n; }); }, + allowClear: true, + options: [{ value: '客户原因', label: '客户原因' }, { value: '车辆原因', label: '车辆原因' }] + }) + ), + React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: '1 / -1' }) }, + React.createElement('div', { style: labelStyle }, '替换原因说明'), + React.createElement(Input.TextArea, { + placeholder: '请说明替换原因', + value: form.replaceReasonDesc || '', + onChange: function (e) { setEdited(true); setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.replaceReasonDesc = e.target.value; return n; }); }, + rows: 3, + style: { width: '100%' } + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车牌号'), + React.createElement(Select, { + placeholder: '请选择该合同已交车未还车车牌号', + style: { width: '100%' }, + value: form.originalPlate, + onChange: onOriginalPlateChange, + allowClear: true, + options: originalPlateList, + disabled: !form.projectId + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车识别代码'), + React.createElement(Input, { value: form.originalVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车品牌'), + React.createElement(Input, { value: form.originalBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车型号'), + React.createElement(Input, { value: form.originalModel || '', disabled: true }) + ), + React.createElement('div', { style: { gridColumn: '1 / -1', width: '100%' } }), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车车牌号'), + React.createElement(Select, { + placeholder: '请选择已备车车辆', + style: { width: '100%' }, + value: form.replacePlate, + onChange: onReplacePlateChange, + allowClear: true, + showSearch: true, + options: replacePlateSelectOptions, + filterOption: function (input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; }, + disabled: !form.projectId + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车识别代码'), + React.createElement(Input, { value: form.replaceVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车品牌'), + React.createElement(Input, { value: form.replaceBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车型号'), + React.createElement(Input, { value: form.replaceModel || '', disabled: true }) + ) + ), + React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 24 } }, + React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'), + React.createElement(Button, { onClick: handleSave }, '保存'), + React.createElement(Button, { onClick: handleCancel }, '取消') + ) + ), + React.createElement(Modal, { + title: '需求说明', + open: requirementModalVisible[0], + onCancel: function () { setRequirementModalVisible(false); }, + width: 720, + footer: React.createElement(Button, { onClick: function () { setRequirementModalVisible(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 } }, requirementContent)) + ), + React.createElement(Modal, { + title: '取消将会丢失所有已填写内容,是否确认?', + open: cancelModalVisible[0], + onCancel: function () { setCancelModalVisible(false); }, + onOk: confirmCancel, + okText: '确认', + cancelText: '返回' + }) + ); +}; diff --git a/web端/运维管理/车辆业务/替换车管理-查看.jsx b/web端/运维管理/车辆业务/替换车管理-查看.jsx new file mode 100644 index 0000000..b8db0c2 --- /dev/null +++ b/web端/运维管理/车辆业务/替换车管理-查看.jsx @@ -0,0 +1,203 @@ +// 【重要】必须使用 const Component 作为组件变量名 +// 运维管理 - 车辆业务 - 替换车管理 - 查看(2026年3月3日版本) + +const Component = function () { + var useState = React.useState; + + var antd = window.antd; + var Breadcrumb = antd.Breadcrumb; + var Card = antd.Card; + var Input = antd.Input; + var Button = antd.Button; + var Modal = antd.Modal; + + var requirementModalVisible = useState(false); + var setRequirementModalVisible = requirementModalVisible[1]; + + // 模拟:根据已填信息反查的一条替换车记录(实际由路由参数或接口拉取) + var detail = useState({ + projectName: '嘉兴氢能示范项目', + contractCode: 'HT-ZL-2025-001', + customerName: '嘉兴某某物流有限公司', + contactPerson: '张三', + signDate: '2025-01-15', + contactPhone: '13800138001', + businessDept: '业务1部', + businessPerson: '张经理', + replaceType: '永久替换', + replaceReason: '车辆原因', + replaceReasonDesc: '原车故障需维修,临时用替换车保障客户用车。', + originalPlate: '浙A12345', + originalVin: 'LGHXCAE28M1234567', + originalBrand: '东风', + originalModel: 'DFH1180', + replacePlate: '浙A67890', + replaceVin: 'LGHXCAE28M6789012', + replaceBrand: '福田', + replaceModel: 'BJ1180' + }); + var data = detail[0]; + + var handleBack = function () { + // 返回替换车管理列表页(实际为路由或平台跳转) + if (window.__replaceCarBack) { + window.__replaceCarBack(); + } else { + antd.message.info('返回替换车管理列表(原型)'); + } + }; + + var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; + var cardStyle = { marginBottom: 16 }; + var labelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; + var formRowStyle = { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', marginBottom: 16 }; + var formItemStyle = { marginBottom: 12 }; + + // 审批情况(参照车辆租赁合同-查看顶部审批状态) + var approvalSteps = [ + { title: '业务部主管', person: '姚守涛', status: '已通过', approveTime: '2026-02-20 09:30' }, + { title: '事业部主管', person: '尚建华', status: '已通过', approveTime: '2026-02-20 10:15' }, + { title: '运维主管', person: '王运维', status: '已通过', approveTime: '2026-02-20 11:00' } + ]; + var approvalCardStyle = { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' }; + var approvalHeaderStyle = { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600, color: '#333', textAlign: 'center' }; + var approvalBodyStyle = { padding: '24px 20px', display: 'flex', justifyContent: 'center' }; + var stepWrapStyle = { display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap', justifyContent: 'center' }; + var stepItemStyle = { flex: '1 1 0', minWidth: 140, maxWidth: 220, textAlign: 'center', position: 'relative' }; + var stepIconStyle = { width: 32, height: 32, borderRadius: '50%', margin: '0 auto 8px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 16, fontWeight: 600, backgroundColor: '#52c41a', color: '#fff' }; + var stepLineStyle = { position: 'absolute', top: 16, left: '50%', right: '-50%', height: 2, backgroundColor: '#52c41a', zIndex: 0 }; + var stepTitleStyle = { fontSize: 13, color: '#333', fontWeight: 500, marginBottom: 4 }; + var stepDescStyle = { fontSize: 12, color: '#666' }; + var stepStatusStyle = { fontSize: 12, color: '#52c41a', marginTop: 4 }; + var stepTimeStyle = { fontSize: 12, color: '#999', marginTop: 2 }; + var requirementContent = '替换车管理-查看(2026年3月3日版本)\n一个「数字化资产ONEOS运管平台」中的「运维管理」「车辆业务」「替换车管理」「查看」模块\n1.面包屑:\n#运维管理-车辆业务-替换车管理-查看\n页面由选择项目、替换车详情、两个单独卡片组成;\n\n2.选择项目:\n#可通过选择进行中的车辆租赁合同,拉取租赁合同中对应车辆进行替换;\n2.1.项目名称:根据已填信息反查,不可编辑;\n2.2.合同编码:根据项目名称自动反查,不可编辑;\n2.3.客户名称:根据项目名称自动反查,不可编辑;\n2.4.对接人:根据项目名称自动反查,不可编辑;\n2.5.合同签订时间:根据项目名称自动反查,不可编辑;\n2.6.客户联系电话:根据项目名称自动反查,不可编辑;\n2.7.业务部门:根据项目名称自动反查,不可编辑;\n2.8.业务人员:根据项目名称自动反查,不可编辑;\n\n3.替换车详情:\n3.1.替换类型:选择器,根据已填信息反查,不可编辑;\n 3.1.1.类型为永久替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),由运维手动将被替换车进行还车;\n 3.1.2.类型为临时替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),被替换车不用还车,在被替换车重新交付客户时,由运维手动将替换车进行还车;\n 重新生成交车任务时,交车地点会自动继承自合同,由对应区域运维人员才能操作;\n 交车任务完成后,所有涉及到被替换车辆显示(例如车辆租赁合同、租赁账单、提车应收款等功能)会替换为新替换车的对应信息,如果是临时替换,在新替换车完成还车后,对应车辆记录会恢复为原有车辆数据。如果是永久替换,则由运维自主进行被替换车辆还车;\n3.2.替换原因:选择器,根据已填信息反查,不可编辑;\n3.3.替换原因说明:文本域,根据已填信息反查,不可编辑;\n3.4.被替换车牌号:选择器,根据已填信息反查,不可编辑;\n3.5.被替换车识别代码:输入框(禁用),选择被替换车车牌号后自动反写该车识别代码;\n3.6.被替换车品牌:输入框(禁用),选择被替换车车牌号后自动反写该车品牌;\n3.7.被替换车型号:输入框(禁用),选择被替换车车牌号后自动反写该车型号;\n3.8.替换车车牌号:选择器,根据已填信息反查,不可编辑;\n3.9.替换车识别代码:输入框(禁用),选择替换车车牌号后自动反写该车识别代码;\n3.10.替换车品牌:输入框(禁用),选择替换车车牌号后自动反写该车品牌;\n3.11.替换车型号:输入框(禁用),选择替换车车牌号后自动反写该车型号;\n\n下方为返回按钮;\n4.1.点击返回,返回替换车管理列表页;'; + var approvalStepEls = approvalSteps.map(function (step, index) { + var isLast = index === approvalSteps.length - 1; + return React.createElement('div', { key: index, style: Object.assign({}, stepItemStyle, { zIndex: approvalSteps.length - index }) }, + !isLast ? React.createElement('div', { style: stepLineStyle }) : null, + React.createElement('div', { style: stepIconStyle }, '✓'), + React.createElement('div', { style: stepTitleStyle }, step.title), + React.createElement('div', { style: stepDescStyle }, step.person), + React.createElement('div', { style: stepStatusStyle }, step.status), + step.approveTime ? React.createElement('div', { style: stepTimeStyle }, step.approveTime) : null + ); + }); + + return React.createElement('div', { style: layoutStyle }, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, + React.createElement(Breadcrumb, { + items: [ + { title: '运维管理' }, + { title: '车辆业务' }, + { title: '替换车管理' }, + { title: '查看' } + ] + }), + React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { setRequirementModalVisible(true); } }, '查看需求说明') + ), + React.createElement('div', { style: approvalCardStyle }, + React.createElement('div', { style: approvalHeaderStyle }, '审批情况'), + React.createElement('div', { style: approvalBodyStyle }, + React.createElement('div', { style: stepWrapStyle }, approvalStepEls) + ) + ), + React.createElement(Card, { title: '选择项目', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '项目名称'), + React.createElement(Input, { value: data.projectName || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同编码'), + React.createElement(Input, { value: data.contractCode || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户名称'), + React.createElement(Input, { value: data.customerName || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '对接人'), + React.createElement(Input, { value: data.contactPerson || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同签订时间'), + React.createElement(Input, { value: data.signDate || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户联系电话'), + React.createElement(Input, { value: data.contactPhone || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务部门'), + React.createElement(Input, { value: data.businessDept || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务人员'), + React.createElement(Input, { value: data.businessPerson || '', disabled: true }) + ) + ) + ), + React.createElement(Card, { title: '替换车详情', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换类型'), + React.createElement(Input, { value: data.replaceType || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换原因'), + React.createElement(Input, { value: data.replaceReason || '', disabled: true }) + ), + React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: '1 / -1' }) }, + React.createElement('div', { style: labelStyle }, '替换原因说明'), + React.createElement(Input.TextArea, { value: data.replaceReasonDesc || '', disabled: true, rows: 3, style: { width: '100%' } }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车牌号'), + React.createElement(Input, { value: data.originalPlate || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车识别代码'), + React.createElement(Input, { value: data.originalVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车品牌'), + React.createElement(Input, { value: data.originalBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车型号'), + React.createElement(Input, { value: data.originalModel || '', disabled: true }) + ), + React.createElement('div', { style: { gridColumn: '1 / -1', width: '100%' } }), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车车牌号'), + React.createElement(Input, { value: data.replacePlate || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车识别代码'), + React.createElement(Input, { value: data.replaceVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车品牌'), + React.createElement(Input, { value: data.replaceBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车型号'), + React.createElement(Input, { value: data.replaceModel || '', disabled: true }) + ) + ), + React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 24 } }, + React.createElement(Button, { onClick: handleBack }, '返回') + ) + ), + React.createElement(Modal, { + title: '需求说明', + open: requirementModalVisible[0], + onCancel: function () { setRequirementModalVisible(false); }, + width: 720, + footer: React.createElement(Button, { onClick: function () { setRequirementModalVisible(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 } }, requirementContent)) + ) + ); +}; diff --git a/web端/运维管理/车辆业务/替换车管理-编辑.jsx b/web端/运维管理/车辆业务/替换车管理-编辑.jsx new file mode 100644 index 0000000..6174327 --- /dev/null +++ b/web端/运维管理/车辆业务/替换车管理-编辑.jsx @@ -0,0 +1,322 @@ +// 【重要】必须使用 const Component 作为组件变量名 +// 运维管理 - 车辆业务 - 替换车管理 - 编辑(2026年3月3日版本) + +const Component = function () { + var useState = React.useState; + + var antd = window.antd; + var Breadcrumb = antd.Breadcrumb; + var Card = antd.Card; + var Input = antd.Input; + var Button = antd.Button; + var Select = antd.Select; + var Modal = antd.Modal; + var Option = Select.Option; + + var requirementModalVisible = useState(false); + var setRequirementModalVisible = requirementModalVisible[1]; + var edited = useState(false); + var setEdited = edited[1]; + + // 模拟:进行中的车辆租赁合同列表(实际由接口拉取) + var contractList = [ + { projectName: '嘉兴氢能示范项目', contractCode: 'HT-ZL-2025-001', customerName: '嘉兴某某物流有限公司', contactPerson: '张三', signDate: '2025-01-15', contactPhone: '13800138001', businessDept: '业务1部', businessPerson: '张经理' }, + { projectName: '上海氢能试点项目', contractCode: 'HT-ZL-2025-002', customerName: '上海某某运输公司', contactPerson: '李四', signDate: '2025-02-01', contactPhone: '13900139001', businessDept: '业务2部', businessPerson: '李经理' }, + { projectName: '杭州示范运营项目', contractCode: 'HT-ZL-2025-003', customerName: '杭州某某物流', contactPerson: '王五', signDate: '2025-01-20', contactPhone: '13700137001', businessDept: '业务1部', businessPerson: '张经理' } + ]; + // 该合同下已交车未还车车辆(被替换车可选) + var contractDeliveredVehicles = { + '嘉兴氢能示范项目': [ + { plateNo: '浙A12345', vin: 'LGHXCAE28M1234567', brand: '东风', model: 'DFH1180' }, + { plateNo: '浙A11111', vin: 'LGHXCAE28M1111111', brand: '东风', model: 'DFH1180' } + ], + '上海氢能试点项目': [ + { plateNo: '沪B22222', vin: 'LGHXCAE28M2222222', brand: '福田', model: 'BJ1180' } + ], + '杭州示范运营项目': [] + }; + // 人员权限下已备车车辆(替换车可选,需先选项目名称后才能选) + var preparedVehicleList = [ + { plateNo: '浙A67890', vin: 'LGHXCAE28M6789012', brand: '福田', model: 'BJ1180' }, + { plateNo: '浙B33333', vin: 'LGHXCAE28M3333333', brand: '东风', model: 'DFH1180' } + ]; + + // 编辑表单状态(实际由路由参数或接口拉取初始值) + var detail = useState({ + projectName: '嘉兴氢能示范项目', + contractCode: 'HT-ZL-2025-001', + customerName: '嘉兴某某物流有限公司', + contactPerson: '张三', + signDate: '2025-01-15', + contactPhone: '13800138001', + businessDept: '业务1部', + businessPerson: '张经理', + replaceType: '永久替换', + replaceReason: '车辆原因', + replaceReasonDesc: '原车故障需维修,临时用替换车保障客户用车。', + originalPlate: '浙A12345', + originalVin: 'LGHXCAE28M1234567', + originalBrand: '东风', + originalModel: 'DFH1180', + replacePlate: '浙A67890', + replaceVin: 'LGHXCAE28M6789012', + replaceBrand: '福田', + replaceModel: 'BJ1180' + }); + var data = detail[0]; + var setData = detail[1]; + + var updateDetail = function (field, value) { + setEdited(true); + setData(function (prev) { + var next = Object.assign({}, prev); + next[field] = value; + if (field === 'projectName') { + var c = contractList.find(function (x) { return x.projectName === value; }); + if (c) { + next.contractCode = c.contractCode; + next.customerName = c.customerName; + next.contactPerson = c.contactPerson; + next.signDate = c.signDate; + next.contactPhone = c.contactPhone; + next.businessDept = c.businessDept; + next.businessPerson = c.businessPerson; + } else { + next.contractCode = ''; + next.customerName = ''; + next.contactPerson = ''; + next.signDate = ''; + next.contactPhone = ''; + next.businessDept = ''; + next.businessPerson = ''; + } + next.originalPlate = ''; + next.originalVin = ''; + next.originalBrand = ''; + next.originalModel = ''; + next.replacePlate = ''; + next.replaceVin = ''; + next.replaceBrand = ''; + next.replaceModel = ''; + } + if (field === 'originalPlate') { + var list = contractDeliveredVehicles[prev.projectName] || []; + var v = list.find(function (x) { return x.plateNo === value; }); + next.originalVin = v ? v.vin : ''; + next.originalBrand = v ? v.brand : ''; + next.originalModel = v ? v.model : ''; + } + if (field === 'replacePlate') { + var v = preparedVehicleList.find(function (x) { return x.plateNo === value; }); + next.replaceVin = v ? v.vin : ''; + next.replaceBrand = v ? v.brand : ''; + next.replaceModel = v ? v.model : ''; + } + return next; + }); + }; + + var handleSubmit = function () { + if (window.__replaceCarSubmit) { + window.__replaceCarSubmit(data); + } else { + antd.message.success('替换车申请已提交审核'); + } + }; + + var handleSave = function () { + if (window.__replaceCarSave) { + window.__replaceCarSave(data); + } else { + antd.message.success('保存成功(原型)'); + } + }; + + var handleCancel = function () { + if (edited[0]) { + antd.Modal.confirm({ + title: '确认取消', + content: '取消将会丢失所有已填写内容,是否确认?', + okText: '确认', + cancelText: '取消', + onOk: function () { + if (window.__replaceCarBack) { + window.__replaceCarBack(); + } else { + antd.message.info('返回替换车管理列表(原型)'); + } + } + }); + } else { + if (window.__replaceCarBack) { + window.__replaceCarBack(); + } else { + antd.message.info('返回替换车管理列表(原型)'); + } + } + }; + + var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; + var cardStyle = { marginBottom: 16 }; + var labelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; + var formRowStyle = { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', marginBottom: 16 }; + var formItemStyle = { marginBottom: 12 }; + + var requirementContent = '替换车管理-编辑(2026年3月3日版本)\n一个「数字化资产ONEOS运管平台」中的「运维管理」「车辆业务」「替换车管理」「编辑」模块\n1.面包屑:\n#运维管理-车辆业务-替换车管理-编辑\n页面由选择项目、替换车详情、两个单独卡片组成;\n\n2.选择项目:\n#可通过选择进行中的车辆租赁合同,拉取租赁合同中对应车辆进行替换;\n2.1.项目名称:选择器,反写已新增完成的内容,可编辑,可选择所有进行中的合同,支持输入框中输入关键词进行模糊搜索,下拉显示对应项;\n2.2.合同编码:根据项目名称自动反查,不可编辑;\n2.3.客户名称:根据项目名称自动反查,不可编辑;\n2.4.对接人:根据项目名称自动反查,不可编辑;\n2.5.合同签订时间:根据项目名称自动反查,不可编辑;\n2.6.客户联系电话:根据项目名称自动反查,不可编辑;\n2.7.业务部门:根据项目名称自动反查,不可编辑;\n2.8.业务人员:根据项目名称自动反查,不可编辑;\n\n3.替换车详情:\n3.1.替换类型:选择器,反写已新增完成的内容,可编辑,分为「永久替换」「临时替换」两个选项;\n 3.1.1.类型为永久替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),由运维手动将被替换车进行还车;\n 3.1.2.类型为临时替换时,该申请通过审核后替换车进行交车(交车时间为流程结束当天),被替换车不用还车,在被替换车重新交付客户时,由运维手动将替换车进行还车;\n 重新生成交车任务时,交车地点会自动继承自合同,由对应区域运维人员才能操作;\n 交车任务完成后,所有涉及到被替换车辆显示(例如车辆租赁合同、租赁账单、提车应收款等功能)会替换为新替换车的对应信息,如果是临时替换,在新替换车完成还车后,对应车辆记录会恢复为原有车辆数据。如果是永久替换,则由运维自主进行被替换车辆还车;\n3.2.替换原因:选择器,反写已新增完成的内容,可编辑,分为「客户原因」「车辆原因」;\n3.3.替换原因说明:文本域,反写已新增完成的内容,可编辑,默认提示信息为:请说明替换原因;\n3.4.被替换车牌号:选择器,反写已新增完成的内容,可编辑,只能选择该租赁合同当前对应的已交车但未还车车牌号;\n3.5.被替换车识别代码:输入框(禁用),选择被替换车车牌号后自动反写该车识别代码;\n3.6.被替换车品牌:输入框(禁用),选择被替换车车牌号后自动反写该车品牌;\n3.7.被替换车型号:输入框(禁用),选择被替换车车牌号后自动反写该车型号;\n3.8.替换车车牌号:选择器,反写已新增完成的内容,可编辑,只能选择该人员权限下所有已备车车辆,在选择项目名称前,不能选择替换车车牌号;\n3.9.替换车识别代码:输入框(禁用),选择替换车车牌号后自动反写该车识别代码;\n3.10.替换车品牌:输入框(禁用),选择替换车车牌号后自动反写该车品牌;\n3.11.替换车型号:输入框(禁用),选择替换车车牌号后自动反写该车型号;\n\n下方为提交审核、保存、取消按钮;\n4.1.点击提交并审核,toast提示:替换车申请已提交审核;\n4.2.点击保存,会存储租赁订单已填写内容,不做必填项校验,同时显示在租赁合同列表中(待审批),该条数据只能保存人自己查看并编辑,其他人无法操作;\n4.3.点击取消,如当前页面有已编辑内容时,点击取消会进行二次提示,内容为:取消将会丢失所有已填写内容,是否确认?点击确认返回替换车管理列表页;'; + + return React.createElement('div', { style: layoutStyle }, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, + React.createElement(Breadcrumb, { + items: [ + { title: '运维管理' }, + { title: '车辆业务' }, + { title: '替换车管理' }, + { title: '编辑' } + ] + }), + React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { setRequirementModalVisible(true); } }, '查看需求说明') + ), + React.createElement(Card, { title: '选择项目', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '项目名称'), + React.createElement(Select, { + style: { width: '100%' }, + placeholder: '请选择或输入关键词搜索', + value: data.projectName || undefined, + onChange: function (v) { updateDetail('projectName', v || ''); }, + showSearch: true, + allowClear: true, + filterOption: function (input, opt) { return opt && opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; } + }, contractList.map(function (c) { return React.createElement(Option, { key: c.projectName, value: c.projectName }, c.projectName); })) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同编码'), + React.createElement(Input, { value: data.contractCode || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户名称'), + React.createElement(Input, { value: data.customerName || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '对接人'), + React.createElement(Input, { value: data.contactPerson || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '合同签订时间'), + React.createElement(Input, { value: data.signDate || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '客户联系电话'), + React.createElement(Input, { value: data.contactPhone || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务部门'), + React.createElement(Input, { value: data.businessDept || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '业务人员'), + React.createElement(Input, { value: data.businessPerson || '', disabled: true }) + ) + ) + ), + React.createElement(Card, { title: '替换车详情', style: cardStyle }, + React.createElement('div', { style: formRowStyle }, + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换类型'), + React.createElement(Select, { + style: { width: '100%' }, + value: data.replaceType || undefined, + onChange: function (v) { updateDetail('replaceType', v || ''); }, + placeholder: '请选择' + }, React.createElement(Option, { value: '永久替换' }, '永久替换'), React.createElement(Option, { value: '临时替换' }, '临时替换')) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换原因'), + React.createElement(Select, { + style: { width: '100%' }, + value: data.replaceReason || undefined, + onChange: function (v) { updateDetail('replaceReason', v || ''); }, + placeholder: '请选择' + }, React.createElement(Option, { value: '客户原因' }, '客户原因'), React.createElement(Option, { value: '车辆原因' }, '车辆原因')) + ), + React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: '1 / -1' }) }, + React.createElement('div', { style: labelStyle }, '替换原因说明'), + React.createElement(Input.TextArea, { + value: data.replaceReasonDesc || '', + onChange: function (e) { updateDetail('replaceReasonDesc', e.target.value); }, + rows: 3, + placeholder: '请说明替换原因', + style: { width: '100%' } + }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车牌号'), + React.createElement(Select, { + style: { width: '100%' }, + placeholder: '请选择或搜索(仅显示该合同已交车未还车车辆)', + value: data.originalPlate || undefined, + onChange: function (v) { updateDetail('originalPlate', v || ''); }, + showSearch: true, + allowClear: true, + disabled: !data.projectName, + filterOption: function (input, opt) { return opt && opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; } + }, (contractDeliveredVehicles[data.projectName] || []).map(function (v) { return React.createElement(Option, { key: v.plateNo, value: v.plateNo }, v.plateNo); })) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车识别代码'), + React.createElement(Input, { value: data.originalVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车品牌'), + React.createElement(Input, { value: data.originalBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '被替换车型号'), + React.createElement(Input, { value: data.originalModel || '', disabled: true }) + ), + React.createElement('div', { style: { gridColumn: '1 / -1', width: '100%' } }), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车车牌号'), + React.createElement(Select, { + style: { width: '100%' }, + placeholder: data.projectName ? '请选择或搜索(仅显示已备车车辆)' : '请先选择项目名称', + value: data.replacePlate || undefined, + onChange: function (v) { updateDetail('replacePlate', v || ''); }, + showSearch: true, + allowClear: true, + disabled: !data.projectName, + filterOption: function (input, opt) { return opt && opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; } + }, preparedVehicleList.map(function (v) { return React.createElement(Option, { key: v.plateNo, value: v.plateNo }, v.plateNo); })) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车识别代码'), + React.createElement(Input, { value: data.replaceVin || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车品牌'), + React.createElement(Input, { value: data.replaceBrand || '', disabled: true }) + ), + React.createElement('div', { style: formItemStyle }, + React.createElement('div', { style: labelStyle }, '替换车型号'), + React.createElement(Input, { value: data.replaceModel || '', disabled: true }) + ) + ), + React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 24 } }, + React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'), + React.createElement(Button, { onClick: handleSave }, '保存'), + React.createElement(Button, { onClick: handleCancel }, '取消') + ) + ), + React.createElement(Modal, { + title: '需求说明', + open: requirementModalVisible[0], + onCancel: function () { setRequirementModalVisible(false); }, + width: 720, + footer: React.createElement(Button, { onClick: function () { setRequirementModalVisible(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 } }, requirementContent)) + ) + ); +}; diff --git a/web端/运维管理/车辆业务/替换车管理.jsx b/web端/运维管理/车辆业务/替换车管理.jsx new file mode 100644 index 0000000..eebd363 --- /dev/null +++ b/web端/运维管理/车辆业务/替换车管理.jsx @@ -0,0 +1,493 @@ +// 【重要】必须使用 const Component 作为组件变量名 +// 运维管理 - 车辆业务 - 替换车管理(2026年3月3日版本) + +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 Table = antd.Table; + var Tabs = antd.Tabs; + var Modal = antd.Modal; + var Input = antd.Input; + var message = antd.message; + + var RangePicker = DatePicker.RangePicker; + + // 筛选展开(默认一行 3 列) + var _filterExpanded = useState(false); + var _replaceDateRange = useState(null); + var _replaceType = useState(undefined); + var _projectName = useState(undefined); + var _approvalStatus = useState(['全部']); + var _originalPlate = useState(undefined); + var _replacePlate = useState(undefined); + var _replaceReason = useState(undefined); + var _creator = useState(undefined); + var _createTimeRange = useState(null); + + var _appliedFilter = useState({ + replaceDateRange: null, + replaceType: undefined, + projectName: undefined, + approvalStatus: ['全部'], + originalPlate: undefined, + replacePlate: undefined, + replaceReason: undefined, + creator: undefined, + createTimeRange: null + }); + + var _activeTab = useState('ongoing'); + var _selectedRowKeys = useState([]); + var _withdrawModalVisible = useState(false); + var _withdrawModalRecord = useState(null); + var _toPermanentModalVisible = useState(false); + var _toPermanentModalRecord = useState(null); + var _requirementModalVisible = useState(false); + + var replaceTypeOptions = [ + { value: '永久替换', label: '永久替换' }, + { value: '临时替换', label: '临时替换' } + ]; + var projectNameOptions = [ + { value: 'p1', label: '嘉兴氢能示范项目' }, + { value: 'p2', label: '上海物流租赁项目' }, + { value: 'p3', label: '杭州城配租赁项目' } + ]; + var approvalStatusOptions = [ + { value: '全部', label: '全部' }, + { value: '待审批', label: '待审批' }, + { value: '审批中', label: '审批中' }, + { value: '审批驳回', label: '审批驳回' }, + { value: '未提交', label: '未提交' }, + { value: '撤回', label: '撤回' } + ]; + var plateOptions = [ + { value: '浙A12345', label: '浙A12345' }, + { value: '浙A67890', label: '浙A67890' }, + { value: '浙B11111', label: '浙B11111' }, + { value: '浙B22222', label: '浙B22222' }, + { value: '浙C33333', label: '浙C33333' } + ]; + var replaceReasonOptions = [ + { value: '全部', label: '全部' }, + { value: '客户原因', label: '客户原因' }, + { value: '车辆原因', label: '车辆原因' } + ]; + var creatorOptions = [ + { value: '张三', label: '张三' }, + { value: '李四', label: '李四' }, + { value: '王五', label: '王五' }, + { value: '赵六', label: '赵六' } + ]; + + // 进行中:未结束、暂存,审批状态为 待审批、审批中、审批驳回、未提交、撤回 + var ongoingList = [ + { id: 'o1', replaceDate: '2025-03-05', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '待审批', originalPlate: '浙A12345', originalBrand: '东风', originalModel: 'DFH1180', replacePlate: '浙A67890', replaceBrand: '福田', replaceModel: 'BJ1180', replaceReason: '车辆原因', replaceReasonDesc: '原车维修', creator: '张三', createTime: '2025-03-01 10:00' }, + { id: 'o2', replaceDate: '2025-03-06', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '审批中', originalPlate: '浙B11111', originalBrand: '江淮', originalModel: 'HFC1180', replacePlate: '浙B22222', replaceBrand: '重汽', replaceModel: 'ZZ1180', replaceReason: '客户原因', replaceReasonDesc: '客户要求换型', creator: '李四', createTime: '2025-03-01 14:30' }, + { id: 'o3', replaceDate: '2025-03-07', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '审批驳回', originalPlate: '浙C33333', originalBrand: '东风', originalModel: 'DFH1190', replacePlate: '浙C44444', replaceBrand: '福田', replaceModel: 'BJ1190', replaceReason: '车辆原因', replaceReasonDesc: '事故替换', creator: '王五', createTime: '2025-03-02 09:15' }, + { id: 'o4', replaceDate: '2025-03-08', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '未提交', originalPlate: '浙A55555', originalBrand: '重汽', originalModel: 'ZZ1160', replacePlate: '浙A66666', replaceBrand: '江淮', replaceModel: 'HFC1190', replaceReason: '车辆原因', replaceReasonDesc: '保养替换', creator: '赵六', createTime: '2025-03-02 16:00' }, + { id: 'o5', replaceDate: '2025-03-09', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '撤回', originalPlate: '浙F77777', originalBrand: '福田', originalModel: 'BJ1180', replacePlate: '浙F88888', replaceBrand: '东风', replaceModel: 'DFH1180', replaceReason: '客户原因', replaceReasonDesc: '年检替换', creator: '张三', createTime: '2025-03-03 11:20' }, + { id: 'o6', replaceDate: '2025-03-10', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '待审批', originalPlate: '浙A11201', originalBrand: '江淮', originalModel: 'HFC1160', replacePlate: '浙A11202', replaceBrand: '东风', replaceModel: 'DFH1160', replaceReason: '车辆原因', replaceReasonDesc: '发动机故障', creator: '李四', createTime: '2025-03-04 08:45' }, + { id: 'o7', replaceDate: '2025-03-11', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批中', originalPlate: '浙B22301', originalBrand: '重汽', originalModel: 'ZZ1160', replacePlate: '浙B22302', replaceBrand: '福田', replaceModel: 'BJ1160', replaceReason: '客户原因', replaceReasonDesc: '临时增运力', creator: '王五', createTime: '2025-03-04 13:00' }, + { id: 'o8', replaceDate: '2025-03-12', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '审批驳回', originalPlate: '浙C33401', originalBrand: '东风', originalModel: 'DFH1190', replacePlate: '浙C33402', replaceBrand: '江淮', replaceModel: 'HFC1190', replaceReason: '车辆原因', replaceReasonDesc: '底盘大修', creator: '赵六', createTime: '2025-03-05 10:20' }, + { id: 'o9', replaceDate: '2025-03-13', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '未提交', originalPlate: '浙D44501', originalBrand: '福田', originalModel: 'BJ1180', replacePlate: '浙D44502', replaceBrand: '重汽', replaceModel: 'ZZ1180', replaceReason: '客户原因', replaceReasonDesc: '线路调整', creator: '张三', createTime: '2025-03-05 15:30' }, + { id: 'o10', replaceDate: '2025-03-14', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '撤回', originalPlate: '浙E55601', originalBrand: '江淮', originalModel: 'HFC1180', replacePlate: '浙E55602', replaceBrand: '东风', replaceModel: 'DFH1180', replaceReason: '车辆原因', replaceReasonDesc: '轮胎更换', creator: '李四', createTime: '2025-03-06 09:00' }, + { id: 'o11', replaceDate: '2025-03-15', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '待审批', originalPlate: '浙F66701', originalBrand: '重汽', originalModel: 'ZZ1190', replacePlate: '浙F66702', replaceBrand: '福田', replaceModel: 'BJ1190', replaceReason: '车辆原因', replaceReasonDesc: '电瓶更换', creator: '王五', createTime: '2025-03-06 14:15' }, + { id: 'o12', replaceDate: '2025-03-16', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '审批中', originalPlate: '浙A77801', originalBrand: '东风', originalModel: 'DFH1160', replacePlate: '浙A77802', replaceBrand: '江淮', replaceModel: 'HFC1160', replaceReason: '客户原因', replaceReasonDesc: '合同到期换车', creator: '赵六', createTime: '2025-03-07 11:00' }, + { id: 'o13', replaceDate: '2025-03-17', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批驳回', originalPlate: '浙B88901', originalBrand: '福田', originalModel: 'BJ1160', replacePlate: '浙B88902', replaceBrand: '重汽', replaceModel: 'ZZ1160', replaceReason: '车辆原因', replaceReasonDesc: '制动系统检修', creator: '张三', createTime: '2025-03-07 16:45' }, + { id: 'o14', replaceDate: '2025-03-18', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '未提交', originalPlate: '浙C99001', originalBrand: '江淮', originalModel: 'HFC1190', replacePlate: '浙C99002', replaceBrand: '东风', replaceModel: 'DFH1190', replaceReason: '客户原因', replaceReasonDesc: '运量增加', creator: '李四', createTime: '2025-03-08 08:30' }, + { id: 'o15', replaceDate: '2025-03-19', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '撤回', originalPlate: '浙D10101', originalBrand: '重汽', originalModel: 'ZZ1180', replacePlate: '浙D10102', replaceBrand: '福田', replaceModel: 'BJ1180', replaceReason: '车辆原因', replaceReasonDesc: '空调维修', creator: '王五', createTime: '2025-03-08 12:00' }, + { id: 'o16', replaceDate: '2025-03-20', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '待审批', originalPlate: '浙E20201', originalBrand: '东风', originalModel: 'DFH1180', replacePlate: '浙E20202', replaceBrand: '江淮', replaceModel: 'HFC1180', replaceReason: '车辆原因', replaceReasonDesc: '变速箱故障', creator: '赵六', createTime: '2025-03-09 10:20' }, + { id: 'o17', replaceDate: '2025-03-21', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '审批中', originalPlate: '浙F30301', originalBrand: '福田', originalModel: 'BJ1190', replacePlate: '浙F30302', replaceBrand: '重汽', replaceModel: 'ZZ1190', replaceReason: '客户原因', replaceReasonDesc: '区域调配', creator: '张三', createTime: '2025-03-09 15:00' }, + { id: 'o18', replaceDate: '2025-03-22', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '审批驳回', originalPlate: '浙A40401', originalBrand: '江淮', originalModel: 'HFC1160', replacePlate: '浙A40402', replaceBrand: '东风', replaceModel: 'DFH1160', replaceReason: '车辆原因', replaceReasonDesc: '车身锈蚀', creator: '李四', createTime: '2025-03-10 09:45' }, + { id: 'o19', replaceDate: '2025-03-23', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '未提交', originalPlate: '浙B50501', originalBrand: '重汽', originalModel: 'ZZ1160', replacePlate: '浙B50502', replaceBrand: '福田', replaceModel: 'BJ1160', replaceReason: '客户原因', replaceReasonDesc: '试运行换车', creator: '王五', createTime: '2025-03-10 14:30' }, + { id: 'o20', replaceDate: '2025-03-24', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '撤回', originalPlate: '浙C60601', originalBrand: '东风', originalModel: 'DFH1190', replacePlate: '浙C60602', replaceBrand: '江淮', replaceModel: 'HFC1190', replaceReason: '车辆原因', replaceReasonDesc: '排放升级', creator: '赵六', createTime: '2025-03-11 11:15' } + ]; + + // 历史记录:审批完成,审批状态均为审批完成 + var historyList = [ + { id: 'h1', replaceDate: '2025-02-15', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A10001', originalBrand: '东风', originalModel: 'DFH1180', replacePlate: '浙A10002', replaceBrand: '福田', replaceModel: 'BJ1180', replaceReason: '车辆原因', replaceReasonDesc: '原车报废', creator: '张三', createTime: '2025-02-10 09:00' }, + { id: 'h2', replaceDate: '2025-02-14', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B20001', originalBrand: '江淮', originalModel: 'HFC1180', replacePlate: '浙B20002', replaceBrand: '重汽', replaceModel: 'ZZ1180', replaceReason: '客户原因', replaceReasonDesc: '客户临时需求', creator: '李四', createTime: '2025-02-09 14:00' }, + { id: 'h3', replaceDate: '2025-02-13', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C30001', originalBrand: '重汽', originalModel: 'ZZ1160', replacePlate: '浙C30002', replaceBrand: '东风', replaceModel: 'DFH1160', replaceReason: '车辆原因', replaceReasonDesc: '使用年限到期', creator: '王五', createTime: '2025-02-08 10:30' }, + { id: 'h4', replaceDate: '2025-02-12', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A40001', originalBrand: '福田', originalModel: 'BJ1180', replacePlate: '浙A40002', replaceBrand: '江淮', replaceModel: 'HFC1180', replaceReason: '客户原因', replaceReasonDesc: '旺季加车', creator: '赵六', createTime: '2025-02-07 15:20' }, + { id: 'h5', replaceDate: '2025-02-11', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B50001', originalBrand: '东风', originalModel: 'DFH1190', replacePlate: '浙B50002', replaceBrand: '重汽', replaceModel: 'ZZ1190', replaceReason: '车辆原因', replaceReasonDesc: '事故车置换', creator: '张三', createTime: '2025-02-06 08:45' }, + { id: 'h6', replaceDate: '2025-02-10', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C60001', originalBrand: '江淮', originalModel: 'HFC1160', replacePlate: '浙C60002', replaceBrand: '福田', replaceModel: 'BJ1160', replaceReason: '客户原因', replaceReasonDesc: '临时项目', creator: '李四', createTime: '2025-02-05 11:00' }, + { id: 'h7', replaceDate: '2025-02-09', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A70001', originalBrand: '重汽', originalModel: 'ZZ1180', replacePlate: '浙A70002', replaceBrand: '东风', replaceModel: 'DFH1180', replaceReason: '车辆原因', replaceReasonDesc: '维修成本过高', creator: '王五', createTime: '2025-02-04 14:15' }, + { id: 'h8', replaceDate: '2025-02-08', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B80001', originalBrand: '福田', originalModel: 'BJ1190', replacePlate: '浙B80002', replaceBrand: '江淮', replaceModel: 'HFC1190', replaceReason: '客户原因', replaceReasonDesc: '车型升级', creator: '赵六', createTime: '2025-02-03 09:30' }, + { id: 'h9', replaceDate: '2025-02-07', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C90001', originalBrand: '东风', originalModel: 'DFH1160', replacePlate: '浙C90002', replaceBrand: '重汽', replaceModel: 'ZZ1160', replaceReason: '车辆原因', replaceReasonDesc: '年检未过', creator: '张三', createTime: '2025-02-02 16:00' }, + { id: 'h10', replaceDate: '2025-02-06', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A01001', originalBrand: '江淮', originalModel: 'HFC1180', replacePlate: '浙A01002', replaceBrand: '福田', replaceModel: 'BJ1180', replaceReason: '客户原因', replaceReasonDesc: '运力不足', creator: '李四', createTime: '2025-02-01 10:45' }, + { id: 'h11', replaceDate: '2025-02-05', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B02001', originalBrand: '重汽', originalModel: 'ZZ1190', replacePlate: '浙B02002', replaceBrand: '东风', replaceModel: 'DFH1190', replaceReason: '车辆原因', replaceReasonDesc: '尾气不达标', creator: '王五', createTime: '2025-01-31 13:20' }, + { id: 'h12', replaceDate: '2025-02-04', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C03001', originalBrand: '福田', originalModel: 'BJ1160', replacePlate: '浙C03002', replaceBrand: '江淮', replaceModel: 'HFC1160', replaceReason: '客户原因', replaceReasonDesc: '线路拓展', creator: '赵六', createTime: '2025-01-30 08:00' }, + { id: 'h13', replaceDate: '2025-02-03', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A04001', originalBrand: '东风', originalModel: 'DFH1180', replacePlate: '浙A04002', replaceBrand: '重汽', replaceModel: 'ZZ1180', replaceReason: '车辆原因', replaceReasonDesc: '核心部件损坏', creator: '张三', createTime: '2025-01-29 11:30' }, + { id: 'h14', replaceDate: '2025-02-02', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B05001', originalBrand: '江淮', originalModel: 'HFC1190', replacePlate: '浙B05002', replaceBrand: '福田', replaceModel: 'BJ1190', replaceReason: '客户原因', replaceReasonDesc: '季节性需求', creator: '李四', createTime: '2025-01-28 15:45' }, + { id: 'h15', replaceDate: '2025-02-01', replaceType: '永久替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C06001', originalBrand: '重汽', originalModel: 'ZZ1160', replacePlate: '浙C06002', replaceBrand: '东风', replaceModel: 'DFH1160', replaceReason: '车辆原因', replaceReasonDesc: '保险拒保', creator: '王五', createTime: '2025-01-27 09:15' }, + { id: 'h16', replaceDate: '2025-01-31', replaceType: '临时替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A07001', originalBrand: '福田', originalModel: 'BJ1180', replacePlate: '浙A07002', replaceBrand: '江淮', replaceModel: 'HFC1180', replaceReason: '客户原因', replaceReasonDesc: '合作试运行', creator: '赵六', createTime: '2025-01-26 12:00' }, + { id: 'h17', replaceDate: '2025-01-30', replaceType: '永久替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B08001', originalBrand: '东风', originalModel: 'DFH1190', replacePlate: '浙B08002', replaceBrand: '重汽', replaceModel: 'ZZ1190', replaceReason: '车辆原因', replaceReasonDesc: '油耗过高', creator: '张三', createTime: '2025-01-25 14:30' }, + { id: 'h18', replaceDate: '2025-01-29', replaceType: '临时替换', projectName: '杭州城配租赁项目', approvalStatus: '审批完成', originalPlate: '浙C09001', originalBrand: '江淮', originalModel: 'HFC1160', replacePlate: '浙C09002', replaceBrand: '福田', replaceModel: 'BJ1160', replaceReason: '客户原因', replaceReasonDesc: '活动保障', creator: '李四', createTime: '2025-01-24 10:20' }, + { id: 'h19', replaceDate: '2025-01-28', replaceType: '永久替换', projectName: '嘉兴氢能示范项目', approvalStatus: '审批完成', originalPlate: '浙A10003', originalBrand: '重汽', originalModel: 'ZZ1180', replacePlate: '浙A10004', replaceBrand: '东风', replaceModel: 'DFH1180', replaceReason: '车辆原因', replaceReasonDesc: '配件停产', creator: '王五', createTime: '2025-01-23 16:45' }, + { id: 'h20', replaceDate: '2025-01-27', replaceType: '临时替换', projectName: '上海物流租赁项目', approvalStatus: '审批完成', originalPlate: '浙B11001', originalBrand: '福田', originalModel: 'BJ1190', replacePlate: '浙B11002', replaceBrand: '江淮', replaceModel: 'HFC1190', replaceReason: '客户原因', replaceReasonDesc: '新业务启动', creator: '赵六', createTime: '2025-01-22 08:30' } + ]; + + var appliedFilter = _appliedFilter[0]; + + var filteredOngoing = useMemo(function () { + var list = ongoingList.filter(function (r) { + if (appliedFilter.replaceDateRange && appliedFilter.replaceDateRange.length === 2) { + var start = appliedFilter.replaceDateRange[0] && appliedFilter.replaceDateRange[0].format ? appliedFilter.replaceDateRange[0].format('YYYY-MM-DD') : ''; + var end = appliedFilter.replaceDateRange[1] && appliedFilter.replaceDateRange[1].format ? appliedFilter.replaceDateRange[1].format('YYYY-MM-DD') : ''; + if (start && (r.replaceDate || '') < start) return false; + if (end && (r.replaceDate || '') > end) return false; + } + if (appliedFilter.replaceType && r.replaceType !== appliedFilter.replaceType) return false; + if (appliedFilter.projectName && r.projectName !== appliedFilter.projectName) return false; + var approval = appliedFilter.approvalStatus; + if (approval && approval.length > 0 && approval.indexOf('全部') === -1 && approval.indexOf(r.approvalStatus) === -1) return false; + if (appliedFilter.originalPlate && (r.originalPlate || '').indexOf(appliedFilter.originalPlate) === -1) return false; + if (appliedFilter.replacePlate && (r.replacePlate || '').indexOf(appliedFilter.replacePlate) === -1) return false; + if (appliedFilter.replaceReason && appliedFilter.replaceReason !== '全部' && r.replaceReason !== appliedFilter.replaceReason) return false; + if (appliedFilter.creator && r.creator !== appliedFilter.creator) return false; + if (appliedFilter.createTimeRange && appliedFilter.createTimeRange.length === 2) { + var cs = appliedFilter.createTimeRange[0] && appliedFilter.createTimeRange[0].format ? appliedFilter.createTimeRange[0].format('YYYY-MM-DD') : ''; + var ce = appliedFilter.createTimeRange[1] && appliedFilter.createTimeRange[1].format ? appliedFilter.createTimeRange[1].format('YYYY-MM-DD') : ''; + var ct = (r.createTime || '').slice(0, 10); + if (cs && ct < cs) return false; + if (ce && ct > ce) return false; + } + return true; + }); + return list; + }, [appliedFilter]); + + var filteredHistory = useMemo(function () { + var list = historyList.filter(function (r) { + if (appliedFilter.replaceDateRange && appliedFilter.replaceDateRange.length === 2) { + var start = appliedFilter.replaceDateRange[0] && appliedFilter.replaceDateRange[0].format ? appliedFilter.replaceDateRange[0].format('YYYY-MM-DD') : ''; + var end = appliedFilter.replaceDateRange[1] && appliedFilter.replaceDateRange[1].format ? appliedFilter.replaceDateRange[1].format('YYYY-MM-DD') : ''; + if (start && (r.replaceDate || '') < start) return false; + if (end && (r.replaceDate || '') > end) return false; + } + if (appliedFilter.replaceType && r.replaceType !== appliedFilter.replaceType) return false; + if (appliedFilter.projectName && r.projectName !== appliedFilter.projectName) return false; + if (appliedFilter.originalPlate && (r.originalPlate || '').indexOf(appliedFilter.originalPlate) === -1) return false; + if (appliedFilter.replacePlate && (r.replacePlate || '').indexOf(appliedFilter.replacePlate) === -1) return false; + if (appliedFilter.replaceReason && appliedFilter.replaceReason !== '全部' && r.replaceReason !== appliedFilter.replaceReason) return false; + if (appliedFilter.creator && r.creator !== appliedFilter.creator) return false; + if (appliedFilter.createTimeRange && appliedFilter.createTimeRange.length === 2) { + var cs = appliedFilter.createTimeRange[0] && appliedFilter.createTimeRange[0].format ? appliedFilter.createTimeRange[0].format('YYYY-MM-DD') : ''; + var ce = appliedFilter.createTimeRange[1] && appliedFilter.createTimeRange[1].format ? appliedFilter.createTimeRange[1].format('YYYY-MM-DD') : ''; + var ct = (r.createTime || '').slice(0, 10); + if (cs && ct < cs) return false; + if (ce && ct > ce) return false; + } + return true; + }); + return list; + }, [appliedFilter]); + + var handleQuery = useCallback(function () { + _appliedFilter[1]({ + replaceDateRange: _replaceDateRange[0], + replaceType: _replaceType[0], + projectName: _projectName[0], + approvalStatus: _approvalStatus[0] ? _approvalStatus[0].slice() : ['全部'], + originalPlate: _originalPlate[0], + replacePlate: _replacePlate[0], + replaceReason: _replaceReason[0], + creator: _creator[0], + createTimeRange: _createTimeRange[0] + }); + }, []); + + var handleReset = useCallback(function () { + _replaceDateRange[1](null); + _replaceType[1](undefined); + _projectName[1](undefined); + _approvalStatus[1](['全部']); + _originalPlate[1](undefined); + _replacePlate[1](undefined); + _replaceReason[1](undefined); + _creator[1](undefined); + _createTimeRange[1](null); + _appliedFilter[1]({ + replaceDateRange: null, + replaceType: undefined, + projectName: undefined, + approvalStatus: ['全部'], + originalPlate: undefined, + replacePlate: undefined, + replaceReason: undefined, + creator: undefined, + createTimeRange: null + }); + }, []); + + var handleApprovalStatusChange = useCallback(function (v) { + if (!v || v.length === 0) { _approvalStatus[1](['全部']); return; } + if (v.indexOf('全部') !== -1 && v.length > 1) { + var prev = _approvalStatus[0] || []; + var hadAllOnly = prev.length === 1 && prev.indexOf('全部') !== -1; + _approvalStatus[1](hadAllOnly ? v.filter(function (x) { return x !== '全部'; }) : ['全部']); + return; + } + _approvalStatus[1](v); + }, []); + + var filterLabelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' }; + var filterItemStyle = { marginBottom: 12 }; + var filterControlStyle = { width: '100%' }; + + function getOperationButtons(record, isHistory) { + if (isHistory) { + var viewBtn = React.createElement(Button, { key: 'view', type: 'link', size: 'small', onClick: function () { message.info('查看(跳转替换车管理-查看)'); } }, '查看'); + var toPermanentBtn = record.replaceType === '临时替换' ? React.createElement(Button, { key: 'toPermanent', type: 'link', size: 'small', onClick: function () { _toPermanentModalRecord[1](record); _toPermanentModalVisible[1](true); } }, '转永久替换') : null; + return React.createElement('div', { style: { display: 'flex', gap: 4, flexWrap: 'wrap' } }, viewBtn, toPermanentBtn); + } + var status = record.approvalStatus; + var items = []; + if (['待审批', '审批中', '审批驳回', '未提交', '撤回'].indexOf(status) !== -1) { + items.push(React.createElement(Button, { key: 'view', type: 'link', size: 'small', onClick: function () { message.info('查看(跳转替换车管理-查看)'); } }, '查看')); + } + if (['未提交', '审批驳回', '撤回'].indexOf(status) !== -1) { + items.push(React.createElement(Button, { key: 'edit', type: 'link', size: 'small', onClick: function () { message.info('编辑(跳转替换车管理-编辑)'); } }, '编辑')); + } + if (status === '审批中') { + items.push(React.createElement(Button, { key: 'withdraw', type: 'link', size: 'small', danger: true, onClick: function () { _withdrawModalRecord[1](record); _withdrawModalVisible[1](true); } }, '撤回')); + } + return React.createElement('div', { style: { display: 'flex', gap: 4, flexWrap: 'wrap' } }, items); + } + + var tableColumns = [ + { title: '替换日期', dataIndex: 'replaceDate', key: 'replaceDate', width: 110, fixed: 'left' }, + { title: '替换类型', dataIndex: 'replaceType', key: 'replaceType', width: 100, fixed: 'left' }, + { title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, fixed: 'left' }, + { title: '审批状态', dataIndex: 'approvalStatus', key: 'approvalStatus', width: 100 }, + { title: '被替换车车牌号', dataIndex: 'originalPlate', key: 'originalPlate', width: 120 }, + { title: '被替换车品牌', dataIndex: 'originalBrand', key: 'originalBrand', width: 100 }, + { title: '被替换车型号', dataIndex: 'originalModel', key: 'originalModel', width: 110 }, + { title: '替换车车牌号', dataIndex: 'replacePlate', key: 'replacePlate', width: 120 }, + { title: '替换车品牌', dataIndex: 'replaceBrand', key: 'replaceBrand', width: 100 }, + { title: '替换车型号', dataIndex: 'replaceModel', key: 'replaceModel', width: 110 }, + { title: '替换原因', dataIndex: 'replaceReason', key: 'replaceReason', width: 100 }, + { title: '替换原因说明', dataIndex: 'replaceReasonDesc', key: 'replaceReasonDesc', width: 120, ellipsis: true }, + { title: '创建人', dataIndex: 'creator', key: 'creator', width: 90 }, + { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 150 }, + { title: '操作', key: 'action', width: 160, fixed: 'right', render: function (_, record) { return getOperationButtons(record, _activeTab[0] === 'history'); } } + ]; + + var filterItems = [ + React.createElement('div', { key: 'replaceDate', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '替换日期'), + React.createElement(RangePicker, { style: filterControlStyle, placeholder: ['请选择开始时间', '请选择结束时间'], value: _replaceDateRange[0], onChange: function (v) { _replaceDateRange[1](v); } })), + React.createElement('div', { key: 'replaceType', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '替换类型'), + React.createElement(Select, { placeholder: '请选择', style: filterControlStyle, value: _replaceType[0], onChange: function (v) { _replaceType[1](v); }, allowClear: true, options: replaceTypeOptions })), + React.createElement('div', { key: 'projectName', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '项目名称'), + React.createElement(Select, { placeholder: '请输入或选择项目名称', style: filterControlStyle, value: _projectName[0], onChange: function (v) { _projectName[1](v); }, allowClear: true, showSearch: true, options: projectNameOptions, filterOption: function (input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } })), + React.createElement('div', { key: 'approvalStatus', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '审批状态'), + React.createElement(Select, { mode: 'multiple', placeholder: '请选择', style: filterControlStyle, value: _approvalStatus[0], onChange: handleApprovalStatusChange, options: approvalStatusOptions })), + React.createElement('div', { key: 'originalPlate', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '被替换车车牌号'), + React.createElement(Select, { placeholder: '请输入或选择车牌号', style: filterControlStyle, value: _originalPlate[0], onChange: function (v) { _originalPlate[1](v); }, allowClear: true, showSearch: true, options: plateOptions, filterOption: function (input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } })), + React.createElement('div', { key: 'replacePlate', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '替换车车牌号'), + React.createElement(Select, { placeholder: '请输入或选择车牌号', style: filterControlStyle, value: _replacePlate[0], onChange: function (v) { _replacePlate[1](v); }, allowClear: true, showSearch: true, options: plateOptions, filterOption: function (input, opt) { return (opt.label || '').toString().toLowerCase().indexOf((input || '').toLowerCase()) !== -1; } })), + React.createElement('div', { key: 'replaceReason', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '替换原因'), + React.createElement(Select, { placeholder: '请选择', style: filterControlStyle, value: _replaceReason[0], onChange: function (v) { _replaceReason[1](v); }, allowClear: true, options: replaceReasonOptions })), + React.createElement('div', { key: 'creator', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '创建人'), + React.createElement(Select, { placeholder: '请选择创建人', style: filterControlStyle, value: _creator[0], onChange: function (v) { _creator[1](v); }, allowClear: true, options: creatorOptions })), + React.createElement('div', { key: 'createTime', style: filterItemStyle }, + React.createElement('div', { style: filterLabelStyle }, '创建时间'), + React.createElement(RangePicker, { style: filterControlStyle, placeholder: ['请选择开始时间', '请选择结束时间'], value: _createTimeRange[0], onChange: function (v) { _createTimeRange[1](v); } })) + ]; + + var filterCount = _filterExpanded[0] ? 9 : 3; + var filterNodes = []; + for (var i = 0; i < filterCount && i < filterItems.length; i++) { + filterNodes.push(filterItems[i]); + } + + var _page = useState(1); + var _pageSize = useState(10); + var page = _page[0]; + var setPage = _page[1]; + var pageSize = _pageSize[0]; + var setPageSize = _pageSize[1]; + var currentList = _activeTab[0] === 'ongoing' ? filteredOngoing : filteredHistory; + var displayList = useMemo(function () { + var start = (page - 1) * pageSize; + return currentList.slice(start, start + pageSize); + }, [currentList, page, pageSize]); + + var rowSelection = { + selectedRowKeys: _selectedRowKeys[0], + onChange: function (keys) { _selectedRowKeys[1](keys); }, + fixed: true + }; + + var requirementContent = `替换车管理(2026年3月3日版本) +一个「数字化资产ONEOS运管平台」中的「运维管理」「车辆业务」「替换车管理」模块 + +1.面包屑: +1.1.运维管理-车辆业务-替换车管理 + +筛选与列表分为2个卡片; + +2.筛选: +支持通过替换日期、替换类型、项目名称、审批状态、被替换车车牌号、替换车车牌号、替换原因、创建人、创建时间进行筛选,右侧为重置、查询、展开/收起(筛选条件以3列显示,默认显示一行,点击展开/收起对筛选栏卡片进行展开/收起所有筛选条件),点击查询后,筛选条件与列表内容联动。点击重置会回到默认筛选条件并在列表展示结果: + +2.1.替换日期:日期选择器,支持单输入框内双日历选择开始-结束时间,默认提示文本为:请选择开始时间、请选择结束时间; +2.2.替换类型:选择器,分为永久替换、临时替换两种方式; +2.3.项目名称:选择器,支持输入框中输入关键内容进行搜索,下拉匹配相应项; +2.4.审批状态:选择器,分为全部、待审批、审批中、审批驳回、未提交、撤回; +2.5.被替换车车牌号:选择器,支持输入框中输入关键内容进行搜索,下拉匹配相应项; +2.6.替换车车牌号:选择器,支持输入框中输入关键内容进行搜索,下拉匹配相应项; +2.7.替换原因:选择器,分为全部、客户原因、车辆原因; +2.8.创建人:选择器,下拉选择所有创建人; +2.9.创建时间:日期选择器,支持单输入框内双日历选择开始-结束时间,默认提示文本为:请选择开始时间、请选择结束时间; + +3.列表:列表右上角为新增、导出,首列为多选,支持多选后导出对应条目; +列表展示所有替换车记录,分为进行中、历史记录两个tab,字段依次为:替换日期、替换类型、项目名称、审批状态、被替换车车牌号、被替换车品牌、被替换车型号、替换车车牌号、替换车品牌、替换车型号、替换原因、替换原因说明、创建人、创建时间、操作; + +3.1.进行中:显示替换车申请流程未结束、暂存的记录; + 3.1.1.替换日期:显示格式为:YYYY-MM-DD,显示替换车申请表单中设置的替换日期; + 3.1.2.替换类型:分为:临时替换、永久替换两种,根据替换车申请表单中设置的替换类型显示; + 3.1.3.项目名称:显示替换车申请表单中设置的项目名称; + 3.1.4.审批状态:显示替换车申请当前审批状态,分为待审批、审批中、审批驳回、未提交、撤回; + 3.1.4.1.待审批:发起人已提交,但还没有任何流程节点完成审批; + 3.1.4.2.审批中:发起人已提交,已有1个以上节点完成审批,但未完成最终节点审批; + 3.1.4.3.审批驳回:发起人已提交,任意流程节点驳回,该状态下操作列支持编辑和重新提交; + 3.1.4.4.未提交:发起人仅保存,但未提交审批; + 3.1.4.5.撤回:发起人主动撤回审批流程; + 3.1.5.被替换车车牌号:显示替换车申请表单中被替换车车牌号; + 3.1.6.被替换车品牌:显示替换车申请表单中被替换车品牌; + 3.1.7.被替换车型号:显示替换车申请表单中被替换车型号; + 3.1.8.替换车车牌号:显示替换车申请表单中替换车车牌号; + 3.1.9.替换车品牌:显示替换车申请表单中替换车品牌; + 3.1.10.替换车型号:显示替换车申请表单中替换车型号; + 3.1.11.替换原因:显示替换车申请表单中替换原因; + 3.1.12.替换原因说明:显示替换车申请表单中替换原因说明; + 3.1.13.创建人:显示替换车申请表单中创建人; + 3.1.14.创建时间:显示替换车申请表单中创建时间,显示格式为:YYYY-MM-DD HH:MM; + 3.1.15.操作:查看、编辑、撤回; + 3.1.15.1.查看:当「审批状态」为「待审批」「审批中」「审批驳回」「未提交」「撤回」时显示,点击跳转替换车管理-查看页面; + 3.1.15.2.编辑:当「审批状态」为「未提交」「审批驳回」「撤回」时显示,点击跳转替换车管理-编辑页面; + 3.1.15.3.撤回:当「审批状态」为「审批中」时显示,点击撤回合同时进行二次确认,提示语:是否确认撤回该替换车申请; + +3.2.历史记录:显示替换车申请流程已结束的记录; + 3.2.1.替换日期:显示格式为:YYYY-MM-DD,显示替换车申请表单中设置的替换日期; + 3.2.2.替换类型:分为:临时替换、永久替换两种,根据替换车申请表单中设置的替换类型显示; + 3.2.3.项目名称:显示替换车申请表单中设置的项目名称; + 3.2.4.审批状态:历史记录中所有审批状态为审批完成; + 3.2.5.被替换车车牌号:显示替换车申请表单中被替换车车牌号; + 3.2.6.被替换车品牌:显示替换车申请表单中被替换车品牌; + 3.2.7.被替换车型号:显示替换车申请表单中被替换车型号; + 3.2.8.替换车车牌号:显示替换车申请表单中替换车车牌号; + 3.2.9.替换车品牌:显示替换车申请表单中替换车品牌; + 3.2.10.替换车型号:显示替换车申请表单中替换车型号; + 3.2.11.替换原因:显示替换车申请表单中替换原因; + 3.2.12.替换原因说明:显示替换车申请表单中替换原因说明; + 3.2.13.创建人:显示替换车申请表单中创建人; + 3.2.14.创建时间:显示替换车申请表单中创建时间,显示格式为:YYYY-MM-DD HH:MM; + 3.2.15.操作:查看、转永久替换; + 3.2.15.1.查看:点击跳转替换车管理-查看页面; + 3.2.15.2.转永久替换:点击转永久替换,进行二次确认,提示语:是否确认转永久替换,点击提交直接转为永久替换; + +列表右下方为分页符。`; + + var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' }; + var reqTitleStyle = { fontSize: 18, fontWeight: 600, marginBottom: 16, color: 'rgba(0,0,0,0.85)' }; + var reqSectionStyle = { fontSize: 15, fontWeight: 600, marginTop: 16, marginBottom: 8, color: 'rgba(0,0,0,0.85)' }; + var reqItemStyle = { fontSize: 13, marginLeft: 32, marginTop: 4, marginBottom: 2, lineHeight: 1.6, color: 'rgba(0,0,0,0.75)' }; + + return React.createElement('div', { style: layoutStyle }, + React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } }, + React.createElement(Breadcrumb, { + items: [ + { title: '运维管理' }, + { title: '车辆业务' }, + { title: '替换车管理' } + ] + }), + React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { _requirementModalVisible[1](true); } }, '查看需求说明') + ), + React.createElement(Card, { style: { marginBottom: 16 } }, + React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', alignItems: 'start' } }, filterNodes), + 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(Button, { type: 'link', size: 'small', onClick: function () { _filterExpanded[1](!_filterExpanded[0]); } }, _filterExpanded[0] ? '收起' : '展开') + ) + ), + React.createElement(Card, null, + React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' } }, + React.createElement(Tabs, { + activeKey: _activeTab[0], + onChange: function (k) { _activeTab[1](k); _selectedRowKeys[1]([]); setPage(1); }, + items: [ + { key: 'ongoing', label: '进行中' }, + { key: 'history', label: '历史记录' } + ] + }), + React.createElement('div', { style: { display: 'flex', gap: 8 } }, + React.createElement(Button, { type: 'primary', onClick: function () { message.info('新增替换车申请(原型)'); } }, '新增'), + React.createElement(Button, { onClick: function () { message.info('导出选中记录(原型)'); } }, '导出') + ) + ), + React.createElement(Table, { + rowKey: 'id', + rowSelection: rowSelection, + columns: tableColumns, + dataSource: displayList, + size: 'small', + scroll: { x: 1600 }, + pagination: { + current: page, + pageSize: pageSize, + total: currentList.length, + showSizeChanger: true, + showQuickJumper: true, + showTotal: function (t) { return '共 ' + t + ' 条'; }, + onChange: function (p, ps) { setPage(p); if (ps) setPageSize(ps); } + } + }) + ), + React.createElement(Modal, { + title: '是否确认撤回该替换车申请', + open: _withdrawModalVisible[0], + onCancel: function () { _withdrawModalVisible[1](false); _withdrawModalRecord[1](null); }, + onOk: function () { message.success('已撤回(原型)'); _withdrawModalVisible[1](false); _withdrawModalRecord[1](null); }, + okText: '确定', + cancelText: '取消' + }), + React.createElement(Modal, { + title: '是否确认转永久替换', + open: _toPermanentModalVisible[0], + onCancel: function () { _toPermanentModalVisible[1](false); _toPermanentModalRecord[1](null); }, + onOk: function () { message.success('已转为永久替换(原型)'); _toPermanentModalVisible[1](false); _toPermanentModalRecord[1](null); }, + okText: '提交', + cancelText: '取消' + }), + React.createElement(Modal, { + title: '需求说明', + open: _requirementModalVisible[0], + onCancel: function () { _requirementModalVisible[1](false); }, + width: 720, + footer: React.createElement(Button, { onClick: function () { _requirementModalVisible[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 } }, requirementContent)) + ) + ); +};