ContinuingEducationEdit.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <script setup lang="ts">
  2. import type { UploadFile, UploadProps } from 'ant-design-vue';
  3. import type { ContinuingEducationSubmitVO } from '#/api/outcome';
  4. import { ref } from 'vue';
  5. import { InboxOutlined } from '@ant-design/icons-vue';
  6. import { Button, message, Upload, UploadDragger } from 'ant-design-vue';
  7. import { useEditShell } from '#/adapter/shell';
  8. import { useWorkroomStore } from '#/stores';
  9. import { continuingEducationForm } from '../continuing-education.data';
  10. const workroomStore = useWorkroomStore();
  11. const PDF_MAX_SIZE = 50 * 1024 * 1024;
  12. const pdfFileList = ref<UploadFile[]>([]);
  13. const pdfUrl = ref<string>();
  14. const pdfUploading = ref(false);
  15. const submittingAction = ref<'draft' | 'publish' | null>(null);
  16. function createUploadFile(url: string | undefined, name: string): UploadFile[] {
  17. if (!url) return [];
  18. return [
  19. {
  20. uid: '-1',
  21. name,
  22. status: 'done',
  23. url,
  24. },
  25. ];
  26. }
  27. function resetUploads() {
  28. pdfFileList.value = [];
  29. pdfUrl.value = void 0;
  30. pdfUploading.value = false;
  31. submittingAction.value = null;
  32. }
  33. const { Form, Shell, api } = useEditShell<ContinuingEducationSubmitVO>(
  34. continuingEducationForm,
  35. {
  36. onLoaded(model) {
  37. api.shell.setState({
  38. title: model.id ? '编辑继续教育项目' : '添加继续教育项目',
  39. });
  40. },
  41. handleLoad(model) {
  42. resetUploads();
  43. pdfUrl.value = model.fileUrl;
  44. pdfFileList.value = createUploadFile(model.fileUrl, '附件.pdf');
  45. return model;
  46. },
  47. handleSubmit(values) {
  48. const workroomId = values.workroomId || workroomStore.workroomId;
  49. if (!workroomId) {
  50. message.error('请先选择工作室');
  51. throw new Error('workroom required');
  52. }
  53. if (pdfUploading.value) {
  54. message.warning('文件上传中,请稍候');
  55. throw new Error('uploading');
  56. }
  57. if (!pdfUrl.value) {
  58. message.error('请上传附件PDF文件');
  59. throw new Error('pdf required');
  60. }
  61. if (!values.isLongTerm && !values.endDate) {
  62. message.error('请选择结束日期或勾选长期');
  63. throw new Error('endDate required');
  64. }
  65. return {
  66. ...values,
  67. workroomId,
  68. endDate: values.isLongTerm ? undefined : values.endDate,
  69. fileUrl: pdfUrl.value,
  70. publishStatus:
  71. submittingAction.value === 'draft' ? 'draft' : 'published',
  72. };
  73. },
  74. onClosed: resetUploads,
  75. },
  76. );
  77. async function handleClose() {
  78. await api.close();
  79. }
  80. async function handleSaveDraft() {
  81. submittingAction.value = 'draft';
  82. try {
  83. await api.submit();
  84. message.success('草稿已保存');
  85. } finally {
  86. submittingAction.value = null;
  87. }
  88. }
  89. async function handlePublish() {
  90. submittingAction.value = 'publish';
  91. try {
  92. await api.submit();
  93. message.success('发布成功');
  94. } finally {
  95. submittingAction.value = null;
  96. }
  97. }
  98. const beforePdfUpload: UploadProps['beforeUpload'] = (file) => {
  99. const isPdf =
  100. file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
  101. if (!isPdf) {
  102. message.error('仅支持PDF格式文件');
  103. return Upload.LIST_IGNORE;
  104. }
  105. if (file.size > PDF_MAX_SIZE) {
  106. message.error('文件大小不能超过50MB');
  107. return Upload.LIST_IGNORE;
  108. }
  109. pdfUrl.value = URL.createObjectURL(file);
  110. pdfFileList.value = [
  111. {
  112. uid: `${Date.now()}`,
  113. name: file.name,
  114. status: 'done',
  115. url: pdfUrl.value,
  116. },
  117. ];
  118. return false;
  119. };
  120. function onPdfRemove() {
  121. pdfUrl.value = void 0;
  122. }
  123. </script>
  124. <template>
  125. <Shell>
  126. <div class="mx-4">
  127. <Form />
  128. <div class="pb-4">
  129. <div class="mb-2 text-sm font-medium">
  130. <span class="text-destructive mr-1">*</span>
  131. 附件
  132. </div>
  133. <UploadDragger
  134. v-model:file-list="pdfFileList"
  135. :before-upload="beforePdfUpload"
  136. :max-count="1"
  137. accept=".pdf,application/pdf"
  138. @remove="onPdfRemove"
  139. >
  140. <p class="ant-upload-drag-icon">
  141. <InboxOutlined />
  142. </p>
  143. <p class="ant-upload-text">点击上传或拖拽PDF文件到此处</p>
  144. <p class="ant-upload-hint">
  145. 仅支持PDF格式文件,建议文件大小不超过50MB
  146. </p>
  147. </UploadDragger>
  148. </div>
  149. </div>
  150. <template #footer>
  151. <div class="flex w-full justify-end gap-2">
  152. <Button @click="handleClose">取消</Button>
  153. <Button
  154. :loading="submittingAction === 'draft'"
  155. @click="handleSaveDraft"
  156. >
  157. 保存草稿
  158. </Button>
  159. <Button
  160. type="primary"
  161. :loading="submittingAction === 'publish'"
  162. @click="handlePublish"
  163. >
  164. 发布
  165. </Button>
  166. </div>
  167. </template>
  168. </Shell>
  169. </template>