diff --git a/apps/admin/src/pages/Classes/index.tsx b/apps/admin/src/pages/Classes/index.tsx index 4afe522..1de4df8 100644 --- a/apps/admin/src/pages/Classes/index.tsx +++ b/apps/admin/src/pages/Classes/index.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState, useMemo, useCallback } from 'react'; import { Table, Button, Input, Select, Space, Tag, Modal, Form, InputNumber, - DatePicker, Popconfirm, message, Card, + DatePicker, Popconfirm, message, Card, Switch, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; -import { PlusOutlined, SearchOutlined, TeamOutlined } from '@ant-design/icons'; +import { PlusOutlined, SearchOutlined, TeamOutlined, InboxOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import dayjs from 'dayjs'; import api from '../../api'; @@ -27,6 +27,7 @@ interface ClassItem { maxStudents: number; notes: string | null; studentCount: number; + isArchived: boolean; createdAt: string; updatedAt: string; } @@ -76,21 +77,34 @@ const ClassesPage: React.FC = () => { const [filterType, setFilterType] = useState(); const [form] = Form.useForm(); const [saving, setSaving] = useState(false); + const [showArchived, setShowArchived] = useState(false); + + const handleArchive = async (id: number, archive: boolean) => { + try { + await api.put(`/classes/${id}/${archive ? 'archive' : 'restore'}`); + message.success(archive ? '已归档' : '已恢复'); + fetchData(); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '操作失败'); + } + }; const fetchData = useCallback(async () => { setLoading(true); try { - const params: ClassQueryParams = {}; + const params: Record = {}; if (filterStatus) params.status = filterStatus; if (filterType) params.classType = filterType; - const res = await api.get('/classes', { params }); + params.isArchived = showArchived; + const res = await api.get('/classes', { params } as Record); setData(res); } catch (e) { console.error(e); } finally { setLoading(false); } - }, [filterStatus, filterType]); + }, [filterStatus, filterType, showArchived]); useEffect(() => { fetchData(); }, [fetchData]); @@ -180,7 +194,7 @@ const ClassesPage: React.FC = () => { }, }, { - title: '操作', width: 200, + title: '操作', width: 280, render: (_: unknown, r: ClassItem) => ( , + ] : [ + , + , + ]} + width={560} + > + {syncResult ? ( + /* ── 同步结果 ── */ +
+ + + + + + + + + + + + + + + {syncResult.skippedNoMapping > 0 && ( + + )} + {syncResult.groups.length > 0 && ( +
+
按部门分组:
+ {syncResult.groups.map((g) => ( + + {g.deptName}:{g.itemCount} 条排班 + + ))} +
+ )} +
+ ) : syncStatus ? ( + /* ── 同步确认信息 ── */ +
+ + + + + + + + + + + + {syncStatus.mappedTeachers < syncStatus.totalTeachers && ( + + )} +
+
同步参数
+ + 起始日期: + d && setSyncDateFrom(d)} allowClear={false} /> + 天数: +