PaperEdit.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <script setup lang="ts">
  2. import type { UploadFile, UploadProps } from 'ant-design-vue';
  3. import type { PaperSubmitVO } from '#/api/outcome';
  4. import { ref } from 'vue';
  5. import { InboxOutlined } from '@ant-design/icons-vue';
  6. import { Alert, message, Upload, UploadDragger } from 'ant-design-vue';
  7. import { useEditShell } from '#/adapter/shell';
  8. import { invokeMethod } from '#/adapter/vxe-table/proxy/invoke-method';
  9. import { uploadFileMethod } from '#/api/common';
  10. import { useWorkroomStore } from '#/stores';
  11. import { paperForm } from '../paper.data';
  12. const workroomStore = useWorkroomStore();
  13. const PDF_MAX_SIZE = 20 * 1024 * 1024;
  14. const pdfFileList = ref<UploadFile[]>([]);
  15. const pdfUrl = ref<string>();
  16. const pdfUploading = ref(false);
  17. function createUploadFile(url: string | undefined, name: string): UploadFile[] {
  18. if (!url) return [];
  19. return [
  20. {
  21. uid: '-1',
  22. name,
  23. status: 'done',
  24. url,
  25. },
  26. ];
  27. }
  28. function resetUploads() {
  29. pdfFileList.value = [];
  30. pdfUrl.value = void 0;
  31. pdfUploading.value = false;
  32. }
  33. async function uploadImmediately(file: File) {
  34. const uploadFile: UploadFile = {
  35. uid: `${Date.now()}`,
  36. name: file.name,
  37. status: 'uploading',
  38. percent: 0,
  39. };
  40. pdfFileList.value = [uploadFile];
  41. pdfUploading.value = true;
  42. try {
  43. const url = await invokeMethod(uploadFileMethod(file), { force: true });
  44. if (!url) {
  45. throw new Error('upload empty url');
  46. }
  47. pdfUrl.value = url;
  48. pdfFileList.value = [
  49. {
  50. ...uploadFile,
  51. status: 'done',
  52. url,
  53. },
  54. ];
  55. } catch {
  56. pdfUrl.value = void 0;
  57. pdfFileList.value = [
  58. {
  59. ...uploadFile,
  60. status: 'error',
  61. },
  62. ];
  63. message.error(`${file.name} 上传失败,请重试`);
  64. } finally {
  65. pdfUploading.value = false;
  66. }
  67. }
  68. const { Form, Shell, api } = useEditShell<PaperSubmitVO>(paperForm, {
  69. onLoaded(model) {
  70. api.shell.setState({
  71. title: model.id ? '编辑论文' : '上传论文',
  72. });
  73. },
  74. handleLoad(model) {
  75. resetUploads();
  76. pdfUrl.value = model.pdfUrl;
  77. pdfFileList.value = createUploadFile(model.pdfUrl, '论文.pdf');
  78. return model;
  79. },
  80. handleSubmit(values) {
  81. const workroomId = values.workroomId || workroomStore.workroomId;
  82. if (!workroomId) {
  83. message.error('请先选择工作室');
  84. throw new Error('workroom required');
  85. }
  86. if (pdfUploading.value) {
  87. message.warning('文件上传中,请稍候');
  88. throw new Error('uploading');
  89. }
  90. if (!pdfUrl.value) {
  91. message.error('请上传论文PDF文件');
  92. throw new Error('pdf required');
  93. }
  94. return {
  95. ...values,
  96. workroomId,
  97. pdfUrl: pdfUrl.value,
  98. };
  99. },
  100. onClosed: resetUploads,
  101. });
  102. const beforePdfUpload: UploadProps['beforeUpload'] = (file) => {
  103. const isPdf =
  104. file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
  105. if (!isPdf) {
  106. message.error('仅支持PDF格式文件');
  107. return Upload.LIST_IGNORE;
  108. }
  109. if (file.size > PDF_MAX_SIZE) {
  110. message.error('文件大小不能超过20MB');
  111. return Upload.LIST_IGNORE;
  112. }
  113. void uploadImmediately(file);
  114. return false;
  115. };
  116. function onPdfRemove() {
  117. pdfUrl.value = void 0;
  118. }
  119. </script>
  120. <template>
  121. <Shell>
  122. <div class="mx-4">
  123. <Form />
  124. <div class="pb-4">
  125. <div class="mb-2 text-sm">
  126. <span class="text-destructive mr-1">*</span>
  127. 论文PDF文件
  128. </div>
  129. <UploadDragger
  130. v-model:file-list="pdfFileList"
  131. :before-upload="beforePdfUpload"
  132. :max-count="1"
  133. accept=".pdf,application/pdf"
  134. @remove="onPdfRemove"
  135. >
  136. <p class="ant-upload-drag-icon">
  137. <InboxOutlined />
  138. </p>
  139. <p class="ant-upload-text">点击上传或拖拽PDF文件到此处</p>
  140. <p class="ant-upload-hint">
  141. 仅支持PDF格式文件,建议文件大小不超过20MB
  142. </p>
  143. </UploadDragger>
  144. </div>
  145. <Alert type="info" show-icon class="mb-4">
  146. <template #message>温馨提示</template>
  147. <template #description>
  148. <ul class="mb-0 list-disc pl-4 text-sm">
  149. <li>请确保论文内容符合学术规范和版权要求</li>
  150. <li>上传的PDF文件将用于在线预览和下载</li>
  151. <li>论文一经上传,将进入审核流程</li>
  152. </ul>
  153. </template>
  154. </Alert>
  155. </div>
  156. </Shell>
  157. </template>