瀏覽代碼

feat: 轨迹图客观题总分显示

zhangjie 11 月之前
父節點
當前提交
a3f80718ec

+ 105 - 0
src/features/student/studentInspect/MarkBody.vue

@@ -72,6 +72,18 @@
               <h3>得分:{{ minfo.score }},满分:{{ minfo.maxScore }}</h3>
             </div>
           </template>
+          <!-- 客观题 -->
+          <template v-if="item.objectiveAnswerTags">
+            <div
+              v-for="tag in item.objectiveAnswerTags"
+              :key="tag.id"
+              class="mark-objective"
+              :style="tag.style"
+            >
+              得分:{{ tag.score }},满分:{{ tag.totalScore }}
+            </div>
+          </template>
+
           <!-- 总分 -->
           <div class="mark-total">
             总分:{{ totalScore }},主观题得分:{{
@@ -111,6 +123,7 @@ interface SliceImage {
   width: string; // 图片在整个图片列表里面的宽度比例
   answerTags?: AnswerTagItem[];
   markDetail?: MarkDetailItem[];
+  objectiveAnswerTags?: ObjectiveAnswerTagItem[];
 }
 
 const { origImageUrls = "sliceUrls" } = defineProps<{
@@ -220,6 +233,8 @@ async function processImage() {
 
   // 解析各试题答题区域以及评分
   const markDetailList = parseMarkDetailList();
+  // 解析客观题的得分情况,按大题统计
+  const objectiveAnswerTagList = parseObjectiveAnswerTags();
 
   for (const url of urls) {
     const indexInSliceUrls = urls.indexOf(url) + 1;
@@ -250,6 +265,7 @@ async function processImage() {
       width: (image.naturalWidth / maxImageWidth) * 100 + "%",
       answerTags,
       markDetail: markDetailList[indexInSliceUrls - 1],
+      objectiveAnswerTags: objectiveAnswerTagList[indexInSliceUrls - 1],
     });
   }
 }
@@ -631,6 +647,95 @@ function parseMarkDetailList(): Array<MarkDetailItem[]> {
   return dataList;
 }
 
+// 解析客观题区域总分
+interface ObjectiveAnswerTagItem {
+  id: string;
+  mainNumber: number;
+  subNumbers: string;
+  score: number;
+  totalScore: number;
+  style: Record<string, string | number>;
+}
+function parseObjectiveAnswerTags() {
+  const objectiveAnswerTags: Array<ObjectiveAnswerTagItem[]> = [];
+
+  if (!store.currentTask.cardData?.length || !store.currentTask.answerMap)
+    return objectiveAnswerTags;
+
+  store.currentTask.cardData.forEach((page, pindex) => {
+    if (!objectiveAnswerTags[pindex]) objectiveAnswerTags[pindex] = [];
+
+    page.columns.forEach((column) => {
+      column.elements.forEach((element) => {
+        if (element.type !== "FILL_QUESTION") return;
+
+        const ogroup = objectiveAnswerTags.find((tgroup) =>
+          tgroup.some((oitem) => oitem.id === element.parent.id)
+        );
+        if (ogroup) return;
+
+        const parent = element.parent;
+        const oaTagItem: ObjectiveAnswerTagItem = {
+          id: parent.id,
+          mainNumber: parent.topicNo,
+          subNumbers: `${parent.startNumber}~${
+            parent.startNumber + parent.questionsCount - 1
+          }`,
+          score: 0,
+          totalScore: 0,
+          style: {
+            position: "absolute",
+            left: 0,
+            top: 0,
+            textAlign: "right",
+            width: "44%",
+            fontSize: "20px",
+            fontWeight: "bold",
+            color: "#f53f3f",
+            lineHeight: 1,
+            zIndex: 9,
+          },
+        };
+
+        let area = [0, 0];
+        page.exchange.fill_area.forEach((fa) => {
+          fa.items.forEach((fitem) => {
+            if (
+              fitem.main_number === oaTagItem.mainNumber &&
+              fitem.sub_number === parent.startNumber
+            ) {
+              area = fitem.options[0];
+            }
+          });
+        });
+
+        const left = (100 * (area[0] - 0.015)).toFixed(4);
+        const top = (100 * (area[1] - 0.04)).toFixed(4);
+        oaTagItem.style.left = `${left}%`;
+        oaTagItem.style.top = `${top}%`;
+
+        const questions: Array<{ score: number; totalScore: number }> = [];
+        for (let i = 0; i < parent.questionsCount; i++) {
+          const qans = store.currentTask.answerMap[
+            `${parent.topicNo}_${i + parent.startNumber}`
+          ] || { score: 0, totalScore: 0 };
+          questions[i] = {
+            score: qans.score,
+            totalScore: qans.totalScore,
+          };
+        }
+
+        oaTagItem.score = calcSum(questions.map((q) => q.score || 0));
+        oaTagItem.totalScore = calcSum(questions.map((q) => q.totalScore || 0));
+
+        objectiveAnswerTags[pindex].push(oaTagItem);
+      });
+    });
+  });
+
+  return objectiveAnswerTags;
+}
+
 // should not render twice at the same time
 let renderLock = false;
 const renderPaperAndMark = async () => {

+ 2 - 0
src/features/student/studentTrack/StudentTrack.vue

@@ -74,6 +74,8 @@ async function updateTask() {
     objectiveData.answers.forEach((item) => {
       answerMap[`${item.mainNumber}_${item.subNumber}`] = {
         answer: item.answer,
+        totalScore: item.totalScore,
+        score: item.score,
         isRight: item.answer === item.standardAnswer,
       };
     });

+ 26 - 7
src/types/index.ts

@@ -229,6 +229,16 @@ type ElementType =
   | "COMPOSITION"
   | "TOPIC_HEAD"
   | "CARD_HEAD";
+interface CardBaseElement {
+  id: string;
+  type: ElementType;
+  topicNo: number;
+  startNumber: number;
+  questionsCount: number;
+}
+interface CardElement extends CardBaseElement {
+  parent: CardBaseElement;
+}
 export interface CardDataItem {
   exchange: {
     answer_area: Array<{
@@ -236,14 +246,20 @@ export interface CardDataItem {
       sub_number: number | string;
       area: [number, number, number, number];
     }>;
+    fill_area: Array<{
+      field: "question" | "examNumber";
+      index: number;
+      single: boolean;
+      horizontal: boolean;
+      items: Array<{
+        main_number: number;
+        sub_number: number | string;
+        options: [number, number, number, number][];
+      }>;
+    }>;
   };
   columns: Array<{
-    elements: Array<{
-      type: ElementType;
-      topicNo: number;
-      startNumber: number;
-      questionsCount: number;
-    }>;
+    elements: CardElement[];
   }>;
 }
 
@@ -256,7 +272,10 @@ export interface Task extends RawTask {
   // 主观题检查时,科组长特殊标记使用headerTagList
   __isMarkLeader: string;
   // 轨迹图中可能存在客观题填涂框数据,答案数据,题卡数据等
-  answerMap?: Record<string, { answer: string; isRight: boolean }>;
+  answerMap?: Record<
+    string,
+    { answer: string; isRight: boolean; score: number; totalScore: number }
+  >;
   recogDatas?: string[];
   cardData?: Array<CardDataItem>;
 }