From 5d102ca3c4234e9c0cc7d7517be2bbc42f35fec3 Mon Sep 17 00:00:00 2001 From: wangziqi Date: Mon, 6 Jul 2026 01:16:55 +0800 Subject: [PATCH] feat: add class roster export button in class detail page --- apps/admin/src/pages/Classes/detail.tsx | 30 +++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/pages/Classes/detail.tsx b/apps/admin/src/pages/Classes/detail.tsx index 1c1b855..2b73e33 100644 --- a/apps/admin/src/pages/Classes/detail.tsx +++ b/apps/admin/src/pages/Classes/detail.tsx @@ -5,7 +5,7 @@ import { Popconfirm, message, Form, Input, DatePicker, InputNumber, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; -import { ArrowLeftOutlined, PlusOutlined } from '@ant-design/icons'; +import { ArrowLeftOutlined, PlusOutlined, DownloadOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; @@ -402,10 +402,36 @@ const ClassDetailPage: React.FC = () => { icon={} type="primary" onClick={openStudentModal} - style={{ marginBottom: 16 }} + style={{ marginBottom: 16, marginRight: 8 }} > 添加学员 + } + onClick={() => { + const token = localStorage.getItem('token'); + fetch(`/api/classes/${id}/roster/export`, { + headers: { Authorization: `Bearer ${token}` }, + }) + .then((res) => { + if (!res.ok) throw new Error('导出失败'); + return res.blob(); + }) + .then((blob) => { + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `班级花名册-${detail?.name || id}.xlsx`; + a.click(); + URL.revokeObjectURL(url); + message.success('花名册导出成功'); + }) + .catch(() => message.error('花名册导出失败')); + }} + > + 导出花名册 + columns={studentColumns} dataSource={students}