Forráskód Böngészése

feat: 轨迹调整

zhangjie 3 hónapja
szülő
commit
9616f65a91
4 módosított fájl, 331 hozzáadás és 142 törlés
  1. 6 0
      CHANGE.md
  2. 10 0
      src/api/task.ts
  3. 72 38
      src/api/types/task.ts
  4. 243 104
      src/views/base/track-export/useDraw.ts

+ 6 - 0
CHANGE.md

@@ -1,3 +1,9 @@
+## 1.0.5
+
+- 适用范围:知学知考 3.4.4
+- 支持新的评卷方式。
+- 评卷区域获取调整,不在通过题卡卡格式获取。
+
 ## 1.0.4
 
 - 适用范围:知学知考 3.4.3

+ 10 - 0
src/api/task.ts

@@ -3,6 +3,7 @@ import {
   CardData,
   Task,
   StudentObjectiveInfo,
+  MarkArea,
   SemesterItem,
   ExamItem,
   CourseItem,
@@ -99,3 +100,12 @@ export async function studentObjectiveConfirmData(
     { params: { studentId } }
   );
 }
+
+/** 获取评卷区域设置 */
+export async function getMarkArea(studentId: string): Promise<MarkArea[]> {
+  return axios.post(
+    '/api/admin/mark/inspected/get_mark_area',
+    {},
+    { params: { studentId } }
+  );
+}

+ 72 - 38
src/api/types/task.ts

@@ -30,7 +30,7 @@ export interface CardData {
 }
 
 // task --------->
