Files
ONE-OS/web端/财务管理/提车首付款.jsx
王冕 09cc45db36 Initial commit: ONE-OS project
Made-with: Cursor
2026-02-27 18:11:40 +08:00

1049 lines
60 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 作为组件变量名
// 提车首付款 - 车辆资产管理后台(运维管理-财务管理-提车首付款)
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));
}
}
}