竞赛 理论考试 代码调整

This commit is contained in:
joylink_cuiweidong 2020-09-25 14:46:57 +08:00
parent 83793d75ca
commit 2386f424d4
3 changed files with 266 additions and 299 deletions

View File

@ -272,3 +272,13 @@ export function getPracticeQuestionProgress(projectCode) {
method: 'get'
});
}
/** 项目更新练习的试题的进度列表 */
export function submitPracticeQuestionData(projectCode, data) {
return request({
url: `/api/v1/competitionTheory/project/${projectCode}/submit`,
method: 'post',
data
});
}

View File

@ -1,271 +0,0 @@
<template>
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false">
<!-- <el-container class="quiz">
<el-container class="quiz__container">
<el-header class="quiz__container-header layer-center">
<div class="title">{{ formModel.name }}</div>
<div class="notes">{{ formModel.description }}</div>
</el-header>
<el-main class="quiz__container-main layer-center">
<div v-for="(el,i) in sortedList" :id="'anchor__lst-'+i" :key="i" class="section">
<template v-if="el.children.length">
<div class="caption">{{ index2UnicodeList[i] }}{{ el.title }} </div>
<question v-for="(item,j) in el.children" :id="'anchor__lst-'+item.type+'-'+item.index" :key="j" v-model="item.answer" class="context" :option="item" @save="onSave" />
</template>
</div>
</el-main>
<el-footer class="quiz__container-footer layer-center" @click="returnTop">
<div style="display: inline-block;position: relative;bottom: 20px;height: 40px;line-height: 40px;float: left;color:#F00;font-size: 12px;">温馨提示考试过程中请退出或关闭本页面不会终止计时</div>
<div style="display: inline-block;position: relative;bottom: 20px;height: 40px;line-height: 40px;margin-right: 10px;font-weight:bold;">{{ '剩余时间:'+countdownTime }}</div>
<el-button-group class="buttons">
<el-button v-loading="loading" type="primary" @click="commit"> </el-button>
</el-button-group>
</el-footer>
</el-container>
</el-container> -->
</el-dialog>
</template>
<script>
import Question from './question';
import { getItemListByProjectCode, commitProjectTestPaper } from '@/api/competition';
import { computationTime } from '@/utils/date';
import { getSessionStorage } from '@/utils/auth';
import { ProjectCode } from '@/scripts/ProjectConfig';
export default {
components: {
Question
},
mixins: [
],
data() {
return {
index: 0,
height: 0,
loading: false,
formModel: {
description: '',
duration: 10,
name: '',
status: '',
totalScore: 0,
passScore: 10
},
examQuestions: [],
theoryAnswersMap: {},
countdownTime: '00:00:00',
theoryExamTime: 0,
countdown: null,
dialogVisible: false,
data: {}
};
},
computed: {
examId() {
return this.$route.params.examId;
},
userExamId() {
return this.$route.params.userExamId;
},
question() {
return this.examQuestions[this.index] || {};
},
project() {
return getSessionStorage('project');
},
index2UnicodeList() {
return ['一', '二', '三', '四'];
},
sortedList() {
return [
{
title: '判断题',
children: this.examQuestions.filter(el => { return el.type === 'judge'; })
},
{
title: '选择题',
children: this.examQuestions.filter(el => { return el.type === 'select'; })
}
];
}
},
watch: {
},
created() {
},
beforeDestroy() {
if (this.countdown) {
clearInterval(this.countdown);
}
},
methods: {
doShow() {
this.theoryAnswersMap = {};
this.dialogVisible = true;
getItemListByProjectCode(ProjectCode[this.project]).then(resp => {
if (resp.data) {
this.examQuestions = resp.data.map((el, i) => {
el.index = i;
el.answer = this.theoryAnswersMap[el.id];
return el;
});
this.theoryExamTime = 3600;
this.countdownTime = computationTime(this.theoryExamTime);
this.countdown = setInterval(() => {
if (this.theoryExamTime <= 0) {
if (this.countdown) {
clearInterval(this.countdown);
}
this.commit();
}
this.theoryExamTime--;
this.countdownTime = computationTime(this.theoryExamTime);
}, 1000);
}
}).catch(() => {
this.$message.error('获取试题列表失败!');
});
},
resizeHandler() {
this.height = this._clientHeight;
},
appendIndex(str, index) {
return `${index + 1}. ${str}`;
},
goAnchor(selector) {
const anchor = this.$el.querySelector(selector);
const el = this.$el.querySelector('.el-main');
if (anchor && el) {
el.scrollTop = anchor.offsetTop;
}
},
returnTop() {
document.querySelector('.el-header').scrollIntoView(true);
},
commit() {
let isFinish = true;
this.examQuestions.forEach(el => {
if (!el.answer) { isFinish = false; }
});
if (isFinish || this.theoryExamTime <= 0) {
this.doEnd();
} else {
this.$confirm('存在试题未完成,是否继续?', '提 示', {
confirmButtonText: '确 定',
cancelButtonText: '取 消',
type: 'warning'
}).then(() => {
this.doEnd();
}).catch( () => { });
}
},
doEnd() {
const theoryAnswers = [];
for (const key in this.theoryAnswersMap) {
theoryAnswers.push({questionId: key, answerOptionId: this.theoryAnswersMap[key]});
}
commitProjectTestPaper(ProjectCode[this.project], theoryAnswers).then(resp => {
this.$emit('commitResult', resp.data);
this.dialogVisible = false;
}).catch(() => {
this.$message.error('提示试卷失败');
});
},
onSave(data) {
this.theoryAnswersMap[data.userExamQuestionId] = data.answer;
}
}
};
</script>
<style lang="scss" scoped>
.layer-center {
width: 900px;
height: 100%;
margin: auto;
background: #fff;
}
.quiz {
background: #eee;
height: 100%;
&::-webkit-scrollbar {
display:none
}
&__card {
height: 100%;
.dir-item {
padding-left: 25px;
}
.dir-caption {
padding-left: 10px;
line-height: 26px;
background: #f1f1f1;
}
}
&__container {
height: 100%;
&-header {
height: auto !important;
.title {
font-size: 24px;
line-height: 60px;
font-weight: bold;
text-align: center;
}
.notes {
color:#606266;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 20px;
}
}
&-main {
.section {
padding: 5px 20px;
.caption {
line-height: 26px;
}
.context {
}
}
}
&-footer {
text-align: right;
position: sticky;
bottom: 0px;
padding: 40px ;
.buttons {
position: relative;
bottom: 20px;
}
}
}
}
/deep/{
.el-dialog__body{
height: 100%;
}
.el-dialog__header{
padding: 0;
}
.el-dialog__headerbtn{
top: 7px;
}
}
</style>

