You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

814 lines
21 KiB

<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 * 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
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,
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
// 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;
.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>