Michael Wang 4 years ago
parent
commit
eb5bf55d39
45 changed files with 219 additions and 774 deletions
  1. 6 6
      .eslintrc.js
  2. 1 1
      jest.config.js
  3. 15 15
      package.json
  4. 4 4
      src/components/MainLayout/MainLayout.vue
  5. 2 2
      src/components/MainLayout/SiteMessagePopup.vue
  6. 1 3
      src/features/Login/StudentAccess.vue
  7. 0 143
      src/features/Login/VerifyCode.vue
  8. 1 1
      src/features/OfflineExam/OfflineExamHome.vue
  9. 2 2
      src/features/OfflineExam/OfflineExamList.vue
  10. 9 9
      src/features/OfflineExam/OfflineExamModal.vue
  11. 9 9
      src/features/OfflineExam/OfflineExamUpload.vue
  12. 0 407
      src/features/OfflineExam/OfflineExamUploadCug.vue
  13. 22 22
      src/features/OnlineExam/CheckComputer.vue
  14. 2 2
      src/features/OnlineExam/Examing/BooleanQuestionView.vue
  15. 7 7
      src/features/OnlineExam/Examing/ExamingEnd.vue
  16. 12 16
      src/features/OnlineExam/Examing/ExamingHome.vue
  17. 9 9
      src/features/OnlineExam/Examing/FaceId.vue
  18. 7 11
      src/features/OnlineExam/Examing/FaceMotion/FaceMotion.vue
  19. 2 0
      src/features/OnlineExam/Examing/FillBlankQuestionView.vue
  20. 3 3
      src/features/OnlineExam/Examing/MultipleQuestionView.vue
  21. 1 1
      src/features/OnlineExam/Examing/OverallProgress.vue
  22. 4 4
      src/features/OnlineExam/Examing/QuestionAudio.vue
  23. 1 1
      src/features/OnlineExam/Examing/QuestionContainer.vue
  24. 1 1
      src/features/OnlineExam/Examing/QuestionNavView.vue
  25. 1 1
      src/features/OnlineExam/Examing/QuestionView.vue
  26. 1 1
      src/features/OnlineExam/Examing/QuestionViewSingle.vue
  27. 3 3
      src/features/OnlineExam/Examing/SingleQuestionView.vue
  28. 10 10
      src/features/OnlineExam/Examing/TextQuestionView.vue
  29. 9 11
      src/features/OnlineExam/Examing/UploadPhotos.vue
  30. 3 7
      src/features/OnlineExam/OnlineExamFaceCheckModal.vue
  31. 11 11
      src/features/OnlineExam/OnlineExamHome.vue
  32. 3 3
      src/features/OnlineExam/OnlineExamOverview.vue
  33. 4 8
      src/features/OnlineExam/PhoneVerifyForDD.vue
  34. 2 2
      src/features/OnlinePractice/OnlinePracticeHome.vue
  35. 1 1
      src/features/OnlinePractice/OnlinePracticeRecordDetail.vue
  36. 2 2
      src/features/OnlinePractice/OnlinePracticeRecordList.vue
  37. 2 2
      src/features/Password/Password.vue
  38. 2 2
      src/features/SiteMessage/SiteMessageDetail.vue
  39. 3 3
      src/features/SiteMessage/SiteMessageHome.vue
  40. 1 1
      src/main.js
  41. 24 24
      src/plugins/vueLifecylceLogs.js
  42. 13 0
      src/router.js
  43. 1 1
      tests/vue/child.vue
  44. 1 1
      tests/vue/event.vue
  45. 1 1
      tests/vue/useMyinput.vue

+ 6 - 6
.eslintrc.js

@@ -5,7 +5,7 @@ module.exports = {
   },
   extends: ["plugin:vue/recommended", "eslint:recommended", "@vue/prettier"],
   parserOptions: {
-    parser: "babel-eslint"
+    parser: "babel-eslint",
   },
   rules: {
     // "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
@@ -18,11 +18,11 @@ module.exports = {
     {
       files: [
         "**/__tests__/*.{j,t}s?(x)",
-        "**/tests/unit/**/*.spec.{j,t}s?(x)"
+        "**/tests/unit/**/*.spec.{j,t}s?(x)",
       ],
       env: {
-        jest: true
-      }
-    }
-  ]
+        jest: true,
+      },
+    },
+  ],
 };

+ 1 - 1
jest.config.js

@@ -1,3 +1,3 @@
 module.exports = {
-  preset: "@vue/cli-plugin-unit-jest"
+  preset: "@vue/cli-plugin-unit-jest",
 };

+ 15 - 15
package.json

@@ -30,7 +30,7 @@
   "dependencies": {
     "@chenfengyuan/vue-qrcode": "^1.0.2",
     "axios": "^0.19.2",
-    "core-js": "^3.6.5",
+    "core-js": "^3.8.0",
     "face-api.js": "0.21.0",
     "intro.js": "^2.9.3",
     "iview": "^3.5.4",
@@ -41,31 +41,31 @@
     "ua-parser-js": "^0.7.21",
     "viewerjs": "^1.6.1",
     "vue": "^2.6.11",
-    "vue-router": "^3.4.3",
+    "vue-router": "^3.4.9",
     "vue-spinner": "^1.0.4",
     "vue-splitpane": "^1.0.6",
     "vuedraggable": "^2.24.0",
-    "vuex": "^3.5.1",
+    "vuex": "^3.6.0",
     "webrtc-adapter": "^7.7.0"
   },
   "devDependencies": {
-    "@vue/cli-plugin-babel": "^4.5.3",
-    "@vue/cli-plugin-eslint": "^4.5.3",
-    "@vue/cli-plugin-pwa": "^4.5.3",
-    "@vue/cli-plugin-router": "~4.5.3",
-    "@vue/cli-plugin-unit-jest": "^4.5.3",
-    "@vue/cli-plugin-vuex": "~4.5.3",
-    "@vue/cli-service": "^4.5.3",
+    "@vue/cli-plugin-babel": "^4.5.9",
+    "@vue/cli-plugin-eslint": "^4.5.9",
+    "@vue/cli-plugin-pwa": "^4.5.9",
+    "@vue/cli-plugin-router": "~4.5.9",
+    "@vue/cli-plugin-unit-jest": "^4.5.9",
+    "@vue/cli-plugin-vuex": "~4.5.9",
+    "@vue/cli-service": "^4.5.9",
     "@vue/eslint-config-prettier": "^6.0.0",
     "@vue/test-utils": "^1.0.3",
     "babel-eslint": "^10.1.0",
-    "babel-plugin-import": "^1.13.0",
-    "eslint": "^7.6.0",
+    "babel-plugin-import": "^1.13.3",
+    "eslint": "^7.14.0",
     "eslint-plugin-prettier": "^3.1.4",
-    "eslint-plugin-vue": "^6.2.2",
+    "eslint-plugin-vue": "^7.1.0",
     "iview-loader": "^1.2.2",
-    "json-server": "^0.16.1",
-    "prettier": "^2.0.5",
+    "json-server": "^0.16.3",
+    "prettier": "^2.2.0",
     "vue-cli-plugin-iview": "^1.0.6",
     "vue-template-compiler": "^2.6.11"
   }

+ 4 - 4
src/components/MainLayout/MainLayout.vue

@@ -19,13 +19,13 @@
           </Tabs>
         </div>
       </Poptip>
-      <span v-if="ifShowQr" style="margin: auto 20px;">|</span>
+      <span v-if="ifShowQr" style="margin: auto 20px">|</span>
       <Poptip trigger="hover" width="300">
         <span class="name-arrow"
           >{{ user.displayName }} &nbsp;
           <i
             class="ivu-icon ivu-icon-md-arrow-dropdown"
-            style="vertical-align: middle;"
+            style="vertical-align: middle"
           ></i>
         </span>
         <div slot="content">
@@ -64,10 +64,10 @@
           </div>
         </div>
       </Poptip>
-      <span style="margin: auto 20px;">|</span>
+      <span style="margin: auto 20px">|</span>
       <a
         class="qm-primary-text"
-        style="display: inline-block; margin-right: 20px; text-align: center;"
+        style="display: inline-block; margin-right: 20px; text-align: center"
         @click="() => logout('?LogoutReason=正常退出')"
       >
         {{ isEpcc ? "返回" : "退出登录" }}

+ 2 - 2
src/components/MainLayout/SiteMessagePopup.vue

@@ -32,7 +32,7 @@
       >
         {{ unreadMessageContent }}
       </p>