-interface SplitConfig {
+export interface SplitConfig {
   /** index of sheets */
   i: number;
   /** 覆盖区域的width */
@@ -50,29 +50,48 @@ export interface Track {
   subNumber: string;
   /** 前端使用,暂时用不着,赋0 */
   number: number;
+  /** 评分数 */
+  score: number;
   /** 第几张图 */
   offsetIndex: number;
   /** 左上角为原点 */
   offsetX: number;
   offsetY: number;
-  /** 相对slice的位置比例 */
-  positionX: number;
-  positionY: number;
-  /** 评分数 */
-  score: number;
   /** 是否此处未作答,未作答时,score默认是-0分 */
   unanswered: boolean;
+  // 是否是复核员复核轨迹 headTrackList没有这个属性
+  headerType: 'ARBITRATED' | 'MARKED' | null;
   userId: string;
   userName: string;
-  // 是否是科组长评卷轨迹
-  headerMarkScore?: boolean;
+  color?: string;
+  isByMultMark?: boolean;
+}
+
+export interface SpecialTag {
+  /** 大题号 */
+  mainNumber: number;
+  /** 小题号,当前api中只有number */
+  subNumber: string;
+  /** 第几张图 */
+  offsetIndex: number;
+  /** 左上角为原点(原图的原点),及相对原图的位置比例 */
+  offsetX: number;
+  offsetY: number;
+  /** 特殊标记的字符串,勾叉 */
+  tagName: string;
+  tagType: 'TEXT' | 'CIRCLE' | 'RIGHT' | 'WRONG' | 'HALF_RIGTH' | 'LINE';
+  // 是否是复核员复核标记
+  headerType: 'ARBITRATED' | 'MARKED' | null;
+  userId: string;
   color?: string;
   isByMultMark?: boolean;
 }
 
 export interface Question {
-  /** 分组序号 */
-  groupNumber: number;
+  /** 任务序号 */
+  taskId: string;
+  /** 试题号 */
+  questionId: string;
   /** 大题号 */
   mainNumber: number;
   /** 小题号 */
@@ -81,18 +100,24 @@ export interface Question {
   intervalScore: number;
   /** 默认分数 */
   defaultScore: number;
-  /** 限制最小分数 */
-  minScore: number;
-  /** 限制最大分数 */
-  maxScore: number;
   /** 题目名称 */
   title: string;
-  /** 轨迹列表 */
-  trackList: Array<Track>;
   /** 得分;null的值时是为打回时可以被评卷修改的;null也是从未评分过的情况,要通过rejected来判断 */
   score: number | null;
+  /** 限制最小分数 */
+  minScore: number;
+  /** 限制最大分数 */
+  maxScore: number;
   /** 未计分 */
   uncalculate: boolean;
+  /** 是否自己评卷,false时为他人评卷,给分板置灰 */
+  selfMark: boolean;
+  // 任务状态: WAIT_ARBITRATE:待仲裁,PROBLEM:问题卷
+  status: 'WAIT_ARBITRATE' | 'PROBLEM' | 'WAITING' | 'MARKED';
+  /** 轨迹列表 */
+  markerTrackList: Array<Track>;
+  // 科组长轨迹
+  headerTrackList: Array<Track>;
   /** 选做题分组 */
   selectiveIndex: number | null;
   /** 无轨迹情况下评卷员打分信息 */
@@ -104,31 +129,28 @@ export interface Question {
     userId: string;
     userName: string;
   }>;
-  rejected?: boolean;
+  // 特殊标记列表
+  markerTagList: Array<SpecialTag> | null;
+  // 科组长特殊标记
+  headerTagList: Array<SpecialTag> | null;
+  // 是否打回
+  rejected: boolean;
+  // 打回原因
+  rejectReason: string | null;
+  // 打回前给分数据
+  rejectScoreList: number[] | null;
+  // 问题卷
+  problem: boolean;
+  // 问题卷类型
+  problemType: string;
+  // 问题卷备注
+  problemRemark: string;
   questionName?: string;
-  headerTrack?: Array<Track>;
-}
-
-export interface SpecialTag {
-  /** 第几张图 */
-  offsetIndex: number;
-  /** 左上角为原点(原图的原点),及相对原图的位置比例 */
-  offsetX: number;
-  offsetY: number;
-  /** 相对裁切图的位置比例 */
-  positionX: number;
-  positionY: number;
-  /** 特殊标记的字符串,勾叉 */
-  tagName: string;
-  tagType: 'TEXT' | 'CIRCLE' | 'RIGHT' | 'WRONG' | 'HALF_RIGTH' | 'LINE';
-  // 分组号
-  groupNumber?: number;
-  userId?: number;
-  color?: string;
-  isByMultMark?: boolean;
 }
 
 export interface Task {
+  // 考试id
+  examId: string;
   /** 学生ID */
   studentId: string;
   /** 任务编号 */
@@ -143,11 +165,12 @@ export interface Task {
   courseCode: string;
   /** 试卷编号 */
   paperNumber: string;
+  /** 试卷类型 */
+  paperType: string;
   /** 最高显示优先级,有sliceConfig就用sliceConfig,否则使用sheetConfig */
   sliceConfig: Array<SplitConfig>;
   jsonUrl: string;
   questionList: Array<Question>;
-  specialTagList: Array<SpecialTag>;
   /** 原图url */
   sheetUrls: Array<string>;
   /** 客观分 复核也用到 */
@@ -186,6 +209,17 @@ export type StudentObjectiveInfo = {
   success: boolean;
 };
 
+export interface MarkArea {
+  title: string;
+  mainNumber: number;
+  subNumber: number;
+  score: number;
+  picList: string;
+  // 1: 单选 2: 多选 3: 判断 4: 填空 5: 问答
+  questionType: 1 | 2 | 3 | 4 | 5;
+  splitConfig?: SplitConfig[];
+}
+
 // card --------->
 
 // page --------->

+ 243 - 104
src/views/base/track-export/useDraw.ts

@@ -2,8 +2,16 @@ import {
   getSingleStudentTaskOfStudentTrack,
   studentObjectiveConfirmData,
   getSingleStudentCardData,
+  getMarkArea,
 } from '@/api/task';
-import { Task, Track, SpecialTag, Question } from '@/api/types/task';
+import {
+  Task,
+  Track,
+  SpecialTag,
+  Question,
+  MarkArea,
+  SplitConfig,
+} from '@/api/types/task';
 import { TrackConfigType } from '@/store/modules/app/types';
 import { PictureTypeEnum, PICTURE_TYPE } from '@/constants/enumerate';
 import {
@@ -96,6 +104,8 @@ type UserMapType = Record<
     userName: string;
     color: string;
     scores: Array<{ subNumber: string; score: number }>;
+    prename: string;
+    score: number;
   }
 >;
 
@@ -134,6 +144,7 @@ export default function useDraw(drawConfig: DrawConfig) {
 
   let answerMap = {} as AnswerMap;
   let cardData = [] as CardDataItem[];
+  let markAreaList = [] as MarkArea[];
   let recogDatas: string[] = [];
   let rawTask = {} as Task;
   let trackData = [] as TrackItemType[];
@@ -264,6 +275,19 @@ export default function useDraw(drawConfig: DrawConfig) {
             ? (JSON.parse(cardRes.content) as CardContentType)
             : { pages: [] };
         cardData = cardContent.pages;
+
+        if (cardData.length) return;
+        // 如果没有题卡信息,就查询评卷区域信息
+        const areaRes = await getMarkArea(studentId);
+        markAreaList = (areaRes || []).map((item: MarkArea) => {
+          const splitConfig: SplitConfig[] = item.picList
+            ? JSON.parse(item.picList)
+            : [];
+          return {
+            ...item,
+            splitConfig,
+          };
+        });
       });
     }
 
@@ -331,11 +355,18 @@ export default function useDraw(drawConfig: DrawConfig) {
 
     const trackLists = (rawTask.questionList || [])
       .map((q) => {
-        return q.headerTrack?.length
-          ? addHeaderTrackColorAttr(q.headerTrack)
-          : addTrackColorAttr(q.trackList);
+        return q.headerTrackList?.length
+          ? addHeaderTrackColorAttr<Track>(q.headerTrackList)
+          : addTrackColorAttr<Track>(q.markerTrackList);
       })
       .flat();
+    const tagLists = (rawTask.questionList || [])
+      .map((q) =>
+        q.headerTagList?.length
+          ? addHeaderTrackColorAttr<SpecialTag>(q.headerTagList)
+          : addTrackColorAttr<SpecialTag>(q.markerTagList || [])
+      )
+      .flat();
 
     const markDeailList = parseMarkDetailList(originImgs);
     const objectiveAnswerTagList = parseObjectiveAnswerTags(originImgs);
@@ -348,7 +379,7 @@ export default function useDraw(drawConfig: DrawConfig) {
         .forEach((item) => {
           drawTrackList.push(getDrawTrackItem(item));
         });
-      (rawTask.specialTagList || [])
+      tagLists
         .filter((item) => item.offsetIndex === i + 1)
         .forEach((item) => {
           drawTrackList.push(getDrawTagTrackItem(item));
@@ -454,14 +485,22 @@ export default function useDraw(drawConfig: DrawConfig) {
     };
   }
 
-  function addHeaderTrackColorAttr(headerTrack: Track[]): Track[] {
-    return headerTrack.map((item) => {
+  function addHeaderTrackColorAttr<T extends { color?: string }>(
+    headerTrackList: T[]
+  ): T[] {
+    return headerTrackList.map((item) => {
       item.color = colorConfig.head;
       return item;
     });
   }
 
-  function addTrackColorAttr(tList: Track[]): Track[] {
+  function addTrackColorAttr<
+    T extends {
+      userId: string;
+      color?: string;
+      isByMultMark?: boolean;
+    }
+  >(tList: T[]): T[] {
     let markerIds: string[] = tList.map((v) => v.userId).filter((x) => !!x);
     markerIds = Array.from(new Set(markerIds));
     // markerIds.sort();
@@ -477,7 +516,7 @@ export default function useDraw(drawConfig: DrawConfig) {
       }
     }
     type ColorK = keyof typeof colorMap;
-    tList = tList.map((item: Track) => {
+    tList = tList.map((item: T) => {
       const k = item.userId as ColorK;
       item.color = colorMap[k] || 'red';
       item.isByMultMark = markerIds.length > 1;
@@ -486,35 +525,6 @@ export default function useDraw(drawConfig: DrawConfig) {
     return tList;
   }
 
-  /* 
-  function addTagColorAttr(tList: SpecialTag[]): SpecialTag[] {
-    let markerIds: string[] = tList
-      .map((v) => String(v.userId))
-      .filter((x) => !!x);
-    markerIds = Array.from(new Set(markerIds));
-    // markerIds.sort();
-    const colorMap: Record<string, string> = {};
-    for (let i = 0; i < markerIds.length; i++) {
-      const mId = markerIds[i];
-      if (i === 0) {
-        colorMap[mId] = 'red';
-      } else if (i === 1) {
-        colorMap[mId] = 'blue';
-      } else if (i > 1) {
-        colorMap[mId] = 'gray';
-      }
-    }
-    type ColorK = keyof typeof colorMap;
-    tList = tList.map((item: SpecialTag) => {
-      const k = String(item.userId) as ColorK;
-      item.color = colorMap[k] || 'red';
-      item.isByMultMark = markerIds.length > 1;
-      return item;
-    });
-    return tList;
-  }
-  */
-
   // track ----- end->
 
   // mark detail ----- start->
@@ -556,7 +566,7 @@ export default function useDraw(drawConfig: DrawConfig) {
       const dataArr = dataList[imgIndex];
       const userMap: UserMapType = {};
       const isDoubleMark = !groupQuestions.some((question) => {
-        let userIds = question.trackList.map((track) => track.userId);
+        let userIds = question.markerTrackList.map((track) => track.userId);
         if (
           !userIds.length &&
           question.markerList &&
@@ -570,13 +580,15 @@ export default function useDraw(drawConfig: DrawConfig) {
         return uids.size === 1;
       });
       groupQuestions.forEach((question) => {
-        question.trackList.forEach((track) => {
+        question.markerTrackList.forEach((track) => {
           if (!userMap[track.userId]) {
             userMap[track.userId] = {
               userId: track.userId,
               userName: track.userName,
               color: track.color || '',
+              prename: '',
               scores: [],
+              score: 0,
             };
           }
           const existUserScore = userMap[track.userId].scores.find(
@@ -594,7 +606,7 @@ export default function useDraw(drawConfig: DrawConfig) {
 
         // 普通模式没有轨迹
         if (
-          !question.trackList.length &&
+          !question.markerTrackList.length &&
           question.markerList &&
           question.markerList.length
         ) {
@@ -606,7 +618,9 @@ export default function useDraw(drawConfig: DrawConfig) {
                   userId: marker.userId,
                   userName: marker.userName,
                   color: marker.header ? 'green' : 'red',
+                  prename: '',
                   scores: [],
+                  score: 0,
                 };
               }
               userMap[marker.userId].scores.push({
@@ -617,16 +631,54 @@ export default function useDraw(drawConfig: DrawConfig) {
         }
       });
 
-      // 填空题的打分需要自动换行,目前一行只展示最多10个评分
-      let offsetY = -1 * trackInfoLineHeight;
-      Object.values(userMap).forEach((user, index) => {
+      const users = Object.values(userMap).map((user, index) => {
         const zhs = ['一', '二', '三'];
         const prename = isDoubleMark ? `${zhs[index] || ''}评` : '评卷员';
+        return {
+          ...user,
+          prename,
+          score: calcSumPrecision(user.scores.map((s) => s.score)),
+        };
+      });
 
-        const userScore = user.scores.map(
-          (item) => `${item.subNumber}:${item.score}分`
-        );
-        const lineScoreCount = 10;
+      // 新增仲裁和复核记录
+      const headerTrackQuestions = groupQuestions.filter(
+        (question) => question.headerTrackList?.length
+      );
+      if (headerTrackQuestions.length) {
+        const updateTypeUser = (type: 'ARBITRATED' | 'MARKED') => {
+          const typeQuestions = headerTrackQuestions.filter(
+            (question) => question.headerTrackList[0].headerType === type
+          );
+          typeQuestions.forEach((question) => {
+            const scores = question.headerTrackList.map((track) => {
+              return {
+                score: track.score,
+                subNumber: track.subNumber,
+              };
+            });
+            const score = calcSumPrecision(scores.map((s) => s.score));
+            const user = {
+              userId: question.headerTrackList[0].userId,
+              userName: question.headerTrackList[0].userName,
+              color: 'green',
+              prename: type === 'ARBITRATED' ? '仲裁' : '复核',
+              scores,
+              score,
+            };
+            users.push(user);
+          });
+        };
+        // 仲裁记录
+        updateTypeUser('ARBITRATED');
+        // 复核记录
+        updateTypeUser('MARKED');
+      }
+
+      // 填空题的打分需要自动换行,目前一行只展示最多10个评分
+      let offsetY = -1 * trackInfoLineHeight;
+      const lineScoreCount = 10;
+      const groupLineScore = (userScore: string[], color: string) => {
         const groupCount = Math.ceil(userScore.length / lineScoreCount);
         const groups: string[] = [];
         for (let i = 0; i < groupCount; i++) {
@@ -636,18 +688,6 @@ export default function useDraw(drawConfig: DrawConfig) {
               .join(',')
           );
         }
-
-        offsetY += trackInfoLineHeight;
-        dataArr.push({
-          type: 'text',
-          option: {
-            x: area.x,
-            y: area.y + offsetY,
-            text: `${prename}:${user.userName},评分:`,
-            fontSize: trackInfoFontSize,
-            color: user.color,
-          },
-        });
         groups.forEach((group) => {
           offsetY += 20;
           dataArr.push({
@@ -657,10 +697,28 @@ export default function useDraw(drawConfig: DrawConfig) {
               y: area.y + offsetY,
               text: group,
               fontSize: trackInfoFontSize,
-              color: user.color,
+              color,
             },
           });
         });
+      };
+
+      users.forEach((user) => {
+        offsetY += trackInfoLineHeight;
+        dataArr.push({
+          type: 'text',
+          option: {
+            x: area.x,
+            y: area.y + offsetY,
+            text: `${user.prename}:${user.userName},评分:`,
+            fontSize: trackInfoFontSize,
+            color: user.color,
+          },
+        });
+        const userScore = user.scores.map(
+          (item) => `${item.subNumber}:${item.score}分`
+        );
+        groupLineScore(userScore, user.color);
       });
 
       const score = calcSumPrecision(
@@ -699,17 +757,28 @@ export default function useDraw(drawConfig: DrawConfig) {
 
       const dataArr = dataList[imgIndex];
       const userMap: UserMapType = {};
-      const isArbitration = Boolean(question.headerTrack?.length);
-      const tList = isArbitration
-        ? (question.headerTrack as Track[])
-        : question.trackList;
+      const hasHeaderTrack = question.headerTrackList?.length;
+      //  是否仲裁
+      const isArbitration =
+        hasHeaderTrack &&
+        question.headerTrackList[0].headerType === 'ARBITRATED';
+      // 是否复核
+      const isReview =
+        hasHeaderTrack && question.headerTrackList[0].headerType === 'MARKED';
+
+      const tList = hasHeaderTrack
+        ? question.headerTrackList || []
+        : question.markerTrackList || [];
+
       tList.forEach((track) => {
         if (!userMap[track.userId]) {
           userMap[track.userId] = {
             userId: track.userId,
             userName: track.userName,
-            color: track.color || '',
+            color: hasHeaderTrack ? 'green' : track.color || 'red',
+            prename: '',
             scores: [],
+            score: 0,
           };
         }
         userMap[track.userId].scores.push({
@@ -718,36 +787,45 @@ export default function useDraw(drawConfig: DrawConfig) {
         });
       });
 
+      // 是否双评,复核或者仲裁只会是一个人
+      const isDoubleMark = Object.keys(userMap).length > 1;
+      const zhs = ['一', '二', '三'];
+      let users = Object.values(userMap).map((user, index) => {
+        let prename = '';
+        if (isArbitration) {
+          prename = '仲裁';
+        } else if (isReview) {
+          prename = '复核';
+        } else {
+          prename = isDoubleMark ? `${zhs[index] || ''}评` : '评卷员';
+        }
+        return {
+          ...user,
+          prename,
+          score: calcSumPrecision(user.scores.map((s) => s.score)),
+        };
+      });
+
       // 普通模式没有轨迹
       if (!tList.length && question.markerList && question.markerList.length) {
         let markers = question.markerList.filter((marker) => marker.header);
         if (!markers.length) {
           markers = question.markerList.filter((marker) => !marker.header);
         }
-        markers.forEach((marker) => {
-          userMap[marker.userId] = {
-            userId: marker.userId,
-            userName: marker.userName,
-            color: marker.header ? 'green' : 'red',
-            scores: [{ score: marker.score, subNumber: question.subNumber }],
+        users = markers.map((item, index) => {
+          return {
+            userId: item.userId,
+            userName: item.userName,
+            color: item.header ? 'green' : 'red',
+            prename: markers.length > 1 ? `${zhs[index] || ''}评` : '评卷员',
+            scores: [],
+            score: item.score,
           };
         });
       }
 
-      const isDoubleMark = Object.values(userMap).length > 1;
-      Object.values(userMap).forEach((user, index) => {
-        const zhs = ['一', '二', '三'];
-        let prename = '';
-        if (isArbitration) {
-          prename = '仲裁';
-        } else {
-          prename = isDoubleMark ? `${zhs[index] || ''}评` : '评卷员';
-        }
-
-        const userScore = calcSumPrecision(
-          user.scores.map((item) => item.score)
-        );
-        const content = `${prename}:${user.userName},评分:${userScore}`;
+      users.forEach((user, index) => {
+        const content = `${user.prename}:${user.userName},评分:${user.score}`;
         dataArr.push({
           type: 'text',
           option: {
@@ -790,28 +868,82 @@ export default function useDraw(drawConfig: DrawConfig) {
     };
   }
 
-  // 获取属于填空题的试题号
+  // 通过题卡获取属于填空题的试题号
+  // function getFillLinesFromCard() {
+  //   const questions: Record<number, string[]> = {};
+  //   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;
+  // }
+
+  // 通过评卷区获取属于填空题的试题号
   function getFillLines() {
     const questions: Record<number, string[]> = {};
-    cardData.forEach((page) => {
-      page.columns.forEach((column) => {
-        column.elements.forEach((element) => {
-          if (element.type !== 'FILL_LINE') return;
+    markAreaList.forEach((markArea) => {
+      const { mainNumber, subNumber, questionType } = markArea;
+      if (questionType !== 4) return;
+      if (!questions[mainNumber]) questions[mainNumber] = [];
+      questions[mainNumber].push(`${mainNumber}_${subNumber}`);
+    });
+    return questions;
+  }
 
-          if (!questions[element.topicNo]) questions[element.topicNo] = [];
+  // 获取题型的评卷区
+  function parseQuestionAreas(questions: QuestionItem[]) {
+    if (!questions.length || !cardData?.length || !markAreaList.length)
+      return [];
 
-          for (let i = 0; i < element.questionsCount; i++) {
-            questions[element.topicNo].push(
-              `${element.topicNo}_${element.startNumber + i}`
-            );
-          }
+    return cardData.length
+      ? parseCardQuestionAreas(questions)
+      : parseMarkAreaQuestionAreas(questions);
+  }
+
+  // 获取设置的评卷获取试题评卷区
+  function parseMarkAreaQuestionAreas(questions: QuestionItem[]) {
+    if (!questions.length || !markAreaList?.length) return [];
+
+    const pictureConfigs: QuestionArea[] = [];
+    const structs = questions.map(
+      (item) => `${item.mainNumber}_${item.subNumber}`
+    );
+
+    markAreaList.forEach((markArea) => {
+      const qStruct = `${markArea.mainNumber}_${markArea.subNumber}`;
+      if (!structs.includes(qStruct)) return;
+
+      (markArea.splitConfig || []).forEach((area) => {
+        pictureConfigs.push({
+          i: area.i,
+          x: area.x,
+          y: area.y,
+          w: area.w,
+          h: area.h,
+          qStruct,
         });
       });
     });
-    return questions;
+
+    // 合并相邻区域
+    const combinePictureConfigList = combinePictureConfig(pictureConfigs);
+    // console.log(combinePictureConfigList);
+    return combinePictureConfigList;
   }
 
-  function parseQuestionAreas(questions: QuestionItem[]) {
+  // 通过题卡获取试题评卷区
+  function parseCardQuestionAreas(questions: QuestionItem[]) {
     if (!questions.length || !cardData?.length) return [];
 
     const pictureConfigs: QuestionArea[] = [];
@@ -854,6 +986,13 @@ export default function useDraw(drawConfig: DrawConfig) {
     // console.log(pictureConfigs);
 
     // 合并相邻区域
+    const combinePictureConfigList: QuestionArea[] =
+      combinePictureConfig(pictureConfigs);
+    // console.log(combinePictureConfigList);
+    return combinePictureConfigList;
+  }
+
+  function combinePictureConfig(pictureConfigs: QuestionArea[]) {
     pictureConfigs.sort((a, b) => {
       return a.i - b.i || a.x - b.x || a.y - b.y;
     });
@@ -1022,10 +1161,10 @@ export default function useDraw(drawConfig: DrawConfig) {
   // mode4 data
   function getMode4MarkerName(q: Question): string {
     let markerName = '';
-    if (q.headerTrack && q.headerTrack.length) {
-      markerName = q.headerTrack[0].userName;
-    } else if (q.trackList && q.trackList.length) {
-      markerName = q.trackList[0].userName;
+    if (q.headerTrackList && q.headerTrackList.length) {
+      markerName = q.headerTrackList[0].userName;
+    } else if (q.markerTrackList && q.markerTrackList.length) {
+      markerName = q.markerTrackList[0].userName;
     } else if (q.markerList && q.markerList.length) {
       let markers = q.markerList.filter((marker) => marker.header);
       if (!markers.length) {
@@ -1038,7 +1177,7 @@ export default function useDraw(drawConfig: DrawConfig) {
 
   function parseMode4Data(img: ImageItem): DrawTrackItem[] {
     const isDoubleMark = (rawTask.questionList || []).some((question) => {
-      let userIds = question.trackList.map((track) => track.userId);
+      let userIds = question.markerTrackList.map((track) => track.userId);
       if (
         !userIds.length &&
         question.markerList &&