167 lines
5.5 KiB
TypeScript
167 lines
5.5 KiB
TypeScript
// aislop-ignore-file: duplicate-block -- 表格/表单声明结构相似且参数不同,渲染逻辑已共享组件化
|
|
import React from 'react';
|
|
import {
|
|
DatePicker,
|
|
Form,
|
|
Input,
|
|
InputNumber,
|
|
Modal,
|
|
Select,
|
|
} from 'antd';
|
|
|
|
const { RangePicker } = DatePicker;
|
|
|
|
export const RoomExpenseModal: React.FC<{
|
|
open: boolean;
|
|
editing: boolean;
|
|
saving: boolean;
|
|
form: ReturnType<typeof Form.useForm>[0];
|
|
rooms: any[];
|
|
typeOptions: Array<{ value: string; label: string }>;
|
|
onOk: () => void;
|
|
onCancel: () => void;
|
|
}> = ({ open, editing, saving, form, rooms, typeOptions, onOk, onCancel }) => {
|
|
return (
|
|
<Modal
|
|
title={editing ? '编辑宿舍费用' : '录入宿舍费用'}
|
|
open={open}
|
|
onOk={onOk}
|
|
onCancel={onCancel}
|
|
okText={editing ? '保存' : '确认录入'}
|
|
confirmLoading={saving}
|
|
>
|
|
<Form form={form} layout="vertical">
|
|
<Form.Item name="roomId" label="宿舍" rules={[{ required: true }]}>
|
|
<Select
|
|
showSearch
|
|
optionFilterProp="label"
|
|
options={rooms.map((r: any) => ({
|
|
value: r.id,
|
|
label: `${r.roomNumber} (${r.building || ''})`,
|
|
}))}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="expenseType" label="费用类型" rules={[{ required: true }]}>
|
|
<Select options={typeOptions} />
|
|
</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%' }}
|
|
placeholder={['开始日期', '结束日期']}
|
|
format="YYYY-MM-DD"
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="description" label="说明">
|
|
<Input.TextArea rows={2} />
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export const UtilityModal: React.FC<{
|
|
open: boolean;
|
|
saving: boolean;
|
|
form: ReturnType<typeof Form.useForm>[0];
|
|
students: any[];
|
|
onOk: () => void;
|
|
onCancel: () => void;
|
|
}> = ({ open, saving, form, students, onOk, onCancel }) => {
|
|
return (
|
|
<Modal
|
|
title="添加学生水电费并立即出账"
|
|
open={open}
|
|
onOk={onOk}
|
|
onCancel={onCancel}
|
|
okText="生成账单并扣余额"
|
|
confirmLoading={saving}
|
|
>
|
|
<Form form={form} 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>
|
|
);
|
|
};
|
|
|
|
export const PersonalExpenseModal: React.FC<{
|
|
open: boolean;
|
|
editing: boolean;
|
|
saving: boolean;
|
|
form: ReturnType<typeof Form.useForm>[0];
|
|
students: any[];
|
|
rooms: any[];
|
|
personalTypeOptions: Array<{ value: string; label: string }>;
|
|
onOk: () => void;
|
|
onCancel: () => void;
|
|
}> = ({ open, editing, saving, form, students, rooms, personalTypeOptions, onOk, onCancel }) => {
|
|
return (
|
|
<Modal
|
|
title={editing ? '编辑个人费用' : '录入个人附加费'}
|
|
open={open}
|
|
onOk={onOk}
|
|
onCancel={onCancel}
|
|
okText={editing ? '保存' : '确认录入'}
|
|
confirmLoading={saving}
|
|
>
|
|
<Form form={form} layout="vertical">
|
|
<Form.Item name="studentId" label="学生" rules={[{ required: true }]}>
|
|
<Select
|
|
showSearch
|
|
optionFilterProp="label"
|
|
options={students.map((s: any) => ({ value: s.id, label: s.name }))}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="roomId" label="关联宿舍">
|
|
<Select
|
|
allowClear
|
|
showSearch
|
|
optionFilterProp="label"
|
|
options={rooms.map((r: any) => ({ value: r.id, label: r.roomNumber }))}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="expenseType" label="费用类型" rules={[{ required: true }]}>
|
|
<Select options={personalTypeOptions} />
|
|
</Form.Item>
|
|
<Form.Item name="amount" label="金额(元)" rules={[{ required: true }]}>
|
|
<InputNumber min={0.01} precision={2} style={{ width: '100%' }} />
|
|
</Form.Item>
|
|
<Form.Item name="expenseDate" label="费用日期" rules={[{ required: true }]}>
|
|
<DatePicker style={{ width: '100%' }} placeholder="选择日期" format="YYYY-MM-DD" />
|
|
</Form.Item>
|
|
<Form.Item name="description" label="说明">
|
|
<Input.TextArea rows={2} />
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
);
|
|
};
|