ExamDataPublishList.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import { CardStepTitle, FileLink, FileUpload } from "@/components";
  2. import ExamDataPublishController from "@/services/apis/ExamDataPublishController";
  3. import { ExamStatus, PublishStatus, ResourceFileType } from "@/services/enums";
  4. import { ActionType, ProTable } from "@ant-design/pro-components";
  5. import { history, useModel } from "@umijs/max";
  6. import { App, Button, Space, theme } from "antd";
  7. import { useCallback, useRef, useState } from "react";
  8. import ExamDataPublishEditModal from "./ExamDataPublishEditModal";
  9. /** 监测发布内容管理 */
  10. const ExamDataPublishList: React.FC<{ examPlanId: number, examPlanStatus?: ExamStatus }> = ({ examPlanId }) => {
  11. const { token } = theme.useToken();
  12. const actionRef = useRef<ActionType>();
  13. const dataRef = useRef<API.ExamDataPublishOutput[]>();
  14. const currentRef = useRef<Partial<API.ExamDataPublishOutput>>();
  15. const [editOpen, setEditOpen] = useState(false);
  16. const { getDictValueEnum } = useModel('useDict');
  17. const { message, modal } = App.useApp();
  18. // 移出
  19. const handleRemove = useCallback(async (id: number) => {
  20. modal.confirm({
  21. title: '警告',
  22. content: '确定立即移出吗',
  23. okText: '确定',
  24. cancelText: '取消',
  25. centered: true,
  26. onOk: async () => {
  27. await ExamDataPublishController.del({ id });
  28. message.success('已移出');
  29. actionRef.current?.reload();
  30. },
  31. });
  32. }, []);
  33. // 发布
  34. const handlePublish = useCallback(async (id: number) => {
  35. modal.confirm({
  36. title: '提示',
  37. content: '确定立即发布吗',
  38. okText: '确定',
  39. cancelText: '取消',
  40. centered: true,
  41. onOk: async () => {
  42. await ExamDataPublishController.publish({ id });
  43. message.success('已发布');
  44. actionRef.current?.reload();
  45. },
  46. });
  47. }, []);
  48. // 取消发布
  49. const handleUnpublish = useCallback(async (id: number) => {
  50. modal.confirm({
  51. title: '提示',
  52. content: '确定立即取消发布吗',
  53. okText: '确定',
  54. cancelText: '取消',
  55. centered: true,
  56. onOk: async () => {
  57. await ExamDataPublishController.unpublish({ id });
  58. message.success('已取消');
  59. actionRef.current?.reload();
  60. },
  61. });
  62. }, []);
  63. // 删除附件
  64. const handleDeleteAttachment = useCallback(async (id: number, fileId: string) => {
  65. modal.confirm({
  66. title: '警告',
  67. content: '确定立即删除吗',
  68. okText: '确定',
  69. cancelText: '取消',
  70. centered: true,
  71. onOk: async () => {
  72. await ExamDataPublishController.delAttachment({ sourceId: id, fileId })
  73. message.success('已删除');
  74. actionRef.current?.reload();
  75. },
  76. });
  77. }, []);
  78. return (
  79. <>
  80. <ProTable<API.ExamDataPublishOutput>
  81. headerTitle={<CardStepTitle>结果反馈</CardStepTitle>}
  82. style={{ marginTop: token.margin }}
  83. search={false}
  84. size="small"
  85. bordered
  86. scroll={{ x: '100%' }}
  87. sticky={{ offsetHeader: 56 }}
  88. actionRef={actionRef}
  89. options={{ density: false, fullScreen: false, setting: false }}
  90. pagination={false}
  91. columns={[
  92. {
  93. title: '序',
  94. valueType: 'option',
  95. fixed: 'left',
  96. width: 32,
  97. align: 'center',
  98. render: (_, r, index) => {
  99. return index + 1;
  100. },
  101. },
  102. {
  103. title: '发布类型',
  104. dataIndex: 'type',
  105. valueEnum: getDictValueEnum('data_publish_type'),
  106. width: 96,
  107. align: 'center',
  108. fixed: 'left',
  109. },
  110. {
  111. title: '发布名称',
  112. dataIndex: 'name',
  113. width: 180,
  114. },
  115. {
  116. title: '发布内容',
  117. valueType: 'option',
  118. width: 80,
  119. align: 'center',
  120. render: (_, r) => {
  121. return (
  122. <Button
  123. type="link"
  124. size="small"
  125. onClick={() => history.push(`/exam-c/plan/result/${examPlanId}/${r.id}`)}
  126. >管理</Button>
  127. );
  128. },
  129. },
  130. {
  131. title: '备注说明',
  132. dataIndex: 'remark',
  133. ellipsis: true,
  134. width: 400,
  135. },
  136. {
  137. title: '发布状态',
  138. dataIndex: 'status',
  139. valueEnum: getDictValueEnum('publish_status', true),
  140. width: 88,
  141. align: 'center',
  142. },
  143. {
  144. title: '发布时间',
  145. dataIndex: 'beginTime',
  146. width: 144,
  147. align: 'center',
  148. },
  149. {
  150. title: '附件',
  151. valueType: 'option',
  152. hideInSearch: true,
  153. width: 280 + token.paddingXS * 2,
  154. render: (_, r) => {
  155. const li = r.attachmentList?.map((t, i) => {
  156. return (
  157. <FileLink
  158. key={i}
  159. fileExtName={t.fileExtName}
  160. fileName={t.fileName}
  161. url={`${AppConfig.fileViewRoot}?id=${t.fileId}`}
  162. thumbUrl={t.thumbFileId && t.thumbFileId !== '0' ? `${AppConfig.fileViewRoot}?id=${t.thumbFileId}` : undefined}
  163. card
  164. onDelete={async () => handleDeleteAttachment(r.id, t.fileId)}
  165. />
  166. );
  167. });
  168. return (
  169. <Space direction="vertical" style={{ width: 280 }}>
  170. {li}
  171. {(li?.length ?? 0) < 9 &&
  172. <FileUpload
  173. addText="添加文件"
  174. // tipText="仅支持PDF或图片文件"
  175. accept="*.png,*.jpg,*.jpeg,*.gif,*.pdf,*.doc,*.docx,*.xls,*.xlsx,*.ppt,*.pptx,*.zip"
  176. limitSize={1024}
  177. onUpload={async (file, onUploadProgress) => {
  178. const fsp = file.name.split('.');
  179. let extName = '';
  180. if (fsp.length > 1) {
  181. extName = fsp[fsp.length - 1].toLowerCase();
  182. }
  183. if (extName === '' || !['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip'].includes(extName)) {
  184. message.error('文件类型错误,请重新选择!')
  185. return { success: false, errorType: 'fileTypeError', errorMessage: '文件类型错误' };
  186. }
  187. try {
  188. const formData = new FormData();
  189. formData.append('type', `${ResourceFileType.EXAM_DATA_PUBLISH_ATTACHMENT}`);
  190. formData.append('sourceId', `${r.id}`);
  191. formData.append('fileName', `${file.name}`);
  192. formData.append('file', file);
  193. await ExamDataPublishController.uploadAttachment(formData, {
  194. onUploadProgress: (p: any) => {
  195. const progress = parseFloat((p.loaded / p.total * 100).toFixed(1));
  196. onUploadProgress?.(progress);
  197. }
  198. });
  199. actionRef.current?.reload();
  200. return { success: true };
  201. }
  202. catch {
  203. return { success: false };
  204. }
  205. }}
  206. />
  207. }
  208. </Space>
  209. );
  210. },
  211. },
  212. {
  213. title: '操作',
  214. valueType: 'option',
  215. width: 196,
  216. align: 'center',
  217. fixed: 'right',
  218. render: (_, r) => {
  219. return (
  220. <>
  221. <Button
  222. type="link"
  223. size="small"
  224. disabled={r.status === PublishStatus.PUBLISHED}
  225. onClick={() => handleRemove(r.id)}
  226. >移出</Button>
  227. <Button
  228. type="link"
  229. size="small"
  230. disabled={r.status === PublishStatus.PUBLISHED}
  231. onClick={() => {
  232. currentRef.current = r;
  233. setEditOpen(true);
  234. }}
  235. >修改</Button>
  236. <Button
  237. type="link"
  238. size="small"
  239. disabled={r.status === PublishStatus.PUBLISHED}
  240. onClick={() => handlePublish(r.id)}
  241. >发布</Button>
  242. <Button
  243. type="link"
  244. size="small"
  245. disabled={r.status !== PublishStatus.PUBLISHED}
  246. onClick={() => handleUnpublish(r.id)}
  247. >取消</Button>
  248. </>
  249. );
  250. },
  251. }
  252. ]}
  253. rowKey="id"
  254. toolbar={{
  255. actions: [
  256. <Button
  257. key="add"
  258. type="primary"
  259. // disabled={examPlanStatus !== ExamStatus.READY}
  260. onClick={() => {
  261. currentRef.current = { id: 0, examPlanId };
  262. setEditOpen(true);
  263. }}
  264. >添加内容</Button>,
  265. ],
  266. }}
  267. request={async () => {
  268. const res = await ExamDataPublishController.getListByExamPlanId({ examplanid: examPlanId });
  269. dataRef.current = res ?? [];
  270. return {
  271. data: res,
  272. success: true,
  273. };
  274. }}
  275. />
  276. {editOpen && currentRef.current &&
  277. <ExamDataPublishEditModal
  278. data={currentRef.current}
  279. onClose={() => setEditOpen(false)}
  280. onFinish={() => actionRef.current?.reload()}
  281. />
  282. }
  283. </>
  284. );
  285. }
  286. export default ExamDataPublishList;