Ver Fonte

feat: 轨迹调整

zhangjie há 2 meses atrás
pai
commit
829713bc29
3 ficheiros alterados com 159 adições e 138 exclusões
  1. 12 0
      src/api/task.ts
  2. 39 8
      src/api/types/task.ts
  3. 108 130
      src/views/base/track-export/useDraw.ts

+ 12 - 0
src/api/task.ts

@@ -13,6 +13,7 @@ import {
   CourseQueryParams,
   CourseQueryParams,
   PaperNumberQueryParams,
   PaperNumberQueryParams,
   TrackExportDetailListPageRes,
   TrackExportDetailListPageRes,
+  StudentTrackTask,
 } from './types/task';
 } from './types/task';
 
 
 // semester
 // semester
@@ -109,3 +110,14 @@ export async function getMarkArea(studentId: string): Promise<MarkArea[]> {
     { params: { studentId } }
     { params: { studentId } }
   );
   );
 }
 }
+
+/** 查看单个学生的试卷轨迹-聚合版 */
+export async function getStudentTrack(
+  studentId: string
+): Promise<StudentTrackTask> {
+  return axios.post(
+    '/api/admin/mark/archive/student/question/track',
+    {},
+    { params: { studentId } }
+  );
+}

+ 39 - 8
src/api/types/task.ts

