import React, { useEffect, useState, useMemo } from 'react'; import { Table, Modal, Form, Select, DatePicker, InputNumber, Input, Space, Tag, Popconfirm, List, Card, Empty, } from 'antd'; import { PlusOutlined, DeleteOutlined, DollarOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; import { message } from '../../ui/app-message'; import { buildDepositStudentOptions } from './deposit-student-option'; const statusMap: Record = { paid: { text: '已缴', color: 'green' }, refunded: { text: '已全退', color: 'blue' }, partial_refund: { text: '部分退还', color: 'orange' }, deducted: { text: '已全扣', color: 'red' }, }; const installmentStatusMap: Record = { pending: { text: '待缴', color: 'orange' }, paid: { text: '已缴', color: 'green' }, }; const isFormValidationError = (error: unknown) => typeof error === 'object' && error !== null && Array.isArray((error as { errorFields?: unknown }).errorFields); const DepositsPage: React.FC = () => { const [data, setData] = useState([]); const [students, setStudents] = useState([]); const [loading, setLoading] = useState(false); const [createModal, setCreateModal] = useState(false); const [refundModal, setRefundModal] = useState(null); const [detailModal, setDetailModal] = useState(null); const [installmentModal, setInstallmentModal] = useState(null); const [createForm] = Form.useForm(); const [refundForm] = Form.useForm(); const [installmentForm] = Form.useForm(); const [searchText, setSearchText] = useState(''); const [filterStatus, setFilterStatus] = useState(undefined); const [saving, setSaving] = useState(false); const fetchData = async () => { setLoading(true); try { const [d, s]: any[] = await Promise.all([ api.get('/deposits'), api.get('/deposits/student-lookups'), ]); setData(d); setStudents(s); } catch (e: any) { message.error(e?.message || '加载失败,请稍后重试'); } setLoading(false); }; useEffect(() => { fetchData(); }, []); const filteredData = useMemo(() => { return data.filter((d: any) => { if (searchText) { const s = searchText.toLowerCase(); if (!d.student?.name?.toLowerCase().includes(s)) return false; } if (filterStatus && d.status !== filterStatus) return false; return true; }); }, [data, searchText, filterStatus]); const studentOptions = useMemo( () => buildDepositStudentOptions(students), [students], ); const handleCreate = async () => { setSaving(true); try { const values = await createForm.validateFields(); await api.post('/deposits', { studentId: values.studentId, amount: values.amount, paidDate: values.paidDate.format('YYYY-MM-DD'), notes: values.notes, }); message.success('押金记录已创建'); setCreateModal(false); createForm.resetFields(); fetchData(); } catch (e: any) { if (!isFormValidationError(e)) { message.error(e?.message || '操作失败'); } } finally { setSaving(false); } }; const handleRefund = async () => { setSaving(true); try { const values = await refundForm.validateFields(); await api.put(`/deposits/${refundModal.id}/refund`, { refundDate: values.refundDate.format('YYYY-MM-DD'), deductionAmount: values.deductionAmount || 0, deductionReason: values.deductionReason, notes: values.notes, }); message.success('退还操作完成'); setRefundModal(null); refundForm.resetFields(); fetchData(); } catch (e: any) { if (!isFormValidationError(e)) { message.error(e?.message || '操作失败'); } } finally { setSaving(false); } }; const handleAddInstallment = async () => { if (installmentModal == null) return; try { const values = await installmentForm.validateFields(); await api.post(`/deposits/${installmentModal}/installments`, { amount: values.amount, dueDate: values.dueDate.format('YYYY-MM-DD'), }); message.success('分期已添加'); setInstallmentModal(null); installmentForm.resetFields(); fetchData(); } catch (e: any) { if (!isFormValidationError(e)) { message.error(e?.message || '操作失败'); } } }; const handlePayInstallment = async (installmentId: number) => { try { await api.put(`/deposits/installments/${installmentId}`, { paidDate: dayjs().format('YYYY-MM-DD'), status: 'paid', }); message.success('分期已标记为已缴'); fetchData(); } catch (e: any) { message.error(e?.message || '操作失败'); } }; const handleDeleteInstallment = async (installmentId: number) => { try { await api.delete(`/deposits/installments/${installmentId}`); message.success('分期已删除'); fetchData(); } catch (e: any) { message.error(e?.message || '操作失败'); } }; const columns = useMemo(() => [ { title: '学生', width: 120, render: (_: any, r: any) => r.student?.name || '-' }, { title: '押金金额', dataIndex: 'amount', width: 110, render: (v: number) => `¥${Number(v).toFixed(2)}` }, { title: '缴纳日期', dataIndex: 'paidDate', width: 110 }, { title: '状态', dataIndex: 'status', render: (s: string) => {statusMap[s]?.text || s}, }, { title: '退还金额', dataIndex: 'refundAmount', render: (v: any) => (v != null ? `¥${Number(v).toFixed(2)}` : '-'), }, { title: '扣除金额', dataIndex: 'deductionAmount', render: (v: any) => (v > 0 ? `¥${Number(v).toFixed(2)}` : '-'), }, { title: '扣除原因', dataIndex: 'deductionReason', width: 120, render: (v: any) => v || '-' }, { title: '退还日期', dataIndex: 'refundDate', width: 110, render: (v: any) => v || '-' }, { title: '备注', dataIndex: 'notes', width: 120, render: (v: any) => v || '-' }, { title: '操作', width: 240, render: (_: any, record: any) => ( { setDetailModal(record); }} > 详情 {record.status === 'paid' && ( <> { setRefundModal(record); refundForm.setFieldsValue({ refundDate: dayjs(), deductionAmount: 0 }); }} > 退还 )} { try { await api.delete(`/deposits/${record.id}`); message.success('删除成功'); fetchData(); } catch (e: any) { message.error(e?.message || '删除失败'); } }} > } > 删除 ), }, ], [fetchData]); return (
setSearchText(v)} onChange={(e) => { if (!e.target.value) setSearchText(''); }} /> {/* Refund Modal */} setRefundModal(null)} okText="确认退还" confirmLoading={saving} >
押金金额: ¥{Number(refundModal?.amount || 0).toFixed(2)}
{/* Detail Modal */} setDetailModal(null)} footer={null} width={640} > {detailModal && (

押金金额: ¥{Number(detailModal.amount).toFixed(2)}

缴纳日期: {detailModal.paidDate}

状态:{' '} {statusMap[detailModal.status]?.text || detailModal.status}

{detailModal.notes &&

备注: {detailModal.notes}

}
{/* Installments Section */}

分期记录

} onClick={() => { setInstallmentModal(detailModal.id); installmentForm.resetFields(); }} > 添加分期
{detailModal.installments?.length > 0 ? ( ( } onClick={() => handlePayInstallment(item.id)} > 标记已缴 ), handleDeleteInstallment(item.id)} > }> 删除 ].filter(Boolean)} > {installmentStatusMap[item.status]?.text || item.status} )} /> ) : (

暂无分期记录

)}
)}
{/* Add Installment Modal */} setInstallmentModal(null)} okText="确认" >
); }; export default DepositsPage;