Explorar o código

完善练习跳转

shmily1213 hai 2 semanas
pai
achega
c682f8d5ed

+ 10 - 1
src/api/modules/study.ts

@@ -1,6 +1,6 @@
 import { ApiResponse, ApiResponseList } from "@/types";
 import flyio from "../flyio";
-import { DirectedSchool, Examinee, ExamPaper, ExamPaperSubmit, GetExamPaperRequestDTO, Knowledge, KnowledgeListRequestDTO, KnowledgeRecord, OpenExamineeRequestDTO, PracticeRecord, SimulatedRecord, SimulationExamSubject, SimulationTestInfo, StudyPlan, Subject, SubjectListRequestDTO, VideoStudyRecord } from "@/types/study";
+import { DirectedSchool, Examinee, ExamPaper, ExamPaperSubmit, GetExamPaperRequestDTO, Knowledge, KnowledgeListRequestDTO, KnowledgeRecord, OpenExamineeRequestDTO, PracticeHistory, PracticeRecord, SimulatedRecord, SimulationExamSubject, SimulationTestInfo, StudyPlan, Subject, SubjectListRequestDTO, VideoStudyRecord } from "@/types/study";
 
 /**
  * 获取学习计划
@@ -197,3 +197,12 @@ export function beginExaminee(examineeId: number) {
 export function correctQuestion(params: { questionid: number, remark: string }) {
   return flyio.post('/front/adjustWrong/correctQuestion', params) as Promise<ApiResponse<any>>;
 }
+
+/**
+ * 获取计划学习记录
+ * @param params 
+ * @returns 
+ */
+export function getPracticeHistory() {
+  return flyio.get('/front/student/record/practice', {}) as Promise<ApiResponseList<PracticeHistory>>;
+}

+ 27 - 26
src/composables/useExam.ts

