zhangjie před 2 roky
rodič
revize
0ba2c27f1b

+ 13 - 1
src/App.vue

@@ -36,7 +36,7 @@ import timeMixin from "./mixins/timeMixin";
 import { QUESTION_API } from "@/constants/constants";
 import { questionSecurityCheckApi } from "./modules/question/api";
 import { USER_SIGNIN } from "./modules/portal/store/user";
-import { mapActions } from "vuex";
+import { mapActions, mapMutations } from "vuex";
 
 export default {
   name: "App",
@@ -93,10 +93,14 @@ export default {
       },
     },
   },
+  mounted() {
+    this.getVersion();
+  },
   beforeDestroy() {
     this.clearSetTs();
   },
   methods: {
+    ...mapMutations(["setVersion"]),
     ...mapActions([USER_SIGNIN]),
     async onlineSignal() {
       if (this.signalWaiting) return;
@@ -135,6 +139,14 @@ export default {
       this.modalForm.safePassword = "";
       this.modalIsShow = false;
     },
+    async getVersion() {
+      const res = await this.$httpWithMsg
+        .post(QUESTION_API + "/auth/version")
+        .catch(() => {});
+      if (!res) return;
+
+      this.setVersion(res.data);
+    },
   },
 };
 </script>

+ 5 - 1
src/modules/portal/views/Login.vue

@@ -12,6 +12,7 @@
           target="_blank"
           >鄂ICP备12000033号-13</a
         >
+        <span v-if="version" class="margin-left-10">v{{ version }}</span>
       </div>
       <div class="login-body" @keyup.enter="submit">
         <h1 class="login-body-title">题库管理系统</h1>
@@ -60,7 +61,7 @@
 </template>
 
 <script>
-import { mapActions } from "vuex";
+import { mapActions, mapState } from "vuex";
 import { USER_SIGNIN } from "../store/user";
 import { QUESTION_API } from "@/constants/constants";
 
@@ -129,6 +130,9 @@ export default {
       },
     };
   },
