提交 d4bb63c3 authored 作者: 王鹏飞's avatar 王鹏飞

bug fixes

上级 14dd1232
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
</div> </div>
<div class="right"> <div class="right">
<question-numbers <question-numbers
:status="status"
:page="currentGroupPage" :page="currentGroupPage"
:data="currentQuestionGroup" :data="currentQuestionGroup"
:list="numberGroups.length ? numberGroups : questionGroups" :list="numberGroups.length ? numberGroups : questionGroups"
...@@ -66,6 +67,7 @@ import questionNumbers from '@/components/exam/questionNumbers' ...@@ -66,6 +67,7 @@ import questionNumbers from '@/components/exam/questionNumbers'
export default { export default {
components: { questionList, questionNumbers }, components: { questionList, questionNumbers },
props: { props: {
status: { type: Number, default: 1 }, // 1:答题;2:查看;3:批阅
title: { type: String }, title: { type: String },
hasMark: { type: Boolean, default: true }, // 标记 hasMark: { type: Boolean, default: true }, // 标记
hasCollect: { type: Boolean, default: true }, // 收藏 hasCollect: { type: Boolean, default: true }, // 收藏
...@@ -259,7 +261,7 @@ export default { ...@@ -259,7 +261,7 @@ export default {
}, },
// 组装试题数据 // 组装试题数据
genQuestions(data) { genQuestions(data) {
const { questions, answers = {} } = data const { questions, answers = {}, score_items: scores = {} } = data
if (!questions) return [] if (!questions) return []
this.questionGroups = questions.question_items.reduce((result, question) => { this.questionGroups = questions.question_items.reduce((result, question) => {
if (question.question_list.length) { if (question.question_list.length) {
...@@ -267,17 +269,27 @@ export default { ...@@ -267,17 +269,27 @@ export default {
list = list.map(item => { list = list.map(item => {
let userAnswers = [] let userAnswers = []
let sign = false let sign = false
let scoreItem = {}
if (answers) { if (answers) {
// 大题答案包含所有小题答案 // 大题答案包含所有小题答案
const bigQuestionAnswer = answers[question.question_item_id] const bigQuestionAnswer = answers[question.question_item_id]
const bigQuestionScore = scores[question.question_item_id]
if (bigQuestionAnswer) { if (bigQuestionAnswer) {
// 小题答案 // 小题答案
const questionAnswer = bigQuestionAnswer[item.id] || {} const questionAnswer = bigQuestionAnswer[item.id] || {}
// 小题分数
scoreItem = bigQuestionScore[item.id] || {}
userAnswers = questionAnswer.answer || [] userAnswers = questionAnswer.answer || []
sign = questionAnswer.sign || false sign = questionAnswer.sign || false
if (userAnswers.length) {
scoreItem.answer = scoreItem.is_right ? 1 : 2
} else {
scoreItem.answer = 0
}
} }
} }
return { ...item, user_answer: userAnswers, sign }
return { ...item, user_answer: userAnswers, sign, ...scoreItem }
}) })
result.push(Object.assign({}, question, { question_list: list })) result.push(Object.assign({}, question, { question_list: list }))
}) })
......
...@@ -52,10 +52,10 @@ ...@@ -52,10 +52,10 @@
</div> </div>
</template> </template>
<template v-else> <template v-else>
<!-- <div class="answer-item"> <div class="answer-item" v-if="data.comment">
<div class="answer-item-label">老师点评:</div> <div class="answer-item-label">老师点评:</div>
<div class="answer-item-content">{{ correctAnswerText }}</div> <div class="answer-item-content">{{ data.comment }}</div>
</div> --> </div>
</template> </template>
<div class="answer-item" v-if="data.question_analysis"> <div class="answer-item" v-if="data.question_analysis">
<div class="answer-item-label">解析:</div> <div class="answer-item-label">解析:</div>
......
<template> <template>
<div> <div class="question-numbers">
<div class="order-num"> <div class="question-num">
<div v-for="item in dataList" :key="item.question_item_id"> <div v-for="item in dataList" :key="item.question_item_id">
<div class="tit">{{ item.title }}</div> <div class="tit">{{ item.title }}</div>
<ul> <ul>
<!-- stu1已答 stu2当前 stu3标记 -->
<li <li
v-for="(item, index) in item.question_list" v-for="(item, index) in item.question_list"
class="question-num-item"
:class="genClass(item)" :class="genClass(item)"
:key="index" :key="index"
@click="handleClick(item)" @click="handleClick(item)"
...@@ -17,36 +17,10 @@ ...@@ -17,36 +17,10 @@
</div> </div>
</div> </div>
<slot></slot> <slot></slot>
<ul class="flag-tips" v-if="true"> <ul class="question-num-tips">
<li> <li v-for="(item, index) in questionNum" :key="index">
<div class="circle1"></div> <div class="question-num-tips-item" :class="item.class"></div>
<div class="txt">已答</div> <div class="txt">{{ item.name }}</div>
</li>
<li>
<div class="circle2"></div>
<div class="txt">未答</div>
</li>
<li>
<div class="circle3"></div>
<div class="txt">当前</div>
</li>
<li>
<div class="circle4"></div>
<div class="txt">标记</div>
</li>
</ul>
<ul class="tips-box" v-else>
<li>
<div class="circle1"></div>
<div class="txt">答对</div>
</li>
<li>
<div class="circle2"></div>
<div class="txt">答错</div>
</li>
<li>
<div class="circle3"></div>
<div class="txt">未答</div>
</li> </li>
</ul> </ul>
</div> </div>
...@@ -54,10 +28,33 @@ ...@@ -54,10 +28,33 @@
<script> <script>
export default { export default {
props: { props: {
status: { type: Number, default: 1 }, // 1:答题;2:查看;3:批阅
page: { type: Number, default: 0 }, // 当前大题的页码 page: { type: Number, default: 0 }, // 当前大题的页码
data: { type: Object, default: () => ({}) }, // 当前大题 data: { type: Object, default: () => ({}) }, // 当前大题
list: { type: Array, default: () => [] } // 所有大题 list: { type: Array, default: () => [] } // 所有大题
}, },
data() {
return {
questionNumTips: {
1: [
{ class: 'is-info', name: '已答' },
{ class: 'is-default', name: '未答' },
{ class: 'is-success', name: '当前' },
{ class: 'is-mark', name: '标记' }
],
2: [
{ class: 'is-success', name: '答对' },
{ class: 'is-error', name: '答错' },
{ class: 'is-info', name: '未答' }
],
3: [
{ class: 'is-success', name: '已批阅' },
{ class: 'is-error', name: '未批阅' },
{ class: 'is-info', name: '未答' }
]
}
}
},
computed: { computed: {
dataList() { dataList() {
const results = [] const results = []
...@@ -78,18 +75,34 @@ export default { ...@@ -78,18 +75,34 @@ export default {
} }
}) })
return results return results
},
questionNum() {
return this.questionNumTips[this.status]
} }
}, },
methods: { methods: {
genClass(data) { genClass(data) {
// answer(0:未做,1:正确,2:错误) // answer(0:未做,1:正确,2:错误)
const hasAnswer = Object.prototype.hasOwnProperty.call(data, 'answer') if (this.status === 1) {
// 已做 return {
const isDone = (hasAnswer && data.answer !== 0) || (data.user_answer ? data.user_answer.length : false) 'is-info': data.user_answer ? data.user_answer.length : false, // 已做
return { 'is-success': data.big_num === this.page, // 当前
stu1: isDone, // 已做 'is-mark': data.sign // 标记
stu2: data.big_num === this.page, }
stu3: data.sign }
if (this.status === 2) {
return {
'is-success': data.answer === 1, // 答对
'is-error': data.answer === 2, // 答错
'is-info': data.answer === 0 // 未答
}
}
if (this.status === 3) {
return {
'is-success': data.checked_flag, // 已批阅
'is-error': !data.checked_flag, // 未批阅
'is-info': data.answer === 0 // 未做
}
} }
}, },
handleClick(data) { handleClick(data) {
...@@ -99,39 +112,14 @@ export default { ...@@ -99,39 +112,14 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.info { .question-numbers {
height: 100%;
display: flex; display: flex;
align-items: center; flex-direction: column;
height: 100px;
.shape {
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
}
img {
width: 75px;
// transform: scale(1);
display: block;
}
.right {
margin-left: 22px;
.name {
font-size: 18px;
color: #222222;
line-height: 25px;
}
.code {
font-size: 14px;
color: #222222;
line-height: 20px;
margin-top: 5px;
}
}
} }
.order-num { .question-num {
flex: 1;
padding-top: 20px; padding-top: 20px;
padding-bottom: 90px;
.tit { .tit {
font-size: 12px; font-size: 12px;
color: #999999; color: #999999;
...@@ -144,254 +132,79 @@ export default { ...@@ -144,254 +132,79 @@ export default {
padding: 0; padding: 0;
margin: 0; margin: 0;
flex-wrap: wrap; flex-wrap: wrap;
li {
cursor: pointer;
position: relative;
border-radius: 50px;
width: 24px;
height: 24px;
border: 1px solid #cccccc;
font-size: 14px;
color: #666666;
line-height: 24px;
margin-right: 20px;
margin-bottom: 10px;
text-align: center;
&:nth-child(5n + 5) {
margin-right: 0;
}
&.analy {
&.stu1 {
border: 2px solid #0fc118;
line-height: 22px;
background: #fff;
color: #999;
}
&.stu2 {
border: 2px solid #c01540;
line-height: 22px;
background: #fff;
color: #999;
}
&.stu3 {
color: #fff;
background: #999999;
&::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: none;
border-radius: 50%;
}
}
}
&.stu1 {
background: #999;
border: 1px solid #999;
color: #fff;
}
&.stu2 {
width: 22px;
height: 22px;
line-height: 22px;
border: 2px solid #0fc118;
}
&.stu3 {
&::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #c01540;
border-radius: 50%;
}
}
}
} }
} }
.flag-tips { .question-num-item {
width: 260px; cursor: pointer;
position: fixed; position: relative;
bottom: 60px; border-radius: 50px;
right: 0; width: 24px;
display: flex; height: 24px;
justify-content: space-around; font-size: 14px;
padding: 15px 0 10px; line-height: 24px;
background: #fff; margin-right: 20px;
margin: 0; margin-bottom: 10px;
list-style: none; text-align: center;
li { border: 2px solid #ccc;
.circle1 { color: #666;
width: 24px;
height: 24px; &:nth-child(5n) {
background: #eeeeee; margin-right: 0;
border: 1px solid #cccccc;
border-radius: 50%;
}
.circle1 {
width: 24px;
height: 24px;
border: 1px solid #cccccc;
border-radius: 50%;
}
.circle2 {
width: 24px;
height: 24px;
border: 1px solid #cccccc;
border-radius: 50%;
}
.circle3 {
width: 24px;
height: 24px;
border: 2px solid #0fc118;
border-radius: 50%;
}
.circle4 {
position: relative;
width: 24px;
height: 24px;
border: 1px solid #cccccc;
border-radius: 50%;
&::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #c01540;
border-radius: 50%;
}
}
.txt {
margin-top: 5px;
font-size: 12px;
color: #cccccc;
line-height: 17px;
}
} }
} }
.flag-tips { .question-num-tips {
width: 260px; padding-bottom: 20px;
position: fixed;
bottom: 60px;
right: 0;
display: flex; display: flex;
justify-content: space-around; align-items: center;
padding: 15px 0 10px; justify-content: space-between;
background: #fff; .txt {
margin: 0; margin-top: 5px;
list-style: none; font-size: 12px;
li { color: #ccc;
.circle1 { line-height: 17px;
width: 24px; text-align: center;
height: 24px;
background: #999;
border: 1px solid #999;
border-radius: 50%;
}
.circle2 {
width: 24px;
height: 24px;
border: 1px solid #cccccc;
border-radius: 50%;
}
.circle3 {
width: 24px;
height: 24px;
border: 2px solid #0fc118;
background: rgba(15, 193, 24, 0.1);
border-radius: 50%;
}
.circle4 {
position: relative;
width: 24px;
height: 24px;
border: 1px solid #cccccc;
border-radius: 50%;
&::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #c01540;
border-radius: 50%;
}
}
.txt {
margin-top: 5px;
font-size: 12px;
color: #cccccc;
line-height: 17px;
}
} }
} }
.tips-box { .question-num-tips-item {
width: 260px; cursor: pointer;
position: fixed; position: relative;
bottom: 60px; border-radius: 50px;
right: 0; width: 24px;
display: flex; height: 24px;
justify-content: space-around; font-size: 14px;
padding: 15px 0 10px; line-height: 24px;
background: #fff; text-align: center;
margin: 0; border: 2px solid #ccc;
list-style: none; color: #666;
li { }
&:nth-child(2) { .is-default {
// margin: 0 50px; color: #666;
} border: 2px solid #ccc;
.circle1 { }
width: 24px; .is-info {
height: 24px; color: #fff;
background: #fff; background-color: #999;
border: 2px solid #0fc118; border: 2px solid #999;
border-radius: 50%; }
box-sizing: border-box; .is-success {
} color: #666;
.circle2 { border: 2px solid #0fc118;
width: 24px; }
height: 24px; .is-info.is-success {
border: 2px solid #c01540; color: #fff;
border-radius: 50%; }
box-sizing: border-box; .is-error {
} color: #666;
.circle3 { border: 2px solid #c01540;
width: 24px; }
height: 24px; .is-mark::after {
background: #999999; content: '';
border-radius: 50%; position: absolute;
} top: -1px;
.circle4 { right: -1px;
position: relative; width: 4px;
width: 24px; height: 4px;
height: 24px; background: #c01540;
border: 1px solid #cccccc; border-radius: 50%;
border-radius: 50%;
&::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #c01540;
border-radius: 50%;
}
}
.txt {
margin-top: 5px;
font-size: 12px;
color: #cccccc;
line-height: 17px;
}
}
} }
</style> </style>
<template>
<div>
<div class="answer-box">
<div class="head" id="head-h">
<el-button icon="el-icon-arrow-left" circle @click="$router.back()"></el-button>
<div class="title">答题</div>
<div class="right">
<div class="count">{{ time.examTimeText }}</div>
</div>
</div>
<div class="exam-main" :style="{height: this.contentHeight + 'px'}">
<div class="left">
<question
v-if="Object.keys(questionParams.question).length"
:contentHeight="contentHeight"
:questionParams="questionParams"
ref="confirmBtn"
@isSign="isSign"
></question>
</div>
<div class="right">
<answer-card
:questionParams="questionParams"
@isSign="isSign"
></answer-card>
</div>
</div>
<!-- @click="confirmBtn" -->
<div class="foot" id="foot-h">
<div class="exam-btn">
<!-- <div class="confirm" @click="confirmBtn">查看解析</div> -->
<div
@click="changeIndex('prev')"
:class="this.questionParams.questionIndex !== 0 ? 'active' : ''"
>上一题</div>
<div
:class="questionParams.questionIndex + 1 !== questionParams.question.total_question_count ? 'active' : ''"
@click="changeIndex('next')"
>下一题</div>
</div>
<div class="rigth-btn">
<div class="sign" @click="collectQuestion">
<div :class="questionParams.question.isCollection ? 'icon active' : 'icon'"></div>
<div class="txt">{{ questionParams.question.isCollection ? '已收藏' : '收藏' }}</div>
</div>
<div class="end-exam-btn">
<div class="btn" @click="endExam" v-if="!$route.query.id">交卷</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as api from '@/api/exam.js'
import answerCard from '../../components/answerCard.vue'
import question from '../../components/question.vue'
export default {
components: {
question,
answerCard
},
data() {
return {
time: {
// 考试持续时间
duration: 0,
examTimeText: '00:00:00',
clearTime: null
},
// isExamTimeDate: true,
// 标记
itemSign: false,
// 设置页面高
contentHeight: 0,
// 原数据
beforeChangeData: {},
// 过滤后的数据
afterChangeData: {},
// 题的数据所需的参数
changeTime: 0,
questionParams: {
// 用户选择的选项 --- 提交后台的数据
answerRecord: {},
// 当前题的下标
questionIndex: 0,
// 所有题 和题的信息
question: {},
card: {},
beforeData: {}
}
}
},
mounted() {
// 赋值页面高度
this.contentHeight = parseInt(document.documentElement.clientHeight - (this.getDom('head-h').offsetHeight + this.getDom('foot-h').offsetHeight))
this.getTopic()
},
methods: {
confirmBtn() {
this.$refs.confirmBtn.answerConfirm()
},
// 收藏试题
collectQuestion() {
const data = this.questionParams.question
console.log(data)
data.isCollection
? this.removeCall(data.id, () => {
data.isCollection = false
})
: this.addCall(data.id, () => {
data.isCollection = true
})
},
addCall(id, call) {
api
.addCollection({ question_id: id })
.then(response => {
call(response.list)
})
.finally(() => {
})
},
removeCall(id, call) {
api
.deleteCollection({ type: 2, question_id: id })
.then(response => {
call(response.list)
})
.finally(() => {
})
},
isSign(value) {
this.itemSign = value
},
// 提交考试
endExam() {
this.handlePapers(1)
},
setClock(time) {
let sec = parseInt(time)
console.log(time)
clearInterval(this.time.clearTime)
this.time.clearTime = setInterval(() => {
if (this.$route.query.id) {
this.time.examTimeText = '00:00:00'
return false
}
sec++
this.time.examTimeText = this.secondToDate(sec)
this.time.duration++
}, 1000)
},
secondToDate(result) {
const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
const m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60))
const s = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60))
if (h === 0) {
result = m + ':' + s
} else {
result = h + ':' + m + ':' + s
}
return result
},
addZero(i) {
return i < 10 ? '0' + i : i + ''
},
getDom(id) {
return document.getElementById(id)
},
// 改变题序
changeIndex(type) {
if (type === 'prev') {
this.questionParams.questionIndex > 0 && (this.questionParams.questionIndex--)
} else {
this.questionParams.questionIndex + 1 !== this.questionParams.question.total_question_count && (this.questionParams.questionIndex++)
}
this.changeData()
this.handlePapers()
},
// 获取考卷
getTopic() {
const param = {
type: 1,
is_create: parseInt(this.$route.query.type) === 2 ? 0 : 1,
course_id: this.$route.query.course_id,
chapter_id: this.$route.query.chapter_id
}
api
.getCourseQuestion(param)
.then(response => {
const data = JSON.parse(response.data)
this.beforeChangeData = data.sheet
this.questionParams.beforeData = data.sheet
this.afterChangeData = this.setData(data.sheet.questions.question_items)
this.questionParams.card = this.setData(data.sheet.questions.question_items)
data.sheet.answers !== null && (this.questionParams.answerRecord = data.sheet.answers)
this.$route.query.id && this.$route.query.id.length > 5
? this.analysisInit()
: this.changeData()
this.setClock(data.sheet.duration || 0)
this.time.duration = data.sheet.duration || 0
})
.finally(() => {
})
},
// 重组数据
setData(data) {
let countNum = 0
const type = {
1: '单选题',
2: '多选题',
5: '案例题',
6: '判断题'
}
return data.map(item => {
return item.question_list.map(cItem => {
countNum++
const data = {
q_order: countNum,
question_item_id: item.question_item_id,
question_item_type: item.question_type,
content: cItem.question_content,
id: cItem.id,
options: cItem.question_options,
question_item_title: type[item.question_type],
total_question_count: this.beforeChangeData.questions.total_question_count,
isCollection: cItem.isCollection
}
const qAnswer = Array.isArray(cItem.question_answer) ? cItem.question_answer : cItem.question_answer = [cItem.question_answer]
let optGroup = ''
const findAB = qAnswer.map(qOpt => {
const findIndex = cItem.question_options.findIndex(i => { return i.id === qOpt })
return this.A_Z()[findIndex]
})
data.question_analysis = cItem.question_analysis
optGroup = (findAB.sort().toString().replace(new RegExp(',', 'g'), ''))
data.question_answer = optGroup
if (parseInt(item.question_type) === 5) {
data.common_content = cItem.common_content
data.group_id = cItem.group_id
data.list = this.mergeData(item.question_list, 'group_id')
data.answer_count = cItem.answer_count
}
return data
})
})
},
// ABC
A_Z() {
const result = []
for (let i = 0; i < 26; i++) {
result.push(String.fromCharCode(65 + i))
}
return result
},
// 合并案例题
mergeData(arr, str) {
const _arr = []
let _t = []
let _tmp = null
arr.length && (_tmp = arr[0][str])
for (const i in arr) {
arr[i][str] === _tmp
? _t.push(arr[i])
: (() => {
_tmp = arr[i][str]
_arr.push(_t)
_t = [arr[i]]
})()
}
_arr.push(_t)
return _arr
},
// 点击上一题下一题 答题卡序号
changeData() {
this.afterChangeData.map(item => {
item.map(cItem => {
cItem.q_order === this.questionParams.questionIndex + 1 && (this.questionParams.question = cItem)
})
})
},
// 结果页进入设置默认点击的题
analysisInit() {
this.afterChangeData.map(item => {
const findData = item.find(datas => { return datas.id === this.$route.query.id })
if (findData) {
this.questionParams.questionIndex = findData.q_order - 1
this.questionParams.questions = findData
findData.q_order === 1 && (this.changeData())
}
})
},
// 缓存 提交
handlePapers(n) {
if (!this.$route.query.id) {
const param = {
type: 1,
sheet_id: this.beforeChangeData.id,
status: n || 0,
answers: JSON.stringify(this.questionParams.answerRecord),
duration: this.time.duration
}
api
.setCourseCache(param)
.then(response => {
if (n) {
// replace
this.$router.replace({
path: '/course/chapter/result',
query: Object.assign({}, this.$route.query, { type: 2 })
})
}
})
.finally(() => {
})
}
}
},
computed: {
changeQuestionIndex() {
return this.questionParams.questionIndex
}
},
watch: {
// 监听题的变化
changeQuestionIndex(newV, oldV) {
this.changeData()
}
}
}
</script>
<style lang="scss" scoped>
.answer-box{
width: 100%;
height: 100%;
// background: #f9f9f9;
.head{
border-bottom: 1px solid #ccc;
height: 80px;
background: #FFFFFF;
display: flex;
align-items: center;
padding-left: 40px;
.title{
padding-left: 20px;
font-size: 24px;
font-weight: bold;
color: #222222;
line-height: 80px;
}
.right{
width: 260px;
margin-left: auto;
display: flex;
justify-content: space-around;
align-items: center;
.count{
font-size: 18px;
font-weight: bold;
color: #222222;
}
.time{
display: flex;
.icon{
width: 23px;
height: 23px;
// background: url(../../assets/images/tick.png);
background-size:100% 100%;
}
.mun{
font-size: 18px;
font-weight: bold;
color: #222222;
line-height: 25px;
margin-left: 10px;
}
}
}
}
.exam-main{
display: flex;
.left{
background: #fff;
flex: 1;
padding: 10px 20px 0 53px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
.right{
border-left: 1px solid #ccc;
position: relative;
width: 220px;
background: #fff;
padding: 0 20px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
}
.foot{
border-top: 1px solid #ccc;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
background: #FFFFFF;
display: flex;
align-items: center;
.exam-btn{
display: flex;
padding-left: 40px;
cursor: pointer;
.confirm{
width: 140px;
height: 40px;
background: #C01540;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
color: #FFFFFF;
line-height: 40px;
text-align: center;
}
div{
width: 100px;
height: 40px;
border-radius: 4px;
border: 1px solid #CCCCCC;
font-size: 14px;
font-weight: bold;
color: #999999;
line-height: 40px;
text-align: center;
margin-right: 20px;
&.active{
background: #C01540;
border-radius: 4px;
color: #fff;
}
}
}
.rigth-btn{
display: flex;
margin-left: auto;
.end-exam-btn{
background: #fff;
height: 62px;
margin-top: -2px;
border-left: 1px solid #ccc;
width: 260px;
display: flex;
justify-content: center;
align-items: center;
.btn{
cursor: pointer;
width: 200px;
height: 40px;
background:#c01540;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
color: #fff;
line-height: 40px;
text-align: center;
}
}
.sign{
margin-right: 20px;
margin-top: 8px;
.icon{
margin: 0 auto;
width: 24px;
height: 24px;
background: url(@/assets/images/collection.png);
background-size:100% 100%;
&.active{
background: url(@/assets/images/collection2.png);
background-size:100% 100%;
}
}
.txt{
font-size: 14px;
color: #CCCCCC;
line-height: 20px;
margin-top: 2px;
}
}
}
}
}
</style>
<template> <template>
<exam-card <exam-card
title="课后练习" title="课后练习"
:hasMark="hasMark"
:status="status"
:data="data" :data="data"
:hasCountdown="false" :hasCountdown="false"
@submit="handleSubmit" @submit="handleSubmit"
...@@ -15,6 +17,8 @@ export default { ...@@ -15,6 +17,8 @@ export default {
components: { ExamCard }, components: { ExamCard },
data() { data() {
return { return {
status: 1, // 考试状态
hasMark: true,
data: {} data: {}
} }
}, },
...@@ -35,6 +39,12 @@ export default { ...@@ -35,6 +39,12 @@ export default {
} }
api.getCourseQuestion(param).then(response => { api.getCourseQuestion(param).then(response => {
this.data = JSON.parse(response.data).sheet this.data = JSON.parse(response.data).sheet
// 已提交
const isSubmited = ['1', '2'].includes(this.data.status)
if (isSubmited) {
this.status = 2
this.hasMark = false
}
}) })
}, },
// 返回 // 返回
...@@ -59,9 +69,9 @@ export default { ...@@ -59,9 +69,9 @@ export default {
answers[group.question_item_id] = {} answers[group.question_item_id] = {}
} }
group.question_list.forEach(item => { group.question_list.forEach(item => {
answers[item.question_item_id][item.id] = { answers[group.question_item_id][item.id] = {
sign: item.sign ? item.sign : false, sign: item.sign ? item.sign : false,
answers: item.user_answer answer: item.user_answer
} }
}) })
}) })
......
...@@ -57,8 +57,7 @@ export default { ...@@ -57,8 +57,7 @@ export default {
return `width: ${this.accuracy}%` return `width: ${this.accuracy}%`
} }
}, },
mounted() { mounted() {},
},
methods: { methods: {
goPage(param) { goPage(param) {
const urlParam = this.$route.query const urlParam = this.$route.query
...@@ -76,24 +75,20 @@ export default { ...@@ -76,24 +75,20 @@ export default {
course_id: this.$route.query.course_id, course_id: this.$route.query.course_id,
chapter_id: this.$route.query.chapter_id chapter_id: this.$route.query.chapter_id
} }
api api.getCourseQuestion(param).then(response => {
.getCourseQuestion(param) const data = JSON.parse(response.data)
.then(response => { this.data = data
const data = JSON.parse(response.data) this.accuracy = (parseInt(data.sheet.score) / parseInt(data.sheet.questions.total_score)) * 100
this.data = data })
this.accuracy = parseInt(data.sheet.score) / parseInt(data.sheet.questions.total_score) * 100
})
.finally(() => {
})
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.result-box{ .result-box {
width: 100%; width: 100%;
display: flex; display: flex;
.card-left{ .card-left {
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: 10px 30px 20px; padding: 10px 30px 20px;
...@@ -102,13 +97,13 @@ export default { ...@@ -102,13 +97,13 @@ export default {
margin-right: 10px; margin-right: 10px;
height: 560px; height: 560px;
border-radius: 8px; border-radius: 8px;
.title{ .title {
font-size: 18px; font-size: 18px;
color: #222222; color: #222222;
line-height: 45px; line-height: 45px;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
} }
.chart-box{ .chart-box {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
...@@ -116,63 +111,63 @@ export default { ...@@ -116,63 +111,63 @@ export default {
width: 148px; width: 148px;
// margin: 26px auto 0; // margin: 26px auto 0;
} }
.assess{ .assess {
font-size: 18px; font-size: 18px;
color: #222222; color: #222222;
line-height: 45px; line-height: 45px;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
} }
.assess-box{ .assess-box {
padding-top: 27px; padding-top: 27px;
.prog{ .prog {
width: 350px; width: 350px;
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.line-box{ .line-box {
width: 300px; width: 300px;
width: 300px; width: 300px;
height: 10px; height: 10px;
background: #F9F9F9; background: #f9f9f9;
border-radius: 5px; border-radius: 5px;
.line{ .line {
width: 80%; width: 80%;
height: 10px; height: 10px;
background: linear-gradient(90deg, #F47C46 0%, #F22F48 100%); background: linear-gradient(90deg, #f47c46 0%, #f22f48 100%);
border-radius: 5px; border-radius: 5px;
} }
} }
.icon{ .icon {
width: 41px; width: 41px;
height: 38px; height: 38px;
background: url(@/assets/images/res-icon.png); background: url(@/assets/images/res-icon.png);
background-size: 100% 100%; background-size: 100% 100%;
} }
} }
.text{ .text {
font-size: 14px; font-size: 14px;
color: #222222; color: #222222;
line-height: 20px; line-height: 20px;
text-align: center; text-align: center;
margin: 50px 0 68px 0; margin: 50px 0 68px 0;
} }
.btn{ .btn {
cursor: pointer; cursor: pointer;
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
width: 144px; width: 144px;
height: 40px; height: 40px;
background: #C01540; background: #c01540;
border-radius: 4px; border-radius: 4px;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
color: #FFFFFF; color: #ffffff;
margin: 0 auto; margin: 0 auto;
} }
} }
} }
.card-right{ .card-right {
box-sizing: border-box; box-sizing: border-box;
flex: 1; flex: 1;
background: #fff; background: #fff;
......
<template> <template>
<exam-card <exam-card
:title="title" :title="title"
:status="2"
:groups="questionGroups" :groups="questionGroups"
:numberGroups="numberGroups" :numberGroups="numberGroups"
:hasMark="false" :hasMark="false"
......
<template>
<div>
<div class="answer-box">
<div class="head" id="head-h">
<el-button icon="el-icon-arrow-left" circle @click="$router.back()"></el-button>
<div class="title">模拟考试</div>
<div class="right">
<div class="count">{{ time.examTimeText }}</div>
</div>
</div>
<div class="exam-main" :style="{ height: this.contentHeight + 'px' }">
<div class="left">
<question
v-if="Object.keys(questionParams.question).length"
:contentHeight="contentHeight"
:questionParams="questionParams"
></question>
</div>
<div class="right">
<answer-card :questionParams="questionParams" ref="signHandle"></answer-card>
</div>
</div>
<div class="foot" id="foot-h">
<div class="exam-btn">
<div @click="changeIndex('prev')" :class="this.questionParams.questionIndex !== 0 ? 'active' : ''">
上一题
</div>
<div
:class="questionParams.questionIndex + 1 !== questionParams.question.total_question_count ? 'active' : ''"
@click="changeIndex('next')"
>
下一题
</div>
</div>
<div class="rigth-btn">
<div class="sign" @click="collectQuestion">
<div :class="questionParams.question.isCollection ? 'icon active' : 'icon'"></div>
<div class="txt">{{ questionParams.question.isCollection ? '已收藏' : '收藏' }}</div>
</div>
<div class="sign2" @click="setSign" v-if="!$route.query.id">
<div :class="isSignText() ? 'icon active' : 'icon'"></div>
<div class="txt">{{ isSignText() ? '已标记' : '标记' }}</div>
</div>
<div class="end-exam-btn">
<div class="btn" @click="endExam" v-if="!$route.query.id">交卷</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as api from '@/api/exam.js'
import answerCard from '../../components/answerCard.vue'
import question from '../../components/question.vue'
export default {
components: { question, answerCard },
data() {
return {
time: {
// 考试持续时间
duration: 0,
examTimeText: '',
clearTime: null
},
// isExamTimeDate: true,
// 标记
itemSign: false,
// 设置页面高
contentHeight: 0,
// 原数据
beforeChangeData: {},
// 过滤后的数据
afterChangeData: {},
// 题的数据所需的参数
changeTime: 0,
questionParams: {
// 用户选择的选项 --- 提交后台的数据
answerRecord: {},
// 当前题的下标
questionIndex: 0,
// 所有题 和题的信息
question: {},
card: {},
beforeData: {}
},
handleTime: null
}
},
computed: {
examId() {
return this.$route.query.exam_id
},
changeQuestionIndex() {
return this.questionParams.questionIndex
}
},
watch: {
// 监听题的变化
changeQuestionIndex(newV, oldV) {
this.changeData()
}
},
beforeDestroy() {
// this.handlePapers()
clearInterval(this.handleTime)
clearInterval(this.time.clearTime)
},
mounted() {
this.handleTime = setInterval(() => {
this.handlePapers()
}, 3000)
// 赋值页面高度
this.contentHeight = parseInt(
document.documentElement.clientHeight - (this.getDom('head-h').offsetHeight + this.getDom('foot-h').offsetHeight)
)
this.getTopic()
},
methods: {
isSignText() {
let flag = false
const ansRecord = this.questionParams.answerRecord
const qData = this.questionParams.question
if (Object.values(ansRecord).length) {
ansRecord[qData.question_item_id]
? ansRecord[qData.question_item_id][qData.id]
? ansRecord[qData.question_item_id][qData.id].sign
? (flag = true)
: (flag = false)
: (flag = false)
: (flag = false)
}
return flag
},
// 标记
setSign() {
const data = this.questionParams.question
data.sign ? (data.sign = false) : (data.sign = true)
this.$refs.signHandle.onSignHandle(data.sign)
},
// 收藏试题
collectQuestion() {
const data = this.questionParams.question
if (data.isCollection) {
this.removeCall(data.id, () => {
data.isCollection = false
})
} else {
this.addCall(data.id, () => {
data.isCollection = true
})
}
},
addCall(id, call) {
api.addCollection({ question_id: id }).then(response => {
call(response.list)
})
},
removeCall(id, call) {
api.deleteCollection({ type: 2, question_id: id }).then(response => {
call(response.list)
})
},
// 提交考试
endExam() {
this.handlePapers(1)
},
setClock(time) {
let sec = parseInt(time)
clearInterval(this.time.clearTime)
this.time.clearTime = setInterval(() => {
if (this.$route.query.id) {
this.time.examTimeText = ''
return false
}
sec--
if (sec === 0) {
clearInterval(this.time.clearTime)
this.time.examTimeText = '00:00:00'
this.$alert('考试时间结束,自动提交试卷', '', {
confirmButtonText: '确定',
callback: action => {
this.endExam()
}
})
return false
}
this.time.examTimeText = this.secondToDate(sec)
this.time.duration++
}, 1000)
},
secondToDate(result) {
const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
const m =
Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60)
const s = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60)
if (h === 0) {
result = m + ':' + s
} else {
result = h + ':' + m + ':' + s
}
return result
},
addZero(i) {
return i < 10 ? '0' + i : i + ''
},
getDom(id) {
return document.getElementById(id)
},
// 改变题序
changeIndex(type) {
if (type === 'prev') {
this.questionParams.questionIndex > 0 && this.questionParams.questionIndex--
} else {
this.questionParams.questionIndex + 1 !== this.questionParams.question.total_question_count &&
this.questionParams.questionIndex++
}
this.changeData()
},
// 获取考卷
getTopic() {
const param = {
type: 2,
paper_id: this.examId,
is_create: this.$route.query.id || this.$route.query.is_create === undefined ? 0 : this.$route.query.is_create
}
api.getExamQuestion(param).then(response => {
const data = JSON.parse(response.data)
this.beforeChangeData = data.sheet
this.questionParams.beforeData = data.sheet
let countData = this.filterData(data)
if (this.$route.query.id === 'err') {
const Num = this.countErrNum(countData)
this.questionParams.question.total_question_count = Num
countData = countData.filter(item => {
return item.map(cItem => {
cItem.total_question_count = Num
})
})
}
this.afterChangeData = countData
this.questionParams.card = countData
data.sheet.answers !== null && (this.questionParams.answerRecord = data.sheet.answers)
this.$route.query.id && this.$route.query.id.length > 5 ? this.analysisInit() : this.changeData()
this.setClock(data.sheet.remaining_times)
this.time.duration = data.sheet.duration
})
},
// 计算错题总数
countErrNum(data) {
let countNum = 0
data.map(item => {
item.map(cItem => {
countNum++
})
})
return countNum
},
// 重组数据
setData(data) {
let countNum = 0
const type = {
1: '单选题',
2: '多选题',
5: '案例题',
6: '判断题'
}
return data.map(item => {
return item.question_list.map(cItem => {
countNum++
const data = {
q_order: countNum,
question_item_id: item.question_item_id,
question_item_type: item.question_type,
content: cItem.question_content,
id: cItem.id,
options: cItem.question_options,
question_item_title: type[item.question_type],
total_question_count: this.beforeChangeData.questions.total_question_count,
isCollection: cItem.is_collection
}
// 解析
if (this.$route.query.id) {
if (this.$route.query.id.length > 5 || this.$route.query.id === 'all' || this.$route.query.id === 'err') {
const qAnswer = Array.isArray(cItem.question_answer)
? cItem.question_answer
: (cItem.question_answer = [cItem.question_answer])
let optGroup = ''
const findAB = qAnswer.map(qOpt => {
const findIndex = cItem.question_options.findIndex(i => {
return i.id === qOpt
})
return this.A_Z()[findIndex]
})
data.question_analysis = cItem.question_analysis
optGroup = findAB
.sort()
.toString()
.replace(new RegExp(',', 'g'), '')
data.question_answer = optGroup
}
}
// 案例题
if (parseInt(item.question_type) === 5) {
data.common_content = cItem.common_content
data.group_id = cItem.group_id
data.list = this.mergeData(item.question_list, 'group_id')
data.answer_count = cItem.answer_count
}
// 错题
if (this.$route.query.id === 'err') {
const isRight = this.beforeChangeData.score_items[data.question_item_id][data.id].is_right
if (!isRight) {
return data
} else {
countNum--
}
} else {
return data
}
})
})
},
// ABC
A_Z() {
const result = []
for (let i = 0; i < 26; i++) {
result.push(String.fromCharCode(65 + i))
}
return result
},
// 合并案例题
mergeData(arr, str) {
const _arr = []
let _t = []
let _tmp = null
arr.length && (_tmp = arr[0][str])
for (const i in arr) {
if (arr[i][str] === _tmp) {
_t.push(arr[i])
} else {
_tmp = arr[i][str]
_arr.push(_t)
_t = [arr[i]]
}
}
_arr.push(_t)
return _arr
},
// 点击上一题下一题 答题卡序号
changeData() {
this.afterChangeData.map(item => {
item.map(cItem => {
cItem.q_order === this.questionParams.questionIndex + 1 && (this.questionParams.question = cItem)
})
})
},
// 结果页进入设置默认点击的题
analysisInit() {
this.afterChangeData.map(item => {
const findData = item.find(datas => {
return datas.id === this.$route.query.id
})
if (findData) {
this.questionParams.questionIndex = findData.q_order - 1
this.questionParams.questions = findData
findData.q_order === 1 && this.changeData()
}
})
},
// 缓存 提交
handlePapers(n) {
if (!this.$route.query.id) {
const param = {
sheet_id: this.beforeChangeData.id,
status: n || 0,
answers: JSON.stringify(this.questionParams.answerRecord),
duration: this.time.duration
}
api.setCache(param).then(response => {
if (n) {
this.$router.replace({
path: '/testExam/result'
})
}
})
}
},
filterData(data) {
return this.setData(data.sheet.questions.question_items).map(item => {
return item.filter(is => is)
})
}
}
}
</script>
<style lang="scss" scoped>
.answer-box {
width: 100%;
height: 100%;
// background: #f9f9f9;
.head {
border-bottom: 1px solid #ccc;
height: 80px;
background: #ffffff;
display: flex;
align-items: center;
padding-left: 40px;
.title {
padding-left: 20px;
font-size: 24px;
font-weight: bold;
color: #222222;
line-height: 80px;
}
.right {
width: 260px;
margin-left: auto;
display: flex;
justify-content: space-around;
align-items: center;
.count {
font-size: 18px;
font-weight: bold;
color: #222222;
}
.time {
display: flex;
.icon {
width: 23px;
height: 23px;
// background: url(../../assets/images/tick.png);
background-size: 100% 100%;
}
.mun {
font-size: 18px;
font-weight: bold;
color: #222222;
line-height: 25px;
margin-left: 10px;
}
}
}
}
.exam-main {
display: flex;
.left {
background: #fff;
flex: 1;
padding: 10px 20px 0 53px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
.right {
border-left: 1px solid #ccc;
position: relative;
width: 220px;
background: #fff;
padding: 0 20px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
}
.foot {
border-top: 1px solid #ccc;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
background: #ffffff;
display: flex;
align-items: center;
.exam-btn {
display: flex;
padding-left: 40px;
cursor: pointer;
div {
width: 100px;
height: 40px;
border-radius: 4px;
border: 1px solid #cccccc;
font-size: 14px;
font-weight: bold;
color: #999999;
line-height: 40px;
text-align: center;
margin-right: 20px;
&.active {
background: #c01540;
border-radius: 4px;
color: #fff;
}
}
}
.rigth-btn {
display: flex;
margin-left: auto;
.end-exam-btn {
background: #fff;
height: 62px;
margin-top: -2px;
border-left: 1px solid #ccc;
width: 260px;
display: flex;
justify-content: center;
align-items: center;
.btn {
cursor: pointer;
width: 200px;
height: 40px;
background: #c01540;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
color: #cccccc;
line-height: 40px;
text-align: center;
}
}
.sign {
margin-right: 20px;
margin-top: 8px;
.icon {
margin: 0 auto;
width: 24px;
height: 24px;
background: url(@/assets/images/collection.png);
background-size: 100% 100%;
&.active {
background: url(@/assets/images/collection2.png);
background-size: 100% 100%;
}
}
.txt {
font-size: 14px;
color: #cccccc;
line-height: 20px;
margin-top: 2px;
}
}
.sign2 {
margin-right: 20px;
margin-top: 8px;
.icon {
margin: 0 auto;
width: 24px;
height: 24px;
background: url(@/assets/images/sign.png);
background-size: 100% 100%;
&.active {
background: url(@/assets/images/sign2.png);
background-size: 100% 100%;
}
}
.txt {
font-size: 14px;
color: #cccccc;
line-height: 20px;
margin-top: 2px;
}
}
}
}
}
</style>
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
<div> <div>
<exam-card <exam-card
title="模拟考试" title="模拟考试"
:hasMark="hasMark"
:status="status"
:hasSubmitBtn="!!!this.$route.query.id" :hasSubmitBtn="!!!this.$route.query.id"
:hasCountdown="!!!this.$route.query.id" :hasCountdown="!!!this.$route.query.id"
:data="data" :data="data"
...@@ -19,9 +21,10 @@ export default { ...@@ -19,9 +21,10 @@ export default {
components: { ExamCard }, components: { ExamCard },
data() { data() {
return { return {
data: { status: 1, // 考试状态
cacheAnswerTime: null // 缓存题计时器 hasMark: true,
} data: {},
cacheAnswerTime: null // 缓存题计时器
} }
}, },
computed: { computed: {
...@@ -56,6 +59,9 @@ export default { ...@@ -56,6 +59,9 @@ export default {
this.cacheAnswerTime = setInterval(() => { this.cacheAnswerTime = setInterval(() => {
this.submitExam(0) this.submitExam(0)
}, 3000) }, 3000)
} else {
this.status = 2
this.hasMark = false
} }
}) })
}, },
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<div> <div>
<exam-card <exam-card
title="批阅考卷" title="批阅考卷"
:status="3"
:hasSubmitBtn="false" :hasSubmitBtn="false"
:hasCountdown="false" :hasCountdown="false"
:hasCollect="false" :hasCollect="false"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<div> <div>
<exam-card <exam-card
title="批阅考卷" title="批阅考卷"
:status="3"
:hasSubmitBtn="false" :hasSubmitBtn="false"
:hasCountdown="false" :hasCountdown="false"
:hasCollect="false" :hasCollect="false"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论