// 【重要】必须使用 const Component 作为组件变量名 // 账单管理 - 车辆资产管理后台(按 antd 规范) const Component = function() { var useState = React.useState; var useCallback = React.useCallback; var useMemo = React.useMemo; var useEffect = React.useEffect; var antd = window.antd; var Breadcrumb = antd.Breadcrumb; var Card = antd.Card; var Select = antd.Select; var Button = antd.Button; var Table = antd.Table; var Tag = antd.Tag; var Modal = antd.Modal; var Input = antd.Input; var message = antd.message; var Space = antd.Space; var Row = antd.Row; var Col = antd.Col; // 当前视图:list | detail var viewState = useState('list'); var currentView = viewState[0]; var setCurrentView = viewState[1]; // 分页 var pageState = useState(1); var currentPage = pageState[0]; var setCurrentPage = pageState[1]; var pageSizeState = useState(10); var pageSize = pageSizeState[0]; var setPageSize = pageSizeState[1]; // 选中项(Table rowSelection 用) var selectedRowKeysState = useState([]); var selectedRowKeys = selectedRowKeysState[0]; var setSelectedRowKeys = selectedRowKeysState[1]; // 筛选器(表单值) var contractFilterState = useState(undefined); var contractFilter = contractFilterState[0]; var setContractFilter = contractFilterState[1]; var projectFilterState = useState(undefined); var projectFilter = projectFilterState[0]; var setProjectFilter = projectFilterState[1]; var customerFilterState = useState(undefined); var customerFilter = customerFilterState[0]; var setCustomerFilter = customerFilterState[1]; var statusFilterState = useState([]); var statusFilter = statusFilterState[0]; var setStatusFilter = statusFilterState[1]; // 已应用的筛选条件(点击查询后生效) var appliedFilterState = useState({ contract: '', project: '', customer: '', status: [] }); var appliedFilter = appliedFilterState[0]; var setAppliedFilter = appliedFilterState[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]; var viewingBillIdState = useState(null); var viewingBillId = viewingBillIdState[0]; var setViewingBillId = viewingBillIdState[1]; // 详情模式:view | payment var detailModeState = useState('view'); var detailMode = detailModeState[0]; var setDetailMode = detailModeState[1]; // 付款表单数据 var paymentFormState = useState({ discountAmount: '', discountReason: '', vehicleList: [], hydrogenList: [], violationList: [], returnFeeList: [] }); var paymentForm = paymentFormState[0]; var setPaymentForm = paymentFormState[1]; // 列表内成本编辑 var editingListCellState = useState(null); var editingListCell = editingListCellState[0]; var setEditingListCell = editingListCellState[1]; var editingInputValueState = useState(''); var editingInputValue = editingInputValueState[0]; var setEditingInputValue = editingInputValueState[1]; var listEditableCostsState = useState({}); var listEditableCosts = listEditableCostsState[0]; var setListEditableCosts = listEditableCostsState[1]; // 模拟选项与数据(与原文一致) var contractOptions = useMemo(function() { return [ { value: 'HT001', label: 'HT001 - 租赁合同A' }, { value: 'HT002', label: 'HT002 - 租赁合同B' }, { value: 'HT003', label: 'HT003 - 租赁合同C' } ]; }, []); var projectOptions = useMemo(function() { return [ { value: 'XM001', label: 'XM001 - 北京项目' }, { value: 'XM002', label: 'XM002 - 上海项目' }, { value: 'XM003', label: 'XM003 - 广州项目' } ]; }, []); var customerOptions = useMemo(function() { return [ { value: 'KH001', label: 'KH001 - 科技公司A' }, { value: 'KH002', label: 'KH002 - 制造企业B' }, { value: 'KH003', label: 'KH003 - 物流公司C' } ]; }, []); var statusOptions = [ { value: 'paid', label: '已付款' }, { value: 'partial', label: '部分付款' }, { value: 'unpaid', label: '未付款' } ]; var mockBillList = useMemo(function() { var list = []; for (var i = 1; i <= 25; i++) { var statuses = ['paid', 'partial', 'unpaid']; var status = statuses[i % 3]; list.push({ id: 'BILL' + i, contractCode: 'HT00' + (i % 3 + 1), projectName: 'XM00' + (i % 3 + 1) + ' - 项目' + i, customerName: 'KH00' + (i % 3 + 1) + ' - 客户' + i, period: i, payableAmount: (15000 + i * 500).toFixed(2), paidAmount: status === 'paid' ? (15000 + i * 500).toFixed(2) : status === 'partial' ? (8000).toFixed(2) : '0.00', discountAmount: (i % 5 === 0 ? 200 : 0).toFixed(2), remark: status !== 'unpaid' ? '已付款备注' + i : '-', vehicleCost: (5000 + i * 100).toFixed(2), hydrogenCost: (300 + i * 20).toFixed(2), otherCost: (200 + i * 10).toFixed(2), status: status }); } return list; }, []); var mockPayableDetail = useMemo(function() { return [ { startDate: '2025-01-01', endDate: '2025-01-31', plateNo: '京A12345', rent: '8000.00', serviceFee: '500.00', deposit: '2000.00' }, { startDate: '2025-01-01', endDate: '2025-01-31', plateNo: '京B67890', rent: '7000.00', serviceFee: '400.00', deposit: '1500.00' } ]; }, []); var mockBillDetail = useMemo(function() { return { startDate: '2025-01-01', endDate: '2025-01-31', contractCode: 'HT001', projectName: 'XM001 - 北京项目', customerName: 'KH001 - 科技公司A', department: '运营部', responsible: '张三', paymentCycle: '先付(付款周期:1个月)', discountTotal: '200.00', discountReason: '长期合作客户优惠,首期账单减免部分金额' }; }, []); var mockVehicleList = useMemo(function() { return [ { brand: '奔驰', model: 'E300L', plateNo: '京A12345', planDelivery: '2024-12-25', 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', 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 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 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 mockHydrogenData = useMemo(function() { return { refuelCount: 12, balance: '3580.00', list: [ { refuelTime: '2025-01-15 09:30:00', stationName: '北京朝阳加氢站', plateNo: '京A12345', amount: '15.5', costPrice: '28.00', feePrice: '434.00', paidFeePrice: '420.00' }, { refuelTime: '2025-01-18 14:20:00', stationName: '北京海淀加氢站', plateNo: '京B67890', amount: '12.0', costPrice: '28.00', feePrice: '336.00', paidFeePrice: '336.00' }, { refuelTime: '2025-01-22 11:00:00', stationName: '北京朝阳加氢站', plateNo: '京A12345', amount: '18.2', costPrice: '28.00', feePrice: '509.60', paidFeePrice: '490.00' } ] }; }, []); 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 billInfoTotals = useMemo(function() { var monthlyRentTotal = parseFloat(vehicleBillTotals.monthlyRentTotal || 0); var serviceFeeTotal = parseFloat(vehicleBillTotals.serviceFeeTotal || 0); var depositTotal = parseFloat(vehicleBillTotals.depositTotal || 0); var hydrogenTotal = 0; (mockHydrogenData.list || []).forEach(function(item) { hydrogenTotal += parseFloat(item.feePrice || 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 = Math.max(0, payableTotal - paidTotal - discountTotal); return { payableTotal: payableTotal.toFixed(2), paidTotal: paidTotal.toFixed(2), unpaidTotal: unpaidTotal.toFixed(2) }; }, [vehicleBillTotals, mockHydrogenData, mockViolationData, mockReturnFeeData, mockVehicleList, mockBillDetail]); var vehicleTotals = billInfoTotals; var filteredList = useMemo(function() { var list = (mockBillList || []).slice(); var c = (appliedFilter.contract || '').trim(); var p = (appliedFilter.project || '').trim(); var cust = (appliedFilter.customer || '').trim(); var st = Array.isArray(appliedFilter.status) ? appliedFilter.status : []; if (c) list = list.filter(function(item) { return String(item.contractCode || '').toLowerCase().indexOf(c.toLowerCase()) >= 0; }); if (p) list = list.filter(function(item) { return String(item.projectName || '').toLowerCase().indexOf(p.toLowerCase()) >= 0; }); if (cust) list = list.filter(function(item) { return String(item.customerName || '').toLowerCase().indexOf(cust.toLowerCase()) >= 0; }); if (st.length > 0) { var statusSet = {}; st.forEach(function(s) { statusSet[s] = true; }); list = list.filter(function(item) { return statusSet[item.status]; }); } return list; }, [mockBillList, appliedFilter.contract, appliedFilter.project, appliedFilter.customer, appliedFilter.status]); var totalCount = filteredList.length; var paginatedList = useMemo(function() { var start = (currentPage - 1) * pageSize; return filteredList.slice(start, start + pageSize); }, [filteredList, currentPage, pageSize]); var handleSearch = useCallback(function() { setAppliedFilter({ contract: (contractFilter != null && contractFilter !== '') ? String(contractFilter) : '', project: (projectFilter != null && projectFilter !== '') ? String(projectFilter) : '', customer: (customerFilter != null && customerFilter !== '') ? String(customerFilter) : '', status: Array.isArray(statusFilter) ? statusFilter.slice() : [] }); setCurrentPage(1); }, [contractFilter, projectFilter, customerFilter, statusFilter]); var handleReset = useCallback(function() { setContractFilter(undefined); setProjectFilter(undefined); setCustomerFilter(undefined); setStatusFilter([]); setAppliedFilter({ contract: '', project: '', customer: '', status: [] }); setCurrentPage(1); }, []); var handleExport = useCallback(function() { if (selectedRowKeys.length === 0) { message.warning('请先选择要导出的数据'); return; } message.success('导出 ' + selectedRowKeys.length + ' 条数据'); }, [selectedRowKeys.length]); var handleView = useCallback(function(id, isPayment) { setViewingBillId(id); setDetailMode(isPayment ? 'payment' : 'view'); if (isPayment) { var vl = mockVehicleList.map(function(v) { return { paidMonthlyRent: v.paidMonthlyRent || '', paidServiceFee: v.paidServiceFee || '', paidDeposit: v.paidDeposit || '' }; }); var hl = mockHydrogenData.list.map(function(item) { return { paidFeePrice: item.paidFeePrice || '' }; }); 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 || '', vehicleList: vl, hydrogenList: hl, violationList: viol, returnFeeList: rfl }); } setCurrentView('detail'); }, []); var handleBackToList = useCallback(function() { setCurrentView('list'); setViewingBillId(null); setDetailMode('view'); }, []); var handlePaymentFormChange = useCallback(function(section, index, field, value) { setPaymentForm(function(prev) { var next = { discountAmount: prev.discountAmount, discountReason: prev.discountReason, 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; } else if (section === 'vehicle' && index >= 0 && index < next.vehicleList.length) { next.vehicleList[index] = Object.assign({}, next.vehicleList[index], { [field]: value }); } else if (section === 'hydrogen' && index >= 0 && index < next.hydrogenList.length) { next.hydrogenList[index] = Object.assign({}, next.hydrogenList[index], { [field]: value }); } else if (section === 'violation' && index >= 0 && index < next.violationList.length) { next.violationList[index] = Object.assign({}, next.violationList[index], { [field]: value }); } else if (section === 'returnFee' && index >= 0 && index < next.returnFeeList.length) { next.returnFeeList[index] = Object.assign({}, 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('减免原因'); 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.hydrogenList.forEach(function(h, i) { if (!h.paidFeePrice || String(h.paidFeePrice).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) { message.warning('请填写必填项:' + errors.join('、')); return; } message.success('提交成功'); handleBackToList(); }, [paymentForm, handleBackToList]); var handleSave = useCallback(function() { message.success('保存成功'); }, []); function getStatusText(status) { if (status === 'paid') return '已付款'; if (status === 'partial') return '部分付款'; return '未付款'; } function getStatusTagColor(status) { if (status === 'paid') return 'success'; if (status === 'partial') return 'warning'; return 'error'; } // 列表表格列(含行内编辑氢费/其他成本) function renderEditableCost(row, field, label) { var rowId = row.id; var val = (listEditableCosts[rowId] && listEditableCosts[rowId][field] !== undefined) ? listEditableCosts[rowId][field] : (row[field] != null ? row[field] : '0.00'); var num = (parseFloat(val) || 0).toFixed(2); var isEditing = editingListCell && editingListCell.rowId === rowId && editingListCell.field === field; if (isEditing) { return React.createElement(Space, { key: 'edit', size: 4 }, React.createElement(Input, { value: editingInputValue, onChange: function(e) { setEditingInputValue(e.target.value); }, onBlur: function() { var n = parseFloat(editingInputValue); var formatted = (isNaN(n) ? 0 : n).toFixed(2); setListEditableCosts(function(prev) { var next = Object.assign({}, prev); next[rowId] = Object.assign({}, next[rowId], { [field]: formatted }); return next; }); setEditingListCell(null); setEditingInputValue(''); }, style: { width: 80 }, autoFocus: true }), React.createElement('span', null, '元') ); } return React.createElement('span', { style: { cursor: 'pointer' }, onClick: function() { setEditingInputValue(num); setEditingListCell({ rowId: rowId, field: field }); } }, num); } var listColumns = useMemo(function() { return [ { title: '付款状态', dataIndex: 'status', key: 'status', width: 100, render: function(s) { return React.createElement(Tag, { color: getStatusTagColor(s) }, getStatusText(s)); } }, { title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 120 }, { title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 160 }, { title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 160 }, { title: '当前期数', dataIndex: 'period', key: 'period', width: 90 }, { title: '应付金额', dataIndex: 'payableAmount', key: 'payableAmount', width: 110, render: function(_, row) { return React.createElement('a', { onClick: function() { setPopover({ type: 'payable', data: mockPayableDetail }); }, style: { color: '#1677ff', fontWeight: 600, textDecoration: 'underline', cursor: 'pointer' } }, row.payableAmount); }}, { title: '实付金额', dataIndex: 'paidAmount', key: 'paidAmount', width: 110 }, { title: '减免金额', dataIndex: 'discountAmount', key: 'discountAmount', width: 100 }, { title: '未付金额', key: 'unpaid', width: 100, render: function(_, row) { return (parseFloat(row.payableAmount || 0) - parseFloat(row.paidAmount || 0) - parseFloat(row.discountAmount || 0)).toFixed(2); }}, { title: '备注', dataIndex: 'remark', key: 'remark', width: 120 }, { title: '车辆成本(元)', dataIndex: 'vehicleCost', key: 'vehicleCost', width: 120, render: function(val) { return (parseFloat(val) || 0).toFixed(2); } }, { title: '氢费成本(元)', key: 'hydrogenCost', width: 120, render: function(_, row) { return renderEditableCost(row, 'hydrogenCost', '氢费'); } }, { title: '其他成本(元)', key: 'otherCost', width: 120, render: function(_, row) { return renderEditableCost(row, 'otherCost', '其他'); } }, { title: '操作', key: 'action', width: 140, fixed: 'right', render: function(_, row) { return React.createElement(Space, null, React.createElement(Button, { type: 'link', size: 'small', onClick: function() { handleView(row.id, false); } }, '查看'), React.createElement(Button, { type: 'link', size: 'small', style: { color: '#52c41a' }, onClick: function() { handleView(row.id, true); } }, '收费') ); }} ]; }, [listEditableCosts, editingListCell, editingInputValue, handleView]); var rowSelection = useMemo(function() { return { selectedRowKeys: selectedRowKeys, onChange: function(keys) { setSelectedRowKeys(keys || []); } }; }, [selectedRowKeys]); var tablePagination = useMemo(function() { return { current: currentPage, pageSize: pageSize, total: totalCount, showSizeChanger: true, showTotal: function(t) { return '共 ' + t + ' 条'; }, pageSizeOptions: ['10', '20', '50'], onChange: function(page, size) { setCurrentPage(page); if (size !== pageSize) setPageSize(size); } }; }, [currentPage, pageSize, totalCount]); // —————— 详情视图 —————— if (currentView === 'detail') { var detailBreadcrumbItems = [ { title: '运维管理' }, { title: '业务管理' }, { title: '租赁账单' }, { title: detailMode === 'payment' ? '收费' : '查看' } ]; var billInfoCols = [ { label: '账单开始日期', value: mockBillDetail.startDate }, { label: '账单结束日期', value: mockBillDetail.endDate }, { label: '合同编码', value: mockBillDetail.contractCode }, { label: '项目名称', value: mockBillDetail.projectName }, { label: '客户名称', value: mockBillDetail.customerName }, { label: '业务部门', value: mockBillDetail.department }, { label: '业务负责人', value: mockBillDetail.responsible }, { label: '付款周期', value: mockBillDetail.paymentCycle } ]; return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } }, React.createElement(Breadcrumb, { items: detailBreadcrumbItems, style: { marginBottom: 16 } }), React.createElement(Card, { style: { marginBottom: 16 } }, React.createElement('div', { style: { fontSize: 16, fontWeight: 600, marginBottom: 16, paddingBottom: 12, borderBottom: '1px solid #f0f0f0' } }, '账单信息'), React.createElement(Row, { gutter: [24, 24] }, billInfoCols.map(function(item, i) { return React.createElement(Col, { key: i, span: 8 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, item.label + ':'), React.createElement('span', null, item.value) ) ); }), React.createElement(Col, { span: 8 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '应付款总额:'), React.createElement('span', { style: { color: '#1890ff', fontWeight: 600 } }, vehicleTotals.payableTotal + ' 元') ) ), React.createElement(Col, { span: 8 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '实付款总额:'), React.createElement('span', { style: { color: '#52c41a', fontWeight: 600 } }, vehicleTotals.paidTotal + ' 元') ) ), React.createElement(Col, { span: 8 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '减免金额:'), detailMode === 'payment' ? React.createElement(Input, { value: paymentForm.discountAmount, onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountAmount', e.target.value); }, style: { width: 120 }, placeholder: '0.00', addonAfter: '元' }) : React.createElement('span', { style: { fontWeight: 600 } }, mockBillDetail.discountTotal + ' 元') ) ), React.createElement(Col, { span: 8 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '未付款总额:'), React.createElement('span', { style: { color: '#ff4d4f', fontWeight: 600 } }, vehicleTotals.unpaidTotal + ' 元') ) ), React.createElement(Col, { span: 24 }, React.createElement('div', { style: { marginBottom: 8 } }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '减免原因:'), detailMode === 'payment' ? React.createElement(Input.TextArea, { value: paymentForm.discountReason, onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountReason', e.target.value); }, placeholder: '请输入减免原因', rows: 3, style: { maxWidth: 400 } }) : React.createElement('span', null, mockBillDetail.discountReason || '-') ) ) ) ), // 车辆账单 React.createElement(Card, { title: '车辆账单', style: { marginBottom: 16 } }, React.createElement(Table, { dataSource: mockVehicleList, rowKey: 'plateNo', pagination: false, scroll: { x: 1200 }, columns: [ { title: '品牌', dataIndex: 'brand', width: 80 }, { title: '型号', dataIndex: 'model', width: 90 }, { title: '车牌号', dataIndex: 'plateNo', width: 100 }, { title: '计划交车日期', dataIndex: 'planDelivery', width: 120 }, { title: '实际交车日期', dataIndex: 'actualDelivery', width: 120 }, { title: '账单开始日期', dataIndex: 'billStart', width: 120 }, { title: '计费结束日期', dataIndex: 'billEnd', width: 120 }, { title: '车辆月租金', dataIndex: 'monthlyRent', width: 110 }, { title: '实付月租金', dataIndex: 'paidMonthlyRent', width: 110, render: function(_, record, idx) { if (detailMode !== 'payment') return (parseFloat(record.paidMonthlyRent || 0)).toFixed(2); var pf = paymentForm.vehicleList[idx] || {}; return React.createElement(Input, { value: pf.paidMonthlyRent, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidMonthlyRent', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }}, { title: '服务费', dataIndex: 'serviceFee', width: 90, render: function(val, record) { if (detailMode === 'payment') return val; return React.createElement('a', { onClick: function() { setPopover({ type: 'service', data: record.serviceItems }); } }, val); }}, { title: '实付服务费', dataIndex: 'paidServiceFee', width: 110, render: function(_, record, idx) { if (detailMode !== 'payment') return (parseFloat(record.paidServiceFee || 0)).toFixed(2); var pf = paymentForm.vehicleList[idx] || {}; return React.createElement(Input, { value: pf.paidServiceFee, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidServiceFee', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }}, { title: '保证金', dataIndex: 'deposit', width: 90 }, { title: '实付保证金', dataIndex: 'paidDeposit', width: 110, render: function(_, record, idx) { if (detailMode !== 'payment') return (parseFloat(record.paidDeposit || 0)).toFixed(2); var pf = paymentForm.vehicleList[idx] || {}; return React.createElement(Input, { value: pf.paidDeposit, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidDeposit', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }} ], summary: function() { return React.createElement(Table.Summary, null, React.createElement(Table.Summary.Row, null, React.createElement(Table.Summary.Cell, { index: 0, colSpan: 7 }, '总计'), React.createElement(Table.Summary.Cell, { index: 7 }, vehicleBillTotals.monthlyRentTotal), React.createElement(Table.Summary.Cell, { index: 8 }, vehicleBillTotals.paidRentTotal), React.createElement(Table.Summary.Cell, { index: 9 }, vehicleBillTotals.serviceFeeTotal), React.createElement(Table.Summary.Cell, { index: 10 }, vehicleBillTotals.paidServiceFeeTotal), React.createElement(Table.Summary.Cell, { index: 11 }, vehicleBillTotals.depositTotal), React.createElement(Table.Summary.Cell, { index: 12 }, vehicleBillTotals.paidDepositTotal) ) ); } }) ), // 氢费账单 React.createElement(Card, { title: '氢费账单', style: { marginBottom: 16 } }, React.createElement('div', { style: { marginBottom: 16 } }, React.createElement('span', { style: { marginRight: 24 } }, '加氢次数:', React.createElement('span', { style: { fontWeight: 600 } }, mockHydrogenData.refuelCount + ' 次')), React.createElement('span', null, '当前氢费余额:', React.createElement('span', { style: { fontWeight: 600, color: '#1890ff' } }, mockHydrogenData.balance + ' 元')) ), React.createElement(Table, { dataSource: mockHydrogenData.list, rowKey: function(item, i) { return i; }, pagination: false, columns: [ { title: '加氢时间', dataIndex: 'refuelTime', width: 180 }, { title: '加氢站名称', dataIndex: 'stationName', width: 140 }, { title: '车牌号', dataIndex: 'plateNo', width: 100 }, { title: '加氢量', dataIndex: 'amount', width: 90 }, { title: '成本单价(元/KG)', dataIndex: 'costPrice', width: 120 }, { title: '氢费价格(元)', dataIndex: 'feePrice', width: 120 }, { title: '实付氢费金额(元)', dataIndex: 'paidFeePrice', width: 140, render: function(_, record, i) { if (detailMode !== 'payment') return (parseFloat(record.paidFeePrice || 0)).toFixed(2); var pf = paymentForm.hydrogenList[i] || {}; return React.createElement(Input, { value: pf.paidFeePrice, onChange: function(e) { handlePaymentFormChange('hydrogen', i, 'paidFeePrice', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }} ], summary: function() { var totalFee = mockHydrogenData.list.reduce(function(s, item) { return s + parseFloat(item.feePrice || 0); }, 0).toFixed(2); var totalPaid = mockHydrogenData.list.reduce(function(s, item) { return s + parseFloat(item.paidFeePrice || 0); }, 0).toFixed(2); return React.createElement(Table.Summary, null, React.createElement(Table.Summary.Row, null, React.createElement(Table.Summary.Cell, { index: 0, colSpan: 5 }, '总计'), React.createElement(Table.Summary.Cell, { index: 5 }, totalFee), React.createElement(Table.Summary.Cell, { index: 6 }, totalPaid) ) ); } }) ), // 违章费用 React.createElement(Card, { title: '违章费用', style: { marginBottom: 16 } }, React.createElement('div', { style: { marginBottom: 16 } }, React.createElement('span', null, '违章次数:', React.createElement('span', { style: { fontWeight: 600 } }, mockViolationData.violationCount + ' 次')) ), React.createElement(Table, { dataSource: mockViolationData.list, rowKey: function(item, i) { return i; }, pagination: false, columns: [ { title: '违章时间', dataIndex: 'violationTime', width: 180 }, { title: '车牌号', dataIndex: 'plateNo', width: 100 }, { title: '违章类型', dataIndex: 'violationType', width: 100 }, { title: '违章地点', dataIndex: 'location', width: 200 }, { title: '罚款金额', dataIndex: 'fineAmount', width: 100 }, { title: '实付罚款金额(元)', dataIndex: 'paidFineAmount', width: 140, render: function(_, record, i) { if (detailMode !== 'payment') return (parseFloat(record.paidFineAmount || 0)).toFixed(2); var pf = paymentForm.violationList[i] || {}; return React.createElement(Input, { value: pf.paidFineAmount, onChange: function(e) { handlePaymentFormChange('violation', i, 'paidFineAmount', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }} ], summary: function() { var totalPaid = mockViolationData.list.reduce(function(s, item) { return s + parseFloat(item.paidFineAmount || 0); }, 0).toFixed(2); return React.createElement(Table.Summary, null, React.createElement(Table.Summary.Row, null, React.createElement(Table.Summary.Cell, { index: 0, colSpan: 4 }, '总计'), React.createElement(Table.Summary.Cell, { index: 4 }, mockViolationData.totalAmount), React.createElement(Table.Summary.Cell, { index: 5 }, totalPaid) ) ); } }) ), // 还车费用 React.createElement(Card, { title: '还车费用', style: { marginBottom: 16 } }, React.createElement(Table, { dataSource: mockReturnFeeData.list, rowKey: function(item, i) { return i; }, pagination: false, columns: [ { title: '费用名称', dataIndex: 'feeName', width: 140 }, { title: '金额', dataIndex: 'amount', width: 100 }, { title: '实付金额(元)', dataIndex: 'paidAmount', width: 120, render: function(_, record, i) { if (detailMode !== 'payment') return (parseFloat(record.paidAmount || 0)).toFixed(2); var pf = paymentForm.returnFeeList[i] || {}; return React.createElement(Input, { value: pf.paidAmount, onChange: function(e) { handlePaymentFormChange('returnFee', i, 'paidAmount', e.target.value); }, style: { width: 100 }, addonAfter: '元' }); }}, { title: '照片', dataIndex: 'photos', width: 200, render: function(photos) { if (!photos || photos.length === 0) return '-'; return React.createElement(Space, null, photos.slice(0, 5).map(function(url, idx) { return React.createElement('img', { key: idx, src: url, alt: '', style: { width: 40, height: 40, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' }, onClick: function() { setPhotoViewer({ visible: true, photos: photos, currentIndex: idx }); } }); })); }}, { title: '附件', dataIndex: 'attachments', render: function(attachments) { if (!attachments || attachments.length === 0) return '-'; return React.createElement(Space, { wrap: true }, attachments.map(function(att, idx) { return React.createElement('a', { key: idx, onClick: function() { message.info('下载附件:' + att.name); } }, att.name); })); }} ], summary: function() { var totalPaid = mockReturnFeeData.list.reduce(function(s, item) { return s + parseFloat(item.paidAmount || 0); }, 0).toFixed(2); return React.createElement(Table.Summary, null, React.createElement(Table.Summary.Row, null, React.createElement(Table.Summary.Cell, { index: 0 }, '总计'), React.createElement(Table.Summary.Cell, { index: 1 }, mockReturnFeeData.totalAmount), React.createElement(Table.Summary.Cell, { index: 2 }, totalPaid), React.createElement(Table.Summary.Cell, { index: 3 }, ''), React.createElement(Table.Summary.Cell, { index: 4 }, '') ) ); } }) ), React.createElement('div', { style: { marginTop: 24, textAlign: 'center' } }, React.createElement(Space, null, detailMode === 'payment' && React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'), detailMode === 'payment' && React.createElement(Button, { onClick: handleSave }, '保存'), detailMode === 'payment' && React.createElement(Button, { onClick: handleBackToList }, '取消'), detailMode === 'view' && React.createElement(Button, { onClick: handleBackToList }, '返回') ) ), // 照片查看器 Modal React.createElement(Modal, { title: '照片查看', open: photoViewer.visible && photoViewer.photos.length > 0, onCancel: function() { setPhotoViewer({ visible: false, photos: [], currentIndex: 0 }); }, footer: null, width: '90vw', centered: true }, photoViewer.photos.length > 0 ? React.createElement('div', { style: { textAlign: 'center' } }, React.createElement('img', { src: photoViewer.photos[photoViewer.currentIndex].replace('80/80', '600/600'), alt: '', style: { maxWidth: '100%', maxHeight: '70vh', objectFit: 'contain' } }), React.createElement('div', { style: { marginTop: 16 } }, React.createElement(Button, { disabled: photoViewer.currentIndex <= 0, onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex - 1 }); } }, '上一张'), React.createElement('span', { style: { margin: '0 16px' } }, (photoViewer.currentIndex + 1) + ' / ' + photoViewer.photos.length), React.createElement(Button, { disabled: photoViewer.currentIndex >= photoViewer.photos.length - 1, onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex + 1 }); } }, '下一张') ) ) : null), // 服务费明细 Modal popover.type === 'service' && React.createElement(Modal, { title: '服务费明细', open: true, onCancel: function() { setPopover({ type: null, data: null }); }, footer: React.createElement(Button, { onClick: function() { setPopover({ type: null, data: null }); } }, '关闭') }, React.createElement(Table, { dataSource: popover.data, rowKey: function(item, i) { return i; }, pagination: false, columns: [ { title: '服务项', dataIndex: 'name' }, { title: '价格', dataIndex: 'price' }, { title: '服务生效日期', dataIndex: 'effectiveDate' } ] })) ); } // —————— 列表视图 —————— var listBreadcrumbItems = [ { title: '运维管理' }, { title: '业务管理' }, { title: '租赁账单' } ]; return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } }, React.createElement(Breadcrumb, { items: listBreadcrumbItems, style: { marginBottom: 16 } }), React.createElement(Card, null, React.createElement(Row, { gutter: [16, 16], style: { marginBottom: 16 }, align: 'middle' }, React.createElement(Col, null, React.createElement('span', { style: { marginRight: 8 } }, '合同编码:'), React.createElement(Select, { placeholder: '请选择合同编码', allowClear: true, showSearch: true, optionFilterProp: 'label', value: contractFilter, onChange: setContractFilter, style: { width: 200 }, options: contractOptions }) ), React.createElement(Col, null, React.createElement('span', { style: { marginRight: 8 } }, '项目名称:'), React.createElement(Select, { placeholder: '请选择项目名称', allowClear: true, showSearch: true, optionFilterProp: 'label', value: projectFilter, onChange: setProjectFilter, style: { width: 200 }, options: projectOptions }) ), React.createElement(Col, null, React.createElement('span', { style: { marginRight: 8 } }, '客户名称:'), React.createElement(Select, { placeholder: '请选择客户名称', allowClear: true, showSearch: true, optionFilterProp: 'label', value: customerFilter, onChange: setCustomerFilter, style: { width: 200 }, options: customerOptions }) ), React.createElement(Col, null, React.createElement('span', { style: { marginRight: 8 } }, '付款状态:'), React.createElement(Select, { mode: 'multiple', placeholder: '全部', allowClear: true, value: statusFilter, onChange: setStatusFilter, style: { width: 200 }, options: statusOptions, maxTagCount: 'responsive' }) ), React.createElement(Col, null, React.createElement(Space, null, React.createElement(Button, { type: 'primary', onClick: handleSearch }, '查询'), React.createElement(Button, { onClick: handleReset }, '重置') ) ) ), React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'flex-end' } }, React.createElement(Button, { type: 'primary', onClick: handleExport }, '导出') ), React.createElement(Table, { rowSelection: rowSelection, columns: listColumns, dataSource: paginatedList, rowKey: 'id', pagination: tablePagination, scroll: { x: 1600 }, size: 'middle' }) ), // 应付金额明细 Modal(列表按内容一行显示、宽度随内容调整) React.createElement(Modal, { title: '应付金额明细', open: popover.type === 'payable', onCancel: function() { setPopover({ type: null, data: null }); }, footer: React.createElement(Button, { onClick: function() { setPopover({ type: null, data: null }); } }, '关闭'), width: 'fit-content', style: { maxWidth: '90vw' }, styles: { body: { paddingBottom: 24 } } }, popover.type === 'payable' && popover.data ? React.createElement(Table, { dataSource: popover.data, rowKey: function(item, i) { return i; }, pagination: false, tableLayout: 'auto', style: { minWidth: 0 }, columns: [ { title: '账单开始日期', dataIndex: 'startDate', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }, { title: '账单结束日期', dataIndex: 'endDate', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }, { title: '车牌号', dataIndex: 'plateNo', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }, { title: '车辆租金', dataIndex: 'rent', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }, { title: '服务费', dataIndex: 'serviceFee', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }, { title: '保证金', dataIndex: 'deposit', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } } ] }) : null) ); }; 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)); } } }