|  | @@ -0,0 +1,688 @@
 | 
	
		
			
				|  |  | +import { ActionSheet, Button, Image, Popup, Swipe, SwipeItem } from 'vant';
 | 
	
		
			
				|  |  | +import {
 | 
	
		
			
				|  |  | +  computed,
 | 
	
		
			
				|  |  | +  defineComponent,
 | 
	
		
			
				|  |  | +  nextTick,
 | 
	
		
			
				|  |  | +  onMounted,
 | 
	
		
			
				|  |  | +  onUnmounted,
 | 
	
		
			
				|  |  | +  reactive,
 | 
	
		
			
				|  |  | +  watch,
 | 
	
		
			
				|  |  | +  ref
 | 
	
		
			
				|  |  | +} from 'vue';
 | 
	
		
			
				|  |  | +import { useRoute, useRouter } from 'vue-router';
 | 
	
		
			
				|  |  | +import styles from './index.module.less';
 | 
	
		
			
				|  |  | +import iconButtonList from '../images/icon-button-list.png';
 | 
	
		
			
				|  |  | +import MSticky from '@/components/m-sticky';
 | 
	
		
			
				|  |  | +import ChoiceQuestion from '../model/choice-question';
 | 
	
		
			
				|  |  | +import AnswerList from '../model/answer-list';
 | 
	
		
			
				|  |  | +import DragQuestion from '../model/drag-question';
 | 
	
		
			
				|  |  | +import KeepLookQuestion from '../model/keep-look-question';
 | 
	
		
			
				|  |  | +import PlayQuestion from '../model/play-question';
 | 
	
		
			
				|  |  | +import ErrorMode from '../model/error-mode';
 | 
	
		
			
				|  |  | +import ResultFinish from '../model/result-finish';
 | 
	
		
			
				|  |  | +import { eventUnit, QuestionType } from '../unit';
 | 
	
		
			
				|  |  | +import request from '@/helpers/request';
 | 
	
		
			
				|  |  | +import { useRect } from '@vant/use';
 | 
	
		
			
				|  |  | +import MHeader from '@/components/m-header';
 | 
	
		
			
				|  |  | +import { useEventListener, useInterval, useWindowScroll } from '@vueuse/core';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default defineComponent({
 | 
	
		
			
				|  |  | +  name: 'unit-detail',
 | 
	
		
			
				|  |  | +  setup() {
 | 
	
		
			
				|  |  | +    const route = useRoute();
 | 
	
		
			
				|  |  | +    const router = useRouter();
 | 
	
		
			
				|  |  | +    const swipeRef = ref();
 | 
	
		
			
				|  |  | +    const state = reactive({
 | 
	
		
			
				|  |  | +      background: 'transparent',
 | 
	
		
			
				|  |  | +      color: '#fff',
 | 
	
		
			
				|  |  | +      visiableError: false,
 | 
	
		
			
				|  |  | +      visiableAnswer: false,
 | 
	
		
			
				|  |  | +      id: route.query.id,
 | 
	
		
			
				|  |  | +      currentIndex: 0,
 | 
	
		
			
				|  |  | +      questionList: [] as any,
 | 
	
		
			
				|  |  | +      page: 1,
 | 
	
		
			
				|  |  | +      rows: 10,
 | 
	
		
			
				|  |  | +      total: 0,
 | 
	
		
			
				|  |  | +      isFinish: false, // 是否完成加载
 | 
	
		
			
				|  |  | +      visiableInfo: {
 | 
	
		
			
				|  |  | +        show: false,
 | 
	
		
			
				|  |  | +        operationType: 'RESULT' as 'RESULT' | 'BACK' | 'CONTINUE' | 'GRASP',
 | 
	
		
			
				|  |  | +        type: 'DEFAULT' as 'DEFAULT' | 'FAIL' | 'PASS' | 'GOOD' | 'COUNTDOWN',
 | 
	
		
			
				|  |  | +        content: '',
 | 
	
		
			
				|  |  | +        showCancelButton: false,
 | 
	
		
			
				|  |  | +        confirmButtonText: '',
 | 
	
		
			
				|  |  | +        cancelButtonText: '',
 | 
	
		
			
				|  |  | +        title: '',
 | 
	
		
			
				|  |  | +        graspItem: {} as any
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      nextStatus: false,
 | 
	
		
			
				|  |  | +      swipeHeight: 'auto' as any,
 | 
	
		
			
				|  |  | +      answerAnalysis: '',
 | 
	
		
			
				|  |  | +      questionTypeCode: '',
 | 
	
		
			
				|  |  | +      overResult: {
 | 
	
		
			
				|  |  | +        time: '00:00', // 时长
 | 
	
		
			
				|  |  | +        questionLength: 0, // 答题数
 | 
	
		
			
				|  |  | +        errorLength: 0, // 错题数
 | 
	
		
			
				|  |  | +        rate: 0 // 正确率
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 计时
 | 
	
		
			
				|  |  | +    const { counter, resume, pause } = useInterval(1000, { controls: true });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const getExamDetails = async () => {
 | 
	
		
			
				|  |  | +      try {
 | 
	
		
			
				|  |  | +        const { data } = await request.post(
 | 
	
		
			
				|  |  | +          '/edu-app/studentUnitExamination/errorEdition',
 | 
	
		
			
				|  |  | +          {
 | 
	
		
			
				|  |  | +            data: {
 | 
	
		
			
				|  |  | +              page: state.page,
 | 
	
		
			
				|  |  | +              rows: state.rows
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        const temp = data || {};
 | 
	
		
			
				|  |  | +        state.total = temp.total || 0;
 | 
	
		
			
				|  |  | +        state.isFinish = temp.current < temp.pages ? false : true;
 | 
	
		
			
				|  |  | +        temp.records.forEach((item: any) => {
 | 
	
		
			
				|  |  | +          item.showAnalysis = false; // 默认不显示解析
 | 
	
		
			
				|  |  | +          item.grasp = false; // 是否掌握题目
 | 
	
		
			
				|  |  | +          item.analysis = {
 | 
	
		
			
				|  |  | +            message: item.answerAnalysis,
 | 
	
		
			
				|  |  | +            topic: true, // 是否显示结果
 | 
	
		
			
				|  |  | +            userResult: false // 用户答题对错
 | 
	
		
			
				|  |  | +          };
 | 
	
		
			
				|  |  | +          item.userAnswer = []; // 用户答题
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        state.questionList.push(...(temp.records || []));
 | 
	
		
			
				|  |  | +      } catch {
 | 
	
		
			
				|  |  | +        //
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 监听索引
 | 
	
		
			
				|  |  | +    watch(
 | 
	
		
			
				|  |  | +      () => state.currentIndex,
 | 
	
		
			
				|  |  | +      () => {
 | 
	
		
			
				|  |  | +        console.log(state.currentIndex, 'index');
 | 
	
		
			
				|  |  | +        // 判断是否在倒数第三题,并且没有加载完
 | 
	
		
			
				|  |  | +        if (
 | 
	
		
			
				|  |  | +          state.currentIndex + 3 >= state.questionList.length &&
 | 
	
		
			
				|  |  | +          !state.isFinish
 | 
	
		
			
				|  |  | +        ) {
 | 
	
		
			
				|  |  | +          state.page = state.page + 1;
 | 
	
		
			
				|  |  | +          getExamDetails();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /** 已掌握此题 */
 | 
	
		
			
				|  |  | +    const onGraspQuestion = async (item: any) => {
 | 
	
		
			
				|  |  | +      // 判断是否掌握此题
 | 
	
		
			
				|  |  | +      if (item.grasp) return;
 | 
	
		
			
				|  |  | +      state.visiableInfo.show = true;
 | 
	
		
			
				|  |  | +      state.visiableInfo.title = '确定掌握此题?';
 | 
	
		
			
				|  |  | +      state.visiableInfo.showCancelButton = true;
 | 
	
		
			
				|  |  | +      state.visiableInfo.operationType = 'GRASP';
 | 
	
		
			
				|  |  | +      state.visiableInfo.cancelButtonText = '取消';
 | 
	
		
			
				|  |  | +      state.visiableInfo.confirmButtonText = '确定';
 | 
	
		
			
				|  |  | +      state.visiableInfo.content = `你确定已掌握该题知识要点,此题将移除你的错题集。`;
 | 
	
		
			
				|  |  | +      state.visiableInfo.graspItem = item;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /** 已掌握此题确认 */
 | 
	
		
			
				|  |  | +    const onGraspQuestionConfirm = async () => {
 | 
	
		
			
				|  |  | +      try {
 | 
	
		
			
				|  |  | +        state.visiableInfo.show = false;
 | 
	
		
			
				|  |  | +        await request.get('/edu-app/studentExaminationErrorEdition/del', {
 | 
	
		
			
				|  |  | +          hideLoading: false,
 | 
	
		
			
				|  |  | +          params: {
 | 
	
		
			
				|  |  | +            studentExaminationErrorEditionId:
 | 
	
		
			
				|  |  | +              state.visiableInfo.graspItem.studentExaminationErrorEditionId
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        state.visiableInfo.graspItem.grasp = true;
 | 
	
		
			
				|  |  | +      } catch {
 | 
	
		
			
				|  |  | +        //
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * @description 下一题 | 测试完成
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    const onNextQuestion = async () => {
 | 
	
		
			
				|  |  | +      try {
 | 
	
		
			
				|  |  | +        const questionList = state.questionList || [];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let result: any = {};
 | 
	
		
			
				|  |  | +        questionList.forEach((question: any, index: number) => {
 | 
	
		
			
				|  |  | +          // 格式化所有题目的答案
 | 
	
		
			
				|  |  | +          if (index === state.currentIndex) {
 | 
	
		
			
				|  |  | +            result = {
 | 
	
		
			
				|  |  | +              questionId: question.id,
 | 
	
		
			
				|  |  | +              details: question.userAnswer || []
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        const { data } = await request.post(
 | 
	
		
			
				|  |  | +          '/edu-app/studentUnitExamination/submitTrainingAnswer',
 | 
	
		
			
				|  |  | +          {
 | 
	
		
			
				|  |  | +            hideLoading: true,
 | 
	
		
			
				|  |  | +            data: result
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        // 初始化是否显示解析
 | 
	
		
			
				|  |  | +        questionList.forEach((question: any, index: number) => {
 | 
	
		
			
				|  |  | +          // 格式化所有题目的答案
 | 
	
		
			
				|  |  | +          if (index === state.currentIndex) {
 | 
	
		
			
				|  |  | +            state.answerAnalysis = question.answerAnalysis;
 | 
	
		
			
				|  |  | +            state.questionTypeCode = question.questionTypeCode;
 | 
	
		
			
				|  |  | +            question.showAnalysis = true;
 | 
	
		
			
				|  |  | +            question.analysis.userResult = data;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 判断是否是最后一题
 | 
	
		
			
				|  |  | +        if (state.questionList.length === state.currentIndex + 1) {
 | 
	
		
			
				|  |  | +          eventUnit.emit('unitAudioStop');
 | 
	
		
			
				|  |  | +          state.visiableInfo.show = true;
 | 
	
		
			
				|  |  | +          state.visiableInfo.title = '练习完成';
 | 
	
		
			
				|  |  | +          state.visiableInfo.showCancelButton = true;
 | 
	
		
			
				|  |  | +          state.visiableInfo.operationType = 'CONTINUE';
 | 
	
		
			
				|  |  | +          state.visiableInfo.cancelButtonText = '再等等';
 | 
	
		
			
				|  |  | +          state.visiableInfo.confirmButtonText = '确认完成';
 | 
	
		
			
				|  |  | +          state.visiableInfo.content = `确认本次练习的题目都完成了吗?`;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (data) {
 | 
	
		
			
				|  |  | +          swipeRef.value?.next();
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          state.visiableError = true;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      } catch {
 | 
	
		
			
				|  |  | +        //
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //
 | 
	
		
			
				|  |  | +    const getAnswerResult = computed(() => {
 | 
	
		
			
				|  |  | +      const questionList = state.questionList || [];
 | 
	
		
			
				|  |  | +      let count = 0;
 | 
	
		
			
				|  |  | +      let passCount = 0;
 | 
	
		
			
				|  |  | +      let noPassCount = 0;
 | 
	
		
			
				|  |  | +      questionList.forEach((item: any) => {
 | 
	
		
			
				|  |  | +        if (item.showAnalysis) {
 | 
	
		
			
				|  |  | +          count += 1;
 | 
	
		
			
				|  |  | +          if (item.analysis.userResult) {
 | 
	
		
			
				|  |  | +            passCount += 1;
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            noPassCount += 1;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      return {
 | 
	
		
			
				|  |  | +        count,
 | 
	
		
			
				|  |  | +        passCount,
 | 
	
		
			
				|  |  | +        noPassCount
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * @description 重置当前的题目高度
 | 
	
		
			
				|  |  | +     * @param {any} scroll 是否滚动到顶部
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    let size = 0;
 | 
	
		
			
				|  |  | +    const resizeSwipeItemHeight = (scroll = true) => {
 | 
	
		
			
				|  |  | +      nextTick(() => {
 | 
	
		
			
				|  |  | +        scroll && window.scrollTo(0, 0);
 | 
	
		
			
				|  |  | +        setTimeout(() => {
 | 
	
		
			
				|  |  | +          const currentItemDom: any = document
 | 
	
		
			
				|  |  | +            .querySelectorAll('.van-swipe-item')
 | 
	
		
			
				|  |  | +            [state.currentIndex]?.querySelector('.swipe-item-question');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          const allImg = currentItemDom?.querySelectorAll(
 | 
	
		
			
				|  |  | +            '.answerTitleImg img'
 | 
	
		
			
				|  |  | +          );
 | 
	
		
			
				|  |  | +          let status = true;
 | 
	
		
			
				|  |  | +          // console.log(allImg)
 | 
	
		
			
				|  |  | +          allImg?.forEach((img: any) => {
 | 
	
		
			
				|  |  | +            if (!img.complete) {
 | 
	
		
			
				|  |  | +              status = false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +          // 判断图片是否加载完了
 | 
	
		
			
				|  |  | +          if (!status && size < 3) {
 | 
	
		
			
				|  |  | +            setTimeout(() => {
 | 
	
		
			
				|  |  | +              size += 1;
 | 
	
		
			
				|  |  | +              resizeSwipeItemHeight(scroll);
 | 
	
		
			
				|  |  | +            }, 300);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          if (status) {
 | 
	
		
			
				|  |  | +            size = 0;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          const rect = useRect(currentItemDom);
 | 
	
		
			
				|  |  | +          state.swipeHeight = rect.height;
 | 
	
		
			
				|  |  | +        }, 100);
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const onConfirmResult = () => {
 | 
	
		
			
				|  |  | +      if (state.visiableInfo.operationType === 'RESULT') {
 | 
	
		
			
				|  |  | +        state.visiableInfo.show = false;
 | 
	
		
			
				|  |  | +        onAfter();
 | 
	
		
			
				|  |  | +      } else if (state.visiableInfo.operationType === 'BACK') {
 | 
	
		
			
				|  |  | +        state.visiableInfo.show = false;
 | 
	
		
			
				|  |  | +        onAfter();
 | 
	
		
			
				|  |  | +      } else if (state.visiableInfo.operationType === 'CONTINUE') {
 | 
	
		
			
				|  |  | +        onResultPopup();
 | 
	
		
			
				|  |  | +      } else if (state.visiableInfo.operationType === 'GRASP') {
 | 
	
		
			
				|  |  | +        onGraspQuestionConfirm();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const onCloseResult = async () => {
 | 
	
		
			
				|  |  | +      const operationType = state.visiableInfo.operationType;
 | 
	
		
			
				|  |  | +      if (operationType === 'RESULT') {
 | 
	
		
			
				|  |  | +      } else if (operationType === 'BACK') {
 | 
	
		
			
				|  |  | +        state.visiableInfo.show = false;
 | 
	
		
			
				|  |  | +        window.history.pushState(null, '', document.URL);
 | 
	
		
			
				|  |  | +        window.addEventListener('popstate', onBack, false);
 | 
	
		
			
				|  |  | +      } else if (operationType === 'CONTINUE' || operationType === 'GRASP') {
 | 
	
		
			
				|  |  | +        state.visiableInfo.show = false;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /** 结果页面弹窗 */
 | 
	
		
			
				|  |  | +    const onResultPopup = () => {
 | 
	
		
			
				|  |  | +      const answerResult = getAnswerResult.value;
 | 
	
		
			
				|  |  | +      let rate = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (answerResult.count > 0) {
 | 
	
		
			
				|  |  | +        rate = Math.floor((answerResult.passCount / answerResult.count) * 100);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      const times = counter.value;
 | 
	
		
			
				|  |  | +      const minute =
 | 
	
		
			
				|  |  | +        Math.floor(times / 60) >= 10
 | 
	
		
			
				|  |  | +          ? Math.floor(times / 60)
 | 
	
		
			
				|  |  | +          : '0' + Math.floor(times / 60);
 | 
	
		
			
				|  |  | +      const seconds = times % 60 >= 10 ? times % 60 : '0' + (times % 60);
 | 
	
		
			
				|  |  | +      state.overResult = {
 | 
	
		
			
				|  |  | +        time: minute + ':' + seconds, // 时长
 | 
	
		
			
				|  |  | +        questionLength: answerResult.count, // 答题数
 | 
	
		
			
				|  |  | +        errorLength: answerResult.noPassCount, // 错题数
 | 
	
		
			
				|  |  | +        rate // 正确率
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +      // 重置计时
 | 
	
		
			
				|  |  | +      pause();
 | 
	
		
			
				|  |  | +      counter.value = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 60 及格
 | 
	
		
			
				|  |  | +      // 85 及以上优秀
 | 
	
		
			
				|  |  | +      state.visiableInfo.show = true;
 | 
	
		
			
				|  |  | +      state.visiableInfo.title = '已完成';
 | 
	
		
			
				|  |  | +      state.visiableInfo.showCancelButton = false;
 | 
	
		
			
				|  |  | +      state.visiableInfo.operationType = 'RESULT';
 | 
	
		
			
				|  |  | +      state.visiableInfo.confirmButtonText = '确认';
 | 
	
		
			
				|  |  | +      state.visiableInfo.content = `<div>您已完成本次测试,答对<span class='${
 | 
	
		
			
				|  |  | +        styles.right
 | 
	
		
			
				|  |  | +      }'>${answerResult.passCount}</span>,答错<span class='${styles.error}'>${
 | 
	
		
			
				|  |  | +        answerResult.count - answerResult.passCount
 | 
	
		
			
				|  |  | +      }</span>,正确率${rate}%~</div>`;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 拦截
 | 
	
		
			
				|  |  | +    const onBack = () => {
 | 
	
		
			
				|  |  | +      const answerResult = getAnswerResult.value;
 | 
	
		
			
				|  |  | +      state.visiableInfo.show = true;
 | 
	
		
			
				|  |  | +      state.visiableInfo.title = '确认退出吗?';
 | 
	
		
			
				|  |  | +      state.visiableInfo.showCancelButton = true;
 | 
	
		
			
				|  |  | +      state.visiableInfo.operationType = 'BACK';
 | 
	
		
			
				|  |  | +      state.visiableInfo.cancelButtonText = '取消';
 | 
	
		
			
				|  |  | +      state.visiableInfo.confirmButtonText = '确定';
 | 
	
		
			
				|  |  | +      state.visiableInfo.content = `您已经完成${
 | 
	
		
			
				|  |  | +        answerResult.passCount + answerResult.noPassCount
 | 
	
		
			
				|  |  | +      }道题了,继续做题可以巩固所学知识哦~`;
 | 
	
		
			
				|  |  | +      eventUnit.emit('unitAudioStop');
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const onAfter = () => {
 | 
	
		
			
				|  |  | +      window.removeEventListener('popstate', onBack, false);
 | 
	
		
			
				|  |  | +      router.back();
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    onMounted(async () => {
 | 
	
		
			
				|  |  | +      useEventListener(document, 'scroll', () => {
 | 
	
		
			
				|  |  | +        const { y } = useWindowScroll();
 | 
	
		
			
				|  |  | +        if (y.value > 52) {
 | 
	
		
			
				|  |  | +          state.background = '#fff';
 | 
	
		
			
				|  |  | +          state.color = '#323333';
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          state.background = 'transparent';
 | 
	
		
			
				|  |  | +          state.color = '#fff';
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +      await getExamDetails();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      resizeSwipeItemHeight();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // window.history.pushState(null, '', document.URL);
 | 
	
		
			
				|  |  | +      // window.addEventListener('popstate', onBack, false);
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    onUnmounted(() => {
 | 
	
		
			
				|  |  | +      // 关闭所有音频
 | 
	
		
			
				|  |  | +      eventUnit.emit('unitAudioStop');
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    return () => (
 | 
	
		
			
				|  |  | +      <div class={styles.unitDetail}>
 | 
	
		
			
				|  |  | +        <MSticky position="top">
 | 
	
		
			
				|  |  | +          <MHeader
 | 
	
		
			
				|  |  | +            border={false}
 | 
	
		
			
				|  |  | +            background={state.background}
 | 
	
		
			
				|  |  | +            color={state.color}
 | 
	
		
			
				|  |  | +          />
 | 
	
		
			
				|  |  | +        </MSticky>
 | 
	
		
			
				|  |  | +        <Swipe
 | 
	
		
			
				|  |  | +          loop={false}
 | 
	
		
			
				|  |  | +          showIndicators={false}
 | 
	
		
			
				|  |  | +          ref={swipeRef}
 | 
	
		
			
				|  |  | +          duration={300}
 | 
	
		
			
				|  |  | +          touchable={false}
 | 
	
		
			
				|  |  | +          class={styles.unitSwipe}
 | 
	
		
			
				|  |  | +          style={{ paddingBottom: '12px' }}
 | 
	
		
			
				|  |  | +          lazyRender
 | 
	
		
			
				|  |  | +          height={state.swipeHeight}
 | 
	
		
			
				|  |  | +          onChange={(index: number) => {
 | 
	
		
			
				|  |  | +            eventUnit.emit('unitAudioStop');
 | 
	
		
			
				|  |  | +            state.currentIndex = index;
 | 
	
		
			
				|  |  | +            resizeSwipeItemHeight();
 | 
	
		
			
				|  |  | +          }}>
 | 
	
		
			
				|  |  | +          {state.questionList.map((item: any, index: number) => (
 | 
	
		
			
				|  |  | +            <SwipeItem>
 | 
	
		
			
				|  |  | +              <div class="swipe-item-question">
 | 
	
		
			
				|  |  | +                {item.questionTypeCode === QuestionType.RADIO && (
 | 
	
		
			
				|  |  | +                  <ChoiceQuestion
 | 
	
		
			
				|  |  | +                    v-model:value={item.userAnswer}
 | 
	
		
			
				|  |  | +                    index={index + 1}
 | 
	
		
			
				|  |  | +                    data={item}
 | 
	
		
			
				|  |  | +                    type="radio"
 | 
	
		
			
				|  |  | +                    showAnalysis={item.showAnalysis}
 | 
	
		
			
				|  |  | +                    analysis={item.analysis}>
 | 
	
		
			
				|  |  | +                    {{
 | 
	
		
			
				|  |  | +                      title: () => (
 | 
	
		
			
				|  |  | +                        <div class={styles.questionTitle}>
 | 
	
		
			
				|  |  | +                          <div class={styles.questionNum}>
 | 
	
		
			
				|  |  | +                            <span>{state.currentIndex + 1}</span>/{state.total}
 | 
	
		
			
				|  |  | +                          </div>
 | 
	
		
			
				|  |  | +                          {/* <div class={styles.questionType}>
 | 
	
		
			
				|  |  | +                            <i></i>
 | 
	
		
			
				|  |  | +                            <span>{item.knowledgePointName}</span>
 | 
	
		
			
				|  |  | +                          </div> */}
 | 
	
		
			
				|  |  | +                          <Button
 | 
	
		
			
				|  |  | +                            round
 | 
	
		
			
				|  |  | +                            plain
 | 
	
		
			
				|  |  | +                            size="mini"
 | 
	
		
			
				|  |  | +                            color={item.grasp ? '#FF5A56' : '#1CACF1'}
 | 
	
		
			
				|  |  | +                            class={styles.controlBtn}
 | 
	
		
			
				|  |  | +                            disabled={item.grasp}
 | 
	
		
			
				|  |  | +                            onClick={() => onGraspQuestion(item)}>
 | 
	
		
			
				|  |  | +                            {item.grasp ? '已掌握此题' : '掌握此题'}
 | 
	
		
			
				|  |  | +                          </Button>
 | 
	
		
			
				|  |  | +                        </div>
 | 
	
		
			
				|  |  | +                      )
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  </ChoiceQuestion>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {item.questionTypeCode === QuestionType.CHECKBOX && (
 | 
	
		
			
				|  |  | +                  <ChoiceQuestion
 | 
	
		
			
				|  |  | +                    v-model:value={item.userAnswer}
 | 
	
		
			
				|  |  | +                    index={index + 1}
 | 
	
		
			
				|  |  | +                    data={item}
 | 
	
		
			
				|  |  | +                    type="checkbox"
 | 
	
		
			
				|  |  | +                    showAnalysis={item.showAnalysis}
 | 
	
		
			
				|  |  | +                    analysis={item.analysis}>
 | 
	
		
			
				|  |  | +                    {{
 | 
	
		
			
				|  |  | +                      title: () => (
 | 
	
		
			
				|  |  | +                        <div class={styles.questionTitle}>
 | 
	
		
			
				|  |  | +                          <div class={styles.questionNum}>
 | 
	
		
			
				|  |  | +                            <span>{state.currentIndex + 1}</span>/{state.total}
 | 
	
		
			
				|  |  | +                          </div>
 | 
	
		
			
				|  |  | +                          {/* <div class={styles.questionType}>
 | 
	
		
			
				|  |  | +                            <i></i>
 | 
	
		
			
				|  |  | +                            <span>{item.knowledgePointName}</span>
 | 
	
		
			
				|  |  | +                          </div> */}
 | 
	
		
			
				|  |  | +                          <Button
 | 
	
		
			
				|  |  | +                            round
 | 
	
		
			
				|  |  | +                            plain
 | 
	
		
			
				|  |  | +                            size="mini"
 | 
	
		
			
				|  |  | +                            color={item.grasp ? '#FF5A56' : '#1CACF1'}
 | 
	
		
			
				|  |  | +                            class={styles.controlBtn}
 | 
	
		
			
				|  |  | +                            disabled={item.grasp}
 | 
	
		
			
				|  |  | +                            onClick={() => onGraspQuestion(item)}>
 | 
	
		
			
				|  |  | +                            {item.grasp ? '已掌握此题' : '掌握此题'}
 | 
	
		
			
				|  |  | +                          </Button>
 | 
	
		
			
				|  |  | +                        </div>
 | 
	
		
			
				|  |  | +                      )
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  </ChoiceQuestion>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {item.questionTypeCode === QuestionType.SORT && (
 | 
	
		
			
				|  |  | +                  <DragQuestion
 | 
	
		
			
				|  |  | +                    v-model:value={item.userAnswer}
 | 
	
		
			
				|  |  | +                    onUpdate:value={() => {
 | 
	
		
			
				|  |  | +                      // 如果是空则滑动到顶部
 | 
	
		
			
				|  |  | +                      const status =
 | 
	
		
			
				|  |  | +                        item.userAnswer && item.userAnswer.length > 0
 | 
	
		
			
				|  |  | +                          ? false
 | 
	
		
			
				|  |  | +                          : true;
 | 
	
		
			
				|  |  | +                      resizeSwipeItemHeight(status);
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                    data={item}
 | 
	
		
			
				|  |  | +                    index={index + 1}
 | 
	
		
			
				|  |  | +                    showAnalysis={item.showAnalysis}
 | 
	
		
			
				|  |  | +                    analysis={item.analysis}>
 | 
	
		
			
				|  |  | +                    {{
 | 
	
		
			
				|  |  | +                      title: () => (
 | 
	
		
			
				|  |  | +                        <div class={styles.questionTitle}>
 | 
	
		
			
				|  |  | +                          <div class={styles.questionNum}>
 | 
	
		
			
				|  |  | +                            <span>{state.currentIndex + 1}</span>/{state.total}
 | 
	
		
			
				|  |  | +                          </div>
 | 
	
		
			
				|  |  | +                          {/* <div class={styles.questionType}>
 | 
	
		
			
				|  |  | +                            <i></i>
 | 
	
		
			
				|  |  | +                            <span>{item.knowledgePointName}</span>
 | 
	
		
			
				|  |  | +                          </div> */}
 | 
	
		
			
				|  |  | +                          <Button
 | 
	
		
			
				|  |  | +                            round
 | 
	
		
			
				|  |  | +                            plain
 | 
	
		
			
				|  |  | +                            size="mini"
 | 
	
		
			
				|  |  | +                            color={item.grasp ? '#FF5A56' : '#1CACF1'}
 | 
	
		
			
				|  |  | +                            class={styles.controlBtn}
 | 
	
		
			
				|  |  | +                            disabled={item.grasp}
 | 
	
		
			
				|  |  | +                            onClick={() => onGraspQuestion(item)}>
 | 
	
		
			
				|  |  | +                            {item.grasp ? '已掌握此题' : '掌握此题'}
 | 
	
		
			
				|  |  | +                          </Button>
 | 
	
		
			
				|  |  | +                        </div>
 | 
	
		
			
				|  |  | +                      )
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  </DragQuestion>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {item.questionTypeCode === QuestionType.LINK && (
 | 
	
		
			
				|  |  | +                  <KeepLookQuestion
 | 
	
		
			
				|  |  | +                    v-model:value={item.userAnswer}
 | 
	
		
			
				|  |  | +                    data={item}
 | 
	
		
			
				|  |  | +                    index={index + 1}
 | 
	
		
			
				|  |  | +                    showAnalysis={item.showAnalysis}
 | 
	
		
			
				|  |  | +                    analysis={item.analysis}>
 | 
	
		
			
				|  |  | +                    {{
 | 
	
		
			
				|  |  | +                      title: () => (
 | 
	
		
			
				|  |  | +                        <div class={styles.questionTitle}>
 | 
	
		
			
				|  |  | +                          <div class={styles.questionNum}>
 | 
	
		
			
				|  |  | +                            <span>{state.currentIndex + 1}</span>/{state.total}
 | 
	
		
			
				|  |  | +                          </div>
 | 
	
		
			
				|  |  | +                          {/* <div class={styles.questionType}>
 | 
	
		
			
				|  |  | +                            <i></i>
 | 
	
		
			
				|  |  | +                            <span>{item.knowledgePointName}</span>
 | 
	
		
			
				|  |  | +                          </div> */}
 | 
	
		
			
				|  |  | +                          <Button
 | 
	
		
			
				|  |  | +                            round
 | 
	
		
			
				|  |  | +                            plain
 | 
	
		
			
				|  |  | +                            size="mini"
 | 
	
		
			
				|  |  | +                            color={item.grasp ? '#FF5A56' : '#1CACF1'}
 | 
	
		
			
				|  |  | +                            class={styles.controlBtn}
 | 
	
		
			
				|  |  | +                            disabled={item.grasp}
 | 
	
		
			
				|  |  | +                            onClick={() => onGraspQuestion(item)}>
 | 
	
		
			
				|  |  | +                            {item.grasp ? '已掌握此题' : '掌握此题'}
 | 
	
		
			
				|  |  | +                          </Button>
 | 
	
		
			
				|  |  | +                        </div>
 | 
	
		
			
				|  |  | +                      )
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  </KeepLookQuestion>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {item.questionTypeCode === QuestionType.PLAY && (
 | 
	
		
			
				|  |  | +                  <PlayQuestion
 | 
	
		
			
				|  |  | +                    v-model:value={item.userAnswer}
 | 
	
		
			
				|  |  | +                    data={item}
 | 
	
		
			
				|  |  | +                    index={index + 1}
 | 
	
		
			
				|  |  | +                    unitId={state.id as any}
 | 
	
		
			
				|  |  | +                    showAnalysis={item.showAnalysis}
 | 
	
		
			
				|  |  | +                    analysis={item.analysis}>
 | 
	
		
			
				|  |  | +                    {{
 | 
	
		
			
				|  |  | +                      title: () => (
 | 
	
		
			
				|  |  | +                        <div class={styles.questionTitle}>
 | 
	
		
			
				|  |  | +                          <div class={styles.questionNum}>
 | 
	
		
			
				|  |  | +                            <span>{state.currentIndex + 1}</span>/{state.total}
 | 
	
		
			
				|  |  | +                          </div>
 | 
	
		
			
				|  |  | +                          {/* <div class={styles.questionType}>
 | 
	
		
			
				|  |  | +                            <i></i>
 | 
	
		
			
				|  |  | +                            <span>{item.knowledgePointName}</span>
 | 
	
		
			
				|  |  | +                          </div> */}
 | 
	
		
			
				|  |  | +                          <Button
 | 
	
		
			
				|  |  | +                            round
 | 
	
		
			
				|  |  | +                            plain
 | 
	
		
			
				|  |  | +                            size="mini"
 | 
	
		
			
				|  |  | +                            color={item.grasp ? '#FF5A56' : '#1CACF1'}
 | 
	
		
			
				|  |  | +                            disabled={item.grasp}
 | 
	
		
			
				|  |  | +                            class={styles.controlBtn}
 | 
	
		
			
				|  |  | +                            onClick={() => onGraspQuestion(item)}>
 | 
	
		
			
				|  |  | +                            {item.grasp ? '已掌握此题' : '掌握此题'}
 | 
	
		
			
				|  |  | +                          </Button>
 | 
	
		
			
				|  |  | +                        </div>
 | 
	
		
			
				|  |  | +                      )
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  </PlayQuestion>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            </SwipeItem>
 | 
	
		
			
				|  |  | +          ))}
 | 
	
		
			
				|  |  | +        </Swipe>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <MSticky position="bottom">
 | 
	
		
			
				|  |  | +          <div class={['btnGroup btnMore', styles.btnSection]}>
 | 
	
		
			
				|  |  | +            <Button
 | 
	
		
			
				|  |  | +              round
 | 
	
		
			
				|  |  | +              block
 | 
	
		
			
				|  |  | +              class={
 | 
	
		
			
				|  |  | +                state.currentIndex > 0 ? styles.activePrevBtn : styles.prevBtn
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +              disabled={state.currentIndex > 0 ? false : true}
 | 
	
		
			
				|  |  | +              onClick={() => {
 | 
	
		
			
				|  |  | +                swipeRef.value?.prev();
 | 
	
		
			
				|  |  | +              }}>
 | 
	
		
			
				|  |  | +              上一题
 | 
	
		
			
				|  |  | +            </Button>
 | 
	
		
			
				|  |  | +            <Button
 | 
	
		
			
				|  |  | +              block
 | 
	
		
			
				|  |  | +              round
 | 
	
		
			
				|  |  | +              class={styles.nextBtn}
 | 
	
		
			
				|  |  | +              onClick={onNextQuestion}
 | 
	
		
			
				|  |  | +              loading={state.nextStatus}
 | 
	
		
			
				|  |  | +              disabled={state.nextStatus}>
 | 
	
		
			
				|  |  | +              {state.questionList.length === state.currentIndex + 1
 | 
	
		
			
				|  |  | +                ? '提交'
 | 
	
		
			
				|  |  | +                : '下一题'}
 | 
	
		
			
				|  |  | +            </Button>
 | 
	
		
			
				|  |  | +            <Image
 | 
	
		
			
				|  |  | +              src={iconButtonList}
 | 
	
		
			
				|  |  | +              class={[styles.wapList, 'van-haptics-feedback']}
 | 
	
		
			
				|  |  | +              onClick={() => (state.visiableAnswer = true)}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </MSticky>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        {/* 题目集合 */}
 | 
	
		
			
				|  |  | +        <ActionSheet
 | 
	
		
			
				|  |  | +          v-model:show={state.visiableAnswer}
 | 
	
		
			
				|  |  | +          title="题目列表"
 | 
	
		
			
				|  |  | +          safeAreaInsetBottom>
 | 
	
		
			
				|  |  | +          <AnswerList
 | 
	
		
			
				|  |  | +            value={state.questionList}
 | 
	
		
			
				|  |  | +            lookType={'PRACTICE'}
 | 
	
		
			
				|  |  | +            statusList={[
 | 
	
		
			
				|  |  | +              {
 | 
	
		
			
				|  |  | +                text: '答对',
 | 
	
		
			
				|  |  | +                color: '#1CACF1'
 | 
	
		
			
				|  |  | +              },
 | 
	
		
			
				|  |  | +              {
 | 
	
		
			
				|  |  | +                text: '答错',
 | 
	
		
			
				|  |  | +                color: '#FF8486'
 | 
	
		
			
				|  |  | +              },
 | 
	
		
			
				|  |  | +              {
 | 
	
		
			
				|  |  | +                text: '未答',
 | 
	
		
			
				|  |  | +                color: '#EAEAEA'
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            ]}
 | 
	
		
			
				|  |  | +            onSelect={(item: any) => {
 | 
	
		
			
				|  |  | +              // 跳转,并且跳过动画
 | 
	
		
			
				|  |  | +              swipeRef.value?.swipeTo(item, {
 | 
	
		
			
				|  |  | +                immediate: true
 | 
	
		
			
				|  |  | +              });
 | 
	
		
			
				|  |  | +              state.visiableAnswer = false;
 | 
	
		
			
				|  |  | +            }}
 | 
	
		
			
				|  |  | +          />
 | 
	
		
			
				|  |  | +        </ActionSheet>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <Popup
 | 
	
		
			
				|  |  | +          v-model:show={state.visiableError}
 | 
	
		
			
				|  |  | +          style={{ width: '90%' }}
 | 
	
		
			
				|  |  | +          round
 | 
	
		
			
				|  |  | +          closeOnClickOverlay={false}>
 | 
	
		
			
				|  |  | +          <ErrorMode
 | 
	
		
			
				|  |  | +            onClose={() => (state.visiableError = false)}
 | 
	
		
			
				|  |  | +            answerAnalysis={state.answerAnalysis}
 | 
	
		
			
				|  |  | +            questionTypeCode={state.questionTypeCode}
 | 
	
		
			
				|  |  | +            onConform={() => {
 | 
	
		
			
				|  |  | +              swipeRef.value?.next();
 | 
	
		
			
				|  |  | +              state.answerAnalysis = '';
 | 
	
		
			
				|  |  | +            }}
 | 
	
		
			
				|  |  | +          />
 | 
	
		
			
				|  |  | +        </Popup>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <Popup
 | 
	
		
			
				|  |  | +          v-model:show={state.visiableInfo.show}
 | 
	
		
			
				|  |  | +          closeOnClickOverlay={false}
 | 
	
		
			
				|  |  | +          style={{
 | 
	
		
			
				|  |  | +            background: 'transparent',
 | 
	
		
			
				|  |  | +            width: '100%',
 | 
	
		
			
				|  |  | +            maxWidth: '100%',
 | 
	
		
			
				|  |  | +            transform: 'translateY(-55%)'
 | 
	
		
			
				|  |  | +          }}>
 | 
	
		
			
				|  |  | +          <ResultFinish
 | 
	
		
			
				|  |  | +            title={state.visiableInfo.title}
 | 
	
		
			
				|  |  | +            showCancelButton={state.visiableInfo.showCancelButton}
 | 
	
		
			
				|  |  | +            cancelButtonText={state.visiableInfo.cancelButtonText}
 | 
	
		
			
				|  |  | +            confirmButtonText={state.visiableInfo.confirmButtonText}
 | 
	
		
			
				|  |  | +            status={state.visiableInfo.type}
 | 
	
		
			
				|  |  | +            content={state.visiableInfo.content}
 | 
	
		
			
				|  |  | +            contentHtml
 | 
	
		
			
				|  |  | +            onConform={onConfirmResult}
 | 
	
		
			
				|  |  | +            onClose={onCloseResult}
 | 
	
		
			
				|  |  | +          />
 | 
	
		
			
				|  |  | +        </Popup>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +});
 |