浏览代码

feat: 文件下载优化

chenhao 2 年之前
父节点
当前提交
6eb00fa30e

+ 2 - 2
src/App.vue

@@ -3,8 +3,8 @@
 </template>
 
 <script setup lang="ts" name="App">
-import { getUserInfoHttp } from "./apis/user";
-import { getLoginResult } from "./utils/auth";
+import { getUserInfoHttp } from "@api/user";
+import { getLoginResult } from "@/utils/auth";
 if (getLoginResult()) {
   getUserInfoHttp();
 }

+ 1 - 1
src/apis/common.ts

@@ -1,6 +1,6 @@
 import request from "@/plugins/request";
 import { cacheLoginResult } from "@/utils/auth";
-import { getUserInfoHttp } from "./user";
+import { getUserInfoHttp } from "@api/user";
 
 /**
  * @description 登录

+ 1 - 0
src/apis/struct.ts

@@ -40,6 +40,7 @@ export const importPaperStructHttp = (data: FormData) => {
 
 export const downloadPaperStructHttp = (data: FetchSubjectsListQuery) => {
   return request.post<Blob>("/api/paper/export-subjective", data, {
+    responseType: "blob",
     download: true,
   });
 };

+ 1 - 1
src/layout/index.vue

@@ -10,7 +10,7 @@
 </template>
 
 <script setup lang="ts" name="Layout">
-import LeftMenu from "./left-menu.vue";
+import LeftMenu from "@/layout/left-menu.vue";
 </script>
 
 <style scoped lang="less">

+ 1 - 1
src/layout/left-menu.vue

@@ -23,7 +23,7 @@
 </template>
 
 <script setup lang="ts" name="LayoutLeftMenu">
-import MenuItem from "./menu-item.vue";
+import MenuItem from "@/layout/menu-item.vue";
 import { exitLogin } from "@/utils/common";
 import useMainStore from "@/store/main";
 

+ 2 - 2
src/main.ts

@@ -1,8 +1,8 @@
 import { createApp } from "vue";
 import { createPinia } from 'pinia'
 import router from "@/routes";
-import App from "./App.vue";
-import flexible from './utils/flexible';
+import App from "@/App.vue";
+import flexible from '@/utils/flexible';
 import 'virtual:svg-icons-register'
 
 import "tailwindcss/tailwind.css";

+ 3 - 14
src/pages/subjects-manage/index.vue

@@ -158,8 +158,6 @@ import {
 } from "@/apis/struct";
 import { getSchoolListHttp } from "@/apis/school";
 import { getExamListHttp } from "@/apis/exam";
-import { download, extractFileName } from "@/utils/common";
-import { AxiosResponse } from "axios";
 
 const showImportModal = ref(false);
 const importType = ref("subject");
@@ -299,14 +297,10 @@ const importPaperStruct = async () => {
 
 const downloadPaperStruct = async () => {
   try {
-    const result = await downloadPaperStructHttp({
+    await downloadPaperStructHttp({
       ...query,
       groupFinish: [void 0, true, false][query.groupFinish],
     });
-    if (result) {
-      const fileName = extractFileName(result.headers["content-disposition"]);
-      result && download(result.data, fileName);
-    }
   } catch (error) {
     console.error(error);
   }
@@ -330,15 +324,10 @@ const clearFileList = () => {
 
 const downloadTemplate = async () => {
   try {
-    let result: AxiosResponse<Blob>;
     if (importType.value === "subject") {
-      result = await downloadSubjectTemplateHttp();
+      await downloadSubjectTemplateHttp();
     } else {
-      result = await downloadPaperStructTemplateHttp();
-    }
-    if (result) {
-      const fileName = extractFileName(result.headers["content-disposition"]);
-      result && download(result.data, fileName);
+      await downloadPaperStructTemplateHttp();
     }
   } catch (error) {
     console.error(error);

+ 1 - 5
src/pages/user-manage/index.vue

@@ -207,7 +207,6 @@ import Block from "@/components/block/index.vue";
 import { message } from "ant-design-vue";
 import { Form } from "ant-design-vue";
 import { getSchoolListHttp } from "@/apis/school";
-import { download, extractFileName } from "@/utils/common";
 import type { UploadProps, TableColumnType } from "ant-design-vue";
 
 const showModal = ref(false);
@@ -378,10 +377,7 @@ const clearFileList = () => {
 };
 
 const downloadTemplate = () => {
-  downloadImportUserHttp().then((d) => {
-    const fileName = extractFileName(d.headers["content-disposition"]);
-    d && download(d.data, fileName);
-  });
+  downloadImportUserHttp()
 };
 
 const onImportUserList = () => {

+ 24 - 8
src/plugins/request.ts

@@ -1,8 +1,9 @@
 import axios, { AxiosError } from "axios";
 import { message } from "ant-design-vue";
 import { loadProgressBar } from "axios-progress-bar";
-import { signToken } from "./signToken";
-import { filterConfigEmpty } from "./configFilter";
+import { signToken } from "@/plugins/signToken";
+import { filterConfigEmpty } from "@/plugins/configFilter";
+import { downloadBlob } from "@/utils/common";
 import router from "@/routes";
 
 const request = axios.create({
@@ -33,6 +34,9 @@ request.interceptors.request.use(
     if (!config.headers["Content-Type"]?.toString().includes("multipart")) {
       config.transformRequest = (d) => new URLSearchParams(d);
     }
+    if (config.download) {
+      config.responseType = config.responseType || "blob";
+    }
     filterConfigEmpty(config);
     return config;
   },
@@ -47,6 +51,7 @@ request.interceptors.request.use(
 request.interceptors.response.use(
   (response) => {
     if (response.config.download) {
+      downloadBlob(response);
       return response;
     }
     if (response.data.hasError) {
@@ -56,13 +61,24 @@ request.interceptors.response.use(
     }
     return response.data;
   },
-  (error: AxiosError<any>) => {
+  async (error: AxiosError<any>) => {
     if (error.isAxiosError && !error.config.noToast) {
-      const msg =
-        error?.response?.data?.message ||
-        error.message ||
-        error.name ||
-        error.code;
+      let msg = "";
+      if (error.config?.responseType === "blob") {
+        try {
+          const e = JSON.parse(await error?.response?.data?.text());
+          msg = e.message || e.error || e;
+        } catch (error) {
+          console.error(error);
+        }
+      }
+      if (!msg) {
+        msg =
+          error?.response?.data?.message ||
+          error.message ||
+          error.name ||
+          error.code;
+      }
       message.error(msg);
     } else if (!error.isAxiosError) {
       error.message && message.error(error.message);

+ 13 - 6
src/utils/common.ts

@@ -1,7 +1,8 @@
-import { sessionStorageTool } from "./storage";
+import { sessionStorageTool } from "@/utils/storage";
 import { SESSION_STORAGE_KEYS } from "@/constants/storage";
 import { loginOutHttp } from "@/apis/common";
 import router from "@/routes";
+import type { AxiosResponse } from "axios";
 
 /** 退出登录 */
 export const exitLogin = () => {
@@ -11,14 +12,13 @@ export const exitLogin = () => {
   router.replace({ name: "login" });
 };
 
-
 /** 提取文件名 */
 export const extractFileName = (str: string) => {
-  if(/fileName=([^;\s]*)/gi.test(str)){
-    return decodeURIComponent(RegExp.$1)
+  if (/fileName=([^;\s]*)/gi.test(str)) {
+    return decodeURIComponent(RegExp.$1);
   }
-  return ''
-}
+  return "";
+};
 
 /** 下载文件 */
 export const download = (blob: Blob, filename: string = "") => {
@@ -31,3 +31,10 @@ export const download = (blob: Blob, filename: string = "") => {
   a.remove();
   URL.revokeObjectURL(blobUrl);
 };
+
+export const downloadBlob = (response: AxiosResponse) => {
+  if(response){
+    const fileName = extractFileName(response.headers["content-disposition"])
+    download(response.data, fileName)
+  }
+};