+  computed: {
+    ...mapState(["version"]),
+  },
   watch: {
     $route(to) {
       this.loginInfo.rootOrgId = to.query.orgId;

+ 2 - 1
src/modules/portal/views/home/Home.vue

@@ -38,6 +38,7 @@
             target="_blank"
             >鄂ICP备12000033号-13</a
           >
+          <span v-if="version" class="margin-left-10">v{{ version }}</span>
         </div>
       </div>
     </div>
@@ -248,7 +249,7 @@ export default {
   },
   computed: {
     ...mapState({ user: (state) => state.user }),
-    ...mapState(["currentPaths"]),
+    ...mapState(["currentPaths", "version"]),
     ifShowHomeSide() {
       return this.$route.fullPath.startsWith("/home") === false;
     },

+ 1 - 0
src/modules/question/api.js

@@ -289,6 +289,7 @@ export function questionImportExcelFileUpload(data, headData) {
     data,
     {
       headers: headData,
+      noToast: true,
     }
   );
 }

+ 108 - 86
src/modules/question/components/QuestionImportDialog.vue

@@ -1,93 +1,108 @@
 <template>
-  <el-dialog
-    custom-class="side-dialog"
-    :visible.sync="modalIsShow"
-    title="试题导入"
-    width="700px"
-    :modal="false"
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-    append-to-body
-    destroy-on-close
-    @open="visibleChange"
-  >
-    <el-form
-      ref="modalFormComp"
-      :model="modalForm"
-      :rules="rules"
-      label-width="120px"
+  <div>
+    <el-dialog
+      custom-class="side-dialog"
+      :visible.sync="modalIsShow"
+      title="试题导入"
+      width="700px"
+      :modal="false"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      destroy-on-close
+      @open="visibleChange"
     >
-      <el-form-item label="导入类型">
-        <el-radio-group v-model="importType" @change="importTypeChange">
-          <el-radio
-            v-for="item in importTypeList"
-            :key="item.name"
-            :label="item.name"
-            >{{ item.name }}</el-radio
-          >
-        </el-radio-group>
-      </el-form-item>
-      <el-form-item
-        v-if="importType !== 'zip'"
-        prop="courseId"
-        label="课程名称"
-      >
-        <course-select v-model="modalForm.courseId" @change="courseChange">
-        </course-select>
-      </el-form-item>
-      <el-form-item v-if="importType !== 'excel'" label="是否使用原卷">
-        <el-radio-group v-model="modalForm.useOriginalPaper">
-          <el-radio :label="true">是</el-radio>
-          <el-radio :label="false">否</el-radio>
-        </el-radio-group>
-      </el-form-item>
-      <el-form-item
-        v-if="modalForm.useOriginalPaper && importType === 'word'"
-        prop="name"
-        label="试卷名称"
+      <el-form
+        ref="modalFormComp"
+        :model="modalForm"
+        :rules="rules"
+        label-width="120px"
       >
-        <el-input
-          v-model="modalForm.name"
-          placeholder="请输入试卷名称"
-          clearable
+        <el-form-item label="导入类型">
+          <el-radio-group v-model="importType" @change="importTypeChange">
+            <el-radio
+              v-for="item in importTypeList"
+              :key="item.name"
+              :label="item.name"
+              >{{ item.name }}</el-radio
+            >
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item
+          v-if="importType !== 'zip'"
+          prop="courseId"
+          label="课程名称"
         >
-        </el-input>
-      </el-form-item>
-      <el-form-item v-if="modalForm.useOriginalPaper" label="总分校验">
-        <el-radio-group v-model="modalForm.checkTotalScore">
-          <el-radio :label="true">开启</el-radio>
-          <el-radio :label="false">关闭</el-radio>
-        </el-radio-group>
-      </el-form-item>
-      <el-form-item
-        v-if="modalForm.checkTotalScore && modalForm.useOriginalPaper"
-        label="试卷总分"
-        prop="totalScore"
-      >
-        <el-input-number
-          v-model="modalForm.totalScore"
-          style="width: 125px"
-          :min="1"
-          :max="1000"
-          :step="1"
-          step-strictly
-          :controls="false"
-        ></el-input-number
-      ></el-form-item>
-      <el-form-item prop="file">
-        <import-file
-          ref="ImportFile"
-          :format="importFileTypes"
-          :template-url="templateUrl"
-          only-fetch-file
-          @file-change="fileChange"
-          @confirm="confirm"
-        ></import-file>
-      </el-form-item>
-    </el-form>
+          <course-select v-model="modalForm.courseId" @change="courseChange">
+          </course-select>
+        </el-form-item>
+        <el-form-item v-if="importType !== 'excel'" label="是否使用原卷">
+          <el-radio-group v-model="modalForm.useOriginalPaper">
+            <el-radio :label="true">是</el-radio>
+            <el-radio :label="false">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item
+          v-if="modalForm.useOriginalPaper && importType === 'word'"
+          prop="name"
+          label="试卷名称"
+        >
+          <el-input
+            v-model="modalForm.name"
+            placeholder="请输入试卷名称"
+            clearable
+          >
+          </el-input>
+        </el-form-item>
+        <el-form-item v-if="modalForm.useOriginalPaper" label="总分校验">
+          <el-radio-group v-model="modalForm.checkTotalScore">
+            <el-radio :label="true">开启</el-radio>
+            <el-radio :label="false">关闭</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item
+          v-if="modalForm.checkTotalScore && modalForm.useOriginalPaper"
+          label="试卷总分"
+          prop="totalScore"
+        >
+          <el-input-number
+            v-model="modalForm.totalScore"
+            style="width: 125px"
+            :min="1"
+            :max="1000"
+            :step="1"
+            step-strictly
+            :controls="false"
+          ></el-input-number
+        ></el-form-item>
+        <el-form-item prop="file">
+          <import-file
+            ref="ImportFile"
+            :format="importFileTypes"
+            :template-url="templateUrl"
+            only-fetch-file
+            @file-change="fileChange"
+            @confirm="confirm"
+          ></import-file>
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer"></div>
+    </el-dialog>
 
-    <div slot="footer"></div>
-  </el-dialog>
+    <el-dialog
+      :visible.sync="errorMsgModalIsShow"
+      title="错误信息"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @closed="excelErrorMsgs = []"
+    >
+      <div>
+        <p v-for="(cont, index) in excelErrorMsgs" :key="index">{{ cont }}</p>
+      </div>
+    </el-dialog>
+  </div>
 </template>
 
 <script>
@@ -169,6 +184,8 @@ export default {
       },
       fileData: {},
       templateUrl: "",
+      errorMsgModalIsShow: false,
+      excelErrorMsgs: [],
       loading: false,
     };
   },
