mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-09 19:06:43 +08:00
971 lines
35 KiB
Vue
971 lines
35 KiB
Vue
<template>
|
||
<div class="test">
|
||
<el-container>
|
||
<el-header>
|
||
<div class="title">{{ testPaper.testName }}</div>
|
||
</el-header>
|
||
<el-container>
|
||
<el-main>
|
||
<div v-if="testStatus == 1">
|
||
<div class="test-info" >
|
||
<ul>
|
||
<li>考试时长: {{ testPaper.testDuration }}分钟</li>
|
||
<li>及格线: {{ testPaper.passLine }}</li>
|
||
<li v-if="testPaper.entranceTime">开始时间:
|
||
{{ testPaper.entranceTime }}</li>
|
||
<li v-if="testPaper.times">尝试次数: {{ testPaper.times }}</li>
|
||
<li v-if="testPaper.deadlineTime">结束时间: {{ testPaper.deadlineTime }}</li>
|
||
</ul>
|
||
</div>
|
||
<div v-if="testPaper.testFront" style="padding: 20px;text-align: center;" v-html="testPaper.testFront">
|
||
<!--考前说明-->
|
||
</div>
|
||
<div v-if="canExam" class="test-time" style="margin-top:20px" >
|
||
<div v-if="examStatus==0" style="text-align: center;color:#6d6d6d; ">考试还未开始</div>
|
||
<div v-if="examStatus==1">
|
||
<div v-if="tipText!=''" style="text-align: center;color:red">
|
||
<span>{{tipText}}</span>
|
||
</div>
|
||
<div v-else>
|
||
<el-button type="primary" :disabled="startButton" v-if="testStatus == 1" @click="startTest()">{{btnText}}</el-button>
|
||
</div>
|
||
</div>
|
||
<div v-if="examStatus==2" style="text-align: center;color:#6d6d6d; ">考试已结束</div>
|
||
</div>
|
||
<div v-else class="no-text">
|
||
<span v-if="noExam">您没有需要的考试</span>
|
||
</div>
|
||
<div class="re-list" v-if="canExam">
|
||
<p>历史记录</p>
|
||
<div style="height:300px" v-if="loading == 1" v-loading="loading == 1">
|
||
|
||
</div>
|
||
<el-table :data="tableData" style="width: 100%" v-if="loading == 2">
|
||
<el-table-column prop="startTime" label="完成时间" width="180"></el-table-column>
|
||
<el-table-column prop="score" align="center" label="成绩">
|
||
<template slot-scope="scope">
|
||
<span>{{toScoreTow(scope.row.score)}}分</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="score" align="center" label="状态">
|
||
<template slot-scope="scope">
|
||
<span v-if="scope.row.status==1" style="color: #ff0000;">未提交</span>
|
||
<span v-if="scope.row.status==8">中断</span>
|
||
<span v-if="scope.row.status==9" style="color: #00aa00; ">完成</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column align="center" label="操作">
|
||
<template slot-scope="scope">
|
||
<el-button v-if="scope.row.status>5" type="text" @click="viewUserPaper(scope.row)"><i class="el-icon-edit"></i> 查看考卷</el-button>
|
||
<el-button v-if="scope.row.status<5 && examStatus==1" type="text" @click="reStartTest(scope.row)"><i class="el-icon-edit"></i> 继续考试</el-button>
|
||
<el-button v-if="scope.row.status<5 && examStatus==2" type="text" @click="viewUserPaper(scope.row)"><i class="el-icon-edit"></i> 查看考卷</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
<!-- <div v-if="testStatus == 1" style="text-align: center;font-size:12px;color:#666666;margin-top:20px">
|
||
{{testPaper.testFront}}
|
||
</div> -->
|
||
<div v-if="testStatus == 2">
|
||
<div style="text-align: center;padding: 10px;color: #ff0000;"><span v-if="testStatus == 2">剩余时间:<span class="reckon-time">{{formatSeconds(remainingTime)}}</span></span></div>
|
||
<div v-if="judge.length > 0">
|
||
<div class="question-type">判断题</div>
|
||
<div v-for="(question, i) in judge" :key="question.id" class="question-info">
|
||
<div>{{ i + 1 }}、{{ question.title }} ({{question.defaultScore}}分)</div>
|
||
<div>
|
||
<div class="question-option">
|
||
<el-radio v-model="question.userAnswer" label="true">正确</el-radio>
|
||
</div>
|
||
<div class="question-option">
|
||
<el-radio v-model="question.userAnswer" label="false">错误</el-radio>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-if="single.length > 0">
|
||
<div class="question-type">单选题</div>
|
||
<div v-for="(question, i) in single" :key="question.id" class="question-info">
|
||
<div>{{ i + 1 + judge.length }}、{{ question.title }}({{question.defaultScore}}分)</div>
|
||
<div>
|
||
<div class="question-option" v-for="(option, j) in question.optionList" :key="option.id">
|
||
<el-radio v-model="question.userAnswer":label="option.id">
|
||
{{ numberToLetter(j+1) }}、{{ option.content }}
|
||
</el-radio>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-if="multiple.length > 0">
|
||
<div class="question-type">多选题</div>
|
||
<div v-for="(question, i) in multiple" :key="question.id" class="question-info">
|
||
<div>
|
||
{{ i + 1 + judge.length + single.length }}、{{ question.title }}({{question.defaultScore}}分)
|
||
</div>
|
||
<div>
|
||
<el-checkbox-group v-model="question.userAnswer">
|
||
<div class="question-option" v-for="(option, j) in question.optionList" :key="option.id">
|
||
<el-checkbox :label="option.id">{{ numberToLetter(j + 1) }}、{{ option.content }}</el-checkbox>
|
||
</div>
|
||
</el-checkbox-group>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="test-submit">
|
||
<el-button type="primary" @click="manualSubmit" :disabled="submitButton">提交试卷</el-button>
|
||
</div>
|
||
</div>
|
||
<div v-if="testStatus == 3" style="margin-top:20px">
|
||
<div style="text-align: center;font-size: 20px;">您本次考试得分:<span style="color: #08a890;font-size:24px">{{toScoreTow(score)}}</span></div>
|
||
<div style="text-align: center;font-size:12px;color:#666666;margin-top:20px">{{testPaper.testUp}}</div>
|
||
<div style="text-align: center;margin-top: 20px;">
|
||
<el-button type="primary" @click="closeTest()">关闭</el-button>
|
||
</div>
|
||
</div>
|
||
<div v-if="showPaperAnser === true">
|
||
<div v-if="judge.length > 0" style="margin-top:20px">
|
||
<div class="question-type">判断题</div>
|
||
<div v-for="(question, i) in judge" :key="question.id" class="question-info">
|
||
<div>{{ i + 1 }}、{{ question.title }} ({{question.defaultScore}}分)</div>
|
||
<div>
|
||
<div class="question-option">
|
||
<el-radio v-model="question.userAnswer" disabled :label="true">正确</el-radio>
|
||
</div>
|
||
<div class="question-option">
|
||
<el-radio v-model="question.userAnswer" disabled :label="false">错误</el-radio>
|
||
</div>
|
||
</div>
|
||
<p v-if="testPaper.showAnswer">正确答案:{{question && question.answer?'正确':'错误'}}</p>
|
||
<p v-if="testPaper.showAnalysis">解析:{{question.analysis}}</p>
|
||
</div>
|
||
|
||
</div>
|
||
<div v-if="single.length > 0">
|
||
<div class="question-type">单选题</div>
|
||
<div v-for="(question, i) in single" :key="question.id" class="question-info">
|
||
<div>{{ i + 1 + judge.length }}、{{ question.title }}({{question.defaultScore}}分)</div>
|
||
<div>
|
||
<div class="question-option" v-for="(option, j) in question.optionList" :key="option.id">
|
||
<el-radio disabled v-model="question.userAnswer" :label="option.id" >{{ numberToLetter(j+1) }}、{{ option.content }}</el-radio>
|
||
</div>
|
||
</div>
|
||
<p v-if="testPaper.showAnswer">正确答案:<span v-for="(item,a) in question.optionList" :key="a">{{item.isAnswer?numberToLetter(a+1):''}}</span></p>
|
||
<p v-if="testPaper.showAnalysis">解析:{{question.analysis}}</p>
|
||
</div>
|
||
</div>
|
||
<div v-if="multiple.length > 0">
|
||
<div class="question-type">多选题</div>
|
||
<div v-for="(question, i) in multiple" :key="question.id" class="question-info">
|
||
<div>
|
||
{{ i + 1 + judge.length + single.length }}、{{ question.title }}({{question.defaultScore}}分)
|
||
</div>
|
||
<div>
|
||
<el-checkbox-group v-model="question.userAnswer">
|
||
<div class="question-option" v-for="(option, j) in question.optionList" :key="option.id">
|
||
<el-checkbox disabled
|
||
:label="option.id">{{ numberToLetter(j + 1) }}、{{ option.content }}</el-checkbox>
|
||
</div>
|
||
</el-checkbox-group>
|
||
</div>
|
||
<p v-if="testPaper.showAnswer">正确答案:<span v-for="(q, b) in question.optionList" :key="b">{{q.isAnswer?numberToLetter(b+1):''}}</span></p>
|
||
<p v-if="testPaper.showAnalysis">解析:{{question.analysis}}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-main>
|
||
</el-container>
|
||
</el-container>
|
||
<el-dialog title="查看试卷" append-to-body :visible.sync="viewUserPapereShow" width="70%" custom-class="g-dialog">
|
||
<div style="padding: 10px; font-size: 20px" class="upaper">
|
||
<div v-for="(ditem,didx) in paperDetailData" :key="didx" class="upaper-item">
|
||
<div class="upaper-item-q">{{didx +1}}.【{{getTypeName(ditem.type)}}】{{ditem.title}}</div>
|
||
<div class="upaper-item-opts" style="padding-left: 20px;">
|
||
<div v-for="(opt,optIdx) in ditem.optionList" :key="optIdx" class="upaper-item-opt" :class="{'upaper-item-opt-user':ditem.userOptIdxs.indexOf(optIdx)>-1}">
|
||
<div>
|
||
<div>{{numberToLetter(optIdx+1)}}, {{opt.content}}</div>
|
||
</div>
|
||
<div>
|
||
<span v-if="ditem.userOptIdxs.indexOf(optIdx)>-1 && ditem.correctOptIdxs.indexOf(optIdx)>-1" style="color: #00aa00;font-size: 25px; ">√</span>
|
||
<span v-if="ditem.userOptIdxs.indexOf(optIdx)>-1 && ditem.correctOptIdxs.indexOf(optIdx)==-1" style="color: #ff0000;font-size: 25px; ">×</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="upaper-item-answer" style="display: flex;">
|
||
<div class="upaper-item-answer-cell">
|
||
<span v-if="ditem.result" style="color: #00aa00; ">回答正确</span>
|
||
<span v-else style="color: #ff0000; ">回答错误</span>
|
||
</div>
|
||
<div v-if="ditem.type !=3" style="display:flex">
|
||
<div v-if="testPaper.showAnswer" class="upaper-item-answer-cell" >
|
||
<span class="response-tit">正确答案:</span>
|
||
<span v-for="op in ditem.correctOptIdxs" :key="op">{{numberToLetter(op+1)}}</span>
|
||
</div>
|
||
<div class="upaper-item-answer-cell">
|
||
<span class="response-tit">我的答案:</span>
|
||
<span v-for="op in ditem.userOptIdxs" :key="op">{{numberToLetter(op+1)}}</span>
|
||
</div>
|
||
</div>
|
||
<div v-else style="display:flex">
|
||
<div v-if="testPaper.showAnswer" class="upaper-item-answer-cell" >
|
||
<span class="response-tit">正确答案:</span>
|
||
<span>{{ditem.correctOptIdxs[0]=='true' ? '正确':'错误'}}</span>
|
||
</div>
|
||
<div class="upaper-item-answer-cell">
|
||
<span class="response-tit">我的答案:</span>
|
||
<span>{{ditem.userOptIdxs[0] == 'true' ? '正确':'错误'}}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!--答案解析-->
|
||
<div v-if="ditem.analysis && testPaper.showAnalysis" style="padding-top: 10px;">
|
||
解析:{{ditem.analysis}}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="viewUserPapereShow = false">关闭</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { mapGetters } from 'vuex';
|
||
import apiTestPaper from '@/api/modules/testPaper.js'
|
||
import apiExamTask from "@/api/modules/examTask";
|
||
import { numberToLetter,examType,toScoreTow} from '@/utils/tools.js'
|
||
import { formatSeconds } from '@/utils/datetime.js'
|
||
export default {
|
||
data() {
|
||
return {
|
||
loading:0,
|
||
toScoreTow,
|
||
examId:'',//考试的id
|
||
taskId:'',//考试任务的id
|
||
lastId:'',//最后一次提交的答卷
|
||
canExam:false,//能否参加考试
|
||
noExam:false,//不能参加考试
|
||
tipText:'',//提示信息
|
||
examStatus:0,//0表无,1表考试中,2表已结束
|
||
btnText:'开始考试',
|
||
handleSaveTest:null,//对应timout定时任务的指向
|
||
getTypeName:examType,
|
||
viewUserPapereShow:false,
|
||
paperDetailData:[],
|
||
showPaperAnser:false,
|
||
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测试模式,独立考试
|
||
publishTime: '',//发布时间
|
||
testRemark: '',//考试描述
|
||
testFront: '',//考前描述
|
||
testUp: '',//考后描述
|
||
entranceTime: '',//入场时间
|
||
paperId: '',//试卷的ID
|
||
paperContent: '',//试卷内容
|
||
},
|
||
remainingTime: 0,
|
||
paperQuestion: [], //试卷内容经过排序后的数据,该数据就是试卷
|
||
judge: [],
|
||
single: [],
|
||
multiple: [],
|
||
startButton:false,
|
||
aloneExamAnswerId:null,// 考试提交答案ID
|
||
curTestAnswer:{},//当前考试的内容
|
||
testStatus: 1,// 1考前 2考中 3考后
|
||
reckonTimeer:null,// 计时器
|
||
updateAnswerTimeer:null,//定时提交答案
|
||
submitButton:false,
|
||
score:0,
|
||
tableData:[]
|
||
}
|
||
},
|
||
computed:{
|
||
...mapGetters(['userInfo'])
|
||
},
|
||
mounted() {
|
||
this.examId = this.$route.query.id
|
||
if(this.examId) {
|
||
this.loadData()
|
||
}else{
|
||
this.$message.error('非法请求');
|
||
}
|
||
},
|
||
methods: {
|
||
loadData() { //加载考试信息
|
||
apiTestPaper.getTestInfo(this.examId).then(res=>{
|
||
if(res.status==200){
|
||
this.canExam = res.result.hasTask;
|
||
if(!this.canExam) {
|
||
this.noExam = true;
|
||
}
|
||
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);
|
||
}
|
||
});
|
||
},
|
||
viewUserPaper(row) { //查看答卷信息
|
||
this.viewUserPapereShow = true;
|
||
this.getAnswerDetail(row.id);
|
||
},
|
||
getAnswerDetail(id) { //获取答卷的详细信息
|
||
apiTestPaper.getAnswerDetail(id).then(res=>{
|
||
if(res.status === 200) {
|
||
let answerJson = [];
|
||
answerJson=JSON.parse(res.result.answerJson);
|
||
let paperJson = [];
|
||
paperJson=JSON.parse(res.result.paperJson);
|
||
let answer = [];
|
||
let data = [];
|
||
for(let key in answerJson){
|
||
answer.push(key);
|
||
paperJson.forEach((item,index) => {
|
||
item.result=true;
|
||
if(item.id == key) {
|
||
if(item.type==1){
|
||
item.userAnswer='';
|
||
}else if(item.type==2){
|
||
item.userAnswer=[];
|
||
}else{
|
||
item.userAnswer=''
|
||
}
|
||
|
||
item.correctOptIdxs=[];
|
||
item.userOptIdxs=[];
|
||
if(item.type==1){
|
||
item.userAnswer=answerJson[key];
|
||
}else if(item.type==2){
|
||
item.userAnswer.push(...answerJson[key].split(','));
|
||
}else{
|
||
item.userAnswer=answerJson[key]
|
||
}
|
||
data.push(item);
|
||
// item.userAnswer.push(answerJson[key]);
|
||
}
|
||
});
|
||
}
|
||
this.paperDetailData = data;
|
||
this.paperDetailData.forEach((item,index)=>{
|
||
if(item.type ==3) {
|
||
item.correctOptIdxs.push(item.answer);
|
||
item.userOptIdxs.push(item.userAnswer);
|
||
}
|
||
item.optionList.forEach((opt,idx)=>{
|
||
//填充正确答案
|
||
if(opt.isAnswer){
|
||
item.correctOptIdxs.push(idx);
|
||
}
|
||
if(item.type==1){ //单选或判断
|
||
if(opt.id==item.userAnswer){
|
||
item.userOptIdxs.push(idx);
|
||
}
|
||
}else if(item.type==2){ //多选
|
||
if(item.userAnswer.indexOf(opt.id)>-1){
|
||
item.userOptIdxs.push(idx);
|
||
}
|
||
}
|
||
// else if(item.type==3){ //判断
|
||
// if(item.userAnswer.indexOf(opt.id)>-1){
|
||
// item.userOptIdxs.push(idx);
|
||
// }
|
||
// }
|
||
});
|
||
//判断答案是否正确
|
||
if(item.correctOptIdxs.toString()==item.userOptIdxs.toString()){
|
||
item.result=true;
|
||
}else{
|
||
item.result=false;
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
testAnswers(){ //获取当前考试的历史记录
|
||
this.loading = 1;
|
||
apiTestPaper.myTestAnswers(this.examId).then(res=>{
|
||
if(res.status ==200) {
|
||
this.loading = 2;
|
||
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.loading = 2;
|
||
this.$message.error('加载考试记录失败');
|
||
}
|
||
})
|
||
},
|
||
//开始考试
|
||
startTest(){
|
||
this.curTestAnswer={};
|
||
// 先禁用,防止重复提交
|
||
if(this.testPaper.entranceTime && this.testPaper.entranceTime !=='') {
|
||
let time = new Date();
|
||
let entranceTime = new Date(this.testPaper.entranceTime);
|
||
if(time < entranceTime) {
|
||
this.$message.warning('考试还未开始,请耐心等候!')
|
||
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){
|
||
//处理试卷内容
|
||
this.paperQuestion=JSON.parse(rs.result.paper);
|
||
if(this.paperQuestion.length==0){
|
||
this.$message.error('此考试无试题内容,可能试卷已删除,请与管理员联系');
|
||
}else{
|
||
this.arrangeQuestion();
|
||
this.splitQuestionType();
|
||
//进入考试阶段
|
||
this.testStatus = 2;
|
||
this.startReckon();
|
||
//60秒后执行保存处理
|
||
this.startUpdateAnswer();
|
||
// window.setTimeout(function(){
|
||
// $this.saveUserTest();
|
||
// },10000);
|
||
}
|
||
}else{
|
||
this.startButton = false;
|
||
this.$message.error('加载试卷内容失败:'+rs.message);
|
||
}
|
||
});
|
||
},
|
||
closeTest(){
|
||
window.location.href='test?id='+this.examId;
|
||
},
|
||
saveUserTest(){ //保存用户的考试,此时包括了考试信息,不只是答案,先在后台建立一条记录
|
||
if(this.handleSaveTest!=null){
|
||
window.clearTimeout(this.handleSaveTest);
|
||
}
|
||
if(this.testStatus!=2){
|
||
//只有在第二阶段才会保存
|
||
return;
|
||
}
|
||
|
||
//一个题都没有答的情况,不能提交
|
||
let strAnswer=this.getAnswer();
|
||
let objAnswer=JSON.parse(strAnswer);
|
||
let total=0;
|
||
let hasOne=false;
|
||
this.paperQuestion.forEach(item=>{
|
||
if(item.defaultScore){
|
||
total+=item.defaultScore;
|
||
}
|
||
if(item.type<900){
|
||
if(objAnswer[item.id]!=''){
|
||
hasOne=true;
|
||
}
|
||
}
|
||
});
|
||
if(!hasOne){
|
||
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 = this.clearPagerJson();
|
||
data.answerJson=strAnswer;
|
||
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{
|
||
this.$message.error(res.message);
|
||
}
|
||
})
|
||
},
|
||
clearPagerJson(){
|
||
let paperJson = [];
|
||
this.paperQuestion.forEach((item,index) => {
|
||
let option = {
|
||
id:item.id,
|
||
optionList:[]
|
||
};
|
||
item.optionList.forEach(it=>{
|
||
option.optionList.push({id:it.id})
|
||
})
|
||
paperJson.push(option);
|
||
})
|
||
return JSON.stringify(paperJson);
|
||
},
|
||
countScore(){
|
||
let total=0;
|
||
if(this.judge.length > 0){
|
||
this.judge.forEach(item => {
|
||
//console.log(total,'判断',item);
|
||
if(item.answer=='true' && item.userAnswer=='true'){
|
||
total+=item.defaultScore;
|
||
}else{
|
||
if(item.answer=='false' && item.userAnswer=='false'){
|
||
total+=item.defaultScore;
|
||
}
|
||
}
|
||
//console.log(total,'分数');
|
||
});
|
||
}
|
||
if(this.single.length > 0){
|
||
this.single.forEach(item => {
|
||
item.optionList.forEach(opt=>{
|
||
if(opt.id==item.userAnswer && opt.isAnswer){
|
||
total+=item.defaultScore;
|
||
}
|
||
})
|
||
});
|
||
}
|
||
if(this.multiple.length > 0){
|
||
this.multiple.forEach(item => {
|
||
//提取正确答案
|
||
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();
|
||
|
||
if(str1==str2){
|
||
console.log('str1='+str1);
|
||
console.log('str2='+str2);
|
||
total+=item.defaultScore;
|
||
}
|
||
});
|
||
}
|
||
console.log('实际得分:'+total)
|
||
return total;
|
||
},
|
||
reStartTest(row){ //继续考试
|
||
this.curTestAnswer=row;
|
||
apiTestPaper.getAnswerDetail(row.id).then(res=>{
|
||
if(res.status === 200) {
|
||
this.paperQuestion= JSON.parse(res.result.paperJson);
|
||
//填充答案
|
||
let answerJson = JSON.parse(res.result.answerJson);
|
||
//设置已答题内容
|
||
this.paperQuestion.forEach((qitem,index) => {
|
||
let avalue=answerJson[qitem.id];
|
||
if(avalue){
|
||
if(qitem.type==1){ //单选
|
||
qitem.userAnswer=avalue;
|
||
}else if(qitem.type==2){ //多选
|
||
qitem.userAnswer=avalue.split(',');
|
||
}else if(qitem.type==3){ //判断
|
||
qitem.userAnswer=avalue;
|
||
//console.log(avalue,'avalue');
|
||
}
|
||
}
|
||
});
|
||
//console.log(this.paperQuestion,'this.paperQuestion')
|
||
this.arrangeQuestion();
|
||
this.splitQuestionType();
|
||
//进入考试阶段
|
||
this.testStatus = 2;
|
||
if(res.result.useSecond){
|
||
this.remainingTime=this.testPaper.testDuration*60-res.result.useSecond;
|
||
}else{
|
||
this.remainingTime=this.testPaper.testDuration*60;
|
||
}
|
||
this.startReckon();
|
||
//启时定时保存
|
||
this.aloneExamAnswerId = row.id;
|
||
this.startUpdateAnswer();
|
||
}else{
|
||
this.$message.error('读取已考试卷错误:'+res.message);
|
||
}
|
||
});
|
||
},
|
||
formatSeconds(time){
|
||
return formatSeconds(time);
|
||
},
|
||
numberToLetter(x){
|
||
return numberToLetter(x);
|
||
},
|
||
//试题排序
|
||
arrangeQuestion() {
|
||
if (this.testPaper.arrange) {
|
||
if (this.testPaper.arrange == 1 || this.testPaper.arrange == 3) {
|
||
this.randArray(this.paperQuestion, this.paperQuestion.length)
|
||
}
|
||
if(this.testPaper.arrange == 2 || this.testPaper.arrange == 3){
|
||
this.paperQuestion.forEach((item) => {
|
||
if (item.optionList && item.optionList.length > 0) {
|
||
this.randArray(item.optionList, item.optionList.length)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
},
|
||
// 拆分题型,用于页面显示
|
||
splitQuestionType() {
|
||
this.judge = this.splitByType(this.paperQuestion, 3)
|
||
this.single = this.splitByType(this.paperQuestion, 1)
|
||
this.multiple = this.splitByType(this.paperQuestion, 2)
|
||
},
|
||
// 按题目类型拆分数组
|
||
splitByType(arr, type) {
|
||
let result = []
|
||
arr.forEach((item, i) => {
|
||
if (item.type == type) {
|
||
if(!item.userAnswer){
|
||
if(type == 1){
|
||
this.$set(item, 'userAnswer', null)
|
||
}else if (type == 2) {
|
||
// 多选题,多选题的答案是数组初始化会报错,且必须通过this.$set初始化
|
||
this.$set(item, 'userAnswer', [])
|
||
}else if(type == 3){
|
||
this.$set(item, 'userAnswer', null)
|
||
}
|
||
}
|
||
result.push(item)
|
||
}
|
||
})
|
||
return result
|
||
},
|
||
// 数组乱序
|
||
randArray(m, len) {
|
||
m.sort(function () {
|
||
return Math.random() - 0.5
|
||
})
|
||
return m.slice(0, len)
|
||
},
|
||
// 开始计时,计时过程中,如果最后到0了,自动提交
|
||
startReckon:function(){
|
||
let that = this;
|
||
this.reckonTimeer = window.setInterval(function(){
|
||
if(that.remainingTime <= 0){
|
||
that.stopReckon();
|
||
that.stopUpdateAnswer();
|
||
that.$message({
|
||
type: 'success',
|
||
message: '考试时间已结束,自动提交试卷'
|
||
});
|
||
that.submit(0);//表时间表了自动提交
|
||
}else{
|
||
that.remainingTime--;
|
||
}
|
||
},1000);
|
||
},
|
||
// 停止计时
|
||
stopReckon:function(){
|
||
window.clearInterval(this.reckonTimeer)
|
||
},
|
||
/**
|
||
* 开始提交答案
|
||
*/
|
||
startUpdateAnswer:function(){
|
||
if(this.paperQuestion.length==0){
|
||
return;
|
||
}
|
||
if(this.updateAnswerTimeer!=null){
|
||
window.clearInterval(this.updateAnswerTimeer)
|
||
}
|
||
let that = this;
|
||
this.updateAnswerTimeer =window.setInterval(function(){
|
||
that.updateAnswer();
|
||
},10000);//测试时可以修改的变小了
|
||
},
|
||
// 停止提交答案
|
||
stopUpdateAnswer(){
|
||
window.clearInterval(this.updateAnswerTimeer)
|
||
},
|
||
getAnswer:function(){
|
||
let answer = {};
|
||
if(this.judge.length > 0){
|
||
this.judge.forEach(item => {
|
||
let judgeUserAnswer = "";
|
||
//if(String(item.userAnswer) && item.userAnswer != null){
|
||
judgeUserAnswer = item.userAnswer + "";
|
||
//}
|
||
answer[item.id] = judgeUserAnswer;
|
||
});
|
||
}
|
||
if(this.single.length > 0){
|
||
this.single.forEach(item => {
|
||
let singleUserAnswer = "";
|
||
if(item.userAnswer && item.userAnswer != null){
|
||
singleUserAnswer = item.userAnswer + "";
|
||
}
|
||
answer[item.id]=singleUserAnswer;
|
||
});
|
||
}
|
||
if(this.multiple.length > 0){
|
||
this.multiple.forEach(item => {
|
||
let multipleUserAnswer = "";
|
||
if(item.userAnswer && item.userAnswer != null && item.userAnswer.length > 0){
|
||
multipleUserAnswer = item.userAnswer.join(",");
|
||
}
|
||
answer[item.id]=multipleUserAnswer;
|
||
});
|
||
}
|
||
return JSON.stringify(answer);
|
||
},
|
||
//自动保存提交答案
|
||
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) {
|
||
}else{
|
||
console.log('自动记录答卷失败:'+res.message,res.error);
|
||
}
|
||
})
|
||
},
|
||
// 人工提交
|
||
manualSubmit(){
|
||
// let tempScore=this.countScore();
|
||
let that = this;
|
||
this.$confirm('您确定要提交试卷吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
that.stopUpdateAnswer();
|
||
that.submit(1);//人工提交
|
||
}).catch(() => { });
|
||
},
|
||
// 提交考卷
|
||
submit(t){
|
||
// if(!this.aloneExamAnswerId || !this.curTestAnswer.totalScore){
|
||
// this.$message.error('请先答题');
|
||
// return;
|
||
// }
|
||
let strAnswer=this.getAnswer();
|
||
//一个题都没有答的情况,不能提交
|
||
let objAnswer=JSON.parse(strAnswer);
|
||
|
||
let total=0;
|
||
let hasOne=false;
|
||
this.paperQuestion.forEach(item=>{
|
||
if(item.defaultScore){
|
||
total+=item.defaultScore;
|
||
}
|
||
if(item.type<900){
|
||
if(objAnswer[item.id]!=''){
|
||
hasOne=true;
|
||
}
|
||
}
|
||
});
|
||
if(!hasOne){
|
||
if(t==1){
|
||
this.$message.error('请先答题再提交');
|
||
return;
|
||
}else{
|
||
this.testStatus = 3;
|
||
//转化为百分制显示
|
||
this.score = 0;
|
||
this.submitButton = false;
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
let that = this;
|
||
this.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.ucode = this.userInfo.userNo;
|
||
if(!this.aloneExamAnswerId){
|
||
//大字段在需要的时候才会提交
|
||
data.paperJson = JSON.stringify(this.paperQuestion);
|
||
}
|
||
data.scoreType=this.testPaper.scoringType;
|
||
data.taskId = this.taskId;
|
||
data.totalScore=total;
|
||
data.answerJson = strAnswer;
|
||
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) {
|
||
this.testStatus = 3;
|
||
//转化为百分制显示
|
||
this.score = data.score;
|
||
this.submitButton = false;
|
||
} else {
|
||
this.submitButton = false;
|
||
this.$message.error(res.message)
|
||
}
|
||
})
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.no-text{
|
||
text-align: center;
|
||
margin-top: 50px;
|
||
color: red;
|
||
}
|
||
.upaper{
|
||
text-align: left;
|
||
.upaper-item{
|
||
border-bottom: 1px solid #dadada;
|
||
padding: 10px;
|
||
.upaper-item-q{
|
||
padding: 8px 0px;
|
||
}
|
||
.upaper-item-opts{
|
||
padding: 8px 0px;
|
||
line-height: 20px;
|
||
.upaper-item-opt{
|
||
min-height: 50px;
|
||
border-radius: 4px;
|
||
display: flex;
|
||
background-color: #FFFFFF;
|
||
justify-content: space-between;
|
||
padding: 10px 20px;
|
||
}
|
||
.upaper-item-opt-user{
|
||
background-color: #fff3e5;
|
||
}
|
||
}
|
||
.upaper-item-answer{
|
||
display: flex;
|
||
.upaper-item-answer-cell{
|
||
margin-right: 20px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.re-list{
|
||
margin-top: 50px;
|
||
p{
|
||
margin: 20px;
|
||
margin-left: 0;
|
||
font-size: 24px;
|
||
}
|
||
}
|
||
.test {
|
||
width: 900px;
|
||
margin: 0 auto;
|
||
background: #fff;
|
||
padding-bottom: 100px;
|
||
}
|
||
.title {
|
||
font-size: 30px;
|
||
line-height: 65px;
|
||
text-align: center;
|
||
}
|
||
.test-info {
|
||
// text-align: center;
|
||
width: 500px;
|
||
margin: 0 auto;
|
||
background: #eee;
|
||
border-radius: 16px;
|
||
ul{
|
||
list-style:none;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-around;
|
||
padding: 20px;
|
||
|
||
li{
|
||
flex: 50%;
|
||
line-height: 60px;
|
||
}
|
||
}
|
||
span {
|
||
margin: 0 20px;
|
||
}
|
||
}
|
||
.question-type {
|
||
font-weight: 500;
|
||
font-size: 20px;
|
||
line-height: 45px;
|
||
background: rgb(250, 244, 244);
|
||
padding-left: 20px;
|
||
}
|
||
.question-info{
|
||
margin: 5px 0;
|
||
padding: 20px
|
||
}
|
||
.question-option{
|
||
margin: 5px 0;
|
||
}
|
||
.test-time {
|
||
text-align: center;
|
||
line-height: 45px;
|
||
.reckon-time {
|
||
color: red;
|
||
}
|
||
}
|
||
.test-submit{
|
||
text-align: center;
|
||
line-height: 65px;
|
||
}
|
||
</style>
|