-      <div style="text-align: left; margin-left: 20px; margin-bottom: 10px;">
+      <div style="text-align: left; margin-left: 20px; margin-bottom: 10px">
         <router-link
           :to="'/site-message/' + unreadMessage.id"
           ondragstart="return false;"
@@ -40,7 +40,7 @@
           详情 >>>
         </router-link>
         <span
-          style="display: inline-block; margin-left: 20px; cursor: pointer;"
+          style="display: inline-block; margin-left: 20px; cursor: pointer"
           @click="ignoreMessage"
           >忽略</span
         >

+ 1 - 3
src/features/Login/StudentAccess.vue

@@ -1,7 +1,5 @@
 <template>
-  <div>
-    第三方登录...
-  </div>
+  <div>第三方登录...</div>
 </template>
 
 <script>

+ 0 - 143
src/features/Login/VerifyCode.vue

@@ -1,143 +0,0 @@
-<template>
-  <div style="display: flex; justify-content: space-between;">
-    <img
-      v-if="init || base64"
-      style="display: inline-block; width: 100px; height: 40px;"
-      :src="base64"
-    />
-    <span
-      v-else
-      style="
-        display: inline-block;
-        width: 100px;
-        height: 40px;
-        line-height: 40px;
-      "
-      >等待获取图片</span
-    >
-    <span style="font-size: 20px; padding: 1px;">=</span>
-
-    <input
-      v-model="result"
-      style="
-        width: 40px;
-        border: 1px solid #dcdee2;
-        padding: 2px;
-        text-align: center;
-      "
-      type="number"
-      step="any"
-      class="input-number"
-      @input="notify"
-      @focus="focused = true"
-      @focusout="changeFocus"
-    />
-    <i-button
-      class="qm-primary-button"
-      style="height: 40px; width: 60px; padding: 0;"
-      :disabled="disabled"
-      @click="getVerifyCode"
-    >
-      看不清
-    </i-button>
-  </div>
-</template>
-
-<script>
-import { mapState as globalMapState } from "vuex";
-
-export default {
-  name: "VerifyCode",
-  props: {
-    init: { type: Boolean, default: false },
-    // rootOrgId: { type: Number, default: 0 },
-    accountValue: { type: String, default: "" },
-  },
-  data() {
-    return {
-      clicked: false,
-      focused: false,
-      base64: "",
-      uuid: "",
-      result: "",
-    };
-  },
-  computed: {
-    ...globalMapState(["QECSConfig"]),
-    disabled() {
-      if (this.focused) {
-        return false; // 优先处理focus的情况
-      }
-      return !this.init || this.clicked;
-    },
-  },
-  watch: {
-    init(val) {
-      if (val) {
-        this.getVerifyCode();
-      }
-    },
-  },
-  beforeDestroy() {
-    clearTimeout(this.clickedTimeout);
-  },
-  methods: {
-    changeFocus() {
-      window.setTimeout(() => (this.focused = false), 300);
-    },
-    async getVerifyCode() {
-      // console.log(this.accountValue);
-      this.result = "";
-      if (!this.accountValue) {
-        this.$Message.warning({
-          content: "请先填写登录账号",
-          duration: 5,
-          closable: true,
-        });
-        return;
-      }
-      this.clicked = true;
-      clearTimeout(this.clickedTimeout);
-      this.clickedTimeout = setTimeout(() => {
-        this.clicked = false;
-      }, 3000);
-      // const params = new URLSearchParams();
-      // params.append("rootOrgId", this.QECSConfig.ROOT_ORG_ID);
-      // params.append("accountValue", this.accountValue);
-      // const res = await this.$http.get(
-      //   "/api/ecs_core/verifyCode/generate?" + params
-      // );
-      const params = new URLSearchParams();
-      params.append("rootOrgId", this.QECSConfig.ROOT_ORG_ID);
-      params.append("accountValue", this.accountValue);
-      const res = await this.$http.post(
-        "/api/ecs_core/verifyCode/generate",
-        params
-      );
-      // console.log(res);
-      this.uuid = res.data.slice(0, 32);
-      this.base64 = "data:image/jpeg;base64," + res.data.slice(32);
-      this.$emit("calcVerify", {
-        uuid: this.uuid,
-        verifyCode: this.result,
-      });
-    },
-    notify() {
-      const p = window.parseInt(this.result);
-
-      this.result = window.isNaN(p) ? "" : p;
-      this.$emit("calcVerify", {
-        uuid: this.uuid,
-        verifyCode: this.result,
-      });
-    },
-  },
-};
-</script>
-
-<style>
-.input-number::-webkit-inner-spin-button,
-.input-number::-webkit-inner-spin-button {
-  -webkit-appearance: none;
-}
-</style>

+ 1 - 1
src/features/OfflineExam/OfflineExamHome.vue

@@ -16,7 +16,7 @@
     <div class="home">
       <ecs-offline-list
         :courses="courses"
-        @reloadList="fetchData"
+        @reload-list="fetchData"
       ></ecs-offline-list>
     </div>
   </main-layout>

+ 2 - 2
src/features/OfflineExam/OfflineExamList.vue

@@ -106,7 +106,7 @@
       v-if="selectedCourse"
       ref="uploadModal"
       :course="selectedCourse"
-      @reloadList="$emit('reloadList')"
+      @reload-list="$emit('reload-list')"
     ></ecs-offline-exam-modal>
   </div>
 </template>
@@ -152,7 +152,7 @@ export default {
           params: { examStudentId: course.examStudentId },
         }
       );
