forked from wangziqi/gongxue-base
chore: commit oxfmt formatting changes and verify artifacts
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { Table, Button, Modal, Form, Select, DatePicker, InputNumber, Input, Space, message, Tag, Popconfirm } from 'antd';
|
||||
import {
|
||||
Table,
|
||||
Button,
|
||||
Modal,
|
||||
Form,
|
||||
Select,
|
||||
DatePicker,
|
||||
InputNumber,
|
||||
Input,
|
||||
Space,
|
||||
message,
|
||||
Tag,
|
||||
Popconfirm,
|
||||
} from 'antd';
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import api from '../../api';
|
||||
@@ -26,17 +39,18 @@ const DepositsPage: React.FC = () => {
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const [d, s]: any[] = await Promise.all([
|
||||
api.get('/deposits'),
|
||||
api.get('/students'),
|
||||
]);
|
||||
const [d, s]: any[] = await Promise.all([api.get('/deposits'), api.get('/students')]);
|
||||
setData(d);
|
||||
setStudents(s);
|
||||
} catch (e) { console.error(e); }
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => { fetchData(); }, []);
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
return data.filter((d: any) => {
|
||||
@@ -62,7 +76,9 @@ const DepositsPage: React.FC = () => {
|
||||
setCreateModal(false);
|
||||
createForm.resetFields();
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '操作失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefund = async () => {
|
||||
@@ -78,7 +94,9 @@ const DepositsPage: React.FC = () => {
|
||||
setRefundModal(null);
|
||||
refundForm.resetFields();
|
||||
fetchData();
|
||||
} catch (e: any) { message.error(e?.message || '操作失败'); }
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
@@ -86,28 +104,54 @@ const DepositsPage: React.FC = () => {
|
||||
{ title: '押金金额', dataIndex: 'amount', render: (v: number) => `¥${Number(v).toFixed(2)}` },
|
||||
{ title: '缴纳日期', dataIndex: 'paidDate' },
|
||||
{
|
||||
title: '状态', dataIndex: 'status',
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
render: (s: string) => <Tag color={statusMap[s]?.color}>{statusMap[s]?.text || s}</Tag>,
|
||||
},
|
||||
{ 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: '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', render: (v: any) => v || '-' },
|
||||
{ title: '退还日期', dataIndex: 'refundDate', render: (v: any) => v || '-' },
|
||||
{ title: '备注', dataIndex: 'notes', render: (v: any) => v || '-' },
|
||||
{
|
||||
title: '操作', width: 160,
|
||||
title: '操作',
|
||||
width: 160,
|
||||
render: (_: any, record: any) => (
|
||||
<Space>
|
||||
{record.status === 'paid' && (
|
||||
<PermissionButton permission="deposit:edit" size="small" type="primary" onClick={() => {
|
||||
setRefundModal(record);
|
||||
refundForm.setFieldsValue({ refundDate: dayjs(), deductionAmount: 0 });
|
||||
}}>退还</PermissionButton>
|
||||
<PermissionButton
|
||||
permission="deposit:edit"
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
setRefundModal(record);
|
||||
refundForm.setFieldsValue({ refundDate: dayjs(), deductionAmount: 0 });
|
||||
}}
|
||||
>
|
||||
退还
|
||||
</PermissionButton>
|
||||
)}
|
||||
<PermissionButton permission="deposit:delete">
|
||||
<Popconfirm title="确定删除?" onConfirm={async () => {
|
||||
try { await api.delete(`/deposits/${record.id}`); message.success('删除成功'); fetchData(); } catch (e: any) { message.error(e?.message || '删除失败'); }
|
||||
}}>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
await api.delete(`/deposits/${record.id}`);
|
||||
message.success('删除成功');
|
||||
fetchData();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '删除失败');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button size="small" danger icon={<DeleteOutlined />} />
|
||||
</Popconfirm>
|
||||
</PermissionButton>
|
||||
@@ -118,21 +162,31 @@ const DepositsPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 }}>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<Space wrap>
|
||||
<Input.Search
|
||||
placeholder="搜索学生姓名"
|
||||
allowClear
|
||||
style={{ width: 180 }}
|
||||
onSearch={v => setSearchText(v)}
|
||||
onChange={e => { if (!e.target.value) setSearchText(''); }}
|
||||
onSearch={(v) => setSearchText(v)}
|
||||
onChange={(e) => {
|
||||
if (!e.target.value) setSearchText('');
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
placeholder="状态筛选"
|
||||
allowClear
|
||||
style={{ width: 120 }}
|
||||
value={filterStatus}
|
||||
onChange={v => setFilterStatus(v)}
|
||||
onChange={(v) => setFilterStatus(v)}
|
||||
options={[
|
||||
{ value: 'paid', label: '已缴' },
|
||||
{ value: 'refunded', label: '已全退' },
|
||||
@@ -141,17 +195,51 @@ const DepositsPage: React.FC = () => {
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
<PermissionButton permission="deposit:create" type="primary" icon={<PlusOutlined />} onClick={() => { createForm.resetFields(); createForm.setFieldsValue({ amount: 500, paidDate: dayjs() }); setCreateModal(true); }}>
|
||||
<PermissionButton
|
||||
permission="deposit:create"
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => {
|
||||
createForm.resetFields();
|
||||
createForm.setFieldsValue({ amount: 500, paidDate: dayjs() });
|
||||
setCreateModal(true);
|
||||
}}
|
||||
>
|
||||
收取押金
|
||||
</PermissionButton>
|
||||
</div>
|
||||
<Table columns={columns} dataSource={filteredData} rowKey="id" loading={loading} pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }} />
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={filteredData}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{ pageSize: 15, showTotal: (total) => `共 ${total} 条` }}
|
||||
/>
|
||||
|
||||
<Modal title="收取押金" open={createModal} onOk={handleCreate} onCancel={() => setCreateModal(false)} okText="确认">
|
||||
<Modal
|
||||
title="收取押金"
|
||||
open={createModal}
|
||||
onOk={handleCreate}
|
||||
onCancel={() => setCreateModal(false)}
|
||||
okText="确认"
|
||||
>
|
||||
<Form form={createForm} layout="vertical">
|
||||
<Form.Item name="studentId" label="学生" rules={[{ required: true, message: '请选择学生' }]}>
|
||||
<Select showSearch optionFilterProp="label" placeholder="搜索并选择学生"
|
||||
options={students.filter((s: any) => s.status === 'active').map((s: any) => ({ value: s.id, label: `${s.name} (${s.idNumber || s.phone || ''})` }))} />
|
||||
<Form.Item
|
||||
name="studentId"
|
||||
label="学生"
|
||||
rules={[{ required: true, message: '请选择学生' }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
placeholder="搜索并选择学生"
|
||||
options={students
|
||||
.filter((s: any) => s.status === 'active')
|
||||
.map((s: any) => ({
|
||||
value: s.id,
|
||||
label: `${s.name} (${s.idNumber || s.phone || ''})`,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="amount" label="押金金额(元)" rules={[{ required: true }]}>
|
||||
<InputNumber min={0} precision={2} style={{ width: '100%' }} />
|
||||
@@ -165,7 +253,13 @@ const DepositsPage: React.FC = () => {
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal title={`退还押金 - ${refundModal?.student?.name}`} open={!!refundModal} onOk={handleRefund} onCancel={() => setRefundModal(null)} okText="确认退还">
|
||||
<Modal
|
||||
title={`退还押金 - ${refundModal?.student?.name}`}
|
||||
open={!!refundModal}
|
||||
onOk={handleRefund}
|
||||
onCancel={() => setRefundModal(null)}
|
||||
okText="确认退还"
|
||||
>
|
||||
<Form form={refundForm} layout="vertical">
|
||||
<div style={{ marginBottom: 16, padding: 12, background: '#f5f5f5', borderRadius: 8 }}>
|
||||
押金金额: <strong>¥{Number(refundModal?.amount || 0).toFixed(2)}</strong>
|
||||
@@ -174,7 +268,12 @@ const DepositsPage: React.FC = () => {
|
||||
<DatePicker style={{ width: '100%' }} placeholder="选择退还日期" format="YYYY-MM-DD" />
|
||||
</Form.Item>
|
||||
<Form.Item name="deductionAmount" label="扣除金额(元)" extra="如无扣除填0">
|
||||
<InputNumber min={0} max={Number(refundModal?.amount || 500)} precision={2} style={{ width: '100%' }} />
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={Number(refundModal?.amount || 500)}
|
||||
precision={2}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="deductionReason" label="扣除原因">
|
||||
<Input placeholder="如:房间损坏赔偿" />
|
||||
|
||||
Reference in New Issue
Block a user