运维/财务:还车应结款分钟级时间与费用明细交互优化

- 还车应结款/查看/费用明细:交车/还车时间统一显示到分钟
- 待审批与审批中状态操作列支持撤回
- 费用明细:已收租金可编辑、预付款退费展示最后一辆车提示、证件丢失费用可编辑
- 同步更新相关需求说明文案

Made-with: Cursor
This commit is contained in:
王冕
2026-03-19 11:54:44 +08:00
parent 3a04a3d1c1
commit 3360dc785e
7 changed files with 110 additions and 46 deletions

View File

@@ -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),