<template>
|
<!-- 此组件用于显示整套试卷·
|
试卷类型包含
|
exam 理论考试
|
paper 模拟考试 知识点练习 -->
|
<view class="container">
|
<!-- 大标题 -->
|
<u-navbar class="header" id="header" height="44" back-icon-color="#fff" title="模拟考试" title-color="#fff"
|
:background="{background: '#103289'}" :custom-back="exitExam">
|
<u-button class="slot-wrap-right" type="primary" size="mini" @click="handleSubmit(1)">交卷
|
</u-button>
|
</u-navbar>
|
|
<!-- 小标题栏 -->
|
<view id="subHeader" :style="{'margin-top': subHeaderTop}">
|
<view class="sub-header" v-if='questionList.length > 0'>
|
<u-tag class="typeTag" :text="answerStatusName" mode="dark" shape="circle" />
|
<view v-if="examDetail.exam.examTime<=0">不限时</view>
|
|
<u-count-down v-if="examDetail.exam.examTime" :timestamp="examDetail.exam.examTime / 1000"
|
:show-days="false" @end="end" @change="change">
|
</u-count-down>
|
|
<span>第
|
{{currentIndex+1}}/{{examDetail.exam.totalQuestion}} 题</span>
|
</view>
|
</view>
|
|
<!-- 答题区域 -->
|
<swiper class="content" :duration='duration' :current='currentIndex' @change='handleSwiperChanged'
|
v-if='questionList.length > 0' :style="{'height':swiperHeight}">
|
<template v-for='item in questionList'>
|
<swiper-item class="content-item">
|
<scroll-view scroll-y :style="{'height':swiperHeight}">
|
<!-- 显示题目的题干 -->
|
<view class="content-title">
|
<rich-text :nodes="item.subjectName"></rich-text>
|
</view>
|
<!-- 以下显示选项 -->
|
<!-- type == 0 单选题 -->
|
<view class="content-solutions" v-if='item.choicesType == 0'>
|
<template v-for='subItem in item.options'>
|
<view class="content-solutions-item"
|
@click="!item.selectedFlag && chooseSolution(item,subItem)">
|
<view class="content-solutions-item-single">
|
{{subItem.optionName}}
|
</view>
|
|
<view
|
:class="item.tempAnswer == subItem.optionName? 'content-solutions-item-select' : ''"
|
class="content-solutions-item-content">{{subItem.optionContent}}</view>
|
</view>
|
</template>
|
</view>
|
|
<!-- type == 1 多选题 -->
|
<view class="content-solutions" v-if='item.choicesType == 1'>
|
<template v-for='subItem in item.options'>
|
<view class="content-solutions-item"
|
@click='!item.selectedFlag && chooseMutiSolution(item,subItem)'>
|
<view class="content-solutions-item-single">
|
{{subItem.optionName}}
|
</view>
|
|
<view
|
:class="item.tempAnswer.indexOf(subItem.optionName) > -1 ? 'content-solutions-item-select' : ''"
|
class="content-solutions-item-content">{{subItem.optionContent}}</view>
|
</view>
|
</template>
|
<u-button v-show="!item.selectedFlag" type="primary" shape="circle"
|
:custom-style="{backgroundColor: '#103289'}" @click="confirm(item)">确认答案
|
</u-button>
|
</view>
|
|
<!-- type == 2 判断题 -->
|
<view class="content-solutions" v-if='item.choicesType == 2'>
|
<template v-for="(judgeItem,judgeIndex) in judgeArr">
|
<view class="content-solutions-judge">
|
<view
|
:class="[item.tempAnswer == judgeItem.name? 'content-solutions-item-select' : '']"
|
class="content-solutions-judge-item"
|
@click="!item.selectedFlag && judgeSolution(item, judgeItem.name)">
|
{{judgeItem.name}}
|
</view>
|
</view>
|
</template>
|
</view>
|
|
<!-- type == 3 实操题 -->
|
<view class="content-solutions" v-if='item.choicesType == 3'>
|
<view style="color: #103289;">
|
您选择的顺序为:<text style="text-decoration: underline;">{{item.tempAnswer}}</text>
|
</view>
|
<template v-for='subItem in item.options'>
|
<view class="content-solutions-item"
|
@click='!item.selectedFlag && chooseMutiSolution(item,subItem)'>
|
<view class="content-solutions-item-single">
|
{{subItem.optionName}}
|
</view>
|
|
<view
|
:class="item.tempAnswer.indexOf(subItem.optionName) > -1 ? 'content-solutions-item-select' : ''"
|
class="content-solutions-item-content">{{subItem.optionContent}}</view>
|
</view>
|
</template>
|
<u-button v-show="!item.selectedFlag" type="primary" shape="circle"
|
:custom-style="{backgroundColor: '#103289'}" @click="pictureConfirm(item)">确认答案
|
</u-button>
|
</view>
|
|
<view class="explain" v-if="item.selectedFlag">
|
<view>
|
<view style="display: flex; justify-content: flex-start; align-items: center;">
|
|
<u-tag style="margin: 0 20rpx;" v-show="item.correctOrError" text="正确"
|
type="success" />
|
<u-tag style="margin: 0 20rpx;" v-show="!item.correctOrError" text="错误"
|
type="error" />
|
|
<view>
|
答案
|
<text style="margin: 0 20rpx;">{{item.answer}}</text>
|
</view>
|
<view>
|
您选择
|
<text style="margin: 0 20rpx;">{{item.tempAnswer}}</text>
|
</view>
|
|
</view>
|
</view>
|
</view>
|
|
</scroll-view>
|
</swiper-item>
|
</template>
|
</swiper>
|
|
<!-- 底部栏 -->
|
<view class="footer" id="footer">
|
<view class="footer-back" @click='handleChangeCurrentSwiper(-1)'>上一题</view>
|
<view class="footer-card" @click="showQuestion = !showQuestion">答题卡</view>
|
<view class="footer-right" @click='handleChangeCurrentSwiper(1)'>下一题</view>
|
</view>
|
|
|
<!-- 答题卡弹出层 -->
|
<modal v-model="showQuestion">
|
<view class='question-modal' :style="{'height': modalHeight}">
|
<view class="question-modal-header" id="questionHeader">
|
答题卡
|
</view>
|
<scroll-view scroll-y class="question-modal-body" :style="{'height': modalContentHeight}">
|
<template v-for="(subItem,subIndex) in queTypeArr">
|
<view class="queTypeName" v-show="queTypeStore[subIndex]>=0">{{subItem.name}}</view>
|
<!-- <u-tag :text="subItem.name" v-show="queTypeStore[subIndex]>0" mode="dark" /> -->
|
<view class="queTypeArea">
|
<template v-for="(item, index) in questionList">
|
<view v-show="item.choicesType == subItem.value">
|
<!-- 未作答 -->
|
<view v-if="!item.selectedFlag"
|
class="question-modal-body-item question-modal-body-item-unselect"
|
@click="handleJumpSwiper(index)">
|
{{index + 1 }}
|
</view>
|
<!-- 回答正确 -->
|
<view v-else-if='item.selectedFlag && item.tempAnswer == item.answer'
|
class="question-modal-body-item question-modal-body-item-right"
|
@click="handleJumpSwiper(index)">{{index + 1 }}</view>
|
<!-- 回答错误 -->
|
<view v-else-if='item.selectedFlag && item.tempAnswer != item.answer'
|
class="question-modal-body-item question-modal-body-item-failed"
|
@click="handleJumpSwiper(index)">{{index + 1 }}</view>
|
</view>
|
</template>
|
</view>
|
</template>
|
</scroll-view>
|
<view class="question-modal-foot" id="questionHeader">
|
|
<view class="ansBlock">
|
<view class="blockItem">
|
<view class="block-right"></view>
|
<view class="">答对</view>
|
</view>
|
<view class="blockItem">
|
<view class="block-wrong"></view>
|
<view class="">答错</view>
|
</view>
|
<view class="blockItem">
|
<view class="block-unansed"></view>
|
<view class="">未答</view>
|
</view>
|
</view>
|
|
</view>
|
</view>
|
</modal>
|
<u-toast ref="uToast" />
|
</view>
|
</template>
|
|
<script>
|
import Modal from './modal.vue'
|
import clock from '@/components/clock/clock.vue';
|
export default {
|
data() {
|
return {
|
sleepTime:2000,
|
subHeaderTop: 0,
|
isreadOnly: true,
|
quesModules: [],
|
judgeArr: [{
|
name: '正确',
|
value: '1'
|
},
|
{
|
name: '错误',
|
value: '0'
|
}
|
],
|
queTypeArr: [{
|
name: '单选题',
|
value: '0',
|
be: false,
|
},
|
{
|
name: '多选题',
|
value: '1',
|
be: false,
|
},
|
{
|
name: '判断题',
|
value: '2',
|
be: false,
|
},
|
{
|
name: '实操题',
|
value: '3',
|
be: false,
|
},
|
{
|
name: '简答题',
|
value: '5',
|
be: false,
|
}
|
],
|
currentIndex: 0,
|
swiperHeight: '667px',
|
modalHeight: '500px',
|
modalContentHeight: '400px',
|
showQuestion: false,
|
articleEditorValue: '',
|
eidtOrFinishValue: '编辑笔记',
|
// eidtOrFinish: true,
|
editorText: '',
|
editor: 'editor',
|
}
|
},
|
filters: {
|
// 判断答案状态
|
analysisFilter(item) {
|
if (item == null) {
|
return "暂无解析"
|
} else {
|
return item
|
}
|
}
|
},
|
watch: {
|
|
// 监听currentIndex的变化,改变则提交答案 相同
|
currentIndex(newVal, oldVal) {
|
let that = this
|
// 对各题型的答案进行处理
|
if (that.questionList[oldVal].selectedFlag) {
|
switch (that.questionList[oldVal].choicesType) {
|
case 0:
|
break;
|
case 1:
|
// 多选题
|
// that.questionList[that.currentIndex].tempAnswer = that.questionList[that.currentIndex]
|
// .dualChooseArr.join(',')
|
break;
|
case 2:
|
// 判断题
|
break;
|
case 3:
|
// 实操题
|
break;
|
|
default:
|
}
|
}
|
}
|
},
|
computed: {
|
// swiperHeight(){
|
// uni.getSystemInfo({
|
// success(res) {
|
// return res.windowHeight+'px'
|
// }
|
// })
|
// },
|
examDetail() {
|
return this.$store.state.examDetail
|
},
|
questionList() {
|
return this.$store.state.questionList
|
},
|
queTypeStore() {
|
return this.$store.state.queTypeArr
|
},
|
max() {
|
return this.questionList.length - 1
|
},
|
answerStatusName() {
|
switch (this.questionList[this.currentIndex].choicesType) {
|
case 0:
|
return '单选题'
|
break;
|
case 1:
|
return '多选题'
|
break;
|
case 2:
|
return '判断题'
|
break;
|
case 3:
|
return '实操题'
|
break;
|
case 5:
|
return '简答题'
|
break;
|
default:
|
return '考试题'
|
}
|
}
|
},
|
props: {
|
duration: {
|
type: [String, Number],
|
default: 300
|
},
|
},
|
mounted() {
|
var that = this
|
this.setAnswerHeight()
|
|
},
|
components: {
|
Modal,
|
clock
|
},
|
methods: {
|
exitExam() {
|
uni.redirectTo({
|
url: '/pages/exam/startexam'
|
});
|
},
|
/*设置题目的高度*/
|
setAnswerHeight() {
|
let that = this
|
let tempHeight = 0
|
uni.getSystemInfo({
|
//获取手机屏幕高度信息,让swiper的高度和手机屏幕一样高
|
success: function(res) {
|
tempHeight = res.windowHeight - res.statusBarHeight;
|
|
that.subHeaderTop = res.statusBarHeight + 'px'
|
|
that.modalHeight = res.windowHeight - uni.upx2px(200) + 'px';
|
|
that.modalContentHeight = res.windowHeight - uni.upx2px(360) + 'px';
|
uni.createSelectorQuery().in(that).select("#header").fields({
|
size: true,
|
scrollOffset: true
|
}, (data) => {
|
tempHeight -= data.height;
|
uni.createSelectorQuery().in(that).select("#subHeader").fields({
|
size: true,
|
scrollOffset: true
|
}, (data) => {
|
tempHeight -= data.height;
|
uni.createSelectorQuery().in(that).select("#footer").fields({
|
size: true,
|
scrollOffset: true
|
}, (data) => {
|
tempHeight -= data.height;
|
that.swiperHeight = tempHeight + 'px';
|
}).exec();
|
}).exec();
|
}).exec();
|
}
|
});
|
},
|
/* 跳转指定题目 */
|
handleJumpSwiper(index) {
|
this.currentIndex = index
|
this.showQuestion = false
|
},
|
change(timestamp) {
|
// var that = this
|
if (timestamp == 30) {
|
this.$refs.uToast.show({
|
title: '考试只剩余30s,请注意时间',
|
type: 'warning',
|
duration: 2000,
|
position: 'top'
|
})
|
}
|
// this.$forceUpdate()
|
},
|
end() {
|
this.$refs.uToast.show({
|
title: '考试时间结束,已自动交卷',
|
type: 'warning'
|
})
|
setTimeout(() => {
|
this.handleSubmit(0)
|
}, 2000)
|
},
|
/* 滑动题目 */
|
handleSwiperChanged(event) {
|
this.currentIndex = event.detail.current
|
},
|
/* 调用上一页,下一页 */
|
handleChangeCurrentSwiper(operation) {
|
let max = this.questionList.length - 1
|
let min = 0
|
// 进行翻页
|
if ((this.currentIndex > min && operation < 0) || (this.currentIndex < max && operation > 0)) {
|
this.currentIndex += operation
|
}
|
},
|
/* 选择答案(单选)*/
|
chooseSolution(item, subItem) {
|
// tempAnswer为学生答案
|
item.tempAnswer = subItem.optionName
|
item.selectedFlag = true
|
if (item.tempAnswer == item.answer) item.correctOrError = true
|
// 强制刷新更新视图
|
this.$forceUpdate()
|
// if (this.currentIndex < this.max) {
|
// setTimeout(() => {
|
// this.currentIndex += 1
|
// }, this.sleepTime)
|
// }
|
},
|
/* 选择答案(多选)*/
|
chooseMutiSolution(item, subItem) {
|
let answerIndex = item.dualChooseArr.indexOf(subItem.optionName)
|
if (answerIndex > -1) {
|
// 该选项已经在数组中了
|
item.dualChooseArr.splice(answerIndex, 1)
|
} else {
|
// 该选项不在数组中
|
item.dualChooseArr.push(subItem.optionName)
|
}
|
item.tempAnswer = item.dualChooseArr.join(',')
|
// 强制刷新更新视图
|
|
},
|
// 多选题中的答案确认
|
confirm(item) {
|
if (item.tempAnswer == "")
|
return this.$refs.uToast.show({
|
title: '答案不能为空,请选择',
|
type: 'warning',
|
duration: 2000
|
})
|
|
|
|
let one = item.answer.split(',')
|
let two = item.tempAnswer.split(',')
|
let flag = true
|
if (one.length == two.length) {
|
one.forEach((item) => {
|
if (two.indexOf(item) == -1) {
|
flag = false
|
return
|
}
|
})
|
} else {
|
flag = false
|
}
|
|
|
item.selectedFlag = true
|
|
if (flag != false) item.correctOrError = true
|
|
this.$forceUpdate()
|
|
// if (this.currentIndex < this.max) {
|
// setTimeout(() => {
|
// this.currentIndex += 1
|
// }, this.sleepTime)
|
// }
|
},
|
// 实操题中的答案确认
|
pictureConfirm(item) {
|
if (item.tempAnswer == "") {
|
this.$refs.uToast.show({
|
title: '答案不能为空,请选择',
|
type: 'warning',
|
duration: 2000
|
})
|
|
return
|
}
|
|
let one = item.answer.split(',')
|
let two = item.tempAnswer.split(',')
|
let flag = true
|
if (one.length == two.length) {
|
one.forEach((item, index) => {
|
if (item != two[index]) {
|
flag = false
|
return
|
}
|
})
|
} else {
|
flag = false
|
}
|
|
item.selectedFlag = true
|
|
if (flag != false) item.correctOrError = true
|
|
this.$forceUpdate()
|
|
// if (this.currentIndex < this.max) {
|
// setTimeout(() => {
|
// this.currentIndex += 1
|
// }, this.sleepTime)
|
// }
|
},
|
/* 判断题答案 */
|
judgeSolution(item, value) {
|
// tempAnswer为学生答案
|
item.tempAnswer = value
|
item.selectedFlag = true
|
if (item.tempAnswer == item.answer) item.correctOrError = true
|
// 强制刷新更新视图
|
this.$forceUpdate()
|
// if (this.currentIndex < this.max) {
|
// setTimeout(() => {
|
// this.currentIndex += 1
|
// }, this.sleepTime)
|
// }
|
},
|
/* 交卷 相同 */
|
handleSubmit(submitORimeEnd) {
|
/*submitORimeEnd == 1,submit
|
submitORimeEnd == 0,stimeEnd*/
|
if (submitORimeEnd) {
|
// this.$emit('submit', this.questionList)
|
this.$emit('submit')
|
} else {
|
this.$emit('timeEnd')
|
}
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
.slot-wrap-right {
|
position: absolute;
|
top: 0;
|
left: auto;
|
right: 10px;
|
bottom: 0;
|
margin: auto;
|
font-size: 1.0rem;
|
color: #fff;
|
letter-spacing: 4rpx;
|
/* 如果您想让slot内容占满整个导航栏的宽度 */
|
/* flex: 1; */
|
/* 如果您想让slot内容与导航栏左右有空隙 */
|
/* padding: 0 30rpx; */
|
}
|
|
page {
|
background-color: #FFFFFF;
|
}
|
|
#header,
|
#subHeader {
|
width: 100%;
|
height: 88rpx;
|
line-height: 88rpx;
|
}
|
|
.header {
|
position: relative;
|
text-align: center;
|
letter-spacing: 2rpx;
|
}
|
|
.sub-header {
|
|
// position: fixed;
|
// margin-top: 130rpx;
|
padding: 0 20rpx;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
color: #000;
|
font-size: 32rpx;
|
font-weight: bold;
|
background-color: #FFFFFF;
|
box-shadow: 0 0 5px 1px #eee;
|
}
|
|
.footer {
|
width: 100%;
|
height: 88rpx;
|
padding: 30rpx 25rpx;
|
position: fixed;
|
bottom: 0;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
font-size: 1rem;
|
box-sizing: border-box;
|
color: #4c8af3;
|
box-shadow: 0 0 5px 1px #eee;
|
background-color: #FFFFFF;
|
|
&-card {
|
padding: 10rpx 20rpx;
|
border: 1px solid #103289;
|
border-radius: 15rpx;
|
color: #FFFFFF;
|
background-color: #103289;
|
}
|
}
|
|
|
.content {
|
// margin-top: 130rpx;
|
letter-spacing: 3rpx;
|
|
.typeTag {
|
margin-right: 20rpx;
|
}
|
|
&-item-explain {
|
padding-bottom: 20rpx;
|
font-size: 30rpx;
|
color: #8799a3;
|
letter-spacing: 5rpx;
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
|
&-result {
|
padding: 20rpx 0;
|
|
span {
|
padding-left: 20rpx;
|
color: #39b54a;
|
}
|
}
|
|
&-content {
|
padding: 20rpx 0;
|
}
|
}
|
|
&-item {
|
padding: 0 20rpx;
|
box-sizing: border-box;
|
}
|
|
&-title {
|
margin-bottom: 30rpx;
|
font-size: 32rpx;
|
line-height: 55rpx;
|
color: #000
|
}
|
|
&-solutions {
|
width: 100%;
|
padding-bottom: 20rpx;
|
|
&-item {
|
margin: 40rpx 0;
|
border: 5rpx solid #103289;
|
border-radius: 20rpx;
|
display: flex;
|
align-items: center;
|
font-size: 30rpx;
|
background-color: #103289;
|
|
&-check-content {
|
padding: 35rpx 20rpx;
|
width: 100%;
|
border-radius: 15rpx;
|
color: #103289;
|
background-color: #FFFFFF;
|
}
|
|
&-single {
|
width: 80rpx;
|
text-align: center;
|
color: #FFFFFF;
|
}
|
|
&-content {
|
padding: 35rpx 20rpx;
|
width: 630rpx;
|
border-top-right-radius: 15rpx;
|
border-bottom-right-radius: 15rpx;
|
color: #000;
|
background-color: #FFFFFF;
|
}
|
|
&-select {
|
color: #FFFFFF;
|
background-color: #103289;
|
}
|
}
|
|
&-judge {
|
display: flex;
|
justify-content: space-around;
|
background-color: #FFFFFF;
|
padding: 20rpx;
|
text-align: center;
|
font-size: 30rpx;
|
|
.content-solutions-judge-item {
|
border: 5rpx solid #103289;
|
border-radius: 60rpx;
|
width: 300rpx;
|
padding: 35rpx 20rpx; // 控制单元格的高度
|
}
|
|
.content-solutions-judge-select {
|
color: #FFFFFF;
|
background-color: #103289;
|
}
|
|
}
|
|
&-blank {
|
// border: 5rpx solid #103289;
|
height: 60rpx;
|
width: 90%;
|
// border-radius: 20rpx;
|
background-color: #FFFFFF;
|
padding: 20rpx;
|
}
|
|
&-fillItem {
|
border: 5rpx solid #103289;
|
border-radius: 20rpx;
|
background-color: #FFFFFF;
|
padding: 20rpx;
|
}
|
}
|
|
.explain {
|
border-top: solid #999999 1px;
|
padding: 10rpx;
|
font-size: 28rpx;
|
color: #666666;
|
}
|
|
}
|
|
|
.question-modal {
|
width: 700rpx;
|
padding: 0 40rpx;
|
background-color: #FFFFFF;
|
|
&-header {
|
height: 80rpx;
|
line-height: 80rpx;
|
text-align: center;
|
font-size: 35rpx;
|
color: #333333;
|
border-bottom: 1rpx solid #F0F0F0;
|
}
|
|
&-body {
|
|
// margin-bottom: 100rpx;
|
.queTypeName {
|
font-size: 32rpx;
|
font-weight: bold;
|
|
}
|
|
.queTypeArea {
|
display: flex;
|
flex-direction: row;
|
flex-wrap: wrap;
|
margin-bottom: 20rpx;
|
|
.question-modal-body-item {
|
width: 80rpx;
|
height: 80rpx;
|
margin: 10rpx 22rpx;
|
line-height: 80rpx;
|
font-size: 35rpx;
|
text-align: center;
|
border-radius: 50%;
|
color: #ffffff;
|
// background-color: #0077AA;
|
}
|
}
|
|
&-item-unselect {
|
// color: #FFFFFF;
|
background-color: #bbbbbb;
|
}
|
|
&-item-select {
|
// color: #FFFFFF;
|
background-color: #103289;
|
}
|
|
&-item-failed {
|
color: #FFFFFF;
|
background-color: #982121;
|
}
|
|
&-item-right {
|
color: #FFFFFF;
|
background-color: #39b54a;
|
}
|
|
&-item-unScored {
|
color: #FFFFFF;
|
background-color: #ff9f73;
|
}
|
}
|
|
.question-modal-foot {
|
height: 40rpx;
|
border-top: 1rpx solid #F0F0F0;
|
// position: fixed;
|
// margin-bottom: 0rpx;
|
|
.ansBlock {
|
display: flex;
|
justify-content: center;
|
|
// align-items: center;
|
.blockItem {
|
display: flex;
|
align-items: center;
|
margin: 20rpx;
|
}
|
|
.block-right {
|
width: 40rpx;
|
height: 40rpx;
|
border-radius: 50%;
|
background: #39b54a;
|
margin: 0 10rpx;
|
}
|
|
.block-wrong {
|
width: 40rpx;
|
height: 40rpx;
|
border-radius: 50%;
|
background: #982121;
|
margin: 0 10rpx;
|
}
|
|
.block-unansed {
|
width: 40rpx;
|
height: 40rpx;
|
border-radius: 50%;
|
// border: solid #ffffff 1px;
|
background: #bbbbbb;
|
margin: 0 10rpx;
|
}
|
|
}
|
|
}
|
}
|
|
.right {
|
border: 8rpx solid #39b54a;
|
}
|
|
.wrong {
|
border: 8rpx solid #d81717;
|
}
|
</style>
|