OfflineExamUpload.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <div>
  3. <Upload
  4. ref="uploadComp"
  5. :headers="headers"
  6. :data="{ fileType: fileType }"
  7. :before-upload="handleBeforeUpload"
  8. :action="
  9. '/api/ecs_oe_student/offlineExam/submitPaper?examRecordDataId=' +
  10. course.examRecordDataId
  11. "
  12. :max-size="1024 * 30"
  13. :format="uploadFileFormat"
  14. :accept="uploadFileAccept"
  15. :on-format-error="handleFormatError"
  16. :on-exceeded-size="handleMaxSize"
  17. :on-success="handleSuccess"
  18. :on-error="handleError"
  19. :show-upload-list="false"
  20. >
  21. <i-button
  22. icon="ios-cloud-upload-outline"
  23. class="qm-primary-button"
  24. style="width: 100%;"
  25. >
  26. 上传作答
  27. </i-button>
  28. </Upload>
  29. <div v-if="file !== null && loadingStatus">
  30. 待上传文件: {{ file.name }}
  31. <i-button :loading="loadingStatus">
  32. {{ loadingStatus ? "上传中..." : "上传" }}
  33. </i-button>
  34. </div>
  35. </div>
  36. </template>
  37. <script>
  38. export default {
  39. name: "EcsOfflineUpload",
  40. data() {
  41. return {
  42. headers: {
  43. token: window.sessionStorage.getItem("token"),
  44. key: window.localStorage.getItem("key")
  45. },
  46. file: null,
  47. fileType: null,
  48. loadingStatus: false,
  49. uploadFileFormat: [],
  50. uploadFileAccept: ""
  51. };
  52. },
  53. props: {
  54. course: Object
  55. },
  56. async created() {
  57. const res = await this.$http.get(
  58. "/api/ecs_exam_work/exam/examOrgProperty/" +
  59. this.course.examId +
  60. `/OFFLINE_UPLOAD_FILE_TYPE`
  61. );
  62. this.uploadFileFormat = res.data || [];
  63. this.uploadFileFormat = this.uploadFileFormat.map(v => v.toLowerCase());
  64. this.uploadFileAccept = this.uploadFileFormat
  65. .map(v => "application/" + v)
  66. .join();
  67. },
  68. methods: {
  69. fileFormatCheck(file, resolve, reject) {
  70. function getMimetype(signature) {
  71. switch (signature) {
  72. case "89504E47":
  73. return "image/png";
  74. case "47494638":
  75. return "image/gif";
  76. case "25504446":
  77. return "application/pdf";
  78. case "FFD8FFDB":
  79. case "FFD8FFE0":
  80. case "FFD8FFE1":
  81. return "image/jpeg";
  82. case "504B0304":
  83. return "application/zip";
  84. case "504B34":
  85. return "application/zip";
  86. default:
  87. return "Unknown filetype";
  88. }
  89. }
  90. const filereader = new FileReader();
  91. let uploads = [];
  92. filereader.onloadend = evt => {
  93. if (evt.target.readyState === FileReader.DONE) {
  94. const uint = new Uint8Array(evt.target.result);
  95. let bytes = [];
  96. uint.forEach(byte => {
  97. bytes.push(byte.toString(16));
  98. });
  99. const hex = bytes.join("").toUpperCase();
  100. uploads.push({
  101. filename: file.name,
  102. filetype: file.type ? file.type : "Unknown/Extension missing",
  103. binaryFileType: getMimetype(hex),
  104. hex: hex
  105. });
  106. if (["application/pdf"].includes(getMimetype(hex))) {
  107. if (!file.name.endsWith(".pdf")) {
  108. this.loadingStatus = false;
  109. this.$Notice.warning({
  110. title: "文件内容与文件的后缀不一致"
  111. // desc: file.name + " 文件是pdf文档,但文件名后缀不是.pdf!"
  112. });
  113. this.file = null;
  114. reject("文件内容与文件的后缀不一致,请确认文件是pdf文档!");
  115. } else {
  116. resolve();
  117. }
  118. } else if (["application/zip"].includes(getMimetype(hex))) {
  119. if (!file.name.endsWith(".zip")) {
  120. this.loadingStatus = false;
  121. // this.$refs.uploadComp.fileList.splice(0);
  122. // this.$refs.uploadComp.fileList = [];
  123. this.$Notice.warning({
  124. title: "文件内容与文件的后缀不一致"
  125. // desc: file.name + " 文件是zip压缩包,但文件名后缀不是.zip!"
  126. });
  127. this.file = null;
  128. reject("文件内容与文件的后缀不一致,请确认文件是zip压缩包!");
  129. } else {
  130. resolve();
  131. }
  132. } else {
  133. console.log("binary file type check: not zip or pdf");
  134. window._hmt.push([
  135. "_trackEvent",
  136. "离线考试页面",
  137. "上传作答",
  138. "文件格式非zip或pdf"
  139. ]);
  140. this.$Notice.warning({
  141. title: "作答文件损坏",
  142. desc:
  143. file.name +
  144. " 文件无法以 " +
  145. this.uploadFileFormat.join(" 或 ") +
  146. " 格式读取。"
  147. });
  148. this.file = null;
  149. this.loadingStatus = false;
  150. reject("作答文件损坏");
  151. }
  152. }
  153. };
  154. const blob = file.slice(0, 4);
  155. filereader.readAsArrayBuffer(blob);
  156. },
  157. handleSuccess() {
  158. window._hmt.push(["_trackEvent", "离线考试页面", "上传作答", "上传成功"]);
  159. this.file = null;
  160. this.loadingStatus = false;
  161. this.$Message.success({
  162. content: "上传成功",
  163. duration: 5,
  164. closable: true
  165. });
  166. this.$emit("reloadList");
  167. },
  168. handleError() {
  169. window._hmt.push(["_trackEvent", "离线考试页面", "上传作答", "上传失败"]);
  170. this.file = null;
  171. this.loadingStatus = false;
  172. this.$Message.error({
  173. content: "上传失败",
  174. duration: 15,
  175. closable: true
  176. });
  177. },
  178. handleFormatError(file) {
  179. this.file = null;
  180. this.loadingStatus = false;
  181. this.$Notice.warning({
  182. title: "作答文件格式不对",
  183. desc:
  184. file.name +
  185. " 文件格式不对,请选择 " +
  186. this.uploadFileFormat.join(" 或 ") +
  187. " 文件。"
  188. });
  189. },
  190. handleMaxSize(file) {
  191. this.file = null;
  192. this.loadingStatus = false;
  193. this.$Notice.warning({
  194. title: "超出文件大小限制",
  195. desc: file.name + " 太大,作答文件不能超过30M."
  196. });
  197. },
  198. handleBeforeUpload(file) {
  199. if (file.type.includes("/pdf")) {
  200. this.fileType = "pdf";
  201. } else if (file.type.includes("/zip")) {
  202. this.fileType = "zip";
  203. }
  204. this.file = file;
  205. this.loadingStatus = true;
  206. return new Promise((resolve, reject) =>
  207. this.fileFormatCheck(file, resolve, reject)
  208. );
  209. }
  210. }
  211. };
  212. </script>
  213. <style lang="postcss">
  214. .list .ivu-upload-select {
  215. width: 100%;
  216. }
  217. </style>