浏览代码

复核:打回

Michael Wang 4 年之前
父节点
当前提交
4cb53e0c38

+ 19 - 0
src/api/inspectPage.ts

@@ -1,4 +1,5 @@
 import { httpApp } from "@/plugins/axiosApp";
+import { Question } from "@/types";
 
 /** 清理复核任务 */
 export async function clearInspectedTask(
@@ -92,3 +93,21 @@ export async function getInspectedHistory({
   form.append("pageSize", pageSize + "");
   return httpApp.post("/admin/exam/inspected/getHistory", form);
 }
+
+/** 保存复核任务 */
+export async function saveInspectedTask(studentId: string) {
+  const form = new FormData();
+  form.append("studentId", studentId);
+  return httpApp.post("/admin/exam/inspected/save", form);
+}
+
+/** 复核任务打回问题 */
+export async function rejectInspectedTask(
+  studentId: string,
+  questionList: Array<Question>
+) {
+  return httpApp.post("/admin/exam/inspected/rejected", {
+    studentId,
+    questionList,
+  });
+}

+ 36 - 3
src/components/inspect/Inspect.vue

@@ -4,25 +4,29 @@
     <div class="tw-flex tw-gap-1">
       <mark-history @reload="fetchTask" />
       <mark-body />
-      <!-- <mark-board-track v-if="showMarkBoardTrack" @submit="saveTaskToServer" /> -->
+      <MarkBoardInspect @inspect="saveTaskToServer" @reject="rejectQuestions" />
     </div>
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, onMounted } from "vue";
+import { computed, defineComponent, onMounted } from "vue";
 import {
   clearInspectedTask,
   getInspectedSetting,
   getInspectedTaskStatus,
   getOneOfInspectedTask,
   getSingleInspectedTask,
+  rejectInspectedTask,
+  saveInspectedTask,
 } from "@/api/inspectPage";
 import { store } from "./store";
 import MarkHeader from "./MarkHeader.vue";
 import { useRoute } from "vue-router";
 import MarkBody from "./MarkBody.vue";
 import MarkHistory from "./MarkHistory.vue";
+import MarkBoardInspect from "./MarkBoardInspect.vue";
+import { Question } from "@/types";
 
 export default defineComponent({
   name: "Inspect",
@@ -30,6 +34,7 @@ export default defineComponent({
     MarkHeader,
     MarkBody,
     MarkHistory,
+    MarkBoardInspect,
   },
   setup: () => {
     const route = useRoute();
@@ -118,10 +123,38 @@ export default defineComponent({
         questionScore,
       });
     }
+
+    const realStudentId = computed(
+      () =>
+        (isSingleStudent ? studentId : store.currentTask?.studentId) as string
+    );
+    const saveTaskToServer = async () => {
+      console.log("save inspect task to server");
+      const res = (await saveInspectedTask(realStudentId.value)) as any;
+      if (res.data.success && store.currentTask) {
+        fetchTask();
+      } else {
+        console.log(res.data.message);
+      }
+    };
+
+    const rejectQuestions = async (questions: Array<Question>) => {
+      const res = (await rejectInspectedTask(
+        realStudentId.value,
+        questions
+      )) as any;
+      if (res.data.success && store.currentTask) {
+        fetchTask();
+      } else {
+        console.log(res.data.message);
+      }
+    };
+
     return {
       store,
-      // saveTaskToServer,
       fetchTask,
+      saveTaskToServer,
+      rejectQuestions,
     };
   },
 });

+ 191 - 0
src/components/inspect/MarkBoardInspect.vue

@@ -0,0 +1,191 @@
+<template>
+  <div
+    v-if="store.currentTask"
+    :style="{ display: store.MarkBoardTrackCollapse ? 'none' : 'block' }"
+    class="mark-board-track-container"
+  >
+    <div>
+      <h1 class="tw-text-3xl tw-text-center">试卷总分:{{ markerScore }}</h1>
+    </div>
+
+    <div v-if="groups">
+      <template v-for="(groupNumber, index) in groups" :key="index">
+        <div class="mb-2">
+          <div class="tw-flex tw-justify-between">
+            分组 {{ groupNumber }}
+            <div>
+              打回
+              <input
+                type="checkbox"
+                @click="groupClicked(groupNumber)"
+                :checked="groupChecked(groupNumber)"
+              />
+            </div>
+          </div>
+          <div v-if="questions">
+            <template v-for="(question, index) in questions" :key="index">
+              <div
+                v-if="question.groupNumber === groupNumber"
+                class="question tw-rounded tw-flex tw-mb-1"
+              >
+                <div class="tw-flex-1">
+                  {{ question.title }} {{ question.mainNumber }}-{{
+                    question.subNumber
+                  }}
+                </div>
+                <div class="tw-flex-1 tw-text-center">
+                  {{ question.score || 0 }}
+                </div>
+                <div>
+                  打回
+                  <input
+                    type="checkbox"
+                    @change="questionCheckChanged(question)"
+                    :checked="questionChecked(question)"
+                  />
+                </div>
+              </div>
+            </template>
+          </div>
+        </div>
+      </template>
+    </div>
+
+    <div class="tw-flex tw-justify-center">
+      <div v-if="store.currentTask.inspectTime > 0" @click="reject">打回</div>
+      <div v-else-if="checkedQuestions.length === 0" @click="inspect">复核</div>
+      <div v-else @click="reject">打回</div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Question } from "@/types";
+import { computed, defineComponent, reactive, watch } from "vue";
+import { store } from "./store";
+
+export default defineComponent({
+  name: "MarkBoardInspect",
+  emits: ["inspect", "reject"],
+  setup(props, { emit }) {
+    let checkedQuestions = reactive([] as Array<Question>);
+
+    watch(
+      () => store.currentTask,
+      () => {
+        checkedQuestions.splice(0);
+      }
+    );
+    const groups = computed(() => {
+      const gs = store.currentTask?.questionList.map((q) => q.groupNumber);
+      return [...new Set(gs)].sort((a, b) => a - b);
+    });
+
+    const questions = computed(() => {
+      const qs = store.currentTask?.questionList;
+      return qs;
+    });
+
+    const markerScore = computed(() =>
+      questions.value?.map((q) => q.score || 0).reduce((acc, s) => acc + s)
+    );
+
+    function addToCheckedQuestion(question: Question) {
+      checkedQuestions.push(question);
+    }
+    function removeCheckedQuestion(question: Question) {
+      const idx = checkedQuestions.indexOf(question);
+      checkedQuestions.splice(idx, 1);
+    }
+    function groupChecked(groupNumber: number) {
+      return (
+        checkedQuestions.filter((q) => q.groupNumber === groupNumber).length ===
+        questions.value?.filter((q) => q.groupNumber === groupNumber).length
+      );
+    }
+
+    function questionChecked(question: Question) {
+      return checkedQuestions.includes(question);
+    }
+
+    function questionCheckChanged(question: Question) {
+      const checked = questionChecked(question);
+      if (checked) {
+        removeCheckedQuestion(question);
+      } else {
+        addToCheckedQuestion(question);
+      }
+    }
+
+    function groupClicked(groupNumber: number) {
+      if (groupChecked(groupNumber)) {
+        checkedQuestions
+          .filter((q) => q.groupNumber === groupNumber)
+          .forEach((q) => {
+            const idx = checkedQuestions.indexOf(q);
+            checkedQuestions.splice(idx, 1);
+          });
+      } else {
+        questions.value
+          ?.filter((q) => q.groupNumber === groupNumber)
+          .forEach((q) => {
+            if (!questionChecked(q)) checkedQuestions.push(q);
+          });
+      }
+    }
+
+    function reject() {
+      emit("reject", checkedQuestions);
+    }
+
+    function inspect() {
+      emit("inspect");
+    }
+
+    return {
+      store,
+      markerScore,
+      groups,
+      checkedQuestions,
+      questions,
+      groupChecked,
+      questionChecked,
+      questionCheckChanged,
+      groupClicked,
+      reject,
+      inspect,
+    };
+  },
+});
+</script>
+
+<style scoped>
+.mark-board-track-container {
+  max-width: 250px;
+  min-width: 250px;
+  border-left: 1px solid grey;
+  padding-left: 6px;
+  padding-right: 6px;
+}
+.question {
+  min-width: 100px;
+  border: 1px solid grey;
+}
+.current-question {
+  border: 1px solid yellowgreen;
+  background-color: lightblue;
+}
+.single-score {
+  width: 30px;
+  height: 30px;
+  display: grid;
+  place-content: center;
+
+  border: 1px solid black;
+  border-radius: 5px;
+}
+.current-score {
+  border: 1px solid yellowgreen;
+  background-color: lightblue;
+}
+</style>

+ 1 - 1
src/components/inspect/MarkHistory.vue

@@ -12,7 +12,7 @@
       <div @click="replaceCurrentTask(task)" class="tw-flex tw-justify-between">
         <div>{{ task.secretNumber }}</div>
         <div>
-          {{ $filters.datetimeFilter(task.markTime) }}
+          {{ $filters.datetimeFilter(task.inspectTime) }}
         </div>
         <div style="width: 30px; text-align: center">
           {{ task.markerScore }}

+ 1 - 0
src/types/index.ts

@@ -89,6 +89,7 @@ export interface Task {
 
   markerScore: number; // 评卷总分
   markTime: number; //评卷时间
+  inspectTime?: number; // 复核有用
   self: boolean; // 是否自评,暂时用不着
   previous: boolean; // 是否回评
   rejected: boolean; // 是否是打回