zhangjie пре 1 година
родитељ
комит
1e78dcc9c7

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

@@ -436,7 +436,7 @@ body {
   color: $--color-primary;
   cursor: pointer;
   &:hover {
-    opacity: 0.9;
+    opacity: 0.8;
   }
 }
 .ml-1 {

+ 3 - 1
src/modules/stmms/api.js

@@ -39,7 +39,9 @@ export const examTransferUser = (datas) => {
 export const examSecretaryList = (datas = {}) => {
   return $postParam("/api/admin/exam/structure/list_secretary", datas);
 };
-
+export const examStructureStatus = (id) => {
+  return $postParam("/api/admin/exam/structure/get_structure_status", { id });
+};
 // score-archive
 export const scoreListPage = (datas) => {
   return $postParam("/api/admin/sync/score/list", datas);

+ 34 - 141
src/modules/stmms/components/markParam/MarkPaperGroup.vue

@@ -9,13 +9,7 @@
         <p class="tips-info tips-error">3.开始阅卷后不允许删除评卷分组!</p>
       </div>
       <div>
-        <span
-          ><i class="el-icon-success color-success"></i>评卷参数提交成功!</span
-        >
-        <span
-          ><i class="el-icon-success color-danger"></i>
-          评卷参数同步阅卷模块失败!</span
-        >
+        <mark-status field="group"></mark-status>
         <el-button type="primary" @click="toAdd">新增</el-button>
       </div>
     </div>
@@ -98,50 +92,15 @@
         </el-table-column>
       </el-table>
     </div>
-
-    <div class="mb-2">
-      <span>分班阅卷:</span>
-      <el-switch
-        v-model="openClassReading"
-        @change="openClassReadingChange"
-      ></el-switch>
-    </div>
-
-    <div v-if="openClassReading" class="part-box part-box-pad">
-      <el-table :data="markerClassList" border>
-        <el-table-column type="index" width="50"> </el-table-column>
-        <el-table-column label="评卷员" width="200">
-          <template slot-scope="scope">
-            <el-tag class="tag-spin" size="medium">
-              {{ scope.row.name }}({{ scope.row.orgName }})
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="评卷班级">
-          <template slot-scope="scope">
-            <el-tag
-              v-for="item in scope.row.className"
-              :key="item"
-              size="medium"
-              type="info"
-              class="mb-1 mr-1"
-            >
-              {{ item }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column class-name="action-column" label="操作" width="100">
-          <template slot-scope="scope">
-            <el-button
-              class="btn-primary"
-              type="text"
-              @click="toEditClass(scope.row)"
-              >选择班级</el-button
-            >
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
+    <mark-paper-class
+      v-if="checkPrivilege('button', 'OpenClassReading') && dataReady"
+      ref="MarkPaperClass"
+      :datas="{
+        groupInfo,
+        classInfo: datas.classInfo,
+        basicPaperInfo: datas.basicPaperInfo,
+      }"
+    ></mark-paper-class>
 
     <!-- ModifyMarkerQuestion -->
     <modify-marker-question
@@ -160,30 +119,25 @@
       :paper-list="paperList"
       @modified="areaModified"
     ></modify-mark-area>
-    <!-- SelectClassByCourse -->
-    <select-class-by-course
-      ref="SelectClassByCourse"
-      :filter-data="{
-        examId: datas.basicPaperInfo.examId,
-        paperNumber: datas.basicPaperInfo.paperNumber,
-      }"
-      :selected-ids="selectedClassIds"
-      :disable-ids="disabledClassIds"
-      @confirm="classSelected"
-    ></select-class-by-course>
   </div>
 </template>
 
 <script>
+import MarkStatus from "./MarkStatus.vue";
 import ModifyMarkerQuestion from "./ModifyMarkerQuestion.vue";
 import ModifyMarkArea from "./ModifyMarkArea.vue";
-import SelectClassByCourse from "../SelectClassByCourse.vue";
+import markPaperClass from "./markPaperClass.vue";
 import { examStructureFindJpg } from "../../api";
 import { cardDetail } from "../../../card/api";
 
 export default {
   name: "mark-paper-group",
-  components: { ModifyMarkerQuestion, ModifyMarkArea, SelectClassByCourse },
+  components: {
+    ModifyMarkerQuestion,
+    ModifyMarkArea,
+    MarkStatus,
+    markPaperClass,
+  },
   props: {
     datas: {
       type: Object,
@@ -213,13 +167,7 @@ export default {
       },
       paperList: [],
       cardPages: [],
-      // 分班阅卷
-      openClassReading: false,
-      markerClassList: [],
-      curMarkClass: {},
-      selectedClassIds: [],
-      disabledClassIds: [],
-      casheMarkerClass: {},
+      dataReady: false,
     };
   },
   filters: {
@@ -271,18 +219,7 @@ export default {
       this.objectiveQuestionCount =
         this.questionCount - this.subjectiveQuestionCount;
 
-      this.openClassReading = this.datas.basicPaperInfo.openClassReading;
-
-      if (this.openClassReading) {
-        this.markerClassList = this.datas.classInfo.map((item) => {
-          let nitem = { ...item };
-          nitem.className = nitem.className.split(",");
-          return nitem;
-        });
-        this.updateCasheMarkerClass();
-        this.initMarkerClassList();
-      }
-
+      this.dataReady = true;
       this.$emit("on-ready");
     },
     updateDisableQuestionIds(filterId) {
@@ -352,9 +289,7 @@ export default {
       this.updateGroupNumber();
 
       // 分班阅卷相关
-      if (!this.openClassReading) return;
-      this.updateCasheMarkerClass();
-      this.initMarkerClassList();
+      this.$refs.MarkPaperClass && this.$refs.MarkPaperClass.groupChange();
     },
     autoParsePictureConfigList(questions) {
       if (!questions.length) return [];
@@ -444,46 +379,6 @@ export default {
       if (pos === -1) return;
       this.groupInfo.splice(pos, 1, row);
     },
-    // 分班阅卷 --->
-    openClassReadingChange(val) {
-      if (val) {
-        this.initMarkerClassList();
-      } else {
-        this.updateCasheMarkerClass();
-        this.markerClassList = [];
-      }
-    },
-    initMarkerClassList() {
-      let markerClassList = [];
-      this.groupInfo.forEach((group) => {
-        group.markerList.forEach((marker) => {
-          markerClassList.push({
-            id: marker.id,
-            loginName: marker.loginName,
-            name: marker.name,
-            orgName: marker.orgName,
-            className: this.casheMarkerClass[marker.id] || [],
-          });
-        });
-      });
-      this.markerClassList = markerClassList;
-    },
-    updateCasheMarkerClass() {
-      let casheMarkerClass = {};
-      this.markerClassList.forEach((item) => {
-        casheMarkerClass[item.id] = item.className;
-      });
-      this.casheMarkerClass = casheMarkerClass;
-    },
-    toEditClass(row) {
-      this.curMarkClass = row;
-      this.selectedClassIds = row.className;
-      this.$refs.SelectClassByCourse.open();
-    },
-    classSelected(className) {
-      this.curMarkClass.className = className;
-    },
-    // 分班阅卷 end --->
     checkData() {
       let errorMessages = [];
 
@@ -497,12 +392,8 @@ export default {
         }
       });
 
-      if (this.openClassReading) {
-        this.markerClassList.forEach((item) => {
-          if (!item.className.length) {
-            errorMessages.push(`评卷员${item.name}的阅卷班级没有设置`);
-          }
-        });
+      if (this.$refs.MarkPaperClass) {
+        errorMessages.push(...this.$refs.MarkPaperClass.checkData());
       }
 
       if (errorMessages.length) {
@@ -514,19 +405,21 @@ export default {
       this.$emit("next-step");
     },
     getData() {
-      return {
+      let data = {
         groupInfo: this.groupInfo.map((item) => {
           return { ...item };
         }),
-        basicPaperInfo: Object.assign(this.datas.basicPaperInfo, {
-          openClassReading: this.openClassReading,
-        }),
-        classInfo: this.markerClassList.map((item) => {
-          let nitem = { ...item };
-          nitem.className = item.className.join();
-          return nitem;
-        }),
       };
+
+      if (this.$refs.MarkPaperClass) {
+        const { openClassReading, classInfo } =
+          this.$refs.MarkPaperClass.getData();
+        data.classInfo = classInfo;
+        data.basicPaperInfo = Object.assign(this.datas.basicPaperInfo, {
+          openClassReading,
+        });
+      }
+      return data;
     },
     updateData() {
       this.$emit("data-change", this.getData());

+ 5 - 0
src/modules/stmms/components/markParam/MarkPaperStructure.vue

@@ -10,6 +10,9 @@
           3.开始阅卷后不允许修改试卷结构,请确认清楚后再提交!
         </p>
       </div>
+      <div>
+        <mark-status field="structure"></mark-status>
+      </div>
     </div>
 
     <div class="part-box part-box-pad mb-0">
@@ -174,9 +177,11 @@
 <script>
 import { calcSum } from "@/plugins/utils";
 import { QUESTION_TYPE_LIST } from "@/constants/enumerate";
+import MarkStatus from "./MarkStatus.vue";
 
 export default {
   name: "mark-paper-structure",
+  components: { MarkStatus },
   props: {
     datas: {
       type: Object,

+ 60 - 17
src/modules/stmms/components/markParam/MarkParamMarker.vue

@@ -8,13 +8,7 @@
           </p>
         </div>
         <div>
-          <span
-            ><i class="el-icon-success color-success"></i>评卷员绑定成功!</span
-          >
-          <span
-            ><i class="el-icon-success color-danger"></i>
-            评卷员同步阅卷模块失败!</span
-          >
+          <mark-status field="marker"></mark-status>
         </div>
       </div>
 
@@ -54,12 +48,22 @@
           </el-table-column>
         </el-table>
       </div>
+
+      <mark-paper-class
+        v-if="checkPrivilege('button', 'OpenClassReading') && dataReady"
+        ref="MarkPaperClass"
+        :datas="{
+          groupInfo,
+          classInfo: markParamInfos.classInfo,
+          basicPaperInfo: markParamInfos.basicPaperInfo,
+        }"
+      ></mark-paper-class>
     </div>
 
     <div class="text-center mt-2">
-      <!-- <el-button type="primary" :disabled="loading" @click="submit"
+      <el-button type="primary" :disabled="loading" @click="submit"
         >提交</el-button
-      > -->
+      >
       <el-button @click="cancel">取消</el-button>
     </div>
 
@@ -79,11 +83,13 @@
 <script>
 import { mapState, mapMutations } from "vuex";
 import ModifyMarkerQuestion from "./ModifyMarkerQuestion";
+import MarkStatus from "./MarkStatus.vue";
+import markPaperClass from "./markPaperClass.vue";
 import { examBindMarker } from "../../api";
 
 export default {
   name: "mark-paper-marker",
-  components: { ModifyMarkerQuestion },
+  components: { ModifyMarkerQuestion, MarkStatus, markPaperClass },
   data() {
     return {
       questionCount: 0,
@@ -100,6 +106,8 @@ export default {
       },
       paperList: [],
       cardPages: [],
+      loading: false,
+      dataReady: false,
     };
   },
   filters: {
@@ -131,6 +139,7 @@ export default {
       this.subjectiveQuestionCount = this.subjectiveQuestionList.length;
       this.objectiveQuestionCount =
         this.questionCount - this.subjectiveQuestionCount;
+      this.dataReady = true;
     },
     updateDisableQuestionIds(filterId) {
       let groupInfo = this.groupInfo;
@@ -163,16 +172,45 @@ export default {
 
       this.updateDisableQuestionIds();
       this.updateGroupNumber();
-      await this.updateGroupMarker(row);
 
-      this.setMarkParamInfos({ groupInfo: this.groupInfo });
+      // 分班阅卷相关
+      this.$refs.MarkPaperClass && this.$refs.MarkPaperClass.groupChange();
     },
-    async updateGroupMarker(group) {
-      console.log(group);
-      await examBindMarker({
+    async submit() {
+      if (!this.checkData()) return;
+
+      if (this.loading) return;
+      this.loading = true;
+
+      let datas = {
         paperStructureId: this.markParamInfos.basicPaperInfo.id,
-        groupInfo: group,
-      });
+        groupInfo: this.groupInfo,
+      };
+      if (this.$refs.MarkPaperClass) {
+        const { openClassReading, classInfo } =
+          this.$refs.MarkPaperClass.getData();
+        datas.classInfo = classInfo;
+        datas.openClassReading = openClassReading;
+      }
+      const res = await examBindMarker(datas).catch(() => {});
+      this.loading = false;
+      if (!res) return;
+
+      let ndata = {
+        groupInfo: this.groupInfo,
+      };
+      if (datas["classInfo"]) {
+        ndata.classInfo = datas.classInfo;
+        ndata.basicPaperInfo = Object.assign(
+          this.markParamInfos.basicPaperInfo,
+          {
+            openClassReading: datas.openClassReading,
+          }
+        );
+      }
+      this.setMarkParamInfos(ndata);
+      this.$message.success("提交成功!");
+      this.$emit("confirm");
     },
     checkData() {
       let errorMessages = [];
@@ -181,10 +219,15 @@ export default {
         errorMessages.push("当前还有题目未设置评卷员");
       }
 
+      if (this.$refs.MarkPaperClass) {
+        errorMessages.push(...this.$refs.MarkPaperClass.checkData());
+      }
       if (errorMessages.length) {
         this.$message.error(errorMessages.join("。"));
         return;
       }
+
+      return true;
     },
     cancel() {
       this.$emit("cancel");

+ 24 - 15
src/modules/stmms/components/markParam/MarkParamMarkerLeader.vue

@@ -8,13 +8,7 @@
         <p class="tips-info">2.支持绑定多个科组长!</p>
       </div>
       <div>
-        <span
-          ><i class="el-icon-success color-success"></i>科组长绑定成功!</span
-        >
-        <span
-          ><i class="el-icon-success color-danger"></i>
-          科组长同步阅卷模块失败!</span
-        >
+        <mark-status field="markerLeader"></mark-status>
       </div>
     </div>
 
@@ -72,10 +66,12 @@
 <script>
 import { examBindMarkLeader } from "../../api";
 import SelectTypeUser from "../SelectTypeUser.vue";
+import { mapState, mapMutations } from "vuex";
+import MarkStatus from "./MarkStatus.vue";
 
 export default {
   name: "mark-param-marker-leader",
-  components: { SelectTypeUser },
+  components: { SelectTypeUser, MarkStatus },
   props: {
     instance: {
       type: Object,
@@ -91,11 +87,18 @@ export default {
     };
   },
   computed: {
+    ...mapState("markParam", ["markLeader", "markParamInfos"]),
     curMarkLeaders() {
       return this.users.map((item) => item.id);
     },
   },
+  mounted() {
+    this.users = this.markLeader.map((item) => {
+      return { ...item };
+    });
+  },
   methods: {
+    ...mapMutations("markParam", ["setMarkLeader"]),
     toDeleteUser(user) {
       this.users = this.users.filter((item) => item.id !== user.id);
     },
@@ -114,18 +117,24 @@ export default {
       if (this.loading) return;
       this.loading = true;
 
+      const markLeader = this.users.map((item) => {
+        return {
+          id: item.id,
+          name: item.name,
+          orgName: item.orgName,
+          loginName: item.loginName,
+          label: item.label,
+        };
+      });
       const res = await examBindMarkLeader({
-        id: this.instance.id,
-        markLeader: this.users.map((item) => {
-          return {
-            id: item.id,
-            loginName: item.loginName,
-          };
-        }),
+        id: this.markParamInfos.basicPaperInfo.id,
+        markLeader,
       }).catch(() => {});
       this.loading = false;
       if (!res) return;
+      this.setMarkLeader(markLeader);
       this.$message.success("绑定成功!");
+      this.$emit("confirm");
     },
     cancel() {
       this.$emit("cancel");

+ 5 - 18
src/modules/stmms/components/markParam/MarkParamObjectiveAnswer.vue

@@ -8,14 +8,7 @@
         </p>
       </div>
       <div>
-        <span
-          ><i class="el-icon-success color-success"></i
-          >客观题标答提交成功!</span
-        >
-        <span
-          ><i class="el-icon-success color-danger"></i>
-          客观题标答同步阅卷模块失败!</span
-        >
+        <mark-status field="objective"></mark-status>
       </div>
     </div>
 
@@ -115,17 +108,11 @@ import { QUESTION_SCORE_TYPE } from "@/constants/enumerate";
 import { updateObjectiveAnswer } from "../../api";
 import { mapState, mapMutations } from "vuex";
 import { deepCopy } from "@/plugins/utils";
+import MarkStatus from "./MarkStatus.vue";
 
 export default {
   name: "modify-objective-answer",
-  props: {
-    instance: {
-      type: Object,
-      default() {
-        return {};
-      },
-    },
-  },
+  components: { MarkStatus },
   data() {
     return {
       loading: false,
@@ -135,7 +122,7 @@ export default {
     };
   },
   computed: {
-    ...mapState("markParam", ["objectiveStructure"]),
+    ...mapState("markParam", ["objectiveStructure", "markParamInfos"]),
   },
   mounted() {
     this.initData();
@@ -254,7 +241,7 @@ export default {
       if (this.loading) return;
       this.loading = true;
       const datas = {
-        id: this.instance.id,
+        id: this.markParamInfos.basicPaperInfo.id,
         objectiveStructure: this.tableData.map((item) => {
           let nitem = { ...item };
           delete nitem.errMsg;

+ 0 - 8
src/modules/stmms/components/markParam/MarkParamStructure.vue

@@ -60,14 +60,6 @@ const STEPS_LIST = [
 export default {
   name: "mark-param-structure",
   components: { MarkPaperGroup, MarkPaperStructure },
-  props: {
-    instance: {
-      type: Object,
-      default() {
-        return {};
-      },
-    },
-  },
   data() {
     return {
       infos: {

+ 35 - 19
src/modules/stmms/components/markParam/MarkParamUploadAnswer.vue

@@ -9,20 +9,15 @@
         <p class="tips-info">3.支持重复提交,以最后一次提交标答文件为准。</p>
       </div>
       <div>
-        <span
-          ><i class="el-icon-success color-success"></i
-          >主观题标答提交成功!</span
-        >
-        <span
-          ><i class="el-icon-success color-danger"></i>
-          主观题标答同步阅卷模块失败!</span
-        >
+        <mark-status field="answerFile"></mark-status>
       </div>
     </div>
     <div class="part-box part-box-pad">
       <el-form ref="modalFormComp" :model="infos" label-width="50px">
         <div class="part-box">
-          <h3 class="mb-2">卷型{{ instance.paperType }}</h3>
+          <h3 class="mb-2">
+            卷型{{ markParamInfos.basicPaperInfo.paperType }}
+          </h3>
           <el-form-item prop="file" label="标答:">
             <select-file
               :format="fileFormat"
@@ -30,6 +25,15 @@
               @file-change="fileChange"
             ></select-file>
           </el-form-item>
+          <el-form-item v-if="answerFileUrl">
+            <span
+              class="cont-link"
+              title="点击查看已上传标答文件"
+              @click="toViewAnswer"
+            >
+              <i class="el-icon-document mr-1"></i>{{ answerFileName }}
+            </span>
+          </el-form-item>
         </div>
       </el-form>
     </div>
@@ -43,20 +47,14 @@
 </template>
 
 <script>
+import { mapState } from "vuex";
 import { examStructureUploadAnswer } from "../../api";
 import SelectFile from "../SelectFile.vue";
+import MarkStatus from "./MarkStatus.vue";
 
 export default {
   name: "mark-param-upload-answer",
-  components: { SelectFile },
-  props: {
-    instance: {
-      type: Object,
-      default() {
-        return {};
-      },
-    },
-  },
+  components: { SelectFile, MarkStatus },
   data() {
     return {
       modalIsShow: false,
@@ -65,7 +63,25 @@ export default {
       fileFormat: ["pdf"],
     };
   },
+  computed: {
+    ...mapState("markParam", ["markParamInfos"]),
+    answerFileName() {
+      return `${this.markParamInfos.basicPaperInfo.courseName}-标答文件`;
+    },
+    answerFileUrl() {
+      const { paperType, paperAnswer } = this.markParamInfos.basicPaperInfo;
+      if (!paperAnswer) return;
+      const paperAnswerInfo = JSON.parse(paperAnswer);
+      const paper = paperAnswerInfo.find(
+        (item) => item.paperType === paperType
+      );
+      return paper ? paper.answerUrl : "";
+    },
+  },
   methods: {
+    toViewAnswer() {
+      window.open(this.answerFileUrl);
+    },
     fileChange(data) {
       if (data.errorMsg) {
         this.infos.file = null;
@@ -87,7 +103,7 @@ export default {
       this.loading = true;
 
       let formData = new FormData();
-      formData.append("id", this.instance.id);
+      formData.append("id", this.markParamInfos.basicPaperInfo.id);
       formData.append(`file`, this.infos.file);
       formData.append(`md5`, this.infos.md5);
       const data = await examStructureUploadAnswer(formData).catch(() => {});

+ 59 - 0
src/modules/stmms/components/markParam/MarkStatus.vue

@@ -0,0 +1,59 @@
+<template>
+  <div class="mark-status">
+    <span>
+      <i
+        :class="[
+          'el-icon-success',
+          status.save ? 'color-success' : 'color-danger',
+        ]"
+      ></i>
+      提交{{ status.save ? "成功" : "失败" }}
+    </span>
+    <span>
+      <i
+        :class="[
+          'el-icon-success',
+          status.save ? 'color-success' : 'color-danger',
+        ]"
+      ></i>
+      同步{{ status.sync ? "成功" : "失败" }}
+    </span>
+  </div>
+</template>
+
+<script>
+import { mapState } from "vuex";
+
+export default {
+  name: "mark-status",
+  props: {
+    field: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {};
+  },
+  computed: {
+    ...mapState("markParam", ["markStatus"]),
+    status() {
+      return (
+        this.markStatus[this.field] || {
+          save: false,
+          sync: false,
+        }
+      );
+    },
+  },
+  methods: {},
+};
+</script>
+
+<style scoped>
+.mark-status {
+  display: inline-block;
+  vertical-align: middle;
+  margin-right: 10px;
+}
+</style>

+ 25 - 2
src/modules/stmms/components/markParam/ModifyMarkParams.vue

@@ -32,7 +32,6 @@
       <component
         :is="currentComponent"
         def="MarkParamRef"
-        :instance="instance"
         @cancel="cancel"
         @confirm="confirm"
       ></component>
@@ -49,6 +48,7 @@ import MarkParamMarkerLeader from "./MarkParamMarkerLeader.vue";
 import MarkParamObjectiveAnswer from "./MarkParamObjectiveAnswer.vue";
 import MarkParamUploadAnswer from "./MarkParamUploadAnswer.vue";
 import { cardDetail } from "../../../card/api";
+import { examStructureStatus } from "../../api";
 
 export default {
   name: "modify-mark-params",
@@ -112,10 +112,17 @@ export default {
       return this.tabs.length - 1;
     },
   },
+  watch: {
+    curTab() {
+      this.updateMarkStatus();
+    },
+  },
   methods: {
     ...mapMutations("markParam", [
       "setMarkParamInfos",
       "setObjectiveStructure",
+      "setMarkStatus",
+      "setMarkLeader",
       "initStore",
     ]),
     async initData() {
@@ -151,6 +158,16 @@ export default {
         this.setMarkParamInfos(infos);
       }
 
+      if (this.instance.status) {
+        const data = JSON.parse(this.instance.status);
+        this.setMarkStatus(data);
+      }
+
+      if (this.instance.markLeader) {
+        const data = JSON.parse(this.instance.markLeader);
+        this.setMarkLeader(data);
+      }
+
       const objectiveStructure = JSON.parse(
         this.instance.objectiveStructure || "[]"
       );
@@ -158,7 +175,13 @@ export default {
 
       this.dataReady = true;
     },
+    async updateMarkStatus() {
+      const res = await examStructureStatus(this.instance.id).catch(() => {});
+      if (!res) return;
 
+      const data = JSON.parse(res);
+      this.setMarkStatus(data);
+    },
     parsePaperStructureFromCard(pages) {
       let structData = [];
       let curTopicId = 0;
@@ -265,7 +288,7 @@ export default {
     },
     confirm() {
       if (this.isLastStep) return;
-      this.selectMenu(this.tabs[this.current + 1]);
+      this.selectMenu(this.tabs[this.current + 1].val);
     },
   },
 };

+ 179 - 0
src/modules/stmms/components/markParam/markPaperClass.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="mark-paper-class">
+    <div class="box-justify mb-2">
+      <div>
+        <span>分班阅卷:</span>
+        <el-switch
+          v-model="openClassReading"
+          @change="openClassReadingChange"
+        ></el-switch>
+      </div>
+      <mark-status field="class"></mark-status>
+    </div>
+
+    <div v-if="openClassReading" class="part-box part-box-pad">
+      <el-table :data="markerClassList" border>
+        <el-table-column type="index" width="50"> </el-table-column>
+        <el-table-column label="评卷员" width="200">
+          <template slot-scope="scope">
+            <el-tag class="tag-spin" size="medium">
+              {{ scope.row.name }}({{ scope.row.orgName }})
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="评卷班级">
+          <template slot-scope="scope">
+            <el-tag
+              v-for="item in scope.row.className"
+              :key="item"
+              size="medium"
+              type="info"
+              class="mb-1 mr-1"
+            >
+              {{ item }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column class-name="action-column" label="操作" width="100">
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              @click="toEditClass(scope.row)"
+              >选择班级</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- SelectClassByCourse -->
+    <select-class-by-course
+      ref="SelectClassByCourse"
+      :filter-data="{
+        examId: datas.basicPaperInfo.examId,
+        paperNumber: datas.basicPaperInfo.paperNumber,
+      }"
+      :selected-ids="selectedClassIds"
+      :disable-ids="disabledClassIds"
+      @confirm="classSelected"
+    ></select-class-by-course>
+  </div>
+</template>
+
+<script>
+import SelectClassByCourse from "../SelectClassByCourse.vue";
+import MarkStatus from "./MarkStatus.vue";
+
+export default {
+  name: "mark-paper-class",
+  components: {
+    SelectClassByCourse,
+    MarkStatus,
+  },
+  props: {
+    datas: {
+      type: Object,
+      default() {
+        return {
+          classInfo: [],
+          groupInfo: [],
+          basicPaperInfo: {},
+        };
+      },
+    },
+  },
+  data() {
+    return {
+      openClassReading: false,
+      markerClassList: [],
+      curMarkClass: {},
+      selectedClassIds: [],
+      disabledClassIds: [],
+      casheMarkerClass: {},
+    };
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      this.openClassReading = this.datas.basicPaperInfo.openClassReading;
+      if (!this.openClassReading) return;
+
+      this.markerClassList = this.datas.classInfo.map((item) => {
+        let nitem = { ...item };
+        nitem.className = nitem.className ? nitem.className.split(",") : [];
+        return nitem;
+      });
+      this.updateCasheMarkerClass();
+      this.initMarkerClassList();
+    },
+    groupChange() {
+      if (!this.openClassReading) return;
+      this.updateCasheMarkerClass();
+      this.initMarkerClassList();
+    },
+    openClassReadingChange(val) {
+      if (val) {
+        this.initMarkerClassList();
+      } else {
+        this.updateCasheMarkerClass();
+        this.markerClassList = [];
+      }
+    },
+    initMarkerClassList() {
+      let markerClassList = [];
+      this.datas.groupInfo.forEach((group) => {
+        group.markerList.forEach((marker) => {
+          markerClassList.push({
+            id: marker.id,
+            loginName: marker.loginName,
+            name: marker.name,
+            orgName: marker.orgName,
+            className: this.casheMarkerClass[marker.id] || [],
+          });
+        });
+      });
+      this.markerClassList = markerClassList;
+    },
+    updateCasheMarkerClass() {
+      let casheMarkerClass = {};
+      this.markerClassList.forEach((item) => {
+        casheMarkerClass[item.id] = item.className;
+      });
+      this.casheMarkerClass = casheMarkerClass;
+    },
+    toEditClass(row) {
+      this.curMarkClass = row;
+      this.selectedClassIds = row.className;
+      this.$refs.SelectClassByCourse.open();
+    },
+    classSelected(className) {
+      this.curMarkClass.className = className;
+    },
+    checkData() {
+      let errorMessages = [];
+      if (!this.openClassReading) return;
+
+      this.markerClassList.forEach((item) => {
+        if (!item.className.length) {
+          errorMessages.push(`评卷员${item.name}的阅卷班级没有设置`);
+        }
+      });
+
+      return errorMessages;
+    },
+    getData() {
+      return {
+        openClassReading: this.openClassReading,
+        classInfo: this.markerClassList.map((item) => {
+          let nitem = { ...item };
+          nitem.className = item.className.join();
+          return nitem;
+        }),
+      };
+    },
+  },
+};
+</script>

+ 42 - 0
src/modules/stmms/components/markParam/store.js

@@ -1,5 +1,36 @@
 import { deepCopy } from "@/plugins/utils";
 
+const initMarkStatus = {
+  structure: {
+    save: false,
+    sync: false,
+  },
+  group: {
+    save: false,
+    sync: false,
+  },
+  class: {
+    save: false,
+    sync: false,
+  },
+  objective: {
+    save: false,
+    sync: false,
+  },
+  markerLeader: {
+    save: false,
+    sync: false,
+  },
+  marker: {
+    save: false,
+    sync: false,
+  },
+  answerFile: {
+    save: false,
+    sync: false,
+  },
+};
+
 const state = {
   markParamInfos: {
     basicPaperInfo: {},
@@ -9,6 +40,8 @@ const state = {
     structureCanEdit: false,
   },
   objectiveStructure: [],
+  markStatus: deepCopy(initMarkStatus),
+  markLeader: [],
 };
 
 const mutations = {
@@ -22,6 +55,14 @@ const mutations = {
   setObjectiveStructure(state, objectiveStructure) {
     state.objectiveStructure = objectiveStructure;
   },
+  setMarkStatus(state, markStatus) {
+    Object.keys(markStatus).forEach((k) => {
+      Object.assign(state.markStatus[k], markStatus[k] || {});
+    });
+  },
+  setMarkLeader(state, markLeader) {
+    state.markLeader = markLeader;
+  },
   initStore(state) {
     state.markParamInfos = {
       basicPaperInfo: {},
@@ -31,6 +72,7 @@ const mutations = {
       structureCanEdit: false,
     };
     state.objectiveStructure = [];
+    state.markStatus = deepCopy(initMarkStatus);
   },
 };
 

+ 1 - 0
src/modules/stmms/views/UploadStructure.vue

@@ -69,6 +69,7 @@
         >
           <template slot-scope="scope">
             <el-button
+              v-if="checkPrivilege('link', 'Submit')"
               class="btn-primary"
               type="text"
               :disabled="scope.row.taskStatus === 'RUNNING'"