<template> <view class="content"> <view class="flex ai-c jc-c"> <view class="flex type_box jc-sb ai-c"> <view class="type_item" v-for="(item,index) of tabsList" :key="index" :class="tCurrent==item.value?'checked':'unchecked'" @tap="sectionChange(item.value)">{{item.label}}</view> </view> </view> <swiper class="swiper mt20" :current="swiperIndex" :duration="duration" :autoplay="false" :disable-programmatic-animation="true" @change="onChange" @animationfinish="onAnimationfinish" @touchend="touchEnd" > <swiper-item v-for="(quesItem,quesIndex) in swiperList" :key="quesIndex"> <scroll-view scroll-y="true" class="swiper-scroll"> <view> <view class="m14lr"> <text class="tag_box">{{quesItem.questionTypeDesc}}</text> <text class="fs18">{{quesItem.questionDesc}}</text> </view> <view class="flex m14lr ai-c mt20" v-for="(item,index) in quesItem.optionList" :key="item.op" @tap="answerQues(item.op,index)"> <template v-if="quesItem.clickAnswer&&item.op===quesItem.rightOp"> <u-icon class="mr15" name="checkmark-circle-fill" color="#05C341" size="30"></u-icon> </template> <template v-else-if="quesItem.clickAnswer===item.op&&item.op!==quesItem.rightAnswer"> <u-icon class="mr15" name="close-circle-fill" color="red" size="30"></u-icon> </template> <template v-else-if="!item.chooseOption"> <view class="option_item">{{item.op}}</view> </template> <text class="fs18">{{item.opDesc}}</text> </view> <view class="m14lr mt30" v-if="quesItem.clickAnswer&&quesItem.clickAnswer!==quesItem.rightOp || tCurrent===1"> <view class="answer_box"> <text class="fs18 fw600 cor-000">答案:{{quesItem.rightOp}}</text> <view class="fs18 cor-000" style="text-indent:2em;"> 这里是相关解释文字,这里是相关解释文字相关解释文字</view> </view> </view> </view> </scroll-view> </swiper-item> </swiper> <view class="wp100 flex jc-sb ai-c p14 bc-fff" style="position: fixed;bottom: 0;left: 0;"> <view style="width: 220rpx;"> <button v-if="type==='practice'" class="btn">四步学科一</button> <view v-else class="btn" style="text-align: center;" @tap="submitPaper"> <u-count-down ref="countDown_1" :time="1 * 60 * 60 * 1000" format="HH:mm:ss"></u-count-down> <text>交卷</text> </view> </view> <view class="text-center flex jc-c ai-c" style="flex-direction: column;" @tap="toCollect"> <u-icon name="star-fill" v-if="questionList[topicIndex].isCollect" color="rgb(249,236,141)" size="24"></u-icon> <u-icon name="star" v-else size="24"></u-icon> <text class="cor-666">{{questionList[topicIndex].isCollect?'已收藏':'收藏'}}</text> </view> <view class="text-center"> <view style="color: #00B74F;">{{rightList.length}}</view> <text class="cor-666">答对</text> </view> <view class="text-center"> <view style="color: #FF6E02;">{{wrongList.length}}</view> <text class="cor-666">答错</text> </view> <view class="text-center" @tap="popupShow=!popupShow"> <view><text class="cor-333">{{topicIndex+1}}</text><text style="color:#999;">/{{questionList.length}}</text></view> <text class="cor-666">题板</text> </view> </view> <u-modal :show="tipShow"> <view class="relative wp100"> <view class="text-center"> <text>{{title}}</text> <view class="mt20">{{content}}</view> </view> <view style="position: absolute;right:0px;top:0" @tap="cancel"> <u-icon name="close-circle-fill" color="rgb(204,204,204)" size="24"></u-icon> </view> </view> <template #confirmButton> <view class="p10" > <u-button :customStyle="{width:'100%',height:'68rpx',borderRadius:'34rpx',color:'#fff',backgroundColor:'#05C341'}" @click="toResult">查看练题结果</u-button> </view> </template> </u-modal> <u-modal :show="isSubmit"> <view class="wp100"> <view class="text-center"> <text>确认交卷</text> <view class="mt20 flex ai-c jc-sb"> <view class="text-center"> <text style="color:#FF6E02">99</text> <view class="cor-333">未答题数</view> </view> <view class="text-center"> <u-count-down ref="countDown_3" class="balckColor" :time="1 * 60 * 60 * 1000" format="HH:mm:ss"></u-count-down> <view>剩余时间</view> </view> <view class="text-center"> <text style="color:#333">9</text> <view class="cor-333">考试得分</view> </view> </view> </view> </view> <template #confirmButton> <view class="p10" > <u-button :customStyle="{width:'45%',marginRight:'10px',height:'68rpx',lineHeight:'68rpx',borderRadius:'34rpx',color:'#666',border:'1px solid #666',display:'inline-block'}" @click="continueExam">继续考试</u-button> <u-button :customStyle="{width:'45%',marginLeft:'10px',height:'68rpx',lineHeight:'68rpx',borderRadius:'34rpx',color:'#fff',backgroundColor:'#05C341',display:'inline-block'}" @click="toSubmit">现在交卷</u-button> </view> </template> </u-modal> <u-popup :show="popupShow" mode="bottom" :closeOnClickOverlay="true" @close="popupShow=false"> <view> <view class="wp100 flex jc-sb p14 bc-fff"> <view style="width: 220rpx;"> <button v-if="type==='practice'" class="btn">四步学科一</button> <view v-else class="btn" style="text-align: center;" @tap="submitPaper"> <u-count-down ref="countDown_2" :time="1 * 60 * 60 * 1000" format="HH:mm:ss"></u-count-down> <text>交卷</text> </view> </view> <view class="text-center flex jc-c ai-c" style="flex-direction: column;" @tap="toCollect"> <u-icon name="star-fill" v-if="questionList[topicIndex].isCollect" color="rgb(249,236,141)" size="24"></u-icon> <u-icon name="star" v-else size="24"></u-icon> <text class="cor-666">{{questionList[topicIndex].isCollect?'已收藏':'收藏'}}</text> </view> <view class="text-center"> <view style="color: #00B74F;">{{rightList.length}}</view> <text class="cor-666">答对</text> </view> <view class="text-center"> <view style="color: #FF6E02;">{{wrongList.length}}</view> <text class="cor-666">答错</text> </view> <view class="text-center" @tap="popupShow=!popupShow"> <view><text class="cor-333">{{topicIndex+1}}</text><text style="color:#999;">/{{questionList.length}}</text></view> <text class="cor-666">题板</text> </view> </view> <view class="flex ai-c jc-sb p14" style="flex-wrap: wrap;max-height: 400px;overflow-y: scroll;"> <view v-for="(item,index) of questionList" :key="index" style="width:20%;" class="flex ai-c jc-c" @tap="chooseQueston(index)"> <view class="tCircle mb10" :class="{ 'active':index == topicIndex, 'success':rightList.includes(item.questionId), 'error':wrongList.includes(item.questionId) }"> {{index+1}} </view> </view> </view> </view> </u-popup> </view> </template> <script> export default { props:{ tabsList:{ type:Array }, type:{ type:String, default:'practice' }, isSubmit:{ type:Boolean, default:false } }, data() { return { popupShow:false, content:'太棒啦,已答完最后一题~', tipShow:false, title:'提示', tCurrent:0, index:0, qIndex:0, rightList:[], wrongList:[], questionList: [],//数据源 swiperList: [], // 轮播图数据列表 swiperIndex: 0, // 轮播图当前位置 isChange: false, // 是否切换 topicIndex: 0, // 题目位置 duration: 200, // 动画过渡时长 } }, onLoad() { this.getQuestionList() this.renderSwiper(0) }, methods: { submitPaper(){ this.$refs.countDown_1.pause(); this.$refs.countDown_2.pause(); this.$refs.countDown_3.pause(); this.$emit('update:isSubmit',true) }, continueExam(){ this.$refs.countDown_1.start(); this.$refs.countDown_2.start(); this.$refs.countDown_3.start(); this.$emit('update:isSubmit',false) }, //切换题目 chooseQueston(index){ this.popupShow=false this.pickerTopic(index) }, //交卷 toSubmit(){ uni.navigateTo({ url:"/pages/questionBank/examResult" }) }, //查看考试结果 toResult(){ uni.navigateTo({ url:"/pages/questionBank/practiceResult" }) }, toCollect(){ if(this.questionList[this.topicIndex].isCollect){ this.questionList[this.topicIndex].isCollect=false uni.showToast({ title:"取消收藏", icon:'none' }) }else{ this.questionList[this.topicIndex].isCollect=true uni.showToast({ title:"已收藏", icon:'none' }) } }, cancel(){ this.tipShow=false }, touchEnd(e){ if(this.topicIndex<this.questionList.length-1){ this.index=this.topicIndex }else{ this.index++ } }, // 渲染 swiper renderSwiper(index) { let list = []; let current = 1; if (this.questionList[index - 1]) { list.push(this.questionList[index - 1]); } else { current = 0; } list.push(this.questionList[index]) if (this.questionList[index + 1]) { list.push(this.questionList[index + 1]); } this.duration = 0; setTimeout(() => { this.swiperList = list; this.swiperIndex = current; setTimeout(() => { this.duration = 200; }, 100) }, 50) }, // 轮播图切换 onChange(e) { // 非触摸事件不做轮播图状态更新 if (e.detail.source != "touch") return; // 标识已切换 this.isChange = true; // 轮播图当前位置大于原来时则表示为下一题 if (e.detail.current > this.swiperIndex) { this.topicIndex++; } else { // 轮播图当前位置小于原来时则表示为上一题 this.topicIndex--; } // 更新轮播图位置数值,为更新时让 Vue 能监听到数据有改变 this.swiperIndex = e.detail.current; }, // 轮播图动画结束 onAnimationfinish(e) { if(this.index>=this.questionList.length){ this.tipShow=true }else{ this.tipShow=false } if (!this.isChange) return; this.isChange = false; setTimeout(() => { this.renderSwiper(this.topicIndex); }, 10); }, // 选择题目 pickerTopic(index) { this.topicIndex = index; this.renderSwiper(index); }, //答题 answerQues(op, index) { if (!this.questionList[this.topicIndex].clickAnswer) { this.questionList[this.topicIndex].optionList[index].chooseOption = op this.questionList[this.topicIndex].clickAnswer = op } if(this.tCurrent!==1){ if(this.questionList[this.topicIndex].clickAnswer===this.questionList[this.topicIndex].rightOp){ if(!this.rightList.includes(this.questionList[this.topicIndex].questionId)){ this.rightList.push(this.questionList[this.topicIndex].questionId) } console.log(this.rightList); if(this.wrongList.includes(this.questionList[this.topicIndex].questionId)){ const wIndex=this.wrongList.findIndex(this.questionList[this.topicIndex].questionId) this.wrongList.splice(wIndex,1) } if(this.topicIndex<this.questionList.length-1){ this.topicIndex ++; this.qIndex=this.topicIndex setTimeout(()=>{ this.renderSwiper(this.topicIndex); },1000) } if(this.topicIndex<=this.questionList.length-1){ this.qIndex=this.topicIndex }else{ this.qIndex++ } if(this.qIndex>=this.questionList.length-1){ setTimeout(()=>{ this.tipShow=true },1000) }else{ this.tipShow=false } }else{ if(!this.wrongList.includes(this.questionList[this.topicIndex].questionId)){ this.wrongList.push(this.questionList[this.topicIndex].questionId) } } } }, sectionChange(index) { this.tCurrent = index this.getQuestionList() this.renderSwiper(0) }, getQuestionList() { this.questionList = [{ questionId: 0, questionTypeDesc: '单选', questionDesc: '第一题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'C', }, { questionId: 1, questionTypeDesc: '单选', questionDesc: '第二题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'B', }, { questionId: 2, questionTypeDesc: '单选', questionDesc: '第三题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 3, questionTypeDesc: '单选', questionDesc: '第四题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 4, questionTypeDesc: '单选', questionDesc: '第5题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 5, questionTypeDesc: '单选', questionDesc: '第6题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 6, questionTypeDesc: '单选', questionDesc: '第7题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 7, questionTypeDesc: '单选', questionDesc: '第8题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 8, questionTypeDesc: '单选', questionDesc: '第9题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'C', }, { questionId: 9, questionTypeDesc: '单选', questionDesc: '第10题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'B', }, { questionId: 10, questionTypeDesc: '单选', questionDesc: '第11题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 11, questionTypeDesc: '单选', questionDesc: '第12题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 12, questionTypeDesc: '单选', questionDesc: '第13题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 13, questionTypeDesc: '单选', questionDesc: '第14题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 14, questionTypeDesc: '单选', questionDesc: '第15题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', }, { questionId: 15, questionTypeDesc: '单选', questionDesc: '第16题,在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?', optionList: [{ op: 'A', opDesc: '注意新手标志' }, { op: 'B', opDesc: '注意新手标志' }, { op: 'C', opDesc: '注意新手标志' }, { op: 'D', opDesc: '注意新手标志' }], rightOp: 'A', } ] if(this.tCurrent===1){ this.questionList=this.questionList.map(item=>{ return{ ...item, clickAnswer:item.rightOp } }) } } } } </script> <style scoped lang="scss"> .type_box { width: 350rpx; height: 72rpx; background-color: #FFFFFF; border-radius: 8rpx; } .type_item { text-align: center; line-height: 64rpx; width: 160rpx; height: 64rpx; border-radius: 8rpx; } .checked { color: #fff; background-color: #05C341; } .unchecked { color: #666; } .tag_box { display: inline-block; width: 78rpx; height: 42rpx; background: #05C341; border-radius: 8rpx; text-align: center; line-height: 42rpx; color: #fff; font-size: 12px; margin-right: 5px; } .option_item { width: 60rpx; height: 60rpx; border: 1px solid #666; border-radius: 50%; text-align: center; line-height: 60rpx; margin-right: 30rpx; } .swiper { height: 100vh; } .answer_box { width: 100%; padding: 30rpx; background: #EEEEEE; border-radius: 20rpx; } .btn{ width: 220rpx; height: 80rpx; border-radius: 40rpx; color:#fff; background: linear-gradient(90deg, #11DF20 0%, #00B74F 100%); font-size: 28rpx; line-height: 80rpx; } .tCircle{ width: 80rpx; height: 80rpx; background-color: #fff; border: #ddd solid 1px; border-radius: 50%; line-height: 80rpx; text-align: center; &.active { border: #05C341 solid 1px; } &.success { background-color:rgb(236,247,241); color: #05C341; border: none; &.active { border: #05C341 solid 1px; } } &.error { background-color: #ffeceb; color: #f84d27; border: none; &.active { border: #f84d27 solid 1px; } } } .content{ padding-top: calc(var(--window-top) + 10px); } </style>