@@ -260,7 +277,12 @@ export default {
 
       const res = await uploadApi(formData, {
         md5: this.fileData.md5,
-      }).catch(() => {});
+      }).catch((error) => {
+        if (error.response?.data.desc) {
+          this.errorMsgModalIsShow = true;
+          this.excelErrorMsgs = error.response.data.desc.split("\n");
+        }
+      });
       this.loading = false;
       this.$refs.ImportFile.setLoading(false);
 

+ 17 - 7
src/plugins/axios.js

@@ -20,6 +20,7 @@ let config = {
 const _$httpWith500Msg = axios.create(config);
 const _$http = axios.create(config); // no auto 500 error UI
 const _$httpWithoutBar = axios.create(config);
+const noauthUrls = ["/auth/login", "/auth/version", "/auth/thirdPartyAccess"];
 
 /**
  * A. token lifecycle
@@ -54,10 +55,7 @@ _$httpWith500Msg.interceptors.request.use(
   function (config) {
     networkInformationHint();
     // Do something before request is sent
-    if (
-      config.url.includes("/login") === false &&
-      config.url.includes("/auth/thirdPartyAccess") === false
-    ) {
+    if (!noauthUrls.some((url) => config.url.includes(url))) {
       if (!wk_token) {
         const user = JSON.parse(window.sessionStorage.getItem("user"));
         if (!user) {
@@ -109,7 +107,7 @@ _$http.interceptors.request.use(
   function (config) {
     networkInformationHint();
     // Do something before request is sent
-    if (config.url.includes("/login") === false) {
+    if (!noauthUrls.some((url) => config.url.includes(url))) {
       if (!wk_token) {
         const user = JSON.parse(window.sessionStorage.getItem("user"));
         if (!user) {
@@ -179,7 +177,7 @@ _$httpWith500Msg.interceptors.response.use(
     return response;
   },
   (error) => {
-    console.log(error);
+    console.dir(error);
     if (!error.response) {
       // "Network Error" 网络不通,直接返回
 
@@ -190,6 +188,10 @@ _$httpWith500Msg.interceptors.response.use(
       });
       return Promise.reject(error);
     }
+
+    if (error.config.noToast) {
+      return Promise.reject(error);
+    }
     // 这里是返回状态码不为200时候的错误处理
     let status = error.response.status;
 
@@ -275,6 +277,10 @@ _$http.interceptors.response.use(
       });
       return Promise.reject(error);
     }
+
+    if (error.config.noToast) {
+      return Promise.reject(error);
+    }
     // 这里是返回状态码不为200时候的错误处理
     let status = error.response.status;
 
@@ -324,7 +330,7 @@ _$httpWithoutBar.interceptors.request.use(
   function (config) {
     networkInformationHint();
     // Do something before request is sent
-    if (config.url.includes("/login") === false) {
+    if (!noauthUrls.some((url) => config.url.includes(url))) {
       if (!wk_token) {
         const user = JSON.parse(window.sessionStorage.getItem("user"));
         if (!user) {
@@ -380,6 +386,10 @@ _$httpWithoutBar.interceptors.response.use(
       });
       return Promise.reject(error);
     }
+
+    if (error.config.noToast) {
+      return Promise.reject(error);
+    }
     // 这里是返回状态码不为200时候的错误处理
     let status = error.response.status;
 

+ 9 - 2
src/store/index.js

@@ -10,8 +10,15 @@ import importEdit from "../modules/question/components/import-edit/store";
 Vue.use(Vuex);
 
 export default new Vuex.Store({
-  state: {},
-  mutations: {},
+  state: {
+    version: "",
+  },
+  mutations: {
+    setVersion(state, version) {
+      sessionStorage.setItem("version", version);
+      state.version = version;
+    },
+  },
   actions: {},
   modules: {
     user,