This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Button, Card, Col, Empty, Form, Input, Progress, Row, Select, Space, Tag } from 'antd';
|
||||
import { CalendarOutlined, PlusOutlined, SearchOutlined, TeamOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Col, Empty, Form, Input, Popconfirm, Progress, Row, Select, Space, Switch, Tag } from 'antd';
|
||||
import { CalendarOutlined, InboxOutlined, PlusOutlined, SearchOutlined, TeamOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import api from '../../api';
|
||||
@@ -21,6 +21,7 @@ const ExamsPage: React.FC = () => {
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [examType, setExamType] = useState<string>();
|
||||
const [classId, setClassId] = useState<number>();
|
||||
const [showArchived, setShowArchived] = useState(false);
|
||||
|
||||
const loadClasses = useCallback(async () => {
|
||||
const result = await api.get<ClassOption[]>('/classes');
|
||||
@@ -34,6 +35,7 @@ const ExamsPage: React.FC = () => {
|
||||
if (keyword.trim()) params.set('keyword', keyword.trim());
|
||||
if (examType) params.set('examType', examType);
|
||||
if (classId) params.set('classId', String(classId));
|
||||
params.set('isArchived', String(showArchived));
|
||||
const result = await api.get<ExamItem[]>(`/exams?${params.toString()}`);
|
||||
setData(result ?? []);
|
||||
} catch (error) {
|
||||
@@ -41,7 +43,7 @@ const ExamsPage: React.FC = () => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [classId, examType, keyword]);
|
||||
}, [classId, examType, keyword, showArchived]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadClasses().catch((error: { message?: string }) => message.error(error?.message || '加载班级失败'));
|
||||
@@ -80,6 +82,16 @@ const ExamsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const changeArchiveStatus = async (exam: ExamItem, archive: boolean) => {
|
||||
try {
|
||||
await api.put(`/exams/${exam.id}/${archive ? 'archive' : 'restore'}`);
|
||||
message.success(archive ? '考试已归档' : '考试已恢复');
|
||||
await loadExams();
|
||||
} catch (error) {
|
||||
message.error((error as { message?: string })?.message || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="exam-page">
|
||||
<div className="exam-toolbar">
|
||||
@@ -89,6 +101,11 @@ const ExamsPage: React.FC = () => {
|
||||
<Select value={classId} onChange={setClassId} options={classOptions} placeholder="考试班级" allowClear showSearch optionFilterProp="label" style={{ width: 180 }} />
|
||||
</Space>
|
||||
<Space wrap>
|
||||
<span className="exam-archive-toggle">
|
||||
<InboxOutlined />
|
||||
归档
|
||||
<Switch size="small" checked={showArchived} onChange={setShowArchived} />
|
||||
</span>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>创建考试</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -105,9 +122,27 @@ const ExamsPage: React.FC = () => {
|
||||
className="exam-card"
|
||||
loading={loading}
|
||||
title={<Space><Tag color="blue">{exam.examType}</Tag><span>{exam.examName}</span></Space>}
|
||||
extra={<Tag color="green">成绩录入</Tag>}
|
||||
extra={<Tag color={exam.status === 'archived' ? 'default' : 'green'}>{exam.status === 'archived' ? '已归档' : '成绩录入'}</Tag>}
|
||||
actions={[
|
||||
<span key="detail" onClick={() => navigate(`/exams/${exam.id}`)}>查看成绩</span>,
|
||||
exam.status === 'archived' ? (
|
||||
<Popconfirm
|
||||
key="restore"
|
||||
title="确认恢复该考试?"
|
||||
onConfirm={() => changeArchiveStatus(exam, false)}
|
||||
>
|
||||
<span>恢复</span>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Popconfirm
|
||||
key="archive"
|
||||
title="确认归档该考试?"
|
||||
description={`当前已录入 ${exam.enteredScores}/${exam.totalStudents} 人,归档后成绩将变为只读。`}
|
||||
onConfirm={() => changeArchiveStatus(exam, true)}
|
||||
>
|
||||
<span>归档</span>
|
||||
</Popconfirm>
|
||||
),
|
||||
]}
|
||||
>
|
||||
<div className="exam-meta"><span>科目</span><strong>{exam.subject}</strong></div>
|
||||
|
||||
Reference in New Issue
Block a user