refactor(admin): extract StudentProfileContent component and reuse in drawer

This commit is contained in:
2026-07-06 17:22:09 +08:00
parent b8563fbde0
commit 85872d6564
3 changed files with 927 additions and 902 deletions

View File

@@ -16,7 +16,6 @@ import {
Col,
Card,
Drawer,
Tabs,
Descriptions,
} from 'antd';
import {
@@ -31,6 +30,7 @@ import {
} from '@ant-design/icons';
import api from '../../api';
import PermissionButton from '../../components/PermissionButton';
import StudentProfileContent from '../../components/StudentProfileContent';
const maskPhone = (phone: string) => {
if (!phone || phone.length < 7) return phone || '-';
@@ -83,18 +83,12 @@ const StudentsPage: React.FC = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
const [enrollmentData, setEnrollmentData] = useState<Record<number, EnrollmentInfo[]>>({});
const [drawerOpen, setDrawerOpen] = useState(false);
const [drawerData, setDrawerData] = useState<any>(null);
const [drawerLoading, setDrawerLoading] = useState(false);
const [drawerStudentId, setDrawerStudentId] = useState<number | undefined>(undefined);
const [form] = Form.useForm();
const openDrawer = async (studentId: number) => {
const openDrawer = (studentId: number) => {
setDrawerStudentId(studentId);
setDrawerOpen(true);
setDrawerLoading(true);
try {
const res = await api.get(`/archive/${studentId}`);
setDrawerData(res);
} catch { setDrawerData(null); }
setDrawerLoading(false);
};
const handleViewSensitive = (studentId: number, field: string, value: string) => {
@@ -583,98 +577,18 @@ const StudentsPage: React.FC = () => {
</Modal>
<Drawer
title={drawerData?.student?.name ? `${drawerData.student.name} — 学生档案` : '学生档案'}
title={null}
open={drawerOpen}
onClose={() => { setDrawerOpen(false); setDrawerData(null); }}
onClose={() => { setDrawerOpen(false); }}
width={720}
loading={drawerLoading}
>
{drawerData && (<div>
<Tabs items={[
{
key: 'info', label: '基础信息',
children: (
<Descriptions column={2} size="small" bordered>
<Descriptions.Item label="姓名">{drawerData.student?.name}</Descriptions.Item>
<Descriptions.Item label="学号">{drawerData.student?.studentNo || '-'}</Descriptions.Item>
<Descriptions.Item label="电话">{drawerData.student?.phone || '-'}</Descriptions.Item>
<Descriptions.Item label="身份证">{drawerData.student?.idNumber || '-'}</Descriptions.Item>
<Descriptions.Item label="状态"><Tag>{drawerData.student?.status}</Tag></Descriptions.Item>
<Descriptions.Item label="目标院校">{drawerData.profile?.targetCollege || '-'}</Descriptions.Item>
<Descriptions.Item label="目标专业">{drawerData.profile?.targetMajor || '-'}</Descriptions.Item>
<Descriptions.Item label="科类方向">{drawerData.profile?.subjectDirection || '-'}</Descriptions.Item>
<Descriptions.Item label="年级">{drawerData.profile?.grade || '-'}</Descriptions.Item>
<Descriptions.Item label="校区">{drawerData.profile?.campusLocation || '-'}</Descriptions.Item>
<Descriptions.Item label="建档日期">{drawerData.profile?.profileDate || '-'}</Descriptions.Item>
</Descriptions>
),
},
{
key: 'enrollments', label: `报读记录 (${drawerData.enrollments?.length || 0})`,
children: drawerData.enrollments?.length ? (
<Table rowKey="id" size="small" pagination={false} dataSource={drawerData.enrollments} columns={[
{ title: '课程类别', dataIndex: 'courseCategory' },
{ title: '班型', dataIndex: 'classType' },
{ title: '班级', dataIndex: 'className' },
{ title: '班主任', dataIndex: 'headTeacher' },
{ title: '开课', dataIndex: 'startDate' },
{ title: '结课', dataIndex: 'endDate' },
]} />
) : <div style={{ color: '#999' }}></div>,
},
{
key: 'exams', label: `考试成绩 (${drawerData.examScores?.length || 0})`,
children: drawerData.examScores?.length ? (
<Table rowKey="id" size="small" pagination={false} dataSource={drawerData.examScores} columns={[
{ title: '类型', dataIndex: 'examType' },
{ title: '科目', dataIndex: 'subject' },
{ title: '分数', dataIndex: 'score' },
{ title: '班均', dataIndex: 'classAvg', render: (v: number) => v ?? '-' },
{ title: '排名', dataIndex: 'rank', render: (v: number) => v ?? '-' },
{ title: '日期', dataIndex: 'examDate' },
]} />
) : <div style={{ color: '#999' }}></div>,
},
{
key: 'result', label: '录取结果',
children: drawerData.result ? (
<Descriptions column={2} size="small" bordered>
<Descriptions.Item label="文化课成绩">{drawerData.result.cultureFinalScore ?? '-'}</Descriptions.Item>
<Descriptions.Item label="专业课成绩">{drawerData.result.professionalFinalScore ?? '-'}</Descriptions.Item>
<Descriptions.Item label="录取状态">{drawerData.result.admissionStatus || '-'}</Descriptions.Item>
<Descriptions.Item label="录取院校">{drawerData.result.admittedCollege || '-'}</Descriptions.Item>
<Descriptions.Item label="录取专业" span={2}>{drawerData.result.admittedMajor || '-'}</Descriptions.Item>
</Descriptions>
) : <div style={{ color: '#999' }}></div>,
},
{
key: 'learning', label: `学情记录 (${drawerData.learningRecords?.length || 0})`,
children: drawerData.learningRecords?.length ? (
<Table rowKey="id" size="small" pagination={false} dataSource={drawerData.learningRecords} columns={[
{ title: '日期', dataIndex: 'recordDate', width: 100 },
{ title: '类型', dataIndex: 'recordType', width: 80 },
{ title: '内容', dataIndex: 'content', ellipsis: true },
{ title: '跟进方式', dataIndex: 'followUpMethod', width: 100 },
{ title: '下一步', dataIndex: 'nextStep', width: 100 },
]} />
) : <div style={{ color: '#999' }}></div>,
},
{
key: 'attachments', label: `附件 (${drawerData.attachments?.length || 0})`,
children: drawerData.attachments?.length ? (
<Table rowKey="id" size="small" pagination={false} dataSource={drawerData.attachments} columns={[
{ title: '分类', dataIndex: 'category', width: 80 },
{ title: '文件名', dataIndex: 'fileName', ellipsis: true },
{ title: '大小', dataIndex: 'fileSize', width: 80, render: (v: number) => v ? `${(v / 1024).toFixed(1)} KB` : '-' },
]} />
) : <div style={{ color: '#999' }}></div>,
},
]} />
<Button type="primary" icon={<DownloadOutlined />} style={{ marginTop: 16 }} onClick={() => {
const token = localStorage.getItem('token');
window.open(`/api/archive/${drawerData?.student?.id}/report?token=${token}`, '_blank');
}}></Button>
</div>)}
{drawerStudentId && (
<StudentProfileContent
studentId={drawerStudentId}
inDrawer
onClose={() => { setDrawerOpen(false); }}
/>
)}
</Drawer>
</div>
);