瀏覽代碼

命题管理接口调试

zhangjie 4 年之前
父節點
當前提交
4ee9c80ceb
共有 65 個文件被更改,包括 1585 次插入581 次删除
  1. 1 0
      .env
  2. 6 11
      card/api.js
  3. 12 19
      card/assets/styles/card-preview.scss
  4. 1 1
      card/components/PagePropEdit.vue
  5. 2 2
      card/components/PaperParams.vue
  6. 17 30
      card/elements/card-head/CardHead.vue
  7. 1 1
      card/enumerate.js
  8. 54 90
      card/views/CardDesign.vue
  9. 30 62
      card/views/CardPreview.vue
  10. 5 0
      src/assets/styles/element-ui-costom.scss
  11. 11 6
      src/assets/styles/home.scss
  12. 7 0
      src/assets/styles/login.scss
  13. 1 1
      src/assets/styles/pages.scss
  14. 18 13
      src/components/UploadButton.vue
  15. 3 3
      src/components/UploadFileDialog.vue
  16. 20 20
      src/components/UploadFileView.vue
  17. 1 1
      src/components/ViewFooter.vue
  18. 2 1
      src/components/base/CardRuleSelect.vue
  19. 3 3
      src/components/base/CourseSelect.vue
  20. 11 2
      src/components/base/QuestionTeacherSelect.vue
  21. 75 0
      src/components/base/QuestionTeacherUserSelect.vue
  22. 64 0
      src/components/base/SchoolSelect.vue
  23. 16 0
      src/constants/app.js
  24. 33 9
      src/constants/enumerate.js
  25. 31 0
      src/constants/navs.js
  26. 24 24
      src/main.js
  27. 3 0
      src/modules/base/api.js
  28. 3 3
      src/modules/base/components/ModifyMenu.vue
  29. 10 1
      src/modules/base/components/ModifyRole.vue
  30. 7 4
      src/modules/base/components/ModifyTemplate.vue
  31. 8 2
      src/modules/base/components/ModifyUser.vue
  32. 3 3
      src/modules/base/components/ResetPwd.vue
  33. 5 5
      src/modules/base/views/MenuManage.vue
  34. 14 5
      src/modules/base/views/UserManage.vue
  35. 3 0
      src/modules/card/api.js
  36. 9 0
      src/modules/customer/api.js
  37. 9 0
      src/modules/customer/router.js
  38. 277 0
      src/modules/customer/views/CustomerCard.vue
  39. 35 17
      src/modules/exam/api.js
  40. 78 57
      src/modules/exam/components/ApplyContent.vue
  41. 84 45
      src/modules/exam/components/CardOptionDialog.vue
  42. 14 6
      src/modules/exam/components/ModifyExamTask.vue
  43. 99 4
      src/modules/exam/components/ModifyTaskApply.vue
  44. 13 7
      src/modules/exam/components/UploadPaperDialog.vue
  45. 2 2
      src/modules/exam/components/WaitTaskAudit.vue
  46. 6 0
      src/modules/exam/router.js
  47. 25 0
      src/modules/exam/store.js
  48. 258 0
      src/modules/exam/views/DataTaskManage.vue
  49. 12 5
      src/modules/exam/views/ExamTaskManage.vue
  50. 4 6
      src/modules/exam/views/TaskApplyManage.vue
  51. 5 2
      src/modules/exam/views/TaskPaperManage.vue
  52. 9 3
      src/modules/exam/views/TaskReviewManage.vue
  53. 4 6
      src/modules/exam/views/WaitTask.vue
  54. 8 2
      src/modules/login/api.js
  55. 40 16
      src/modules/login/views/Login.vue
  56. 8 25
      src/modules/login/views/SelectSchool.vue
  57. 13 13
      src/modules/print/api.js
  58. 5 1
      src/modules/print/views/BusinessDataExport.vue
  59. 8 12
      src/plugins/axios.js
  60. 14 9
      src/plugins/crypto.js
  61. 13 1
      src/plugins/filters.js
  62. 5 1
      src/plugins/globalVuePlugins.js
  63. 2 1
      src/router.js
  64. 3 1
      src/store.js
  65. 18 17
      src/views/Home.vue

+ 1 - 0
.env

@@ -3,3 +3,4 @@ VUE_APP_DOMAIN=
 VUE_APP_TIMEOUT=600000
 VUE_APP_PAGE_SIZE=10
 VUE_APP_AUTH_TIMEOUT=72000000
+VUE_APP_SELF_DEFINE_DOMAIN=true

+ 6 - 11
card/api.js

@@ -1,7 +1,7 @@
-import { $get, $post } from "@/plugins/axios";
+import { $postParam, $post } from "@/plugins/axios";
 
 export const cardConfigInfos = id => {
-  return $get("/api/admin/basic/card_rule/get_one", { id });
+  return $postParam("/api/admin/basic/card_rule/get_one", { id });
 
   // return Promise.resolve({
   //   pageSize: "A3",
@@ -45,15 +45,10 @@ export const cardConfigInfos = id => {
   //     "注意:必须使用黑色字迹签字笔书写;在答题区内作答,超出以下黑色矩形边框限定区域的答案无效。"
   // });
 };
-export const cardDetailEdit = cardId => {
-  return $get("/api/admin/print/card/card/detailEdit", { cardId });
-};
-export const cardTempDetail = cardId => {
-  return $get("/api/admin/print/card/card/preView", { cardId });
+export const cardDetail = cardId => {
+  return $postParam("/api/admin/exam/card/get_one", { cardId });
 };
+
 export const saveCard = datas => {
-  return $post("/api/admin/print/card/card/add", datas);
-};
-export const submitCard = datas => {
-  return $post("/api/admin/print/card/submit", datas);
+  return $post("/api/admin/exam/card/save", datas);
 };

+ 12 - 19
card/assets/styles/card-preview.scss

@@ -376,33 +376,26 @@
     }
   }
   &-subtitle {
-    height: 23px;
+    height: 45px;
     font-family: $--font-family;
     font-size: 14px;
     font-weight: bold;
-    .el-input__inner {
-      line-height: 23px;
-      height: 23px;
-    }
-    > p {
-      padding: 0 10px;
-      line-height: 23px;
-      overflow: hidden;
-    }
-  }
-  &-title-desc {
-    height: 22px;
-    font-family: $--font-family;
-    font-size: 14px;
-    font-weight: bold;
-    .el-input__inner {
+    overflow: hidden;
+    textarea {
       line-height: 22px;
-      height: 22px;
+      height: 45px;
+      padding: 0 10px;
+      text-align: center;
+      border-radius: 0;
+      border: 0;
+      background-color: transparent;
+      box-shadow: 0 0 1px #ccc;
+      color: #000;
     }
     > p {
       padding: 0 10px;
       line-height: 22px;
-      overflow: hidden;
+      white-space: pre;
     }
   }
   &-body {

+ 1 - 1
card/components/PagePropEdit.vue

@@ -50,7 +50,7 @@
         >
       </el-form-item>
       <el-form-item label="大题数">
-        <ul class="topicno-list">
+        <ul class="topicno-list" v-if="topicSeries.length">
           <li>{{ topicSeries.length }}</li>
         </ul>
       </el-form-item>

+ 2 - 2
card/components/PaperParams.vue

@@ -336,9 +336,9 @@ export default {
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });
     },
