Explorar o código

修复题目跳转问题,做题页面新增手势返回拦截,其他bug修复

shmily1213 hai 3 días
pai
achega
1dd9ff8279

+ 32 - 9
src/composables/useExam.ts

@@ -11,7 +11,7 @@ import { Question } from "@/types/study";
 export const decodeHtmlEntities = (str: string): string => {
   if (!str) return str;
 
-  // 音标和常用 HTML 实体映射表
+  // 标准 HTML 实体映射表
   const entityMap: Record<string, string> = {
     // 音标相关 - 锐音符 (acute)
     'aacute': 'á',
@@ -60,23 +60,45 @@ export const decodeHtmlEntities = (str: string): string => {
     'plusmn': '±',
   };
 
-  // 处理命名实体(如 &iacute;)
-  // 使用 [a-z0-9] 以支持包含数字的实体名称
-  let result = str.replace(/&([a-z0-9]+);/gi, (match, entity) => {
+  let result = str;
+
+  // 1. 处理非标准的上标实体:&sup数字; → <sup>数字</sup>
+  // 例如:&sup2; → <sup>2</sup>, &sup123; → <sup>123</sup>
+  result = result.replace(/&sup(\d+);/gi, (match, digits) => {
+    return `<sup>${digits}</sup>`;
+  });
+
+  // 2. 处理非标准的下标实体:&sub数字; → <sub>数字</sub>
+  // 例如:&sub2; → <sub>2</sub>, &sub123; → <sub>123</sub>
+  result = result.replace(/&sub(\d+);/gi, (match, digits) => {
+    return `<sub>${digits}</sub>`;
+  });
+
+  // 3. 处理标准命名实体(如 &iacute;)
+  result = result.replace(/&([a-z]+);/gi, (match, entity) => {
     const lowerEntity = entity.toLowerCase();
     if (entityMap[lowerEntity]) {
       return entityMap[lowerEntity];
     }
-    return match; // 如果找不到映射,保持原样
+    return match;
   });
 
-  // 处理数字实体(如 &#237; 或 &#xED;)
+  // 4. 处理十进制数字实体(如 &#178; → ²
   result = result.replace(/&#(\d+);/g, (match, num) => {
-    return String.fromCharCode(parseInt(num, 10));
+    const code = parseInt(num, 10);
+    if (!isNaN(code)) {
+      return String.fromCharCode(code);
+    }
+    return match;
   });
 
+  // 5. 处理十六进制数字实体(如 &#xB2; → ²)
   result = result.replace(/&#x([0-9a-f]+);/gi, (match, hex) => {
-    return String.fromCharCode(parseInt(hex, 16));
+    const code = parseInt(hex, 16);
+    if (!isNaN(code)) {
+      return String.fromCharCode(code);
+    }
+    return match;
   });
 
   return result;
@@ -569,7 +591,8 @@ export const useExam = () => {
         answers: item.answers || [],
         subQuestions: item.subQuestions?.map(transerQuestion) || [],
         options: item.options?.map((option, index) => {
-          // 移除选项编号(如 A.)并解码 HTML 实体(如 &iacute; → í)
+          // 移除选项编号(如 A.)并解码 HTML 实体为 Unicode 字符
+          // 必须在这里解码,因为 Vue/uni-app 会对动态属性中的 & 进行转义
           const cleanedOption = option.replace(/[A-Z]\./g, '').replace(/\s/g, ' ');
           return {
             name: decodeHtmlEntities(cleanedOption),

+ 7 - 0
src/pagesMain/pages/me/components/me-menu.vue

@@ -93,6 +93,13 @@ const handleClick = async (item: MenuItem) => {
     if (item.name === '绑定会员卡' && userStore.isVip) {
       uni.$ie.showToast('您已是会员');
       return;
+    } else if (item.name === '我的志愿表') {
+      if (userStore.isVHS) {
+        transferTo('/pagesOther/pages/voluntary/list/list');
+      } else {
+        transferTo(item.pagePath);
+      }
+      return;
     }
     transferTo(item.pagePath);
   }

+ 3 - 2
src/pagesOther/pages/voluntary/index/components/cart-step.vue

@@ -66,9 +66,10 @@ const { isMock, ensureHistoryYears } = useInjectVoluntaryHeader()
 const { formatQueryParams, onSearch, reset: resetCondition } = useProvideVoluntarySearch()
 
 const safeScrollHeight = computed(() => scrollHeight ? toValue(scrollHeight) + 'px' : undefined)
+
 const isNotVip = computed(() => {
-  return !toValue(isBind) && toValue(total) > 1
-})
+  return !userStore.isVip;
+});
 
 const showNotify = (message) => {
   const msg = message || '未发布详细的征集信息'

+ 1 - 1
src/pagesStudy/components/ie-exam-record-item.vue

@@ -49,7 +49,7 @@ const handleDetail = () => {
         readonly: false,
         simulationInfo: {
           examineeId: props.data.id,
-          name: '模拟考试-' + props.data.subjectName,
+          name: props.data.subjectName,
         }
       }
     });

+ 1 - 1
src/pagesStudy/pages/exam-start/components/exam-stats-card.vue

@@ -136,7 +136,7 @@ const hanadleNavigate = (question: Study.Question, index: number) => {
   if (question.isSubQuestion) {
     changeIndex(question.parentIndex || 0, question.subIndex || 0);
   } else {
-    changeIndex(index);
+    changeIndex(question.index);
   }
 }
 </script>

+ 30 - 1
src/pagesStudy/pages/exam-start/exam-start.vue

@@ -74,7 +74,9 @@ const totalExamTime = ref<number>(0);
 const hasShowSubmitConfirm = ref(false);
 const examineeId = ref<number | undefined>(undefined);
 const paperData = ref<Study.ExamPaper>({} as Study.ExamPaper);
-
+// 是否确认退出
+const confirmQuit = ref(false);
+const confirmShowing = ref(false);
 /**
  * 自动提交
  */
@@ -107,6 +109,7 @@ const isReadOnly = computed(() => {
 });
 const handleLeftClick = () => {
   if (!isReady.value || isReadOnly.value) {
+    confirmQuit.value = true;
     transferBack();
     return;
   }
@@ -124,6 +127,7 @@ const beforeQuit = () => {
   }
   stopTime();
   const msg = paperType === EnumPaperType.PRACTICE ? '当前练习未完成,确认退出?' : '当前考试未完成,确认退出?';
+  confirmShowing.value = true;
   uni.$ie.showModal({
     title: '提示',
     content: msg,
@@ -131,6 +135,8 @@ const beforeQuit = () => {
     if (confirm) {
       handleSubmit(true);
     } else {
+      confirmQuit.value = false;
+      confirmShowing.value = false;
       startTime();
     }
   });
@@ -198,6 +204,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         setTimeout(async () => {
           uni.$ie.hideLoading();
           await nextTick();
+          confirmQuit.value = true;
+          confirmShowing.value = false;
           transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
             data: {
               examineeId: examineeId.value,
@@ -208,6 +216,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         }, 2500);
       } else {
         uni.$ie.hideLoading();
+        confirmQuit.value = true;
+        confirmShowing.value = false;
         nextTick(() => {
           transferBack();
         });
@@ -217,6 +227,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         setTimeout(async () => {
           uni.$ie.hideLoading();
           await nextTick();
+          confirmQuit.value = true;
+          confirmShowing.value = false;
           transferTo('/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail', {
             data: {
               paperType: prevData.value.paperType,
@@ -230,6 +242,8 @@ const handleSubmit = (tempSave: boolean = false) => {
         }, 2500);
       } else {
         uni.$ie.hideLoading();
+        confirmQuit.value = true;
+        confirmShowing.value = false;
         nextTick(() => {
           transferBack();
         });
@@ -415,6 +429,21 @@ const loadData = async () => {
 onLoad(() => {
   console.log(prevData.value)
   loadData();
+  uni.addInterceptor('navigateBack', {
+    invoke: (e) => {
+      if (confirmShowing.value) {
+        return false;
+      }
+      if (confirmQuit.value) {
+        return e;
+      }
+      handleLeftClick();
+      return false;
+    }
+  })
+});
+onUnload(() => {
+  uni.removeInterceptor('navigateBack');
 });
 </script>
 

+ 3 - 13
src/pagesStudy/pages/simulation-analysis/simulation-analysis.vue

@@ -49,23 +49,13 @@ import { EnumPaperType, EnumQuestionType } from '@/common/enum';
 const { prevData, transferTo } = useTransferPage<Transfer.SimulationAnalysisPageOptions, Transfer.ExamAnalysisPageOptions>();
 const examineeData = ref<Study.Examinee>();
 const userStore = useUserStore();
-const titleMap = {
-  [EnumPaperType.PRACTICE]: '知识点练习',
-  [EnumPaperType.SIMULATED]: '模拟考试',
-  [EnumPaperType.TEST]: '组卷作业',
-}
-const readonlyTitleMap = {
-  [EnumPaperType.PRACTICE]: '练习解析',
-  [EnumPaperType.SIMULATED]: '考试解析',
-  [EnumPaperType.TEST]: '作业解析',
-}
 
 const paperName = computed(() => {
-  const prefix = titleMap[prevData.value.paperType as keyof typeof titleMap];
+  console.log(examineeData.value, 111)
   if (userStore.isVHS) {
-    return prefix + '-' + examineeData.value?.name || examineeData.value?.subjectName || '';
+    return examineeData.value?.name || examineeData.value?.subjectName || '';
   } else {
-    return prefix + '-' + examineeData.value?.subjectName;
+    return examineeData.value?.name || examineeData.value?.subjectName || '';
   }
 });
 const rightRate = computed(() => {