@@ -47,7 +47,7 @@ export interface Track {
   /** 大题号 */
   /** 大题号 */
   mainNumber: number;
   mainNumber: number;
   /** 小题号,当前api中只有number // 特殊标记中没有 */
   /** 小题号,当前api中只有number // 特殊标记中没有 */
-  subNumber: string;
+  subNumber: number;
   /** 前端使用,暂时用不着,赋0 */
   /** 前端使用,暂时用不着,赋0 */
   number: number;
   number: number;
   /** 评分数 */
   /** 评分数 */
@@ -71,7 +71,7 @@ export interface SpecialTag {
   /** 大题号 */
   /** 大题号 */
   mainNumber: number;
   mainNumber: number;
   /** 小题号,当前api中只有number */
   /** 小题号,当前api中只有number */
-  subNumber: string;
+  subNumber: number;
   /** 第几张图 */
   /** 第几张图 */
   offsetIndex: number;
   offsetIndex: number;
   /** 左上角为原点(原图的原点),及相对原图的位置比例 */
   /** 左上角为原点(原图的原点),及相对原图的位置比例 */
@@ -95,7 +95,7 @@ export interface Question {
   /** 大题号 */
   /** 大题号 */
   mainNumber: number;
   mainNumber: number;
   /** 小题号 */
   /** 小题号 */
-  subNumber: string;
+  subNumber: number;
   /** 分数间隔 */
   /** 分数间隔 */
   intervalScore: number;
   intervalScore: number;
   /** 默认分数 */
   /** 默认分数 */
@@ -197,7 +197,7 @@ export type StudentObjectiveInfo = {
   sheetUrls: Array<{ index: number; url: string; recogData: string }>;
   sheetUrls: Array<{ index: number; url: string; recogData: string }>;
   answers: Array<{
   answers: Array<{
     mainNumber: number;
     mainNumber: number;
-    subNumber: string;
+    subNumber: number;
     answer: string;
     answer: string;
     exist: boolean;
     exist: boolean;
     questionType: string;
     questionType: string;
@@ -210,14 +210,11 @@ export type StudentObjectiveInfo = {
 };
 };
 
 
 export interface MarkArea {
 export interface MarkArea {
-  title: string;
   mainNumber: number;
   mainNumber: number;
   subNumber: number;
   subNumber: number;
-  score: number;
-  picList: string;
   // 1: 单选 2: 多选 3: 判断 4: 填空 5: 问答
   // 1: 单选 2: 多选 3: 判断 4: 填空 5: 问答
   questionType: 1 | 2 | 3 | 4 | 5;
   questionType: 1 | 2 | 3 | 4 | 5;
-  splitConfig?: SplitConfig[];
+  splitConfig: SplitConfig[];
 }
 }
 
 
 // card --------->
 // card --------->
@@ -279,3 +276,37 @@ export interface TrackExportDetailItem {
   totalScore: number;
   totalScore: number;
 }
 }
 export type TrackExportDetailListPageRes = PageResult<TrackExportDetailItem>;
 export type TrackExportDetailListPageRes = PageResult<TrackExportDetailItem>;
+
+export interface SubjectiveQuestion extends Question {
+  picList: SplitConfig[];
+  // 1-单选,2-多选,3-判断,4-填空,5-问答
+  questionType: 1 | 2 | 3 | 4 | 5;
+}
+export interface objectiveQuestion {
+  mainNumber: number;
+  subNumber: number;
+  answer: string;
+  exist: boolean;
+  standardAnswer: string;
+  score: number;
+  totalScore: number;
+  // 1-单选,2-多选,3-判断
+  questionType: 1 | 2 | 3;
+}
+export interface StudentTrackTask {
+  examId: string;
+  studentId: string;
+  secretNumber: string;
+  studentName: string;
+  studentCode: string;
+  courseCode: string;
+  courseName: string;
+  paperNumber: string;
+  paperType: string;
+  objectiveScore: number;
+  subjectiveScore: number;
+  sheetUrls: Array<{ index: number; url: string; recogData: string }>;
+  subjectiveQuestions: SubjectiveQuestion[];
+  objectiveQuestions: objectiveQuestion[];
+  cardContent: string;
+}

+ 108 - 130
src/views/base/track-export/useDraw.ts

@@ -1,17 +1,5 @@
-import {
-  getSingleStudentTaskOfStudentTrack,
-  studentObjectiveConfirmData,
-  getSingleStudentCardData,
-  getMarkArea,
-} from '@/api/task';
-import {
-  Task,
-  Track,
-  SpecialTag,
-  Question,
-  MarkArea,
-  SplitConfig,
-} from '@/api/types/task';
+import { getStudentTrack } from '@/api/task';
+import { Task, Track, SpecialTag, Question, MarkArea } from '@/api/types/task';
 import { TrackConfigType } from '@/store/modules/app/types';
 import { TrackConfigType } from '@/store/modules/app/types';
 import { PictureTypeEnum, PICTURE_TYPE } from '@/constants/enumerate';
 import { PictureTypeEnum, PICTURE_TYPE } from '@/constants/enumerate';
 import {
 import {
@@ -103,7 +91,7 @@ type UserMapType = Record<
     userId: string;
     userId: string;
     userName: string;
     userName: string;
     color: string;
     color: string;
-    scores: Array<{ subNumber: string; score: number }>;
+    scores: Array<{ subNumber: number; score: number }>;
     prename: string;
     prename: string;
     score: number;
     score: number;
   }
   }
@@ -144,7 +132,7 @@ export default function useDraw(drawConfig: DrawConfig) {
 
 
   let answerMap = {} as AnswerMap;
   let answerMap = {} as AnswerMap;
   let cardData = [] as CardDataItem[];
   let cardData = [] as CardDataItem[];
-  let markAreaList = [] as MarkArea[];
+  let markAreas = [] as MarkArea[];
   let recogDatas: string[] = [];
   let recogDatas: string[] = [];
   let rawTask = {} as Task;
   let rawTask = {} as Task;
   let trackData = [] as TrackItemType[];
   let trackData = [] as TrackItemType[];
@@ -245,53 +233,53 @@ export default function useDraw(drawConfig: DrawConfig) {
   }
   }
 
 
   async function getTaskData(studentId: string) {
   async function getTaskData(studentId: string) {
-    const funcs = [
-      async () => {
-        rawTask = await getSingleStudentTaskOfStudentTrack(studentId);
-        if (!rawTask.sheetUrls) rawTask.sheetUrls = [];
-      },
-    ];
+    const res = await getStudentTrack(studentId);
+    if (!res?.studentId) return;
+
+    rawTask = {
+      examId: res.examId,
+      studentId: res.studentId,
+      secretNumber: res.secretNumber,
+      courseCode: res.courseCode,
+      courseName: res.courseName,
+      paperNumber: res.paperNumber,
+      studentCode: res.studentCode,
+      studentName: res.studentName,
+      paperType: res.paperType,
+      objectiveScore: res.objectiveScore || 0,
+      markerScore: (res.objectiveScore || 0) + (res.subjectiveScore || 0),
+      sheetUrls: res.sheetUrls ? res.sheetUrls.map((item) => item.url) : [],
+      questionList: res.subjectiveQuestions,
+      sliceConfig: [],
+      jsonUrl: '',
+      markerTime: 0,
+    };
+    recogDatas = (res.sheetUrls || []).map((item) => item.recogData);
 
 
-    if (hasTrack || hasPdf) {
-      funcs.push(async () => {
-        // 获取客观题选项信息
-        const objectiveData = await studentObjectiveConfirmData(studentId);
-        objectiveData.answers.forEach((item) => {
-          answerMap[`${item.mainNumber}_${item.subNumber}`] = {
-            answer: item.answer,
-            totalScore: item.totalScore,
-            score: item.score,
-            isRight: item.answer === item.standardAnswer,
-          };
-        });
-        recogDatas = objectiveData.sheetUrls.map((item) => item.recogData);
-      });
+    markAreas = res.subjectiveQuestions.map((item) => {
+      return {
+        mainNumber: item.mainNumber,
+        subNumber: item.subNumber,
+        questionType: item.questionType,
+        splitConfig: item.picList || [],
+      };
+    });
 
 
-      funcs.push(async () => {
-        // 获取题卡数据
-        const cardRes = await getSingleStudentCardData(studentId);
-        const cardContent =
-          cardRes && cardRes.content
-            ? (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,
-          };
-        });
-      });
-    }
+    // 获取客观题选项信息
+    res.objectiveQuestions.forEach((item) => {
+      answerMap[`${item.mainNumber}_${item.subNumber}`] = {
+        answer: item.answer,
+        totalScore: item.totalScore,
+        score: item.score,
+        isRight: item.answer === item.standardAnswer,
+      };
+    });
 
 
-    await Promise.all(funcs.map((func) => func()));
+    // 获取题卡数据
+    const cardCont: CardContentType = res.cardContent
+      ? JSON.parse(res.cardContent)
+      : { pages: [] };
+    cardData = cardCont.pages;
   }
   }
 
 
   /**
   /**
@@ -401,11 +389,6 @@ export default function useDraw(drawConfig: DrawConfig) {
         drawTrackList,
         drawTrackList,
       };
       };
     }
     }
-
-    if (!cardData.length) {
-      const summarys = parseMode4Data(originImgs[0]);
-      trackData[0].drawTrackList.push(...summarys);
-    }
   }
   }
 
 
   async function drawTask(): Promise<ImageItem[]> {
   async function drawTask(): Promise<ImageItem[]> {
@@ -891,8 +874,10 @@ export default function useDraw(drawConfig: DrawConfig) {
 
 
   // 通过评卷区获取属于填空题的试题号
   // 通过评卷区获取属于填空题的试题号
   function getFillLines() {
   function getFillLines() {
+    if (!markAreas?.length) return {};
+
     const questions: Record<number, string[]> = {};
     const questions: Record<number, string[]> = {};
-    markAreaList.forEach((markArea) => {
+    markAreas.forEach((markArea) => {
       const { mainNumber, subNumber, questionType } = markArea;
       const { mainNumber, subNumber, questionType } = markArea;
       if (questionType !== 4) return;
       if (questionType !== 4) return;
       if (!questions[mainNumber]) questions[mainNumber] = [];
       if (!questions[mainNumber]) questions[mainNumber] = [];
@@ -903,24 +888,14 @@ export default function useDraw(drawConfig: DrawConfig) {
 
 
   // 获取题型的评卷区
   // 获取题型的评卷区
   function parseQuestionAreas(questions: QuestionItem[]) {
   function parseQuestionAreas(questions: QuestionItem[]) {
-    if (!questions.length || !cardData?.length || !markAreaList.length)
-      return [];
-
-    return cardData.length
-      ? parseCardQuestionAreas(questions)
-      : parseMarkAreaQuestionAreas(questions);
-  }
-
-  // 获取设置的评卷获取试题评卷区
-  function parseMarkAreaQuestionAreas(questions: QuestionItem[]) {
-    if (!questions.length || !markAreaList?.length) return [];
+    if (!questions.length || !markAreas?.length) return [];
 
 
     const pictureConfigs: QuestionArea[] = [];
     const pictureConfigs: QuestionArea[] = [];
     const structs = questions.map(
     const structs = questions.map(
       (item) => `${item.mainNumber}_${item.subNumber}`
       (item) => `${item.mainNumber}_${item.subNumber}`
     );
     );
 
 
-    markAreaList.forEach((markArea) => {
+    markAreas.forEach((markArea) => {
       const qStruct = `${markArea.mainNumber}_${markArea.subNumber}`;
       const qStruct = `${markArea.mainNumber}_${markArea.subNumber}`;
       if (!structs.includes(qStruct)) return;
       if (!structs.includes(qStruct)) return;
 
 
@@ -943,60 +918,61 @@ export default function useDraw(drawConfig: DrawConfig) {
   }
   }
 
 
   // 通过题卡获取试题评卷区
   // 通过题卡获取试题评卷区
-  function parseCardQuestionAreas(questions: QuestionItem[]) {
-    if (!questions.length || !cardData?.length) return [];
-
-    const pictureConfigs: QuestionArea[] = [];
-    const structs = questions.map(
-      (item) => `${item.mainNumber}_${item.subNumber}`
-    );
-    cardData.forEach((page, pindex) => {
-      page.exchange.answer_area.forEach((area) => {
-        const [x, y, w, h] = area.area;
-        const qStruct = `${area.main_number}_${area.sub_number}`;
-
-        const pConfig: QuestionArea = {
-          i: pindex + 1,
-          x,
-          y,
-          w,
-          h,
-          qStruct,
-        };
-
-        if (typeof area.sub_number === 'number') {
-          if (!structs.includes(qStruct)) return;
-          pictureConfigs.push(pConfig);
-          return;
-        }
-        // 复合区域处理,比如填空题,多个小题合并为一个区域
-        if (typeof area.sub_number === 'string') {
-          const areaStructs = area.sub_number
-            .split(',')
-            .map((subNumber) => `${area.main_number}_${subNumber}`);
-          if (
-            structs.some((struct) => areaStructs.includes(struct)) &&
-            !pictureConfigs.find((item) => item.qStruct === qStruct)
-          ) {
-            pictureConfigs.push(pConfig);
-          }
-        }
-      });
-    });
-    // console.log(pictureConfigs);
+  // function parseCardQuestionAreas(questions: QuestionItem[]) {
+  //   if (!questions.length || !cardData?.length) return [];
+
+  //   const pictureConfigs: QuestionArea[] = [];
+  //   const structs = questions.map(
+  //     (item) => `${item.mainNumber}_${item.subNumber}`
+  //   );
+  //   cardData.forEach((page, pindex) => {
+  //     page.exchange.answer_area.forEach((area) => {
+  //       const [x, y, w, h] = area.area;
+  //       const qStruct = `${area.main_number}_${area.sub_number}`;
+
+  //       const pConfig: QuestionArea = {
+  //         i: pindex + 1,
+  //         x,
+  //         y,
+  //         w,
+  //         h,
+  //         qStruct,
+  //       };
+
+  //       if (typeof area.sub_number === 'number') {
+  //         if (!structs.includes(qStruct)) return;
+  //         pictureConfigs.push(pConfig);
+  //         return;
+  //       }
+  //       // 复合区域处理,比如填空题,多个小题合并为一个区域
+  //       if (typeof area.sub_number === 'string') {
+  //         const areaStructs = area.sub_number
+  //           .split(',')
+  //           .map((subNumber) => `${area.main_number}_${subNumber}`);
+  //         if (
+  //           structs.some((struct) => areaStructs.includes(struct)) &&
+  //           !pictureConfigs.find((item) => item.qStruct === qStruct)
+  //         ) {
+  //           pictureConfigs.push(pConfig);
+  //         }
+  //       }
+  //     });
+  //   });
+  //   // console.log(pictureConfigs);
 
 
-    // 合并相邻区域
-    const combinePictureConfigList: QuestionArea[] =
-      combinePictureConfig(pictureConfigs);
-    // console.log(combinePictureConfigList);
-    return combinePictureConfigList;
-  }
+  //   // 合并相邻区域
+  //   const combinePictureConfigList: QuestionArea[] =
+  //     combinePictureConfig(pictureConfigs);
+  //   // console.log(combinePictureConfigList);
+  //   return combinePictureConfigList;
+  // }
 
 
   function combinePictureConfig(pictureConfigs: QuestionArea[]) {
   function combinePictureConfig(pictureConfigs: QuestionArea[]) {
     pictureConfigs.sort((a, b) => {
     pictureConfigs.sort((a, b) => {
       return a.i - b.i || a.x - b.x || a.y - b.y;
       return a.i - b.i || a.x - b.x || a.y - b.y;
     });
     });
     const combinePictureConfigList: QuestionArea[] = [];
     const combinePictureConfigList: QuestionArea[] = [];
+    const elasticRate = 0.01;
     let prevConfig = {} as QuestionArea;
     let prevConfig = {} as QuestionArea;
     pictureConfigs.forEach((item, index) => {
     pictureConfigs.forEach((item, index) => {
       if (!index) {
       if (!index) {
@@ -1005,7 +981,6 @@ export default function useDraw(drawConfig: DrawConfig) {
         return;
         return;
       }
       }
 
 
-      const elasticRate = 0.01;
       if (
       if (
         prevConfig.i === item.i &&
         prevConfig.i === item.i &&
         prevConfig.y + prevConfig.h + elasticRate >= item.y &&
         prevConfig.y + prevConfig.h + elasticRate >= item.y &&
@@ -1158,8 +1133,9 @@ export default function useDraw(drawConfig: DrawConfig) {
   }
   }
   // objective answer tag ----- end->
   // objective answer tag ----- end->
 
 
-  // mode4 data
-  function getMode4MarkerName(q: Question): string {
+  /* 首页汇总信息
+  // 获取汇总记录中评卷员信息
+  function getSummaryMarkerName(q: Question): string {
     let markerName = '';
     let markerName = '';
     if (q.headerTrackList && q.headerTrackList.length) {
     if (q.headerTrackList && q.headerTrackList.length) {
       markerName = q.headerTrackList[0].userName;
       markerName = q.headerTrackList[0].userName;
@@ -1175,7 +1151,8 @@ export default function useDraw(drawConfig: DrawConfig) {
     return markerName;
     return markerName;
   }
   }
 
 
-  function parseMode4Data(img: ImageItem): DrawTrackItem[] {
+  // 解析首页汇总信息
+  function parseSummaryData(img: ImageItem): DrawTrackItem[] {
     const isDoubleMark = (rawTask.questionList || []).some((question) => {
     const isDoubleMark = (rawTask.questionList || []).some((question) => {
       let userIds = question.markerTrackList.map((track) => track.userId);
       let userIds = question.markerTrackList.map((track) => track.userId);
       if (
       if (
@@ -1199,7 +1176,7 @@ export default function useDraw(drawConfig: DrawConfig) {
       sources.push([
       sources.push([
         `${q.mainNumber}-${q.subNumber}`,
         `${q.mainNumber}-${q.subNumber}`,
         `${q.score}`,
         `${q.score}`,
-        getMode4MarkerName(q),
+        getSummaryMarkerName(q),
       ]);
       ]);
     });
     });
 
 
@@ -1225,6 +1202,7 @@ export default function useDraw(drawConfig: DrawConfig) {
 
 
     return dataList;
     return dataList;
   }
   }
+  */
 
 
   return {
   return {
     runTask,
     runTask,