import { EnumQuestionType } from "@/common/enum"; import { getPaper } from '@/api/modules/study'; import { Study } from "@/types"; import { Question } from "@/types/study"; export const useExam = () => { const questionTypeDesc: Record = { [EnumQuestionType.SINGLE_CHOICE]: '单选题', [EnumQuestionType.MULTIPLE_CHOICE]: '多选题', [EnumQuestionType.JUDGMENT]: '判断题', [EnumQuestionType.FILL_IN_THE_BLANK]: '填空题', [EnumQuestionType.SUBJECTIVE]: '主观题', [EnumQuestionType.SHORT_ANSWER]: '简答题', [EnumQuestionType.ESSAY]: '问答题', [EnumQuestionType.ANALYSIS]: '分析题', [EnumQuestionType.OTHER]: '阅读题' } // 题型顺序 const questionTypeOrder = [ EnumQuestionType.SINGLE_CHOICE, EnumQuestionType.MULTIPLE_CHOICE, EnumQuestionType.JUDGMENT, EnumQuestionType.FILL_IN_THE_BLANK, EnumQuestionType.SUBJECTIVE, EnumQuestionType.SHORT_ANSWER, EnumQuestionType.ESSAY, EnumQuestionType.ANALYSIS, EnumQuestionType.OTHER ]; let interval: NodeJS.Timeout | null = null; const countDownCallback = ref<() => void>(() => { }); // 练习时长 const practiceDuration = ref(0); const formatPracticeDuration = computed(() => { const hours = Math.floor(practiceDuration.value / 3600); const minutes = Math.floor((practiceDuration.value % 3600) / 60); const seconds = practiceDuration.value % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; }); // 考试时长 const examDuration = ref(0); const formatExamDuration = computed(() => { const hours = Math.floor(examDuration.value / 3600); const minutes = Math.floor((examDuration.value % 3600) / 60); const seconds = examDuration.value % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; }); const swiperDuration = ref(300); const questionList = ref([]); // 收藏列表 const favoriteList = ref([]); // 不会列表 const notKnowList = ref([]); // 重点标记列表 const markList = ref([]); // 包含状态的问题列表 const stateQuestionList = computed(() => { return questionList.value.map(item => { return { ...item, isDone: isDone(item) } }); }); const groupedQuestionList = computed(() => { // 状态:已做、未做、是否不会、是否标记,整体按照题型分组 const state = questionTypeOrder.map(type => { return { type, list: [] as { question: Study.Question; index: number }[] } }); for (let i = 0; i <= questionList.value.length - 1; i++) { const qs = questionList.value[i]; state.forEach(item => { if (qs.typeId === item.type) { qs.isDone = isDone(qs); item.list.push({ question: qs, index: i }); } }); } return state; }); const isAllDone = computed(() => { return questionList.value.every(q => isDone(q)); }); // 当前下标 const currentIndex = ref(0); const totalCount = computed(() => { return questionList.value.length; }); const doneCount = computed(() => { // 有答案的或者不会做的,都认为是做了 // return groupedQuestionList.value.reduce((acc, item) => acc + item.list.filter(q => q.question.isDone || q.question.isNotKnow).length, 0); return stateQuestionList.value.filter(q => q.isDone || q.isNotKnow).length; }); const notDoneCount = computed(() => { // return questionList.value.length - doneCount.value; return stateQuestionList.value.length - doneCount.value; }); const notKnowCount = computed(() => { // return groupedQuestionList.value.reduce((acc, item) => acc + item.list.filter(q => q.question.isNotKnow).length, 0); return stateQuestionList.value.filter(q => q.isNotKnow).length; }); const markCount = computed(() => { // return groupedQuestionList.value.reduce((acc, item) => acc + item.list.filter(q => q.question.isMark).length, 0); return stateQuestionList.value.filter(q => q.isMark).length; }); const isDone = (qs: Study.Question): boolean => { if (qs.subQuestions && qs.subQuestions.length > 0) { return qs.subQuestions.every(q => isDone(q)); } return qs.answers && qs.answers.length > 0 || !!qs.isNotKnow; } const nextQuestion = () => { if (currentIndex.value >= questionList.value.length - 1) { return; } currentIndex.value++; } const prevQuestion = () => { if (currentIndex.value <= 0) { return; } currentIndex.value--; } const nextQuestionQuickly = () => { if (currentIndex.value >= questionList.value.length - 1) { return; } swiperDuration.value = 0; setTimeout(() => { nextQuestion(); setTimeout(() => { swiperDuration.value = 300; }, 0); }, 0); } const prevQuestionQuickly = () => { if (currentIndex.value <= 0) { return; } swiperDuration.value = 0; setTimeout(() => { prevQuestion(); setTimeout(() => { swiperDuration.value = 300; }, 0); }, 0); } const changeIndex = (index: number) => { swiperDuration.value = 0; setTimeout(() => { currentIndex.value = index; setTimeout(() => { swiperDuration.value = 300; }, 0); }, 0); } // 开始计时 const startPracticeDuration = () => { interval = setInterval(() => { practiceDuration.value += 1; }, 1000); } // 停止计时 const stopPracticeDuration = () => { interval && clearInterval(interval); interval = null; } // 开始倒计时 const startExamDuration = () => { interval = setInterval(() => { if (examDuration.value <= 0) { console.log('停止倒计时') stopExamDuration(); return; } examDuration.value -= 1; }, 1000); } // 停止倒计时 const stopExamDuration = () => { interval && clearInterval(interval); interval = null; countDownCallback.value && countDownCallback.value(); } const setExamDuration = (duration: number) => { examDuration.value = duration; } const setPracticeDuration = (duration: number) => { practiceDuration.value = duration; } const setCountDownCallback = (callback: () => void) => { countDownCallback.value = callback; } const setDuration = (duration: number) => { examDuration.value = duration; practiceDuration.value = duration; } const setQuestionList = (list: Study.ApiQuestion[]) => { const orders = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; // 数据预处理 // 1、给每个项目补充额外字段 const parseQuestion = (item: Study.ApiQuestion): Study.Question => { return { title: item.title, // 处理没有题型的大题,统一作为阅读题 typeId: (item.typeId === null || item.typeId === undefined) ? EnumQuestionType.OTHER : item.typeId, id: item.id, answers: item.answers || [], subQuestions: item.subQuestions?.map(parseQuestion) || [], options: item.options?.map((option, index) => { return { name: option, no: orders[index], id: index, isAnswer: false } as Study.QuestionOption }) || [], isDone: false, isMark: item.isMark, isNotKnow: item.isNotKnow, isFavorite: item.isFavorite } as Study.Question } const arr: Study.Question[] = list.map(item => { return parseQuestion(item); }); questionList.value = arr; } const reset = () => { questionList.value = questionList.value.map(item => { return { ...item, answers: [], isMark: false, isNotKnow: false } as Study.Question; }); changeIndex(0); practiceDuration.value = 0; examDuration.value = 0; interval && clearInterval(interval); interval = null; } return { questionList, groupedQuestionList, stateQuestionList, favoriteList, notKnowList, markList, currentIndex, isAllDone, totalCount, doneCount, notDoneCount, notKnowCount, markCount, questionTypeDesc, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration, practiceDuration, examDuration, formatExamDuration, formatPracticeDuration, startPracticeDuration, stopPracticeDuration, setDuration, startExamDuration, stopExamDuration, setExamDuration, setPracticeDuration, setCountDownCallback, setQuestionList, changeIndex, reset } }