zhangjie 1 жил өмнө
parent
commit
873f184806

+ 181 - 24
src/features/student/studentInspect/MarkBody.vue

@@ -42,9 +42,31 @@
               :style="minfo.style"
               class="mark-info"
             >
-              <div>
-                <p v-for="user in minfo.users" :key="user.userId">
-                  评卷员:{{ user.userName }},评分:{{ user.score }}
+              <div v-if="minfo.isFillQuestion">
+                <div
+                  v-for="user in minfo.users"
+                  :key="user.userId"
+                  :style="{ color: user.color }"
+                >
+                  <p>{{ user.prename }}:{{ user.userName }},评分:</p>
+                  <p>
+                    {{
+                      user.scores
+                        .map((s) => `${s.subNumber}:${s.score}分`)
+                        .join(",")
+                    }}
+                  </p>
+                </div>
+              </div>
+              <div v-else>
+                <p
+                  v-for="user in minfo.users"
+                  :key="user.userId"
+                  :style="{ color: user.color }"
+                >
+                  {{ user.prename }}:{{ user.userName }},评分:{{
+                    user.score
+                  }}
                 </p>
               </div>
               <h3>得分:{{ minfo.score }},满分:{{ minfo.maxScore }}</h3>
@@ -68,7 +90,13 @@
 import { reactive, watch } from "vue";
 import { store } from "@/store/store";
 import MarkDrawTrack from "@/features/mark/MarkDrawTrack.vue";
-import type { SpecialTag, Track, ColorMap, PaperRecogData } from "@/types";
+import type {
+  SpecialTag,
+  Track,
+  ColorMap,
+  PaperRecogData,
+  Question,
+} from "@/types";
 import { useTimers } from "@/setups/useTimers";
 import { loadImage, addHeaderTrackColorAttr, calcSum } from "@/utils/utils";
 import { dragImage } from "@/features/mark/use/draggable";
