import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Button, Drawer, Form, Input, InputNumber, Modal, Radio, Space, Switch, Table, Tag } from 'antd'; import { HistoryOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; import { message } from '../../ui/app-message'; interface WalletRow { studentId: number; studentName: string; studentNo?: string; balance: number; outstandingAmount: number; } const transactionNames: Record = { recharge: '充值', adjustment: '调账', bill_payment: '账单扣款', bill_refund: '账单冲正', }; const WalletsPage: React.FC = () => { const [rows, setRows] = useState([]); const [loading, setLoading] = useState(false); const [keyword, setKeyword] = useState(''); const [debtOnly, setDebtOnly] = useState(false); const [selected, setSelected] = useState(null); const [transactions, setTransactions] = useState([]); const [drawerOpen, setDrawerOpen] = useState(false); const [form] = Form.useForm(); const [saving, setSaving] = useState(false); const fetchRows = useCallback(async () => { setLoading(true); try { const data = await api.get('/wallets', { params: { keyword: keyword || undefined, debtOnly } }); setRows(data as WalletRow[]); } catch (error: any) { message.error(error?.message || '加载学生余额失败'); } finally { setLoading(false); } }, [keyword, debtOnly]); useEffect(() => { void fetchRows(); }, [fetchRows]); const openChange = (row: WalletRow) => { setSelected(row); form.setFieldsValue({ type: 'recharge', amount: undefined, description: '' }); }; const submitChange = async () => { if (!selected) return; const values = await form.validateFields(); setSaving(true); try { const result: any = await api.post('/wallets/change-balance', { studentId: selected.studentId, ...values }); const paid = (result.payments || []).reduce((sum: number, bill: any) => sum + Number(bill.paidAmount || 0), 0); message.success(paid > 0 ? `余额已更新,并自动补扣历史账单` : '余额已更新'); setSelected(null); await fetchRows(); } catch (error: any) { message.error(error?.message || '余额操作失败'); } finally { setSaving(false); } }; const showTransactions = async (row: WalletRow) => { setSelected(row); setDrawerOpen(true); try { setTransactions(await api.get('/wallets/transactions', { params: { studentId: row.studentId } }) as any[]); } catch (error: any) { message.error(error?.message || '加载流水失败'); } }; const columns = useMemo(() => [ { title: '学生', render: (_: unknown, row: WalletRow) => <>{row.studentName}
{row.studentNo || `#${row.studentId}`}
}, { title: '可用余额', dataIndex: 'balance', render: (value: number) => 0 ? '#1677ff' : undefined }}>¥{Number(value).toFixed(2)} }, { title: '未付账单', dataIndex: 'outstandingAmount', render: (value: number) => Number(value) > 0 ? ¥{Number(value).toFixed(2)} : 无欠费 }, { title: '操作', render: (_: unknown, row: WalletRow) => } onClick={() => openChange(row)}>充值/调账 }, ], []); return
!event.target.value && setKeyword('')} />仅看欠费
`共 ${total} 人` }} /> setSelected(null)} onOk={submitChange} confirmLoading={saving} okText="确认">
{ setDrawerOpen(false); setSelected(null); }}>
dayjs(value).format('YYYY-MM-DD HH:mm') }, { title: '类型', dataIndex: 'type', render: (value: string) => transactionNames[value] || value }, { title: '金额', dataIndex: 'amount', render: (value: number) => = 0 ? '#389e0d' : '#cf1322' }}>{Number(value) >= 0 ? '+' : ''}¥{Number(value).toFixed(2)} }, { title: '变动后余额', dataIndex: 'balanceAfter', render: (value: number) => `¥${Number(value).toFixed(2)}` }, { title: '关联账单', dataIndex: 'billId', render: (value: number) => value ? `#${value}` : '-' }, { title: '说明', dataIndex: 'description' }, ]} /> ; }; export default WalletsPage;