| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790 |
- import { toValueEnum } from "@/common/converter";
- import { downloadFileByBlob } from "@/common/net/download";
- import { CardStepTitle, FileLink, FileUpload, SuperTable, TabBadge } from "@/components";
- import ReportButton from "@/components/ReportButton";
- import ExamGradeController from "@/services/apis/ExamGradeController";
- import ExamOrgDataReportController from "@/services/apis/ExamOrgDataReportController";
- import ExamSpecialStudentController from "@/services/apis/ExamSpecialStudentController";
- import SysOrgController from "@/services/apis/SysOrgController";
- import { AuditStatus, DataReportStatus, DataReportType, ExamStatus, ResourceFileType } from "@/services/enums";
- import { BulbOutlined, DownloadOutlined, PlusOutlined, ReloadOutlined, UploadOutlined } from "@ant-design/icons";
- import { ActionType, PageContainer, ProCard, ProColumns, ProDescriptions, ProDescriptionsItemProps, ProTable } from "@ant-design/pro-components";
- import { history, useModel, useParams } from "@umijs/max";
- import { useRequest } from "ahooks";
- import { Alert, App, Badge, Button, Card, Drawer, Space, Tag, Tour, Typography, theme } from "antd";
- import { useCallback, useRef, useState } from "react";
- import ExamSpecialStudentDetailDrawer from "./components/ExamSpecialStudentDetailDrawer";
- import ExamSpecialStudentEditModal from "./components/ExamSpecialStudentEditModal";
- const OrgExamSpecialStudentReport: React.FC = () => {
- const reqParams = useParams() as unknown as { examPlanId: number };
- const { token } = theme.useToken();
- const { getDictValueEnum, getKeyDict, getDict } = useModel('useDict');
- const examStatusDict = getKeyDict('exam_status');
- const dataReportStatusDict = getKeyDict('data_report_status');
- const dataReportTypeDict = getKeyDict('data_report_type');
- const auditStatusDict = getKeyDict('audit_status');
- // const { baseData } = useModel('useBaseData');
- const { initialState } = useModel('@@initialState');
- const { currentUser } = initialState ?? {};
- const [detailOpen, setDetailOpen] = useState(false);
- const [remarkOpen, setRemarkOpen] = useState(false);
- const [editOpen, setEditOpen] = useState(false);
- const actionRef = useRef<ActionType>();
- const currentRef = useRef<Partial<API.ExamSpecialStudentOutput>>();
- const [activeKey, setActiveKey] = useState<React.Key>('2');
- const [statusCount, seStatusCount] = useState<Record<number, number>>({});
- const [tourOpen, setTourOpen] = useState(false);
- const tourAddRef = useRef(null);
- const tourDownloadRef = useRef(null);
- const tourUploadRef = useRef(null);
- const tourReportRef = useRef(null);
- const { message, modal, notification } = App.useApp();
- const { data: gradeBranchData } = useRequest(async () => {
- const res1 = await ExamGradeController.getListByExamPlanId({ examplanid: reqParams.examPlanId });
- const res2 = await SysOrgController.getOrgBranchByOrgId({ orgid: currentUser?.sysOrgId ?? 0 });
- return {
- examGrades: res1 ?? [],
- branches: res2 ?? [],
- hasBranch: (res2?.length ?? 0) > 0,
- };
- });
- // 加载上报数据
- const { data: reportData, run: loadReport } = useRequest(() => {
- return ExamOrgDataReportController.getByTypeExamPlanId({ type: DataReportType.SP_STUDENT, examplanid: reqParams.examPlanId });
- });
- // 加载数量统计
- const loadCount = useCallback(async (params: API.ExamSpecialStudentPageInput) => {
- const m = await ExamSpecialStudentController.queryStatusCount(params);
- const tc = m?.reduce((a, b) => a + b.count, 0) ?? 0;
- const d: Record<number, number> = { 0: tc };
- m?.forEach((t) => { d[t.status] = t.count; });
- seStatusCount(d);
- }, []);
- // 加载统计数据
- const { data: studentCountData, run: loadStudentCount, loading } = useRequest(() => {
- return ExamSpecialStudentController.getOrgGradeClassStudentCount({ examplanid: reqParams.examPlanId });
- });
- // 统计数据列定义
- let studentCountColumns: ProColumns<any>[] = [
- {
- title: '年级',
- dataIndex: ['Grade', 'name'],
- width: 64,
- align: 'center',
- fixed: 'left',
- },
- {
- title: '合计',
- dataIndex: 'GradeTotal',
- width: 64,
- align: 'center',
- fixed: 'left',
- },
- ];
- studentCountData?.classNumberList?.forEach(t => {
- studentCountColumns.push({
- title: `${t}班`,
- dataIndex: `${t}`,
- width: 56,
- align: 'center',
- render: (v) => v ? v : null,
- });
- });
- studentCountColumns.push({});
- // 删除
- const handleDelete = useCallback((id: number) => {
- modal.confirm({
- title: '警告',
- content: '确定立即删除吗',
- okText: '确定',
- cancelText: '取消',
- centered: true,
- onOk: async () => {
- await ExamSpecialStudentController.del({ id });
- message.success('已删除');
- actionRef.current?.reload();
- loadStudentCount();
- },
- });
- }, []);
- // 上报
- const handleSubmit = useCallback(() => {
- return new Promise<void>((resolve, reject) => {
- if ((studentCountData?.total ?? 0) > 0 && (reportData?.examOrgDataReport?.attachmentList?.length ?? 0) === 0) {
- message.error('未上传《特殊学生明细表》和《会议记录》打印盖章的扫描电子文件');
- reject();
- return;
- }
- let content = `共 ${studentCountData?.total ?? 0} 个学生,上报后不能再修改,确定立即上报吗?`;
- modal.confirm({
- title: '警告',
- content,
- okText: '确定',
- cancelText: '取消',
- centered: true,
- onOk: async () => {
- try {
- await ExamOrgDataReportController.submit({ examPlanId: reqParams.examPlanId, type: DataReportType.SP_STUDENT })
- message.success('已上报');
- loadReport();
- resolve();
- }
- catch (ex) {
- const exm = ex as any;
- notification.error({
- message: '上报失败',
- description: exm?.info?.errorMessage ? `${exm?.info?.errorMessage}!请仔细检查特殊学生明细信息和佐证材料` : JSON.stringify(ex),
- })
- reject();
- }
- },
- onCancel: () => reject(),
- });
- });
- }, [studentCountData, reportData]);
- // 删除佐证材料
- const handleDeleteAttachment = useCallback((id: number, fileId: string) => {
- modal.confirm({
- title: '警告',
- content: '确定立即删除吗',
- okText: '确定',
- cancelText: '取消',
- centered: true,
- onOk: async () => {
- await ExamSpecialStudentController.delAttachment({ sourceId: id, fileId });
- message.success('已删除');
- actionRef.current?.reload();
- loadStudentCount();
- },
- });
- }, []);
- // 删除上报佐证材料
- const handleDeleteReportAttachment = useCallback(async (id: number, fileId: string) => {
- modal.confirm({
- title: '警告',
- content: '确定立即删除吗',
- okText: '确定',
- cancelText: '取消',
- centered: true,
- onOk: async () => {
- await ExamOrgDataReportController.delAttachment({ sourceId: id, fileId });
- message.success('已删除');
- loadReport();
- },
- });
- }, []);
- // 下载打印文件
- const handleDownloadPrintFile = useCallback(async () => {
- const res = await ExamSpecialStudentController.exportPrintTable({ examplanid: reqParams.examPlanId });
- if (res) {
- downloadFileByBlob(res.data, res.fileName);
- }
- }, []);
- // // 提交单个学生审核
- // const handleStudentSubmit = useCallback((id: number) => {
- // modal.confirm({
- // title: '警告',
- // content: '确定立即提交吗',
- // okText: '确定',
- // cancelText: '取消',
- // centered: true,
- // onOk: async () => {
- // await ExamSpecialStudentAuditController.submit({ id });
- // message.success('已提交');
- // actionRef.current?.reload();
- // loadStudentCount();
- // },
- // });
- // }, [])
- // 是否可操作和上报
- const reportable = (reportData?.examDataReport?.status === ExamStatus.ACTIVE && reportData?.isExpired === false &&
- (reportData?.examOrgDataReport?.status === DataReportStatus.UNREPORT ||
- reportData?.examOrgDataReport?.status === DataReportStatus.REJECTED));
- // 工具栏按定义
- let detailActions = [];
- if (reportable) {
- detailActions.push(
- <Button
- key="add"
- ref={tourAddRef}
- type="primary"
- disabled={!reportable}
- icon={<PlusOutlined />}
- onClick={() => {
- currentRef.current = { id: 0 };
- setEditOpen(true);
- }}
- >添加特殊学生</Button>
- );
- detailActions.push(
- <Button
- key="import"
- disabled={!reportable}
- icon={<UploadOutlined />}
- onClick={() => history.push(`/exam-s/sp-stu/import/${reqParams.examPlanId}`)}
- >批量导入</Button>
- );
- detailActions.push(
- <Button
- key="download"
- ref={tourDownloadRef}
- disabled={!reportable}
- icon={<DownloadOutlined />}
- onClick={handleDownloadPrintFile}
- >下载打印表格文件</Button>
- );
- }
- // 明细表列定义
- const detailColumns: ProColumns<API.ExamSpecialStudentOutput>[] = [
- {
- title: '状态',
- dataIndex: 'status',
- hideInSearch: true,
- width: 80,
- align: 'center',
- valueEnum: getDictValueEnum('audit_status', true),
- render: (_, r) => {
- // const s = auditStatusDict[r.status];
- // return <Tag color={s.antStatus} style={{ marginRight: 0 }}>{s.name}</Tag>;
- const s = auditStatusDict[r.status];
- const ta = <Tag color={s.antStatus} style={{ marginRight: 0 }}>{s.name}</Tag>;
- if (r.isPreIdentified) {
- return (
- <Space direction="vertical" size="small" style={{ lineHeight: 1 }}>
- {ta}
- <Typography.Text type="warning" style={{ fontSize: token.fontSizeSM }}>往期已认定</Typography.Text>
- </Space>
- );
- }
- if (r.preTotalScore !== null) {
- return (
- <Space direction="vertical" size="small" style={{ lineHeight: 1 }}>
- {ta}
- <Typography.Text type="secondary" style={{ fontSize: token.fontSizeSM }}>
- 前期{r.preTotalCourse}科得分
- <Typography.Text type="warning" strong style={{ fontSize: token.fontSizeSM }}>{r.preTotalScore}</Typography.Text>
- </Typography.Text>
- </Space>
- );
- }
- return ta;
- },
- },
- // {
- // title: '校区',
- // dataIndex: ['sysOrgBranch', 'name'],
- // width: 88,
- // align: 'center',
- // },
- ...(gradeBranchData?.hasBranch ? [{
- title: '校区',
- dataIndex: 'sysOrgBranchId',
- width: 96,
- align: 'center',
- hideInSearch: !gradeBranchData?.hasBranch,
- valueEnum: toValueEnum(gradeBranchData?.branches ?? []),
- } as ProColumns] : []),
- // {
- // title: '年级',
- // dataIndex: 'gradeId',
- // width: 72,
- // align: 'center',
- // render: (_, r) => `${r.examGrade?.grade.name}`,
- // },
- {
- title: '年级',
- dataIndex: 'gradeId',
- width: 80,
- align: 'center',
- valueEnum: toValueEnum(gradeBranchData?.examGrades?.map(t => ({ id: t.gradeId, name: `${t.grade.name}(${t.gradeBeginName})` })) ?? []),
- render: (_, r) => {
- return (
- <Space size="small" direction="vertical" style={{ lineHeight: 1 }}>
- {r.examGrade?.grade.name}
- <Typography.Text type="secondary" style={{ fontSize: token.fontSizeSM }}>({r.examGrade?.gradeBeginName})</Typography.Text>
- </Space>
- );
- },
- },
- {
- title: '班级',
- dataIndex: 'classNumber',
- width: 64,
- align: 'center',
- renderText: (v) => `${v}班`,
- },
- {
- title: '姓名',
- dataIndex: 'name',
- width: 112,
- align: 'center',
- render: (v, r) => <a onClick={() => { currentRef.current = r; setDetailOpen(true); }}>{v}</a>,
- },
- {
- title: '证件类型',
- dataIndex: 'certificateType',
- valueEnum: getDictValueEnum('certificate_type'),
- width: 112,
- align: 'center',
- },
- {
- title: '证件号码',
- dataIndex: 'idNumber',
- width: 160,
- align: 'center',
- },
- // {
- // title: '学籍号码',
- // width: 168,
- // align: 'center',
- // },
- {
- title: '特殊原因',
- dataIndex: 'applyReason',
- hideInSearch: true,
- className: 'minw-120',
- },
- {
- title: '家长电话',
- dataIndex: 'patriarchTel',
- hideInSearch: true,
- width: 128,
- align: 'center',
- },
- {
- title: '备注',
- dataIndex: 'remark',
- hideInSearch: true,
- // className: 'minw-64',
- width: 120,
- },
- {
- title: '佐证材料(每个学生最多上传3个)',
- valueType: 'option',
- hideInSearch: true,
- width: 280,
- fixed: 'right',
- render: (_, r) => {
- let editable = reportable && [AuditStatus.UNSUBMIT, AuditStatus.REJECTED, AuditStatus.AUDIT].includes(r.status);
- if (!editable) {
- editable = r.status === AuditStatus.REJECTED && reportData?.examDataReport?.status === ExamStatus.ACTIVE;
- }
- const li = r.attachmentList?.map((t, i) => {
- return (
- <FileLink
- key={i}
- fileExtName={t.fileExtName}
- fileName={t.fileName}
- url={`${AppConfig.fileViewRoot}?id=${t.fileId}`}
- thumbUrl={t.thumbFileId && t.thumbFileId !== '0' ? `${AppConfig.fileViewRoot}?id=${t.thumbFileId}` : undefined}
- card
- onDelete={editable ? async () => handleDeleteAttachment(r.id, t.fileId) : undefined}
- />
- );
- });
- return (
- <Space direction="vertical" style={{ width: 280 }}>
- {li}
- {editable && (li?.length ?? 0) < 3 &&
- <FileUpload
- addText="添加文件"
- tipText="仅支持PDF或图片文件"
- accept="image/jpeg,image/png,image/gif,application/pdf"
- limitSize={20}
- onUpload={async (file, onUploadProgress) => {
- const fsp = file.name.split('.');
- let extName = '';
- if (fsp.length > 1) {
- extName = fsp[fsp.length - 1].toLowerCase();
- }
- if (extName === '' || !['jpg', 'jpeg', 'png', 'gif', 'pdf'].includes(extName)) {
- message.error('文件类型错误,请重新选择!')
- return { success: false, errorType: 'fileTypeError', errorMessage: '文件类型错误,请选择扩展名为.jpg、.jpeg、.png或.pdf的文件' };
- }
- try {
- const formData = new FormData();
- formData.append('type', `${ResourceFileType.EXAM_SPECIAL_STUDENT}`);
- formData.append('sourceId', `${r.id}`);
- formData.append('fileName', `${file.name}`);
- formData.append('file', file);
- await ExamSpecialStudentController.uploadAttachment(formData, {
- onUploadProgress: (p: any) => {
- const progress = parseFloat((p.loaded / p.total * 100).toFixed(1));
- onUploadProgress?.(progress);
- }
- });
- actionRef.current?.reload();
- return { success: true };
- }
- catch {
- return { success: false };
- }
- }}
- />
- }
- </Space>
- );
- },
- },
- {
- title: '佐证材料',
- // valueType: 'option',
- hideInSearch: true,
- hideInTable: true,
- width: 280,
- fixed: 'right',
- render: (_, r) => {
- const li = r.attachmentList?.map((t, i) => {
- return (
- <FileLink
- key={i}
- fileExtName={t.fileExtName}
- fileName={t.fileName}
- url={`${AppConfig.fileViewRoot}?id=${t.fileId}`}
- thumbUrl={t.thumbFileId && t.thumbFileId !== '0' ? `${AppConfig.fileViewRoot}?id=${t.thumbFileId}` : undefined}
- card
- />
- );
- });
- return (
- <Space direction="vertical" style={{ width: '100%' }}>
- {li?.length === 0 ? '未上传' : li}
- </Space>
- );
- },
- },
- {
- title: '操作',
- valueType: 'option',
- width: 120,
- align: 'center',
- fixed: 'right',
- // hideInTable: !reportable,
- render: (_, r) => {
- if (reportable && [AuditStatus.UNSUBMIT, AuditStatus.REJECTED, AuditStatus.AUDIT].includes(r.status)) {
- return (
- <Space>
- <a onClick={() => { currentRef.current = r; setEditOpen(true); }}>修改</a>
- <a onClick={() => handleDelete(r.id)}>删除</a>
- </Space>
- );
- }
- // if (reportData?.examDataReport?.status === ExamStatus.ACTIVE && r.status === AuditStatus.REJECTED) {
- // return (
- // <Space>
- // <a onClick={() => { currentRef.current = r; setEditOpen(true); }}>修改</a>
- // <a onClick={() => handleDelete(r.id)}>删除</a>
- // <a onClick={() => handleStudentSubmit(r.id)}>提交</a>
- // </Space>
- // );
- // }
- return null;
- },
- }
- ];
- // 呈现状态 tab
- const renderTabItems = useCallback(() => {
- let items: { key: string; label: React.ReactNode }[] = [];
- items = items.concat(
- getDict('audit_status')?.filter(t => t.value > 1)?.sort((a, b) => a.sort - b.sort)?.map((t) => ({
- key: `${t.value}`,
- label: (
- <span>
- {t.name}
- <TabBadge color={t.antColor} count={statusCount[t.value] ?? 0} active={activeKey === `${t.value}`} />
- </span>
- ),
- })),
- );
- items.push({
- key: '0',
- label: (<span>全部<TabBadge count={statusCount[0]} active={activeKey === 0} /></span>),
- });
- return items;
- }, [activeKey, statusCount]);
- return (
- <PageContainer
- title={`${reportData?.examPlan?.fullName ?? ''} - 特殊学生上报`}
- onBack={() => history.back()}
- extra={reportable &&
- <Button
- type="link"
- icon={<BulbOutlined />}
- onClick={() => {
- window.scrollTo({ top: 0 });
- setTourOpen(true);
- }}
- >查看操作指引</Button>
- }
- >
- <ProCard
- title={<CardStepTitle>基本情况</CardStepTitle>}
- extra={reportData?.examOrgDataReport?.status &&
- <Tag
- style={{ marginRight: 0 }}
- color={dataReportStatusDict[reportData.examOrgDataReport.status].antColor}
- >
- {dataReportStatusDict[reportData.examOrgDataReport.status].name}
- </Tag>
- }
- >
- <ProDescriptions>
- <ProDescriptions.Item label="上报类型">
- {reportData?.examDataReport?.type ? dataReportTypeDict[reportData?.examDataReport?.type].name : ''}
- </ProDescriptions.Item>
- <ProDescriptions.Item label="监测上报">
- {reportData?.examDataReport?.status &&
- <Badge
- status={examStatusDict[reportData.examDataReport.status].antStatus as any}
- text={examStatusDict[reportData.examDataReport.status].name}
- />
- }
- </ProDescriptions.Item>
- <ProDescriptions.Item label="截止时间">
- <Typography.Text strong>
- {reportData?.examDataReport?.endTime}
- {reportData?.isExpired && reportData.examDataReport?.status === ExamStatus.ACTIVE &&
- <Typography.Text type="danger">(已截止)</Typography.Text>
- }
- </Typography.Text>
- </ProDescriptions.Item>
- <ProDescriptions.Item label="上报人员">{reportData?.examOrgDataReport?.reportSysUser?.name}</ProDescriptions.Item>
- <ProDescriptions.Item label="上报时间">{reportData?.examOrgDataReport?.reportTime}</ProDescriptions.Item>
- <ProDescriptions.Item label="备注说明">{reportData?.examOrgDataReport?.remark}</ProDescriptions.Item>
- <ProDescriptions.Item label="上报说明" span={3}>
- <Typography.Text ellipsis>{reportData?.examDataReport?.remark || '无'}</Typography.Text>
- {reportData?.examDataReport?.remark && <Button type="link" size="small" onClick={() => setRemarkOpen(true)}>详情</Button>}
- </ProDescriptions.Item>
- </ProDescriptions>
- <Drawer open={remarkOpen} title="上报说明" width={720} maskClosable onClose={() => setRemarkOpen(false)}>
- <pre>{reportData?.examDataReport?.remark || '无'}</pre>
- </Drawer>
- </ProCard>
- <ProCard
- style={{ marginTop: token.margin }}
- title={<CardStepTitle>特殊学生上报</CardStepTitle>}
- extra={reportable &&
- <Space>
- <span key="tooltip">离上报结束还有</span>
- <ReportButton
- key="time"
- buttonRef={tourReportRef}
- expireTime={reportData?.examDataReport?.endTime}
- showIcon
- onSubmit={handleSubmit}
- onTimerFinish={() => loadReport()}
- />
- </Space>
- }
- >
- <Alert
- type="warning"
- message={<Typography.Title level={5}>上报步骤:</Typography.Title>}
- description={
- <Typography>
- <ol>
- <li><Typography.Text type="danger" strong>只需要上报新增特殊学生,往期已认定的特殊学生不能重复上报;</Typography.Text></li>
- <li>在下方 <Typography.Text strong>特殊学生明细</Typography.Text> 中录入特殊学生信息,并上传佐证材料<Typography.Text type="danger">(必传)</Typography.Text>;</li>
- <li>特殊学生信息录入完成后,点击 <Typography.Text strong>下载打印表格文件</Typography.Text> 下载文件打印签字盖章;</li>
- <li>扫描已签字盖章的文件为电子文档(PDF或图片);</li>
- <li>在 <Typography.Text strong> 特殊学生上报</Typography.Text> 的 <Typography.Text strong>上传《特殊学生明细表》和《会议记录》打印盖章的扫描电子文件</Typography.Text> 中上传电子文档<Typography.Text type="danger">(必传)</Typography.Text>;</li>
- <li>确认无误后点击 <Typography.Text strong> 特殊学生上报</Typography.Text> 右侧的 <Typography.Text strong>立即上报</Typography.Text> 按钮完成上传。</li>
- </ol>
- </Typography>
- }
- />
- <Typography.Title level={5} style={{ marginTop: token.marginSM }} type="danger">上传《特殊学生明细表》和《会议记录》打印盖章的扫描电子文件(最多上传6个文件):</Typography.Title>
- <Card bordered ref={tourUploadRef}>
- <Space direction="vertical" style={{ width: '100%' }}>
- {reportData?.examOrgDataReport?.attachmentList?.map((t, i) => {
- return (
- <FileLink
- key={i}
- fileExtName={t.fileExtName}
- fileName={t.fileName}
- url={`${AppConfig.fileViewRoot}?id=${t.fileId}`}
- thumbUrl={t.thumbFileId && t.thumbFileId !== '0' ? `${AppConfig.fileViewRoot}?id=${t.thumbFileId}` : undefined}
- card
- onDelete={reportable ? async () => handleDeleteReportAttachment(reportData.examOrgDataReportId ?? 0, t.fileId) : undefined}
- />
- );
- }) ?? null}
- {reportable && reportData?.examOrgDataReport && (reportData?.examOrgDataReport?.attachmentList?.length ?? 0) < 6 &&
- <FileUpload
- addText="添加文件"
- tipText="仅支持PDF或图片文件"
- accept="image/jpeg,image/png,image/gif,application/pdf"
- limitSize={20}
- onUpload={async (file, onUploadProgress) => {
- const fsp = file.name.split('.');
- let extName = '';
- if (fsp.length > 1) {
- extName = fsp[fsp.length - 1].toLowerCase();
- }
- if (extName === '' || !['jpg', 'jpeg', 'png', 'gif', 'pdf'].includes(extName)) {
- message.error('文件类型错误,请重新选择!')
- return { success: false, errorType: 'fileTypeError', errorMessage: '文件类型错误,请选择扩展名为.jpg、.jpeg、.png或.pdf的文件' };
- }
- try {
- const formData = new FormData();
- formData.append('type', `${ResourceFileType.EXAM_ORG_DATA_REPORT}`);
- formData.append('dataReportType', `${DataReportType.SP_STUDENT}`);
- formData.append('examPlanId', `${reportData?.examPlan?.id ?? 0}`);
- formData.append('sourceId', `${reportData?.examOrgDataReportId ?? 0}`);
- formData.append('fileName', `${file.name}`);
- formData.append('file', file);
- await ExamOrgDataReportController.uploadAttachment(formData, {
- onUploadProgress: (p: any) => {
- const progress = parseFloat((p.loaded / p.total * 100).toFixed(1));
- onUploadProgress?.(progress);
- }
- });
- loadReport();
- return { success: true };
- }
- catch {
- return { success: false };
- }
- }}
- />
- }
- </Space>
- </Card>
- <Typography.Title level={5} style={{ marginTop: token.marginSM }}>特殊学生人数统计:</Typography.Title>
- <ProTable<any>
- style={{ marginTop: token.margin }}
- search={false}
- pagination={false}
- size="small"
- bordered
- options={{ setting: false, density: false, reloadIcon: <ReloadOutlined onClick={loadStudentCount} /> }}
- rowKey="GradeId"
- loading={loading}
- columns={studentCountColumns}
- columnEmptyText=""
- dataSource={studentCountData?.items ?? []}
- toolBarRender={false}
- />
- </ProCard>
- <SuperTable<API.ExamSpecialStudentOutput>
- headerTitle={<CardStepTitle>特殊学生明细</CardStepTitle>}
- style={{ marginTop: token.margin }}
- actionRef={actionRef}
- scroll={{ x: 'max-content' }}
- rowKey="id"
- columns={detailColumns}
- // search={{ showHiddenNum: false }}
- search={false}
- options={{ setting: false, fullScreen: false }}
- toolbar={{
- menu: {
- type: 'tab',
- activeKey: activeKey,
- items: renderTabItems(),
- onChange: (key) => {
- setActiveKey(key as React.Key);
- actionRef.current?.reload();
- },
- },
- actions: detailActions,
- }}
- request={async (params, sort) => {
- return SuperTable.requestPageAgent({ params, sort }, async (p) => {
- const qparams = { ...p, examPlanId: reqParams.examPlanId };
- await loadCount(qparams);
- const res = await ExamSpecialStudentController.queryPageList({
- ...qparams,
- status: activeKey !== '0' ? parseInt(activeKey as string) : undefined,
- });
- return res;
- });
- }}
- // rowSelection={reportable ? {} : false}
- />
- {editOpen && currentRef.current && gradeBranchData &&
- <ExamSpecialStudentEditModal
- examPlanId={reqParams.examPlanId}
- data={currentRef.current}
- gradeBranch={gradeBranchData}
- onFinish={() => {
- actionRef.current?.reload();
- loadStudentCount();
- }}
- onClose={() => setEditOpen(false)}
- />
- }
- {detailOpen && currentRef.current &&
- <ExamSpecialStudentDetailDrawer
- data={currentRef.current}
- columns={detailColumns as ProDescriptionsItemProps<Partial<API.ExamSpecialStudentOutput>>[]}
- onClose={() => setDetailOpen(false)}
- />
- }
- <Tour
- steps={[
- {
- title: '添加特殊学生信息',
- description: '添加完特殊学生信息后,在列表中上传相应的佐证材料(一个学生最多3个图片或PDF)',
- target: () => tourAddRef.current,
- },
- {
- title: '下载打印表格文件',
- description: '打印表格按年级分页,按文件要求签字和盖章',
- target: () => tourDownloadRef.current,
- },
- {
- title: '上传签字盖章文件',
- description: '打印文件签字盖章后,扫描成电子文件(PDF或图片)上传,推荐PDF文件,最多上传6个文件',
- target: () => tourUploadRef.current,
- },
- {
- title: '上报特殊学生信息',
- description: '确认无误后立即上报',
- target: () => tourReportRef.current,
- },
- ]}
- open={tourOpen}
- onClose={() => setTourOpen(false)}
- />
- </PageContainer>
- );
- }
- export default OrgExamSpecialStudentReport;
|