import { ActionSheet, Button, Image, Popup, Swipe, SwipeItem, showToast } 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'; import { browser } from '@/helpers/utils'; export default defineComponent({ name: 'unit-detail', setup() { const route = useRoute(); const router = useRouter(); const swipeRef = ref(); const state = reactive({ background: 'transparent', // color: '#323333', visiableError: false, visiableAnswer: false, id: route.query.id, currentIndex: 0, questionList: [] as any, page: 1, rows: 50, 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 ( maxStudentExaminationErrorEditionId?: string ) => { try { const { data } = await request.post( '/edu-app/studentUnitExamination/errorEdition', { data: { page: state.page, rows: state.rows, maxStudentExaminationErrorEditionId } } ); 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, () => { // 判断是否在倒数第三题,并且没有加载完 if ( state.currentIndex + 3 >= state.questionList.length && !state.isFinish ) { const lastQuestion = state.questionList[state.questionList.length - 1]; state.page = state.page + 1; getExamDetails(lastQuestion.id); } } ); /** 已掌握此题 */ 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; console.log(state.total, 'toa'); if (state.total <= 1) { onAfter(); } }; /** 已掌握此题确认 */ const onGraspQuestionConfirm = async () => { try { state.visiableInfo.show = false; await request.get('/edu-app/studentExaminationErrorEdition/del', { hideLoading: false, params: { questionId: state.visiableInfo.graspItem.id } }); state.visiableInfo.graspItem.grasp = true; eventUnit.emit('unitAudioStop'); // 只有一道题 if (state.total <= 1) { router.back(); router.back(); return; } // 后面还有题 if (state.total > state.currentIndex + 1) { const index = state.questionList.findIndex( (item: any) => item.studentExaminationErrorEditionId === state.visiableInfo.graspItem.studentExaminationErrorEditionId ); state.questionList.splice(index, 1); state.total -= 1; resizeSwipeItemHeight(); // swipeRef.value?.next(); return; } // 后面没有题 if (state.total == state.currentIndex + 1) { const index = state.questionList.findIndex( (item: any) => item.studentExaminationErrorEditionId === state.visiableInfo.graspItem.studentExaminationErrorEditionId ); state.questionList.splice(index, 1); state.total -= 1; state.currentIndex -= 1; resizeSwipeItemHeight(); // swipeRef.value?.prev(); return; } } catch { // } }; /** * @description 下一题 | 测试完成 */ const onNextQuestion = async () => { try { const questionList = state.questionList || []; const question: any = questionList[state.currentIndex]; if (question?.userAnswer?.length <= 0) { showToast('题目尚未做答'); state.nextStatus = false; return; } 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 = `确认本次练习的题目都完成了吗?`; onAfter(); 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; router.back(); router.back(); } else if (state.visiableInfo.operationType === 'BACK') { state.visiableInfo.show = false; window.history.pushState(null, '', document.URL); window.addEventListener('popstate', onBack, false); } 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; onAfter(); } else if (operationType === 'CONTINUE') { state.visiableInfo.show = false; } else if (operationType === 'GRASP') { state.visiableInfo.show = false; window.history.pushState(null, '', document.URL); window.addEventListener('popstate', onBack, 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 = `
{item.knowledgePointName}
{state.currentIndex + 1}/{state.total}{item.knowledgePointName}
{state.currentIndex + 1}/{state.total}{item.knowledgePointName}
{state.currentIndex + 1}/{state.total}{item.knowledgePointName}
{state.currentIndex + 1}/{state.total}