Files
ONE-OS/web端/财务管理/提车应收款.jsx

433 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 【重要】必须使用 const Component 作为组件变量名
// 提车应收款(财务管理 - 运维管理-财务管理-提车应收款antd 规范布局)
const Component = function() {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var 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))
)
);
};