浏览代码

评卷员打分

zhangjie 3 年之前
父节点
当前提交
36b0020f3c

+ 18 - 1
src/assets/styles/marker.less

@@ -265,7 +265,7 @@
   }
   .image-level {
     height: 26px;
-    width: 26px;
+    min-width: 26px;
     margin-right: 5px;
     border-radius: 5px;
     background-color: @color-background;
@@ -381,6 +381,20 @@
     }
   }
 
+  // marking
+  .action-mark-item {
+    color: @color-text;
+
+    &-content {
+      background: @color-background;
+
+      &:hover {
+        background-color: @color-act1;
+        color: @color-text-act;
+      }
+    }
+  }
+
   // iview-ui
   .ivu-btn-primary {
     color: @color-text-act;
@@ -416,6 +430,9 @@
       }
     }
   }
+  .ivu-form .ivu-form-item-label {
+    color: @color-text;
+  }
 }
 
 // marker-history

+ 6 - 1
src/constants/authority.js

@@ -215,7 +215,12 @@ export const checkRouterValid = (roleCode, routerName) => {
   const func = {
     SUPER_ADMIN: () => getAdminRouter(1),
     ADMIN: getAdminRouter,
-    MARKER: () => ["GradingOperation", "MarkOperation", "MarkerGrading"],
+    MARKER: () => [
+      "GradingOperation",
+      "MarkOperation",
+      "MarkerGrading",
+      "MarkerMarking"
+    ],
     MARK_LEADER: () => ["LeaderGrading", "leaderMark"],
     INSPECTION: () => inspection.map(item => item.name),
     QC: () => ["Quality"]

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

@@ -321,7 +321,9 @@ export default {
       this.setSteps({ levelStep, otherStep });
 
       if (!this.curStep.name) {
-        this.setCurStep(levelStep[0]);
+        const firstStep = otherStep.find(item => item.count);
+        const curStep = firstStep || levelStep[0];
+        this.setCurStep(curStep);
       } else {
         const curStep = [...levelStep, ...otherStep].find(
           item => item.name === this.curStep.name

+ 14 - 3
src/modules/grading/marker/MarkerHeader.vue

@@ -22,7 +22,7 @@
           </DropdownMenu>
         </Dropdown>
       </div>
-      <div class="header-part" @click="toStatistics">
+      <div v-if="showStatistics" class="header-part" @click="toStatistics">
         <p>统计分析 <Icon type="ios-arrow-down"></Icon></p>
       </div>
       <div class="header-part">
@@ -101,7 +101,8 @@
           @on-click="stepClick"
         >
           <span class="el-dropdown-link">
-            {{ curStep.name }}:{{ curStep.count }}
+            <i>{{ curStep.name }}</i>
+            <i v-if="showPaperRelateCount">:{{ curStep.count }}</i>
             <Icon type="ios-arrow-down"></Icon>
           </span>
           <DropdownMenu slot="list">
@@ -127,7 +128,7 @@
       <div v-if="IS_MARK_LEADER" class="header-part" @click="toProgress">
         <p>分档进度 <Icon type="ios-arrow-down"></Icon></p>
       </div>
-      <div class="header-part" @click="toStandard">
+      <div v-if="showStandard" class="header-part" @click="toStandard">
         <p>标准卷 <Icon type="ios-arrow-down"></Icon></p>
       </div>
       <div class="header-part header-history" @click="toHistory">
@@ -170,6 +171,16 @@ import ResetPwd from "@/modules/login/ResetPwd";
 export default {
   name: "marker-header",
   components: { ResetPwd },
+  props: {
+    showStandard: {
+      type: Boolean,
+      default: true
+    },
+    showStatistics: {
+      type: Boolean,
+      default: true
+    }
+  },
   data() {
     return {
       filter: {

+ 1 - 1
src/modules/grading/marker/MarkerHistory.vue

@@ -17,7 +17,7 @@
           <marker-image-view :data="paper" @to-review="toReview(index)">
             <div class="image-info">
               <div class="image-level">
-                {{ IS_MARK_LEADER ? paper.result : paper.level }}
+                {{ IS_MARK_LEADER ? paper.level : paper.result }}
               </div>
               <div class="image-action-name">{{ actionName }}</div>
             </div>

+ 15 - 1
src/modules/grading/marker/MarkerImageView.vue

@@ -7,7 +7,7 @@
     ></image-view-contain>
     <div class="image-view-footer">
       <slot>
-        <div class="image-info">
+        <div v-if="IS_LEVEL" class="image-info">
           <div v-if="image.level" class="image-level">{{ image.level }}</div>
           <div v-if="image.sample" class="image-sample">标</div>
           <div
@@ -26,6 +26,10 @@
             {{ image.title }}
           </div> -->
         </div>
+        <div v-else class="image-info">
+          <div v-if="image.level" class="image-level">{{ image.level }}</div>
+          <div v-if="image.score" class="image-level">{{ image.score }}</div>
+        </div>
         <div class="image-rotate" @click="toRotate">
           <Icon type="md-refresh-circle" />
         </div>
@@ -46,6 +50,15 @@ export default {
       default() {
         return {};
       }
+    },
+    stage: {
+      type: String,
+      default: "LEVEL"
+    }
+  },
+  computed: {
+    IS_LEVEL() {
+      return this.stage === "LEVEL";
     }
   },
   created() {
@@ -58,6 +71,7 @@ export default {
         thumbSrc: "",
         title: "",
         level: "",
+        score: "",
         deg: 0,
         sample: false,
         selected: false

+ 1 - 1
src/modules/login/LoginHome.vue

@@ -91,7 +91,7 @@ export default {
           router: "MarkerGrading"
         },
         MARKER_SCORE: {
-          router: "MarkOperation"
+          router: "MarkerMarking"
         },
         MARK_LEADER_LEVEL: {
           router: "LeaderGrading"

+ 493 - 0
src/modules/mark/marker/MarkerMarking.vue

@@ -0,0 +1,493 @@
+<template>
+  <div class="marker-marking marker-grading">
+    <marker-header
+      :show-standard="false"
+      :show-statistics="false"
+      @area-change="areaChange"
+      @step-change="stepChange"
+      @page-set-change="pageSetChange"
+      @to-history="toHistory"
+      @to-statistics="toStatistics"
+    ></marker-header>
+
+    <div
+      :class="[
+        'marker-action',
+        { 'marker-action-fullscreen': isFullscreenMarking }
+      ]"
+    >
+      <mark-action
+        :cur-paper-or-task="curPaper"
+        :levels="levels"
+        :show-count="showPaperRelateCount"
+        :params-set="paramsSet"
+        @on-leader-level="gradingCurPaper"
+        @on-select-score="scoreCurPaper"
+        @on-pass="passCurPaper"
+        ref="GradeAction"
+        v-if="curPaper.id"
+      ></mark-action>
+    </div>
+
+    <div class="marker-body">
+      <div :class="markerImageListClasses" v-if="papers.length">
+        <div
+          v-for="(paper, index) in papers"
+          :key="paper.id"
+          :class="[
+            'marker-image-item',
+            {
+              'marker-image-item-act': curPaperIndex === index
+            }
+          ]"
+        >
+          <div class="marker-image-content">
+            <marker-image-view
+              :data="paper"
+              :stage="stage"
+              @to-review="toReview(index)"
+            ></marker-image-view>
+          </div>
+        </div>
+      </div>
+      <div v-else class="marker-image-none">暂无数据</div>
+    </div>
+
+    <!-- MarkerHistory -->
+    <marker-history
+      :question-id="filter.questionId"
+      :stage="stage"
+      @on-paper-click="
+        (index, papers) => {
+          toViewCarouselPaper(index, papers, 'history');
+        }
+      "
+      ref="MarkerHistory"
+    ></marker-history>
+    <!-- image-preview -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toPrevPaper"
+      @on-next="toNextPaper"
+      @on-close="isFullscreenMarking = false"
+      ref="SimpleImagePreview"
+    ></simple-image-preview>
+    <!-- carousel paper review -->
+    <simple-image-preview
+      class="grading-operation-image-preview"
+      :cur-image="curPaper"
+      @on-prev="toCarousePaper('prev')"
+      @on-next="toCarousePaper('next')"
+      @on-close="carouseImagePreviewClose"
+      ref="CarouselPapersPreview"
+    ></simple-image-preview>
+  </div>
+</template>
+
+<script>
+import { mapState, mapMutations } from "vuex";
+import MarkerHeader from "../../grading/marker/MarkerHeader";
+import MarkAction from "../components/MarkAction";
+import SimpleImagePreview from "@/components/SimpleImagePreview";
+import MarkerImageView from "../../grading/marker/MarkerImageView";
+import MarkerHistory from "../../grading/marker/MarkerHistory";
+
+import {
+  getParamsSet,
+  markerTaskList,
+  markerChangeLevelPaperList,
+  markerScoreTotalStatData,
+  workLevelList,
+  paperSelectLevelOrScore,
+  markerManualScorePaperList,
+  paperTaskPass
+} from "@/api";
+
+export default {
+  name: "marker-marking",
+  components: {
+    MarkerHeader,
+    MarkerImageView,
+    MarkerHistory,
+    // MarkerStatistics,
+    MarkAction,
+    SimpleImagePreview
+  },
+  data() {
+    return {
+      filter: {
+        markerId: this.$ls.get("user").id,
+        questionId: ""
+      },
+      typeFilter: {
+        undo: {
+          sort: "paper.level",
+          stage: "SCORE"
+        },
+        done: {
+          level: "",
+          sort: "updatedOn,desc",
+          stage: "SCORE"
+        },
+        shift: {
+          isShift: true,
+          isShiftScore: false
+        },
+        shiftScore: {
+          isShift: false,
+          isShiftScore: true
+        },
+        manualScore: {}
+      },
+      stage: "SCORE",
+      workId: this.$route.params.workId,
+      subjectId: this.$route.params.subjectId,
+      subject: "",
+      workSubject: {},
+      curSubject: {},
+      curUserRoleType: "MARKER",
+      changeStage: 0, // 是否显示改档及改档打分
+      curStandardGradeId: "",
+      levels: [],
+      papers: [],
+      curPaper: {},
+      curPaperIndex: 0,
+      // carousel paper review,
+      carouselPapers: [],
+      curCarouselPaperIndex: 0,
+      isFullscreenMarking: false
+    };
+  },
+  computed: {
+    ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
+    markerImageListClasses() {
+      return ["marker-image-list", `marker-image-list-${this.page.size}`];
+    },
+    showPaperRelateCount() {
+      return !!this.paramsSet["showPaperCount"];
+    }
+  },
+  created() {
+    this.subject = this.subjectId.split("-")[1];
+    this.workSubject = {
+      workId: this.workId,
+      subject: this.subject
+    };
+    this.initData();
+  },
+  methods: {
+    ...mapMutations("marker", [
+      "setParamSet",
+      "setPage",
+      "setSteps",
+      "setCurArea",
+      "setCurStep",
+      "clearState"
+    ]),
+    async initData() {
+      await this.getParamsSetInfo();
+      await this.getWorkLevels();
+    },
+    async getParamsSetInfo() {
+      const data = await getParamsSet(this.workId);
+      this.setParamSet(data || {});
+      this.changeStage = this.paramsSet.changeStage;
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        ...this.typeFilter[this.curStep.type],
+        subject: this.subject,
+        workId: this.workId,
+        page: this.page.current - 1,
+        size: this.page.size
+      };
+      if (this.curStep.type === "done") {
+        datas.level = this.curStep.name;
+      }
+
+      let requestAction = null;
+      if (this.curStep.type.includes("shift")) {
+        requestAction = markerChangeLevelPaperList;
+      } else if (this.curStep.type === "manualScore") {
+        requestAction = markerManualScorePaperList;
+      } else {
+        requestAction = markerTaskList;
+      }
+
+      const data = await requestAction(datas);
+      this.papers = data.data.map(paper => {
+        paper.title = `NO.${paper.sn}`;
+        paper.score = paper.result;
+        return paper;
+      });
+      this.setPage({
+        total: data.totalCount,
+        totalPage: data.pageCount
+      });
+    },
+    async toPage(page) {
+      this.setPage({
+        current: page
+      });
+      await this.getList();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async getStepLevels() {
+      const data = await markerScoreTotalStatData(
+        this.filter.markerId,
+        this.filter.questionId
+      );
+      const undoIndex = data.findIndex(item => item.id === null);
+      let otherStep = [];
+      let undo = {
+        count: 0,
+        shift: 0,
+        shiftScore: 0
+      };
+      if (undoIndex !== -1) {
+        undo = { ...data[undoIndex] };
+        data.splice(undoIndex, 1);
+      }
+      otherStep.push({
+        name: "待评",
+        count: undo.count,
+        type: "undo"
+      });
+
+      if (this.changeStage) {
+        otherStep.push({
+          name: "改档",
+          count: undo.shift,
+          type: "shift"
+        });
+        otherStep.push({
+          name: "改档打分",
+          count: undo.shiftScore,
+          type: "shiftScore"
+        });
+      }
+
+      let levelStep = data
+        .filter(item => item.id !== "manualScore")
+        .map(item => {
+          return {
+            ...item,
+            name: item.id,
+            type: "done"
+          };
+        });
+      const msInfo = data.find(item => item.id === "manualScore");
+      if (msInfo) {
+        levelStep.push({
+          count: msInfo.count,
+          name: "输分试卷",
+          type: "manualScore"
+        });
+      }
+
+      this.setSteps({ levelStep, otherStep });
+      if (!this.curStep.name) {
+        let curStep = {};
+        if (undoIndex === -1) {
+          curStep = levelStep[0];
+        } else {
+          const firstStep = otherStep.find(item => item.count);
+          curStep = firstStep || levelStep[0];
+        }
+        this.setCurStep(curStep);
+      } else {
+        const curStep = [...levelStep, ...otherStep].find(
+          item => item.name === this.curStep.name
+        );
+        this.setCurStep(curStep);
+      }
+    },
+    updateStepLevel(curStep, curLevel, count = 1) {
+      if (curStep.type === "done") return;
+
+      const opos = this.steps.otherStep.findIndex(
+        item => item.type === curStep.type
+      );
+      this.steps.otherStep[opos].count -= count;
+
+      if (curStep.type === "shift") {
+        const spos = this.steps.otherStep.findIndex(
+          item => item.type === "shiftScore"
+        );
+        this.steps.otherStep[spos].count += count;
+      } else {
+        const pos = this.steps.levelStep.findIndex(
+          item => item.name === curLevel
+        );
+        this.steps.levelStep[pos].count += count;
+      }
+    },
+    async getWorkLevels() {
+      const data = await workLevelList(this.workId);
+      this.levels = data.map(item => {
+        return {
+          ...item,
+          name: item.code
+        };
+      });
+    },
+    pageSetChange() {
+      this.papers = [];
+      this.getList();
+    },
+    async stepChange(step) {
+      this.setCurStep(step);
+      this.setPage({ current: 1 });
+      this.isFullscreenMarking = false;
+      await this.getList();
+      this.getStepLevels();
+      if (this.papers.length) {
+        this.selectPaper(0);
+      } else {
+        this.curPaper = {};
+      }
+    },
+    async areaChange(curArea) {
+      this.setCurArea(curArea);
+      this.filter.questionId = curArea.id;
+      await this.getStepLevels();
+      this.toPage(1);
+    },
+    toReview(index) {
+      this.isFullscreenMarking = true;
+      this.selectPaper(index);
+      this.$refs.SimpleImagePreview.open();
+    },
+    selectPaper(index) {
+      let nindex = index;
+      if (!this.papers.length) {
+        nindex = 0;
+      } else if (index > this.papers.length - 1) {
+        nindex = this.papers.length - 1;
+      } else if (index < 0) {
+        nindex = 0;
+      }
+      const lastPaper = { ...this.curPaper };
+      this.curPaperIndex = nindex;
+      this.curPaper = this.papers[nindex] ? { ...this.papers[nindex] } : {};
+
+      // 待评时,检查当前试卷是否已经切换档位
+      if (
+        this.curStep.type === "undo" &&
+        this.curPaper["level"] &&
+        this.curPaper["level"] !== lastPaper["level"]
+      ) {
+        this.$Modal.info({
+          content: `即将打分档位:${this.curPaper.level}`
+        });
+      }
+    },
+    async toPrevPaper() {
+      if (this.curPaperIndex === 0) {
+        if (this.page.current > 1) {
+          this.setPage({ current: this.page.current - 1 });
+          this.curPaperIndex = this.page.size - 1;
+          await this.getList();
+        } else {
+          this.$Message.warning("当前已经是第一条数据了");
+          return;
+        }
+      } else {
+        this.curPaperIndex--;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async toNextPaper() {
+      if (this.curPaperIndex === this.papers.length - 1) {
+        if (this.page.current === this.page.totalPage) {
+          this.$Message.warning("当前已经是最后一条数据了");
+          return;
+        } else {
+          this.setPage({ current: this.page.current + 1 });
+          this.curPaperIndex = 0;
+          await this.getList();
+        }
+      } else {
+        this.curPaperIndex++;
+      }
+
+      this.selectPaper(this.curPaperIndex);
+    },
+    async toActionNextPaper() {
+      if (this.page.current > 1 && this.papers.length === 1) {
+        this.setPage({ current: this.page.current - 1 });
+        this.curPaperIndex = this.page.size;
+      }
+
+      await this.getList();
+      if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
+      this.selectPaper(this.curPaperIndex);
+    },
+    async gradingCurPaper({ selectedLevel }) {
+      await paperSelectLevelOrScore(
+        this.curPaper.id, // is taskId
+        selectedLevel,
+        "LEVEL"
+      );
+      this.updateStepLevel(this.curStep, "shiftScore");
+      this.toActionNextPaper();
+    },
+    async scoreCurPaper(info) {
+      const paper = await paperSelectLevelOrScore(
+        this.curPaper.id, // is taskId
+        info.score,
+        "SCORE",
+        info.manualScore
+      );
+      if (!paper) return;
+      this.updateStepLevel(this.curStep, this.curPaper.level);
+      this.toActionNextPaper();
+    },
+    async passCurPaper(level) {
+      await paperTaskPass(this.curPaper.id);
+      this.toActionNextPaper();
+    },
+    // paper carousel
+    toViewCarouselPaper(paperIndex, papers) {
+      this.isFullscreenMarking = true;
+      this.carouselPapers = papers;
+      this.selectCarouselPaper(paperIndex);
+      this.$nextTick(() => {
+        this.$refs.CarouselPapersPreview.open();
+      });
+    },
+    selectCarouselPaper(index) {
+      this.curCarouselPaperIndex = index;
+      this.curPaper = { ...this.carouselPapers[index] };
+    },
+    toCarousePaper(type) {
+      if (type === "prev" && this.curCarouselPaperIndex > 0) {
+        this.curCarouselPaperIndex--;
+      } else if (
+        type === "next" &&
+        this.curCarouselPaperIndex < this.carouselPapers.length - 1
+      ) {
+        this.curCarouselPaperIndex++;
+      }
+      this.selectCarouselPaper(this.curCarouselPaperIndex);
+    },
+    carouseImagePreviewClose() {
+      this.isFullscreenMarking = false;
+      this.selectPaper(this.curPaperIndex);
+    },
+    // header
+    toHistory() {
+      this.$refs.MarkerHistory.open();
+    },
+    toStatistics() {
+      this.$refs.MarkerStatistics.open();
+    }
+  },
+  beforeDestroy() {
+    this.clearState();
+  }
+};
+</script>

+ 9 - 0
src/routers/mark.js

@@ -9,6 +9,7 @@ import ExamPaperView from "../modules/main/ExamPaperView";
 
 // 阅卷员打分
 import MarkOperation from "../modules/mark/MarkOperation";
+import MarkerMarking from "../modules/mark/marker/MarkerMarking";
 
 const markRoutes = [
   {
@@ -77,5 +78,13 @@ export default [
     meta: {
       title: "阅卷员打分"
     }
+  },
+  {
+    path: "/marker-marking/:workId(\\d+)/:subjectId",
+    name: "MarkerMarking",
+    component: MarkerMarking,
+    meta: {
+      title: "阅卷员打分"
+    }
   }
 ];