|
|
<template> <view class="content"> <up-navbar leftText=" " title="" :safeAreaInsetTop="false" :autoBack="true"> <template #center> <view class="flex"> <view class="lastText">剩余时间</view> <view class="lastText" style="margin: 8rpx 0 0 8rpx"><up-count-down :time="totalExamTime * 60 * 1000" format="mm:ss" @finish="finishFn" ref="countDownRef"></up-count-down></view> </view> </template> </up-navbar> <view class="top_row flex"> <view class="itemCount"> <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" ></up-icon> <view class="count">{{ yesNum }}</view> </view> <view class="itemCount"> <up-icon name="close-circle-fill" color="#ff0000" size="20" ></up-icon> <view class="count">{{ noNum }}</view> </view> <view class="mr"> <view class="count">{{currentIndex+1}}/<text>{{questionBankList.length}}</text></view> </view> </view>
<view class="con padding"> <view class="h1_row"> <text class="tag" :class="{red: questionBank.types==2, blue: questionBank.types==3}">{{types[questionBank.types-1]}}</text> <text class="h1" @click="speak(questionBank.title)">{{ questionBank.title}}</text> </view> <view class="imgBox" style="width: 100%;padding: 0 0 30rpx 0;" v-if="questionBank.img"> <image :src="questionBank.img" mode="widthFix"></image> </view> <view class="option"> <view v-for="(item,index) in questionBank.optionArr" @click="chooseOption(item)"> <!-- 多选题 --> <view class="optionItem flex" v-if="questionBank.types ==2&& (!curOption.answer||curOption.answer==questionBank.answer)"> <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" v-if="curOption.ans?.includes(item.key)"></up-icon> <view class="icon" v-else></view> <view class="text"><text >{{item.key}}</text> {{item.text}}</view> </view> <!-- 正常答案 --> <view class="optionItem flex" v-else > <view class="icon" v-if="!curOption.key&&questionBank.types !=2"></view> <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" v-else-if="questionBank.answer.includes(item.key)"></up-icon> <up-icon name="close-circle-fill" color="#ff0000" size="20" v-else></up-icon> <view class="text"><text v-if="questionBank.types!=3">{{item.key}}</text> {{item.text}}</view> </view> <!-- ans --> </view> </view> <view class="answerCss flex" v-if="curOption.answer&&questionBank.answer!=curOption.answer"> <view class="ans">正确答案是 <text v-if="questionBank.types==3" >{{ questionBank.answer=='false'?'错误':'正确' }}</text> <text v-else >{{ questionBank.answer }}</text> </view> <view class="ans">您的答案是 <text v-if="questionBank.types==3" class="red">{{ curOption.answer=='false'?'错误':'正确' }}</text> <text v-else class="red">{{ curOption.answer }}</text> </view> </view> <view class="btn_row flex-b"> <!-- @click="$goPage('/pages/exercises/lastPage/lastPage')" --> <button class="btn border" @click="debounce(nextQuestion(-1), 500)" :class="{disable: currentIndex==0}" :disabled="currentIndex==0">上一题</button> <button class="btn bg" @click="debounce(nextQuestion(1), 500)" :class="{disable: currentIndex>=questionBankList.length-1}" :disabled="currentIndex>=questionBankList.length-1">下一题</button> </view> <view class="analysis" v-if="currentNav==2||(curOption.answer&&curOption.answer!=questionBank.answer)"> <view class="tit">题目解析</view> <view class="txt">{{ questionBank.resolving }}</view> </view> </view> <view class="bottomBar"> <view class="ul"> <!-- <view class="li"> <view class="icon" style="color: #55ff7f;">{{ yesNum }}</view> <view class="text">答对</view> </view> <view class="li"> <view class="icon" style="color: #ff0000;">{{ noNum }}</view> <view class="text">答错</view> </view> <view class="li"> <view class="icon">{{currentIndex}}/<text style="color: #999; font-size: 24rpx;">{{quesIdList.length}}</text></view> <view class="text">题目</view> </view> --> <view class="flex leftCotrl"> <view class="li" @click="showCommt=true"> <view class="icon"> <image src="@/static/images/theory/fankui.png" mode=""></image> </view> <view class="text">反馈</view> </view> <view class="li" @click="openPopup"> <view class="icon"> <image src="@/static/images/theory/dtk.png" mode=""></image> </view> <view class="text">答题卡</view> </view> <view class="li" @click="questionWrongColleFn"> <view class="icon"> <image src="@/static/images/theory/scActive.png" mode="" v-if="questionBank.isCollect=='1'"></image> <image src="@/static/images/theory/sc.png" mode="" v-else></image> </view> <view class="text">收藏</view> </view> </view> <view class="submitBtn" @click="handApaper">交卷</view> </view> </view> <up-popup :show="show" @close="closePopup" @open="openPopup" mode="bottom" round="20" closeable> <view class="popupCon"> <view class="h3">答题卡</view> <view class="ulRow"> <view class="ul"> <view class="li"> <view class="icon" style="color: #55ff7f;">{{ yesNum }}</view> <view class="text">答对</view> </view> <view class="li"> <view class="icon" style="color: #ff0000;">{{ noNum }}</view> <view class="text">答错</view> </view> <view class="li" style="margin-left: auto;"> <view class="icon">{{currentIndex+1}}/<text style="color: #999; font-size: 24rpx;">{{questionBankList.length}}</text></view> <view class="text">题目</view> </view> </view> </view> <view class="ul2"> <view class="li2" v-for="(item,index) in questionBankList" :key="index" @click="quesIdListClick(item,index)"> <view class="num" :class="{yes: item.yes==1, no: item.yes==0}">{{ index+1 }} <text v-if="index==currentIndex">当前</text> </view> </view> </view> </view> </up-popup> <up-popup :show="showCommt" @close="showCommtClose" mode="bottom" round="20rpx" closeable> <view class="commtCon" style="padding: 30rpx"> <up-textarea v-model.trim="contentStr" placeholder="请输入反馈内容" style="margin-top: 50rpx;" maxlength="300"></up-textarea> <up-button text="提 交" style="margin-top: 20rpx;" type="primary" @click="submitClick"></up-button> </view> </up-popup> <up-popup :show="showCommit" @close="closeCommitPopup" mode="center" round="20rpx" closeable > <view class="commitCon"> <view class="tit" v-if="remaining">当前考试进度</view> <view class="tit" style="color: red;" v-else-if="passScore.value*1>yesNum.value">成绩不合格</view> <view class="flex"> <view class="commitItem"> <view class="num">{{ remaining }}</view> <view class="lab">未答题数</view> </view> <view class="commitItem"> <view class="num">{{ questionBankList.length - remaining}}</view> <view class="lab">已答题数</view> </view> <view class="commitItem"> <view class="num"><up-count-down :time="totalExamTime||0 * 60 * 60 * 1000" format="HH:mm" ref="countDownRef"/></view> <view class="lab">剩余时间</view> </view> </view> <view class="imgAdd"> <image src="@/static/images/bigImg/addImg.png" mode="widthFix"></image> </view> <view class="btn_commit_row flex-b" v-if="remaining"> <view class="border btn" @click="goBack" >放弃考试</view> <view class="btn" @click="closeCommitPopup">继续考试</view> </view> <view class="btn_commit_row flex-b" v-else> <view class="border btn" @click="closeCommitPopup" >继续答题</view> <view class="btn" @click="submitBtnFn">现在交卷</view> </view> </view> </up-popup> </view> </template>
<script setup> function speak(text) { const speech = new SpeechSynthesisUtterance(text); // 创建语音消息
window.speechSynthesis.speak(speech); // 播报消息
} import { startExam, getQuestionApi, questionCommentAdd, startExamDo, questionWrongColle } from '@/config/api.js' import { debounce } from '@/uni_modules/uview-plus'; import { ref, reactive, watch, nextTick, } from 'vue'; const currentNav = ref('1') const types = ref([ '单选题', '多选题', '判断题' ]) const yesNum = ref(0) const noNum = ref(0) let showCommit = ref(false) import carStore from '@/store/modules/car.js' let usecarStore = carStore() import { onLoad, onReady } from "@dcloudio/uni-app" let totalExamTime = ref(45) let passScore = ref(90) onLoad((options)=>{ totalExamTime.value = options.totalExamTime || 45 passScore.value = options.score }) // 1:单选题,2:多选题,3:判断题
function changeNav(val) { console.log(window) if(currentNav.value == val) return currentNav.value = val } function goEmam() { uni.navigateTo({ // url: '/pages/exercises/exam/exam',
// url: '/pages/exercises/beforeExam/beforeExam',
// url: '/pages/exercises/examResults/examResults',
// url: '/pages/exercises/wrongQuestion/wrongQuestion',
// url: '/pages/exercises/theoryStudy/theoryStudy',
url: '/pages/vip/vipEntry/vipEntry' }) } function changeTabbar(val) { console.log(val) } const show = ref(false) function closePopup() { show.value = false } function openPopup() { show.value = true } let showCommt = ref(false) let contentStr = ref('') function showCommtClose() { showCommt.value = false contentStr.value = '' } // 提交反馈
async function submitCommt() { if(!contentStr.value) return uni.$u.toast('请输入内容') let obj = { content: contentStr.value, questionId: questionBank.value.id } const res = await questionCommentAdd(obj) if(res.errorcode==0) { uni.$u.toast('提交成功,感谢您的反馈') showCommt.value = false } } // 请求数据
const questionBank = ref({}) const questionBankList = ref([]) let examInfo = ref([]) let currentIndex = ref(0) async function startQuestionFn() { try{ uni.showLoading({ title: '正在加载...' }) let obj = { carType: usecarStore.carInfo.carType, stepType: usecarStore.carInfo.stepType, city: usecarStore.carInfo.city, examType: 1, } const {data: res} = await startExam(obj) uni.hideLoading() questionBank.value = res.questionBank[0] questionBankList.value = res.questionBank initOptionArr() examInfo.value = res }catch(e){ uni.hideLoading() } } startQuestionFn() watch(()=>questionBankList, (newVal, oldVal)=>{ yesNum.value = oldVal.value.filter(item=>item.yes).length noNum.value = oldVal.value.filter(item=>item.yes==0).length }, {deep: true}) function initOptionArr() { questionBank.value.optionArr = [] let abcd = [ 'a', 'b', 'c', 'd', 'e', 'f' ] abcd.forEach((k,i)=>{ let option = 'option'+k if(questionBank.value[option]) { let obj = { key: k.toLocaleUpperCase(), text: questionBank.value[option], index: i+1 } questionBank.value.optionArr.push(obj) // console.log(questionBank.value.optionArr)
} }) // 如果是判断题
if(questionBank.value.types==3) { questionBank.value.optionArr[0].key = 'true' questionBank.value.optionArr[1].key = 'false' } } // 下一题
async function nextQuestion(num) { // 如果是多选题,什么时候不直接请求下一题,是多选题 ,并且有答案,答错了,并且不是next
if(questionBank.value.types==2 && curOption.value.ans) { // 如果没有请求就请求一下
if(!curOption.value.answer) { curOption.value.answer = curOption.value.ans } // 如果答案不一样,并且是第一次请求
if(questionBank.value.answer != curOption.value.ans&&curOption.value.isNext != 'next') { curOption.value.isNext = 'next' questionBank.value.yes = 0 return false }else if(questionBank.value.answer == curOption.value.ans) { questionBank.value.yes = 1 } } curOption.value = {} currentIndex.value = currentIndex.value + num getQuestionFn() } // 请求下一题
async function getQuestionFn() { console.log(currentIndex.value) // let questionId = quesIdList.value[currentIndex.value-1]
// let obj = {
// "carType": usecarStore.carInfo.carType,
// "questionId": questionId,
// "sort": currentIndex.value,
// "stepType": usecarStore.carInfo.stepType,
// 'tempId': questionBank.value.questionDoTemp.id
// }
// const {data: res} = await getQuestionApi(obj)
questionBank.value = questionBankList.value[currentIndex.value] curOption.value = {} curOption.value.isNext = '' initOptionArr() } async function quesIdListClick(id, index) { curOption.value = {} currentIndex.value = index getQuestionFn() show.value = false } async function questionWrongColleFn() { let isAdd = questionBank.value.isCollect==1?'0':'1' const obj = { "carType": usecarStore.carInfo.carType, "isAdd": isAdd, "questionId": questionBank.value.id, "stepType": usecarStore.carInfo.stepType } const res = await questionWrongColle(obj) questionBank.value.isCollect = isAdd console.log(questionBank.value.isCollect) } // 选择答案
const curOption = ref({}) async function chooseOption(item) { console.log(item) if(curOption.value.answer) return if(questionBank.value.types != 2) { // 如果答案正确 下一题
if(questionBank.value.answer==item.key) { questionBank.value.yes = 1 currentIndex.value = currentIndex.value + 1 curOption.value = item setTimeout(()=>{ getQuestionFn() },500) }else { item.answer = item.key curOption.value = item questionBank.value.yes = 0 } }else if(questionBank.value.types == 2){ if(!curOption.value.ans) curOption.value.ans = '' if(curOption.value.ans.includes(item.key)) { curOption.value.ans = curOption.value.ans.replace(item.key, '') return } curOption.value.ans = (curOption.value.ans + item.key).split('').sort().join('') // console.log(curOption.value.ans)
} } // 点击交卷
let remaining = ref(0) let countDownRef = ref(null) function handApaper() { let arr = questionBankList.value.filter(item=>item.yes==undefined) // 不及格或者有没有做完的题
if(arr.length || passScore.value*1>yesNum.value) { remaining.value = arr.length showCommit.value = true if (countDownRef.value) { countDownRef.value.pause(); } }else { submitBtnFn() } } // 关闭交卷弹框
function closeCommitPopup() { showCommit.value = false if (countDownRef.value) { countDownRef.value.start(); } } // 交卷
async function submitBtnFn() { let wrongArr = questionBankList.value.filter(item=>item.yes!=1) let worngId = wrongArr.map(item=>item.id).join(',') let obj = { "answer": null, "carType": usecarStore.carInfo.carType, "examId": examInfo.value.id, "examType": 1, "grade": questionBankList.value.length - wrongArr.length, "isEnd": 1, "pass": 1, "sort": examInfo.value.sort, "stepType": usecarStore.carInfo.stepType, "userId": examInfo.value.userId, "wrongQuestionIds": worngId } const res = await startExamDo(obj) console.log(res) uni.$u.toast('已交卷') setTimeout(()=>{ uni.navigateBack() },1500) } function finishFn() { uni.$u.toast('考试时间已到,准备自动为您交卷') setTimeout(()=>{ submitBtnFn() },1500) } // 返回
function goBack() { uni.navigateBack() } </script>
<style lang="scss" scoped> .top_row { height: 88rpx; font-weight: 500; font-size: 24rpx; color: #333333; border-bottom: 2rpx solid #F4F4F4; padding: 0 30rpx; margin-bottom: 30rpx; .itemCount { margin-right: 60rpx; display: flex; align-items: center; .count { margin-left: 20rpx; } } .mr { margin-left: auto; } } image {display: block;width: 100%;height: 100%;} .bottomBar { position: fixed; bottom: 0; left: 0; width: 100%; height: 98rpx; background: #FFFFFF; border-top: 1rpx solid #F4F4F4; } .ul { display: flex; justify-content: space-between; height: 100%; align-items: center; .leftCotrl { flex: 1; } .submitBtn { width: 100rpx; height: 50rpx; background: linear-gradient(0deg, #4FACFE 0%, #00F2FE 100%); border-radius: 25rpx; font-size: 24rpx; line-height: 50rpx; text-align: center; margin-right: 32rpx; color: #fff; } .li { // width: 16.6%;
padding: 0 30rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; .icon { font-size: 30rpx; height: 30rpx; line-height: 30rpx; image { display: block; margin-top: 4rpx; width: 26rpx; height: 26rpx; } } .text { font-weight: 500; font-size: 24rpx; color: #999999; margin-top: 10rpx; } } } .content { padding: 120rpx 0; min-height: 100vh; .u-nav-slot { width: 306rpx; height: 54rpx; border-radius: 10rpx; border: 1px solid #333333; display: flex;
.btn { font-size: 24rpx; color: #333333; flex: 1; text-align: center; line-height: 54rpx;
&.active { background-color: #333333; color: #fff; } } } .btn_row { padding: 60rpx 0 30rpx 0; .btn { width: 44%; height: 76rpx; border-radius: 38rpx; border: 1rpx solid $themC; line-height: 76rpx; text-align: center; font-size: 28rpx; color: $themC; &.disable { opacity: 0.4; } &.bg { background: #3776FF; border-radius: 38rpx; color: #fff; } } } .con { .h1_row { margin-bottom: 50rpx; .tag { display: inline-block; // width: 66px;
height: 36rpx; line-height: 36rpx; padding: 4rpx 6rpx; background: #63C168; border-radius: 6rpx; margin-top: -2rpx; margin-right: 16rpx; font-size: 28rpx; color: #fff; &.blue { background: #3776FF; } &.red { background: orangered; } }
text.h1 { font-size: 36rpx; } }
.option { width: 100%; .optionItem { margin-bottom: 50rpx; align-items: center; .icon { width: 36rpx; height:36rpx; border-radius: 50%; border: 1rpx solid #999; }
.text { font-size: 32rpx; margin-left: 16rpx; } } }
.answerCss { height: 90rpx; background: #F4F4F4; padding: 30rpx; margin-top: 20rpx; justify-content: space-around; .ans { font-size: 30rpx; text { &.red { color: red; } } } }
.analysis { margin-top: 60rpx; .tit { font-weight: 700; font-size: 32rpx; position: relative; padding-left: 30rpx; &::after { content: ''; position: absolute; left: 0; top: 8rpx; width: 6rpx; height: 30rpx; background: linear-gradient(0deg, #43EA80 0%, #38F8D4 100%); border-radius: 3rpx; } }
.txt { margin-top: 39rpx; font-size: 32rpx; color: #333333; } } } }
.popupCon { width: 100%; height: calc(100vh - 200rpx); .h3 { height: 88rpx; border-bottom: 1px solid #F4F4F4; line-height: 88rpx; font-size: 30rpx; padding: 0rpx 0 0 30rpx; } .ulRow { height: 100rpx; padding: 30rpx 0; } .ul2 { display: flex; flex-wrap: wrap; padding: 30rpx 10rpx; height: calc(100vh - 388rpx); overflow-y: auto; align-content: flex-start; .li2 { width: 16.6%; margin-bottom: 20rpx; .num { width: 100rpx; height: 100rpx; border-radius: 50%; margin: auto; background: #F6F7FA; font-size: 32rpx; line-height: 100rpx; text-align: center; position: relative; text { width: 68rpx; height: 34rpx; background: #3776FF; border-radius: 17rpx; display: block; font-weight: 400; font-size: 24rpx; color: #FFFFFF; text-align: center; line-height: 34rpx; position: absolute; bottom: -14rpx; left: 16rpx; } &.yes { border: 1px solid #63C168; background: rgba(99,193,104,0.1); color: #63C168; } &.no { border: 1px solid #FF3333; background: rgba(255,51,51,0.1); color: #FF3333; } } } } }
.commitCon { width: calc(100vw - 100rpx); padding: 30rpx; .tit { font-weight: 500; font-size: 36rpx; color: #333333; text-align: center; }
.flex { .commitItem { flex: 1; text-align: center; padding: 50rpx 0 40rpx 0; .lab { font-size: 28rpx; color: #CCCCCC; margin-top: 10rpx; } .num { font-weight: bold; font-size: 36rpx; color: #333333; } } }
.imgAdd { width: 100%; img {
} }
.btn_commit_row { padding-top: 40rpx; .border.btn { border: 1rpx solid #CCCCCC; color: #CCCCCC; background: none; }
.btn { width: 46%; height: 77rpx; text-align: center; line-height: 77rpx; background: #3776FF; border-radius: 39rpx; font-size: 28rpx; color: #FFFFFF; } } } </style>
|