|
|
@@ -2,48 +2,55 @@
|
|
|
<ie-page :fix-height="true" :safe-area-inset-bottom="false">
|
|
|
<ie-navbar :title="pageTitle" custom-back @left-click="handleLeftClick">
|
|
|
<template v-if="isReady" #headerRight>
|
|
|
- <view class="" :class="{ 'text-red-500': practiceDuration > totalExamTime }">{{ formatPracticeDuration }}</view>
|
|
|
+ <view v-if="!isReadOnly" class="" :class="{ 'text-red-500': practiceDuration > totalExamTime }">{{
|
|
|
+ formatPracticeDuration }}</view>
|
|
|
+ <view v-else class="text-28">用时:{{ formatPracticeDuration }}</view>
|
|
|
</template>
|
|
|
</ie-navbar>
|
|
|
- <view v-if="isReady" 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-wrap :question="item" @update:question="handleUpdateQuestion" />
|
|
|
- </swiper-item>
|
|
|
- </swiper>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <ie-safe-toolbar v-if="isReady" :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" id="question-correct-btn" @click="handleCorrect">
|
|
|
- <uv-icon name="info-circle" size="24" />
|
|
|
+ <block v-if="isReady">
|
|
|
+ <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 class="w-48 h-48 flex items-center justify-center" id="question-favorite-btn" @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" id="question-mark-btn" @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" id="question-calendar-btn" @click="handleCalendar">
|
|
|
- <uv-icon name="calendar" size="28" />
|
|
|
+ </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">
|
|
|
+ <block v-for="(item, index) in questionList" :key="item.id">
|
|
|
+ <swiper-item class="h-full" v-show="Math.abs(currentIndex - index) <= 2">
|
|
|
+ <question-wrap :question="item" :currentIndex="currentIndex" :index="index" :readonly="isReadOnly"
|
|
|
+ @update:question="handleUpdateQuestion" />
|
|
|
+ </swiper-item>
|
|
|
+ </block>
|
|
|
+ </swiper>
|
|
|
</view>
|
|
|
</view>
|
|
|
- </ie-safe-toolbar>
|
|
|
+ <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" id="question-correct-btn" @click="handleCorrect">
|
|
|
+ <uv-icon name="info-circle" size="24" />
|
|
|
+ </view>
|
|
|
+ <view class="w-48 h-48 flex items-center justify-center" id="question-favorite-btn" @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" id="question-mark-btn" @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" id="question-calendar-btn" @click="handleCalendar">
|
|
|
+ <uv-icon name="calendar" size="28" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </ie-safe-toolbar>
|
|
|
+ </block>
|
|
|
</ie-page>
|
|
|
- <question-stats-popup ref="questionStatsPopupRef">
|
|
|
+ <question-stats-popup ref="questionStatsPopupRef" :readonly="isReadOnly">
|
|
|
<template #title>
|
|
|
<view class="ml-20">
|
|
|
<text class="text-30 text-primary">{{ doneCount }}</text>
|
|
|
@@ -57,20 +64,22 @@
|
|
|
<view v-for="(item, i) in groupedQuestionList" :key="i" class="">
|
|
|
<template v-if="item.list.length > 0">
|
|
|
<view class="h-70 bg-back px-20 leading-70 text-fore-subcontent">{{ questionTypeDesc[item.type] }}</view>
|
|
|
- <view class="grid grid-cols-5 place-items-center gap-x-20 gap-y-20 p-30">
|
|
|
+ <view class="grid grid-cols-5 place-items-center gap-x-20 gap-y-30 p-30">
|
|
|
<view v-for="(qs, j) in item.list" :key="j" class="aspect-square flex items-center justify-center"
|
|
|
@click="hanadleNavigate(qs.index)">
|
|
|
<view
|
|
|
class="w-74 h-74 rounded-full flex items-center justify-center bg-white border border-solid border-border relative"
|
|
|
:class="{
|
|
|
- 'is-done': qs.question.isDone,
|
|
|
- 'is-not-know': qs.question.isNotKnow,
|
|
|
- 'is-mark': qs.question.isMark
|
|
|
+ 'is-done': !isReadOnly && qs.question.isDone,
|
|
|
+ 'is-not-know': !isReadOnly && qs.question.isNotKnow,
|
|
|
+ 'is-mark': !isReadOnly && qs.question.isMark,
|
|
|
+ 'is-correct': isReadOnly && qs.question.isCorrect,
|
|
|
+ 'is-incorrect': isReadOnly && !qs.question.isCorrect,
|
|
|
}">
|
|
|
- <text class="z-1">{{ qs.index + 1 }}</text>
|
|
|
+ <text class="z-1 font-bold text-32">{{ qs.index + 1 }}</text>
|
|
|
<ie-image v-if="qs.question.isMark" src="/pagesStudy/static/image/icon-mark-active.png"
|
|
|
custom-class="absolute -top-12 left-14 w-28 h-28 z-1" mode="aspectFill" />
|
|
|
- <question-progress :progress="qs.question.progress || 0" />
|
|
|
+ <question-progress v-if="!isReadOnly" :progress="qs.question.progress || 0" />
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -78,7 +87,7 @@
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
- <view class="h-150 bg-white flex items-center gap-x-120 px-40">
|
|
|
+ <view v-if="!isReadOnly" class="h-150 bg-white flex items-center gap-x-120 px-40">
|
|
|
<view class="flex flex-col items-center gap-x-10" @click="handleReset">
|
|
|
<uv-icon name="reload" size="20" :color="doneCount > 0 ? '#999' : '#cccccc'" />
|
|
|
<text class="mt-4 text-20 text-subcontent" :class="{ 'text-fore-light': doneCount <= 0 }">重新作答</text>
|
|
|
@@ -102,7 +111,7 @@ import QuestionSwiperTip from './components/question-swiper-tip.vue';
|
|
|
import { useTransferPage } from '@/hooks/useTransferPage';
|
|
|
import { useUserStore } from '@/store/userStore';
|
|
|
import { EnumPaperType } from '@/common/enum';
|
|
|
-import { getOpenExaminee, getPaper, commitExamineePaper, collectQuestion, cancelCollectQuestion, beginExaminee } from '@/api/modules/study';
|
|
|
+import { getOpenExaminee, getPaper, commitExamineePaper, collectQuestion, cancelCollectQuestion, beginExaminee, getExamineeResult } 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';
|
|
|
@@ -157,18 +166,22 @@ const examineeId = ref<number | undefined>(undefined);
|
|
|
// const examineerData = ref<Study.Examinee>({} as Study.Examinee);
|
|
|
const paperData = ref<Study.ExamPaper>({} as Study.ExamPaper);
|
|
|
const pageTitle = computed(() => {
|
|
|
- const { paperType } = prevData.value;
|
|
|
- return paperType === EnumPaperType.PRACTICE ? '练习' : '考试';
|
|
|
+ if (isReadOnly.value) {
|
|
|
+ return '考试解析';
|
|
|
+ }
|
|
|
+ return isExam.value ? '练习' : '考试';
|
|
|
});
|
|
|
const isExam = computed(() => {
|
|
|
return prevData.value.paperType === EnumPaperType.SIMULATED;
|
|
|
});
|
|
|
const pageSubtitle = computed(() => {
|
|
|
- const { name } = prevData.value;
|
|
|
- return name;
|
|
|
+ return prevData.value.name;
|
|
|
+});
|
|
|
+const isReadOnly = computed(() => {
|
|
|
+ return prevData.value.readonly;
|
|
|
});
|
|
|
const handleLeftClick = () => {
|
|
|
- if (!isReady.value) {
|
|
|
+ if (isReady.value) {
|
|
|
transferBack();
|
|
|
return;
|
|
|
}
|
|
|
@@ -261,7 +274,9 @@ const handleSwiperAnimationFinish = (e: any) => {
|
|
|
}
|
|
|
const offsetX = transitionEndX.value - transitionStartX.value;
|
|
|
if (offsetX < 0 && offsetX > -150) {
|
|
|
- beforeSubmit();
|
|
|
+ if (!isReadOnly.value) {
|
|
|
+ beforeSubmit();
|
|
|
+ }
|
|
|
}
|
|
|
isAnimationFinish.value = true;
|
|
|
transitionStartX.value = null;
|
|
|
@@ -357,7 +372,7 @@ const handleUpdateQuestion = (question: Study.Question) => {
|
|
|
* @param savedQuestion 上次做题历史数据
|
|
|
* @param fullQuestion 当前试卷数据
|
|
|
*/
|
|
|
-const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion: Study.ApiQuestion[]) => {
|
|
|
+const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion: Study.ExamineeQuestion[]) => {
|
|
|
if (!savedQuestion) {
|
|
|
return fullQuestion;
|
|
|
}
|
|
|
@@ -367,9 +382,12 @@ const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion:
|
|
|
if (savedQs.answers) {
|
|
|
item.answers = savedQs.answers.filter(ans => ans.trim());
|
|
|
}
|
|
|
+ item.answer1 = savedQs.answer1;
|
|
|
+ item.answer2 = savedQs.answer2;
|
|
|
item.isMark = savedQs.isMark;
|
|
|
item.isFavorite = savedQs.isFavorite;
|
|
|
item.isNotKnow = savedQs.isNotKnow;
|
|
|
+ item.parse = savedQs.parse;
|
|
|
if (item.subQuestions) {
|
|
|
restoreQuestion(savedQs.subQuestions, item.subQuestions);
|
|
|
}
|
|
|
@@ -394,9 +412,15 @@ const loadPracticeData = async () => {
|
|
|
combinePaperData(data, paperType);
|
|
|
}
|
|
|
const loadSimulationData = async () => {
|
|
|
- const { paperType, simulationInfo } = prevData.value;
|
|
|
- const { data } = await beginExaminee(simulationInfo.examineeId);
|
|
|
- console.log('开卷信息', data)
|
|
|
+ const { paperType, readonly, simulationInfo } = prevData.value;
|
|
|
+ let data: Study.Examinee;
|
|
|
+ if (readonly) {
|
|
|
+ const res = await getExamineeResult(simulationInfo.examineeId);
|
|
|
+ data = res.data;
|
|
|
+ } else {
|
|
|
+ const res = await beginExaminee(simulationInfo.examineeId);
|
|
|
+ data = res.data;
|
|
|
+ }
|
|
|
if (!data) {
|
|
|
uni.$ie.hideLoading();
|
|
|
transferBack();
|
|
|
@@ -417,8 +441,11 @@ const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperTy
|
|
|
setQuestionList(paperData.value.questions);
|
|
|
setDuration(examinee.duration || 0);
|
|
|
await nextTick();
|
|
|
- isReady.value = true;
|
|
|
+ const questionIndex = prevData.value.questionId ? paperData.value.questions.findIndex(item => item.id === prevData.value.questionId) : 0;
|
|
|
+ changeIndex(questionIndex);
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 50));
|
|
|
await nextTick();
|
|
|
+ isReady.value = true;
|
|
|
console.log('试卷信息', res)
|
|
|
if (!userStore.isExamGuideShow) {
|
|
|
setTimeout(() => {
|
|
|
@@ -429,7 +456,9 @@ const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperTy
|
|
|
}, 300);
|
|
|
} else {
|
|
|
uni.$ie.hideLoading();
|
|
|
- startTime();
|
|
|
+ if (!isReadOnly.value) {
|
|
|
+ startTime();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -479,4 +508,12 @@ onLoad(() => {
|
|
|
.is-not-know {
|
|
|
@apply text-fore-title border-[#F2F2F2] bg-[#F2F2F2];
|
|
|
}
|
|
|
+
|
|
|
+.is-correct {
|
|
|
+ @apply text-[#2CC6A0] border-[#E7FCF8] bg-[#E7FCF8];
|
|
|
+}
|
|
|
+
|
|
|
+.is-incorrect {
|
|
|
+ @apply text-[#FF5B5C] border-[#FEEDE9] bg-[#FEEDE9];
|
|
|
+}
|
|
|
</style>
|