| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- <template>
- <ie-page :fix-height="true" :safe-area-inset-bottom="false">
- <ie-navbar :title="pageTitle" custom-back @left-click="handleLeftClick">
- <template #headerRight>
- <view v-if="isExamMode" class="countdown-text" :class="{ 'text-red-500': examDuration < 30 }">
- {{ formatExamDuration }}
- </view>
- <view v-else class="">{{ formatPracticeDuration }}</view>
- </template>
- </ie-navbar>
- <view class="px-20 py-14 bg-back flex justify-between items-center gap-x-20">
- <text class="flex-1 min-w-1 text-26 ellipsis-1">{{ pageSubtitle }}</text>
- <view class="flex items-baseline">
- <text class="text-34 text-primary font-bold">{{ currentIndex + 1 }}</text>/
- <text class="text-28 text-fore-subtitle">{{ totalCount }}</text>
- </view>
- </view>
- <view class="flex-1 min-h-1 relative">
- <view class="absolute inset-0 ">
- <swiper class="h-full" :disable-touch="false" :current="currentIndex" :duration="swiperDuration"
- @change="handleSwiperChange" @transition="handleSwiperTransition"
- @animationfinish="handleSwiperAnimationFinish">
- <swiper-item class="h-full" v-for="(item, index) in questionList" :key="index">
- <question-item :question="item" />
- </swiper-item>
- </swiper>
- </view>
- </view>
- <ie-safe-toolbar :height="64" :shadow="false">
- <view class="px-18 h-full flex items-center justify-around border-0 border-t border-solid border-[#EFEFEF]">
- <view class="w-48 h-48 flex items-center justify-center" @click="handleFavorite">
- <uv-icon v-if="currentQuestion.isFavorite" name="star-fill" color="#FF9A18" size="27" />
- <uv-icon v-else name="star" size="27" />
- </view>
- <view class="w-48 h-48 flex items-center justify-center" @click="handleMark">
- <ie-image
- :src="currentQuestion.isMark ? '/pagesStudy/static/image/icon-mark-active.png' : '/pagesStudy/static/image/icon-mark.png'"
- custom-class="w-38 h-38" mode="aspectFill" />
- </view>
- <view class="w-48 h-48 flex items-center justify-center" @click="handleCalendar">
- <uv-icon name="calendar" size="28" />
- </view>
- </view>
- </ie-safe-toolbar>
- </ie-page>
- <question-stats-popup ref="questionStatsPopupRef">
- <template #title>
- <view class="ml-20">
- <text class="text-30 text-primary">{{ doneCount }}</text>
- <text>/</text>
- <text class="text-30 text-fore-light">{{ totalCount }}</text>
- </view>
- </template>
- <view class="popup-content">
- <view class="flex-1 min-h-1">
- <scroll-view class="h-full" scroll-y>
- <view v-for="(item, i) in stateQuestionList" :key="i" class="">
- <template v-if="item.list.length > 0">
- <view class="h-60 bg-back px-20 leading-60 text-fore-subcontent">{{ questionTypeDesc[item.type] }}</view>
- <view class="grid grid-cols-5 place-items-center gap-x-20 gap-y-20">
- <view v-for="(qs, j) in item.list" :key="j" class="py-20 flex items-center justify-center">
- <view
- class="w-52 h-52 rounded-full flex items-center justify-center bg-white border border-solid border-border"
- :class="{
- 'is-done': qs.question.isDone,
- 'is-not-know': qs.question.isNotKnow,
- 'is-mark': qs.question.isMark
- }">
- {{ qs.index + 1 }}
- </view>
- </view>
- </view>
- </template>
- </view>
- </scroll-view>
- </view>
- <view class="h-150 bg-white flex items-center gap-x-120 px-40">
- <view class="flex flex-col items-center gap-x-10">
- <uv-icon name="reload" size="20" />
- <text class="mt-4 text-20 text-subcontent">重新作答</text>
- </view>
- <view class="flex-1 py-20 text-center rounded-full bg-primary text-white">交卷</view>
- </view>
- </view>
- </question-stats-popup>
- </template>
- <script lang="ts" setup>
- import QuestionItem from './components/question-item.vue';
- import QuestionStatsPopup from './components/question-stats-popup.vue';
- import { useTransferPage } from '@/hooks/useTransferPage';
- import { EnumExamMode, EnumQuestionType } from '@/common/enum';
- import { getOpenExaminee } 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';
- const { prevData } = useTransferPage();
- const { questionList, stateQuestionList, questionTypeDesc, favoriteList, notKnowList, markList, currentIndex,
- totalCount, doneCount, notDoneCount, notKnowCount, markCount,
- loadExamData, nextQuestion, prevQuestion, nextQuestionQuickly, prevQuestionQuickly, swiperDuration,
- formatPracticeDuration, formatExamDuration, practiceDuration, startPracticeDuration, stopPracticeDuration,
- examDuration, startExamDuration, stopExamDuration, setExamDuration, setCountDownCallback } = useExam();
- provide(NEXT_QUESTION, nextQuestion);
- provide(PREV_QUESTION, prevQuestion);
- provide(NEXT_QUESTION_QUICKLY, nextQuestionQuickly);
- provide(PREV_QUESTION_QUICKLY, prevQuestionQuickly);
- const isAnimationFinish = ref(false);
- const transitionStartX = ref(null);
- const transitionEndX = ref(null);
- const pageTitle = computed(() => {
- const { mode } = prevData.value;
- return mode === EnumExamMode.PRACTICE ? '练习' : '考试';
- });
- const pageSubtitle = computed(() => {
- const { mode, name } = prevData.value;
- return (mode === EnumExamMode.PRACTICE ? '知识点练习' : '考试') + '-' + name;
- });
- const isExamMode = computed(() => {
- return prevData.value.mode === EnumExamMode.EXAM;
- });
- const handleLeftClick = () => {
- beforeQuit();
- };
- const handleSwiperChange = (e: any) => {
- console.log(e)
- currentIndex.value = e.detail.current;
- };
- const beforeQuit = () => {
- const { mode } = prevData.value;
- if (mode === EnumExamMode.PRACTICE) {
- beforeQuitPractice();
- } else {
- beforeQuitExam();
- }
- };
- const beforeQuitPractice = () => {
- uni.$ie.showModal({
- title: '提示',
- content: '当前练习未完成,确认退出?',
- }).then(confirm => {
- if (confirm) {
- uni.$ie.showLoading('保存中...');
- setTimeout(() => {
- uni.$ie.hideLoading();
- uni.navigateBack();
- }, 1000);
- }
- });
- };
- const beforeQuitExam = () => {
- uni.$ie.showModal({
- title: '提示',
- content: '当前考试未完成,确认退出?',
- }).then(confirm => {
- if (confirm) {
- uni.navigateBack();
- }
- });
- };
- const currentQuestion = computed(() => {
- console.log(questionList.value[currentIndex.value])
- return questionList.value[currentIndex.value];
- });
- const handleFavorite = () => {
- console.log('handleFavorite')
- currentQuestion.value.isFavorite = !currentQuestion.value.isFavorite;
- };
- const handleMark = () => {
- console.log('handleMark')
- currentQuestion.value.isMark = !currentQuestion.value.isMark;
- };
- const questionStatsPopupRef = ref();
- const handleCalendar = () => {
- console.log('handleCalendar')
- questionStatsPopupRef.value.open();
- };
- const handleSwiperTransition = (e: any) => {
- if (currentIndex.value === questionList.value.length - 1) {
- if (!transitionStartX.value) {
- transitionStartX.value = e.detail.dx;
- } else {
- transitionEndX.value = e.detail.dx;
- }
- return;
- }
- };
- const startTime = () => {
- if (isExamMode.value) {
- startExamDuration();
- } else {
- startPracticeDuration();
- }
- }
- const stopTime = () => {
- if (isExamMode.value) {
- stopExamDuration();
- } else {
- stopPracticeDuration();
- }
- }
- const handleSwiperAnimationFinish = (e: any) => {
- if (transitionStartX.value == null || transitionEndX.value == null || currentIndex.value !== questionList.value.length - 1) {
- isAnimationFinish.value = true;
- transitionStartX.value = null;
- transitionEndX.value = null;
- return;
- }
- const offsetX = transitionEndX.value - transitionStartX.value;
- if (offsetX < 0 && offsetX > -150) {
- const text = notDoneCount.value > 0 ? `还有${notDoneCount.value}题未做,确认交卷?` : '是否确认交卷?';
- stopTime();
- uni.$ie.showModal({
- title: '提示',
- content: text,
- }).then(confirm => {
- if (confirm) {
- // uni.navigateBack();
- handleSubmit();
- } else {
- startTime();
- }
- });
- }
- isAnimationFinish.value = true;
- transitionStartX.value = null;
- transitionEndX.value = null;
- };
- const handleSubmit = () => {
- uni.$ie.showLoading('保存中...');
- setTimeout(() => {
- uni.$ie.hideLoading();
- uni.navigateBack();
- }, 1000);
- console.log('handleSubmit')
- }
- const loadData = async () => {
- // const { data } = await getOpenExaminee({
- // paperType: prevData.value.paperType,
- // relateId: prevData.value.relateId
- // });
- // console.log(data)
- // 构造模拟数据
- console.log(questionList.value)
- loadExamData();
- // setExamDuration(35)
- setCountDownCallback(() => {
- uni.$ie.showToast('考试结束');
- // uni.navigateBack();
- });
- startTime();
- // startExamDuration();
- };
- onMounted(() => {
- setTimeout(() => {
- console.log(stateQuestionList.value)
- handleCalendar();
- }, 500);
- });
- onLoad(() => {
- console.log(prevData.value)
- loadData();
- });
- </script>
- <style lang="scss" scoped>
- .countdown-text {
- height: 100%;
- display: flex;
- align-items: center;
- font-weight: bold;
- font-family: 'Courier New', Courier, monospace;
- }
- .popup-content {
- @apply h-[42vh] flex flex-col;
- }
- .scroll-view {
- @apply h-full;
- }
- .is-done {
- @apply text-primary border-[#EBF9FF] bg-[#EBF9FF];
- }
- .is-not-know {
- @apply border-[#F2F2F2] bg-[#F2F2F2];
- }
- </style>
|