瀏覽代碼

快捷键失效机制改造

zhangjie 2 年之前
父節點
當前提交
9067e23c2e

+ 14 - 6
src/modules/grading/components/GradeAction.vue

@@ -160,7 +160,7 @@
 <script>
 import { markHistoryList } from "@/api";
 import { CODE_TYPE } from "@/constants/enumerate";
-import { mapState } from "vuex";
+import { mapState, mapMutations } from "vuex";
 
 // 三种情况:
 // 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
@@ -317,7 +317,7 @@ export default {
     };
   },
   computed: {
-    ...mapState("marker", ["ribbonSet"]),
+    ...mapState("marker", ["ribbonSet", "shortcutKeyStatus"]),
     IS_ADMIN() {
       return this.curUserRoleType === "ADMIN";
     },
@@ -350,10 +350,17 @@ export default {
     "ribbonSet.keyboardMark": {
       immediate: true,
       handler(val) {
+        this.setShortcutStatus({ action: val });
+      }
+    },
+    "shortcutKeyStatus.action": {
+      immediate: true,
+      handler(val, oldval) {
+        // console.log(val, oldval);
+        if (val === oldval) return;
         if (val) {
           document.addEventListener("keydown", this.keyEvent);
         } else {
-          this.keyInput = null;
           document.removeEventListener("keydown", this.keyEvent);
         }
       }
@@ -376,6 +383,7 @@ export default {
     this.rebuildRight();
   },
   methods: {
+    ...mapMutations("marker", ["setShortcutStatus"]),
     getStepType() {
       const info = this.curPaperOrTask;
       if (info.sample) return "sample";
@@ -490,14 +498,14 @@ export default {
       if (this.btnClicked) return;
       // if (!this.ribbonSet.keyboardMark) return;
       if (!e.altKey && !e.shiftKey && !e.ctrlKey) {
-        const validKeys = ["F5", "ArrowLeft", "ArrowRight"];
-        if (validKeys.includes(e.key)) return;
-
         if (e.key === "Enter" && this.ribbonSet.needEnterSubmit) {
           e.preventDefault();
           this.toKeySubmit();
           return;
         }
+
+        if (!/^[a-z0-9]$/.test(e.key)) return;
+
         const keyInput = e.key.toUpperCase();
         if (this.getKeyInputLevel(keyInput)) {
           e.preventDefault();

+ 34 - 3
src/modules/grading/leader/LeaderGrading.vue

@@ -65,10 +65,14 @@
     <!-- LeaderStatistics -->
     <leader-statistics
       :question-id="filter.questionId"
+      @on-close="statisticsClose"
       ref="LeaderStatistics"
     ></leader-statistics>
     <!-- LeaderProgress -->
-    <leader-progress ref="LeaderProgress"></leader-progress>
+    <leader-progress
+      ref="LeaderProgress"
+      @on-close="progressClose"
+    ></leader-progress>
     <!-- MarkerHistory -->
     <marker-history
       :question-id="filter.questionId"
@@ -77,6 +81,7 @@
           toViewCarouselPaper(index, papers, 'history');
         }
       "
+      @on-close="historyClose"
       ref="MarkerHistory"
     ></marker-history>
     <!-- MarkerStandard -->
@@ -88,6 +93,7 @@
           toViewCarouselPaper(index, papers, 'sample');
         }
       "
+      @on-close="standardClose"
       ref="MarkerStandard"
       v-if="levels.length && filter.questionId"
     ></marker-standard>
@@ -105,7 +111,7 @@
       :cur-image="curPaper"
       @on-prev="toPrevPaper"
       @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
+      @on-close="imagePreviewClose"
       ref="SimpleImagePreview"
     ></simple-image-preview>
     <!-- carousel paper review -->
@@ -237,6 +243,7 @@ export default {
       "setCurArea",
       "setCurSubject",
       "setCurUserRoleType",
+      "setShortcut",
       "clearState"
     ]),
     initData() {
@@ -459,6 +466,7 @@ export default {
     },
     // paper view action
     toReview(data) {
+      this.setShortcut(["action"]);
       this.isFullscreenMarking = true;
       this.clearMultiplePaper();
       this.curPaperIndex = this.papers.findIndex(item => item.id === data.id);
@@ -594,6 +602,10 @@ export default {
         this.toActionNextPaper();
       }
     },
+    imagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.setShortcut(["page", "action"]);
+    },
     // paper carousel
     toViewCarouselPaper(paperIndex, papers, type) {
       this.carouselType = type;
@@ -602,6 +614,7 @@ export default {
       this.selectCarouselPaper(paperIndex);
       this.$nextTick(() => {
         this.$refs.CarouselPapersPreview.open();
+        this.setShortcut(["action"]);
       });
     },
     selectCarouselPaper(index) {
@@ -620,27 +633,45 @@ export default {
       this.selectCarouselPaper(this.curCarouselPaperIndex);
     },
     carouseImagePreviewClose() {
+      this.setShortcut([]);
       this.isFullscreenMarking = false;
       this.carouselType = "";
-      this.selectPaper(this.curPaperIndex);
     },
     // header
     toHistory() {
+      this.setShortcut([]);
       this.$refs.MarkerHistory.open();
     },
+    historyClose() {
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
+    },
     toStandard() {
+      this.setShortcut([]);
       this.$refs.MarkerStandard.open();
     },
+    standardClose() {
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
+    },
     toProgress() {
+      this.setShortcut([]);
       this.$refs.LeaderProgress.open();
     },
+    progressClose() {
+      this.setShortcut(["page", "action"]);
+    },
     toSelectAll(allSelected) {
       this.$refs.MarkerImageView.forEach(item => {
         item.changeSelect(allSelected);
       });
     },
     toStatistics() {
+      this.setShortcut([]);
       this.$refs.LeaderStatistics.open();
+    },
+    statisticsClose() {
+      this.setShortcut(["page", "action"]);
     }
   },
   beforeDestroy() {

+ 200 - 198
src/modules/grading/leader/LeaderProgress.vue

@@ -1,198 +1,200 @@
-<template>
-  <Modal
-    v-model="modalIsShow"
-    class="leader-progress marker-modal"
-    :title="title"
-    footer-hide
-    fullscreen
-    :transition-names="['slide-left', 'fade']"
-    @on-visible-change="visibleChange"
-  >
-    <div class="leader-progress-part">
-      <h3>总体</h3>
-      <table class="table table-dark">
-        <colgroup>
-          <col width="120" />
-          <col width="390" />
-          <col width="60" />
-        </colgroup>
-        <tr>
-          <th>区域</th>
-          <th>进度</th>
-          <th></th>
-        </tr>
-        <tr v-for="(item, aindex) in areaProgress" :key="aindex">
-          <td>{{ item.areaName }}</td>
-          <td>
-            <progress-line
-              :sum="item.totalCount"
-              :current="item.successCount"
-            ></progress-line>
-          </td>
-          <td class="td-nopad">{{ item.progress }}%</td>
-        </tr>
-      </table>
-    </div>
-
-    <div v-if="kzzInfo.length && IS_LEVEL" class="leader-progress-part">
-      <table class="table table-dark">
-        <tr v-for="(user, uindex) in kzzInfo" :key="uindex">
-          <td>科组长</td>
-          <td>{{ user.loginName }}</td>
-          <td>仲裁</td>
-          <td>{{ user.arbitrated }}</td>
-        </tr>
-      </table>
-    </div>
-
-    <div
-      v-for="(group, index) in groupMarkers"
-      :key="index"
-      class="leader-progress-part"
-    >
-      <div v-if="IS_LEVEL">
-        <div v-for="(kzz, kindex) in group.kzzProgress" :key="kindex">
-          科组长:{{ kzz.loginName }},仲裁:{{ kzz.arbitrated }}
-        </div>
-        <table class="table table-dark">
-          <colgroup>
-            <col width="120" />
-            <col width="310" />
-            <col width="60" />
-            <col width="80" />
-          </colgroup>
-          <tr>
-            <th>评卷员</th>
-            <th>进度</th>
-            <th></th>
-            <th>打回</th>
-          </tr>
-          <tr v-for="(item, aindex) in group.markerProgress" :key="aindex">
-            <td>{{ item.loginName }}</td>
-            <td>
-              <progress-line
-                :sum="item.totalCount"
-                :current="item.successCount"
-              ></progress-line>
-            </td>
-            <td class="td-nopad">{{ item.progress }}%</td>
-            <td>{{ item.rejectedCount }}</td>
-          </tr>
-        </table>
-      </div>
-
-      <div v-if="IS_SCORE">
-        <div v-for="(kzz, kindex) in group.kzzProgress" :key="kindex">
-          科组长:{{ kzz.loginName }}
-        </div>
-        <table class="table table-dark">
-          <colgroup>
-            <col width="120" />
-            <col width="210" />
-            <col width="60" />
-            <col width="80" />
-            <col width="100" />
-          </colgroup>
-          <tr>
-            <th>评卷员</th>
-            <th>进度</th>
-            <th></th>
-            <th>改档</th>
-            <th>改档打分</th>
-          </tr>
-          <tr v-for="(item, aindex) in group.markerProgress" :key="aindex">
-            <td>{{ item.loginName }}</td>
-            <td>
-              <progress-line
-                :sum="item.totalCount"
-                :current="item.successCount"
-              ></progress-line>
-            </td>
-            <td class="td-nopad">{{ item.progress }}%</td>
-            <td>{{ item.shiftCount }}</td>
-            <td>{{ item.shiftScoreCount }}</td>
-          </tr>
-        </table>
-      </div>
-    </div>
-  </Modal>
-</template>
-
-<script>
-import { mapState } from "vuex";
-import { markLeaderGradingProgressDetail } from "@/api";
-import ProgressLine from "../components/ProgressLine";
-
-export default {
-  name: "leader-progress",
-  components: { ProgressLine },
-  data() {
-    return {
-      modalIsShow: false,
-      kzzInfo: [],
-      totalProgress: {},
-      areaProgress: [],
-      groupMarkers: []
-    };
-  },
-  computed: {
-    ...mapState("marker", ["paramsSet", "curSubject"]),
-    IS_LEVEL() {
-      return this.curSubject.stage === "LEVEL";
-    },
-    IS_SCORE() {
-      return this.curSubject.stage === "SCORE";
-    },
-    title() {
-      return this.IS_LEVEL ? "分档进度" : "打分进度";
-    }
-  },
-  methods: {
-    visibleChange(visible) {
-      if (visible) {
-        this.initData();
-      }
-    },
-    async initData() {
-      const subjectId = this.$route.params.subjectId.split("-");
-      const data = await markLeaderGradingProgressDetail({
-        workId: subjectId[0],
-        subject: subjectId[1]
-      });
-      this.kzzInfo = data.kzz || [];
-      this.totalProgress = data.totalProgress;
-      const totalInfo = {
-        successCount: data.totalProgress.successCount,
-        totalCount: data.totalProgress.totalCount,
-        progress: data.totalProgress.progress.toFixed(2),
-        areaName: "总体进度"
-      };
-      if (this.curSubject.stage === "INIT") {
-        this.areaProgress = [totalInfo];
-        this.groupMarkers = [];
-      } else {
-        this.areaProgress = [totalInfo, ...this.addProgress(data.areaProgress)];
-        this.groupMarkers = data.groupMarkers.map(group => {
-          group.markerProgress = this.addProgress(group.markerProgress);
-          return group;
-        });
-      }
-    },
-    addProgress(data) {
-      return data.map(item => {
-        item.successCount = item.totalCount - item.leftCount;
-        item.progress = item.totalCount
-          ? ((100 * item.successCount) / item.totalCount).toFixed(2)
-          : "0.00";
-        return item;
-      });
-    },
-    cancel() {
-      this.modalIsShow = false;
-    },
-    open() {
-      this.modalIsShow = true;
-    }
-  }
-};
-</script>
+<template>
+  <Modal
+    v-model="modalIsShow"
+    class="leader-progress marker-modal"
+    :title="title"
+    footer-hide
+    fullscreen
+    :transition-names="['slide-left', 'fade']"
+    @on-visible-change="visibleChange"
+  >
+    <div class="leader-progress-part">
+      <h3>总体</h3>
+      <table class="table table-dark">
+        <colgroup>
+          <col width="120" />
+          <col width="390" />
+          <col width="60" />
+        </colgroup>
+        <tr>
+          <th>区域</th>
+          <th>进度</th>
+          <th></th>
+        </tr>
+        <tr v-for="(item, aindex) in areaProgress" :key="aindex">
+          <td>{{ item.areaName }}</td>
+          <td>
+            <progress-line
+              :sum="item.totalCount"
+              :current="item.successCount"
+            ></progress-line>
+          </td>
+          <td class="td-nopad">{{ item.progress }}%</td>
+        </tr>
+      </table>
+    </div>
+
+    <div v-if="kzzInfo.length && IS_LEVEL" class="leader-progress-part">
+      <table class="table table-dark">
+        <tr v-for="(user, uindex) in kzzInfo" :key="uindex">
+          <td>科组长</td>
+          <td>{{ user.loginName }}</td>
+          <td>仲裁</td>
+          <td>{{ user.arbitrated }}</td>
+        </tr>
+      </table>
+    </div>
+
+    <div
+      v-for="(group, index) in groupMarkers"
+      :key="index"
+      class="leader-progress-part"
+    >
+      <div v-if="IS_LEVEL">
+        <div v-for="(kzz, kindex) in group.kzzProgress" :key="kindex">
+          科组长:{{ kzz.loginName }},仲裁:{{ kzz.arbitrated }}
+        </div>
+        <table class="table table-dark">
+          <colgroup>
+            <col width="120" />
+            <col width="310" />
+            <col width="60" />
+            <col width="80" />
+          </colgroup>
+          <tr>
+            <th>评卷员</th>
+            <th>进度</th>
+            <th></th>
+            <th>打回</th>
+          </tr>
+          <tr v-for="(item, aindex) in group.markerProgress" :key="aindex">
+            <td>{{ item.loginName }}</td>
+            <td>
+              <progress-line
+                :sum="item.totalCount"
+                :current="item.successCount"
+              ></progress-line>
+            </td>
+            <td class="td-nopad">{{ item.progress }}%</td>
+            <td>{{ item.rejectedCount }}</td>
+          </tr>
+        </table>
+      </div>
+
+      <div v-if="IS_SCORE">
+        <div v-for="(kzz, kindex) in group.kzzProgress" :key="kindex">
+          科组长:{{ kzz.loginName }}
+        </div>
+        <table class="table table-dark">
+          <colgroup>
+            <col width="120" />
+            <col width="210" />
+            <col width="60" />
+            <col width="80" />
+            <col width="100" />
+          </colgroup>
+          <tr>
+            <th>评卷员</th>
+            <th>进度</th>
+            <th></th>
+            <th>改档</th>
+            <th>改档打分</th>
+          </tr>
+          <tr v-for="(item, aindex) in group.markerProgress" :key="aindex">
+            <td>{{ item.loginName }}</td>
+            <td>
+              <progress-line
+                :sum="item.totalCount"
+                :current="item.successCount"
+              ></progress-line>
+            </td>
+            <td class="td-nopad">{{ item.progress }}%</td>
+            <td>{{ item.shiftCount }}</td>
+            <td>{{ item.shiftScoreCount }}</td>
+          </tr>
+        </table>
+      </div>
+    </div>
+  </Modal>
+</template>
+
+<script>
+import { mapState } from "vuex";
+import { markLeaderGradingProgressDetail } from "@/api";
+import ProgressLine from "../components/ProgressLine";
+
+export default {
+  name: "leader-progress",
+  components: { ProgressLine },
+  data() {
+    return {
+      modalIsShow: false,
+      kzzInfo: [],
+      totalProgress: {},
+      areaProgress: [],
+      groupMarkers: []
+    };
+  },
+  computed: {
+    ...mapState("marker", ["paramsSet", "curSubject"]),
+    IS_LEVEL() {
+      return this.curSubject.stage === "LEVEL";
+    },
+    IS_SCORE() {
+      return this.curSubject.stage === "SCORE";
+    },
+    title() {
+      return this.IS_LEVEL ? "分档进度" : "打分进度";
+    }
+  },
+  methods: {
+    visibleChange(visible) {
+      if (visible) {
+        this.initData();
+      } else {
+        this.$emit("on-close");
+      }
+    },
+    async initData() {
+      const subjectId = this.$route.params.subjectId.split("-");
+      const data = await markLeaderGradingProgressDetail({
+        workId: subjectId[0],
+        subject: subjectId[1]
+      });
+      this.kzzInfo = data.kzz || [];
+      this.totalProgress = data.totalProgress;
+      const totalInfo = {
+        successCount: data.totalProgress.successCount,
+        totalCount: data.totalProgress.totalCount,
+        progress: data.totalProgress.progress.toFixed(2),
+        areaName: "总体进度"
+      };
+      if (this.curSubject.stage === "INIT") {
+        this.areaProgress = [totalInfo];
+        this.groupMarkers = [];
+      } else {
+        this.areaProgress = [totalInfo, ...this.addProgress(data.areaProgress)];
+        this.groupMarkers = data.groupMarkers.map(group => {
+          group.markerProgress = this.addProgress(group.markerProgress);
+          return group;
+        });
+      }
+    },
+    addProgress(data) {
+      return data.map(item => {
+        item.successCount = item.totalCount - item.leftCount;
+        item.progress = item.totalCount
+          ? ((100 * item.successCount) / item.totalCount).toFixed(2)
+          : "0.00";
+        return item;
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    }
+  }
+};
+</script>

+ 30 - 4
src/modules/grading/marker/MarkerGrading.vue

@@ -63,7 +63,7 @@
           toViewCarouselPaper(index, papers, 'history');
         }
       "
-      @on-close="getList"
+      @on-close="historyClose"
       ref="MarkerHistory"
     ></marker-history>
     <!-- MarkerStandard -->
@@ -75,18 +75,22 @@
           toViewCarouselPaper(index, papers, 'sample');
         }
       "
+      @on-close="standardClose"
       ref="MarkerStandard"
       v-if="levels.length && filter.questionId"
     ></marker-standard>
     <!-- MarkerStatistics -->
-    <marker-statistics ref="MarkerStatistics"></marker-statistics>
+    <marker-statistics
+      ref="MarkerStatistics"
+      @on-close="statisticsClose"
+    ></marker-statistics>
     <!-- image-preview -->
     <simple-image-preview
       class="grading-operation-image-preview"
       :cur-image="curPaper"
       @on-prev="toPrevPaper"
       @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
+      @on-close="imagePreviewClose"
       ref="SimpleImagePreview"
     ></simple-image-preview>
 
@@ -195,6 +199,7 @@ export default {
       "setCurArea",
       "setCurStep",
       "setCurUserRoleType",
+      "setShortcut",
       "clearState"
     ]),
     async initData() {
@@ -410,6 +415,7 @@ export default {
     },
     // paper view action
     toReview(data) {
+      this.setShortcut(["action"]);
       this.isFullscreenMarking = true;
       this.clearMultiplePaper();
       this.curPaperIndex = this.papers.findIndex(item => item.id === data.id);
@@ -496,6 +502,10 @@ export default {
       await paperTaskPass(this.curPaper.id);
       this.toActionNextPaper();
     },
+    imagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.setShortcut(["page", "action"]);
+    },
     // paper carousel
     toViewCarouselPaper(paperIndex, papers, type) {
       this.carouselType = type;
@@ -504,6 +514,7 @@ export default {
       this.selectCarouselPaper(paperIndex);
       this.$nextTick(() => {
         this.$refs.CarouselPapersPreview.open();
+        this.setShortcut(["action"]);
       });
     },
     selectCarouselPaper(index) {
@@ -533,20 +544,35 @@ export default {
       }
     },
     carouseImagePreviewClose() {
+      this.setShortcut([]);
       this.isFullscreenMarking = false;
       this.carouselType = "";
-      this.selectPaper(this.curPaperIndex);
     },
     // header
     toHistory() {
+      this.setShortcut([]);
       this.$refs.MarkerHistory.open();
     },
+    async historyClose() {
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
+    },
     toStandard() {
+      this.setShortcut([]);
       this.$refs.MarkerStandard.open();
     },
+    standardClose() {
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
+    },
     async toStatistics() {
+      this.setShortcut([]);
       await this.getStepLevels();
       this.$refs.MarkerStatistics.open();
+    },
+    statisticsClose() {
+      this.setShortcut(["page", "action"]);
     }
   },
   beforeDestroy() {

+ 15 - 2
src/modules/grading/marker/MarkerHeader.vue

@@ -316,7 +316,8 @@ export default {
       "curArea",
       "curSubject",
       "areas",
-      "IS_MARK_LEADER"
+      "IS_MARK_LEADER",
+      "shortcutKeyStatus"
     ]),
     stageName() {
       return this.curSubject.stage === "LEVEL" ? "分档" : "打分";
@@ -325,13 +326,25 @@ export default {
       return this.IS_MARK_LEADER && this.curSubject.stage === "SCORE";
     }
   },
+  watch: {
+    "shortcutKeyStatus.page": {
+      immediate: true,
+      handler(val, oldval) {
+        if (val === oldval) return;
+        if (val) {
+          document.addEventListener("keydown", this.keyEvent);
+        } else {
+          document.removeEventListener("keydown", this.keyEvent);
+        }
+      }
+    }
+  },
   mounted() {
     const subjectId = this.$route.params.subjectId.split("-");
     this.filter.workId = subjectId[0];
     this.filter.subject = subjectId[1];
     this.getAreaList();
     if (this.IS_MARK_LEADER) this.getLeaderMarkerList();
-    document.addEventListener("keydown", this.keyEvent);
 
     this.codeTypes = Object.entries(CODE_TYPE)
       .map(([key, val]) => {

+ 4 - 1
src/modules/grading/marker/MarkerStandard.vue

@@ -151,7 +151,10 @@ export default {
   },
   methods: {
     async visibleChange(visible) {
-      if (!visible) return;
+      if (!visible) {
+        this.$emit("on-close");
+        return;
+      }
 
       this.getPaperList();
     },

+ 104 - 103
src/modules/grading/marker/MarkerStatistics.vue

@@ -1,103 +1,104 @@
-<template>
-  <Modal
-    v-model="modalIsShow"
-    class="marker-statistics marker-modal"
-    title="统计分析"
-    footer-hide
-    fullscreen
-    @on-visible-change="visibleChange"
-  >
-    <div class="marker-statistics-table">
-      <table class="table table-dark">
-        <tr>
-          <th>档位</th>
-          <th>考区定档数量</th>
-          <th>考区内试卷总数</th>
-          <th>考区阈值</th>
-          <th>当前批次评卷员分档数量</th>
-          <th>当前批次试卷总数</th>
-          <!-- <th>当前批次阈值</th> -->
-        </tr>
-        <tr v-for="(step, sindex) in steps.levelStep" :key="sindex">
-          <td>{{ step.name }}</td>
-          <td>{{ step.gcount }}</td>
-          <td>{{ step.gpercent }}%</td>
-          <td>{{ step.pt }}%</td>
-          <td>{{ step.count }}</td>
-          <td>{{ step.percent }}%</td>
-          <!-- <td>{{ step.kdpt !== null ? step.kdpt + "%" : "" }}</td> -->
-        </tr>
-      </table>
-    </div>
-    <div class="marker-statistics-chart">
-      <h3>分档数量分布图</h3>
-      <echart-render
-        :chart-data="lineChartData"
-        chart-type="darkLines"
-        v-if="lineChartData"
-      ></echart-render>
-    </div>
-  </Modal>
-</template>
-
-<script>
-import { mapState } from "vuex";
-import EchartRender from "@/components/EchartRender";
-
-export default {
-  name: "marker-statistics",
-  components: { EchartRender },
-  data() {
-    return {
-      modalIsShow: false,
-      lineChartData: null
-    };
-  },
-  computed: {
-    ...mapState("marker", ["paramsSet", "steps"])
-  },
-  methods: {
-    visibleChange(visible) {
-      if (visible) {
-        this.initData();
-      } else {
-        this.lineChartData = null;
-      }
-    },
-    initData() {
-      const groups = [
-        {
-          key: "percent",
-          label: "当前批次评卷员"
-        },
-        {
-          key: "gpercent",
-          label: "考区定档"
-        }
-      ];
-      this.lineChartData = groups.map(group => {
-        const data = this.steps.levelStep.map(item => {
-          return {
-            name: item.name,
-            value: item[group.key]
-          };
-        });
-        return {
-          name: group.label,
-          data
-        };
-      });
-    },
-    cancel() {
-      this.modalIsShow = false;
-    },
-    open() {
-      this.modalIsShow = true;
-    },
-    stepClick(step) {
-      this.cancel();
-      this.$emit("step-change", step.name);
-    }
-  }
-};
-</script>
+<template>
+  <Modal
+    v-model="modalIsShow"
+    class="marker-statistics marker-modal"
+    title="统计分析"
+    footer-hide
+    fullscreen
+    @on-visible-change="visibleChange"
+  >
+    <div class="marker-statistics-table">
+      <table class="table table-dark">
+        <tr>
+          <th>档位</th>
+          <th>考区定档数量</th>
+          <th>考区内试卷总数</th>
+          <th>考区阈值</th>
+          <th>当前批次评卷员分档数量</th>
+          <th>当前批次试卷总数</th>
+          <!-- <th>当前批次阈值</th> -->
+        </tr>
+        <tr v-for="(step, sindex) in steps.levelStep" :key="sindex">
+          <td>{{ step.name }}</td>
+          <td>{{ step.gcount }}</td>
+          <td>{{ step.gpercent }}%</td>
+          <td>{{ step.pt }}%</td>
+          <td>{{ step.count }}</td>
+          <td>{{ step.percent }}%</td>
+          <!-- <td>{{ step.kdpt !== null ? step.kdpt + "%" : "" }}</td> -->
+        </tr>
+      </table>
+    </div>
+    <div class="marker-statistics-chart">
+      <h3>分档数量分布图</h3>
+      <echart-render
+        :chart-data="lineChartData"
+        chart-type="darkLines"
+        v-if="lineChartData"
+      ></echart-render>
+    </div>
+  </Modal>
+</template>
+
+<script>
+import { mapState } from "vuex";
+import EchartRender from "@/components/EchartRender";
+
+export default {
+  name: "marker-statistics",
+  components: { EchartRender },
+  data() {
+    return {
+      modalIsShow: false,
+      lineChartData: null
+    };
+  },
+  computed: {
+    ...mapState("marker", ["paramsSet", "steps"])
+  },
+  methods: {
+    visibleChange(visible) {
+      if (visible) {
+        this.initData();
+      } else {
+        this.lineChartData = null;
+        this.$emit("on-close");
+      }
+    },
+    initData() {
+      const groups = [
+        {
+          key: "percent",
+          label: "当前批次评卷员"
+        },
+        {
+          key: "gpercent",
+          label: "考区定档"
+        }
+      ];
+      this.lineChartData = groups.map(group => {
+        const data = this.steps.levelStep.map(item => {
+          return {
+            name: item.name,
+            value: item[group.key]
+          };
+        });
+        return {
+          name: group.label,
+          data
+        };
+      });
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    stepClick(step) {
+      this.cancel();
+      this.$emit("step-change", step.name);
+    }
+  }
+};
+</script>

+ 21 - 1
src/modules/grading/marker/store.js

@@ -14,7 +14,13 @@ const state = {
   ribbonSet: { keyboardMark: false, needEnterSubmit: true },
   curUserRoleType: "",
   IS_MARKER: false,
-  IS_MARK_LEADER: false
+  IS_MARK_LEADER: false,
+  // key shortcut:
+  shortcutKeyStatus: {
+    page: false,
+    action: false,
+    preview: false
+  }
 };
 const mutations = {
   setParamSet(state, paramsSet) {
@@ -46,6 +52,15 @@ const mutations = {
   setRibbonSet(state, ribbonSet) {
     state.ribbonSet = ribbonSet;
   },
+  setShortcutStatus(state, data) {
+    state.shortcutKeyStatus = Object.assign({}, state.shortcutKeyStatus, data);
+  },
+  setShortcut(state, types) {
+    Object.keys(state.shortcutKeyStatus).forEach(key => {
+      state.shortcutKeyStatus[key] = types.includes(key);
+    });
+    // console.log(JSON.stringify(state.shortcutKeyStatus));
+  },
   clearState(state) {
     state.paramsSet = {};
     state.page = {
@@ -61,6 +76,11 @@ const mutations = {
     state.curUserRoleType = "";
     state.IS_MARKER = false;
     state.IS_MARK_LEADER = false;
+    state.shortcutKeyStatus = {
+      page: false,
+      action: false,
+      preview: false
+    };
   }
 };
 

+ 17 - 5
src/modules/mark/components/MarkAction.vue

@@ -181,7 +181,7 @@
 <script>
 import { markHistoryList } from "@/api";
 import { CODE_TYPE, CHANGE_LEVEL_STATUS } from "@/constants/enumerate";
-import { mapState } from "vuex";
+import { mapState, mapMutations } from "vuex";
 
 // 三种情况:
 // 管理员(ADMIN),科组长(MARK_LEADER),评卷员(MARKER)
@@ -320,7 +320,7 @@ export default {
     };
   },
   computed: {
-    ...mapState("marker", ["ribbonSet"]),
+    ...mapState("marker", ["ribbonSet", "shortcutKeyStatus"]),
     IS_ADMIN() {
       return this.curUserRoleType === "ADMIN";
     },
@@ -338,10 +338,17 @@ export default {
     "ribbonSet.keyboardMark": {
       immediate: true,
       handler(val) {
+        this.setShortcutStatus({ action: val });
+      }
+    },
+    "shortcutKeyStatus.action": {
+      immediate: true,
+      handler(val, oldval) {
+        // console.log(val, oldval);
+        if (val === oldval) return;
         if (val) {
           document.addEventListener("keydown", this.keyEvent);
         } else {
-          this.keyInput = null;
           document.removeEventListener("keydown", this.keyEvent);
         }
       }
@@ -360,6 +367,7 @@ export default {
     this.rebuildRight();
   },
   methods: {
+    ...mapMutations("marker", ["setShortcutStatus"]),
     getStepType() {
       const paper = this.curPaperOrTask;
       if (paper.shift && paper.shiftScore && !paper.level && !paper.result)
@@ -477,10 +485,9 @@ export default {
     // keyboard submit
     keyEvent(e) {
       if (this.btnClicked) return;
+      this.$Message.destroy();
       // if (!this.ribbonSet.keyboardMark) return;
       if (!e.altKey && !e.shiftKey && !e.ctrlKey) {
-        if (e.key === "F5") return;
-        this.$Message.destroy();
         // 打分
         if (this.rights.levelList) {
           if (e.key === "Enter" && this.ribbonSet.needEnterSubmit) {
@@ -488,6 +495,9 @@ export default {
             this.toKeySubmitScore();
             return;
           }
+
+          if (!/^[a-z0-9]$/.test(e.key)) return;
+
           if (this.checkKeyCodeValid(e.keyCode)) {
             e.preventDefault();
             this.keyInput += e.key;
@@ -508,6 +518,8 @@ export default {
             this.toKeySubmitLevel();
             return;
           }
+          if (!/^[a-z0-9]$/.test(e.key)) return;
+
           const keyInput = e.key.toUpperCase();
           if (this.getKeyInputLevel(keyInput)) {
             e.preventDefault();

+ 22 - 6
src/modules/mark/leader/LeaderMarking.vue

@@ -9,7 +9,6 @@
       @page-set-change="pageSetChange"
       @to-progress="toProgress"
       @to-history="toHistory"
-      @to-statistics="toStatistics"
       @on-code-search="serachPaperByCode"
       @on-mark-search="serachMarkPaper"
     ></marker-header>
@@ -57,7 +56,10 @@
     </div>
 
     <!-- LeaderProgress -->
-    <leader-progress ref="LeaderProgress"></leader-progress>
+    <leader-progress
+      ref="LeaderProgress"
+      @on-close="progressClose"
+    ></leader-progress>
     <!-- MarkerHistory -->
     <marker-history
       :question-id="filter.questionId"
@@ -67,6 +69,7 @@
           toViewCarouselPaper(index, papers, 'history');
         }
       "
+      @on-close="historyClose"
       ref="MarkerHistory"
     ></marker-history>
     <!-- image-preview -->
@@ -75,7 +78,7 @@
       :cur-image="curPaper"
       @on-prev="toPrevPaper"
       @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
+      @on-close="imagePreviewClose"
       ref="SimpleImagePreview"
     ></simple-image-preview>
     <!-- carousel paper review -->
@@ -180,6 +183,7 @@ export default {
       "setCurStep",
       "setCurSubject",
       "setCurUserRoleType",
+      "setShortcut",
       "clearState"
     ]),
     initData() {
@@ -358,6 +362,7 @@ export default {
       this.toPage(1);
     },
     toReview(data) {
+      this.setShortcut(["action"]);
       this.isFullscreenMarking = true;
       this.curPaperIndex = this.papers.findIndex(item => item.id === data.id);
       this.curPaper = Object.assign({}, this.papers[this.curPaperIndex], data);
@@ -465,6 +470,10 @@ export default {
         }
       });
     },
+    imagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.setShortcut(["page", "action"]);
+    },
     // paper carousel
     toViewCarouselPaper(paperIndex, papers, type) {
       this.carouselType = type;
@@ -473,6 +482,7 @@ export default {
       this.selectCarouselPaper(paperIndex);
       this.$nextTick(() => {
         this.$refs.CarouselPapersPreview.open();
+        this.setShortcut(["action"]);
       });
     },
     selectCarouselPaper(index) {
@@ -491,19 +501,25 @@ export default {
       this.selectCarouselPaper(this.curCarouselPaperIndex);
     },
     carouseImagePreviewClose() {
+      this.setShortcut([]);
       this.carouselType = "";
       this.isFullscreenMarking = false;
-      this.selectPaper(this.curPaperIndex);
     },
     // header
     toHistory() {
+      this.setShortcut([]);
       this.$refs.MarkerHistory.open();
     },
-    toStatistics() {
-      this.$refs.MarkerStatistics.open();
+    historyClose() {
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
     },
     toProgress() {
+      this.setShortcut([]);
       this.$refs.LeaderProgress.open();
+    },
+    progressClose() {
+      this.setShortcut(["page", "action"]);
     }
   },
   beforeDestroy() {

+ 13 - 5
src/modules/mark/marker/MarkerMarking.vue

@@ -8,7 +8,6 @@
       @step-change="stepChange"
       @page-set-change="pageSetChange"
       @to-history="toHistory"
-      @to-statistics="toStatistics"
     ></marker-header>
 
     <div
@@ -65,6 +64,7 @@
           toViewCarouselPaper(index, papers, 'history');
         }
       "
+      @on-close="historyClose"
       ref="MarkerHistory"
     ></marker-history>
     <!-- image-preview -->
@@ -73,7 +73,7 @@
       :cur-image="curPaper"
       @on-prev="toPrevPaper"
       @on-next="toNextPaper"
-      @on-close="isFullscreenMarking = false"
+      @on-close="imagePreviewClose"
       ref="SimpleImagePreview"
     ></simple-image-preview>
     <!-- carousel paper review -->
@@ -210,6 +210,7 @@ export default {
       "setCurArea",
       "setCurStep",
       "setCurUserRoleType",
+      "setShortcut",
       "clearState"
     ]),
     initData() {
@@ -384,6 +385,7 @@ export default {
       this.toPage(1);
     },
     toReview(data) {
+      this.setShortcut(["action"]);
       this.isFullscreenMarking = true;
       this.curPaperIndex = this.papers.findIndex(item => item.id === data.id);
       this.curPaper = Object.assign({}, this.papers[this.curPaperIndex], data);
@@ -482,6 +484,10 @@ export default {
       await paperTaskPass(this.curPaper.id);
       this.toActionNextPaper();
     },
+    imagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.setShortcut(["page", "action"]);
+    },
     // paper carousel
     toViewCarouselPaper(paperIndex, papers, type) {
       this.carouselType = type;
@@ -490,6 +496,7 @@ export default {
       this.selectCarouselPaper(paperIndex);
       this.$nextTick(() => {
         this.$refs.CarouselPapersPreview.open();
+        this.setShortcut(["action"]);
       });
     },
     selectCarouselPaper(index) {
@@ -508,16 +515,17 @@ export default {
       this.selectCarouselPaper(this.curCarouselPaperIndex);
     },
     carouseImagePreviewClose() {
+      this.setShortcut([]);
       this.carouselType = "";
       this.isFullscreenMarking = false;
-      this.selectPaper(this.curPaperIndex);
     },
     // header
     toHistory() {
       this.$refs.MarkerHistory.open();
     },
-    toStatistics() {
-      this.$refs.MarkerStatistics.open();
+    historyClose() {
+      this.selectPaper(this.curPaperIndex);
+      this.setShortcut(["page", "action"]);
     }
   },
   beforeDestroy() {