first commit
This commit is contained in:
260
src/pages/Admin/Student/components/GradeManage.tsx
Normal file
260
src/pages/Admin/Student/components/GradeManage.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Input, Button, Table, message, Modal, Popconfirm } from 'antd';
|
||||
import { ExclamationCircleOutlined, SettingOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import { request } from '@umijs/max';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import styles from '../index.less';
|
||||
|
||||
interface GradeRecord {
|
||||
id: string;
|
||||
name: string;
|
||||
createTime: string;
|
||||
graduated?: boolean;
|
||||
}
|
||||
|
||||
interface GradeManageProps {
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
const GradeManage: React.FC<GradeManageProps> = ({ onBack }) => {
|
||||
const [filterName, setFilterName] = useState('');
|
||||
const [list, setList] = useState<GradeRecord[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 新增/编辑弹窗
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [modalLoading, setModalLoading] = useState(false);
|
||||
const [editingRecord, setEditingRecord] = useState<GradeRecord | null>(null);
|
||||
const [gradeName, setGradeName] = useState('');
|
||||
|
||||
const fetchList = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const params: Record<string, any> = { page, pageSize };
|
||||
if (filterName) params.name = filterName;
|
||||
const res = await request('/api/admin/grade', { params });
|
||||
if (res.code === 0) {
|
||||
setList(res.data.list);
|
||||
setTotal(res.data.total);
|
||||
}
|
||||
} catch {
|
||||
message.error('获取数据失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [page, pageSize, filterName]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchList();
|
||||
}, [fetchList]);
|
||||
|
||||
const handleSearch = () => {
|
||||
setPage(1);
|
||||
fetchList();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setFilterName('');
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handleOpenAdd = () => {
|
||||
setEditingRecord(null);
|
||||
setGradeName('');
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
const handleOpenEdit = (record: GradeRecord) => {
|
||||
setEditingRecord(record);
|
||||
setGradeName(record.name);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
const handleModalSubmit = async () => {
|
||||
if (!gradeName.trim()) {
|
||||
message.warning('请输入年级名称');
|
||||
return;
|
||||
}
|
||||
setModalLoading(true);
|
||||
try {
|
||||
const url = editingRecord ? '/api/admin/grade/edit' : '/api/admin/grade/add';
|
||||
const data = editingRecord ? { id: editingRecord.id, name: gradeName } : { name: gradeName };
|
||||
const res = await request(url, { method: 'POST', data });
|
||||
if (res.code === 0) {
|
||||
message.success(editingRecord ? '编辑成功' : '新增成功');
|
||||
setModalVisible(false);
|
||||
fetchList();
|
||||
} else {
|
||||
message.error(res.message);
|
||||
}
|
||||
} catch {
|
||||
message.error('操作失败');
|
||||
} finally {
|
||||
setModalLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleGraduateConfirm = async (record: GradeRecord) => {
|
||||
const res = await request('/api/admin/grade/graduate', {
|
||||
method: 'POST',
|
||||
data: { id: record.id },
|
||||
});
|
||||
if (res.code === 0) {
|
||||
message.success('转毕业成功');
|
||||
fetchList();
|
||||
} else {
|
||||
message.error(res.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRestoreConfirm = async (record: GradeRecord) => {
|
||||
const res = await request('/api/admin/grade/restore', {
|
||||
method: 'POST',
|
||||
data: { id: record.id },
|
||||
});
|
||||
if (res.code === 0) {
|
||||
message.success('还原成功');
|
||||
fetchList();
|
||||
} else {
|
||||
message.error(res.message);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ColumnsType<GradeRecord> = [
|
||||
{ title: '年级名称', dataIndex: 'name', key: 'name' },
|
||||
{ title: '创建时间', dataIndex: 'createTime', key: 'createTime' },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 160,
|
||||
render: (_, record) => (
|
||||
<span className={styles.actionCell}>
|
||||
<a className={styles.actionLink} onClick={() => handleOpenEdit(record)}>编辑</a>
|
||||
<span className={styles.actionDivider}>|</span>
|
||||
{record.graduated ? (
|
||||
<Popconfirm
|
||||
title="还原"
|
||||
description="确定要还原该年级吗?"
|
||||
onConfirm={() => handleRestoreConfirm(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
overlayStyle={{ maxWidth: 200 }}
|
||||
>
|
||||
<a className={styles.actionLink}>还原</a>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Popconfirm
|
||||
title="转毕业"
|
||||
description="转毕业后此年级下的所有学生将不再计入数据统计。"
|
||||
onConfirm={() => handleGraduateConfirm(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
icon={<ExclamationCircleOutlined style={{ color: '#faad14' }} />}
|
||||
overlayStyle={{ maxWidth: 200 }}
|
||||
>
|
||||
<a className={styles.actionLink}>转毕业</a>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<h2 className={styles.title}>年级管理</h2>
|
||||
|
||||
{/* 筛选区域 */}
|
||||
<div className={styles.filterRow}>
|
||||
<div className={styles.filterItem}>
|
||||
<span className={styles.filterLabel}>年级</span>
|
||||
<Input
|
||||
className={styles.filterInput}
|
||||
placeholder="请输入"
|
||||
value={filterName}
|
||||
onChange={(e) => setFilterName(e.target.value)}
|
||||
allowClear
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.filterBtns}>
|
||||
<Button className={styles.searchBtn} onClick={handleSearch}>查询</Button>
|
||||
<Button className={styles.resetBtn} onClick={handleReset}>重置</Button>
|
||||
</div>
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
|
||||
{/* 分割线 */}
|
||||
<div className={styles.divider} />
|
||||
|
||||
{/* 操作按钮栏 */}
|
||||
<div className={styles.actionBar}>
|
||||
<div className={styles.actionBarLeft}>
|
||||
<Button className={styles.primaryOutlineBtn} icon={<PlusOutlined />} onClick={handleOpenAdd}>新增年级</Button>
|
||||
</div>
|
||||
<div className={styles.actionBarRight}>
|
||||
<Button className={styles.defaultBtn} onClick={onBack} style={{ marginRight: 12 }}>返回</Button>
|
||||
<SettingOutlined className={styles.settingIcon} />
|
||||
<span className={styles.settingText}>列表设置</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 数据表格 */}
|
||||
<div className={styles.dataTable}>
|
||||
<Table<GradeRecord>
|
||||
columns={columns}
|
||||
dataSource={list}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{
|
||||
current: page,
|
||||
pageSize,
|
||||
total,
|
||||
showTotal: (t) => `共${t}条`,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
onChange: (p, ps) => {
|
||||
setPage(p);
|
||||
setPageSize(ps);
|
||||
},
|
||||
}}
|
||||
size="middle"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 新增/编辑年级弹窗 */}
|
||||
<Modal
|
||||
open={modalVisible}
|
||||
title={editingRecord ? '编辑年级' : '新增年级'}
|
||||
onCancel={() => setModalVisible(false)}
|
||||
footer={null}
|
||||
width={400}
|
||||
centered
|
||||
className={styles.addModal}
|
||||
destroyOnClose
|
||||
>
|
||||
<div className={styles.addModalBody} style={{ padding: '24px 0' }}>
|
||||
<div className={styles.formField}>
|
||||
<label className={styles.formLabel}><span className={styles.formRequired}>*</span>年级名称</label>
|
||||
<Input
|
||||
className={styles.formInput}
|
||||
placeholder="请输入年级名称"
|
||||
value={gradeName}
|
||||
onChange={(e) => setGradeName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.addModalFooter}>
|
||||
<Button className={styles.confirmBtn} onClick={handleModalSubmit} loading={modalLoading}>确定</Button>
|
||||
<Button className={styles.cancelBtn} onClick={() => setModalVisible(false)}>取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GradeManage;
|
||||
Reference in New Issue
Block a user