-      this.$emit("reloadList");
+      this.$emit("reload-list");
     },
     previewPaper(course) {
       window._hmt.push(["_trackEvent", "离线考试页面", "预览"]);

+ 9 - 9
src/features/OfflineExam/OfflineExamModal.vue

@@ -10,8 +10,8 @@
     width="660"
     @close="modalClose"
   >
-    <div style="font-size: 16px; line-height: 20px;">
-      <span style="padding-right: 10px;">请选择上传文件类型:</span>
+    <div style="font-size: 16px; line-height: 20px">
+      <span style="padding-right: 10px">请选择上传文件类型:</span>
       <span
         v-if="serverFormat.includes('ZIP')"
         @click="selectedFileType = 'ZIP'"
@@ -21,7 +21,7 @@
           name="filetype"
           value="ZIP"
           :checked="selectedFileType == 'ZIP'"
-          style="display: inline-block;"
+          style="display: inline-block"
         />
         <span class="right-margin">ZIP</span>
       </span>
@@ -34,7 +34,7 @@
           name="filetype"
           value="PDF"
           :checked="selectedFileType == 'PDF'"
-          style="display: inline-block;"
+          style="display: inline-block"
         />
         <span class="right-margin">PDF</span>
       </span>
@@ -47,22 +47,22 @@
           name="filetype"
           value="IMAGE"
           :checked="selectedFileType == 'IMAGE'"
-          style="display: inline-block;"
+          style="display: inline-block"
         />
         <span class="right-margin">图片</span>
       </span>
     </div>
     <div
-      style="font-size: 16px; line-height: 20px; margin: 20px 0; display: flex;"
+      style="font-size: 16px; line-height: 20px; margin: 20px 0; display: flex"
     >
-      <div style="padding-right: 10px;">请选择文件:</div>
+      <div style="padding-right: 10px">请选择文件:</div>
       <OfflineExamUpload
         :course="course"
         :selected-file-type="selectedFileType"
         :upload-file-format="uploadFileFormat"
         :upload-file-accept="uploadFileAccept"
-        @reloadList="$emit('reloadList')"
-        @closeModal="closeModal"
+        @reload-list="$emit('reload-list')"
+        @close-modal="closeModal"
       />
     </div>
   </Modal>

+ 9 - 9
src/features/OfflineExam/OfflineExamUpload.vue

@@ -1,5 +1,5 @@
 <template>
-  <div style="width: 350px;">
+  <div style="width: 350px">
     <div v-if="selectedFileType === 'IMAGE'" class="total-images">
       <div
         v-for="(item, index) in uploadFileList"
@@ -20,7 +20,7 @@
           <Icon
             type="ios-trash-outline"
             size="30"
-            style="position: absolute; top: 0px;"
+            style="position: absolute; top: 0px"
             @click.native="handleRemoveTotal(index)"
           ></Icon>
         </div>
@@ -66,7 +66,7 @@
       <i-button
         icon="ios-cloud-upload-outline"
         class="qm-primary-button"
-        style="width: 40%; margin-right: 20px;"
+        style="width: 40%; margin-right: 20px"
         :disabled="uploadFileList.length === 0"
         @click="uploadFiles"
       >
@@ -74,8 +74,8 @@
       </i-button>
       <i-button
         class="qm-primary-button"
-        style="width: 40%;"
-        @click="$emit('closeModal')"
+        style="width: 40%"
+        @click="$emit('close-modal')"
       >
         取消上传
       </i-button>
@@ -309,8 +309,8 @@ export default {
       //     closable: true,
       //   });
       //   this.uploadFileList = [];
-      //   this.$emit("closeModal");
-      //   this.$emit("reloadList");
+      //   this.$emit("close-modal");
+      //   this.$emit("reload-list");
     },
     handleError(error, file) {
       window._hmt.push(["_trackEvent", "离线考试页面", "上传作答", "上传失败"]);
@@ -480,8 +480,8 @@ export default {
         closable: true,
       });
       this.uploadFileList = [];
-      this.$emit("closeModal");
-      this.$emit("reloadList");
+      this.$emit("close-modal");
+      this.$emit("reload-list");
     },
 
     async blobToSrc(item, index) {

+ 0 - 407
src/features/OfflineExam/OfflineExamUploadCug.vue

@@ -1,407 +0,0 @@
-<template>
-  <div>
-    <Upload
-      ref="uploadComp"
-      :headers="headers"
-      :data="{ fileType: fileType }"
-      :before-upload="handleBeforeUpload"
-      :action="
-        '/api/branch_ecs_oe_admin/offlineExam/submitPaper?examRecordDataId=' +
-        course.examRecordDataId
-      "
-      :max-size="1024 * 30"
-      :format="uploadFileFormat"
-      :accept="uploadFileAccept"
-      :on-format-error="handleFormatError"
-      :on-exceeded-size="handleMaxSize"
-      :on-success="handleSuccess"
-      :on-error="handleError"
-      :show-upload-list="false"
-    >
-      <i-button
-        icon="ios-cloud-upload-outline"
-        class="qm-primary-button"
-        style="width: 100%;"
-      >
-        上传作答
-      </i-button>
-    </Upload>
-    <div v-if="file !== null && loadingStatus">
-      待上传文件: {{ file.name }}
-      <i-button :loading="loadingStatus">
-        {{ loadingStatus ? "上传中..." : "上传" }}
-      </i-button>
-    </div>
-    <Modal v-model="showPreview" fullscreen footer-hide :closable="false">
-      <!-- <div slot="header"></div> -->
-      <img :id="previewId" class="preview-image" />
-    </Modal>
-  </div>
-</template>
-
-<script>
-import { printCurrentPage } from "./imageToPdf";
-
-export default {
-  name: "EcsOfflineUploadCug",
-  props: {
-    course: {
-      type: Object,
-      default() {
-        return {};
-      },
-    },
-  },
-  data() {
-    return {
-      headers: {
-        token: window.sessionStorage.getItem("token"),
-        key: window.localStorage.getItem("key"),
-      },
-      file: null,
-      fileType: null,
-      loadingStatus: false,
-      uploadFileFormat: [],
-      uploadFileAccept: "",
-      // imageSrc
-      previewImage: null,
-      showPreview: false,
-      previewId: "previewId" + Date.now(),
-    };
-  },
-  async created() {
-    const res = await this.$http.get(
-      "/api/ecs_exam_work/exam/getExamPropertyFromCacheByStudentSession/" +
-        this.course.examId +
-        `/OFFLINE_UPLOAD_FILE_TYPE`
-    );
-
-    this.uploadFileFormat =
-      (res.data.OFFLINE_UPLOAD_FILE_TYPE &&
-        JSON.parse(res.data.OFFLINE_UPLOAD_FILE_TYPE)) ||
-      [];
-    this.uploadFileAccept =
-      "image/jpeg," +
-      this.uploadFileFormat.map((v) => "application/" + v.toLowerCase()).join();
-    if (this.uploadFileAccept.includes("zip")) {
-      this.uploadFileAccept = ".zip," + this.uploadFileAccept;
-    }
-    this.uploadFileFormat.push(...["jpeg", "jpg"]);
-    this.uploadFileFormat = this.uploadFileFormat.map((v) => v.toLowerCase());
-  },
-  methods: {
-    fileFormatCheck(file, resolve, reject) {
-      function getMimetype(signature) {
-        switch (signature) {
-          case "89504E47":
-            return "image/png";
-          case "47494638":
-            return "image/gif";
-          case "25504446":
-            return "application/pdf";
-          case "FFD8FFDB":
-          case "FFD8FFE0":
-          case "FFD8FFE1":
-            return "image/jpeg";
-          case "504B0304":
-            return "application/zip";
-          case "504B34":
-            return "application/zip";
-          default:
-            return "Unknown filetype";
-        }
-      }
-      console.log(file);
-
-      const filereader = new FileReader();
-      let uploads = [];
-      filereader.onloadend = (evt) => {
-        if (evt.target.readyState === FileReader.DONE) {
-          const uint = new Uint8Array(evt.target.result);
-          let bytes = [];
-          uint.forEach((byte) => {
-            bytes.push(byte.toString(16));
-          });
-          const hex = bytes.join("").toUpperCase();
-          uploads.push({
-            filename: file.name,
-            filetype: file.type ? file.type : "Unknown/Extension missing",
-            binaryFileType: getMimetype(hex),
-            hex: hex,
-          });
-
-          if (["application/pdf"].includes(getMimetype(hex))) {
-            if (!file.name.endsWith(".pdf")) {
-              this.loadingStatus = false;
-              this.$Notice.warning({
-                title: "文件内容与文件的后缀不一致",
-                // desc: file.name + " 文件是pdf文档,但文件名后缀不是.pdf!"
-              });
-              this.file = null;
-              reject("文件内容与文件的后缀不一致,请确认文件是pdf文档!");
-            } else {
-              resolve();
-            }
-          } else if (["application/zip"].includes(getMimetype(hex))) {
-            if (!file.name.endsWith(".zip")) {
-              this.loadingStatus = false;
-              // this.$refs.uploadComp.fileList.splice(0);
-              // this.$refs.uploadComp.fileList = [];
-              this.$Notice.warning({
-                title: "文件内容与文件的后缀不一致",
-                // desc: file.name + " 文件是zip压缩包,但文件名后缀不是.zip!"
-              });
-              this.file = null;
-              reject("文件内容与文件的后缀不一致,请确认文件是zip压缩包!");
-            } else {
-              resolve();
-            }
-          } else if (["image/jpeg"].includes(getMimetype(hex))) {
-            if (file.name.endsWith(".jpeg") || file.name.endsWith(".jpg")) {
-              printCurrentPage()
-                .then((filename) => {
-                  // const fs = nodeRequire("fs");
-                  const path = window.nodeRequire("path");
-                  const fileNew = {
-                    name: path.basename(filename),
-                    path: filename,
-                    type: "application/pdf",
-                    // lastModified
-                    // lastModifiedDate
-                    // size
-                  };
-                  this.file = fileNew;
-                  file = fileNew;
-                  // console.log(this.$refs.uploadComp.fileList);
-                  // this.$refs.uploadComp.fileList = [file];
-                  // console.log(this.$refs.uploadComp.fileList);
-                  resolve();
-                })
-                .catch(() => {
-                  reject();
-                });
-            } else {
-              this.loadingStatus = false;
-              // this.$refs.uploadComp.fileList.splice(0);
-              // this.$refs.uploadComp.fileList = [];
-              this.$Notice.warning({
-                title: "文件内容与文件的后缀不一致",
-              });
-              this.file = null;
-              reject("文件内容与文件的后缀不一致,请确认文件是jpg文件!");
-            }
-          } else {
-            console.log("binary file type check: not zip or pdf");
-            window._hmt.push([
-              "_trackEvent",
-              "离线考试页面",
-              "上传作答",
-              "文件格式非zip或pdf",
-            ]);
-            this.$Notice.warning({
-              title: "作答文件损坏",
-              desc:
-                file.name +
-                " 文件无法以 " +
-                this.uploadFileFormat.join(" 或 ") +
-                " 格式读取。",
-            });
-            this.file = null;
-            this.loadingStatus = false;
-            reject("作答文件损坏");
-          }
-        }
-      };
-      const blob = file.slice(0, 4);
-      filereader.readAsArrayBuffer(blob);
-    },
-    handleSuccess() {
-      window._hmt.push(["_trackEvent", "离线考试页面", "上传作答", "上传成功"]);
-      this.file = null;
-      this.loadingStatus = false;
-      this.$Message.success({
-        content: "上传成功",
-        duration: 5,
-        closable: true,
-      });
-      this.$emit("reloadList");
-      this.showPreview = false;
-    },
-    handleError(error, file) {
-      window._hmt.push(["_trackEvent", "离线考试页面", "上传作答", "上传失败"]);
-      this.file = null;
-      this.loadingStatus = false;
-      console.log(error);
-      this.$Message.error({
-        content: (file && file.desc) || "上传失败",
-        duration: 15,
-        closable: true,
-      });
-      this.showPreview = false;
-    },
-    handleFormatError(file) {
-      this.file = null;
-      this.loadingStatus = false;
-      this.$Notice.warning({
-        title: "作答文件格式不对",
-        desc:
-          file.name +
-          " 文件格式不对,请选择 " +
-          this.uploadFileFormat.join(" 或 ") +
-          "  文件。",
-      });
-      this.showPreview = false;
-    },
-    handleMaxSize(file) {
-      this.file = null;
-      this.loadingStatus = false;
-      this.$Notice.warning({
-        title: "超出文件大小限制",
-        desc: file.name + " 太大,作答文件不能超过30M.",
-      });
-      this.showPreview = false;
-    },
-    async handleBeforeUpload(file) {
-      const suffix = file.name.split(".").pop();
-      if (suffix.toLowerCase() !== suffix) {
-        this.$Notice.error({
-          title: "文件名后缀必须是小写",
-          desc: file.name + " 文件名后缀必须是小写。",
-        });
-        return Promise.reject("file suffix should be lower case");
-      }
-      if (file.name.endsWith(".jpeg") || file.name.endsWith(".jpg")) {
-        new Promise((resolve, reject) => {
-          if (this.course.offlineFileUrl) {
-            this.$Modal.confirm({
-              title: "已有作答附件,是否覆盖?",
-              onCancel: () => reject("离线考试,取消覆盖"),
-              onOk: () => resolve(),
-            });
-          } else {
-            resolve();
-          }
-        })
-          .then(() => {
-            this.showPreview = true;
-            this.$Message.info({
-              content: "正在准备将图片转为PDF...",
-              duration: 1.5,
-              closable: true,
-            });
-
-            return new Promise((resolve) => {
-              var reader = new FileReader();
-              reader.onload = (e) => {
-                document
-                  .getElementById(this.previewId)
-                  .setAttribute("src", e.target.result);
-
-                setTimeout(resolve, 2500);
-                // resolve();
-              };
-              //Imagepath.files[0] is blob type
-              reader.readAsDataURL(file);
-            });
-          })
-          .then(() => {
-            // return;
-            return printCurrentPage()
-              .then((filename) => {
-                const fs = window.nodeRequire("fs");
-                const path = window.nodeRequire("path");
-                // const fileNew = {
-                //   name: path.basename(filename),
-                //   // filename: path.basename(filename),
-                //   uri: "file://" + filename,
-                //   // path: filename,
-                //   type: "application/pdf",
-                // };
-                const fileNew = new File(
-                  [fs.readFileSync(filename)],
-                  path.basename(filename),
-                  { type: "application/pdf" } // what I upload is image.
-                );
-                this.file = fileNew;
-
-                this.$Message.info({
-                  content: "图片转换成功,正在上传...",
-                  duration: 2,
-                  closable: true,
-                });
-
-                var stats = fs.statSync(filename);
-                var fileSizeInBytes = stats["size"];
-                if (fileSizeInBytes > 1024 * 30 * 1024) {
-                  this.handleMaxSize();
-                  throw new Error("附件超过最大限制");
-                }
-
-                const formData = new FormData();
-                formData.append("fileType", "pdf");
-                formData.append("file", fileNew);
-
-                return this.$http
-                  .post(
-                    "/api/branch_ecs_oe_admin/offlineExam/submitPaper?examRecordDataId=" +
-                      this.course.examRecordDataId,
-                    formData
-                  )
-                  .then(() => {
-                    this.handleSuccess();
-                  })
-                  .catch(() => {
-                    this.handleError();
-                  });
-              })
-              .catch((error) => {
-                console.log(error);
-                this.handleError();
-              });
-          });
-        return Promise.reject("图片另外路径上传");
-      }
-
-      return new Promise((resolve, reject) => {
-        if (this.course.offlineFileUrl) {
-          this.$Modal.confirm({
-            title: "已有作答附件,是否覆盖?",
-            onCancel: () => reject("离线考试,取消覆盖"),
-            onOk: () => resolve(),
-          });
-        } else {
-          resolve();
-        }
-      }).then(() => {
-        if (
-          file.type.includes("/pdf")
-          //  ||
-          // file.type.includes("/jpeg") ||
-          // file.type.includes("/jpg")
-        ) {
-          this.fileType = "pdf";
-        } else if (file.type.includes("/zip")) {
-          this.fileType = "zip";
-        }
-        this.file = file;
-        this.loadingStatus = true;
-        return new Promise((resolve, reject) =>
-          this.fileFormatCheck(file, resolve, reject)
-        );
-      });
-    },
-  },
-};
-</script>
-
-<style scoped>
-.list .ivu-upload-select {
-  width: 100%;
-}
-.preview-image {
-  max-width: 100vw;
-  max-height: 100vh;
-  margin: -16px;
-  object-fit: contain;
-}
-</style>

+ 22 - 22
src/features/OnlineExam/CheckComputer.vue

@@ -1,5 +1,5 @@
 <template>
-  <div style="max-width: 800px; margin: 30px auto;">
+  <div style="max-width: 800px; margin: 30px auto">
     <Steps :current="current" size="small">
       <Step title="网速"></Step>
       <Step title="时钟"></Step>
@@ -127,7 +127,7 @@
 
     <div v-show="current === 2" key="2" class="section">
       <div>
-        <div style="display: flex;">
+        <div style="display: flex">
           <video
             id="video"
             ref="video"
@@ -138,7 +138,7 @@
 
           <div
             v-if="camera.openCameraResolved && camera.openCameraStatus"
-            style="margin-left: 50px; margin-top: 100px;"
+            style="margin-left: 50px; margin-top: 100px"
           >
             <Button
               type="warning"
@@ -149,7 +149,7 @@
             >
               图像中不是电脑操作者本人
             </Button>
-            <div style="width: 30px; height: 30px;"></div>
+            <div style="width: 30px; height: 30px"></div>
             <Button
               type="primary"
               @click="
@@ -247,10 +247,10 @@
       v-show="current === 3"
       key="3"
       class="section"
-      style="text-align: center;"
+      style="text-align: center"
     >
       <div>
-        <div style="display: flex; margin-bottom: 30px;">
+        <div style="display: flex; margin-bottom: 30px">
           <audio
             src="https://ecs-static.qmth.com.cn/check-audio.mp3"
             controls
@@ -265,7 +265,7 @@
             "
           />
 
-          <div style="margin-left: 30px; display: flex;">
+          <div style="margin-left: 30px; display: flex">
             <Button
               type="warning"
               title="或者听不到声音"
@@ -276,7 +276,7 @@
             >
               不能播放声音
             </Button>
-            <div style="width: 30px; height: 30px;"></div>
+            <div style="width: 30px; height: 30px"></div>
             <Button
               type="primary"
               @click="
@@ -358,23 +358,23 @@
 
     <div v-show="current === 4" key="4" class="section">
       <div>
-        <div style="display: flex;">
+        <div style="display: flex">
           <div>
-            <div v-if="wechat.qrValue" style="display: flex;">
+            <div v-if="wechat.qrValue" style="display: flex">
               <qrcode
                 :value="wechat.qrValue"
                 :options="{ width: 200 }"
-                style="margin-left: -10px;"
+                style="margin-left: -10px"
               ></qrcode>
-              <div style="margin-top: 10px;">
-                <div style="font-size: 30px;">
-                  请使用<span style="font-weight: 900; color: #1e90ff;"
+              <div style="margin-top: 10px">
+                <div style="font-size: 30px">
+                  请使用<span style="font-weight: 900; color: #1e90ff"
                     >微信</span
                   >扫描二维码后,在微信小程序上录音,并上传文件。
                 </div>
                 <div
                   v-if="wechat.qrScanned"
-                  style="margin-top: 30px; font-size: 30px;"
+                  style="margin-top: 30px; font-size: 30px"
                 >
                   {{ wechat.studentAnswer ? "已上传" : "已扫描" }}
                   <Icon type="md-checkmark" />
@@ -387,7 +387,7 @@
 
         <div
           class="audio-answer audio-answer-line-height"
-          style="margin-top: 20px; text-align: left;"
+          style="margin-top: 20px; text-align: left"
         >
           <span class="audio-answer-line-height">上传文件:</span>
           <audio
@@ -400,7 +400,7 @@
           <span v-else class="audio-answer-line-height">未上传文件</span>
         </div>
 
-        <div style="margin-top: 30px; display: flex; margin-bottom: 30px;">
+        <div style="margin-top: 30px; display: flex; margin-bottom: 30px">
           <Button
             type="warning"
             title="扫码不成功"
@@ -411,7 +411,7 @@
           >
             不能正确扫描二维码
           </Button>
-          <div style="width: 30px; height: 30px;"></div>
+          <div style="width: 30px; height: 30px"></div>
           <Button
             type="warning"
             title="上传不成功"
@@ -576,7 +576,7 @@
         </table>
       </div>
 
-      <div style="color: red;">
+      <div style="color: red">
         <div v-if="!step1Status" key="a">
           检查网络是否连接,路由器是否正常工作。
         </div>
@@ -608,15 +608,15 @@
       </div>
     </div>
 
-    <div style="margin-top: 30px; text-align: center;">
+    <div style="margin-top: 30px; text-align: center">
       <Button type="primary" :disabled="current === 0" @click="previous">
         上一步
       </Button>
-      <div style="width: 30px; height: 1px; display: inline-block;"></div>
+      <div style="width: 30px; height: 1px; display: inline-block"></div>
       <Button type="primary" :disabled="current === 5" @click="next">
         下一步
       </Button>
-      <div style="width: 30px; height: 1px; display: inline-block;"></div>
+      <div style="width: 30px; height: 1px; display: inline-block"></div>
       <Button
         v-if="current === 5"
         key="xxx"

+ 2 - 2
src/features/OnlineExam/Examing/BooleanQuestionView.vue

@@ -19,7 +19,7 @@
         name="question"
         value="true"
         :checked="studentAnswer === 'true'"
-        style="margin-top: 3px; display: block;"
+        style="margin-top: 3px; display: block"
       />
       <span class="question-options">正确</span>
     </div>
@@ -32,7 +32,7 @@
         name="question"
         value="false"
         :checked="studentAnswer === 'false'"
-        style="margin-top: 3px; display: block;"
+        style="margin-top: 3px; display: block"
       />
       <span class="question-options">错误</span>
     </div>

+ 7 - 7
src/features/OnlineExam/Examing/ExamingEnd.vue

@@ -13,42 +13,42 @@
         <div
           v-if="!examResult && getResultTimes > 10"
           class="qm-big-text score-text"
-          style="font-size: 20px;"
+          style="font-size: 20px"
         >
           请稍后在待考列表中查看客观题得分。
         </div>
         <div v-if="examResult">
           <div v-if="!examResult.isWarn" class="qm-big-text score-text">
             客观题得分:
-            <span style="color: red;">{{ examResult.objectiveScore }}</span>
+            <span style="color: red">{{ examResult.objectiveScore }}</span>
           </div>
           <div v-if="examResult.isWarn" class="qm-big-text score-text">
             客观题得分: 成绩待审核
           </div>
           <h1
             v-if="showCheatingRemark && examResult.isWarn"
-            style="text-align: left;"
+            style="text-align: left"
           >
             违纪提示:
           </h1>
           <div
             v-if="showCheatingRemark && examResult.isWarn"
             class=""
-            style="text-align: left; padding-bottom: 20px;"
+            style="text-align: left; padding-bottom: 20px"
           >
             <p v-html="cheatingRemark"></p>
           </div>
         </div>
       </div>
-      <h1 style="text-align: left;">考后说明:</h1>
-      <div style="text-align: left; padding-bottom: 20px;">
+      <h1 style="text-align: left">考后说明:</h1>
+      <div style="text-align: left; padding-bottom: 20px">
         <p v-html="afterExamRemark"></p>
       </div>
 
       <router-link
         class="qm-primary-button"
         :to="backTo"
-        style="display: inline-block; width: 100%;"
+        style="display: inline-block; width: 100%"
         ondragstart="return false;"
       >
         返回主页

+ 12 - 16
src/features/OnlineExam/Examing/ExamingHome.vue

@@ -44,9 +44,7 @@
             justify-content: center;
           "
         >
-          <div>
-            正在打开摄像头...
-          </div>
+          <div>正在打开摄像头...</div>
         </div>
       </div>
     </div>
@@ -57,7 +55,7 @@
       width="800"
       :styles="{ top: '10px' }"
     >
-      <FaceId v-if="showFaceId" @closeFaceId="closeFaceId" />
+      <FaceId v-if="showFaceId" @close-faceid="closeFaceId" />
       <p slot="footer"></p>
     </Modal>
     <Modal
@@ -67,7 +65,7 @@
       width="800"
       :styles="{ top: '10px' }"
     >
-      <FaceMotion v-if="showFaceMotion" @closeFaceMotion="closeFaceMotion" />
+      <FaceMotion v-if="showFaceMotion" @close-face-motion="closeFaceMotion" />
       <p slot="footer"></p>
     </Modal>
     <FaceTracking v-if="faceEnable && startVideoAfterDelay && PRODUCTION" />
@@ -83,9 +81,7 @@
         position: absolute;
       "
     >
-      <h3 style="margin-top: 80px;">
-        请关闭远程桌面软件再进行考试!
-      </h3>
+      <h3 style="margin-top: 80px">请关闭远程桌面软件再进行考试!</h3>
       <i-button @click="checkRemoteApp">确认已关闭远程桌面软件</i-button>
     </div>
   </div>
@@ -128,6 +124,14 @@ export default {
     FaceMotion,
     FaceTracking,
   },
+  beforeRouteUpdate(from, to, next) {
+    window._hmt.push(["_trackEvent", "答题页面", "题目切换"]);
+    if (process.env.NODE_ENV === "development") {
+      console.log("beforeRouteUpdate from: " + this.$route.fullPath);
+    }
+    this.answerAllQuestions();
+    next();
+  },
   data() {
     return {
       showFaceId: false,
@@ -335,14 +339,6 @@ export default {
       }
     }
   },
-  beforeRouteUpdate(from, to, next) {
-    window._hmt.push(["_trackEvent", "答题页面", "题目切换"]);
-    if (process.env.NODE_ENV === "development") {
-      console.log("beforeRouteUpdate from: " + this.$route.fullPath);
-    }
-    this.answerAllQuestions();
-    next();
-  },
   beforeDestroy() {
     clearTimeout(this.timeoutTimeout);
     clearInterval(this.submitInterval);

+ 9 - 9
src/features/OnlineExam/Examing/FaceId.vue

@@ -1,14 +1,14 @@
 <template>
-  <div class="row" style="margin: 0;">
-    <div class="col-md-12 text-center" style="padding: 8px;">
-      <div style="font-size: 30px;">
+  <div class="row" style="margin: 0">
+    <div class="col-md-12 text-center" style="padding: 8px">
+      <div style="font-size: 30px">
         <span>指定动作检测</span>
         <span v-if="showIframe">({{ timeCount }})</span>
       </div>
       <div
         v-if="showIframe"
         class="text-center"
-        style="color: red; font-size: 16px;"
+        style="color: red; font-size: 16px"
       >
         (注意:请点击下方“开始比对”按钮并在60秒内完成指定动作检测,超时将退出考试)
       </div>
@@ -26,9 +26,9 @@
         v-show="!showIframe"
         width="100%"
         height="200px"
-        style="text-align: center; line-height: 100px; margin-top: 5px;"
+        style="text-align: center; line-height: 100px; margin-top: 5px"
       >
-        <div style="color: white; font-weight: bold; font-size: 20px;">
+        <div style="color: white; font-weight: bold; font-size: 20px">
           {{ redoBtnMsg }}
         </div>
         <button
@@ -45,7 +45,7 @@
         v-show="showIframe"
         id="myFrame"
         :preload="electronDir + 'manipulateFaceID.js'"
-        style="position: absolute; width: 100%; height: 710px;"
+        style="position: absolute; width: 100%; height: 710px"
       ></webview>
       <!-- <iframe
         src="https://www.baidu.com"
@@ -166,7 +166,7 @@ export default {
             this.faceTestEnd(receivedMsg);
             clearTimeout(this.faceIdTimeout);
             clearInterval(this.timeCountInterval);
-            this.$emit("closeFaceId");
+            this.$emit("close-faceid");
             // this.closeWS();
           })
           .catch(() => {
@@ -265,7 +265,7 @@ export default {
           this.faceTestEnd(receivedMsg);
           clearTimeout(this.faceIdTimeout);
           clearInterval(this.timeCountInterval);
-          this.$emit("closeFaceId");
+          this.$emit("close-faceid");
           // 无需关闭,在beforeDestory会关闭
           // this.closeWS();
         }

+ 7 - 11
src/features/OnlineExam/Examing/FaceMotion/FaceMotion.vue

@@ -1,10 +1,6 @@
 <template>
   <div class="page-container">
-    <div
-      id="video-container"
-      style="position: relative;"
-      class="page-container"
-    >
+    <div id="video-container" style="position: relative" class="page-container">
       <div v-if="shouldShowSections" class="instruction-tips above-video">
         <div
           class="instruction-animation"
@@ -16,10 +12,10 @@
           }"
           data-intro="停留的时间:每一次停留时长可能不一样。"
         >
-          请将脸部移入此区域,停留<span style="color: blue;">{{
+          请将脸部移入此区域,停留<span style="color: blue">{{
             currentStep.stay
           }}</span
-          >秒,并保持<span style="color: blue;">{{
+          >秒,并保持<span style="color: blue">{{
             shouldDetectExpression ? (currentStep.happy ? "笑容" : "严肃") : ""
           }}</span>
         </div>
@@ -37,7 +33,7 @@
             请调整脸部与摄像头的距离
           </div>
           <div v-else>
-            保持<span style="color: blue;">{{
+            保持<span style="color: blue">{{
               shouldDetectExpression
                 ? currentStep.happy
                   ? "笑容"
@@ -52,7 +48,7 @@
       <div
         v-if="isDetecting"
         class="instruction-total above-video"
-        style="z-index: 3;"
+        style="z-index: 3"
       >
         <div class="total-text" data-intro="请在规定的时间内完成。">
           {{ instructions.total >= 0 ? instructions.total : 0 }}
@@ -128,7 +124,7 @@
       <video
         id="inputVideo"
         class="detect-video"
-        style="transform: scaleX(-1);"
+        style="transform: scaleX(-1)"
         autoplay
         muted
         @loadedmetadata="onPlay"
@@ -362,7 +358,7 @@ export default {
       }
       const faceLiveResult = faceLiveResultData.data;
       console.log(faceLiveResult);
-      this.$emit("closeFaceMotion", faceLiveResult);
+      this.$emit("close-face-motion", faceLiveResult);
     },
     resetTest() {
       // this.isDetecting = true;

+ 2 - 0
src/features/OnlineExam/Examing/FillBlankQuestionView.vue

@@ -179,6 +179,8 @@ export default {
         order: this.examQuestion.order,
         studentAnswer: null,
       });
+      // FIXME
+      // eslint-disable-next-line
       this.examQuestion.studentAnswer = null;
       this.prepareData();
     },

+ 3 - 3
src/features/OnlineExam/Examing/MultipleQuestionView.vue

@@ -19,16 +19,16 @@
     >
       <div
         :class="studentAnswer.includes(option.oldIndex) && 'row-selected'"
-        style="display: flex;"
+        style="display: flex"
       >
         <input
           type="checkbox"
           name="question"
           value="option.oldIndex"
           :checked="studentAnswer && studentAnswer.includes(option.oldIndex)"
-          style="margin-top: 4px;"
+          style="margin-top: 4px"
         />
-        <span style="padding: 0 10px;">{{ optionName[index] }}: </span>
+        <span style="padding: 0 10px">{{ optionName[index] }}: </span>
         <div v-if="option.value" class="question-options">
           <question-body
             :question-body="option.value.body"

+ 1 - 1
src/features/OnlineExam/Examing/OverallProgress.vue

@@ -5,7 +5,7 @@
       :stroke-width="20"
       status="active"
       hide-info
-      style="color: black;"
+      style="color: black"
     >
     </i-progress>
     <span>{{ progress }}</span>

+ 4 - 4
src/features/OnlineExam/Examing/QuestionAudio.vue

@@ -1,5 +1,5 @@
 <template>
-  <span class="a-container" style="display: inline-flex; align-items: center;">
+  <span class="a-container" style="display: inline-flex; align-items: center">
     <span v-show="shouldShowAudio" @click.stop="play">
       <Button
         v-if="!playing"
@@ -15,17 +15,17 @@
         type="primary"
         shape="circle"
         icon="md-pause"
-        style="cursor: not-allowed;"
+        style="cursor: not-allowed"
         size="small"
         class="pause"
       ></Button>
     </span>
-    <span style="padding-left: 2px;">&nbsp;</span>
+    <span style="padding-left: 2px">&nbsp;</span>
     <span v-show="shouldShowAudio">
       {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
     </span>
 
-    <span v-if="!shouldShowAudio" style="color: blueviolet;">
+    <span v-if="!shouldShowAudio" style="color: blueviolet">
       音频下载中{{ downloadPercent }}%
     </span>
   </span>

+ 1 - 1
src/features/OnlineExam/Examing/QuestionContainer.vue

@@ -32,7 +32,7 @@
           </span>
           <div
             v-if="audioInPlay.has(item.getAttribute('data-name'))"
-            style="position: absolute; top: 0; right: 0; bottom: 0; left: 0;"
+            style="position: absolute; top: 0; right: 0; bottom: 0; left: 0"
           ></div>
         </div>
       </template>

+ 1 - 1
src/features/OnlineExam/Examing/QuestionNavView.vue

@@ -1,5 +1,5 @@
 <template>
-  <div style="padding-bottom: 10px;">
+  <div style="padding-bottom: 10px">
     <template v-if="paperStruct && examQuestionList">
       <div
         v-for="(struct, section) in paperStruct.defaultPaper.questionGroupList"

+ 1 - 1
src/features/OnlineExam/Examing/QuestionView.vue

@@ -24,7 +24,7 @@
             :key="examQuestion.questionId"
             :question-body="parentQuestionBody"
             :exam-question="examQuestion"
-            style="margin-bottom: 20px;"
+            style="margin-bottom: 20px"
           ></question-body>
           <!-- <div class="hr" /> -->
         </div>

+ 1 - 1
src/features/OnlineExam/Examing/QuestionViewSingle.vue

@@ -5,7 +5,7 @@
       :key="examQuestion.order"
       class="question-view"
     >
-      <div style="margin-bottom: -45px;">{{ examQuestion.groupOrder }}、</div>
+      <div style="margin-bottom: -45px">{{ examQuestion.groupOrder }}、</div>
       <template
         v-if="
           question &&

+ 3 - 3
src/features/OnlineExam/Examing/SingleQuestionView.vue

@@ -23,7 +23,7 @@
     >
       <div
         :class="studentAnswer === option.oldIndex && 'row-selected'"
-        style="display: flex;"
+        style="display: flex"
       >
         <div>
           <input
@@ -31,10 +31,10 @@
             name="question"
             :value="option.oldIndex"
             :checked="studentAnswer === option.oldIndex"
-            style="margin-top: 3px; display: block;"
+            style="margin-top: 3px; display: block"
           />
         </div>
-        <span style="padding: 0 10px;">{{ optionName[index] }}: </span>
+        <span style="padding: 0 10px">{{ optionName[index] }}: </span>
         <div v-if="option.value" class="question-options">
           <question-body
             :question-body="option.value.body"

+ 10 - 10
src/features/OnlineExam/Examing/TextQuestionView.vue

@@ -68,27 +68,27 @@
             max-width: 500px;
           "
         >
-          <div style="float: right; margin-right: 10px;">
+          <div style="float: right; margin-right: 10px">
             {{ answerWordCount }}
           </div>
         </div>
       </div>
       <div v-if="shouldFetchQrCode && isAudioAnswerType">
         <div>
-          <div v-if="qrValue" style="display: flex;">
+          <div v-if="qrValue" style="display: flex">
             <qrcode
               :value="qrValue"
               :options="{ width: 200 }"
-              style="margin-left: -10px;"
+              style="margin-left: -10px"
             ></qrcode>
-            <div style="margin-top: 10px;">
+            <div style="margin-top: 10px">
               <div>
-                请使用<span style="font-weight: 900; color: #1e90ff;">微信</span
+                请使用<span style="font-weight: 900; color: #1e90ff">微信</span
                 >扫描二维码后,在微信小程序上{{
                   isAudioAnswerType ? "录音" : "拍照"
                 }},并上传文件。
               </div>
-              <div v-if="qrScanned" style="margin-top: 30px; font-size: 30px;">
+              <div v-if="qrScanned" style="margin-top: 30px; font-size: 30px">
                 {{ examQuestion.studentAnswer ? "已上传" : "已扫描" }}
                 <Icon type="md-checkmark" />
               </div>
@@ -99,7 +99,7 @@
 
         <div
           class="audio-answer audio-answer-line-height"
-          style="margin-top: 20px;"
+          style="margin-top: 20px"
         >
           <span class="audio-answer-line-height">答案:</span>
           <audio
@@ -113,7 +113,7 @@
         </div>
       </div>
 
-      <div v-if="canAttachPhotos" style="padding-top: 1px;">
+      <div v-if="canAttachPhotos" style="padding-top: 1px">
         <UploadPhotos
           :default-list="
             photoAnswers.map((v) => {
@@ -122,13 +122,13 @@
           "
           :qr-value="qrValue"
           :exam-question="examQuestion"
-          style="margin-top: 20px; width: 350px;"
+          style="margin-top: 20px; width: 350px"
           @on-photo-added="photoAdded"
           @on-photo-removed="photoRemoved"
           @on-photos-reseted="photosReseted"
         />
       </div>
-      <div class="reset" style="padding-top: 20px;">
+      <div class="reset" style="padding-top: 20px">
         <!-- <i-button type="warning" size="large" @click="resetAnswer">
           重置答案
         </i-button> -->

+ 9 - 11
src/features/OnlineExam/Examing/UploadPhotos.vue

@@ -21,7 +21,7 @@
           <Icon
             type="ios-trash-outline"
             size="30"
-            style="position: absolute; top: 0px;"
+            style="position: absolute; top: 0px"
             @click.native="handleRemove(item)"
           ></Icon>
         </div>
@@ -36,7 +36,7 @@
     </draggable>
 
     <div>
-      点击<span style="color: blue; font-size: 24px;">+</span
+      点击<span style="color: blue; font-size: 24px">+</span
       >上传图片(最多上传6张图片)
     </div>
 
@@ -50,7 +50,7 @@
       width="660"
     >
       <div>
-        <div v-if="qrValue" style="display: flex;">
+        <div v-if="qrValue" style="display: flex">
           <qrcode
             :value="qrValue"
             :options="{ width: 200 }"
@@ -59,13 +59,13 @@
               filter: totalList.length >= 6 ? 'blur(10px)' : 'none',
             }"
           ></qrcode>
-          <div style="font-size: 24px; margin-top: 10px;">
+          <div style="font-size: 24px; margin-top: 10px">
             <div>
-              请使用<span style="font-weight: 900; color: #1e90ff;">微信</span
+              请使用<span style="font-weight: 900; color: #1e90ff">微信</span
               >扫描二维码后,在微信小程序上拍照,并上传文件。<br />
               上传期间,请勿关闭二维码。
             </div>
-            <div v-if="qrScanned" style="margin-top: 30px; font-size: 30px;">
+            <div v-if="qrScanned" style="margin-top: 30px; font-size: 30px">
               {{ uploaded ? "已上传" : "已扫描" }}
               <Icon type="md-checkmark" />
             </div>
@@ -94,17 +94,15 @@
               <Icon
                 type="ios-trash-outline"
                 size="30"
-                style="position: absolute; top: 0px;"
+                style="position: absolute; top: 0px"
                 @click.native="handleRemoveTotal(item)"
               ></Icon>
             </div>
           </div>
         </draggable>
 
-        <div v-if="totalList.length > 6">
-          * 图片上传最多只支持6张
-        </div>
-        <div style="display: flex; justify-content: center;">
+        <div v-if="totalList.length > 6">* 图片上传最多只支持6张</div>
+        <div style="display: flex; justify-content: center">
           <Button type="primary" size="large" @click="modalCloseClicked">
             确认
           </Button>

+ 3 - 7
src/features/OnlineExam/OnlineExamFaceCheckModal.vue

@@ -8,11 +8,7 @@
   >
     <div
       slot="header"
-      style="
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-      "
+      style="display: flex; justify-content: space-between; align-items: center"
     >
       <div class="qm-title-text">人脸识别</div>
       <Icon
@@ -34,7 +30,7 @@
         <!-- <img :src="userPhoto" width="200px" height="300px" alt="底照" /> -->
         <div
           class="avatar-info"
-          style="text-align: center; margin-top: 260px; color: white;"
+          style="text-align: center; margin-top: 260px; color: white"
         >
           <span
             style="
@@ -60,7 +56,7 @@
         </FaceRecognition>
       </div>
       <div class="verify-desc qm-primary-text">
-        <h4 class="qm-big-text" style="font-weight: bold;">操作提示:</h4>
+        <h4 class="qm-big-text" style="font-weight: bold">操作提示:</h4>
         <p>1.请先确保摄像头设备已连接并能正常工作;</p>
         <p>2.请保持光源充足,不要逆光操作;</p>
         <p>

+ 11 - 11
src/features/OnlineExam/OnlineExamHome.vue

@@ -32,6 +32,17 @@ export default {
     "ecs-online-list": EcsOnlineList,
     PhoneVerifyForDD,
   },
+  beforeRouteEnter(to, from, next) {
+    next((vm) => {
+      vm.previousUrl = from.path;
+      if (
+        from.path.includes("/online-homework") ||
+        from.path.includes("/online-exam")
+      ) {
+        vm.getData();
+      }
+    });
+  },
   props: {
     examType: {
       type: String,
@@ -56,17 +67,6 @@ export default {
       ).name;
     },
   },
-  beforeRouteEnter(to, from, next) {
-    next((vm) => {
-      vm.previousUrl = from.path;
-      if (
-        from.path.includes("/online-homework") ||
-        from.path.includes("/online-exam")
-      ) {
-        vm.getData();
-      }
-    });
-  },
   watch: {
     menus() {
       if (this.menus[0]) {

+ 3 - 3
src/features/OnlineExam/OnlineExamOverview.vue

@@ -2,14 +2,14 @@
   <div v-if="startInfo && paperStruct" id="exam-overview" class="container">
     <div class="instructions">
       <h1 class="">考试说明</h1>
-      <div style="text-align: left; padding-bottom: 20px;">
+      <div style="text-align: left; padding-bottom: 20px">
         <p v-html="beforeExamRemark"></p>
         <!-- <p>{{"测试".repeat(500)}}</p> -->
       </div>
       <i-button
         class="qm-primary-button"
         :disabled="isForceRead"
-        style="display: inline-block; width: 100%;"
+        style="display: inline-block; width: 100%"
         @click="goToPaper"
       >
         接受以上条款,开始考试(倒计时:
@@ -39,7 +39,7 @@
         </li>
       </ul>
       <div>
-        <img style="width: 100%; padding-top: 40px;" src="./good-wish.png" />
+        <img style="width: 100%; padding-top: 40px" src="./good-wish.png" />
       </div>
     </div>
   </div>

+ 4 - 8
src/features/OnlineExam/PhoneVerifyForDD.vue

@@ -7,11 +7,7 @@
     :footer-hide="true"
   >
     <div
-      style="
-        display: grid;
-        grid-template-rows: 40px 40px 40px;
-        font-size: 20px;
-      "
+      style="display: grid; grid-template-rows: 40px 40px 40px; font-size: 20px"
     >
       <p>
         预留手机号: &nbsp;&nbsp;{{
@@ -29,14 +25,14 @@
       </p>
       <div>
         <i-button
-          style="margin: 0; margin-right: 5px;"
+          style="margin: 0; margin-right: 5px"
           class="qm-primary-button"
           :disabled="remainTime > 0"
           @click="getCode"
           >{{ btnText }} {{ remainTime > 0 ? "(" + remainTime + "秒)" : "" }}
         </i-button>
         <i-button
-          style="margin: 0; margin-right: 5px;"
+          style="margin: 0; margin-right: 5px"
           class="qm-primary-button"
           :disabled="!code"
           @click="verify"
@@ -44,7 +40,7 @@
           验证
         </i-button>
         <i-button
-          style="margin: 0; margin-right: 5px;"
+          style="margin: 0; margin-right: 5px"
           class="qm-primary-button"
           @click="() => logout('?LogoutReason=验证预留手机号')"
         >

+ 2 - 2
src/features/OnlinePractice/OnlinePracticeHome.vue

@@ -14,11 +14,11 @@
     </Breadcrumb>
 
     <div class="home">
-      <div style="text-align: left; margin-bottom: 20px;">
+      <div style="text-align: left; margin-bottom: 20px">
         选择考试批次:
         <Select
           v-model="examId"
-          style="width: 200px;"
+          style="width: 200px"
           filterable
           @on-change="fetchList"
         >

+ 1 - 1
src/features/OnlinePractice/OnlinePracticeRecordDetail.vue

@@ -62,7 +62,7 @@
 
         <div class="info-text">
           <h4 class="font-thin text-primary-lt m-t">报告提示:</h4>
-          <div class="scroll-y wrapper-sm" style="min-height: 80px;">
+          <div class="scroll-y wrapper-sm" style="min-height: 80px">
             <p class="m-b-sm">
               1、若本练习卷中包含部分主观题型,则报告统计数据仅供参考,因为部分题型需考生根据参考答案判断正确和错误,报告仅对可统计的题型进行统计。
             </p>

+ 2 - 2
src/features/OnlinePractice/OnlinePracticeRecordList.vue

@@ -52,7 +52,7 @@
               <td>错误</td>
               <td>未答</td>
               <td>正确率</td>
-              <td style="max-width: 200px;">操作</td>
+              <td style="max-width: 200px">操作</td>
             </tr>
 
             <tr v-for="record in recordList" :key="record.examId">
@@ -65,7 +65,7 @@
               <td>{{ record.failQuestionNum }}</td>
               <td>{{ record.notAnsweredCount }}</td>
               <td>{{ record.objectiveAccuracy }}%</td>
-              <td style="min-width: 120px;">
+              <td style="min-width: 120px">
                 <i-button
                   class="qm-primary-button"
                   @click="() => enterPracticeRecordDetail(record)"

+ 2 - 2
src/features/Password/Password.vue

@@ -14,7 +14,7 @@
     </i-breadcrumb>
 
     <div class="password-container">
-      <i-form ref="form" :model="form" :rules="rules" style="width: 320px;">
+      <i-form ref="form" :model="form" :rules="rules" style="width: 320px">
         <i-form-item label="" prop="oldPassword">
           <i-input
             v-model="form.oldPassword"
@@ -36,7 +36,7 @@
             placeholder="请再次输入新密码"
           ></i-input>
         </i-form-item>
-        <i-form-item style="text-align: left;">
+        <i-form-item style="text-align: left">
           <i-button size="large" class="qm-primary-button" @click="changePwd">
             保存
           </i-button>

+ 2 - 2
src/features/SiteMessage/SiteMessageDetail.vue

@@ -13,8 +13,8 @@
       <BreadcrumbItem>{{ locationTitle }}</BreadcrumbItem>
     </i-breadcrumb>
 
-    <div style="display: flex; flex-direction: row-reverse;">
-      <div style="margin-top: 20px; margin-right: 20px;">
+    <div style="display: flex; flex-direction: row-reverse">
+      <div style="margin-top: 20px; margin-right: 20px">
         <i-button>
           <div class="back-block" @click="goBack">
             <img src="./svgs/back.svg" /> &nbsp;返回列表

+ 3 - 3
src/features/SiteMessage/SiteMessageHome.vue

@@ -14,7 +14,7 @@
     </i-breadcrumb>
 
     <div class="home">
-      <div style="font-size: 18px; font-weight: 500; color: #222c32;">
+      <div style="font-size: 18px; font-weight: 500; color: #222c32">
         公告通知
       </div>
       <i-button>
@@ -24,7 +24,7 @@
       </i-button>
     </div>
     <div class="site-message-container">
-      <div style="text-align: left; color: #999; margin-bottom: 5px;">
+      <div style="text-align: left; color: #999; margin-bottom: 5px">
         *仅保留近1年的公告通知。
       </div>
       <Table
@@ -37,7 +37,7 @@
         :total="siteMessages.length"
         :page-size="pageSize"
         :current.sync="page"
-        style="text-align: right; margin-top: 10px;"
+        style="text-align: right; margin-top: 10px"
       />
     </div>
   </main-layout>

+ 1 - 1
src/main.js

@@ -29,7 +29,7 @@ Vue.use(axiosPlugin);
 
 Vue.config.productionTip = process.env.NODE_ENV !== "production";
 
-Vue.component("main-layout", MainLayout);
+Vue.component("MainLayout", MainLayout);
 
 if (process.env.NODE_ENV !== "production") {
   // 测试vue cli打包的环境变量

+ 24 - 24
src/plugins/vueLifecylceLogs.js

@@ -100,30 +100,6 @@ function getParentNumber(that) {
   return parentNumber;
 }
 Vue.mixin({
-  created() {
-    const parentNumber = getParentNumber(this);
-    if (!ignoreComponents.includes(this.$options.name))
-      console.log(
-        "--".repeat(parentNumber) + `${this.$options.name} %c created`,
-        "color: green"
-      );
-  },
-  mounted() {
-    const parentNumber = getParentNumber(this);
-    if (!ignoreComponents.includes(this.$options.name))
-      console.log(
-        "--".repeat(parentNumber) + `${this.$options.name} %c mounted`,
-        "color: green"
-      );
-  },
-  updated() {
-    const parentNumber = getParentNumber(this);
-    if (!ignoreComponents.includes(this.$options.name))
-      console.log(
-        "--".repeat(parentNumber) + `${this.$options.name} %c updated`,
-        "color: #0000aa"
-      );
-  },
   beforeRouteEnter(to, from, next) {
     console.log(
       "%c " + from.fullPath + " --> " + to.fullPath + " %c beforeRouteEnter",
@@ -155,6 +131,30 @@ Vue.mixin({
     );
     next();
   },
+  created() {
+    const parentNumber = getParentNumber(this);
+    if (!ignoreComponents.includes(this.$options.name))
+      console.log(
+        "--".repeat(parentNumber) + `${this.$options.name} %c created`,
+        "color: green"
+      );
+  },
+  mounted() {
+    const parentNumber = getParentNumber(this);
+    if (!ignoreComponents.includes(this.$options.name))
+      console.log(
+        "--".repeat(parentNumber) + `${this.$options.name} %c mounted`,
+        "color: green"
+      );
+  },
+  updated() {
+    const parentNumber = getParentNumber(this);
+    if (!ignoreComponents.includes(this.$options.name))
+      console.log(
+        "--".repeat(parentNumber) + `${this.$options.name} %c updated`,
+        "color: #0000aa"
+      );
+  },
   beforeDestroy() {
     const parentNumber = getParentNumber(this);
     if (!ignoreComponents.includes(this.$options.name))

+ 13 - 0
src/router.js

@@ -17,6 +17,19 @@ import SiteMessageDetail from "./features/SiteMessage/SiteMessageDetail.vue";
 import Password from "./features/Password/Password.vue";
 import CheckComputer from "./features/OnlineExam/CheckComputer.vue";
 
+// ignore NavigationDuplicated. https://github.com/vuejs/vue-router/issues/2881
+const originalPush = Router.prototype.push;
+Router.prototype.push = function push(location, onResolve, onReject) {
+  if (onResolve || onReject)
+    return originalPush.call(this, location, onResolve, onReject);
+  try {
+    return originalPush.call(this, location).catch((err) => err);
+  } catch (error) {
+    console.log(error);
+  }
+};
+// end ignore
+
 Vue.use(Router);
 let router = new Router({
   mode: "history",

+ 1 - 1
tests/vue/child.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <button @click="$emit('countChange', counte++)">emit value</button>
+    <button @click="$emit('count-change', counte++)">emit value</button>
     <div>from parent: {{ passToChild }}</div>
     <div>from parent to computed: {{ computedFromProps }}</div>
     <div>from parent to data: {{ dataFromProps }}</div>

+ 1 - 1
tests/vue/event.vue

@@ -3,7 +3,7 @@
     test - {{ name }}
 
     <div>
-      <Child @countChange="childListener" />
+      <Child @count-change="childListener" />
       <div>{{ globalCount }}</div>
     </div>
 

+ 1 - 1
tests/vue/useMyinput.vue

@@ -1,5 +1,5 @@
 <template>
-  <div style="margin-top: 200px;">
+  <div style="margin-top: 200px">
     myinput: <myinput v-model="val" @focus="myfocus" />
     <div>{{ val }}</div>
     parent: <input v-model="val" />