|
@@ -0,0 +1,446 @@
|
|
|
+<template lang="html">
|
|
|
+ <div class="m-right-block fr">
|
|
|
+ <div class="exam-card">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="16" :loading="loading">
|
|
|
+ <div class="exam-content">
|
|
|
+ <el-card class="box-card" v-for="(currentQuestion, aindex) in questionList" :key="aindex" v-show="aindex==cindex">
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
+ <span>第{{aindex+1}}题({{currentQuestion.type|getType}})</span>
|
|
|
+
|
|
|
+ <span style="float: right;">
|
|
|
+ <span> 剩余时间: <span class="ltime">{{end.h}}: {{end.m}}:{{end.s}}</span> </span>
|
|
|
+
|
|
|
+ <el-button type="danger" @click="submitPaper" class="ml20">交卷</el-button>
|
|
|
+
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="q-single">
|
|
|
+ <div class="question">
|
|
|
+ 题目 : <span v-html="currentQuestion.title"></span>
|
|
|
+ </div>
|
|
|
+ <!-- 当选题 -->
|
|
|
+ <div class="answer" v-if="currentQuestion.type<3">
|
|
|
+ <el-radio-group v-model="currentQuestion.answer" @change="selectRadio">
|
|
|
+ <el-radio class="answer-item" v-for="(item,index) in currentQuestion.choice"
|
|
|
+ :label="index+1"
|
|
|
+ :key="index">
|
|
|
+ <span class="answer-title">{{transformChar[index]+'、 '+item}}</span>
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 多选题 -->
|
|
|
+ <div class="answer" v-if="currentQuestion.type==3">
|
|
|
+ <el-checkbox-group v-model="currentQuestion.answer" @change="selectCheckBox">
|
|
|
+ <el-checkbox
|
|
|
+ :label="index"
|
|
|
+ v-for="(item,index) in currentQuestion.choice"
|
|
|
+ :key="index"
|
|
|
+ class="answer-item">
|
|
|
+ {{transformChar[index]+'、 '+item}}
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 案例题 -->
|
|
|
+ <div class="answer" v-if="currentQuestion.type==4">
|
|
|
+ <div v-for="(child,cidx) in currentQuestion.child" :key="child.id">
|
|
|
+ {{cidx+1}}小题: <span v-html="child.title"></span>
|
|
|
+
|
|
|
+ <div class="answer" v-if="child.type==3">
|
|
|
+ <el-checkbox-group v-model="currentQuestion.child[cidx].answer" @change="(e)=>{selectCheckBox(e,cidx)}">
|
|
|
+ <el-checkbox
|
|
|
+ :label="index"
|
|
|
+ v-for="(item,index) in child.choice"
|
|
|
+ :key="index"
|
|
|
+ class="answer-item">
|
|
|
+ {{transformChar[index]+'、 '+item}}
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="answer" v-else>
|
|
|
+ <el-radio-group v-model="currentQuestion.child[cidx].answer" @change="(e)=>{selectRadio(e, cidx)}">
|
|
|
+ <el-radio class="answer-item" v-for="(item,index) in child.choice"
|
|
|
+ :label="index+1"
|
|
|
+ :key="index">
|
|
|
+ <span class="answer-title">{{transformChar[index]+'、 '+item}}</span>
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="mark" >
|
|
|
+ <el-checkbox v-model="currentQuestion.marked" @change="changeMark" :checked="currentQuestion.marked">
|
|
|
+ <span class="red">*</span> 题目标注
|
|
|
+ </el-checkbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="page-ctrl">
|
|
|
+ <el-button type="primary" :disabled="currentQuestion.index<1" @click="prevQuestion">上一题</el-button>
|
|
|
+ <el-button type="primary" :disabled="currentQuestion.index>48" @click="nextQuestion">下一题</el-button>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="8" >
|
|
|
+ <div class="card-select">
|
|
|
+ <div>
|
|
|
+ <h3 class="p5">单项选择题</h3>
|
|
|
+ <el-row :gutter="24" class="ml20">
|
|
|
+ <el-col :span="3" v-for="(item,index) in info.answers" :key="index" class="select-item" v-if="item.type==2">
|
|
|
+ <el-button :class="'b-grid '+getStyle(index)" @click="gotoQuestion(index)" >
|
|
|
+ {{index+1}}
|
|
|
+ <span class="red">
|
|
|
+ {{isMarked(index)}}
|
|
|
+ </span>
|
|
|
+ </el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <h3 class="p5">多选题</h3>
|
|
|
+ <el-row :gutter="24" class="ml20">
|
|
|
+ <el-col :span="3" v-for="(item,index) in info.answers" :key="index" class="select-item" v-if="item.type==3">
|
|
|
+ <el-button :class="'b-grid '+getStyle(index)" @click="gotoQuestion(index)" >
|
|
|
+ {{index+1}}
|
|
|
+ <span class="red">
|
|
|
+ {{isMarked(index)}}
|
|
|
+ </span>
|
|
|
+ </el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <h3 class="p5">判断题</h3>
|
|
|
+ <el-row :gutter="24" class="ml20">
|
|
|
+ <el-col :span="3" v-for="(item,index) in info.answers" :key="index" class="select-item" v-if="item.type==1">
|
|
|
+ <el-button :class="'b-grid '+getStyle(index)" @click="gotoQuestion(index)" >
|
|
|
+ {{index+1}}
|
|
|
+ <span class="red">
|
|
|
+ {{isMarked(index)}}
|
|
|
+ </span>
|
|
|
+ </el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <h3 class="p10" v-if="isAnli">案例题</h3>
|
|
|
+ <el-row :gutter="24" class="ml20">
|
|
|
+ <el-col :span="3" v-for="(item,index) in info.answers" :key="index" class="select-item" v-if="item.type==4">
|
|
|
+ <el-button :class="'b-grid '+getStyle(index)" @click="gotoQuestion(index)" >
|
|
|
+ {{index+1}}
|
|
|
+ <span class="red">
|
|
|
+ {{isMarked(index)}}
|
|
|
+ </span>
|
|
|
+ </el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <my-dialog style="margin-top:20vh" :dialogVisible="dialogVisible" :info="info" :start="start" :end="end" @leavePage="leavePage" >
|
|
|
+
|
|
|
+
|
|
|
+ </my-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { Message, MessageBox } from "element-ui";
|
|
|
+import {httpServer } from "@/components/httpServer/httpServer.js";
|
|
|
+import md5 from 'js-md5';
|
|
|
+import { getTime, packTime, time2str, saveExam, getExam,getSelect,delExam } from "./components/util.js";
|
|
|
+import headline from "./components/headline.vue";
|
|
|
+import myDialog from "./components/my-dialog.vue";
|
|
|
+const defAnswer = [false,false,false,false,false];
|
|
|
+
|
|
|
+export default {
|
|
|
+ components:{
|
|
|
+ headline,
|
|
|
+ myDialog
|
|
|
+ },
|
|
|
+ filters:{
|
|
|
+ getType( val ){
|
|
|
+ const d = {1:'判断题', 2:'单选题', 3:'多选题', 4:'案例题'}
|
|
|
+ return d[val]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ uuid:0,
|
|
|
+ examId:0,
|
|
|
+ groupId:0,
|
|
|
+ startExam: false,
|
|
|
+ dialogVisible: false,
|
|
|
+ info: {},
|
|
|
+ id:'',
|
|
|
+ index:0,
|
|
|
+ cindex:0,
|
|
|
+ loading: false,
|
|
|
+ isAnli: false,
|
|
|
+ questionList: [],
|
|
|
+ answers:{},
|
|
|
+ questionLen: 0,
|
|
|
+ questionType: '单选题',
|
|
|
+ textarea: "",
|
|
|
+ radio: "",
|
|
|
+ checked:defAnswer,
|
|
|
+ getSelect,
|
|
|
+ time2str,
|
|
|
+ questionId: 0,
|
|
|
+ startTime: "",
|
|
|
+ endTime: "",
|
|
|
+ transformChar: ["A", "B", "C", "D","E"],
|
|
|
+ start: { h: 0, m: 0, s: 0 },
|
|
|
+ end: { h: 0, m: 0, s: 0 },
|
|
|
+ timer: 0,
|
|
|
+ commitMap:{},
|
|
|
+ loadCache:{ },
|
|
|
+ onblurTime: 0
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ isMarked(val){
|
|
|
+ if( val>= this.questionList.length || val < 0 ) return '';
|
|
|
+ return this.questionList[val].marked?'*':'';
|
|
|
+ },
|
|
|
+ initTimer() {
|
|
|
+ let courseId = this.info.courseId;
|
|
|
+ let leftTime = this.info.startTime +this.info.duration -getTime();
|
|
|
+ if (leftTime < 0) return;
|
|
|
+ if (this.timer) {
|
|
|
+ window.clearInterval(this.timer);
|
|
|
+ }
|
|
|
+ this.tickTimer( courseId );
|
|
|
+ this.timer = window.setInterval(() => {
|
|
|
+ this.tickTimer( courseId );
|
|
|
+ }, 1000);
|
|
|
+ },
|
|
|
+ tickTimer( courseId ) {
|
|
|
+ let nowSec = getTime();
|
|
|
+ let {startTime, duration} = this.info;
|
|
|
+ let timeLast = startTime+duration -nowSec;
|
|
|
+ this.end = packTime(timeLast);
|
|
|
+ this.start = packTime( startTime );
|
|
|
+ if (timeLast < 0) {
|
|
|
+ window.clearInterval(this.timer);
|
|
|
+ this.dosubmit(answer);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ doLoadQuestion( index, item ){
|
|
|
+ item.choice = [];
|
|
|
+ this.cindex = index;
|
|
|
+ for( let i=0;i<6;i++){
|
|
|
+ let mkey = "answer"+i
|
|
|
+ if(item[mkey] ) item.choice.push( item[mkey] );
|
|
|
+ }
|
|
|
+ if( item.type == 4){
|
|
|
+ for ( let i in item.child){
|
|
|
+ let child = item.child[i]
|
|
|
+ child.choice = [];
|
|
|
+ for( let i=0;i<6;i++){
|
|
|
+ let mkey = "answer"+i
|
|
|
+ if(child[mkey] ) child.choice.push( child[mkey] );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ item.child = []
|
|
|
+ }
|
|
|
+ console.log("index", index, item.type, item.radio, item.answer)
|
|
|
+ this.questionList[index] = item
|
|
|
+ },
|
|
|
+ loadQuestion( index ) {
|
|
|
+ let item = this.questionList[index];
|
|
|
+ item.index = index;
|
|
|
+ if( !item.title ){
|
|
|
+ let {id} = item;
|
|
|
+ this.loading= true;
|
|
|
+ httpServer("course.loadAnswer", {id} ).then(res => {
|
|
|
+ this.loading= false;
|
|
|
+ if( res.code != 200) return;
|
|
|
+ item = Object.assign( item, res.data )
|
|
|
+ let childs = res.data.child;
|
|
|
+ if( item.type == 4){
|
|
|
+ item.child = childs.map( v=>{
|
|
|
+ if( v.type == 3){ v.answer = [false,false,false,false,false]
|
|
|
+ }else{ v.answer=0 }
|
|
|
+ return v
|
|
|
+ })
|
|
|
+ }else if(item.type == 3){
|
|
|
+ item.answer= [false,false,false,false,false];
|
|
|
+ }else{
|
|
|
+ item.answer = 0;
|
|
|
+ }
|
|
|
+ this.doLoadQuestion( index, item )
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ this.doLoadQuestion( index, item )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeMark(marked){
|
|
|
+ let index = this.currentQuestion.index
|
|
|
+ this.questionList[ index ].marked = marked
|
|
|
+ this.$forceUpdate()
|
|
|
+ },
|
|
|
+ getStyle: function(i) {
|
|
|
+ let item = this.questionList[i];
|
|
|
+ let select = getSelect( item.answer )
|
|
|
+ let cls = ""
|
|
|
+ if( i == this.cindex) cls+='select '
|
|
|
+ cls+=(select ? "finish" : "unfinish");
|
|
|
+ return cls
|
|
|
+ },
|
|
|
+ leavePage(){
|
|
|
+ let courseId = this.info.courseId
|
|
|
+ this.timer && window.clearInterval(this.timer);
|
|
|
+ delExam( )
|
|
|
+ this.$router.push(`/center/play/${courseId}`);
|
|
|
+ },
|
|
|
+ submitPaper() {
|
|
|
+ let that = this
|
|
|
+ MessageBox({
|
|
|
+ title: "确认交卷",
|
|
|
+ message: "是否确认交卷",
|
|
|
+ showCancelButton: true,
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ beforeClose: (action, instance, done) => {
|
|
|
+ if (action === "confirm") {
|
|
|
+ instance.confirmButtonLoading = true;
|
|
|
+ instance.confirmButtonText = '提交中...';
|
|
|
+ that.dosubmit(done);
|
|
|
+ done();
|
|
|
+ instance.confirmButtonLoading = false;
|
|
|
+ that.dialogVisible = true;
|
|
|
+
|
|
|
+ } else{
|
|
|
+ done();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ dosubmit( cb ) {
|
|
|
+ let param = { examId: this.info.examId, result: { }};
|
|
|
+ for( let i in this.questionList){
|
|
|
+ let item = this.questionList[i];
|
|
|
+ if(item.type!= 4){
|
|
|
+ let select = getSelect(item.answer);
|
|
|
+ if( select) param.result[item.id] =select ;
|
|
|
+ }else{
|
|
|
+ for( let j in item.child){
|
|
|
+ if(!item.child[j] || !item.child[j].id) continue;
|
|
|
+ let select = getSelect(item.child[j].answer);
|
|
|
+ if(select) param.result[item.child[j].id] = select;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ httpServer("course.FinishExamTest", param).then(res => {
|
|
|
+ if (res.code == 200) {
|
|
|
+ let { score, useTime } = res.data;
|
|
|
+ this.info.score = score;
|
|
|
+ this.info.useTime = useTime;
|
|
|
+ this.info.isFinish = 1;
|
|
|
+ this.timer && window.clearInterval(this.timer);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ prevQuestion() {
|
|
|
+ let index = this.cindex
|
|
|
+ if( index <1) return
|
|
|
+ this.loadQuestion(index-1);
|
|
|
+ },
|
|
|
+ nextQuestion() {
|
|
|
+ let index = this.cindex
|
|
|
+ if( index >= this.questionList.length - 1) return
|
|
|
+ this.loadQuestion(index+1);
|
|
|
+ },
|
|
|
+ gotoQuestion( index ) {
|
|
|
+ index = parseInt(index);
|
|
|
+ this.loadQuestion(index);
|
|
|
+ },
|
|
|
+ doStartExam( info ){
|
|
|
+ info.groupId = this.groupId||0;
|
|
|
+ this.info = info
|
|
|
+ this.questionList = info.answers||[];
|
|
|
+ this.isAnli = false;
|
|
|
+ for( let i in this.questionList){
|
|
|
+ if( this.questionList[i].type == 4){
|
|
|
+ this.isAnli = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loadQuestion(0);
|
|
|
+ this.startTime = info.startTime;
|
|
|
+ saveExam( this.info, this.questionList );
|
|
|
+ // this.initTimer();
|
|
|
+ },
|
|
|
+ selectRadio( value, cidx ){
|
|
|
+ let index = this.index;
|
|
|
+ let curAnswer = this.questionList[index];
|
|
|
+ if( curAnswer.type == 4 ){
|
|
|
+ this.questionList[index].child[cidx].answer = value;
|
|
|
+ }
|
|
|
+ this.questionList[index].answer = value;
|
|
|
+ saveExam( this.info, this.questionList );
|
|
|
+ this.$forceUpdate()
|
|
|
+ },
|
|
|
+ selectCheckBox(value, cidx){
|
|
|
+ let index = this.index;
|
|
|
+ let curAnswer= this.questionList[index];
|
|
|
+ if( curAnswer.type == 4 ){
|
|
|
+ this.questionList[index].child[cidx].answer = value;
|
|
|
+ }
|
|
|
+ this.questionList[index].answer = value;
|
|
|
+ saveExam( this.info, this.questionList );
|
|
|
+ this.$forceUpdate()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ destroyed(){
|
|
|
+ this.timer && window.clearInterval(this.timer)
|
|
|
+ saveExam( this.info, this.questionList );
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeMount() {
|
|
|
+ let courseId = +this.$route.params.courseId
|
|
|
+ let groupId = +this.$route.query.groupId;
|
|
|
+ this.groupId = groupId;
|
|
|
+ this.courseId = courseId;
|
|
|
+ let info = getExam()
|
|
|
+ let nowSec = getTime()
|
|
|
+
|
|
|
+ if( info.courseId == courseId && info.groupId == groupId&&
|
|
|
+ info.questionList.length>0 &&info.startTime + info.duration > nowSec){
|
|
|
+ this.doStartExam( info )
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let that = this;
|
|
|
+ //
|
|
|
+ httpServer("course.StartExamTest", {courseId, groupId} ).then(res => {
|
|
|
+ if( res.code != 200) return;
|
|
|
+ let info = res.data||{}
|
|
|
+ info.questionList = info.answers.map( v =>{
|
|
|
+ v.marked = false
|
|
|
+ v.answer = 0
|
|
|
+ if(v.type==3) v.answer = [false,false,false,false,false];
|
|
|
+ return v;
|
|
|
+ });
|
|
|
+ that.doStartExam( info );
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="css">
|
|
|
+ @import url("./index.css");
|
|
|
+ @import url("../../../assets/css/base.css");
|
|
|
+</style>
|