-    uploadSuccess(response) {
+    uploadSuccess(data) {
       this.$message.success("上传成功!");
-      this.subjectiveAttachmentId = response.data.id;
+      this.subjectiveAttachmentId = data.id;
     },
     // dialog
     cancel() {

+ 17 - 30
card/elements/card-head/CardHead.vue

@@ -1,39 +1,32 @@
 <template>
   <div :class="classes">
     <div class="card-head-top">
+      <!-- 高度变化之后会印象内容排版,先固定高度 -->
       <div class="card-head-title">
         <el-input
-          placeholder="请输入主标题"
+          v-if="!preview && !data.isSimple"
+          id="cardTitleInput"
+          v-model="cardTitle"
           size="small"
+          placeholder="请输入题卡标题"
           @blur="nameChange"
-          v-model="cardTitle"
-          id="cardTitleInput"
-          v-if="!preview && !data.isSimple"
         >
         </el-input>
-        <h1 v-else>{{ data.schoolName }}</h1>
+        <h1 v-else>{{ data.cardTitle }}</h1>
       </div>
       <div class="card-head-subtitle">
         <el-input
-          placeholder="请输入题卡标题"
-          @blur="nameChange"
-          v-model="cardName"
-          id="cardNameInput"
           v-if="!preview && !data.isSimple"
-        >
-        </el-input>
-        <p v-else>{{ data.cardName }}</p>
-      </div>
-      <div class="card-head-title-desc">
-        <el-input
-          placeholder="请输入内容"
+          id="cardDescInput"
+          v-model="cardDesc"
+          type="textarea"
+          resize="none"
+          :rows="2"
+          placeholder="请输入题卡描述信息"
           @blur="nameChange"
-          v-model="cardTitleDesc"
-          id="cardTileDescInput"
-          v-if="!preview && !data.isSimple"
         >
         </el-input>
-        <p v-else>{{ data.cardTitleDesc }}</p>
+        <p v-else>{{ data.cardDesc }}</p>
       </div>
     </div>
 
@@ -129,9 +122,8 @@ export default {
   },
   data() {
     return {
-      cardName: this.data.cardName,
-      cardTitle: this.data.schoolName,
-      cardTitleDesc: this.data.cardTitleDesc
+      cardTitle: this.data.cardTitle,
+      cardDesc: this.data.cardDesc
     };
   },
   computed: {
@@ -156,17 +148,12 @@ export default {
       return !noDynamic;
     }
   },
-  // created() {
-  //   this.initCardTitle();
-  // },
   methods: {
     ...mapMutations("card", ["setCardConfig"]),
-    // initCardTitle() {},
     nameChange() {
       this.setCardConfig({
-        cardName: this.cardName,
-        schoolName: this.cardTitle,
-        cardTitleDesc: this.cardTitleDesc
+        cardTitle: this.cardTitle,
+        cardDesc: this.cardDesc
       });
     }
   }

+ 1 - 1
card/enumerate.js

@@ -1,4 +1,4 @@
-export const CARD_VERSION = "1.0.0";
+export const CARD_VERSION = "2.0.0";
 
 export const EXAM_NUMBER_STYLE = {
   PRINT: "印刷条码",

+ 54 - 90
card/views/CardDesign.vue

@@ -2,7 +2,7 @@
   <div class="card-design">
     <div class="design-top">
       <div class="design-top-logo">
-        <h1>答题卡制作</h1>
+        <h1><i class="icon icon-back" @click="toExit"></i>答题卡制作</h1>
       </div>
       <!-- <div class="design-top-info">
         <div class="info-help"><i class="icon icon-help"></i>帮助</div>
@@ -245,13 +245,7 @@
 
 <script>
 import { mapState, mapMutations, mapActions } from "vuex";
-import {
-  cardConfigInfos,
-  cardDetailEdit,
-  cardTempDetail,
-  saveCard,
-  submitCard
-} from "../api";
+import { cardConfigInfos, cardDetail, saveCard } from "../api";
 import {
   getElementModel,
   getCardHeadModel,
@@ -287,8 +281,14 @@ export default {
   data() {
     return {
       cardId: this.$route.params.cardId || this.$ls.get("cardId"),
-      cardDetailId: this.$ls.get("cardDetailId"),
-      prepareTcPCard: this.$ls.get("prepareTcPCard", {}),
+      prepareTcPCard: this.$ls.get("prepareTcPCard", {
+        examTaskId: "",
+        courseCode: "",
+        courseName: "",
+        makeMethod: "SELF",
+        cardRuleId: "",
+        paperType: ""
+      }),
       ELEMENT_LIST,
       TOPIC_LIST,
       topicList: [],
@@ -320,7 +320,7 @@ export default {
     }
   },
   mounted() {
-    if (!this.prepareTcPCard.examTaskId) {
+    if (!this.prepareTcPCard.examTaskId && !this.isEdit) {
       this.$message.error("找不到命题任务,请退出题卡制作!");
       return;
     }
@@ -350,24 +350,21 @@ export default {
       "initTopicsFromPages"
     ]),
     async initCard() {
-      await this.getCardConfig();
       if (this.isEdit) {
-        this.getCardTempDetail();
+        await this.getCardTempDetail();
       } else {
+        await this.getCardConfig();
         this.initPageData();
       }
       this.addWatch();
     },
     async getCardTempDetail() {
-      const detData = await cardDetailEdit(this.cardId);
-      const tempData = await cardTempDetail(this.cardId);
+      const detData = await cardDetail(this.cardId);
       // this.canSave = !detData.operateStatus;
-      // this.prepareTcPCard = Object.assign(this.prepareTcPCard, detData);
 
       // 可能存在题卡内容没有记录的情况
-      if (tempData) {
-        const cont = JSON.parse(tempData.content);
-        this.cardDetailId = tempData.id;
+      if (detData.content) {
+        const cont = JSON.parse(detData.content);
         this.setPages(cont.pages);
         this.setCardConfig(cont.cardConfig);
         this.setPaperParams(cont.paperParams);
@@ -375,11 +372,11 @@ export default {
         this.resetTopicSeries();
         this.setCurPage(0);
       } else {
+        await this.getCardConfig();
         // 没有题卡内容时,直接创建新的内容
-        this.setCardConfig({
-          cardName: detData.title,
-          aOrB: detData.enablePaperType.split(",").length > 1
-        });
+        let mod = { aOrB: detData.paperType.split(",").length > 1 };
+        if (detData.makeMethod === "CUST") mod.cardTitle = detData.title;
+        this.setCardConfig(mod);
         this.initPageData();
       }
     },
@@ -405,12 +402,15 @@ export default {
           columnNumber: 2,
           columnGap: 20,
           showForbidArea: true,
-          cardName: ""
+          cardDesc: ""
         }
       };
       config.aOrB = this.prepareTcPCard["paperType"]
         ? this.prepareTcPCard.paperType.split(",").length > 1
-        : null;
+        : false;
+      config.requiredFields = JSON.parse(config.requiredFields);
+      config.extendFields = JSON.parse(config.extendFields);
+      config.cardTitle = config.titleRule;
       this.setCardConfig(config);
     },
     addNewTopic(item) {
@@ -477,47 +477,15 @@ export default {
       this.setPaperParams(paperParams);
     },
     // save
-    getCardData(contentTemp = "", model = "") {
-      const multiEnablePaperType =
-        this.prepareTcPCard["paperType"] &&
-        this.prepareTcPCard["paperType"].split(",").length > 1
-          ? this.prepareTcPCard["paperType"]
-          : "";
-      const tcPCard = this.$objAssign(
-        {
-          examId: "",
-          enablePaperType: "A",
-          courseName: "",
-          courseCode: "",
-          cardSource: "",
-          title: "",
-          id: this.cardId
-        },
-        {
-          ...this.prepareTcPCard,
-          title: this.cardConfig.cardName,
-          enablePaperType: this.cardConfig.aOrB
-            ? multiEnablePaperType || "A,B"
-            : "A"
-        }
-      );
-
+    getCardData(htmlContent = "", model = "") {
       let data = {
-        tcPCard,
-        tcPCardDetail: {
-          content: model,
-          subjectiveAttachmentId:
-            this.paperParams["subjectiveAttachmentId"] || "",
-          contentTemp
-        }
+        title: this.cardConfig.cardTitle,
+        content: model,
+        htmlContent,
+        type: "CUSTOM",
+        ...this.prepareTcPCard
       };
-      if (this.cardDetailId) data.tcPCardDetail.id = this.cardDetailId;
-
-      if (this.prepareTcPCard.taskId && this.prepareTcPCard.cardSource === "1")
-        data.tcPExamTaskDetail = {
-          ...this.prepareTcPCard,
-          cardId: this.cardId
-        };
+      if (this.cardId) data.id = this.cardId;
       return data;
     },
     checkElementCovered() {
@@ -534,19 +502,19 @@ export default {
       return elements.length;
     },
     checkCardValid() {
-      if (!this.cardConfig.schoolName) {
-        this.$message.error("标题不能为空!");
+      if (!this.cardConfig.cardTitle) {
+        this.$message.error("题卡标题不能为空!");
         this.setCurPageNo(0);
         setTimeout(() => {
           document.getElementById("cardTitleInput").focus();
         });
         return false;
       }
-      if (!this.cardConfig.cardName) {
-        this.$message.error("题卡标题不能为空!");
+      if (!this.cardConfig.cardDesc) {
+        this.$message.error("题卡描述信息不能为空!");
         this.setCurPage(0);
         setTimeout(() => {
-          document.getElementById("cardNameInput").focus();
+          document.getElementById("cardDescInput").focus();
         });
         return false;
       }
@@ -570,11 +538,10 @@ export default {
     },
     async save() {
       if (!this.checkCardValid()) return;
-
-      const result = await saveCard(this.getCardData("", this.getModel()));
-      this.cardDetailId = result.cardDetailId;
-      this.cardId = result.cardId;
-      this.$ls.set("cardDetailId", this.cardDetailId);
+      let datas = this.getCardData("", this.getModel());
+      datas.status = "STAGE";
+      const result = await saveCard(datas);
+      this.cardId = result;
       this.$ls.set("cardId", this.cardId);
       return true;
     },
@@ -582,13 +549,6 @@ export default {
       const result = await this.save();
       if (result) this.$message.success("保存成功!");
     },
-    // toSave() {
-    //   // console.log(this.getCardData());
-    //   this.canSave = true;
-    //   setTimeout(() => {
-    //     this.canSave = false;
-    //   }, 500);
-    // },
     toSubmit() {
       if (this.isSubmit) return;
 
@@ -606,25 +566,30 @@ export default {
             paperParams: this.paperParams
           };
           this.isSubmit = true;
-          this.cardPreviewUrl = `/#/card/preview/${this.cardId}/frame`;
+          const { href } = this.$router.resolve({
+            name: "CardPreview",
+            params: {
+              cardId: 1,
+              viewType: "frame"
+            }
+          });
+          this.cardPreviewUrl = href;
         })
         .catch(() => {});
     },
     registWindowSubmit() {
-      window.submitCardTemp = async (cardContentTemp, model) => {
-        const data = this.getCardData(cardContentTemp, model);
-        const result = await submitCard(data).catch(() => {});
+      window.submitCardTemp = async (htmlContent, model) => {
+        const datas = this.getCardData(htmlContent, model);
+        datas.status = "SUBMIT";
+        const result = await saveCard(datas).catch(() => {});
         this.cardPreviewUrl = "";
         this.isSubmit = false;
         window.cardData = null;
         if (result) {
-          this.cardDetailId = result.cardDetailId;
-          this.cardId = result.cardId;
-          this.$ls.set("cardDetailId", this.cardDetailId);
+          this.cardId = result;
           this.$ls.set("cardId", this.cardId);
           this.canSave = false;
           this.$message.success("提交成功!");
-          // 提交之后退出编辑,v1.1修改
           this.goback();
         } else {
           this.$message.error("提交失败,请重新尝试!");
@@ -649,7 +614,6 @@ export default {
   },
   beforeDestroy() {
     this.$ls.remove("cardId");
-    this.$ls.remove("cardDetailId");
     this.$ls.remove("prepareTcPCard");
     this.initState();
     delete window.submitCardTemp;

+ 30 - 62
card/views/CardPreview.vue

@@ -1,6 +1,7 @@
 <template>
   <div :class="classes">
-    <div class="preview-body">
+    <div class="preview-frame" id="preview-frame" v-if="IS_COMMON_CARD"></div>
+    <div class="preview-body" v-else>
       <template v-for="(page, pageNo) in pages">
         <div :class="['page-box', `page-box-${pageNo % 2}`]" :key="pageNo">
           <div
@@ -70,14 +71,13 @@
         </div>
       </template>
     </div>
-    <div class="preview-frame" id="preview-frame" v-if="showHtmlTemp"></div>
   </div>
 </template>
 
 <script>
 import TopicElementPreview from "../components/TopicElementPreview";
 import PageNumber from "../components/PageNumber";
-import { cardTempDetail } from "../api";
+import { cardDetail } from "../api";
 import previewTemp from "../previewTemp";
 import exchangeMixins from "../mixins/exchange";
 import { deepCopy } from "../plugins/utils";
@@ -91,11 +91,10 @@ export default {
     return {
       isPrint: this.$route.params.viewType !== "view",
       isFrame: this.$route.params.viewType === "frame",
-      isFrameView: this.$route.params.viewType === "frame-view",
       cardId: this.$route.params.cardId,
       cardConfig: {},
       pages: [],
-      showHtmlTemp: false
+      IS_COMMON_CARD: false
     };
   },
   computed: {
@@ -111,8 +110,6 @@ export default {
   mounted() {
     if (this.isFrame) {
       this.initFrame();
-    } else if (this.isFrameView) {
-      this.initFrameView();
     } else {
       this.init();
     }
@@ -124,15 +121,17 @@ export default {
 
       const { cardConfig, pages } = deepCopy(cardData);
       let fieldInfos = {};
-      cardConfig.businessParams.map(item => {
-        fieldInfos[item.field] = "${" + item.field + "}";
-      });
-      if (cardConfig.examNumberStyle === "auto") {
+      [...cardConfig.requiredFields, ...cardConfig.extendFields]
+        .filter(item => item.enable)
+        .map(item => {
+          fieldInfos[item.field] = "${" + item.field + "}";
+        });
+      if (cardConfig.examNumberStyle === "PRINT") {
         fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
         fieldInfos.examNumberStr = "${examNumberStr}";
       }
 
-      if (cardConfig.aOrB && cardConfig.aOrBType === "auto") {
+      if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
         fieldInfos.paperType = "data:image/png;base64,${paperType}";
         fieldInfos.paperTypeName = "${paperTypeName}";
       }
@@ -148,56 +147,23 @@ export default {
           window.parent.submitCardTemp(cardContentTemp, model);
       });
     },
-    async initFrameView() {
-      const tempData = await cardTempDetail(this.cardId);
-      if (!tempData) {
-        this.$message.error("很抱歉,当前题卡还没开始制作!");
-        return;
-      }
-      const { cardConfig, pages } = tempData;
-      let fieldInfos = {};
-      cardConfig.businessParams.map(item => {
-        fieldInfos[item.field] = "${" + item.field + "}";
-      });
-      if (cardConfig.examNumberStyle === "auto") {
-        fieldInfos.examNumber = "data:image/png;base64,${examNumber}";
-        fieldInfos.examNumberStr = "${examNumberStr}";
-      }
-
-      if (cardConfig.aOrB && cardConfig.aOrBType === "auto") {
-        fieldInfos.paperType = "data:image/png;base64,${paperType}";
-        fieldInfos.paperTypeName = "${paperTypeName}";
-      }
-
-      this.cardConfig = cardConfig;
-      this.pages = this.appendFieldInfo(pages, fieldInfos);
-    },
-    async initTemp() {
-      const { cardConfig, pages } = this.$ls.get("cardData");
-      // const { cardConfig, pages } = JSON.parse(tempData.content);
-      const fieldInfos = this.fetchFieldInfos(cardConfig, {});
-
-      this.cardConfig = cardConfig;
-      this.pages = this.appendFieldInfo(pages, fieldInfos);
-    },
     async init() {
-      const tempData = await cardTempDetail(this.cardId);
-      if (!tempData) {
-        this.$message.error("很抱歉,当前题卡还没开始制作!");
-        return;
-      }
-      if (!tempData.content) {
-        if (!tempData.contentTemp) {
-          this.$message.error("当前题卡详情数据错误!");
-          return;
-        }
-        this.showHtmlTemp = true;
+      const detData = await cardDetail(this.cardId);
+
+      this.IS_COMMON_CARD = detData.type === "GENERIC";
+      // 通卡展示
+      if (this.IS_COMMON_CARD) {
         this.$nextTick(() => {
-          this.initHtmlTemp(tempData.contentTemp);
+          this.initHtmlTemp(detData.htmlContent);
         });
         return;
       }
-      const { cardConfig, pages } = JSON.parse(tempData.content);
+      // 常规卡展示
+      if (!detData.content) {
+        this.$message.error("很抱歉,当前题卡还没开始制作!");
+        return;
+      }
+      const { cardConfig, pages } = JSON.parse(detData.content);
       const fieldInfos = this.fetchFieldInfos(cardConfig, {});
 
       this.cardConfig = cardConfig;
@@ -218,16 +184,18 @@ export default {
       let fieldInfos = {};
       const defContent = "相关信息";
       const defNumber = "123456789";
-      cardConfig.businessParams.map(item => {
-        fieldInfos[item.field] = stdInfo[item.field] || defContent;
-      });
-      if (cardConfig.examNumberStyle === "auto") {
+      [...cardConfig.requiredFields, ...cardConfig.extendFields]
+        .filter(item => item.enable)
+        .map(item => {
+          fieldInfos[item.field] = stdInfo[item.field] || defContent;
+        });
+      if (cardConfig.examNumberStyle === "PRINT") {
         fieldInfos.examNumber = this.getBase64Barcode(
           stdInfo["examNumber"] || defNumber
         );
         fieldInfos.examNumberStr = stdInfo["examNumber"] || defNumber;
       }
-      if (cardConfig.aOrB && cardConfig.aOrBType === "auto") {
+      if (cardConfig.aOrB && cardConfig.paperType === "PRINT") {
         fieldInfos.paperType = this.getBase64Barcode(
           stdInfo["paperType"] || defNumber
         );

+ 5 - 0
src/assets/styles/element-ui-costom.scss

@@ -317,6 +317,11 @@
         background-color: $--color-primary;
       }
     }
+    &.is-disabled.is-checked {
+      .el-checkbox__inner {
+        opacity: 0.6;
+      }
+    }
   }
   .el-checkbox__label {
     color: $--color-text-regular !important;

+ 11 - 6
src/assets/styles/home.scss

@@ -135,9 +135,15 @@
   .head-logo {
     width: 220px;
     float: left;
-    padding: 10px 36px;
+    padding: 5px 30px;
     font-size: 20px;
-    line-height: 30px;
+    line-height: 40px;
+
+    img {
+      display: block;
+      max-width: 160px;
+      height: 40px;
+    }
   }
   .head-menu {
     float: left;
@@ -154,8 +160,7 @@
     li {
       display: inline-block;
       vertical-align: top;
-      width: 190px;
-      padding: 10px 0;
+      padding: 10px 25px;
       height: 50px;
       line-height: 30px;
       opacity: 0.7;
@@ -186,8 +191,8 @@
 
       span {
         display: inline-block;
-        vertical-align: middle;
-        margin-left: 14px;
+        vertical-align: top;
+        margin-left: 8px;
       }
       .menu-item-account {
         white-space: nowrap;

+ 7 - 0
src/assets/styles/login.scss

@@ -82,6 +82,13 @@
     font-size: 23px;
     font-weight: bold;
   }
+
+  img {
+    display: block;
+    max-width: 160px;
+    height: 40px;
+    margin: 0 auto;
+  }
 }
 .login-form {
   .el-form-item:last-child {

+ 1 - 1
src/assets/styles/pages.scss

@@ -47,7 +47,7 @@
 
     img {
       position: absolute;
-      margin: 0;
+      margin: auto;
       max-width: 100%;
       max-height: 100%;
       top: 0;

+ 18 - 13
src/components/UploadButton.vue

@@ -26,7 +26,7 @@
 
 <script>
 import { fileMD5 } from "../plugins/md5";
-import ajax from "@/plugins/ajax";
+import { $post } from "@/plugins/axios";
 
 export default {
   name: "upload-button",
@@ -70,7 +70,7 @@ export default {
   data() {
     return {
       headers: {
-        token: this.$ls.get("token"),
+        Authorization: this.$ls.get("token"),
         md5: ""
       },
       res: {},
@@ -117,7 +117,13 @@ export default {
       return true;
     },
     upload(options) {
-      return ajax(options);
+      let formData = new FormData();
+      Object.entries(options.data).forEach(([k, v]) => {
+        formData.append(k, v);
+      });
+      formData.append("file", options.file);
+
+      return $post(options.action, formData, { headers: options.headers });
     },
     handleError(error) {
       this.loading = false;
@@ -127,17 +133,16 @@ export default {
       };
       this.$emit("upload-error", error);
     },
-    handleSuccess(response) {
+    handleSuccess(responseData) {
       this.loading = false;
-      if (response.code === "200") {
-        this.res = {
-          success: true,
-          message: "导入成功!"
-        };
-        this.$emit("upload-success", response);
-      } else {
-        this.handleError(response);
-      }
+      this.res = {
+        success: true,
+        message: "导入成功!"
+      };
+      this.$emit("upload-success", {
+        ...responseData,
+        filename: this.uploadDataDict[this.addFilenameParam]
+      });
     },
     handleFormatError() {
       const content = "只支持文件格式为" + this.format.join("/");

+ 3 - 3
src/components/UploadFileDialog.vue

@@ -71,11 +71,11 @@ export default {
         message: errorData.message
       });
     },
-    uploadSuccess(res) {
+    uploadSuccess(data) {
       this.$message.success("上传成功!");
       let infos = {
-        attachmentId: res.data.id,
-        filename: `${res.data.name}${res.data.type}`
+        attachmentId: data.id,
+        filename: data.filename
       };
       this.attachment = Object.assign(this.attachment, infos);
     },

+ 20 - 20
src/components/UploadFileView.vue

@@ -40,7 +40,7 @@
 
 <script>
 import { fileMD5 } from "@/plugins/md5";
-import ajax from "@/plugins/ajax";
+import { $post } from "@/plugins/axios";
 
 export default {
   name: "upload-file-view",
@@ -89,18 +89,11 @@ export default {
       loading: false,
       uploadDataDict: {},
       headers: {
-        token: this.$ls.get("token"),
         md5: ""
       },
       res: {}
     };
   },
-  created() {
-    this.headers = {
-      ...this.headers,
-      ...this.getHeadIds()
-    };
-  },
   methods: {
     startUpload() {
       this.loading = true;
@@ -136,12 +129,20 @@ export default {
       }
 
       const md5 = await fileMD5(file);
-      this.uploadDataDict["md5"] = md5;
+      this.headers["md5"] = md5;
+
+      if (this.autoUpload) this.loading = true;
 
       return this.autoUpload;
     },
     upload(options) {
-      return ajax(options);
+      let formData = new FormData();
+      Object.entries(options.data).forEach(([k, v]) => {
+        formData.append(k, v);
+      });
+      formData.append("file", options.file);
+
+      return $post(options.action, formData, { headers: options.headers });
     },
     handleError(error) {
       this.canUpload = false;
@@ -152,18 +153,17 @@ export default {
       };
       this.$emit("upload-error", error);
     },
-    handleSuccess(response) {
+    handleSuccess(responseData) {
       this.canUpload = false;
       this.loading = false;
-      if (response.code === 200) {
-        this.res = {
-          success: true,
-          message: "导入成功!"
-        };
-        this.$emit("upload-success", response);
-      } else {
-        this.handleError(response);
-      }
+      this.res = {
+        success: true,
+        message: "导入成功!"
+      };
+      this.$emit("upload-success", {
+        ...responseData,
+        filename: this.uploadDataDict[this.addFilenameParam]
+      });
     },
     handleProgress() {
       this.loading = true;

+ 1 - 1
src/components/ViewFooter.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="view-footer home-footer">
     <p>
-      Copyright © 2018-2020
+      Copyright © 2018-2021
       <a href="http://www.qmth.com.cn" target="_blank">www.qmth.com.cn</a> , All
       Rights Reserved.
     </p>

+ 2 - 1
src/components/base/CardRuleSelect.vue

@@ -22,6 +22,7 @@
 
 <script>
 import { cardRuleQuery } from "../../modules/base/api";
+import { COMMON_CARD_RULE_ID } from "@/constants/enumerate";
 
 export default {
   name: "card-rule-select",
@@ -53,7 +54,7 @@ export default {
       const res = await cardRuleQuery(query);
       this.optionList = res;
       this.optionList.unshift({
-        id: "GENENAL",
+        id: COMMON_CARD_RULE_ID,
         name: "全部通卡"
       });
     },

+ 3 - 3
src/components/base/CourseSelect.vue

@@ -11,8 +11,8 @@
   >
     <el-option
       v-for="item in optionList"
-      :key="item.id"
-      :value="item.id"
+      :key="item.code"
+      :value="item.code"
       :label="`${item.name}(${item.code})`"
     >
       <span>{{ `${item.name}(${item.code})` }}</span>
@@ -57,7 +57,7 @@ export default {
       this.$emit("input", this.selected);
       this.$emit(
         "change",
-        this.optionList.find(item => item.id === this.selected)
+        this.optionList.find(item => item.code === this.selected)
       );
     }
   }

+ 11 - 2
src/components/base/QuestionTeacherSelect.vue

@@ -28,7 +28,8 @@ export default {
     value: { type: [Number, String], default: "" },
     styles: { type: String, default: "" },
     clearable: { type: Boolean, default: true },
-    courseCode: { type: String, default: "" }
+    courseCode: { type: String, default: "" },
+    schoolId: { type: String, default: "" }
   },
   data() {
     return {
@@ -49,6 +50,13 @@ export default {
         this.$emit("input", "");
         this.$emit("change", {});
       }
+    },
+    schoolId(val, oldval) {
+      if (val !== oldval) {
+        this.search("");
+        this.$emit("input", "");
+        this.$emit("change", {});
+      }
     }
   },
   async created() {
@@ -58,7 +66,8 @@ export default {
     async search(query) {
       const res = await questionTeatherQuery({
         param: query,
-        courseCode: this.courseCode
+        courseCode: this.courseCode,
+        schoolId: this.schoolId
       });
       this.optionList = res;
     },

+ 75 - 0
src/components/base/QuestionTeacherUserSelect.vue

@@ -0,0 +1,75 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="question-teacher-user-select"
+    placeholder="请选择"
+    :style="styles"
+    filterable
+    :clearable="clearable"
+    :disabled="disabled"
+    @change="select"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.id"
+      :value="item.id"
+      :label="item.name"
+    ></el-option>
+  </el-select>
+</template>
+
+<script>
+import { questionTeatherUserQuery } from "../../modules/base/api";
+
+export default {
+  name: "question-teacher-user-select",
+  props: {
+    disabled: { type: Boolean, default: false },
+    value: { type: [Number, String], default: "" },
+    styles: { type: String, default: "" },
+    clearable: { type: Boolean, default: true },
+    courseCode: { type: String, default: "" }
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: ""
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      }
+    },
+    courseCode(val, oldval) {
+      if (val !== oldval) {
+        this.search("");
+        this.$emit("input", "");
+        this.$emit("change", {});
+      }
+    }
+  },
+  async created() {
+    this.search();
+  },
+  methods: {
+    async search(query) {
+      if (!this.courseCode) return;
+      const res = await questionTeatherUserQuery({
+        param: query,
+        courseCode: this.courseCode
+      });
+      this.optionList = res;
+    },
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit(
+        "change",
+        this.optionList.find(item => item.id === this.selected)
+      );
+    }
+  }
+};
+</script>

+ 64 - 0
src/components/base/SchoolSelect.vue

@@ -0,0 +1,64 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="school-select"
+    placeholder="请选择"
+    :style="styles"
+    filterable
+    :clearable="clearable"
+    :disabled="disabled"
+    @change="select"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.id"
+      :value="item.id"
+      :label="item.name"
+    >
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+import { schoolList } from "../../modules/login/api";
+
+export default {
+  name: "school-select",
+  props: {
+    disabled: { type: Boolean, default: false },
+    value: { type: [Number, String], default: "" },
+    styles: { type: String, default: "" },
+    clearable: { type: Boolean, default: true }
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: ""
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      }
+    }
+  },
+  async created() {
+    this.search();
+  },
+  methods: {
+    async search() {
+      const res = await schoolList();
+      this.optionList = res;
+    },
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit(
+        "change",
+        this.optionList.find(item => item.id === this.selected)
+      );
+    }
+  }
+};
+</script>

+ 16 - 0
src/constants/app.js

@@ -0,0 +1,16 @@
+const MD5 = require("js-md5");
+
+// domain
+let domain;
+if (process.env.VUE_APP_SELF_DEFINE_DOMAIN === "true") {
+  domain = window.localStorage.getItem("domain_in_url");
+}
+if (!domain) domain = window.location.hostname.split(".")[0];
+export const ORG_CODE = domain;
+
+export const PLATFORM = "WEB";
+
+if (!localStorage.getItem("deviceId")) {
+  localStorage.setItem("deviceId", MD5(Math.random() + "-" + Date.now()));
+}
+export const DEVICE_ID = localStorage.getItem("deviceId");

+ 33 - 9
src/constants/enumerate.js

@@ -62,6 +62,9 @@ export const AUDITING_RESULT = {
   PASS: "通过"
 };
 
+// 通用题卡规则id
+export const COMMON_CARD_RULE_ID = "-1";
+
 export const CARD_BUSINESS_FIELDS = {
   must: [
     {
@@ -95,9 +98,9 @@ export const RESERVE_TYPE = {
 };
 
 export const CARD_SOURCE_TYPE = {
-  0: "选择已有答题卡",
-  1: "自助创建",
-  2: "申请客服制卡"
+  SELECT: "选择已有答题卡",
+  SELF: "自助创建",
+  CUST: "申请客服制卡"
 };
 
 export const EXAM_NUMBER_STYLE = {
@@ -137,8 +140,8 @@ export const CONFIRM_PRINT_TYPE = {
 };
 
 export const PRIVILEGE_TYPE = {
-  M: "菜单",
-  F: "操作"
+  MENU: "菜单",
+  URL: "操作"
 };
 
 export const TEMPLATE_CLASSIFY = {
@@ -148,10 +151,12 @@ export const TEMPLATE_CLASSIFY = {
 };
 
 export const EXAM_TASK_STATUS = {
-  NEW: "新建任务",
-  STAGE: "暂存",
-  SUBMIT: "确认提交",
-  CANCEL: "撤回"
+  NEW: "新建",
+  READY: "待命题",
+  STAGE: "进行中",
+  SUBMIT: "待审核",
+  FINISH: "已完成"
+  // CANCEL: "撤回"
 };
 
 export const DRAW_RULE_TYPE = {
@@ -177,3 +182,22 @@ export const ROLE_TYPE = {
   PRINT: "印刷人员",
   CUSTOM: "自定义"
 };
+// data-manage
+export const DATA_TASK_STATUS = {
+  INIT: "未开始",
+  RUNNING: "进行中",
+  FINISH: "已完成"
+};
+export const DATA_TASK_TYPE = {
+  USER_IMPORT: "用户导入",
+  QUESTION_MISSION_BATCH_CREATE: "批量新建命题任务",
+  SAMPLE_EXPORT: "导出审核样本",
+  PAPER_DOWNLOAD: "卷库下载",
+  EXAMINATION_IMPORT: "考务数据导入",
+  EXAMINATION_EXPORT: "考务数据导出",
+  PRINT_PDF_DOWNLOAD: "批量下载pdf"
+};
+export const DATA_TASK_RESULT = {
+  SUCCESS: "成功",
+  ERROR: "失败"
+};

+ 31 - 0
src/constants/navs.js

@@ -2,6 +2,7 @@ const navs = [
   {
     title: "考试中心",
     name: "exam",
+    icon: "el-icon-receiving",
     children: [
       {
         title: "我的工作台",
@@ -71,12 +72,24 @@ const navs = [
           //   router: "PrintProgressManage"
           // }
         ]
+      },
+      {
+        title: "数据管理",
+        name: "data",
+        icon: "el-icon-set-up",
+        children: [
+          {
+            title: "任务管理",
+            router: "DataTaskManage"
+          }
+        ]
       }
     ]
   },
   {
     title: "基础配置",
     name: "base",
+    icon: "el-icon-setting",
     children: [
       {
         title: "用户管理",
@@ -133,6 +146,24 @@ const navs = [
         ]
       }
     ]
+  },
+  {
+    title: "客服制卡",
+    name: "customer",
+    icon: "el-icon-service",
+    children: [
+      {
+        title: "客服制卡",
+        name: "customer",
+        icon: "el-icon-s-custom",
+        children: [
+          {
+            title: "题卡审核",
+            router: "CustomerCard"
+          }
+        ]
+      }
+    ]
   }
 ];
 

+ 24 - 24
src/main.js

@@ -6,10 +6,9 @@ import router from "./router";
 import store from "./store";
 import globalVuePlugins from "./plugins/globalVuePlugins";
 import GLOBAL from "./config";
-import { jsonBigNumberToString } from "./plugins/utils";
 // import "./plugins/keepAlive";
 import "./plugins/filters";
-// import { getAuthorisation } from "./plugins/crypto";
+import { getAuthorization } from "./plugins/crypto";
 
 // https://github.com/RobinCK/vue-ls
 import VueLocalStorage from "vue-ls";
@@ -17,6 +16,8 @@ import ElementUI from "element-ui";
 import "element-ui/lib/theme-chalk/index.css";
 import "./assets/styles/index.scss";
 import "../card/assets/styles/module.scss";
+import { PLATFORM, DEVICE_ID } from "./constants/app";
+
 Vue.use(ElementUI, { size: "medium" });
 
 Vue.use(VueLocalStorage, { storage: "session" });
@@ -24,6 +25,7 @@ Vue.use(globalVuePlugins);
 
 Vue.prototype.GLOBAL = GLOBAL;
 Vue.config.productionTip = false;
+const IS_DEV = process.env.NODE_ENV === "development";
 
 // route interceptor
 router.beforeEach((to, from, next) => {
@@ -47,12 +49,6 @@ var load = "";
 // 同一时间有多个请求时,会形成队列。在第一个请求创建loading,在最后一个响应关闭loading
 var queue = [];
 
-// 解决js处理超过16位number时精度丢失的问题
-axios.defaults.transformResponse = [
-  data => {
-    return JSON.parse(jsonBigNumberToString(data));
-  }
-];
 // 设置延迟时效
 axios.defaults.timeout = GLOBAL.timeout;
 axios.interceptors.request.use(
@@ -81,23 +77,27 @@ axios.interceptors.request.use(
       });
 
       // 新版鉴权 to open
-      // const userId = Vue.ls.get("user").id;
-      // const { Authorization, timestamp } = getAuthorisation(
-      //   {
-      //     token: token,
-      //     account: userId,
-      //     uri: config.url,
-      //     method: config.method
-      //   },
-      //   "token"
-      // );
-      // config.headers["Authorization"] = Authorization;
-      // config.headers["time"] = timestamp;
-      // config.headers["deviceId"] = userId;
-      // config.headers["domain"] = window.location.origin;
-      // config.headers["platform"] = "print-web";
-      config.headers["token"] = token;
+      if (IS_DEV) {
+        config.headers["Authorization"] = token;
+        config.headers["time"] = 1;
+      } else {
+        const sessionId = Vue.ls.get("user", { sessionId: "" }).sessionId;
+        const { Authorization, timestamp } = getAuthorization(
+          {
+            token: token,
+            account: sessionId,
+            uri: config.url,
+            method: config.method
+          },
+          "token"
+        );
+        config.headers["Authorization"] = Authorization;
+        config.headers["time"] = timestamp;
+      }
     }
+    config.headers["deviceId"] = DEVICE_ID;
+    config.headers["platform"] = PLATFORM;
+    config.headers["domain"] = window.location.origin;
     return config;
   },
   error => {

+ 3 - 0
src/modules/base/api.js

@@ -1,5 +1,8 @@
 import { $postParam, $post } from "@/plugins/axios";
 
+export const questionTeatherUserQuery = ({ courseCode, param }) => {
+  return $postParam("/api/admin/sys/user/user_list", { courseCode, param });
+};
 // user-manage
 export const userListPage = datas => {
   return $postParam("/api/admin/sys/user/list", datas);

+ 3 - 3
src/modules/base/components/ModifyMenu.vue

@@ -82,7 +82,7 @@ const initModalForm = {
   parentId: null,
   parentName: "",
   sequence: 1,
-  type: "M",
+  type: "MENU",
   remark: ""
 };
 
@@ -122,9 +122,9 @@ export default {
         url: [
           {
             required: true,
-            pattern: /^[0-9a-zA-Z_-]{3,30}$/,
+            pattern: /^[0-9a-zA-Z/_-]{3,30}$/,
             message:
-              "URL地址只能由字母、数字、短横线和下划线组成,长度在3-30之间",
+              "URL地址只能由字母、数字、斜线、短横线和下划线组成,长度在3-30之间",
             trigger: "change"
           }
         ]

+ 10 - 1
src/modules/base/components/ModifyRole.vue

@@ -57,13 +57,21 @@
               :expand-on-click-node="false"
               @check-change="checkChange"
             >
+              <span class="custom-tree-node" slot-scope="{ node, data }">
+                <span
+                  ><i class="el-icon-s-check" v-if="data.type === 'LINK'"></i>
+                  {{ node.label }}</span
+                >
+              </span>
             </el-tree>
           </div>
         </el-form-item>
       </el-form>
     </div>
     <div slot="footer">
-      <el-button type="primary" @click="submit">确认</el-button>
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
       <el-button type="danger" @click="cancel" plain>取消</el-button>
     </div>
   </el-dialog>
@@ -112,6 +120,7 @@ export default {
   data() {
     return {
       modalIsShow: false,
+      isSubmit: false,
       modalForm: {},
       defaultProps: {
         label: "name"

+ 7 - 4
src/modules/base/components/ModifyTemplate.vue

@@ -61,6 +61,7 @@
         </el-form-item>
         <el-form-item prop="attachmentId" label="上传模板文件:">
           <upload-file-view
+            :upload-data="uploadData"
             :upload-url="uploadUrl"
             :disabled="!editable"
             :format="format"
@@ -146,7 +147,7 @@ export default {
     },
     format() {
       const formats = {
-        GENERIC: ["pdf"],
+        GENERIC: ["html"],
         VARIABLE: ["pdf"],
         ORDINARY: ["pdf"]
       };
@@ -197,7 +198,10 @@ export default {
         ]
       },
       // upload
-      uploadUrl: "/api/admin/common/file/upload"
+      uploadUrl: "/api/admin/common/file/upload",
+      uploadData: {
+        type: "UPLOAD"
+      }
     };
   },
   methods: {
@@ -254,9 +258,8 @@ export default {
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });
     },
-    uploadSuccess(res) {
+    uploadSuccess(data) {
       this.$message.success("上传成功!");
-      const data = res.data;
 
       this.modalForm.attachmentId = data.id;
       this.$refs.modalFormComp.validateField("attachmentId");

+ 8 - 2
src/modules/base/components/ModifyUser.vue

@@ -22,8 +22,14 @@
             style="width:100%;"
             v-model.trim="modalForm.loginName"
             placeholder="请输入用户名"
-            disabled
+            :disabled="isEdit"
           ></el-input>
+          <!-- <el-input
+            style="width:100%;"
+            v-model.trim="modalForm.loginName"
+            placeholder="请输入用户名"
+            disabled
+          ></el-input> -->
         </el-form-item>
         <el-form-item prop="realName" label="姓名:">
           <el-input
@@ -271,7 +277,7 @@ export default {
         oldRoleIds !== newRoleIds &&
         this.$ls.get("user").id === this.instance.id
       ) {
-        await logout(this.$ls.get("user", { id: "" }).id);
+        await logout();
         this.$ls.clear();
         this.$router.push({ name: "Login" });
         this.$message.info("您的权限已经变更,请重新登录系统!");

+ 3 - 3
src/modules/base/components/ResetPwd.vue

@@ -58,7 +58,7 @@
 <script>
 import { updatePwd } from "../api";
 import { password } from "@/plugins/formRules";
-import { AES } from "@/plugins/crypto";
+import { Base64 } from "@/plugins/crypto";
 
 const initModalForm = {
   id: "",
@@ -121,8 +121,8 @@ export default {
       this.isSubmit = true;
       const datas = {
         id: this.resetModel.id,
-        oldPassword: AES(this.resetModel.oldPassword),
-        password: AES(this.resetModel.password)
+        oldPassword: Base64(this.resetModel.oldPassword),
+        password: Base64(this.resetModel.password)
       };
       const data = await updatePwd(datas).catch(() => {
         this.isSubmit = false;

+ 5 - 5
src/modules/base/views/MenuManage.vue

@@ -15,12 +15,12 @@
       >
         <span class="custom-tree-node" slot-scope="{ node, data }">
           <span
-            ><i class="el-icon-s-check" v-if="data.type === 'F'"></i>
+            ><i class="el-icon-s-check" v-if="data.type === 'LINK'"></i>
             {{ node.label }}</span
           >
           <span>
             <el-button
-              v-if="data.type === 'M'"
+              v-if="data.type === 'MENU'"
               class="btn-table-icon"
               type="text"
               icon="icon icon-plus-act"
@@ -34,13 +34,13 @@
               @click="() => edit(node, data)"
               title="修改"
             ></el-button>
-            <el-button
+            <!-- <el-button
               class="btn-table-icon"
               type="text"
               icon="icon icon-delete"
               @click="() => remove(node, data)"
               title="删除"
-            ></el-button>
+            ></el-button> -->
           </span>
         </span>
       </el-tree>
@@ -112,7 +112,7 @@ export default {
     },
     append(node, data) {
       const sequences = node.parent.childNodes.map(item => item.sequence);
-      const maxSequence = Math.max.apply(null, sequences);
+      const maxSequence = Math.max.apply(null, sequences) || 0;
 
       this.curMenu = {
         parentId: data.id,

+ 14 - 5
src/modules/base/views/UserManage.vue

@@ -54,6 +54,7 @@
           btn-type="warning"
           btn-content="导入"
           :upload-url="uploadUrl"
+          :upload-data="uploadData"
           :format="['xls', 'xlsx']"
           @upload-error="uplaodError"
           @upload-success="uploadSuccess"
@@ -64,6 +65,7 @@
             >用户导入模板下载</a
           >
         </el-button>
+        <el-button type="primary" @click="toAdd">新增用户</el-button>
       </div>
     </div>
 
@@ -187,7 +189,10 @@ export default {
       curUser: {},
       downloadUrl: "/temps/用户导入模板.xlsx",
       // import
-      uploadUrl: "/api/admin/sys/user/import"
+      uploadUrl: "/api/admin/sys/user/import",
+      uploadData: {
+        type: "FILE"
+      }
     };
   },
   created() {
@@ -244,6 +249,10 @@ export default {
       this.curUser = row;
       this.$refs.ModifyUser.open();
     },
+    toAdd() {
+      this.curUser = {};
+      this.$refs.ModifyUser.open();
+    },
     async toResetPwd(row) {
       await resetPwd(row.id);
       this.$message.success("密码重置成功!");
@@ -251,10 +260,10 @@ export default {
       // 修改自己时,会强制重新登录
       const userId = this.$ls.get("user", { id: "" }).id;
       if (row.id !== userId) return;
-      this.toLogout(userId);
+      this.toLogout();
     },
-    async toLogout(userId) {
-      await logout(userId);
+    async toLogout() {
+      await logout();
       this.$ls.clear();
       this.$router.push({ name: "Login" });
       this.$message.info("您的密码已经变更,请重新登录系统!");
@@ -262,7 +271,7 @@ export default {
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });
     },
-    uploadSuccess(res) {
+    uploadSuccess() {
       this.$message.success("上传成功!");
       this.getList();
     }

+ 3 - 0
src/modules/card/api.js

@@ -0,0 +1,3 @@
+import { cardConfigInfos, cardDetail, saveCard } from "../../../card/api";
+
+export { cardConfigInfos, cardDetail, saveCard };

+ 9 - 0
src/modules/customer/api.js

@@ -0,0 +1,9 @@
+import { $postParam, $post } from "@/plugins/axios";
+
+// 试卷编号模糊查询
+export const customerCardTaskList = datas => {
+  return $postParam("/api/admin/exam/card/cust_list", datas);
+};
+export const applyCustomerCard = datas => {
+  return $post("/api/admin/exam/card/cust_save", datas);
+};

+ 9 - 0
src/modules/customer/router.js

@@ -0,0 +1,9 @@
+import CustomerCard from "./views/CustomerCard";
+
+export default [
+  {
+    path: "customer/card",
+    name: "CustomerCard",
+    component: CustomerCard
+  }
+];

+ 277 - 0
src/modules/customer/views/CustomerCard.vue

@@ -0,0 +1,277 @@
+<template>
+  <div class="customer-card">
+    <div class="mb-4">
+      <el-button
+        v-for="(val, key) in AUDITING_STATUS"
+        :key="key"
+        :type="filter.status == key ? 'primary' : 'default'"
+        @click="selectMenu(key)"
+        >{{ val }}</el-button
+      >
+    </div>
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="85px" inline>
+        <el-form-item label="学校名称:">
+          <school-select v-model="filter.schoolId"></school-select>
+        </el-form-item>
+        <el-form-item label="试卷编号:">
+          <paper-number-select
+            ref="PaperNumberSelect"
+            v-model="filter.paperNumber"
+            placeholder="请选择"
+            clearable
+          ></paper-number-select>
+        </el-form-item>
+        <el-form-item label="申请人:">
+          <question-teacher-select
+            ref="QuestionTeacherSelect"
+            v-model="filter.userId"
+            :school-id="filter.schoolId"
+            placeholder="请选择"
+          ></question-teacher-select>
+        </el-form-item>
+        <el-form-item label="申请时间:">
+          <el-date-picker
+            v-model="createTime"
+            type="datetimerange"
+            :picker-options="pickerOptions"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="timestamp"
+            align="right"
+            unlink-panels
+          >
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="完成时间:" v-if="AUDITED">
+          <el-date-picker
+            v-model="finishTime"
+            type="datetimerange"
+            :picker-options="pickerOptions"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="timestamp"
+            align="right"
+            unlink-panels
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label-width="0px">
+          <el-button type="primary" icon="icon icon-search" @click="toPage(1)"
+            >查询</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action" v-if="!AUDITED">
+        <el-button
+          icon="el-icon-download"
+          type="primary"
+          :disabled="loading"
+          @click="toExport"
+        >
+          批量下载试卷文件
+        </el-button>
+      </div>
+    </div>
+
+    <div class="part-box">
+      <el-table ref="TableList" :data="taskList" border stripe>
+        <el-table-column
+          type="index"
+          label="序号"
+          width="70"
+          align="center"
+          :index="indexMethod"
+        ></el-table-column>
+        <el-table-column
+          prop="paperNumber"
+          label="试卷编号"
+          width="120"
+        ></el-table-column>
+        <el-table-column prop="schoolName" label="学校名称"></el-table-column>
+        <el-table-column prop="orgName" label="所属部门"> </el-table-column>
+        <el-table-column
+          prop="createName"
+          label="申请人"
+          width="100"
+        ></el-table-column>
+        <el-table-column prop="createTime" label="申请时间">
+          <span slot-scope="scope">{{
+            scope.row.createTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column prop="updateTime" label="完成时间" v-if="AUDITED">
+          <span slot-scope="scope">{{
+            scope.row.updateTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          align="center"
+          width="80px"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="AUDITED"
+              class="btn-table-icon"
+              type="text"
+              icon="icon icon-circle-right"
+              @click="toPreview(scope.row)"
+              title="查看详情"
+            ></el-button>
+            <el-button
+              v-else
+              class="btn-table-icon"
+              type="text"
+              icon="icon icon-edit"
+              @click="toEdit(scope.row)"
+              title="设计题卡"
+            ></el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import pickerOptions from "@/constants/datePickerOptions";
+import { customerCardTaskList } from "../api";
+import { download, randomCode } from "@/plugins/utils";
+
+export default {
+  name: "customer-card",
+  data() {
+    return {
+      filter: {
+        status: "STAGE",
+        paperNumber: "",
+        userId: "",
+        applyStartTime: null,
+        applyEndTime: null,
+        finishStartTime: null,
+        finishEndTime: null
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      AUDITING_STATUS: {
+        STAGE: "待审核",
+        SUBMIT: "已审核"
+      },
+      caches: {},
+      taskList: [],
+      loading: false,
+      // date-picker
+      createTime: [],
+      finishTime: [],
+      pickerOptions
+    };
+  },
+  computed: {
+    AUDITED() {
+      return this.filter.status === "SUBMIT";
+    }
+  },
+  created() {
+    this.toPage(1);
+  },
+  methods: {
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      if (this.createTime) {
+        datas.applyStartTime = this.createTime[0];
+        datas.applyEndTime = this.createTime[1];
+      }
+      if (this.finishTime) {
+        datas.finishStartTime = this.finishTime[0];
+        datas.finishEndTime = this.finishTime[1];
+      }
+      const data = await customerCardTaskList(datas);
+      this.taskList = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    selectMenu(val) {
+      this.caches[this.filter.status] = {
+        current: this.current,
+        taskList: this.taskList,
+        total: this.total
+      };
+      this.filter.status = val;
+      if (this.caches[val] && this.caches[val].taskList) {
+        this.current = this.caches[val].current;
+        this.total = this.caches[val].total;
+        this.taskList = this.caches[val].taskList;
+      } else {
+        this.toPage(1);
+      }
+    },
+    async toExport() {
+      if (this.loading) return;
+      this.loading = true;
+      const res = await download({
+        type: "post",
+        url: this.GLOBAL.domain + "/api/admin/exam/task_review/export",
+        data: {},
+        fileName: `${Date.now()}${randomCode()}.zip`,
+        header: this.getHeadIds()
+      }).catch(error => {
+        this.$message.error(error + "文件下载失败,请重新尝试!");
+      });
+      this.loading = false;
+      if (!res) return;
+      this.$message.success("文件下载成功!");
+    },
+    toEdit(row) {
+      this.$ls.set("prepareTcPCard", {
+        examTaskId: row.examTaskId,
+        courseCode: row.courseCode,
+        courseName: row.courseName,
+        makeMethod: "CUST",
+        cardRuleId: row.cardRuleId
+      });
+      // 打开题卡编辑页,创建题卡,并预设需要绑定的任务
+      this.$router.push({
+        name: "CardDesign",
+        params: {
+          cardId: row.cardId
+        }
+      });
+    },
+    toPreview(row) {
+      window.open(
+        this.getRouterPath({
+          name: "CardPreview",
+          params: {
+            cardId: row.cardId,
+            viewType: "view"
+          }
+        })
+      );
+    }
+  }
+};
+</script>

+ 35 - 17
src/modules/exam/api.js

@@ -1,13 +1,17 @@
 import { $postParam, $post } from "@/plugins/axios";
 
 // other
+// 待办任务数量
+export const waitTaskListCount = () => {
+  return $postParam("/api/admin/exam/task_undo_count", {});
+};
 // 试卷编号模糊查询
 export const pageNumberQuery = param => {
   return $postParam("/api/admin/exam/task/paper_number_query", { param });
 };
 // 命题老师模糊查询
-export const questionTeatherQuery = ({ param, courseCode }) => {
-  return $postParam("/api/admin/exam/task/user_query", { param, courseCode });
+export const questionTeatherQuery = datas => {
+  return $postParam("/api/admin/exam/task/user_query", datas);
 };
 
 // exam-task-manage
@@ -17,49 +21,63 @@ export const examTaskListPage = datas => {
 export const updateExamTask = datas => {
   return $post("/api/admin/exam/task/save", datas);
 };
+export const updatExamTaskTeacher = ({ id, userId }) => {
+  return $post("/api/admin/exam/task/assign_user", { id, userId });
+};
 export const ableExamTask = ({ id, enable }) => {
   return $post("/api/admin/exam/task/enable", { id, enable });
 };
 export const batchAddExamTask = datas => {
   return $post("/api/admin/exam/task/save_batch", datas);
 };
-export const taskApplyAuditHistory = id => {
-  return $postParam("/api/admin/exam/task/review_list", { id });
+export const taskApplyAuditHistory = examTaskId => {
+  return $postParam("/api/admin/exam/task/review_list", { examTaskId });
 };
 
 // task-apply-manage
 export const taskApplyListPage = datas => {
-  return $postParam("/api/admin/exam/task_apply/list", datas);
+  return $postParam("/api/admin/exam/task/apply_list", datas);
 };
-export const taskApplyDetail = id => {
-  return $postParam("/api/admin/exam/task_apply/get_one", { id });
+export const taskApplyDetail = examTaskId => {
+  return $postParam("/api/admin/exam/task/apply_get_one", { examTaskId });
 };
 export const updateTaskApply = datas => {
-  return $post("/api/admin/exam/task_apply/save", datas);
+  return $post("/api/admin/exam/task/apply_save", datas);
 };
 export const cancelOrRestartTaskApply = ({ id, status }) => {
-  return $post("/api/admin/exam/task_apply/status", { id, status });
+  return $post("/api/admin/exam/task/apply_status", { id, status });
 };
 
 // task-review-manage
-export const taskReviewListPage = datas => {
-  return $postParam("/api/admin/exam/task_review/list", datas);
+export const taskReviewUnauditedListPage = datas => {
+  return $postParam("/api/admin/exam/task/review_list_unaudited", datas);
+};
+export const taskReviewAuditedListPage = datas => {
+  return $postParam("/api/admin/exam/task/review_list_audited", datas);
 };
 export const updateTaskReview = datas => {
-  return $post("/api/admin/exam/task_review/save", datas);
+  return $post("/api/admin/exam/task/review_save", datas);
 };
 export const batchUpdateTaskReview = datas => {
-  return $post("/api/admin/exam/task_review/save_batch", datas);
+  return $post("/api/admin/exam/task/review_save_batch", datas);
 };
 // task-paper-manage
 export const taskPaperListPage = datas => {
-  return $postParam("/api/admin/exam/task_paper/list", datas);
+  return $postParam("/api/admin/exam/task/paper_list", datas);
 };
 export const ableTaskPaper = ({ id, enable }) => {
-  return $post("/api/admin/exam/task_paper/enable", { id, enable });
+  return $post("/api/admin/exam/task/paper_enable", { id, enable });
 };
 
 // card
-export const cardList = datas => {
-  return $postParam("/api/admin/card/list", datas);
+export const cardForSelectList = datas => {
+  return $postParam("/api/admin/exam/card/select_card_list", datas);
+};
+
+// data-manage ie-task-manage
+export const dataTaskList = datas => {
+  return $postParam("/api/admin/data/task/query", datas);
+};
+export const removeDataTask = ({ ids, type }) => {
+  return $post("/api/admin/data/task/query", { ids, type });
 };

+ 78 - 57
src/modules/exam/components/ApplyContent.vue

@@ -49,9 +49,12 @@
             :rowspan="paperAttachments.length"
             v-if="index === 0"
           >
-            <span @click="toCreateCard"
+            <span v-if="IS_APPLY" @click="toCreateOrViewCard"
               ><i class="icon icon-plus-act"></i>{{ cardTodoName }}</span
             >
+            <span v-else @click="toViewCard"
+              >查看题卡 <i class="icon icon-circle-right"></i
+            ></span>
           </td>
           <td v-if="IS_APPLY">
             <el-button
@@ -86,7 +89,7 @@
           v-for="(img, index) in paperConfirmAttachments"
           :key="index"
         >
-          <img :src="img.path" :alt="img.filename" />
+          <img :src="img.url" :alt="img.filename" />
           <div v-if="IS_APPLY" class="image-delete">
             <i
               class="el-icon-delete-solid"
@@ -176,15 +179,18 @@ import CardOptionDialog from "./CardOptionDialog";
 import { taskApplyDetail, updateTaskApply, updateTaskReview } from "../api";
 
 const initTaskApply = {
-  id: "",
   examTaskId: "",
   paperType: "A",
   paperAttachmentIds: "",
   paperConfirmAttachmentIds: "",
   cardId: "",
-  cardSource: "",
+  cardRuleId: "",
+  makeMethod: "",
   refCardId: "",
-  remark: ""
+  remark: "",
+  courseCode: "",
+  courseName: "",
+  status: "" // 题卡状态
 };
 
 export default {
@@ -207,7 +213,7 @@ export default {
     return {
       isSubmit: false,
       curTaskApply: { ...initTaskApply },
-      paperConfirmAttachmentId: { attachmentId: "", filename: "", path: "" },
+      paperConfirmAttachmentId: { attachmentId: "", filename: "", url: "" },
       paperAttachments: [],
       paperConfirmAttachments: [],
       curAttachment: {},
@@ -231,13 +237,14 @@ export default {
     cardTodoName() {
       let name = "创建答题卡";
       if (this.curTaskApply.cardId) {
-        if (this.curTaskApply.cardSource === 0) {
+        if (this.curTaskApply.makeMethod === "SELECT") {
           name = "选择题卡";
-        } else if (this.curTaskApply.cardSource === 1) {
+        } else if (this.curTaskApply.makeMethod === "SELF") {
           name = "编辑题卡";
         } else {
           // 已经审核的题卡可以自行编辑,未审核的题卡只能查看
-          // name = this.curTaskApply.auditingStatus ? "编辑题卡" : "查看题卡";
+          name =
+            this.curTaskApply.status === "SUBMIT" ? "编辑题卡" : "查看题卡";
         }
       }
       return name;
@@ -249,12 +256,16 @@ export default {
   methods: {
     async initData() {
       const data = await taskApplyDetail(this.examTask.id);
-      this.curTaskApply = this.$objAssign(initTaskApply, data);
-      this.paperAttachments = data.paperAttachmentIds
-        ? JSON.parse(data.paperAttachmentIds)
+      this.curTaskApply = this.$objAssign(initTaskApply, data || {});
+      this.curTaskApply.examTaskId = this.examTask.id;
+      this.curTaskApply.courseCode = this.examTask.courseCode;
+      this.curTaskApply.courseName = this.examTask.courseName;
+      this.curTaskApply.cardRuleId = this.examTask.cardRuleId;
+      this.paperAttachments = this.curTaskApply.paperAttachmentIds
+        ? JSON.parse(this.curTaskApply.paperAttachmentIds)
         : [];
-      this.paperConfirmAttachments = data.paperConfirmAttachmentIds
-        ? JSON.parse(data.paperConfirmAttachmentIds)
+      this.paperConfirmAttachments = this.curTaskApply.paperConfirmAttachmentIds
+        ? JSON.parse(this.curTaskApply.paperConfirmAttachmentIds)
         : [];
     },
     addAtachment() {
@@ -306,50 +317,56 @@ export default {
     deletePaperConfirmAttachment(index) {
       this.paperConfirmAttachments.splice(index, 1);
     },
-    toCreateCard() {
-      this.task = {
-        ...this.getTaskData(),
-        auditStatus: this.examTask.auditStatus,
-        examTaskId: this.examTask.id,
-        cardRuleId: this.examTask.cardRuleId
-      };
-      if (this.curTaskApply.cardId) {
-        if (this.curTaskApply.cardSource === 0) {
-          this.$refs.CardOptionDialog.open();
-        } else if (this.curTaskApply.cardSource === 1) {
-          window.open(
-            this.getRouterPath({
-              name: "CardDesign",
-              params: {
-                cardId: this.curTaskApply.cardId
-              }
-            })
-          );
-        } else {
-          if (this.curTaskApply.auditingStatus) {
-            window.open(
-              this.getRouterPath({
-                name: "CardDesign",
-                params: {
-                  cardId: this.curTaskApply.cardId
-                }
-              })
-            );
-          } else {
-            window.open(
-              this.getRouterPath({
-                name: "CardPreview",
-                params: {
-                  cardId: this.curTaskApply.cardId,
-                  viewType: "view"
-                }
-              })
-            );
+    toViewCard() {
+      window.open(
+        this.getRouterPath({
+          name: "CardPreview",
+          params: {
+            cardId: this.curTaskApply.cardId,
+            viewType: "view"
           }
+        })
+      );
+    },
+    toEditCard() {
+      this.cachePrepareTcpCard();
+      this.$router.push({
+        name: "CardDesign",
+        params: {
+          cardId: this.curTaskApply.cardId
         }
+      });
+    },
+    cachePrepareTcpCard() {
+      this.$ls.set("prepareTcPCard", {
+        examTaskId: this.task.examTaskId,
+        courseCode: this.task.courseCode,
+        courseName: this.task.courseName,
+        makeMethod: this.task.makeMethod,
+        cardRuleId: this.task.cardRuleId,
+        paperType: this.task.paperType
+      });
+    },
+    async toCreateOrViewCard() {
+      await this.silentSave();
+      this.task = this.getTaskData();
+      if (!this.curTaskApply.cardId) {
+        this.$refs.CardOptionDialog.open();
         return;
       }
-      this.$refs.CardOptionDialog.open();
+
+      if (this.curTaskApply.makeMethod === "SELECT") {
+        this.$refs.CardOptionDialog.open();
+      } else if (this.curTaskApply.makeMethod === "SELF") {
+        this.toEditCard();
+      } else {
+        // 客服制卡:制作完毕则可以编辑,未制作完毕则可以查看
+        if (this.curTaskApply.status === "SUBMIT") {
+          this.toEditCard();
+        } else {
+          this.toViewCard();
+        }
+      }
     },
     cancel() {
       this.$emit("cancel");
@@ -362,12 +379,11 @@ export default {
     },
     getTaskData() {
       let data = { ...this.curTaskApply };
-      data.paperType = this.paperAttachments.map(item => item.name).join();
+      data.paperType = this.paperAttachments.map(item => item.name).join(",");
       data.paperAttachmentIds = JSON.stringify(this.paperAttachments);
       data.paperConfirmAttachmentIds = JSON.stringify(
         this.paperConfirmAttachments
       );
-      console.log(data);
       return data;
     },
     checkDataValid() {
@@ -383,10 +399,15 @@ export default {
         return;
       }
 
-      if (!this.task.cardId && !this.task.refCardId) {
+      if (!this.curTaskApply.cardId && !this.curTaskApply.refCardId) {
         this.$message.error("请选择题卡创建方式!");
         return;
       }
+
+      if (this.curTaskApply.status !== "SUBMIT") {
+        this.$message.error("请先提交题卡!");
+        return;
+      }
       return true;
     },
     async toSave() {

+ 84 - 45
src/modules/exam/components/CardOptionDialog.vue

@@ -18,7 +18,7 @@
           2.申请客服制卡:由客服后台统一处理,处理完毕后您可查看或微调。
         </p>
         <div class="card-type">
-          <el-radio-group v-model="modalForm.cardSource">
+          <el-radio-group v-model="modalForm.makeMethod">
             <el-radio
               v-for="item in cardSourceTypes"
               :key="item.type"
@@ -29,7 +29,7 @@
           </el-radio-group>
         </div>
         <!-- card-select -->
-        <div class="card-select" v-if="modalForm.cardSource === 0">
+        <div class="card-select" v-if="modalForm.makeMethod === 'SELECT'">
           <el-form
             ref="ModalForm"
             :model="modalForm"
@@ -47,7 +47,7 @@
                   v-for="item in cards"
                   :key="item.id"
                   :value="item.id"
-                  :label="item.name"
+                  :label="item.title"
                 >
                 </el-option>
               </el-select>
@@ -56,7 +56,7 @@
           </el-form>
         </div>
         <!-- apply-customer -->
-        <div class="card-apply" v-if="modalForm.cardSource === 2">
+        <div class="card-apply" v-if="modalForm.makeMethod === 'CUST'">
           <el-form
             ref="ApplyModalForm"
             :model="applyModalForm"
@@ -70,12 +70,13 @@
                 placeholder="请输入文件标题"
               ></el-input>
             </el-form-item>
-            <el-form-item prop="paperAttachmentId">
+            <el-form-item prop="attachmentId">
               <upload-button
                 btn-icon="icon icon-upload"
                 btn-type="default"
                 btn-content="选择上传文件"
                 :upload-url="uploadUrl"
+                :upload-data="uploadData"
                 :format="format"
                 :max-size="maxSize"
                 @upload-error="uplaodError"
@@ -90,7 +91,9 @@
         </div>
       </div>
       <div slot="footer">
-        <el-button type="primary" @click="confirm">确定</el-button>
+        <el-button type="primary" :disabled="isSubmit" @click="confirm"
+          >确定</el-button
+        >
         <el-button type="danger" @click="cancel" plain>返回</el-button>
       </div>
     </el-dialog>
@@ -98,16 +101,19 @@
 </template>
 
 <script>
-import { CARD_SOURCE_TYPE } from "@/constants/enumerate";
-import { cardList } from "../api";
+import { cardForSelectList } from "../api";
+import { applyCustomerCard } from "../../customer/api";
+import { CARD_SOURCE_TYPE, COMMON_CARD_RULE_ID } from "@/constants/enumerate";
 import UploadButton from "@/components/UploadButton";
 
 const initModalForm = {
   examTaskId: "",
   paperType: "",
+  courseCode: "",
+  courseName: "",
   cardRuleId: "",
   cardId: "",
-  cardSource: "",
+  makeMethod: "",
   refCardId: ""
 };
 
@@ -125,6 +131,7 @@ export default {
   data() {
     return {
       modalIsShow: false,
+      isSubmit: false,
       modalForm: { ...initModalForm },
       rules: {
         refCardId: [
@@ -142,7 +149,7 @@ export default {
       // apply-customer
       applyModalForm: {
         title: "",
-        paperAttachmentId: ""
+        attachmentId: ""
       },
       applyRules: {
         title: [
@@ -152,7 +159,7 @@ export default {
             trigger: "change"
           }
         ],
-        paperAttachmentId: [
+        attachmentId: [
           {
             required: true,
             message: "请上传样卷或试卷结构文件",
@@ -163,16 +170,20 @@ export default {
       // upload
       format: ["pdf"],
       maxSize: 20 * 1024 * 1024,
-      uploadUrl: "/api/admin/common/file/upload"
+      uploadUrl: "/api/admin/common/file/upload",
+      uploadData: {
+        type: "PAPER"
+      }
     };
   },
   methods: {
     visibleChange() {
       this.getCardSourceTypes();
-      this.modalForm.cardSource = this.cardSourceTypes[0].type;
       this.modalForm = this.$objAssign(initModalForm, this.data);
+      this.modalForm.makeMethod =
+        this.data.makeMethod || this.cardSourceTypes[0].type;
 
-      this.getCardList();
+      // this.getCardList();
     },
     getCardSourceTypes() {
       let cardSourceTypes = [];
@@ -183,10 +194,11 @@ export default {
         // 申请客服制卡 =>
         // 若题卡规则为专卡,命题人可即时创建专卡;
         // 若题卡规则为全部通卡,则不显示该制卡方式;
-        if (this.data.curRuleId === "GENERAL" && key !== "0") return;
+        if (this.data.cardRuleId === COMMON_CARD_RULE_ID && key !== "SELECT")
+          return;
 
         cardSourceTypes.push({
-          type: key * 1,
+          type: key,
           name: CARD_SOURCE_TYPE[key]
         });
       });
@@ -196,17 +208,12 @@ export default {
       // 选择已有题卡 =>
       // 若题卡规则为专卡,选择已有题卡时,下拉列表将显示适用的专卡和通卡;
       // 若题卡规则为“全部通卡”,则下拉列表中只显示适用的通卡模板;
-      const data = await cardList({
+      const data = await cardForSelectList({
         courseCode: this.modalForm.courseCode,
         paperType: this.modalForm.paperType,
-        curRuleId: this.modalForm.curRuleId === "GENERAL" ? "GENERAL" : null
-      });
-      this.cards = data.map(item => {
-        return {
-          id: item.id,
-          name: `${item.title}(${item.code})`
-        };
+        cardRuleId: this.modalForm.cardRuleId
       });
+      this.cards = data || [];
     },
     cancel() {
       this.modalIsShow = false;
@@ -217,43 +224,75 @@ export default {
     uplaodError(errorData) {
       this.$notify.error({ title: "错误提示", message: errorData.message });
     },
-    uploadSuccess(res) {
+    uploadSuccess(data) {
       this.$message.success("上传成功!");
-      this.applyModalForm.paperAttachmentId = res.data.id;
-      this.$refs.ApplyModalForm.validateField("paperAttachmentId");
+      this.applyModalForm.attachmentId = data.id;
+      this.$refs.ApplyModalForm.validateField("attachmentId");
     },
     async confirm() {
-      // TODO:具体后续逻辑待定
-      if (this.modalForm.cardSource === 2) {
+      // 客服制卡
+      if (this.modalForm.makeMethod === "CUST") {
         this.$emit("draft-task");
         const valid = await this.$refs.ApplyModalForm.validate().catch(
           () => {}
         );
         if (!valid) return;
+
+        if (this.isSubmit) return;
+        this.isSubmit = true;
+        // 创建题卡
+        const result = await applyCustomerCard({
+          status: "STAGE",
+          examTaskId: this.modalForm.examTaskId,
+          courseCode: this.modalForm.courseCode,
+          courseName: this.modalForm.courseName,
+          makeMethod: "CUST",
+          type: "CUSTOM",
+          ...this.applyModalForm
+        }).catch(() => {});
+        this.isSubmit = false;
+        if (!result) return;
+        this.$message.success("申请成功!");
+        this.$emit("confirm", {
+          cardId: result,
+          makeMethod: this.modalForm.makeMethod
+        });
+        this.cancel();
+        return;
       }
 
-      if (this.modalForm.cardSource === 1) {
-        // 暂存任务,确保以上传的试卷信息正常保存
+      // 自主创建
+      if (this.modalForm.makeMethod === "SELF") {
         this.$emit("draft-task");
+        this.$ls.set("prepareTcPCard", {
+          examTaskId: this.modalForm.examTaskId,
+          courseCode: this.modalForm.courseCode,
+          courseName: this.modalForm.courseName,
+          makeMethod: this.modalForm.makeMethod,
+          cardRuleId: this.modalForm.cardRuleId,
+          paperType: this.modalForm.paperType
+        });
         // 打开题卡编辑页,创建题卡,并预设需要绑定的任务
-        this.$ls.set("prepareTcPCard", this.modalForm);
-        window.open(
-          this.getRouterPath({
-            name: "CardDesign"
-          })
-        );
+        this.$router.push({
+          name: "CardDesign"
+        });
         return;
       }
 
-      if (this.modalForm.cardSource === 0 && !this.modalForm.refCardId) {
-        this.$message.error("请选择已有的题卡!");
-        return;
-      }
+      // 选择已有题卡
+      if (this.modalForm.makeMethod === "SELECT") {
+        if (!this.modalForm.refCardId) {
+          this.$message.error("请选择已有的题卡!");
+          return;
+        }
 
-      const data = { ...this.modalForm };
-      if (data.cardSource !== 0) data.refCardId = "";
-      this.$emit("confirm", data);
-      this.cancel();
+        this.$emit("confirm", {
+          cardId: this.modalForm.cardId,
+          makeMethod: this.modalForm.makeMethod,
+          refCardId: this.modalForm.refCardId
+        });
+        this.cancel();
+      }
     },
     toPreview() {
       if (!this.modalForm.refCardId) {

+ 14 - 6
src/modules/exam/components/ModifyExamTask.vue

@@ -25,6 +25,7 @@
             v-model.trim="modalForm.courseCode"
             placeholder="请选择"
             clearable
+            @change="courseChange"
           ></course-select>
           <span v-else
             >{{ modalForm.courseName }}({{ modalForm.courseCode }})</span
@@ -85,14 +86,14 @@
           </p>
         </el-form-item>
         <el-form-item prop="userId" label="命题老师:">
-          <question-teacher-select
-            v-if="editType !== 'PREVIEW'"
+          <question-teacher-user-select
+            v-if="editType !== 'PREVIEW' && modalIsShow"
             ref="QuestionTeacherSelect"
             v-model="modalForm.userId"
             :course-code="modalForm.courseCode"
             placeholder="请选择"
-          ></question-teacher-select>
-          <span v-else>{{ modalForm.userName }}</span>
+          ></question-teacher-user-select>
+          <span v-else>{{ modalForm.userName || "--" }}</span>
         </el-form-item>
       </el-form>
     </div>
@@ -107,7 +108,7 @@
 </template>
 
 <script>
-import { updateExamTask } from "../api";
+import { updateExamTask, updatExamTaskTeacher } from "../api";
 
 const initModalForm = {
   id: null,
@@ -209,6 +210,8 @@ export default {
   methods: {
     initData(val) {
       this.modalForm = this.$objAssign(initModalForm, val);
+      console.log(this.modalForm);
+      this.createTime = [];
     },
     visibleChange() {
       this.initData(this.instance);
@@ -232,6 +235,9 @@ export default {
         this.modalForm.endTime = "";
       }
     },
+    courseChange(course) {
+      this.modalForm.courseName = course.name;
+    },
     async submit() {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
@@ -241,7 +247,9 @@ export default {
       let modals = {
         ...this.modalForm
       };
-      const data = await updateExamTask(modals).catch(() => {});
+      const func =
+        this.editType === "ADD" ? updateExamTask : updatExamTaskTeacher;
+      const data = await func(modals).catch(() => {});
       this.isSubmit = false;
       if (!data) return;
 

+ 99 - 4
src/modules/exam/components/ModifyTaskApply.vue

@@ -68,7 +68,19 @@
       </el-form>
     </div>
 
-    <div class="mb-2">
+    <div class="mb-4">
+      <el-steps align-center>
+        <el-step
+          v-for="(step, index) in steps"
+          :key="index"
+          :title="step.title"
+          :description="step.desc"
+          :status="step.status"
+        ></el-step>
+      </el-steps>
+    </div>
+
+    <div class="mb-2" v-if="needReview">
       <el-button
         v-for="item in menus"
         :key="item.id"
@@ -78,19 +90,20 @@
       >
     </div>
     <div class="part-box part-box-pad part-box-border">
-      <!-- <component :is="curMenu.component"></component> -->
       <apply-content
+        v-if="modalIsShow"
+        v-show="curMenu.id === '1'"
         ref="ApplyContent"
         :exam-task="modalForm"
         :edit-type="editType"
-        v-show="curMenu.id === '1'"
         @cancel="cancel"
         @modified="modified"
       ></apply-content>
       <apply-audit-history
+        v-if="needReview"
+        v-show="curMenu.id === '2'"
         ref="ApplyAuditHistory"
         :exam-task-id="modalForm.id"
-        v-show="curMenu.id === '2'"
       ></apply-audit-history>
     </div>
 
@@ -101,6 +114,7 @@
 <script>
 import ApplyContent from "./ApplyContent";
 import ApplyAuditHistory from "./ApplyAuditHistory";
+import { commonRuleDetail } from "../../base/api";
 
 const initModalForm = {
   id: null,
@@ -118,6 +132,60 @@ const initModalForm = {
   reviewStatus: ""
 };
 
+const STEPS = [
+  {
+    title: "提交申请",
+    status: {
+      wait: {
+        desc: "待进行",
+        range: []
+      },
+      process: {
+        desc: "进行中",
+        range: ["NEW", "READY", "STAGE"]
+      },
+      success: {
+        desc: "已完成",
+        range: ["SUBMIT", "FINISH"]
+      }
+    }
+  },
+  {
+    title: "审核",
+    status: {
+      wait: {
+        desc: "待进行",
+        range: ["NEW", "READY", "STAGE"]
+      },
+      process: {
+        desc: "进行中",
+        range: ["SUBMIT"]
+      },
+      success: {
+        desc: "已完成",
+        range: ["FINISH"]
+      }
+    }
+  },
+  {
+    title: "入库",
+    status: {
+      wait: {
+        desc: "待进行",
+        range: ["NEW", "READY", "STAGE", "SUBMIT"]
+      },
+      process: {
+        desc: "进行中",
+        range: []
+      },
+      success: {
+        desc: "已完成",
+        range: ["FINISH"]
+      }
+    }
+  }
+];
+
 export default {
   name: "modify-task-apply",
   components: { ApplyContent, ApplyAuditHistory },
@@ -148,6 +216,9 @@ export default {
     return {
       modalIsShow: false,
       modalForm: {},
+      needReview: false,
+      steps: [],
+      actStep: "",
       menus: [
         { id: "1", name: "命题处理", component: "apply-content" },
         { id: "2", name: "审核意见", component: "apply-audit-history" }
@@ -155,9 +226,33 @@ export default {
       curMenu: {}
     };
   },
+  created() {
+    this.checkNeedReview();
+  },
   methods: {
+    async checkNeedReview() {
+      const commonRule = await commonRuleDetail();
+      this.needReview = commonRule && commonRule.review;
+    },
     initData(val) {
       this.modalForm = this.$objAssign(initModalForm, val);
+      this.buildSteps();
+    },
+    buildSteps() {
+      const curStatus = this.instance.status;
+      // 构建steps
+      const stepList = this.needReview ? STEPS : [STEPS[0], STEPS[2]];
+      this.steps = stepList.map(step => {
+        const validStepStatus = Object.keys(step.status).find(key =>
+          step.status[key].range.includes(curStatus)
+        );
+
+        return {
+          title: step.title,
+          status: validStepStatus,
+          desc: step.status[validStepStatus].desc
+        };
+      });
     },
     visibleChange() {
       this.initData(this.instance);

+ 13 - 7
src/modules/exam/components/UploadPaperDialog.vue

@@ -4,7 +4,7 @@
     :visible.sync="modalIsShow"
     :title="`上传${curConfig.title}`"
     top="10vh"
-    width="500px"
+    width="520px"
     :close-on-click-modal="false"
     :close-on-press-escape="false"
     append-to-body
@@ -18,6 +18,7 @@
         input-width="360px"
         :format="curConfig.format"
         :upload-url="uploadUrl"
+        :upload-data="curConfig.uploadData"
         @upload-error="uplaodError"
         @upload-success="uploadSuccess"
         ref="UploadFileView"
@@ -56,10 +57,15 @@ export default {
       modalIsShow: false,
       attachment: {},
       config: {
-        paper: { title: "试卷文件", format: ["pdf"] },
+        paper: {
+          title: "试卷文件",
+          format: ["pdf"],
+          uploadData: { type: "PAPER" }
+        },
         paperConfirm: {
           title: "入库审核表",
-          format: ["jpg", "png"]
+          format: ["jpg", "png"],
+          uploadData: { type: "UPLOAD" }
         }
       },
       curConfig: { format: [] },
@@ -82,12 +88,12 @@ export default {
         message: errorData.message
       });
     },
-    uploadSuccess(res) {
+    uploadSuccess(data) {
       this.$message.success("上传成功!");
       let infos = {
-        attachmentId: res.data.id,
-        filename: `${res.data.fileName}${res.data.fileType}`,
-        path: res.data.path
+        attachmentId: data.id,
+        filename: data.filename,
+        url: data.url
       };
       this.attachment = Object.assign(this.attachment, infos);
     },

+ 2 - 2
src/modules/exam/components/WaitTaskAudit.vue

@@ -65,7 +65,7 @@
 
 <script>
 import ModifyTaskApply from "./ModifyTaskApply";
-import { taskReviewListPage } from "../api";
+import { taskReviewUnauditedListPage } from "../api";
 
 export default {
   name: "wait-task-audit",
@@ -94,7 +94,7 @@ export default {
         pageNumber: this.current,
         pageSize: this.size
       };
-      const data = await taskReviewListPage(datas);
+      const data = await taskReviewUnauditedListPage(datas);
       this.tasks = data.records;
       this.total = data.total;
     },

+ 6 - 0
src/modules/exam/router.js

@@ -5,6 +5,7 @@ import ExamTaskManage from "./views/ExamTaskManage.vue";
 import TaskApplyManage from "./views/TaskApplyManage.vue";
 import TaskReviewManage from "./views/TaskReviewManage.vue";
 import TaskPaperManage from "./views/TaskPaperManage.vue";
+import DataTaskManage from "./views/DataTaskManage.vue";
 
 export default [
   {
@@ -36,5 +37,10 @@ export default [
     path: "/exam/task-paper-manage",
     name: "TaskPaperManage",
     component: TaskPaperManage
+  },
+  {
+    path: "/exam/data-task-manage",
+    name: "DataTaskManage",
+    component: DataTaskManage
   }
 ];

+ 25 - 0
src/modules/exam/store.js

@@ -0,0 +1,25 @@
+import { waitTaskListCount } from "./api";
+
+const state = {
+  waitTaskCount: 0
+};
+
+const mutations = {
+  setNotDoneTaskCount(state, waitTaskCount) {
+    state.waitTaskCount = waitTaskCount;
+  }
+};
+
+const actions = {
+  async updateWaitTaskCount({ commit }) {
+    const count = await waitTaskListCount();
+    commit("setNotDoneTaskCount", count);
+  }
+};
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+};

+ 258 - 0
src/modules/exam/views/DataTaskManage.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="data-task-manage">
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form ref="FilterForm" label-position="left" label-width="55px" inline>
+        <el-form-item label="状态:">
+          <el-select v-model="filter.status" placeholder="请选择" clearable>
+            <el-option
+              v-for="(val, key) in DATA_TASK_STATUS"
+              :key="key"
+              :value="key"
+              :label="val"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="类别:">
+          <el-select v-model="filter.type" placeholder="请选择" clearable>
+            <el-option
+              v-for="(val, key) in DATA_TASK_TYPE"
+              :key="key"
+              :value="key"
+              :label="val"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="数据结果:" label-width="85px">
+          <el-select v-model="filter.result" placeholder="请选择" clearable>
+            <el-option
+              v-for="(val, key) in DATA_TASK_RESULT"
+              :key="key"
+              :value="key"
+              :label="val"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="icon icon-search" @click="toPage(1)"
+            >查询</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          @click="toRemove('DELETE')"
+          >批量删除</el-button
+        >
+        <el-button
+          type="danger"
+          icon="el-icon-delete-solid"
+          @click="toRemove('CLEAR')"
+          >清空</el-button
+        >
+      </div>
+    </div>
+    <div class="part-box">
+      <el-table
+        ref="TableList"
+        :data="tasks"
+        border
+        stripe
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column
+          type="index"
+          label="序号"
+          width="70"
+          align="center"
+          :index="indexMethod"
+        ></el-table-column>
+        <el-table-column prop="schoolName" label="项目"></el-table-column>
+        <el-table-column prop="type" label="类别">
+          <template slot-scope="scope">
+            {{ scope.row.type | dataTaskTypeFilter }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态">
+          <template slot-scope="scope">
+            {{ scope.row.status | dataTaskStatusFilter }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="result" label="结果">
+          <template slot-scope="scope">
+            {{ scope.row.result | dataTaskResultFilter }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="createTime" label="创建时间" width="180">
+          <span slot-scope="scope">{{
+            scope.row.createTime | timestampFilter
+          }}</span>
+        </el-table-column>
+        <el-table-column prop="name" label="创建人"></el-table-column>
+        <el-table-column
+          class-name="action-column"
+          label="操作"
+          align="center"
+          width="120px"
+        >
+          <template slot-scope="scope">
+            <el-button
+              v-if="scope.row.hasReportFile"
+              class="btn-table-icon"
+              type="text"
+              icon="icon icon-edit"
+              :disabled="loading"
+              @click="toDonwloadLog(scope.row)"
+              title="导出日志"
+            ></el-button>
+            <el-button
+              v-if="scope.row.hasResultFile"
+              class="btn-table-icon"
+              type="text"
+              icon="icon icon-circle-right"
+              :disabled="loading"
+              @click="toDonwloadFile(scope.row)"
+              title="下载文件"
+            ></el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  DATA_TASK_STATUS,
+  DATA_TASK_TYPE,
+  DATA_TASK_RESULT
+} from "@/constants/enumerate";
+import { dataTaskList, removeDataTask } from "../api";
+import { download, randomCode } from "@/plugins/utils";
+
+export default {
+  name: "data-task-manage",
+  data() {
+    return {
+      filter: {
+        type: "",
+        status: "",
+        result: ""
+      },
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      DATA_TASK_STATUS,
+      DATA_TASK_TYPE,
+      DATA_TASK_RESULT,
+      tasks: [],
+      curTask: {},
+      multipleSelection: [],
+      loading: false
+    };
+  },
+  created() {
+    // this.toPage(1);
+  },
+  methods: {
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await dataTaskList(datas);
+      this.tasks = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+      this.multipleSelection = [];
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val.map(item => item.id);
+      console.log(this.multipleSelection);
+    },
+    toRemove(type) {
+      let tips = "";
+      if (type === "CLEAR") {
+        tips = "确定要清空所有任务吗?";
+      } else {
+        tips = "确定要删除选中的任务吗?";
+        if (!this.multipleSelection.length) {
+          this.$message.error("请选择要删除的记录!");
+          return;
+        }
+      }
+
+      this.$confirm(tips, "提示", {
+        cancelButtonClass: "el-button--danger is-plain",
+        confirmButtonClass: "el-button--primary",
+        type: "warning"
+      })
+        .then(async () => {
+          const data = await removeDataTask({
+            ids: type === "CLEAR" ? null : this.multipleSelection,
+            type: type === "CLEAR" ? "ALL" : null
+          }).catch(() => {});
+          if (!data) return;
+          this.$message.success("操作成功!");
+          this.deletePageLastItem();
+        })
+        .catch(() => {});
+    },
+    async toDonwloadLog(row) {
+      if (this.loading) return;
+
+      this.loading = true;
+      const res = await download({
+        type: "post",
+        url: this.GLOBAL.domain + "/api/admin/exam/task_review/export",
+        data: {
+          id: row.id
+        },
+        fileName: `${Date.now()}${randomCode()}.zip`,
+        header: this.getHeadIds()
+      }).catch(error => {
+        this.$message.error(error + "文件下载失败,请重新尝试!");
+      });
+      this.loading = false;
+      if (!res) return;
+      this.$message.success("文件下载成功!");
+    },
+    async toDonwloadFile(row) {
+      if (this.loading) return;
+
+      this.loading = true;
+      const res = await download({
+        type: "post",
+        url: this.GLOBAL.domain + "/api/admin/exam/task_review/export",
+        data: {
+          id: row.id
+        },
+        fileName: `${Date.now()}${randomCode()}.zip`,
+        header: this.getHeadIds()
+      }).catch(error => {
+        this.$message.error(error + "文件下载失败,请重新尝试!");
+      });
+      this.loading = false;
+      if (!res) return;
+      this.$message.success("文件下载成功!");
+    }
+  }
+};
+</script>

+ 12 - 5
src/modules/exam/views/ExamTaskManage.vue

@@ -110,7 +110,8 @@
           prop="specialty"
           label="适用专业(方向)"
         ></el-table-column>
-        <el-table-column prop="cardRuleName" label="题卡规则"></el-table-column>
+        <el-table-column prop="cardRuleName" label="题卡规则">
+        </el-table-column>
         <el-table-column
           prop="userName"
           label="命题老师"
@@ -144,6 +145,7 @@
         >
           <template slot-scope="scope">
             <el-button
+              v-if="scope.row.status !== 'FINISH'"
               class="btn-table-icon"
               type="text"
               :icon="
@@ -155,15 +157,17 @@
               :title="scope.row.enable ? '禁用' : '启用'"
             ></el-button>
             <el-button
-              v-if="scope.row.status === 'STAGE' || scope.row.status === 'NEW'"
+              v-if="
+                (scope.row.status === 'READY' && !scope.row.enable) ||
+                  scope.row.status === 'NEW'
+              "
               class="btn-table-icon"
               type="text"
               icon="icon icon-edit"
               @click="toEdit(scope.row)"
-              :title="scope.row.status === 'NEW' ? '更改' : '指派'"
+              :title="scope.row.status === 'NEW' ? '指派' : '更改'"
             ></el-button>
             <el-button
-              v-if="scope.row.status === 'SUBMIT'"
               class="btn-table-icon"
               type="text"
               icon="icon icon-circle-right"
@@ -290,13 +294,16 @@ export default {
         type: "warning"
       })
         .then(async () => {
-          const enable = Number(!row.enable);
+          const enable = !row.enable;
           await ableExamTask({
             id: row.id,
             enable
           });
           row.enable = enable;
           this.$message.success("操作成功!");
+          // 启用之后,更新列表。
+          // 因为禁用时会解绑题卡,影响命题任务状态。
+          if (enable) this.getList();
         })
         .catch(() => {});
     },

+ 4 - 6
src/modules/exam/views/TaskApplyManage.vue

@@ -127,11 +127,6 @@
             {{ scope.row.reviewStatus | reviewStatusFilter }}
           </template>
         </el-table-column>
-        <el-table-column prop="enable" label="启用/取消" width="100">
-          <template slot-scope="scope">
-            {{ scope.row.enable ? "启用" : "取消" }}
-          </template>
-        </el-table-column>
         <el-table-column
           class-name="action-column"
           label="操作"
@@ -159,7 +154,10 @@
               title="重新申请"
             ></el-button>
             <el-button
-              v-if="scope.row.auditStatus === 'NOT_AUDITED'"
+              v-if="
+                scope.row.auditStatus === 'NOT_AUDITED' &&
+                  scope.row.status === 'SUBMIT'
+              "
               class="btn-table-icon"
               type="text"
               icon="icon icon-close-act"

+ 5 - 2
src/modules/exam/views/TaskPaperManage.vue

@@ -54,14 +54,17 @@
           label="试卷编号"
           width="120"
         ></el-table-column>
-        <el-table-column prop="courseNameCode" label="课程(代码)">
+        <el-table-column prop="courseName" label="课程(代码)">
+          <template slot-scope="scope">
+            {{ scope.row.courseName }}({{ scope.row.courseCode }})
+          </template>
         </el-table-column>
         <el-table-column
           prop="specialty"
           label="适用专业(方向)"
         ></el-table-column>
         <el-table-column
-          prop="relatePaperType"
+          prop="paperType"
           label="卷型"
           width="100"
         ></el-table-column>

+ 9 - 3
src/modules/exam/views/TaskReviewManage.vue

@@ -245,7 +245,11 @@
 import ModifyTaskApply from "../components/ModifyTaskApply";
 import { AUDITING_RESULT, AUDITING_STATUS } from "@/constants/enumerate";
 import pickerOptions from "@/constants/datePickerOptions";
-import { taskReviewListPage, batchUpdateTaskReview } from "../api";
+import {
+  taskReviewAuditedListPage,
+  taskReviewUnauditedListPage,
+  batchUpdateTaskReview
+} from "../api";
 import { download, randomCode } from "@/plugins/utils";
 
 export default {
@@ -300,7 +304,6 @@ export default {
     async getList() {
       const datas = {
         ...this.filter,
-        auditStatus: this.auditStatus,
         pageNumber: this.current,
         pageSize: this.size
       };
@@ -308,7 +311,10 @@ export default {
         datas.startTime = this.createTime[0];
         datas.endTime = this.createTime[1];
       }
-      const data = await taskReviewListPage(datas);
+      const func = this.AUDITED
+        ? taskReviewAuditedListPage
+        : taskReviewUnauditedListPage;
+      const data = await func(datas);
       this.examTasks = data.records;
       this.total = data.total;
     },

+ 4 - 6
src/modules/exam/views/WaitTask.vue

@@ -30,17 +30,15 @@ export default {
   components: { WaitTaskExam, WaitTaskAudit, WaitTaskExamTask },
   data() {
     return {
-      userRoles: this.$ls.get("user", { roles: [] }).roles
+      userRoles: this.$ls.get("user", { roleList: [] }).roleList
     };
   },
   computed: {
     IS_QUESTION_TEACHER() {
-      return !!this.userRoles.filter(item => item.type === "QUESTION_TEACHER")
-        .length;
+      return this.userRoles.includes("QUESTION_TEACHER");
     },
     IS_EXAM_TEACHER() {
-      return !!this.userRoles.filter(item => item.type === "EXAM_TEACHER")
-        .length;
+      return this.userRoles.includes("EXAM_TEACHER");
     },
     colSpan() {
       const modules = [
@@ -49,7 +47,7 @@ export default {
         this.IS_EXAM_TEACHER
       ];
       const moduleCount = modules.filter(item => item).length;
-      return 24 / moduleCount;
+      return Math.floor(24 / moduleCount);
     }
   },
   methods: {}

+ 8 - 2
src/modules/login/api.js

@@ -6,8 +6,8 @@ export const login = datas => {
 export const getSmsCode = mobileNumber => {
   return $post("/api/admin/common/get_verify_code", { mobileNumber });
 };
-export const logout = userId => {
-  return $post("/api/admin/common/logout", { userId });
+export const logout = () => {
+  return $post("/api/admin/common/logout", {});
 };
 export const sysMenu = () => {
   return $postParam("/api/admin/common/get_menu", {});
@@ -21,3 +21,9 @@ export const getEnums = type => {
 export const schoolList = () => {
   return $postParam("/api/admin/common/school/list", {});
 };
+export const getSchoolInfo = code => {
+  return $postParam("/api/admin/common/school/query_by_school_code", { code });
+};
+export const getSysConfig = key => {
+  return $postParam("/api/admin/common/sys_config/get_one", { key });
+};

+ 40 - 16
src/modules/login/views/Login.vue

@@ -2,7 +2,8 @@
   <div class="login login-box">
     <div class="login-body" @keyup.enter="submit('loginForm')">
       <div class="login-title">
-        <h1>逸教云</h1>
+        <img v-if="schoolLogo" :src="schoolLogo" alt="学校logo" />
+        <h1 v-else>分布式印刷</h1>
       </div>
       <div class="login-form">
         <el-form ref="loginForm" :model="loginModel" :rules="loginRules">
@@ -25,7 +26,7 @@
               <i class="icon icon-lock" slot="prefix"></i
             ></el-input>
           </el-form-item>
-          <el-form-item prop="code">
+          <el-form-item prop="code" v-if="smsCodeRequired">
             <div class="vlcode">
               <div class="vlcode-right">
                 <el-button
@@ -45,6 +46,7 @@
               </div>
             </div>
           </el-form-item>
+          <el-form-item prop="schoolCode"></el-form-item>
           <el-form-item>
             <el-button
               style="width:100%;"
@@ -67,10 +69,10 @@
 
 <script>
 import { password, smscode } from "@/plugins/formRules";
-import { login, getSmsCode } from "../api";
-import { AES } from "@/plugins/crypto";
-
+import { login, getSmsCode, getSchoolInfo, getSysConfig } from "../api";
+import { Base64 } from "@/plugins/crypto";
 import ResetPwd from "@/modules/base/components/ResetPwd";
+import { ORG_CODE } from "@/constants/app";
 
 const wstorage = {
   set(key, value, expire = null) {
@@ -96,13 +98,16 @@ export default {
   data() {
     return {
       nameWaitTime,
+      smsCodeRequired: false,
       loginModel: {
+        schoolCode: ORG_CODE,
         loginName: "",
         code: "qmth",
         password: ""
       },
       loginRules: {
         code: smscode,
+        password,
         loginName: [
           {
             required: true,
@@ -110,10 +115,17 @@ export default {
             trigger: "change"
           }
         ],
-        password
+        schoolCode: [
+          {
+            required: true,
+            message: "学校编码缺失",
+            trigger: "change"
+          }
+        ]
       },
       roles: [],
       isSubmit: false,
+      schoolLogo: "",
       // code
       isFetchingCode: false,
       codeContent: "获取验证码",
@@ -124,8 +136,19 @@ export default {
   mounted() {
     this.$ls.clear();
     this.setWaitingTime();
+    this.getSchool();
+    this.getSmsCodeRequired();
   },
   methods: {
+    async getSmsCodeRequired() {
+      const data = await getSysConfig("sys.code.enable");
+      this.smsCodeRequired = data.configValue === "true";
+    },
+    async getSchool() {
+      const data = await getSchoolInfo(ORG_CODE);
+      this.$ls.set("schoolLogo", data.logo);
+      this.schoolLogo = data.logo;
+    },
     async submit(name) {
       const valid = await this.$refs[name].validate().catch(() => {});
       if (!valid) return;
@@ -134,17 +157,18 @@ export default {
       this.isSubmit = true;
       const data = await login({
         loginName: this.loginModel.loginName,
-        password: AES(this.loginModel.password),
-        code: this.loginModel.code
+        password: Base64(this.loginModel.password),
+        code: this.smsCodeRequired ? this.loginModel.code : null,
+        schoolCode: this.loginModel.schoolCode
       }).catch(() => {});
       this.isSubmit = false;
       if (!data) return;
 
-      if (data.user.orgId)
-        this.$ls.set("orgId", data.user.orgId, this.GLOBAL.authTimeout);
-      if (data.user.schoolId)
-        this.$ls.set("schoolId", data.user.schoolId, this.GLOBAL.authTimeout);
-      this.$ls.set("user", data.user, this.GLOBAL.authTimeout);
+      if (data.orgInfo)
+        this.$ls.set("orgId", data.orgInfo.id, this.GLOBAL.authTimeout);
+      if (data.schoolInfo)
+        this.$ls.set("schoolId", data.schoolInfo.id, this.GLOBAL.authTimeout);
+      this.$ls.set("user", data, this.GLOBAL.authTimeout);
 
       // 强制修改密码
       // if (!data.user.pwdUpdateTime) {
@@ -152,10 +176,10 @@ export default {
       //   return;
       // }
 
-      this.$ls.set("token", data.token, this.GLOBAL.authTimeout);
-      this.$store.commit("setUser", data.user);
+      this.$ls.set("token", data.accessToken, this.GLOBAL.authTimeout);
+      this.$store.commit("setUser", data);
 
-      if (data.user.roles.includes("ADMIN")) {
+      if (data.roleList.includes("ADMIN")) {
         this.$router.push({
           name: "SelectSchool"
         });

+ 8 - 25
src/modules/login/views/SelectSchool.vue

@@ -7,21 +7,11 @@
       <div class="login-form">
         <el-form ref="modalFormComp" :model="modalForm" :rules="rules">
           <el-form-item prop="schoolId">
-            <el-select
+            <school-select
               v-model="modalForm.schoolId"
               style="width:100%;"
-              placeholder="请选择"
-              filterable
-              clearable
-            >
-              <el-option
-                v-for="item in schools"
-                :key="item.id"
-                :value="item.id"
-                :label="item.name"
-              >
-              </el-option>
-            </el-select>
+              @change="schoolChange"
+            ></school-select>
           </el-form-item>
           <el-form-item>
             <el-button style="width:100%;" type="primary" @click="confirm"
@@ -35,40 +25,33 @@
 </template>
 
 <script>
-import { schoolList } from "../api";
-
 export default {
   name: "select-school",
   data() {
     return {
       schools: [],
       modalForm: { schoolId: "" },
+      curSchool: {},
       rules: {
         schoolId: [{ required: true, message: "请选择学校", trigger: "change" }]
       }
     };
   },
-  created() {
-    this.getList();
-  },
   methods: {
-    async getList() {
-      this.schools = await schoolList();
+    schoolChange(school) {
+      this.curSchool = school;
     },
     async confirm() {
       const valid = await this.$refs.modalFormComp.validate().catch(() => {});
       if (!valid) return;
 
-      const curSchool = this.schools.find(
-        item => item.id === this.modalForm.schoolId
-      );
-
       this.$ls.set(
         "schoolId",
         this.modalForm.schoolId,
         this.GLOBAL.authTimeout
       );
-      this.$ls.set("schoolName", curSchool.name, this.GLOBAL.authTimeout);
+      this.$ls.set("schoolName", this.curSchool.name, this.GLOBAL.authTimeout);
+      this.$ls.set("schoolLogo", this.curSchool.logo, this.GLOBAL.authTimeout);
 
       this.$router.push({
         name: "Home"

+ 13 - 13
src/modules/print/api.js

@@ -7,11 +7,11 @@ export const printPlanQuery = param => {
 };
 // 考点模糊查询
 export const placeQuery = param => {
-  return $postParam("/api/admin/exam/print_data/place_query", { param });
+  return $postParam("/api/admin/exam/print/data_place_query", { param });
 };
 // 考场模糊查询
 export const roomQuery = param => {
-  return $postParam("/api/admin/exam/print_data/room_query", { param });
+  return $postParam("/api/admin/exam/print/data_room_query", { param });
 };
 
 // print-plan
@@ -29,41 +29,41 @@ export const printPlanTemplateList = datas => {
 };
 // business-data-export
 export const businessDataListPage = datas => {
-  return $postParam("/api/admin/exam/print_data/list", datas);
+  return $postParam("/api/admin/exam/print/data_list", datas);
 };
 export const businessTotalData = datas => {
-  return $postParam("/api/admin/exam/print_data/total", datas);
+  return $postParam("/api/admin/exam/print/data_total", datas);
 };
 
 // business-data-detail
 export const businessDataDetailListPage = datas => {
-  return $postParam("/api/admin/exam/print_data/detail", datas);
+  return $postParam("/api/admin/exam/print/data_detail", datas);
 };
 
 // plan-link-paper
 export const planLinkPaperListPage = datas => {
-  return $postParam("/api/admin/exam/print_relate/list", datas);
+  return $postParam("/api/admin/exam/print/relate_list", datas);
 };
 export const updatePlanLinkPaper = datas => {
-  return $post("/api/admin/exam/print_relate/update", datas);
+  return $post("/api/admin/exam/print/relate_update", datas);
 };
 export const linkPaperNumberList = datas => {
-  return $postParam("/api/admin/exam/print_relate/get_paper_numbers", datas);
+  return $postParam("/api/admin/exam/print/relate_get_paper_numbers", datas);
 };
 
 // print-task-manage
 export const printTaskListPage = datas => {
-  return $postParam("/api/admin/exam/print_task/list", datas);
+  return $postParam("/api/admin/exam/print/task_list", datas);
 };
 export const submitPrintTask = id => {
-  return $post("/api/admin/exam/print_task/submit", { id });
+  return $post("/api/admin/exam/print/task_submit", { id });
 };
 export const cancelPrintTask = id => {
-  return $post("/api/admin/exam/print_task/cancel", { id });
+  return $post("/api/admin/exam/print/task_cancel", { id });
 };
 export const printTaskTotalInfo = datas => {
-  return $postParam("/api/admin/exam/print_task/total", datas);
+  return $postParam("/api/admin/exam/print/task_total", datas);
 };
 export const getPrintTaskPdf = id => {
-  return $post("/api/admin/exam/print_task/view_pdf", { id });
+  return $post("/api/admin/exam/print/task_view_pdf", { id });
 };

+ 5 - 1
src/modules/print/views/BusinessDataExport.vue

@@ -66,6 +66,7 @@
           btn-type="warning"
           btn-content="导入"
           :upload-url="uploadUrl"
+          :upload-data="uploadData"
           :format="['xls', 'xlsx']"
           @upload-error="uplaodError"
           @upload-success="uploadSuccess"
@@ -176,7 +177,10 @@ export default {
       curPrintPlan: {},
       // import
       downloadUrl: "/temps/考务数据模板.xlsx",
-      uploadUrl: "/api/admin/sys/user/import"
+      uploadUrl: "/api/admin/sys/user/import",
+      uploadData: {
+        type: "FILE"
+      }
     };
   },
   computed: {

+ 8 - 12
src/plugins/axios.js

@@ -22,21 +22,18 @@ const mdData = datas => {
  * @param {Object} error 请求失败时的错误信息
  */
 const errorCallback = error => {
-  let message = "";
   if (error.response) {
-    message =
-      (error.response.data && error.response.data.message) || "服务错误";
-  } else if (error.request) {
-    message = "请求错误";
+    return errorDataCallback(error.response.data);
+  }
+
+  if (error.request) {
+    let message = "请求错误";
     if (error.message.indexOf("timeout") > -1) {
       message = "请求超时";
     }
-  } else {
-    return error;
+    Notification.error({ title: "错误提示", message });
   }
 
-  message = message.indexOf("###") !== -1 ? "参数错误" : message;
-  Notification.error({ title: "错误提示", message });
   return error;
 };
 
@@ -46,9 +43,8 @@ const errorCallback = error => {
  */
 const errorDataCallback = error => {
   let message = error.message || "数据错误";
-  message = message.indexOf("###") !== -1 ? "参数错误" : message;
 
-  if (error.code === 106) {
+  if (error.code === 4010006) {
     if (unauthMsgBoxIsShow) return error;
     unauthMsgBoxIsShow = true;
     message = "身份验证失效,请重新登录";
@@ -122,7 +118,7 @@ const $postParam = (url, datas, config = {}) => {
   const sqDatas = qs.stringify(mdData(datas), {
     arrayFormat: "brackets"
   });
-  url += "?" + sqDatas;
+  if (sqDatas) url += "?" + sqDatas;
 
   return axios
     .post(url, {}, config)

+ 14 - 9
src/plugins/crypto.js

@@ -1,15 +1,20 @@
 const CryptoJS = require("crypto-js");
 
-export const AES = content => {
-  return content;
-  // const key = CryptoJS.enc.Utf8.parse("1234567890123456");
+export const Base64 = content => {
+  const words = CryptoJS.enc.Utf8.parse(content);
+  const base64Str = CryptoJS.enc.Base64.stringify(words);
+
+  return base64Str;
+};
 
-  // const enstr = CryptoJS.AES.encrypt(content + "", key, {
-  //   mode: CryptoJS.mode.ECB,
-  //   padding: CryptoJS.pad.Pkcs7
-  // }).toString();
+export const AES = content => {
+  const KEY = "1234567890123456";
+  const IV = "1234567890123456";
 
-  // return enstr;
+  var key = CryptoJS.enc.Utf8.parse(KEY);
+  var iv = CryptoJS.enc.Utf8.parse(IV);
+  var encrypted = CryptoJS.AES.encrypt(content, key, { iv: iv });
+  return encrypted.toString();
 };
 
 /**
@@ -17,7 +22,7 @@ export const AES = content => {
  * @param {Object} infos 相关信息
  * @param {String} type 类别:secret、token两种
  */
-export const getAuthorisation = (infos, type) => {
+export const getAuthorization = (infos, type) => {
   // {type} {invoker}:base64(sha1(method&uri&timestamp&{secret}))
   const timestamp = Date.now();
   if (type === "secret") {

+ 13 - 1
src/plugins/filters.js

@@ -5,7 +5,10 @@ import {
   AUDITING_STATUS,
   AUDITING_RESULT,
   PRINT_PLAN_STATUS,
-  PRINT_STATUS
+  PRINT_STATUS,
+  DATA_TASK_STATUS,
+  DATA_TASK_TYPE,
+  DATA_TASK_RESULT
 } from "../constants/enumerate";
 import { formatDate } from "../plugins/utils";
 
@@ -41,6 +44,15 @@ Vue.filter("printPlanStatusFilter", function(val) {
 Vue.filter("printStatusFilter", function(val) {
   return PRINT_STATUS[val] || DEFAULT_FIELD;
 });
+Vue.filter("dataTaskTypeFilter", function(val) {
+  return DATA_TASK_TYPE[val] || DEFAULT_FIELD;
+});
+Vue.filter("dataTaskStatusFilter", function(val) {
+  return DATA_TASK_STATUS[val] || DEFAULT_FIELD;
+});
+Vue.filter("dataTaskResultFilter", function(val) {
+  return DATA_TASK_RESULT[val] || DEFAULT_FIELD;
+});
 Vue.filter("timestampFilter", function(val) {
   return val ? formatDate("YYYY-MM-DD HH:mm:ss", new Date(val)) : DEFAULT_FIELD;
 });

+ 5 - 1
src/plugins/globalVuePlugins.js

@@ -10,6 +10,8 @@ import CardRuleSelect from "../components/base/CardRuleSelect.vue";
 import CourseSelect from "../components/base/CourseSelect.vue";
 import PaperNumberSelect from "../components/base/PaperNumberSelect.vue";
 import QuestionTeacherSelect from "../components/base/QuestionTeacherSelect.vue";
+import QuestionTeacherUserSelect from "../components/base/QuestionTeacherUserSelect.vue";
+import SchoolSelect from "../components/base/SchoolSelect.vue";
 
 const components = {
   ViewFooter,
@@ -19,7 +21,9 @@ const components = {
   CardRuleSelect,
   CourseSelect,
   PaperNumberSelect,
-  QuestionTeacherSelect
+  QuestionTeacherSelect,
+  QuestionTeacherUserSelect,
+  SchoolSelect
 };
 
 export default {

+ 2 - 1
src/router.js

@@ -9,6 +9,7 @@ import login from "./modules/login/router";
 import base from "./modules/base/router";
 import exam from "./modules/exam/router";
 import print from "./modules/print/router";
+import customer from "./modules/customer/router";
 // card part
 import card from "./modules/card/router";
 
@@ -38,7 +39,7 @@ export default new Router({
       path: "/home",
       name: "Home",
       component: Home,
-      children: [...base, ...exam, ...print]
+      children: [...base, ...exam, ...print, ...customer]
     },
     { ...login },
     ...card,

+ 3 - 1
src/store.js

@@ -5,6 +5,7 @@ Vue.use(Vuex);
 
 // modules
 import card from "./modules/card/store";
+import exam from "./modules/exam/store";
 
 export default new Vuex.Store({
   state: {
@@ -17,6 +18,7 @@ export default new Vuex.Store({
   },
   actions: {},
   modules: {
-    card
+    card,
+    exam
   }
 });

+ 18 - 17
src/views/Home.vue

@@ -2,7 +2,8 @@
   <div class="home">
     <div class="home-header">
       <div class="head-logo">
-        <h1>分布式印刷</h1>
+        <img v-if="schoolLogo" :src="schoolLogo" alt="分布式印刷" />
+        <h1 v-else>分布式印刷</h1>
       </div>
       <div class="head-menu menu-list">
         <ul>
@@ -15,7 +16,7 @@
             ]"
             @click="toMenu(menu)"
           >
-            <i :class="['icon', `icon-${menu.name}`]"></i>
+            <i :class="menu.icon"></i>
             <span>{{ menu.title }}</span>
           </li>
         </ul>
@@ -23,18 +24,18 @@
       <div class="head-user menu-list">
         <ul>
           <li v-if="schoolName" @click="toSelectSchool" title="切换学校">
-            <i class="icon icon-home"></i>
+            <i class="el-icon-s-home"></i>
             <span>{{ schoolName }}</span>
           </li>
           <li
             class="menu-item menu-item-account"
             @click="$refs.ResetPwd.open()"
           >
-            <i class="icon icon-account"></i>
+            <i class="el-icon-s-custom"></i>
             <span :title="username">{{ username }}</span>
           </li>
           <li class="menu-item" @click="toLogout">
-            <i class="icon icon-shut"></i>
+            <i class="el-icon-switch-button"></i>
             <span>退出登录</span>
           </li>
         </ul>
@@ -94,7 +95,7 @@
         <div class="home-breadcrumb" v-if="breadcrumbs.length">
           <el-breadcrumb separator=">">
             <el-breadcrumb-item>
-              <i class="icon icon-home" style="margin-top: -2px;"></i>
+              <i class="el-icon-s-home" style="margin-top: -2px;"></i>
             </el-breadcrumb-item>
             <el-breadcrumb-item
               v-for="(bread, index) in breadcrumbs"
@@ -120,10 +121,10 @@
 </template>
 
 <script>
-// import { mapState, mapActions } from "vuex";
+import { mapState, mapActions } from "vuex";
 import localNavs from "@/constants/navs";
 import { deepCopy } from "@/plugins/utils";
-import { sysMenu } from "../modules/login/api";
+import { sysMenu, logout } from "../modules/login/api";
 import ResetPwd from "../modules/base/components/ResetPwd";
 
 export default {
@@ -137,9 +138,9 @@ export default {
       breadcrumbs: [],
       validRoutes: [],
       username: this.$ls.get("user", { realName: "" }).realName,
+      schoolLogo: this.$ls.get("schoolLogo"),
       schoolName: this.$ls.get("schoolName"),
-      menuDailogIsShow: false,
-      waitTaskCount: 0
+      menuDailogIsShow: false
     };
   },
   watch: {
@@ -149,15 +150,13 @@ export default {
     }
   },
   computed: {
-    // ...mapState("examCenter", ["waitTaskCount"]),
+    ...mapState("exam", ["waitTaskCount"])
   },
   created() {
     this.getMenus();
-    // this.menus = localNavs;
-    // this.actCurNav();
   },
   methods: {
-    // ...mapActions("examCenter", ["updateWaitTaskCount"]),
+    ...mapActions("exam", ["updateWaitTaskCount"]),
     getMenus() {
       this.menus = localNavs;
       if (this.$route.name === "Home") {
@@ -166,6 +165,7 @@ export default {
         });
       } else {
         this.actCurNav();
+        // this.updateWaitTaskCount();
       }
     },
     async getMenus1() {
@@ -216,6 +216,7 @@ export default {
       };
 
       this.validRoutes = validRoutes;
+      // TODO:只有设置需要审核的情况才能显示入库审核页面
 
       return { menus: anchorNav(navTree), firstRouter };
     },
@@ -273,7 +274,7 @@ export default {
         this.validRoutes.includes("WaitTask") &&
         this.curMenu.name === "exam"
       ) {
-        // this.updateWaitTaskCount();
+        this.updateWaitTaskCount();
       }
     },
     toLogout() {
@@ -287,8 +288,8 @@ export default {
         })
         .catch(() => {});
     },
-    logoutAction() {
-      // await logout(this.$ls.get("user", { id: "" }).id);
+    async logoutAction() {
+      await logout();
       this.$ls.clear();
       this.$router.push({ name: "Login" });
     },