运维/财务:还车应结款分钟级时间与费用明细交互优化
- 还车应结款/查看/费用明细:交车/还车时间统一显示到分钟 - 待审批与审批中状态操作列支持撤回 - 费用明细:已收租金可编辑、预付款退费展示最后一辆车提示、证件丢失费用可编辑 - 同步更新相关需求说明文案 Made-with: Cursor
This commit is contained in:
@@ -28,6 +28,22 @@ const Component = function () {
|
||||
return n.toFixed(2);
|
||||
}
|
||||
|
||||
function fmtYMDHM(v) {
|
||||
if (v === null || v === undefined) return '-';
|
||||
var s = String(v).trim();
|
||||
if (!s) return '-';
|
||||
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}/.test(s)) return s.slice(0, 16);
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s + ' 00:00';
|
||||
try {
|
||||
var d = new Date(s.replace(/-/g, '/'));
|
||||
if (isNaN(d.getTime())) return s;
|
||||
var p2 = function (n) { return n < 10 ? '0' + n : '' + n; };
|
||||
return d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate()) + ' ' + p2(d.getHours()) + ':' + p2(d.getMinutes());
|
||||
} catch (e) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// 页面样式
|
||||
var layoutStyle = { padding: '16px 24px 72px', background: '#f5f5f5', minHeight: '100vh' };
|
||||
var cardStyle = { marginBottom: 16 };
|
||||
@@ -41,8 +57,8 @@ const Component = function () {
|
||||
contractCode: 'LNZLHT20251106001',
|
||||
projectName: '嘉兴腾4.5T租赁',
|
||||
customerName: '嘉兴某某物流有限公司',
|
||||
deliveryTime: '2026-02-01',
|
||||
returnTime: '2026-02-27',
|
||||
deliveryTime: '2026-02-01 09:30',
|
||||
returnTime: '2026-02-27 16:20',
|
||||
fragileInsurance: '是',
|
||||
tireInsurance: '否',
|
||||
maintenanceInsurance: '是'
|
||||
@@ -268,8 +284,8 @@ const Component = function () {
|
||||
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 160, ellipsis: true },
|
||||
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, ellipsis: true },
|
||||
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 140, ellipsis: true },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 110 },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 110 },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{
|
||||
title: '易损保', dataIndex: 'fragileInsurance', key: 'fragileInsurance', width: 110,
|
||||
render: function (v) {
|
||||
|
||||
@@ -34,6 +34,22 @@ const Component = function () {
|
||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
|
||||
}
|
||||
|
||||
function fmtYMDHM(v) {
|
||||
if (v === null || v === undefined) return '-';
|
||||
var s = String(v).trim();
|
||||
if (!s) return '-';
|
||||
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}/.test(s)) return s.slice(0, 16);
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s + ' 00:00';
|
||||
try {
|
||||
var d = new Date(s.replace(/-/g, '/'));
|
||||
if (isNaN(d.getTime())) return s;
|
||||
var p2 = function (n) { return n < 10 ? '0' + n : '' + n; };
|
||||
return d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate()) + ' ' + p2(d.getHours()) + ':' + p2(d.getMinutes());
|
||||
} catch (e) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function toFixed2(v) {
|
||||
if (v === null || v === undefined || v === '') return '';
|
||||
var n = typeof v === 'number' ? v : parseFloat(v);
|
||||
@@ -53,8 +69,8 @@ const Component = function () {
|
||||
contractCode: 'LNZLHT20251106001',
|
||||
projectName: '嘉兴腾4.5T租赁',
|
||||
customerName: '嘉兴某某物流有限公司',
|
||||
deliveryTime: '2026-02-01',
|
||||
returnTime: '2026-02-27',
|
||||
deliveryTime: '2026-02-01 09:30',
|
||||
returnTime: '2026-02-27 16:20',
|
||||
fragileInsurance: '是',
|
||||
tireInsurance: '否',
|
||||
maintenanceInsurance: '是'
|
||||
@@ -70,6 +86,11 @@ const Component = function () {
|
||||
};
|
||||
}, [vehicleDetail]);
|
||||
|
||||
// 原型判断:当前合同仅展示 1 辆车,则视为“最后一辆车还车”
|
||||
var isLastVehicleInContract = useMemo(function () {
|
||||
return (vehicleDetail || []).length === 1;
|
||||
}, [vehicleDetail]);
|
||||
|
||||
// 费用统计
|
||||
var statsState = useState({
|
||||
depositAmount: '5000.00',
|
||||
@@ -386,7 +407,7 @@ const Component = function () {
|
||||
setOperationRows(function (p) {
|
||||
var next = p.map(function (r) {
|
||||
var n = {}; for (var k in r) n[k] = r[k];
|
||||
if (n.feeItem === '证件丢失费用') n.amount = operationAuto.docLossFee;
|
||||
if (n.feeItem === '证件丢失费用' && !String(n.amount || '').trim()) n.amount = operationAuto.docLossFee;
|
||||
if (n.feeItem === '送车服务费') n.amount = operationAuto.deliveryServiceFee;
|
||||
if (n.feeItem === '接车服务费') n.amount = operationAuto.receiveServiceFee;
|
||||
if (n.feeItem === '轮胎磨损费用' && !String(n.amount || '').trim()) n.amount = operationAuto.tireWearFee;
|
||||
@@ -647,7 +668,7 @@ var requirementDocContent = useMemo(function () {
|
||||
4.13.附件:附件上传按钮,文案为:上传附件,支持多个附件;
|
||||
4.14.操作:除固定费用项外,其余操作中为删除;
|
||||
列表下方为车辆租金:包含本期账单已收租金、车辆实际租金、车辆应退租金;
|
||||
4.15.本期账单已收租金:输入框(禁用),反写本期账单实际到账租金(从租赁账单中,首期由于未和用友YS打通,先显示为0,对接完成后显示财务实际到账金额);
|
||||
4.15.本期账单已收租金:输入框(可编辑),反写本期账单该车辆实收款租金金额(后期与用友YS打通后,显示财务到账金额)
|
||||
4.16.车辆实际租金:输入框(可编辑),自动计算车辆实际租金,按照:(车辆月租金/30)*(账单开始日期-还车日期总天数,取整)
|
||||
4.17.车辆应退租金:输入框(可编辑),根据:本期账单已收租金-车辆实际租金计算并反写;
|
||||
|
||||
@@ -664,7 +685,7 @@ var requirementDocContent = useMemo(function () {
|
||||
5.9.还车氢量:格式为:xx.xxMPa,保留2位小数,从该车辆交车在该合同还车时间氢量获取;
|
||||
5.10.退还车氢气单价:xx.xx元,从车辆租赁合同中获取;
|
||||
5.11.能源费补缴金额:右侧为2个输入框,分别为氢费补缴金额、电费补缴金额,支持2位小数,后缀为元;
|
||||
5.12.预付款退费金额:输入框,支持2位小数,后缀为元;输入框下方显示项目预充值余额;
|
||||
5.12.预付款退费金额:输入框,支持2位小数,后缀为元;输入框下方显示项目预充值余额,如果当前租赁合同已是最后一辆车还车,则输入框右侧加红提示:当前车辆为该合同最后一辆车;
|
||||
|
||||
6.运维部:仅由运维部人员进行填写;标题栏标题为运维部,后方为总金额、提交人、状态(待提交、已提交),该部分只有运维部能查看;
|
||||
6.1.总金额:显示运维部所有费用项费用金额总额;
|
||||
@@ -717,8 +738,8 @@ var requirementDocContent = useMemo(function () {
|
||||
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 160, ellipsis: true },
|
||||
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, ellipsis: true },
|
||||
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 140, ellipsis: true },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 110 },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 110 },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{
|
||||
title: '易损保', dataIndex: 'fragileInsurance', key: 'fragileInsurance', width: 110,
|
||||
render: function (v) {
|
||||
@@ -921,7 +942,7 @@ var requirementDocContent = useMemo(function () {
|
||||
var readOnly = meta.status === '已提交';
|
||||
var fee = r && r.feeItem;
|
||||
var disabled = readOnly;
|
||||
if (fee === '送车服务费' || fee === '接车服务费' || fee === '证件丢失费用') disabled = true;
|
||||
if (fee === '送车服务费' || fee === '接车服务费') disabled = true;
|
||||
return React.createElement(Input, { value: v, onChange: function (e) { ref.updateOperationRow(r.key, 'amount', e.target.value); }, placeholder: '0.00', addonAfter: '元', disabled: disabled });
|
||||
}
|
||||
},
|
||||
@@ -1130,7 +1151,13 @@ return React.createElement('div', { style: layoutStyle },
|
||||
React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 12 } },
|
||||
React.createElement('div', null,
|
||||
React.createElement('div', { style: { fontSize: 12, color: '#666', marginBottom: 6 } }, '本期账单已收租金'),
|
||||
React.createElement(Input, { value: billInfo.receivedRent, addonAfter: '元', disabled: true })
|
||||
React.createElement(Input, {
|
||||
value: billInfo.receivedRent,
|
||||
onChange: function (e) { var v = e.target.value; setBillInfo(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.receivedRent = v; return n; }); },
|
||||
placeholder: '0.00',
|
||||
addonAfter: '元',
|
||||
disabled: businessServiceMeta.status === '已提交'
|
||||
})
|
||||
),
|
||||
React.createElement('div', null,
|
||||
React.createElement('div', { style: { fontSize: 12, color: '#666', marginBottom: 6 } }, RequiredLabel('车辆实际租金')),
|
||||
@@ -1218,7 +1245,12 @@ return React.createElement('div', { style: layoutStyle },
|
||||
React.createElement('div', { style: { marginBottom: 8, fontWeight: 500 } }, RequiredLabel('预付款退费金额')),
|
||||
React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 12 } },
|
||||
React.createElement('div', null,
|
||||
React.createElement(Input, { value: energy.prepayRefund, onChange: function (e) { setEnergy(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.prepayRefund = e.target.value; return n; }); }, placeholder: '0.00', addonAfter: '元', style: { width: '100%' }, disabled: energyMeta.status === '已提交' })
|
||||
React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 12 } },
|
||||
React.createElement('div', { style: { flex: 1, minWidth: 0 } },
|
||||
React.createElement(Input, { value: energy.prepayRefund, onChange: function (e) { setEnergy(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.prepayRefund = e.target.value; return n; }); }, placeholder: '0.00', addonAfter: '元', style: { width: '100%' }, disabled: energyMeta.status === '已提交' })
|
||||
),
|
||||
isLastVehicleInContract ? React.createElement('span', { style: { color: '#f5222d', fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap' } }, '当前车辆为该合同最后一辆车') : null
|
||||
)
|
||||
),
|
||||
React.createElement('div', null),
|
||||
React.createElement('div', null),
|
||||
|
||||
@@ -27,6 +27,22 @@ var message = antd.message;
|
||||
return dd.getFullYear() + '-' + p2(dd.getMonth() + 1) + '-' + p2(dd.getDate());
|
||||
}
|
||||
|
||||
function fmtYMDHM(v) {
|
||||
if (v === null || v === undefined) return '-';
|
||||
var s = String(v).trim();
|
||||
if (!s) return '-';
|
||||
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}/.test(s)) return s.slice(0, 16);
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s + ' 00:00';
|
||||
try {
|
||||
var d = new Date(s.replace(/-/g, '/'));
|
||||
if (isNaN(d.getTime())) return s;
|
||||
var p2 = function (n) { return n < 10 ? '0' + n : '' + n; };
|
||||
return d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate()) + ' ' + p2(d.getHours()) + ':' + p2(d.getMinutes());
|
||||
} catch (e) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function fmtMoney(v) {
|
||||
var n = typeof v === 'number' ? v : parseFloat(v);
|
||||
if (isNaN(n)) n = 0;
|
||||
@@ -83,8 +99,8 @@ var message = antd.message;
|
||||
plateNo: '粤AGP5621',
|
||||
businessDept: '业务一部',
|
||||
businessOwner: '张经理',
|
||||
deliveryTime: '2026-02-01',
|
||||
returnTime: '2026-02-27',
|
||||
deliveryTime: '2026-02-01 09:30',
|
||||
returnTime: '2026-02-27 16:20',
|
||||
returnPerson: '陈还车'
|
||||
},
|
||||
{
|
||||
@@ -100,8 +116,8 @@ var message = antd.message;
|
||||
plateNo: '浙F03218F',
|
||||
businessDept: '业务二部',
|
||||
businessOwner: '李主管',
|
||||
deliveryTime: '2026-01-10',
|
||||
returnTime: '2026-02-20',
|
||||
deliveryTime: '2026-01-10 10:00',
|
||||
returnTime: '2026-02-20 18:05',
|
||||
returnPerson: '周还车'
|
||||
},
|
||||
{
|
||||
@@ -117,8 +133,8 @@ var message = antd.message;
|
||||
plateNo: '京A29256F',
|
||||
businessDept: '业务三部',
|
||||
businessOwner: '王总',
|
||||
deliveryTime: '2025-08-01',
|
||||
returnTime: '2026-02-02',
|
||||
deliveryTime: '2025-08-01 08:30',
|
||||
returnTime: '2026-02-02 11:15',
|
||||
returnPerson: '刘还车'
|
||||
},
|
||||
{
|
||||
@@ -134,8 +150,8 @@ var message = antd.message;
|
||||
plateNo: '苏E8K2P1',
|
||||
businessDept: '业务一部',
|
||||
businessOwner: '张经理',
|
||||
deliveryTime: '2026-02-15',
|
||||
returnTime: '2026-02-26',
|
||||
deliveryTime: '2026-02-15 13:40',
|
||||
returnTime: '2026-02-26 09:10',
|
||||
returnPerson: '孙还车'
|
||||
},
|
||||
{
|
||||
@@ -342,14 +358,14 @@ var requirementDocContent = useMemo(function () {
|
||||
2.6.车牌号:显示合同对应车牌号;
|
||||
2.7.业务部门:显示合同对应业务部门;
|
||||
2.8.业务负责人:显示合同对应业务负责人;
|
||||
2.9.交车时间:显示该车辆交车时间;
|
||||
2.10.还车时间:显示该车辆还车时间;
|
||||
2.9.交车时间:显示该车辆交车时间,格式为:YYYY-MM-DD HH:MM;
|
||||
2.10.还车时间:显示该车辆还车时间,格式为:YYYY-MM-DD HH:MM;
|
||||
2.11.还车人:显示该车辆还车人姓名;
|
||||
2.12.操作:查看、生成账单、费用明细、撤回;
|
||||
2.12.1.查看:点击跳转还车应结款-查看页面;
|
||||
2.12.2.生成账单:点击生成账单,弹框显示账单界面,审批状态为待审批的记录才可生成账单,其他状态生成账单隐藏;
|
||||
2.12.3.费用明细:点击跳转还车应结款-费用明细页面,审批状态为待审批、审批中、审批完成时,不显示费用明细;
|
||||
2.12.4.撤回:审批状态为审批中时,不显示费用明细点击二次确认,提示:是否确认撤回,点击确定后,提示:撤回成功,同时审批状态修改为撤回;
|
||||
2.12.4.撤回:审批状态为待审批、审批中时,不显示费用明细点击二次确认,提示:是否确认撤回,点击确定后,提示:撤回成功,同时审批状态修改为撤回;
|
||||
2.13.右下角为分页符,支持单页查看数据条数;
|
||||
`);
|
||||
}, []);
|
||||
@@ -358,8 +374,8 @@ var requirementDocContent = useMemo(function () {
|
||||
var row = billRowState[0] || (filteredData && filteredData[0]) || (tableDataAll && tableDataAll[0]) || {};
|
||||
var customerName = row.customerName || '广州毅斌物流有限公司';
|
||||
var plateNo = row.plateNo || '粤AGP6579';
|
||||
var deliveryTime = row.deliveryTime || '2025-07-21';
|
||||
var returnTime = row.returnTime || '2025-10-01';
|
||||
var deliveryTime = fmtYMDHM(row.deliveryTime || '2025-07-21 00:00');
|
||||
var returnTime = fmtYMDHM(row.returnTime || '2025-10-01 00:00');
|
||||
var billDate = fmtYMD(new Date());
|
||||
|
||||
var feeRows = [
|
||||
@@ -509,8 +525,8 @@ var requirementDocContent = useMemo(function () {
|
||||
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 110 },
|
||||
{ title: '业务部门', dataIndex: 'businessDept', key: 'businessDept', width: 110 },
|
||||
{ title: '业务负责人', dataIndex: 'businessOwner', key: 'businessOwner', width: 110 },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 110 },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 110 },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{ title: '还车人', dataIndex: 'returnPerson', key: 'returnPerson', width: 110 },
|
||||
{
|
||||
title: '操作',
|
||||
@@ -520,7 +536,7 @@ var requirementDocContent = useMemo(function () {
|
||||
render: function (_, r) {
|
||||
var st = String(r && r.approvalStatus);
|
||||
var showFeeDetail = !(st === '待审批' || st === '审批中' || st === '审批完成');
|
||||
var showRevoke = String(r && r.approvalStatus) === '审批中';
|
||||
var showRevoke = (st === '待审批' || st === '审批中');
|
||||
var showGenerateBill = String(r && r.approvalStatus) === '待审批';
|
||||
return React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 8 } },
|
||||
React.createElement(Button, { type: 'link', size: 'small', onClick: function () { handleView(r); } }, '查看'),
|
||||
@@ -685,8 +701,8 @@ return React.createElement('div', { style: layoutStyle },
|
||||
return React.createElement('tr', { key: 'fee-' + idx },
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, String(billDetail.vehicle.seq || 1)) : null,
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, billDetail.vehicle.plateNo) : null,
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, billDetail.vehicle.deliveryTime) : null,
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, billDetail.vehicle.returnTime) : null,
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, fmtYMDHM(billDetail.vehicle.deliveryTime)) : null,
|
||||
idx === 0 ? React.createElement('td', { rowSpan: rowspan, className: 't-center' }, fmtYMDHM(billDetail.vehicle.returnTime)) : null,
|
||||
React.createElement('td', null, r.item),
|
||||
React.createElement('td', { className: 't-right' }, fmtMoney(r.amount))
|
||||
);
|
||||
@@ -1437,8 +1453,8 @@ var requirementDocContent = useMemo(function () {
|
||||
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 160, ellipsis: true },
|
||||
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, ellipsis: true },
|
||||
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 140, ellipsis: true },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 110 },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 110 },
|
||||
{ title: '交车时间', dataIndex: 'deliveryTime', key: 'deliveryTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{ title: '还车时间', dataIndex: 'returnTime', key: 'returnTime', width: 160, render: function (v) { return fmtYMDHM(v); } },
|
||||
{
|
||||
title: '易损保', dataIndex: 'fragileInsurance', key: 'fragileInsurance', width: 110,
|
||||
render: function (v) {
|
||||
|
||||
Reference in New Issue
Block a user