mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-mobile.git
synced 2025-12-06 17:36:45 +08:00
472 lines
13 KiB
Vue
472 lines
13 KiB
Vue
<template>
|
||
<!--考试页面,用户在此页面一个试题一个试题的回答-->
|
||
<view>
|
||
<u-toast ref="messager"></u-toast>
|
||
<page-title :showBack="false">课程考试</page-title>
|
||
<view>
|
||
<view style="display: flex;justify-content: space-between;padding: 20upx;">
|
||
<view style="padding-top: 10upx;color: #757575; ">第{{curIndex+1}}题 / 共{{total}}题</view>
|
||
<view style="color: #000000;">
|
||
<text style="font-size: 40upx;" :class="{'redText':timerValue<5}">{{timerValue}}</text> 分钟
|
||
</view>
|
||
</view>
|
||
<!--试题内容-->
|
||
<view class="qitem">
|
||
<view class="qitem-info">
|
||
<view> [{{getTypeName(curItem.type)}}]{{curItem.content}}</view>
|
||
<view class="qimg" v-if="curItem.images"><img class="qimg-fit" :src="imageBaseUrl+curItem.images"/></view>
|
||
</view>
|
||
<view v-for="(opt,optIdx) in curItem.options" :key="optIdx">
|
||
<view class="qitem-opts">
|
||
<view class="qitem-opt" :class="{check:opt.checked}" @click="chooseOption(opt)">
|
||
{{toLetter(optIdx+1)}}.{{opt.content}}
|
||
<u-icon v-if="opt.checked" name="checkbox-mark" color="#00aa00"></u-icon>
|
||
</view>
|
||
<view v-if="opt.images" class="qimg">
|
||
<img class="qimg-fit" :src="imageBaseUrl+opt.images"/>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view style="height: 50px;"></view>
|
||
<view v-if="!stop" class="bottom-btns">
|
||
<u-button type="success" text="提交" class="sub" :disabled="!thisTrue" @click="present"></u-button>
|
||
<u-button type="info" text="上一题" @click="prevSub" class="next" v-if="curIndex>0"></u-button>
|
||
<u-button type="primary" text="下一题" @click="nextSub" class="next" v-if="curIndex<(total-1)"></u-button>
|
||
</view>
|
||
<u-modal :show="stop"
|
||
@confirm="confirmStop"
|
||
@cancel="cancelStop"
|
||
ref="stopModal"
|
||
content="时间已到,是否提交答卷? 否:不提交答卷返回课程页面,是:提交答卷并返回课程页面"
|
||
confirmText="是"
|
||
:showCancelButton="true"
|
||
cancelText="否"
|
||
:asyncClose="true">
|
||
</u-modal>
|
||
<u-modal :show="scoreShow"
|
||
@confirm="confirmFinish"
|
||
title="您本次得分">
|
||
<view class="slot-content">
|
||
<view style="text-align: center;font-size: 60rpx;">{{lastScore}}</view>
|
||
</view>
|
||
</u-modal>
|
||
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import config from '@/config/index.js'
|
||
import apiCourseStudy from '@/api/modules/courseStudy.js'
|
||
import apiCourse from '@/api/modules/course.js';
|
||
import apiExamPaper from '@/api/modules/paper.js';
|
||
import {formatDate,getQuestionType,correctJudgment,numberToLetter} from '@/utils/tools.js';
|
||
export default {
|
||
data() {
|
||
return {
|
||
thisTrue: true,
|
||
studyId:'',
|
||
examId:'',
|
||
ctype:10,
|
||
startTime:null,
|
||
toLetter:numberToLetter,
|
||
getTypeName:getQuestionType,
|
||
imageBaseUrl:config.fileUrl,
|
||
info:{},
|
||
stop:false,
|
||
paper:[],
|
||
total:0,
|
||
curIndex:0,
|
||
curItem:{},
|
||
timer:null,
|
||
scoreShow:false,
|
||
lastScore:0,
|
||
timerValue:0,
|
||
noAnswers:[] //有未答完的试题
|
||
}
|
||
},
|
||
onLoad(options){
|
||
this.studyId=options.studyId;
|
||
this.examId=options.ccid;
|
||
this.ctype=options.ctype;
|
||
if(this.examId){
|
||
this.loadExamInfo();
|
||
}
|
||
// this.debouncedPresent = this.debounce(this.present, 500);
|
||
// this.confirmStop = this.debounce(this.submitTest,500)
|
||
},
|
||
methods: {
|
||
changeTimer(){
|
||
if(this.timerValue==0){
|
||
window.clearInterval(this.timer);
|
||
//系统自动提交
|
||
this.stop=true;
|
||
}else{
|
||
this.timerValue--;
|
||
}
|
||
|
||
},
|
||
loadExamInfo(){//加载考试信息
|
||
this.curIndex=0;
|
||
apiCourse.getExam(this.examId).then(res=>{
|
||
if(res.status==200){
|
||
this.info=res.result;
|
||
this.loadStudyItemId();
|
||
if(this.info.paperType==2){
|
||
// apiExamPaper.getPaperContent(this.info.paperId).then(rs=>{
|
||
apiExamPaper.getPcPaperContent(this.info.id).then(rs=>{
|
||
if(rs.status==200){
|
||
//console.log(rs.result)
|
||
let paperItems=JSON.parse(rs.result);
|
||
//console.log(this.examPaper.json,'this.examPaper.json');
|
||
let qitems=this.convertToItems(paperItems);
|
||
this.paper ={items:qitems};
|
||
this.total=qitems.length;
|
||
this.curItem=qitems[this.curIndex];
|
||
this.startTime=new Date();//记录开始时间
|
||
this.timerValue=this.info.testDuration;
|
||
this.timer=setInterval(this.changeTimer,60000);
|
||
}else{
|
||
this.$message.error('加载试卷内容失败,请与管理员联系,试卷是否已删除');
|
||
}
|
||
})
|
||
}else{
|
||
let paper= JSON.parse(this.info.paperContent);
|
||
paper.items.forEach(item=>{
|
||
//console.log(item);
|
||
if(item.type==101){
|
||
item.userAnswer='';
|
||
}else if(item.type==102){
|
||
item.userAnswer=[];
|
||
}else{
|
||
item.userAnswer=''
|
||
}
|
||
item.options.forEach(opt=>{
|
||
opt.checked=false;
|
||
})
|
||
})
|
||
this.total=paper.items.length;
|
||
this.paper =paper;
|
||
//console.log(this.paper);
|
||
this.curItem=paper.items[this.curIndex];
|
||
this.startTime=new Date();//记录开始时间
|
||
this.timerValue=res.result.testDuration;
|
||
this.timer=setInterval(this.changeTimer,60000);
|
||
|
||
}
|
||
}else if(res.status==404){
|
||
//没有找到考试信息
|
||
}else{
|
||
//this.$message.error(res.message);
|
||
}
|
||
})
|
||
},
|
||
//独立考试的试题转化为课内考试的试题
|
||
convertToItems(questions){
|
||
let qitems=[];
|
||
questions.forEach(item=>{
|
||
let q={
|
||
id:item.id,
|
||
type:item.type==1? 101:item.type==2? 102:103,
|
||
score:item.defaultScore,
|
||
checked:false,
|
||
userAnswer:'',
|
||
optShow:true,
|
||
content:item.title,
|
||
images:item.images,
|
||
options:[]
|
||
}
|
||
if(item.type==3){
|
||
q.options.push({
|
||
id:item.id+'1',
|
||
images:'',
|
||
content:"正确",
|
||
answer:item.answer=='true'? true:false,
|
||
checked:false
|
||
});
|
||
q.options.push({
|
||
id:item.id+'2',
|
||
images:'',
|
||
content:"错误",
|
||
answer:item.answer=='true'? false:true,
|
||
checked:false
|
||
})
|
||
}else{
|
||
item.optionList.forEach(opt=>{
|
||
q.options.push({
|
||
id:opt.id,
|
||
images:opt.images,
|
||
content:opt.content,
|
||
answer:opt.isAnswer,
|
||
checked:false
|
||
})
|
||
});
|
||
}
|
||
|
||
if(q.type==102){
|
||
q.userAnswer=[];
|
||
}
|
||
qitems.push(q);
|
||
});
|
||
console.log(qitems,'qitems')
|
||
return qitems;
|
||
},
|
||
loadStudyItemId(){
|
||
//获取studyItemId;
|
||
apiCourseStudy.getStudyContentItem(this.studyId,this.info.contentId).then(rs=>{
|
||
if(rs.status==200){
|
||
this.studyItemId=rs.result.id;
|
||
}
|
||
})
|
||
},
|
||
chooseOption(opt){
|
||
if(this.curItem.type==101 || this.curItem.type==103){
|
||
this.curItem.options.forEach(op=>{
|
||
op.checked=false;
|
||
})
|
||
opt.checked=true;
|
||
}else{
|
||
if(opt.checked){
|
||
opt.checked=false;
|
||
}else{
|
||
opt.checked=true;
|
||
}
|
||
}
|
||
},
|
||
confirmStop(){
|
||
this.submitTest()
|
||
},
|
||
cancelStop(){
|
||
//应该返回课程面页
|
||
this.confirmFinish();
|
||
},
|
||
prevSub(){
|
||
if(this.curIndex==0){
|
||
return;
|
||
}
|
||
this.curIndex--;
|
||
if(this.curIndex>-1){
|
||
this.curItem=this.paper.items[this.curIndex];
|
||
}
|
||
},
|
||
nextSub() {
|
||
if(this.curIndex>=(this.total-1)){
|
||
return;
|
||
}
|
||
this.curIndex++;
|
||
this.curItem=this.paper.items[this.curIndex];
|
||
|
||
},
|
||
countTest(){ //计算课程的分数
|
||
//console.log(this.paper.items);
|
||
let totalScore=0;
|
||
this.paper.items.forEach(item => {
|
||
item.score=parseInt(item.score);
|
||
totalScore+=item.score;//加到总分中
|
||
if(item.type != 102){
|
||
item.userAnswer='';
|
||
item.options.forEach(opt => {
|
||
if(opt.checked){
|
||
item.userAnswer=opt.id;
|
||
}
|
||
});
|
||
}else{
|
||
item.userAnswer=[];
|
||
item.options.forEach(opt => {
|
||
if(opt.checked){
|
||
item.userAnswer.push(opt.id);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
let scoreNum = 0;//用户得分
|
||
let noAnswers=[];//是否都已答
|
||
this.paper.items.forEach((item,idx) => {
|
||
if(item.type != 102){
|
||
if(item.userAnswer==''){
|
||
noAnswers.push(idx+1);
|
||
}
|
||
item.options.forEach(it => {
|
||
if(it.answer && item.userAnswer == it.id) {
|
||
scoreNum+=item.score
|
||
}
|
||
})
|
||
}else{
|
||
if(item.userAnswer.length==0){
|
||
noAnswers.push(idx+1);
|
||
}
|
||
let allRight = true;
|
||
item.options.forEach(it =>{
|
||
if(it.answer){ //正确答案
|
||
if(item.userAnswer.indexOf(it.id)==-1){
|
||
allRight=false;
|
||
}
|
||
}else{
|
||
if(item.userAnswer.indexOf(it.id)>-1){
|
||
allRight=false;
|
||
}
|
||
}
|
||
});
|
||
if(allRight){
|
||
scoreNum+=item.score;
|
||
}
|
||
}
|
||
})
|
||
|
||
this.noAnswers=noAnswers;
|
||
if(scoreNum === null)scoreNum=0;
|
||
this.lastScore=scoreNum;
|
||
//转化成百分制显示
|
||
if(this.info.percentScore){
|
||
this.lastScore=parseInt(scoreNum*100/totalScore);
|
||
}
|
||
return this.lastScore;
|
||
},
|
||
submitTest(){
|
||
let now=new Date();
|
||
let postData={
|
||
studyId:this.studyId,//
|
||
studyItemId:this.studyItemId,//此值没有的,需要单独的查询了来
|
||
courseId:this.info.courseId,
|
||
contentId:this.info.contentId,
|
||
testId:this.info.id,
|
||
testName:''+this.info.testName,//应该是课程的名称 + 内容的名称
|
||
testDuration:0,
|
||
arrange:this.info.arrange,
|
||
passLine:this.info.passLine,
|
||
randomMode:this.info.randomMode,
|
||
score:this.lastScore,//分数需要计算,在检查是否填写完整性时就可以计算出分数
|
||
paperJson:JSON.stringify(this.paper),//原来是对象,这里要也要对象
|
||
startTime:formatDate(this.startTime),//此时间需要格式化,格式化时间可以放在util中
|
||
//endTime:formatDate(now),
|
||
}
|
||
//计划考试的时长
|
||
var dateDiff = now.getTime() - this.startTime.getTime();//时间差的毫秒数
|
||
var minutes=Math.floor(dateDiff/(1000))//计算相差秒数,分钟记录的太大,经常为0
|
||
postData.testDuration=minutes;
|
||
this.thisTrue = false
|
||
apiCourseStudy.saveExam(postData).then(res=>{
|
||
this.thisTrue = true
|
||
if(res.status == 200) {
|
||
this.studyItemId=res.result.studyItemId;
|
||
this.scoreShow=true;
|
||
} else {
|
||
this.$refs.messager.show({message:res.message,type:'error'});
|
||
}
|
||
})
|
||
},
|
||
debounce(func, delay) {
|
||
let timerId;
|
||
return function (...args) {
|
||
if (timerId) clearTimeout(timerId);
|
||
timerId = setTimeout(() => {
|
||
func.apply(this, args);
|
||
timerId = null;
|
||
}, delay);
|
||
};
|
||
},
|
||
present(){
|
||
let $this=this;
|
||
let score=this.countTest();
|
||
//console.log(score)
|
||
//console.log(this.noAnswers)
|
||
if(this.noAnswers.length>0){
|
||
uni.showModal({
|
||
title: '友情提示',
|
||
content: '还有未答试题,您确定要提交吗?',
|
||
success(res) {
|
||
if (res.confirm) {
|
||
$this.submitTest()
|
||
}
|
||
}
|
||
});
|
||
}else{
|
||
this.submitTest()
|
||
}
|
||
},
|
||
confirmFinish(){
|
||
//这里应该是返回课程的页面
|
||
uni.redirectTo({
|
||
url:'/pages/study/courseStudy?id='+this.info.courseId + '&contentId='+this.examId
|
||
})
|
||
// if(this.ctype==10){
|
||
// uni.redirectTo({
|
||
// url:'/pages/resource/microDetail?id='+this.info.courseId + '&exam=1'
|
||
// })
|
||
// }else if(this.ctype==20){
|
||
// uni.redirectTo({
|
||
// url:'/pages/study/onlineCourse?id='+this.info.courseId
|
||
// })
|
||
// }
|
||
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.redText{
|
||
color:#ff0000;
|
||
}
|
||
.footer {
|
||
position: fixed;
|
||
bottom: 0px;
|
||
width: 100%;
|
||
height: 80upx;
|
||
line-height: 80upx;
|
||
border-top: 1px solid #d9d9d9;
|
||
background-color: #FFFFFF;
|
||
}
|
||
|
||
.column{
|
||
color: #838383;
|
||
font-size: 40upx;
|
||
padding: 10px 20px;
|
||
}
|
||
|
||
.qitem {
|
||
padding: 10px 20px;
|
||
|
||
.qitem-info {
|
||
font-size: 1.2em;
|
||
padding: 10px 0px;
|
||
}
|
||
|
||
.qitem-opts {
|
||
padding: 5px 0px;
|
||
|
||
.qitem-opt {
|
||
display: flex;
|
||
margin-bottom: 10px;
|
||
padding: 20px 15px;
|
||
background-color: #FFFFFF;
|
||
border-radius: 6px;
|
||
}
|
||
.check{
|
||
color:#00aa00;
|
||
}
|
||
}
|
||
}
|
||
.bottom-btns{
|
||
padding: 10px;
|
||
position: fixed;
|
||
width: 100%;
|
||
bottom: 0px;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
}
|
||
.qimg{
|
||
//padding-left: 30px;
|
||
width:100%;
|
||
text-align: left;
|
||
.qimg-fit{
|
||
width:100%;
|
||
|
||
object-fit:scale-down
|
||
}
|
||
}
|
||
</style>
|