@@ -68,11 +68,11 @@ export const useExam = () => {
     function parseQuestion(qs: Study.Question, parentIndex: number) {
       if (qs.subQuestions && qs.subQuestions.length > 0) {
         qs.subQuestions.forEach((item, index) => {
-          item.isSubQuestion = true;
-          item.parentId = qs.id;
-          item.parentTypeId = qs.typeId;
-          item.subIndex = index;
-          item.parentIndex = parentIndex;
+          // item.isSubQuestion = true;
+          // item.parentId = qs.id;
+          // item.parentTypeId = qs.typeId;
+          // item.subIndex = index;
+          // item.parentIndex = parentIndex;
           item.isDone = isDone(item);
         });
       } else {
@@ -86,6 +86,10 @@ export const useExam = () => {
     console.log('重新计算')
     return questionList.value.map((item, index) => {
       return parseQuestion(item, index)
+      // return {
+      //   ...item,
+      //   // isDone: isDone(item)
+      // };
     });
   });
   const groupedQuestionList = computed(() => {
@@ -137,7 +141,8 @@ export const useExam = () => {
     return state;
   });
   const isAllDone = computed(() => {
-    return questionList.value.every(q => isDone(q));
+    // return questionList.value.every(q => isDone(q));
+    return doneCount.value === virtualTotalCount.value;
   });
   // 当前下标
   const currentIndex = ref<number>(0);
@@ -151,15 +156,16 @@ export const useExam = () => {
     let count = 0;
     for (let i = 0; i <= stateQuestionList.value.length - 1; i++) {
       const qs = stateQuestionList.value[i];
-      if (qs.isDone || qs.isNotKnow) {
-        count++;
-      }
       if (qs.subQuestions && qs.subQuestions.length > 0) {
         qs.subQuestions.forEach(subQs => {
-          if (subQs.isDone || subQs.isNotKnow) {
+          if (subQs.isDone) {
             count++;
           }
         });
+      } else {
+        if (qs.isDone) {
+          count++;
+        }
       }
     }
     return count;
@@ -301,30 +307,25 @@ export const useExam = () => {
         isCorrect: isCorrect(item)
       } as Study.Question
     }
-    const arr: Study.Question[] = list.map(item => {
-      return transerQuestion(item);
-    });
-    const qsList: Study.Question[] = [];
-    const parseQuestion = (qs: Study.Question) => {
+    const parseQuestion = (qs: Study.Question, parentIndex: number) => {
       if (qs.subQuestions && qs.subQuestions.length > 0) {
-        qs.isSubQuestion = true;
-        qs.isDone = isDone(qs);
         qs.subQuestions.forEach((item, index) => {
+          item.isSubQuestion = true;
           item.parentId = qs.id;
           item.parentTypeId = qs.typeId;
           item.subIndex = index;
-          // parseQuestion(item);
+          item.parentIndex = parentIndex;
+          // item.isDone = isDone(item);
         });
       } else {
-        qsList.push({
-          ...qs,
-          isSubQuestion: false,
-          isDone: isDone(qs)
-        });
+        qs.isSubQuestion = false;
+        // qs.isDone = isDone(qs);
       }
-    };
-    // arr.forEach(parseQuestion);
-    // return qsList;
+      return qs;
+    }
+    const arr: Study.Question[] = list.map((item, index) => {
+      return parseQuestion(transerQuestion(item), index);
+    });
     questionList.value = arr;
   }
   const reset = () => {

+ 15 - 42
src/pagesStudy/pages/exam-start/components/question-item.vue

@@ -40,7 +40,8 @@
             <uv-icon name="info-circle" color="#31A0FC" size="16" />
             <text>主观题请线下答题,查看解析对比后,选“会”或“不会”</text>
           </view>
-          <view class="mt-30 mb-20 text-24 text-white bg-primary w-fit mx-auto px-20 py-12 rounded-full text-center" @click="handleShowParse">
+          <view class="mt-30 mb-20 text-24 text-white bg-primary w-fit mx-auto px-20 py-12 rounded-full text-center"
+            @click="handleShowParse">
             查看解析</view>
         </view>
       </view>
@@ -76,15 +77,14 @@
         <view class="flex items-center px-20 gap-x-20">
           <view class="px-40 py-8 rounded-full"
             :class="[subIndex === subQuestionIndex ? 'bg-[#EBF9FF] text-primary font-bold' : 'bg-back']"
-            v-for="(subQuestion, subIndex) in question.subQuestions" @click="handleSubQuestionClick(subIndex)">
+            v-for="(subQuestion, subIndex) in question.subQuestions" @click="changeSubQuestion(subIndex)">
             {{ index + subIndex + 1 }}
           </view>
         </view>
       </scroll-view>
       <view v-if="subQuestion">
         <question-item :question="subQuestion" :readonly="readonly" :is-sub-question="true" :index="index"
-          :total="question.subQuestions.length" @update:question="handleSubQuestionUpdate" @select="handleSelectOption"
-          @notKnow="handleSelectNotKnow" />
+          :total="question.subQuestions.length" @select="handleSelectOption" @notKnow="handleSelectNotKnow" />
       </view>
     </view>
   </view>
@@ -94,7 +94,7 @@
 import { Study } from '@/types';
 import { useExam } from '@/composables/useExam';
 import { EnumQuestionType } from '@/common/enum';
-import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUICKLY } from '@/types/injectionSymbols';
+import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUICKLY, SHOW_SUBMIT_CONFIRM, IS_ALL_DONE } from '@/types/injectionSymbols';
 const { questionTypeDesc } = useExam();
 const props = defineProps<{
   question: Study.Question;
@@ -108,6 +108,7 @@ const nextQuestion = inject(NEXT_QUESTION);
 const prevQuestion = inject(PREV_QUESTION);
 const nextQuestionQuickly = inject(NEXT_QUESTION_QUICKLY);
 const prevQuestionQuickly = inject(PREV_QUESTION_QUICKLY);
+const isAllDone = inject(IS_ALL_DONE);
 const subQuestion = computed(() => {
   return props.question.subQuestions[props.subQuestionIndex ?? 0];
 });
@@ -118,6 +119,7 @@ const emit = defineEmits<{
   (e: 'scrollTo', selector: string): void;
   (e: 'changeSubQuestion', index: number): void;
   (e: 'selectSubQuestion', index: number): void;
+  (e: 'changeQuestion', question: Study.Question): void;
 }>();
 const isOnlySubjective = computed(() => {
   return props.question.typeId === EnumQuestionType.SUBJECTIVE;
@@ -178,16 +180,11 @@ const getOptionContent = (option: Study.QuestionOption) => {
 }
 const handleShowParse = () => {
   props.question.showParse = !props.question.showParse;
-  emit('update:question', props.question);
 }
 const handleNotKnow = () => {
   props.question.answers = [];
   props.question.isNotKnow = !props.question.isNotKnow;
   checkIsDone();
-  emit('update:question', props.question);
-  // emit('notKnow', props.question);
-  // nextQuestion?.();
-  // handleSelectNotKnow();
   if (props.isSubQuestion) {
     emit('select', props.question);
   } else {
@@ -218,25 +215,16 @@ const handleSelect = (option: Study.QuestionOption) => {
   }
   props.question.isNotKnow = false;
   checkIsDone();
-  emit('update:question', props.question);
 
-  // props.question.answer = option.no;
   if (props.isSubQuestion) {
     emit('select', props.question);
   } else {
-    // 没有子题的,直接切换到下一题
-    changeQuestion();
+    changeQuestion()
   }
 }
-const handleSubQuestionClick = (index: number) => {
-  emit('changeSubQuestion', index);
-}
-const handleSubQuestionUpdate = (question: Study.Question) => {
-  emit('update:question', question);
-  checkIsDone();
-}
+
 const checkIsDone = () => {
-  if (props.question.subQuestions.length > 0) {
+  if (props.question.subQuestions && props.question.subQuestions.length > 0) {
     props.question.isDone = props.question.subQuestions.every(q => q.answers.length > 0 || q.isNotKnow);
   } else {
     props.question.isDone = props.question.answers.length > 0 || props.question.isNotKnow;
@@ -244,43 +232,28 @@ const checkIsDone = () => {
 }
 // 子题选中方法
 const handleSelectOption = () => {
-  // changeQuestion();
   findNotDoneSubQuestion();
 }
 const handleSelectNotKnow = () => {
-  // changeQuestion();
   findNotDoneSubQuestion();
 }
 // 查找是否有子题没有做,有的话就自动滚动到目标处
 const findNotDoneSubQuestion = () => {
   const notDoneSubQuestion = props.question.subQuestions.find(q => !q.isDone);
-  console.log(notDoneSubQuestion)
   if (notDoneSubQuestion) {
-    const selector = `qs_${notDoneSubQuestion.id}`;
-    // 通知父组件滚动
-    // emit('scrollTo', selector);
     if (notDoneSubQuestion.subIndex !== undefined) {
-      emit('changeSubQuestion', notDoneSubQuestion.subIndex);
+      changeSubQuestion(notDoneSubQuestion.subIndex);
     }
   } else {
     // 否则切换到下一题
     changeQuestion();
   }
 }
+const changeSubQuestion = (index: number) => {
+  emit('changeSubQuestion', index);
+}
 const changeQuestion = () => {
-  // 判断是多选还是单选
-  if (props.question.typeId === EnumQuestionType.MULTIPLE_CHOICE) {
-    // 多选题,选择不会时切换下一题,否则不自动切换
-    if (props.question.isNotKnow) {
-      nextQuestion?.();
-    } else {
-      return;
-    }
-  } else {
-    if (props.question.isDone) {
-      nextQuestion?.();
-    }
-  }
+  emit('changeQuestion', props.question);
 }
 
 const isSelected = (option: Study.QuestionOption) => {

+ 5 - 2
src/pagesStudy/pages/exam-start/components/question-wrap.vue

@@ -4,7 +4,7 @@
     <view class="h-20"></view>
     <question-item :question="question" :readonly="readonly" :index="index" :subQuestionIndex="subQuestionIndex"
       @update:question="emit('update:question', $event)" @scrollTo="handleScrollTo"
-      @changeSubQuestion="handleChangeSubQuestion" />
+      @changeSubQuestion="handleChangeSubQuestion" @change-question="handleChangeQuestion" />
     <view class="h-20"></view>
   </scroll-view>
 </template>
@@ -25,6 +25,7 @@ const visible = computed(() => {
 const emit = defineEmits<{
   (e: 'update:question', question: Study.Question): void;
   (e: 'changeSubQuestion', index: number): void;
+  (e: 'changeQuestion', question: Study.Question): void;
 }>();
 const handleChangeSubQuestion = (index: number) => {
   emit('changeSubQuestion', index);
@@ -39,7 +40,9 @@ const handleScrollTo = (selector: string) => {
     }
   }, 200);
 }
-
+const handleChangeQuestion = (question: Study.Question) => {
+  emit('changeQuestion', question);
+}
 </script>
 
 <style lang="scss" scoped>

+ 43 - 18
src/pagesStudy/pages/exam-start/exam-start.vue

@@ -24,8 +24,8 @@
             <block v-for="(item, index) in questionList" :key="item.id">
               <swiper-item class="h-full" v-show="Math.abs(currentIndex - index) <= 2">
                 <question-wrap :question="item" :currentIndex="currentIndex" :index="index"
-                  :subQuestionIndex="subQuestionIndex" :readonly="isReadOnly" @update:question="handleUpdateQuestion"
-                  @changeSubQuestion="handleChangeSubQuestion" />
+                  :subQuestionIndex="subQuestionIndex" :readonly="isReadOnly"
+                  @changeSubQuestion="handleChangeSubQuestion" @change-question="handleChangeQuestion" />
               </swiper-item>
             </block>
           </swiper>
@@ -57,7 +57,7 @@
       <view class="ml-20">
         <text class="text-30 text-primary">{{ doneCount }}</text>
         <text>/</text>
-        <text class="text-30 text-fore-light">{{ totalCount }}</text>
+        <text class="text-30 text-fore-light">{{ virtualTotalCount }}</text>
       </view>
     </template>
     <view class="popup-content">
@@ -115,11 +115,11 @@ import QuestionCorrectPopup from './components/question-correct-popup.vue';
 import QuestionSwiperTip from './components/question-swiper-tip.vue';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { useUserStore } from '@/store/userStore';
-import { EnumPaperType } from '@/common/enum';
+import { EnumPaperType, EnumQuestionType } from '@/common/enum';
 import { getOpenExaminee, getPaper, commitExamineePaper, collectQuestion, cancelCollectQuestion, beginExaminee, getExamineeResult } from '@/api/modules/study';
 import { useExam } from '@/composables/useExam';
 import { Study } from '@/types';
-import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUICKLY } from '@/types/injectionSymbols';
+import { NEXT_QUESTION, PREV_QUESTION, NEXT_QUESTION_QUICKLY, PREV_QUESTION_QUICKLY, SHOW_SUBMIT_CONFIRM, IS_ALL_DONE } from '@/types/injectionSymbols';
 
 const userStore = useUserStore();
 // import { Examinee, ExamPaper, ExamPaperSubmit } from '@/types/study';
@@ -130,10 +130,6 @@ const { setQuestionList, questionList, groupedQuestionList, questionTypeDesc,
   notDoneCount, isAllDone, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
   formatPracticeDuration, practiceDuration, startPracticeDuration, stopPracticeDuration, changeIndex, setDuration, reset } = useExam();
 
-provide(NEXT_QUESTION, nextQuestion);
-provide(PREV_QUESTION, prevQuestion);
-provide(NEXT_QUESTION_QUICKLY, nextQuestionQuickly);
-provide(PREV_QUESTION_QUICKLY, prevQuestionQuickly);
 //
 const showSwiperTip = ref(false);
 const guideShow = ref(false);
@@ -172,6 +168,13 @@ const hasShowSubmitConfirm = ref(false);
 const examineeId = ref<number | undefined>(undefined);
 // const examineerData = ref<Study.Examinee>({} as Study.Examinee);
 const paperData = ref<Study.ExamPaper>({} as Study.ExamPaper);
+
+provide(NEXT_QUESTION, nextQuestion);
+provide(PREV_QUESTION, prevQuestion);
+provide(NEXT_QUESTION_QUICKLY, nextQuestionQuickly);
+provide(PREV_QUESTION_QUICKLY, prevQuestionQuickly);
+provide(IS_ALL_DONE, isAllDone);
+
 const pageTitle = computed(() => {
   if (isReadOnly.value) {
     return '考试解析';
@@ -364,7 +367,14 @@ const handleSubmit = (tempSave: boolean = false) => {
       questions: questionList.value.map(item => {
         return {
           ...item,
-          isDone: tempSave ? item.isDone : true
+          title: '',
+          isDone: tempSave ? item.isDone : true,
+          subQuestions: item.subQuestions.map(subItem => {
+            return {
+              ...subItem,
+              title: '',
+            };
+          })
         };
       }),
       examineeId: examineeId.value,
@@ -372,6 +382,7 @@ const handleSubmit = (tempSave: boolean = false) => {
       isDone: tempSave ? isAllDone.value : true,
       duration: practiceDuration.value
     } as Study.ExamPaperSubmit;
+    console.log(params, 123)
     commitExamineePaper(params);
     setTimeout(async () => {
       uni.$ie.hideLoading();
@@ -381,15 +392,28 @@ const handleSubmit = (tempSave: boolean = false) => {
   }, 1000);
 }
 
-const handleUpdateQuestion = (question: Study.Question) => {
-  if (currentIndex.value === questionList.value.length - 1) {
-    autoSubmit();
-  }
-}
 const handleChangeSubQuestion = (index: number) => {
-  console.log(index, 123)
   setSubQuestionIndex(index);
 }
+const handleChangeQuestion = (question: Study.Question) => {
+  if (isAllDone.value && !hasShowSubmitConfirm.value) {
+    autoSubmit();
+    return;
+  }
+  // 判断是多选还是单选
+  if (question.typeId === EnumQuestionType.MULTIPLE_CHOICE) {
+    // 多选题,选择不会时切换下一题,否则不自动切换
+    if (question.isNotKnow) {
+      nextQuestion?.();
+    } else {
+      return;
+    }
+  } else {
+    if (question.isDone) {
+      nextQuestion?.();
+    }
+  }
+}
 /**
  * 恢复上次做题历史数据
  * @param savedQuestion 上次做题历史数据
@@ -416,6 +440,7 @@ const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion:
       }
     }
   }
+  console.log(fullQuestion, 123)
   return fullQuestion;
 }
 const loadPracticeData = async () => {
@@ -449,7 +474,7 @@ const loadSimulationData = async () => {
     transferBack();
     return;
   }
-  totalExamTime.value = data.paperInfo.time;
+  totalExamTime.value = data.paperInfo?.time || 0;
   combinePaperData(data, paperType);
 }
 const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperType) => {
@@ -498,7 +523,7 @@ const loadData = async () => {
   const { paperType } = prevData.value;
   if (paperType === EnumPaperType.PRACTICE) {
     loadPracticeData();
-  } else {
+  } else if (paperType === EnumPaperType.SIMULATED) {
     loadSimulationData();
   }
 };

+ 36 - 20
src/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail.vue

@@ -6,7 +6,7 @@
         <rate-chart :value="rightRate" />
         <view class="h-1 bg-[#E6E6E6] my-20"></view>
         <view>
-          <view class="my-20 flex items-center justify-between text-24">
+          <view v-if="prevData.isDirected" class="my-20 flex items-center justify-between text-24">
             <ie-image src="/pagesStudy/static/image/icon-house.png" custom-class="w-24 h-24" mode="aspectFill" />
             <text class="ml-10 text-fore-light flex-1">练习科目</text>
             <text class="text-fore-title">{{ examineeData.collegeName }}-{{ examineeData.majorName }}</text>
@@ -14,7 +14,7 @@
           <view class="my-20 flex items-center justify-between text-24">
             <ie-image src="/pagesStudy/static/image/icon-group.png" custom-class="w-24 h-24" mode="aspectFill" />
             <text class="ml-10 text-fore-light flex-1">练习知识点</text>
-            <text class="text-fore-title">{{ examineeData.subjectName || '-' }}</text>
+            <text class="text-fore-title">{{ prevData.name || '-' }}</text>
           </view>
           <view class="my-20 flex items-center justify-between text-24">
             <ie-image src="/pagesStudy/static/image/icon-clock.png" custom-class="w-24 h-24" mode="aspectFill" />
@@ -23,14 +23,10 @@
           </view>
         </view>
       </view>
-      <exam-stat :data="examineeData" :show-stats="false" />
+      <exam-stat :data="examineeData" :show-stats="false" @detail="handleDetail" />
     </view>
     <ie-safe-toolbar :height="84" :shadow="false">
       <view class="h-[84px] px-46 bg-white flex items-center justify-between gap-x-40">
-        <!-- <view class="flex flex-col items-center justify-center">
-          <uv-icon name="clock" size="22" color="#31A0FC"></uv-icon>
-          <view class="text-28">记录</view>
-        </view> -->
         <view class="text-30 text-primary bg-back flex-1 py-22 rounded-full text-center" @click="handleStartPractice">
           继续刷题
         </view>
@@ -44,18 +40,20 @@
 <script lang="ts" setup>
 import RateChart from '@/pagesStudy/pages/simulation-analysis/components/rate-chart.vue';
 import ExamStat from '@/pagesStudy/pages/simulation-analysis/components/exam-stat.vue';
-import { useNavbar } from '@/hooks/useNavbar';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { Study } from '@/types';
+import { getExamineeResult } from '@/api/modules/study';
 import { EnumPaperType } from '@/common/enum';
 const { prevData, transferTo } = useTransferPage();
-const { baseStickyTop } = useNavbar();
+
 
 const rightRate = computed(() => {
   const { totalCount = 0, wrongCount = 0 } = examineeData.value;
   return Math.round((totalCount - wrongCount) / totalCount * 100) || 0;
 });
-
+const paperName = computed(() => {
+  return '知识点练习-' + prevData.value.name;
+});
 const examineeData = ref<Study.Examinee>({} as Study.Examinee);
 const pageTitle = computed(() => {
   return prevData.value.isDirected ? '定向练习结果' : '全量练习结果';
@@ -74,30 +72,48 @@ const formatTime = (time: number) => {
     return `${minutes}分${seconds}秒`;
   }
 };
-const handleStartPractice = () => {
+const handleDetail = (item: Study.ExamineeQuestion) => {
+  console.log(item, examineeData)
   transferTo('/pagesStudy/pages/exam-start/exam-start', {
     data: {
-      name: '知识点练习-' + examineeData.value.name,
-      paperType: EnumPaperType.PRACTICE,
+      name: paperName.value,
+      paperType: EnumPaperType.SIMULATED,
+      readonly: true,
+      questionId: item.id,
+      simulationInfo: {
+        examineeId: examineeData.value.examineeId,
+      }
     }
   });
 }
-const handleViewAnalysis = () => {
+const handleStartPractice = () => {
+  console.log(examineeData)
   // transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
   //   data: {
   //     examineeId: examineeData.value.id
   //   }
   // });
 }
+const handleViewAnalysis = () => {
+  transferTo('/pagesStudy/pages/exam-start/exam-start', {
+    data: {
+      name: paperName.value,
+      paperType: EnumPaperType.SIMULATED,
+      readonly: true,
+      simulationInfo: {
+        examineeId: examineeData.value.examineeId,
+      }
+    }
+  });
+}
 const loadData = async () => {
-  // uni.$ie.showLoading();
+  uni.$ie.showLoading();
   try {
-    // const res = await getKnowledgePracticeHistory();
-    // console.log(res);
+    const res = await getExamineeResult(prevData.value.id);
+    examineeData.value = res.data;
+    console.log(examineeData.value)
   } finally {
-    // setTimeout(() => {
-    //   uni.$ie.hideLoading();
-    // }, 1000);
+    uni.$ie.hideLoading();
   }
 }
 onLoad(() => {

+ 20 - 14
src/pagesStudy/pages/knowledge-practice-history/knowledge-practice-history.vue

@@ -2,20 +2,20 @@
   <ie-page bg-color="#F6F8FA" :fix-height="true">
     <ie-navbar title="刷题记录" />
     <view class="mt-20">
-      <view v-for="value in historyList" :key="value.id"
+      <view v-for="(item, index) in historyList" :key="index"
         class="bg-white px-40 py-30 flex items-center sibling-border-top">
         <view class="flex-1">
           <view class="text-28">
             <text class=" text-fore-light">知识点:</text>
-            <text class="text-fore-title">{{ value.name }}</text>
+            <text class="text-fore-title">{{ item.paperName }}</text>
           </view>
           <view class="mt-10 text-28">
             <text class=" text-fore-light">完成时间:</text>
-            <text class="text-fore-title">{{ value.time }}</text>
+            <text class="text-fore-title">{{ item.endTime }}</text>
           </view>
         </view>
         <view class="text-24 text-white bg-primary w-fit px-40 py-12 rounded-full text-center"
-          @click="handleViewHistory(value)">
+          @click="handleViewHistory(item)">
           查看
         </view>
       </view>
@@ -23,29 +23,35 @@
   </ie-page>
 </template>
 <script lang="ts" setup>
-import IePage from '@/components/ie-page/ie-page.vue';
 import { useNavbar } from '@/hooks/useNavbar';
 import { useTransferPage } from '@/hooks/useTransferPage';
+import { getPracticeHistory } from '@/api/modules/study';
+import { Study } from '@/types';
 const { transferTo } = useTransferPage();
 const { baseStickyTop } = useNavbar();
-const historyList = ref<any[]>([{ id: 1, name: '知识点1', time: '2021-01-01' }, { id: 2, name: '知识点2', time: '2021-01-02' }]);
-const handleViewHistory = (value: any) => {
+const historyList = ref<Study.PracticeHistory[]>([]);
+const handleViewHistory = (value: Study.PracticeHistory) => {
   transferTo('/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail', {
     data: {
-      id: value.id,
-      isDirected: value.isDirected
+      id: value.examineeId,
+      name: value.paperName,
+      isDirected: value.directed === 1
     }
   });
 }
 const loadData = async () => {
   uni.$ie.showLoading();
   try {
-    // const res = await getKnowledgePracticeHistory();
-    // console.log(res);
+    const { rows } = await getPracticeHistory();
+    historyList.value = rows.map(item => {
+      return {
+        ...item,
+        isDirected: item.directed === 1,
+        endTime: uni.$uv.timeFormat(item.endTime, 'yyyy-mm-dd hh:MM:ss')
+      } as Study.PracticeHistory;
+    });
   } finally {
-    setTimeout(() => {
-      uni.$ie.hideLoading();
-    }, 400);
+    uni.$ie.hideLoading();
   }
 }
 onLoad(() => {

+ 35 - 21
src/pagesStudy/pages/simulation-analysis/components/exam-stat.vue

@@ -19,8 +19,8 @@
         <view class="mt-5 text-28 text-fore-light">正确率</view>
       </view>
     </view>
-    <view v-if="showStats" class="h-1 bg-[#E6E6E6] my-20"></view>
-    <view class="mt-40 flex items-center justify-end gap-x-30">
+    <view v-if="showStats" class="h-1 bg-[#E6E6E6] my-20 mb-40 "></view>
+    <view class="flex items-center justify-end gap-x-30">
       <view class="flex items-center gap-x-12" :class="{ 'is-filter': !filterTypes.includes('correct') }"
         @click="handleFilter('correct')">
         <view class="icon w-18 h-18 rounded-full bg-[#2CC6A0]"></view>
@@ -51,10 +51,18 @@ import { EnumPaperType, EnumQuestionType } from '@/common/enum';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { Study } from '@/types';
 const { transferTo } = useTransferPage();
+const emit = defineEmits<{
+  (e: 'detail', item: Study.ExamineeQuestion): void;
+}>();
 const props = defineProps<{
   data: Study.Examinee;
   showStats: boolean;
 }>();
+interface QuestionItem extends Study.ExamineeQuestion {
+  originalIndex?: number;
+  isRight?: boolean;
+  isNotAnswer?: boolean;
+}
 const paperInfo = computed(() => {
   return props.data.paperInfo || {};
 });
@@ -66,14 +74,29 @@ const totalQuestions = computed(() => {
 });
 const filterTypes = ref<('correct' | 'incorrect' | 'unanswered')[]>(['correct', 'incorrect', 'unanswered']);
 const questionList = computed(() => {
-  return (props.data.questions || []).map((item, index) => {
-    return {
-      ...item,
-      originalIndex: index + 1, // 保存原始序号
-      isRight: judgeCorrect(item),
-      isNotAnswer: !item.answers.filter(item => item !== ' ').length
+  const list: QuestionItem[] = [];
+  let offset = 0 ;
+  (props.data.questions || []).forEach((item, index) => {
+    if (item.subQuestions && item.subQuestions.length > 0) {
+      item.subQuestions.forEach((subItem, subIndex) => {
+        offset++;
+        list.push({
+          ...subItem,
+          originalIndex: index + subIndex + 1, // 保存原始序号
+          isRight: judgeCorrect(subItem),
+          isNotAnswer: !subItem.answers.filter(item => item !== ' ').length
+        });
+      });
+    } else {
+      list.push({
+        ...item,
+        originalIndex: index + offset + 1, // 保存原始序号
+        isRight: judgeCorrect(item),
+        isNotAnswer: !item.answers.filter(item => item !== ' ').length
+      });
     }
-  }).filter(item => {
+  });
+  return list.filter((item: QuestionItem) => {
     // 判断是否答对
     if (item.isRight && filterTypes.value.includes('correct')) {
       return true;
@@ -90,7 +113,8 @@ const questionList = computed(() => {
   });
 });
 const judgeCorrect = (qs: Study.ExamineeQuestion) => {
-  if (qs.typeId === EnumQuestionType.SINGLE_CHOICE) {
+  if (qs.typeId === EnumQuestionType.SINGLE_CHOICE
+    || qs.typeId === EnumQuestionType.JUDGMENT) {
     return qs.answers.includes(qs.answer1);
   } else if (qs.typeId === EnumQuestionType.MULTIPLE_CHOICE) {
     const rightAnswers = qs.answer1.split('').filter(item => item !== ' ');
@@ -106,17 +130,7 @@ const handleFilter = (type: 'correct' | 'incorrect' | 'unanswered') => {
   console.log(filterTypes.value)
 }
 const handleDetail = (item: Study.ExamineeQuestion) => {
-  transferTo('/pagesStudy/pages/exam-start/exam-start', {
-    data: {
-      name: '模拟考试-' + props.data.subjectName,
-      readonly: true,
-      questionId: item.id,
-      paperType: EnumPaperType.SIMULATED,
-      simulationInfo: {
-        examineeId: props.data.examineeId,
-      }
-    }
-  });
+  emit('detail', item);
 }
 </script>
 <style lang="scss" scoped>

+ 19 - 4
src/pagesStudy/pages/simulation-analysis/simulation-analysis.vue

@@ -27,7 +27,7 @@
             </view>
           </view>
         </view>
-        <exam-stat :data="examineeData" :show-stats="true" />
+        <exam-stat :data="examineeData" :show-stats="true" @detail="handleDetail"/>
         <score-stat :data="examineeData" />
       </view>
     </view>
@@ -41,10 +41,12 @@ import ScoreStat from './components/score-stat.vue';
 import { getExamineeResult } from '@/api/modules/study';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { Study } from '@/types';
-import { EnumQuestionType } from '@/common/enum';
-const { prevData } = useTransferPage();
+import { EnumPaperType, EnumQuestionType } from '@/common/enum';
+const { prevData, transferTo } = useTransferPage();
 const examineeData = ref<Study.Examinee>({} as Study.Examinee);
-
+const paperName = computed(() => {
+  return '模拟考试-' + examineeData.value.subjectName;
+});
 const rightRate = computed(() => {
   const { totalCount = 0, wrongCount = 0 } = examineeData.value;
   return Math.round((totalCount - wrongCount) / totalCount * 100) || 0;
@@ -64,6 +66,19 @@ const formatTime = (time: number) => {
     return `${minutes}分${seconds}秒`;
   }
 };
+const handleDetail = (item: Study.ExamineeQuestion) => {
+  transferTo('/pagesStudy/pages/exam-start/exam-start', {
+    data: {
+      name: paperName.value,
+      readonly: true,
+      questionId: item.id,
+      paperType: EnumPaperType.SIMULATED,
+      simulationInfo: {
+        examineeId: examineeData.value.examineeId
+      }
+    }
+  });
+};
 const loadData = async () => {
   uni.$ie.showLoading();
   const res = await getExamineeResult(prevData.value.examineeId);

+ 3 - 0
src/types/injectionSymbols.ts

@@ -24,6 +24,9 @@ export const NEXT_QUESTION_QUICKLY = Symbol('NEXT_QUESTION_QUICKLY') as Injectio
 
 export const PREV_QUESTION_QUICKLY = Symbol('PREV_QUESTION_QUICKLY') as InjectionKey<() => void>;
 
+export const SHOW_SUBMIT_CONFIRM = Symbol('SHOW_SUBMIT_CONFIRM') as InjectionKey<Ref<boolean>>;
+export const IS_ALL_DONE = Symbol('IS_ALL_DONE') as InjectionKey<Ref<boolean>>;
+
 /**
  * 学习计划
  */

+ 7 - 0
src/types/study.ts

@@ -328,4 +328,11 @@ export interface SimulationExamSubject {
   subject: string;
   examTime: number;
   icon: string;
+}
+
+export interface PracticeHistory {
+  directed: number;
+  endTime: string;
+  examineeId: number;
+  paperName: string;
 }