2022年5月29日 从svn移到git

This commit is contained in:
daihh
2022-05-29 18:59:24 +08:00
parent 9580ff8c9b
commit faa7afb65f
897 changed files with 171836 additions and 0 deletions

747
pages/exam/exam.vue Normal file
View File

@@ -0,0 +1,747 @@
<template>
<!--考试页面用户在此页面一个试题一个试题的回答-->
<view>
<u-toast ref="messager"></u-toast>
<view style="text-align: center;padding: 10px;"><text class="title-name">{{testPaper.testName}}</text></view>
<view class="epage" v-if="testStatus ==1">
<view class="">
<u-cell-group>
<u-cell size="large" title="答题时间" :value="testPaper.testDuration+ '分钟'"></u-cell>
<u-cell size="large" title="答题次数" :value="testPaper.times + '次'"></u-cell>
<u-cell size="large" title="及格线" :value="testPaper.passLine"></u-cell>
<u-cell v-if="testPaper.entranceTime" size="large" title="入场时间" :value="testPaper.entranceTime">
</u-cell>
</u-cell-group>
<view class="" style="padding: 20upx;" v-if="testPaper.testFront">
{{testPaper.testFront}}
</view>
<view class="sta-btn" v-if="canExam">
<view v-if="examStatus==0" style="text-align: center;color:#6d6d6d; ">考试还未开始</view>
<view v-if="examStatus==1">
<view v-if="tipText!=''" style="text-align: center;color:red">
<text>{{tipText}}</text>
</view>
<view v-else>
<u-button type="primary" :disabled="startButton" v-if="testStatus == 1" @click="startTest()">{{btnText}}</u-button>
</view>
</view>
<view v-if="examStatus==2" style="text-align: center;color:#6d6d6d; ">考试已结束</view>
</view>
<view class="" style="padding: 20upx;" v-if="canExam">
<view class="" style="margin-bottom: 20upx;">
考试记录
</view>
<view class="history">
<view v-for="(item, index) in tableData" :key="index" class="history-item">
<view class="history-row">
<view>{{item.lastTime}}</view>
<view>
<text v-if="item.status==1" style="color: #ff0000;">未提交</text>
<text v-if="item.status==8">中断</text>
<text v-if="item.status==9" style="color: #00aa00; ">完成</text>
</view>
</view>
<view class="history-row">
<view>得分{{toScoreTow(item.score)}}</view>
<view>
<text v-if="item.status<9 && examStatus==1" @click="reStartTest(item)">继续考试</text>
<text v-else @click="toShowAnswer(item)">查看试卷</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view v-if="testStatus ==2">
<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':remainingTime<5}">{{formatSeconds(remainingTime)}}</text>
</view>
</view>
<!--试题内容-->
<view class="qitem">
<view class="qitem-info">[{{getQuestionType(curItem.type)}}]{{curItem.title}}</view>
<view v-if="curItem.type == 3">
<view class="qitem-opts">
<view class="qitem-opt" :class="{check:curItem.userAnswer == true}"
@click="chooseOption(curItem,true)">
{{toLetter(1)}}.正确
<u-icon v-if="curItem.userAnswer == true" name="checkbox-mark" color="#00aa00"></u-icon>
</view>
<view class="qitem-opt" :class="{check:String(curItem.userAnswer) != '' && !curItem.userAnswer}"
@click="chooseOption(curItem,false)">
{{toLetter(2)}}.错误
<u-icon v-if="String(curItem.userAnswer) != '' && !curItem.userAnswer" name="checkbox-mark" color="#00aa00"></u-icon>
</view>
</view>
</view>
<view v-else v-for="(opt,optIdx) in curItem.optionList" :key="optIdx">
<view class="qitem-opts" v-if="curItem.type == 1">
<view class="qitem-opt" :class="{check:opt.id==curItem.userAnswer}" @click="chooseOption(opt)">
{{toLetter(optIdx+1)}}.{{opt.content}}
<u-icon v-if="opt.id==curItem.userAnswer" name="checkbox-mark" color="#00aa00"></u-icon>
</view>
</view>
<view class="qitem-opts" v-if="curItem.type == 2">
<view class="qitem-opt" :class="{check:curItem.userAnswer.indexOf(opt.id) > -1}" @click="chooseOption(opt)">
{{toLetter(optIdx+1)}}.{{opt.content}}
<u-icon v-if="curItem.userAnswer.indexOf(opt.id) > -1" name="checkbox-mark" color="#00aa00"></u-icon>
</view>
</view>
</view>
</view>
<view style="height: 50px;"></view>
<view class="bottom-btns">
<u-button class="next" v-if="curIndex==(total-1)" type="success" text="提交" @click="manualSubmit"></u-button>
<u-button type="primary" text="下一题" @click="nextSub" class="next" v-if="curIndex<(total-1)"></u-button>
<u-button type="info" text="上一题" @click="prevSub" class="next" v-if="curIndex>0"></u-button>
</view>
</view>
<view class="" v-if="testStatus ==3">
<view class="pager-title">
</view>
<view class="score-box">
考试已结束得分 {{toScoreTow(score)}}
</view>
<view class="sta-btn">
<u-button style="border-radius: 36upx;" text=" 关 闭 " @click="closeTest()" type="primary"></u-button>
</view>
</view>
<u-modal :show="stop" @confirm="confirmStop" @cancel="cancelStop" ref="stopModal"
content="时间已到,系统自动提交" confirmText="是" :showCancelButton="false"
:asyncClose="true">
</u-modal>
<u-modal :show="scoreShow" @confirm="confirmFinish" title="您本次得分" :content="''+lastScore">
</u-modal>
</view>
</template>
<script>
import apiTestPaper from '@/api/modules/testPaper.js'
import { correctJudgment, numberToLetter, examType,toScoreTow } from '@/utils/tools.js';
import { formatDate, formatSeconds } from '@/utils/index.js';
import { mapGetters } from 'vuex';
export default {
data() {
return {
toScoreTow,
startButton: false,
examId: '', //考试的id
taskId: '', //考试任务的id
lastId: '', //最后一次提交的答卷
canExam: false, //能否参加考试
tipText: '', //提示信息
examStatus: 0, //0表无1表考试中2表已结束
btnText: '开始考试',
handleSaveTest: null, //对应timout定时任务的指向
getTypeName: examType,
userInfo: {},
formatDate,
testPaper: {
id: '',
testName: '', //考试名称
testDuration: null, //考试时长
showAnalysis: false, //显示解析
showAnswer: false, //显示答案
times: null, //尝试次数 默认是0无限制
arrange: null, //试题排列 1试题乱序2选项乱序3全部乱序
scoringType: null, //评分方式 1最高一次2最后一次
passLine: null, //及格线
randomMode: false, //随机模式
randomCount: null, //随机数量
testType: null, //考试的类型* 1测试模式 2练习模式
publishTime: '', //发布时间
testRemark: '', //考试描述
testFront: '', //考前描述
testUp: '', //考后描述
entranceTime: '', //入场时间
paperId: '', //试卷的ID
paperContent: '', //试卷内容
},
aloneExamAnswerId: null, // 考试提交答案ID
testStatus: 1, // 1考前 2考中 3考后
reckonTimeer: null, // 计时器
score: 0,
studyId: '',
remainingTime: 0,
ctype: 10,
startTime: null,
toLetter: numberToLetter,
info: {},
stop: false,
paper: [],
total: 0,
curIndex: 0,
curItem: {},
timer: null,
scoreShow: false,
lastScore: 0,
timerValue: 0,
noAnswers: [], //有未答完的试题
tableData: [],
}
},
onLoad(options) {
this.examId = options.id;
this.$store.dispatch('GetUserInfo').then(rs => {
this.userInfo = rs;
});
if (this.examId) {
this.loadData();
}
},
methods: {
loadData() { //加载考试信息
apiTestPaper.getTestInfo(this.examId).then(res => {
if (res.status == 200) {
this.canExam = res.result.hasTask;
this.examStatus = res.result.examStatus;
this.testPaper = res.result.exam;
this.taskId = res.result.taskId;
if (res.result.hasLast && res.result.lastStatus < 9) {
this.lastId = res.result.lastId;
}
if(!this.testPaper.published){
this.tipText="此考试已取消,请与管理员联系";
}
//转换testDuration为秒,此转化在点击开始考试时才应该执行
this.remainingTime = this.testPaper.testDuration * 60;
//加载考试记录
if (res.result.hasTask) {
if (res.result.hasLast) {
this.btnText = '重新考试';
this.testAnswers();
}
}
} else {
// this.$message.error(res.message);
}
});
},
testAnswers() {
apiTestPaper.myTestAnswers(this.examId).then(res => {
if (res.status == 200) {
this.tableData = res.result;
let len = res.result.length;
let times = this.testPaper.times ? this.testPaper.times : 0;
if (times != 0 && len >= times) {
//考试次数限制
this.tipText = '已达到允许考试次数上限';
}
} else {
this.$refs.messager.show({message:'加载考试记录失败',type:'error'});
}
})
},
toShowAnswer(item){
uni.navigateTo({
url:`/pages/exam/answer?id=${item.id}&showAnalysis=${this.testPaper.showAnalysis}&showAnswer=${this.testPaper.showAnswer}`
})
},
formatSeconds(time) {
return formatSeconds(time);
},
chooseOption(opt, is) {
if (this.curItem.type == 1) {
this.curItem.userAnswer=opt.id;
} else if (this.curItem.type == 2) {
if (this.curItem.userAnswer.indexOf(opt.id) > -1) {
//需要移除
this.curItem.userAnswer.forEach((item, index) => {
if (item === opt.id) {
this.curItem.userAnswer.splice(index, 1)
}
})
} else {
this.curItem.userAnswer.push(opt.id);
}
} else if (this.curItem.type == 3) {
this.curItem.userAnswer=is;
//opt.checked = is;
//this.curItem.userAnswer = String(is);
}
},
startTest() {
this.curTestAnswer = {};
this.curIndex=0;
// 先禁用,防止重复提交
if (this.testPaper.entranceTime && this.testPaper.entranceTime !== '') {
let time = new Date();
let entranceTime = new Date(this.testPaper.entranceTime);
if (time < entranceTime) {
uni.showLoading({
title:"考试还未开始,请耐心等候!",
duration:2000
});
return;
}
}
this.startButton = true;
this.remainingTime = this.testPaper.testDuration * 60;
//提取考试试卷内容
let startParams = {
exam: this.examId,
task: this.taskId,
lastId: this.lastId
}
let $this = this;
apiTestPaper.getTestStart(startParams).then(rs => {
if (rs.status == 200) {
//处理试卷内容
let paperQuestion = JSON.parse(rs.result.paper);
//以下是去掉分页符
let tempPaper = [];
paperQuestion.forEach(qitem=>{
qitem.userAnswer='';
if(qitem.type<900){
if(qitem.type==2){
qitem.userAnswer=[];
}
tempPaper.push(qitem);
}
});
this.paper=tempPaper;
this.total=this.paper.length;//计算试题总数
this.arrangeQuestion();
this.curItem = this.paper[this.curIndex];
//console.log(this.paper,'this.paper');
//进入考试阶段
this.testStatus = 2;
this.startReckon();
//60秒后执行保存处理,这里和pc端不一致不做延迟直接保存考试信息
//window.setTimeout(function() {
//$this.saveUserTest();
//}, 10000);
} else {
this.startButton = false;
uni.showLoading({
title:"加载试卷内容失败",
duration:2000
});
}
});
},
reStartTest(item){
//直接提取
this.curTestAnswer = {};
this.curIndex=0;
apiTestPaper.getAnswerDetail(item.id).then(res => {
if (res.status === 200) {
this.aloneExamAnswerId=res.result.id;
this.curTestAnswer=res.result;
let answerJson = JSON.parse(res.result.answerJson);
let paperJson = JSON.parse(res.result.paperJson);
if(paperJson.length==0){
this.$refs.messager.show({message:'无试卷内容',type:'error'});
return;
}
//console.log(answerJson,'answerJson');
//console.log(paperJson,'paperJson');
let paperQuestions=[];//不包含分页符的试题数组
//设置答案
paperJson.forEach((qitem , index) => {
if(qitem.type<900){
let avalue=answerJson[qitem.id];
//console.log(avalue,'avalue')
if(qitem.type==3){
qitem.answer=qitem.answer=='true'? true:false;
}
if(avalue){
if(qitem.type==1){ //单选
qitem.userAnswer=avalue;
//console.log(qitem,avalue,'单选qitem')
}else if(qitem.type==2){ //多选
qitem.userAnswer=avalue.split(',');
}else if(qitem.type==3){ //判断
qitem.userAnswer=avalue=='true'? true:false;
}
}
paperQuestions.push(qitem);
}
});
//设置选中状态及对于错
// paperQuestions.forEach((item, index) => {
// });
this.total=paperQuestions.length;
this.paper = paperQuestions;
this.curItem = this.paper[this.curIndex];
//console.log(this.curItem,'this.curItem');
if(res.result.useSecond){
this.remainingTime=this.testPaper.testDuration*60-res.result.useSecond;
}
this.testStatus = 2;
this.startReckon();
} else {
this.$refs.messager.show({message:res.message,type:'error'});
}
})
},
saveUserTest() { //保存用户的考试在点击开始考试1分钟后执行
if (this.handleSaveTest != null) {
window.clearTimeout(this.handleSaveTest);
}
if (this.testStatus != 2) {
//只有在第二阶段才会保存
return;
}
let that = this;
let data = {};
data.testId = this.testPaper.id;
data.testName = this.testPaper.testName;
data.testDuration = this.testPaper.testDuration;
data.useSecond = 10; //用时秒
data.arrange = this.testPaper.arrange;
data.passLine = this.testPaper.passLine;
data.ucode = this.userInfo.userNo;
data.paperJson = JSON.stringify(this.paper);
data.answerJson = this.getAnswer();
//计算总分
let total = 0;
this.paper.forEach(item => {
total += item.defaultScore;
});
data.totalScore = total;
//计算出当前的成绩
data.realScore = this.countScore();
apiTestPaper.start(data).then((res) => {
if (res.status == 200) {
that.aloneExamAnswerId = res.result.id;
that.curTestAnswer = res.result; //
//that.startUpdateAnswer();
} else {
uni.showLoading({
title:res.message,
duration:2000
});
}
})
},
countScore() {
let total = 0;
this.paper.forEach(item => {
if (item.type == 3) {
//console.log(item,item.answer,item.userAnswer,'item');
if (item.answer && item.userAnswer) {
total += item.defaultScore;
}else if(!item.answer && !item.userAnswer){
total+=item.defaultScore;
}
}
if (item.type == 1) {
item.optionList.forEach(opt => {
if (opt.id == item.userAnswer && opt.isAnswer) {
total += item.defaultScore;
}
})
}
if (item.type == 2) {
let tempAnswer = [];
item.optionList.forEach(opt => {
if (opt.isAnswer) {
tempAnswer.push(opt.id);
}
})
tempAnswer.sort(function(n1, n2) {
return n1 > n2 ? -1 : 1;
});
if (item.userAnswer) {
item.userAnswer.sort(function(n1, n2) {
return n1 > n2 ? -1 : 1;
});
}
let str1 = item.userAnswer.join();
let str2 = tempAnswer.join();
//console.log(str1,str2,'aaa');
if (str1 == str2) {
total += item.defaultScore;
}
}
});
return total;
},
// 提交考卷
submit: function() {
if(!this.aloneExamAnswerId){
this.$refs.messager.show({message:'请先答题再提交',type:'error'});
return;
}
let that = this;
that.submitButton = true;
let data = {};
data.id = this.aloneExamAnswerId;
data.testId = this.testPaper.id;
data.testName = this.testPaper.testName;
data.testDuration = this.testPaper.testDuration;
data.arrange = this.testPaper.arrange;
data.passLine = this.testPaper.passLine;
data.scoreType=this.testPaper.scoringType;
data.totalScore=this.curTestAnswer.totalScore;
data.answerJson = this.getAnswer();
data.realScore=this.countScore();
data.useSecond=this.testPaper.testDuration*60-this.remainingTime;
//计算百分制显示
data.score=data.realScore*100/data.totalScore;
apiTestPaper.submit(data).then((res) => {
if (res.status == 200) {
that.testStatus = 3;
this.score = data.score;
this.submitButton = false;
} else {
this.submitButton = false;
this.$refs.messager.show({message:res.message,type:'error'});
}
})
},
closeTest(){
uni.redirectTo({
url:'/pages/exam/exam?id='+this.examId
})
},
//自动提交答案
updateAnswer: function() {
if(!this.aloneExamAnswerId){
this.saveUserTest();
return;
}
let data = {};
data.id = this.aloneExamAnswerId;
data.json = this.getAnswer();
data.second=this.testPaper.testDuration*60-this.remainingTime;
data.score=this.countScore();
apiTestPaper.updateAnswer(data).then((res) => {
if (res.status != 200) {
console.log('自动记录答卷失败:'+res.message,res.error);
}
})
},
getAnswer: function() {
let answer = {};
if (this.paper.length > 0) {
this.paper.forEach(item => {
let judgeUserAnswer = "";
if (String(item.userAnswer) && item.userAnswer != null) {
judgeUserAnswer = item.userAnswer + "";
}
answer[item.id] = judgeUserAnswer;
});
}
return JSON.stringify(answer);
},
// 试题排序
arrangeQuestion() {
if (this.testPaper.arrange) {
if (this.testPaper.arrange == 1 || this.testPaper.arrange == 3) {
this.randArray(this.paper, this.paper.length)
}
if (this.testPaper.arrange == 2 || this.testPaper.arrange == 3) {
this.paper.forEach((item) => {
if (item.optionList && item.optionList.length > 0) {
this.randArray(item.optionList, item.optionList.length)
}
})
}
}
},
//数组乱序
randArray(m, len) {
m.sort(function() {
return Math.random() - 0.5
})
return m.slice(0, len)
},
//开始计时
startReckon: function() {
let that = this;
that.reckonTimeer = setInterval(function() {
if (that.remainingTime <= 0) {
that.stopReckon();
//自动提交,应该先提示,然后再自动提交
uni.showToast({
title:'时间已到自动提交'
})
that.submit();
} else {
that.remainingTime--;
}
}, 1000)
},
// 停止计时
stopReckon: function() {
window.clearInterval(this.reckonTimeer)
},
prevSub() {
if (this.curIndex == 0) {
return;
}
this.curIndex--;
if (this.curIndex > -1) {
this.curItem = this.paper[this.curIndex];
}
},
nextSub() {
if (this.curIndex >= (this.total - 1)) {
return;
}
this.curIndex++;
this.curItem = this.paper[this.curIndex];
//console.log(this.curItem,'curItem');
this.updateAnswer();
},
// 人工提交
manualSubmit() {
let that = this;
uni.showModal({
title: '提示',
content: '您确定要提交试卷吗?',
success(res) {
if (res.confirm) {
that.stopReckon();
that.submit();
}
}
});
},
getQuestionType(type) {
let name = '';
switch (type) {
case 1:
name = '单选';
break;
case 2:
name = '多选';
break;
case 3:
name = '判断';
break;
}
return name;
}
}
}
</script>
<style lang="scss" scoped>
.epage{
background-color: #FFFFFF;
padding-bottom: 50px;
}
.history{
.history-item{
line-height: 80upx;
border-bottom: 2upx solid #c5c5c5;
.history-row{
display: flex;
justify-content: space-between;
font-size: 12px;
}
}
}
.sta-can {
text-align: center;
color: red;
margin-top: 20px;
}
.pager-title {
height: 40px;
display: flex;
justify-content: space-between;
line-height: 40px;
padding: 0 20upx;
.title-name {
margin-left: 20upx;
font-weight: bold;
}
.titlt-btn {
display: flex;
.sub {
height: 20px;
border-radius: 40px;
margin-top: 10px;
margin-left: 20upx;
}
}
}
.score-box {
height: 40px;
text-align: center;
margin: 20px;
}
.sta-btn {
margin: 20upx 50upx;
}
.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 0px;
position: fixed;
width: 100%;
bottom: 0px;
.next {
width: 60%;
border-radius: 40px;
margin-bottom: 20px;
}
// display: flex;
// justify-content: space-around;
}
</style>