feat: add student wallet utility billing

This commit is contained in:
2026-07-14 20:39:32 +08:00
parent b480070e69
commit c75a08affe
29 changed files with 986 additions and 548 deletions

View File

@@ -46,10 +46,12 @@ const ExpensesPage: React.FC = () => {
const [loading, setLoading] = useState(false);
const [roomModal, setRoomModal] = useState(false);
const [personalModal, setPersonalModal] = useState(false);
const [utilityModal, setUtilityModal] = useState(false);
const [editingRoom, setEditingRoom] = useState<any>(null);
const [editingPersonal, setEditingPersonal] = useState<any>(null);
const [roomForm] = Form.useForm();
const [personalForm] = Form.useForm();
const [utilityForm] = Form.useForm();
const [roomSearch, setRoomSearch] = useState('');
const [roomTypeFilter, setRoomTypeFilter] = useState<string | undefined>(undefined);
const [personalSearch, setPersonalSearch] = useState('');
@@ -192,6 +194,27 @@ const ExpensesPage: React.FC = () => {
}
};
const handleStudentUtility = async () => {
const values = await utilityForm.validateFields();
setSaving(true);
try {
const result: any = await api.post('/expenses/student-utility', {
studentId: values.studentId,
expenseType: values.expenseType,
amount: values.amount,
periodStart: values.period[0].format('YYYY-MM-DD'),
periodEnd: values.period[1].format('YYYY-MM-DD'),
description: values.description,
});
const bill = result.bill;
message.success(`账单已生成,已从余额扣除 ¥${Number(bill.paidAmount || 0).toFixed(2)},待补缴 ¥${Number(bill.outstandingAmount || 0).toFixed(2)}`);
setUtilityModal(false);
utilityForm.resetFields();
fetchData();
} catch (e: any) { message.error(e?.message || '水电费出账失败'); }
finally { setSaving(false); }
};
const handlePersonalExpense = async () => {
setSaving(true);
try {
@@ -560,6 +583,13 @@ const ExpensesPage: React.FC = () => {
</PermissionButton>
</Popconfirm>
<PermissionButton
permission="expense:create"
icon={<PlusOutlined />}
onClick={() => { utilityForm.resetFields(); setUtilityModal(true); }}
>
</PermissionButton>
<PermissionButton
permission="expense:create"
type="primary"
@@ -639,6 +669,19 @@ const ExpensesPage: React.FC = () => {
</Form>
</Modal>
<Modal title="添加学生水电费并立即出账" open={utilityModal} onOk={handleStudentUtility} onCancel={() => setUtilityModal(false)} okText="生成账单并扣余额" confirmLoading={saving}>
<Form form={utilityForm} layout="vertical">
<Form.Item name="studentId" label="学生" rules={[{ required: true }]}>
<Select showSearch optionFilterProp="label" options={students.map((student: any) => ({ value: student.id, label: `${student.name} (${student.studentNo || `#${student.id}`})` }))} />
</Form.Item>
<Form.Item name="expenseType" label="费用类型" rules={[{ required: true }]}><Select options={[{ value: 'water', label: '水费' }, { value: 'electricity', label: '电费' }]} /></Form.Item>
<Form.Item name="amount" label="金额(元)" rules={[{ required: true }]}><InputNumber min={0.01} precision={2} style={{ width: '100%' }} /></Form.Item>
<Form.Item name="period" label="账单周期" rules={[{ required: true }]}><RangePicker style={{ width: '100%' }} format="YYYY-MM-DD" /></Form.Item>
<Form.Item name="description" label="说明"><Input.TextArea rows={2} maxLength={300} /></Form.Item>
</Form>
</Modal>
<Modal
title={editingPersonal ? '编辑个人费用' : '录入个人附加费'}
open={personalModal}