@@ -179,9 +207,6 @@ async function processImage() {
 
   maxImageWidth = Math.max(...images.map((i) => i.naturalWidth));
 
-  // 解析各试题答题区域以及评分
-  const markDetailList = parseMarkDetailList();
-
   const trackLists = (store.currentTask.questionList || [])
     // .map((q) => q.trackList)
     .map((q) => {
@@ -193,6 +218,9 @@ async function processImage() {
     .flat();
   store.setting.doubleTrack = trackLists.some((item) => item.isByMultMark);
 
+  // 解析各试题答题区域以及评分
+  const markDetailList = parseMarkDetailList();
+
   for (const url of urls) {
     const indexInSliceUrls = urls.indexOf(url) + 1;
     const image = images[indexInSliceUrls - 1];
@@ -395,51 +423,181 @@ function parseQuestionAreas(questions: QuestionItem[]) {
   return combinePictureConfigList;
 }
 
+// 获取属于填空题的试题号
+function getFillLines() {
+  if (!store.currentTask.cardData?.length) return {};
+
+  const questions: Record<number, string[]> = {};
+  store.currentTask.cardData.forEach((page) => {
+    page.columns.forEach((column) => {
+      column.elements.forEach((element) => {
+        if (element.type !== "FILL_LINE") return;
+
+        if (!questions[element.topicNo]) questions[element.topicNo] = [];
+
+        for (let i = 0; i < element.questionsCount; i++) {
+          questions[element.topicNo].push(
+            `${element.topicNo}_${element.startNumber + i}`
+          );
+        }
+      });
+    });
+  });
+  return questions;
+}
+
 // 解析各试题答题区域以及评分
+interface MarkDetailUserItem {
+  userId: string;
+  userName: string;
+  prename: string;
+  color: string;
+  scores: Array<{ subNumber: string; score: number }>;
+  score: number;
+}
+type UserMapType = Record<string, MarkDetailUserItem>;
 interface MarkDetailItem {
   mainNumber: number;
   subNumber: string;
+  isFillQuestion: boolean;
   score: number;
   maxScore: number;
-  users: Array<{
-    userId: string;
-    userName: string;
-    scores: number[];
-    score: number;
-  }>;
+  users: MarkDetailUserItem[];
   area: QuestionArea;
   style: Record<string, string>;
 }
+
 function parseMarkDetailList(): Array<MarkDetailItem[]> {
   const dataList: Array<MarkDetailItem[]> = [];
+  const questions = store.currentTask.questionList || [];
+
+  const fillQues = getFillLines();
+  let fillQuestions = [] as Question[];
+  let otherQuestions = questions;
+  if (Object.keys(fillQues).length) {
+    const fillQNos = Object.values(fillQues).flat();
+    fillQuestions = questions.filter((q) =>
+      fillQNos.includes(`${q.mainNumber}_${q.subNumber}`)
+    );
+    otherQuestions = questions.filter(
+      (q) => !fillQNos.includes(`${q.mainNumber}_${q.subNumber}`)
+    );
+  }
 
-  (store.currentTask.questionList || []).forEach((question) => {
-    const areas = parseQuestionAreas([question]);
+  // 填空题:合并所有小题为一个区域
+  Object.values(fillQues).forEach((qnos) => {
+    const groupQuestions = fillQuestions.filter((q) =>
+      qnos.includes(`${q.mainNumber}_${q.subNumber}`)
+    );
+    const areas = parseQuestionAreas(groupQuestions);
     if (!areas.length) return;
-    const area = areas[0];
-    if (!dataList[area.i - 1]) {
-      dataList[area.i - 1] = [];
+    const area = { ...areas[0] };
+    const imgIndex = area.i - 1;
+    if (!dataList[imgIndex]) {
+      dataList[imgIndex] = [];
     }
 
-    const userMap = {};
+    const userMap: UserMapType = {};
+    // 大题分成两个部分给两个人评 与 大题被两人同时评 是不一样的
+    const isDoubleMark = !groupQuestions.some((question) => {
+      const userIds = question.trackList.map((track) => track.userId);
+      const uids = new Set(userIds);
+      return uids.size === 1;
+    });
+    groupQuestions.forEach((question) => {
+      question.trackList.forEach((track) => {
+        if (!userMap[track.userId]) {
+          userMap[track.userId] = {
+            userId: track.userId,
+            userName: track.userName,
+            color: track.color || "red",
+            prename: "",
+            scores: [],
+            score: 0,
+          };
+        }
+        userMap[track.userId].scores.push({
+          score: track.score,
+          subNumber: track.subNumber,
+        });
+      });
+    });
+
+    const users = Object.values(userMap).map((user, index) => {
+      const zhs = ["一", "二", "三"];
+      const prename = isDoubleMark ? `${zhs[index] || ""}评` : "评卷员";
+      return {
+        ...user,
+        prename,
+        score: calcSum(user.scores.map((s) => s.score)),
+      };
+    });
+
+    const score = calcSum(groupQuestions.map((item) => item.score || 0));
+    const maxScore = calcSum(groupQuestions.map((item) => item.maxScore));
+
+    dataList[imgIndex].push({
+      mainNumber: groupQuestions[0].mainNumber,
+      subNumber: "",
+      isFillQuestion: true,
+      score,
+      maxScore,
+      users,
+      area,
+      style: {
+        position: "absolute",
+        left: (100 * area.x).toFixed(4) + "%",
+        top: (100 * area.y).toFixed(4) + "%",
+        width: (100 * area.w).toFixed(4) + "%",
+        fontSize: "14px",
+        lineHeight: 1,
+        zIndex: 9,
+      },
+    });
+  });
+
+  // 其他试题
+  otherQuestions.forEach((question) => {
+    const areas = parseQuestionAreas([question]);
+    const area = { ...areas[0] };
+    const imgIndex = area.i - 1;
+    if (!dataList[imgIndex]) {
+      dataList[imgIndex] = [];
+    }
+
+    const userMap: UserMapType = {};
     question.trackList.forEach((track) => {
       if (!userMap[track.userId]) {
         userMap[track.userId] = {
           userId: track.userId,
           userName: track.userName,
+          color: track.color || "red",
+          prename: "",
           scores: [],
+          score: 0,
         };
       }
-      userMap[track.userId].scores.push(track.score);
+      userMap[track.userId].scores.push({
+        score: track.score,
+        subNumber: track.subNumber,
+      });
     });
 
-    const users = Object.values(userMap).map((user) => {
-      return { ...user, score: calcSum(user.scores) };
+    const isDoubleMark = Object.keys(userMap).length > 1;
+    const users = Object.values(userMap).map((user, index) => {
+      const zhs = ["一", "二", "三"];
+      const prename = isDoubleMark ? `${zhs[index] || ""}评` : "评卷员";
+      return {
+        ...user,
+        prename,
+        score: calcSum(user.scores.map((s) => s.score)),
+      };
     });
 
-    dataList[area.i - 1].push({
+    dataList[imgIndex].push({
       mainNumber: question.mainNumber,
       subNumber: question.subNumber,
+      isFillQuestion: false,
       score: question.score,
       maxScore: question.maxScore,
       users,
@@ -449,7 +607,6 @@ function parseMarkDetailList(): Array<MarkDetailItem[]> {
         left: (100 * area.x).toFixed(4) + "%",
         top: (100 * area.y).toFixed(4) + "%",
         width: (100 * area.w).toFixed(4) + "%",
-        color: "#f53f3f",
         fontSize: "14px",
         lineHeight: 1,
         zIndex: 9,

+ 1 - 1
src/features/student/studentTrack/StudentTrack.vue

@@ -80,7 +80,7 @@ async function updateTask() {
 
     // 获取题卡数据
     const cardRes = await getSingleStudentCardData(studentId);
-    const cardData = cardRes.data.content
+    const cardData = cardRes.data?.content
       ? JSON.parse(cardRes.data.content)
       : { pages: [] };
 

+ 26 - 1
src/types/index.ts

@@ -222,6 +222,31 @@ interface RawTask {
   headerTagList?: any;
 }
 
+type ElementType =
+  | "FILL_QUESTION"
+  | "FILL_LINE"
+  | "EXPLAIN"
+  | "COMPOSITION"
+  | "TOPIC_HEAD"
+  | "CARD_HEAD";
+export interface CardDataItem {
+  exchange: {
+    answer_area: Array<{
+      main_number: number;
+      sub_number: number | string;
+      area: [number, number, number, number];
+    }>;
+  };
+  columns: Array<{
+    elements: Array<{
+      type: ElementType;
+      topicNo: number;
+      startNumber: number;
+      questionsCount: number;
+    }>;
+  }>;
+}
+
 export interface Task extends RawTask {
   /** 评卷结果,在task第一次被访问时自动添加,watch currentTask */
   markResult: MarkResult;
@@ -233,7 +258,7 @@ export interface Task extends RawTask {
   // 轨迹图中可能存在客观题填涂框数据,答案数据,题卡数据等
   answerMap?: Record<string, { answer: string; isRight: boolean }>;
   recogDatas?: string[];
-  cardData?: Array<any>;
+  cardData?: Array<CardDataItem>;
 }
 
 interface RawQuestion {