diff --git a/apps/admin/src/pages/Bills/index.tsx b/apps/admin/src/pages/Bills/index.tsx index c4e1030..7501a24 100644 --- a/apps/admin/src/pages/Bills/index.tsx +++ b/apps/admin/src/pages/Bills/index.tsx @@ -38,11 +38,166 @@ const typeMap: Record = { water: '水费', electricity: '电费', cleaning: '保洁费', + rent: '租金', damage: '损坏赔偿', penalty: '罚款', other: '其他', }; +const escapeHtml = (value: unknown) => + String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); + +const money = (value: unknown) => `¥${Number(value || 0).toFixed(2)}`; + +const buildBillPrintHtml = (bill: any) => { + const studentName = bill.student?.name || '-'; + const status = statusMap[bill.status]?.text || bill.status || '-'; + const generatedAt = bill.generatedAt + ? dayjs(bill.generatedAt).format('YYYY-MM-DD HH:mm') + : dayjs().format('YYYY-MM-DD HH:mm'); + const hasDeposit = Number(bill.availableDeposit || 0) > 0; + const items = bill.items || []; + + return ` + + + + 账单_${escapeHtml(studentName)}_${escapeHtml(bill.id)} + + + + +
+

恭学教育基地水电费账单

+
生成时间: ${escapeHtml(generatedAt)}
+ +
+
学生姓名: ${escapeHtml(studentName)}
+
计费周期: ${escapeHtml(bill.periodStart)} ~ ${escapeHtml(bill.periodEnd)}
+
账单状态: ${escapeHtml(status)}
+
+ +
+
费用汇总
+
+
分摊费用: ${escapeHtml(money(bill.sharedAmount))}
+
个人费用: ${escapeHtml(money(bill.personalAmount))}
+
应付总额: ${escapeHtml(money(bill.totalAmount))}
+ ${ + hasDeposit + ? `
可用押金: ${escapeHtml(money(bill.availableDeposit))}
+
押金抵扣: -${escapeHtml(money(bill.depositApplied))}
+
抵扣后应付: ${escapeHtml(money(bill.amountAfterDeposit ?? bill.totalAmount))}
` + : '' + } +
+
+ +
+
费用明细
+ + + + + + + + + + + + ${ + items.length + ? items + .map( + (item: any) => ` + + + + + + `, + ) + .join('') + : '' + } + +
费用类型说明天数总人天金额(元)
${escapeHtml(typeMap[item.expenseType] || item.expenseType || '-')}${escapeHtml(item.description || '-')}${escapeHtml(item.days || 0)}${escapeHtml(item.totalRoomDays || 0)}${escapeHtml(Number(item.studentAmount || 0).toFixed(2))}
暂无费用明细
+
+ + +
+ + +`; +}; + const BillsPage: React.FC = () => { const [bills, setBills] = useState([]); const [loading, setLoading] = useState(false); @@ -181,11 +336,24 @@ const BillsPage: React.FC = () => { ); }; - const handleExportPdf = (billId: number) => { - downloadBlob(`/bills/export/pdf/${billId}`, `账单_${billId}.pdf`).catch(() => - message.error('导出失败'), - ); - }; + const handleExportPdf = useCallback(async (billId: number) => { + const printWindow = window.open('', '_blank'); + if (!printWindow) { + message.error('无法打开打印窗口,请允许浏览器弹窗后重试'); + return; + } + + printWindow.document.write('账单加载中账单加载中...'); + try { + const bill = await api.get(`/bills/${billId}`); + printWindow.document.open(); + printWindow.document.write(buildBillPrintHtml(bill)); + printWindow.document.close(); + } catch (e: any) { + printWindow.close(); + message.error(e?.message || '账单数据加载失败'); + } + }, []); const columns = useMemo(() => [ { title: '学生', width: 120, render: (_: any, r: any) => r.student?.name || '-' },