View File

@ -1,11 +1,11 @@
<template>
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" class="theoryExam" fullscreen style="background:#eeeeee">
<div v-loading="loading" class="theoryExamBody">
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" class="theoryExam" fullscreen style="background:#eeeeee" :before-close="close">
<div v-if="!isResult" v-loading="loading" class="theoryExamBody">
<div class="theoryExamBodyL">
<div class="theoryExamQuestion">
<div class="QuestionName">{{ covert() }}</div>
<div class="choiceList">
<div v-if="judgeQuestionType('radio')">
<div v-if="judgeQuestionType('radio',questionList[currentQuestionNum])">
<el-radio
v-for="(choice,index) in questionList[currentQuestionNum].optionList "
:key="index"
@ -15,7 +15,7 @@
@change="changeAnswer"
>{{ choiceTypeList[index]+'、 '+choice.content }}</el-radio>
</div>
<div v-else-if="judgeQuestionType('multi')">
<div v-else-if="judgeQuestionType('multi',questionList[currentQuestionNum])">
<el-checkbox-group v-model="currentSelectAnswer" @change="changeAnswer">
<el-checkbox
v-for="(choice,index) in questionList[currentQuestionNum].optionList "
@ -26,21 +26,22 @@
</el-checkbox-group>
</div>
</div>
<div v-if="mode=='practice'&&isSelect" class="correctAnswer" :style="answerIsCorrect?'color: #67C23A;':'color: #ff4d4f;'">
<div v-if="!isTest&&isSelect" class="correctAnswer" :style="answerIsCorrect?'color: #67C23A;':'color: #ff4d4f;'">
<span class="practiceIconTips" :class="answerIsCorrect?'el-icon-success':'el-icon-error'" />
<span class="practicecorrectAnswer">{{ '答案:'+correctAnswer }}</span>
</div>
</div>
<div class="buttonList">
<el-button v-if="mode=='practice'" :disabled="isSelect" type="success" class="commitQuestion" size="small" @click="commitQuestion"> </el-button>
<div class="buttonList" :style="!isTest?'bottom: 15px;':''">
<el-button v-if="!isTest" :disabled="isSelect" type="success" class="commitQuestion" size="small" @click="commitQuestion"> </el-button>
<div class="prevAndNext">
<el-button-group>
<el-button type="primary" size="small" :disabled="currentQuestionNum==0" @click="prevQuestion"><span class="el-icon-arrow-left" style="margin-right:5px;" />上一题</el-button>
<el-button type="primary" size="small" :disabled="checkNextButton()" @click="nextQuestion">下一题<span class="el-icon-arrow-right" style="margin-left:5px;" /></el-button>
</el-button-group>
</div>
<el-button v-if="mode=='test'" type="success" class="commitExam" size="small" @click="commitExam">交卷</el-button>
<el-button v-if="isTest" type="success" class="commitExam" size="small" @click="commitExam">交卷</el-button>
</div>
<div v-if="isTest" class="examTips">距离测试结束还有 {{ currentTime }}</div>
</div>
<div class="theoryExamBodyR">
<div v-if="mode=='test'" class="theoryExamBodyRT">
@ -49,16 +50,59 @@
<!-- <span class="hasSign">标记</span> -->
</div>
<div class="theoryExamQuestionList">
<div v-for="(eachNum,index) in questionList" :key="index" class="eachQuestionNum" @click="changeQuestion(index)">
<!-- :class="item.answerOptionId.length>0?'hasSelect':''" -->
<div v-for="(item,index) in questionList" :id="'eachQuestionNum'+index" :key="index" class="eachQuestionNum" @click="changeQuestion(index+1)">
{{ (index+1) }}
</div>
</div>
</div>
</div>
<div v-else class="theoryExamBody">
<div class="theoryExamScore">{{ '测验得分:' }}<span class="resultScoreStyle">{{ resultScore+' 分' }}</span></div>
<div class="theoryExamWrongListName">错题列表</div>
<div class="theoryExamWrongList">
<div class="theoryExamWrongListL">
<div class="QuestionName">{{ covertWrong() }}</div>
<div class="choiceList">
<div v-if="judgeQuestionType('radio',theoryExamWrongList[wrongQuestionNum].question)">
<el-radio
v-for="(choice,index) in theoryExamWrongList[wrongQuestionNum].question.optionList "
:key="index"
v-model="currentRadioAnswer"
:label="choice.id"
:disabled="true"
class="eachChoice"
>{{ choiceTypeList[index]+'、 '+choice.content }}</el-radio>
</div>
<div v-else-if="judgeQuestionType('multi',theoryExamWrongList[wrongQuestionNum].question)">
<el-checkbox-group v-model="currentSelectAnswer">
<el-checkbox
v-for="(choice,index) in theoryExamWrongList[wrongQuestionNum].question.optionList"
:key="index"
:label="choice.id"
:disabled="true"
class="eachChoice"
>{{ choiceTypeList[index]+'、 '+choice.content }}</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="correctAnswer" style="color: #ff4d4f;">
<span class="practicecorrectAnswer">{{ '答案:'+wrongCorrectAnswer() }}</span>
</div>
</div>
<div class="theoryExamWrongListR">
<div class="theoryExamWrongQuestionList">
<div v-for="(wrongQuestion,index) in theoryExamWrongList" :key="index" class="eachQuestionNum" :class="wrongQuestionNum==index?'active':''" @click="changeWrongQuestion(index)">
{{ index+1 }}
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script>
import {getItemListByProjectCode, updatePracticeQuestionProgress, getPracticeQuestionProgress} from '@/api/competition';
import {getItemListByProjectCode, updatePracticeQuestionProgress, getPracticeQuestionProgress, submitPracticeQuestionData} from '@/api/competition';
export default {
name:'TheoryExam',
data() {
@ -66,25 +110,40 @@ export default {
loading:false,
dialogVisible:false,
mode:'',
currentTime:'00:30:00',
allTime:30 * 60,
questionList:[],
inter:null,
currentQuestionNum:0,
wrongQuestionNum:0,
currentSelectAnswer:[],
currentRadioAnswer:'',
currentCorrectAnswer:[],
answerIsCorrect:false,
hasAnswerList:{},
correctAnswer:'',
isSelect:false,
isResult:false,
theoryExamWrongList:[],
resultScore:0,
choiceTypeList:['A', 'B', 'C', 'D', 'E', 'F', 'G']
};
},
computed:{
isTest() {
return this.mode == 'test';
}
},
methods:{
doShow({type}) {
this.isResult = false;
this.loading = true;
this.allTime = 30 * 60;
this.currentTime = '00:30:00';
this.isSelect = false;
this.questionList = [];
this.currentSelectAnswer = [];
this.currentRadioAnswer = '';
this.hasAnswerList = {};
let currentMode = '01';
if (type == 'practice') {
currentMode = '01';
@ -94,6 +153,11 @@ export default {
this.mode = type;
getItemListByProjectCode('drts', {mode:currentMode}).then(res=>{
this.questionList = res.data;
if (this.isTest) {
this.questionList.forEach((question, index)=>{
this.hasAnswerList[index] = {questionId:question.id, answerOptionId:[]};
});
}
if (this.mode == 'practice') {
getPracticeQuestionProgress('drts').then(res=>{
this.currentQuestionNum = res.data.questionIndex;
@ -102,7 +166,9 @@ export default {
console.log(error.message);
});
} else {
this.initCurrentTime();
this.currentQuestionNum = 0;
this.wrongQuestionNum = 0;
this.loading = false;
}
});
@ -110,23 +176,50 @@ export default {
},
close() {
this.dialogVisible = false;
clearInterval(this.inter);
},
covert() {
const typeList = {'judge':'判断', 'select':'选择', 'multi':'多选'};
const currentQuestion = this.questionList[this.currentQuestionNum];
if (currentQuestion) {
return '第 ' + (this.currentQuestionNum + 1) + ' 题、[' + typeList[currentQuestion.type] + '] ' + currentQuestion.topic;
return '第 ' + (this.currentQuestionNum + 1) + ' 题、[' + typeList[currentQuestion.type] + '] ' + currentQuestion.topic + ' (' + currentQuestion.score + '分)';
}
return '';
},
initCurrentTime() {
this.inter = setInterval(() => {
if (this.allTime > 0) {
this.allTime--;
let seconds = this.allTime % 60;
let minutes = (this.allTime - this.allTime % 60) / 60;
minutes = minutes > 9 ? minutes : '0' + minutes;
seconds = seconds > 9 ? seconds : '0' + seconds;
this.currentTime = '00:' + minutes + ':' + seconds;
} else {
clearInterval(this.inter);
const submitData = Object.values(this.hasAnswerList);
this.submitConfirmExam(submitData);
}
}, 1000);
},
covertWrong() {
const typeList = {'judge':'判断', 'select':'选择', 'multi':'多选'};
const WrongQuestion = this.theoryExamWrongList[this.wrongQuestionNum];
if (WrongQuestion) {
return (this.wrongQuestionNum + 1) + '、[' + typeList[WrongQuestion.question.type] + '] ' + WrongQuestion.question.topic + ' (' + WrongQuestion.question.score + '分)';
}
return '';
},
changeQuestion(num) {
this.isSelect = false;
this.currentQuestionNum = num;
this.currentSelectAnswer = [];
this.currentRadioAnswer = '';
this.currentQuestionNum = num - 1;
this.checkCurrentData(this.currentQuestionNum);
},
judgeQuestionType(type) {
const currentQuestion = this.questionList[this.currentQuestionNum];
changeWrongQuestion(num) {
this.wrongQuestionNum = num;
this.getWrongDataOption();
},
judgeQuestionType(type, currentQuestion) {
if (currentQuestion && type == 'radio') {
return currentQuestion.type == 'judge' || currentQuestion.type == 'select';
} else if (currentQuestion && type == 'multi') {
@ -139,8 +232,7 @@ export default {
if (this.currentQuestionNum > 0) {
this.currentQuestionNum -= 1;
this.isSelect = false;
this.currentSelectAnswer = [];
this.currentRadioAnswer = '';
this.checkCurrentData(this.currentQuestionNum);
}
},
@ -148,12 +240,85 @@ export default {
if (this.currentQuestionNum < this.questionList.length) {
this.currentQuestionNum += 1;
this.isSelect = false;
this.checkCurrentData(this.currentQuestionNum);
}
},
checkCurrentData(currentQuestionNum) {
if (this.hasAnswerList[currentQuestionNum]) {
const answerObj = this.hasAnswerList[currentQuestionNum].answerOptionId;
if (answerObj.length > 0) {
const question = this.questionList[currentQuestionNum];
if (question.type == 'judge' || question.type == 'select') {
this.currentRadioAnswer = answerObj[0];
} else {
this.currentSelectAnswer = answerObj;
}
} else {
this.currentSelectAnswer = [];
this.currentRadioAnswer = '';
}
} else {
this.currentSelectAnswer = [];
this.currentRadioAnswer = '';
}
},
commitExam() {
const submitData = Object.values(this.hasAnswerList);
let submitWriteLength = 0;
submitData.forEach(each=>{
if (each.answerOptionId.length > 0) {
submitWriteLength++;
}
});
if (submitWriteLength < this.questionList.length) {
this.$confirm(`测试未完成,是否确认交卷?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.submitConfirmExam(submitData);
});
} else {
this.submitConfirmExam(submitData);
}
},
submitConfirmExam(submitData) {
this.loading = true;
submitPracticeQuestionData('drts', {mode:'02', theoryAnswers:submitData}).then(res=>{
this.loading = false;
this.isResult = true;
this.$message.success('提交成功');
const writeList = res.data.filter(wrong=>{
return wrong.answerOptionId && wrong.answerOptionId.length > 0;
});
this.theoryExamWrongList = writeList.filter(wrong=>{
return wrong.correct == false;
});
this.resultScore = writeList.reduce((prev, cur, index, arr)=>{
return prev.score == undefined ? prev + cur.score : prev.score + cur.score;
});
this.getWrongDataOption();
}).catch(()=>{
this.$message.error('提交失败,请稍后再试');
});
},
getWrongDataOption() {
const wrongList = this.theoryExamWrongList[this.wrongQuestionNum].answerOptionId;
if (wrongList.length > 1) {
this.currentSelectAnswer = wrongList;
} else {
this.currentRadioAnswer = wrongList[0];
}
},
wrongCorrectAnswer() {
let correctAnswer = '';
const wrongList = this.theoryExamWrongList[this.wrongQuestionNum].question.optionList;
wrongList.forEach((choice, index)=>{
if (choice.correct) {
correctAnswer += this.choiceTypeList[index] + '、' + choice.content + ' ';
}
});
return correctAnswer;
},
checkNextButton() {
if (this.questionList.length > 0) {
@ -163,7 +328,7 @@ export default {
},
commitQuestion() {
if (this.mode == 'practice') {
this.currentCorrectAnswer = [];
const currentCorrectAnswer = [];
this.correctAnswer = '';
this.answerIsCorrect = false;
const question = this.questionList[this.currentQuestionNum];
@ -172,18 +337,18 @@ export default {
options.forEach((choice, index)=>{
if (choice.correct) {
this.correctAnswer += this.choiceTypeList[index] + '、' + choice.content + ' ';
this.currentCorrectAnswer.push(choice.id);
currentCorrectAnswer.push(choice.id);
}
});
if (this.currentRadioAnswer) {
if (this.currentRadioAnswer == this.currentCorrectAnswer.toString()) {
if (this.currentRadioAnswer == currentCorrectAnswer.toString()) {
this.answerIsCorrect = true;
} else {
this.answerIsCorrect = false;
}
}
if (this.currentSelectAnswer.length > 0) {
if (this.currentCorrectAnswer.toString() == this.currentSelectAnswer.sort().toString()) {
if (currentCorrectAnswer.toString() == this.currentSelectAnswer.sort().toString()) {
this.answerIsCorrect = true;
} else {
this.answerIsCorrect = false;
@ -198,6 +363,16 @@ export default {
}
},
changeAnswer(data) {
if (this.isTest) {
let answerOptionId = [];
if (data instanceof Array) {
answerOptionId = data;
} else {
answerOptionId = [data];
}
this.hasAnswerList[this.currentQuestionNum].answerOptionId = answerOptionId;
document.querySelector('#eachQuestionNum' + this.currentQuestionNum).classList.add('hasSelect');
}
}
}
};
@ -205,7 +380,7 @@ export default {
<style lang="scss" scoped>
.theoryExamBody{
width: 800px;
height: 400px;
height: 460px;
border: 1px #ccc solid;
position: absolute;
left: 50%;
@ -234,6 +409,12 @@ export default {
.theoryExamBodyRT{margin-top: 5px;margin-left: 25px;}
.theoryExamQuestionList{
margin-top: 10px;
height: 360px;
overflow:auto;
padding-left: 10px;
width: 256px;
}
.theoryExamWrongQuestionList{
height: 320px;
overflow:auto;
padding-left: 10px;
@ -295,7 +476,7 @@ export default {
line-height: 160%;
}
.choiceList{
margin-top:20px;
margin-top:10px;
display: inline-block;
margin-left: 15px;
}
@ -304,12 +485,11 @@ export default {
margin-top: 15px;
}
.correctAnswer{
margin-left: 10px;
margin-top: 20px;
}
.buttonList{
position: absolute;
bottom: 25px;
bottom: 30px;
left: 20px;
}
.prevAndNext{
@ -325,6 +505,7 @@ export default {
font-size: 25px;
display: inline-block;
float: left;
margin-left:10px;
}
.practicecorrectAnswer{
vertical-align: top;
@ -334,6 +515,53 @@ export default {
margin-left: 8px;
margin-top: 3px;
}
.hasSelect{
background: #409eff;
color: #fff;
}
.theoryExamScore{
margin-left: 20px;
margin-top: 10px;
font-size: 15px;
}
.theoryExamWrongList{}
.theoryExamWrongListL{
width: 500px;
display: inline-block;
float: left;
height: 100%;
position: relative;
padding-left: 20px;
padding-right: 20px;
padding-top: 5px;
}
.theoryExamWrongListR{
width: 277px;
display: inline-block;
height: 100%;
}
.theoryExamWrongListName{
margin-left: 20px;
margin-top: 15px;
font-size: 15px;
font-weight: bold;
color: #ff3737;
margin-bottom: 5px;
}
.eachQuestionNum.active{
background: #67c23a;
color: #fff;
}
.resultScoreStyle{
color: #f00;
font-size: 17px;
}
.examTips{
position: absolute;
bottom: 5px;
left: 22px;
color:#000;
}
</style>
<style lang="scss">
.theoryExam .el-dialog.is-fullscreen{