YNUtdPlatform/pages/YNEduApp/exam/examination.vue

569 lines
17 KiB
Vue
Raw Normal View History

2024-08-14 18:55:18 +08:00
<template>
<view>
<u-navbar leftIcon="" title="考试" :placeholder="true" />
<div class="content">
<div class="top-content">
<div class="top-wrapper">
<div class="time">
<div>距离考试结束</div>
<div>
<u-count-down
class="count-down"
ref="countDown"
:autoStart="false"
:time="time"
@change="changeCountDown"
/>
</div>
</div>
<div>
<span style="color: #1989fa">{{ currentIndex + 1 }}</span>
/{{ questionList.length }}
</div>
</div>
<div class="center-wrapper">
<div class="answer-wrapper">
<div
class="item-wrapper"
v-for="(item, index) in questionList"
:key="index"
v-show="item.isShow"
@click="handleQuestionNumber(item, index)"
>
<div class="answer-item" :class="{ isActive: item.isActive }">{{ index + 1 }}</div>
</div>
</div>
<div class="unfold" @click="handleUnfold">
{{ isRotating ? '收起' : '展开' }}
<u-icon v-if="!this.isRotating" name="arrow-down-fill" size="10" />
<u-icon v-else name="arrow-up-fill" size="10" />
</div>
</div>
</div>
<!-- 题目 -->
<div class="question-wrapper" v-for="(item, index) in questionList" :key="index" v-show="index == currentIndex">
<div class="question-type-wrapper">
<div class="line" />
<div class="question-type">
<div v-if="item.type == 1">单选题{{ item.score }}</div>
<div v-if="item.type == 2">多选题{{ item.score }}</div>
<div v-if="item.type == 3">判断题{{ item.score }}</div>
</div>
</div>
<div class="question">{{ currentIndex + 1 }}. {{ item.question }}</div>
<div class="options">
<div
class="option"
v-for="(option, optionIndex) in item.options"
:key="optionIndex"
:class="{ isActive: option.isActive }"
@click="handleSelectOption(item, index, option, optionIndex)"
>
<div class="option-item">{{ option.value }}.</div>
<div class="option-content">{{ option.label }}</div>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="bottom-btn">
<div class="btn" v-show="currentIndex != 0">
<u-button size="small" shape="circle" text="上一题" @click="currentIndex--" />
</div>
<div class="btn" v-if="currentIndex !== questionList.length - 1">
<u-button type="primary" size="small" shape="circle" text="下一题" @click="currentIndex++" />
</div>
<div class="btn" v-else>
<u-button type="primary" size="small" shape="circle" text="交 卷" @click="openConfirmModal" />
</div>
</div>
</div>
<!-- 提交弹框 -->
<u-modal
:show="showConfirmModal"
title="提示"
showCancelButton
@cancel="showConfirmModal = false"
@confirm="handleConfirmSubmit"
>
<view class="slot-content">
<view v-if="unDoCount > 0">
本场考试还有
<span style="color: #1989fa; margin: 0 5px">{{ unDoCount }}</span>
题尚未完成
</view>
2024-08-15 17:47:52 +08:00
<view style="text-align: center">确定交卷</view>
2024-08-14 18:55:18 +08:00
</view>
</u-modal>
2024-08-15 17:47:52 +08:00
<u-toast ref="uToast"></u-toast>
2024-08-14 18:55:18 +08:00
</view>
</template>
<script>
2024-08-15 17:47:52 +08:00
import face from '@/uni_modules/mcc-face/index.js'
2024-08-14 18:55:18 +08:00
export default {
data() {
return {
2024-08-15 17:47:52 +08:00
// 切屏次数
screenCount: 0,
2024-08-14 18:55:18 +08:00
showConfirmModal: false,
time: 30 * 60 * 1000,
2024-08-15 17:47:52 +08:00
random1: 0,
random2: 0,
2024-08-20 17:44:53 +08:00
hasScanned: false,
2024-08-14 18:55:18 +08:00
// 答题时间
answerTime: 0,
currentIndex: 0,
// 是否展开
isRotating: false,
// 是否结束
isEnd: false,
// 未做题目数
unDoCount: 0,
// 答题卡
answerCard: [],
// 题目列表
questionList: [
{
id: 1,
// 题目类型
type: 1, // 1: 单选题, 2: 多选题, 3: 判断题
// 分数
score: 2,
// 题目
question: '送配电线路架设工的主要工作是?',
// 选项
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 2,
type: 2,
score: 2,
question: '送配电线路架设工的主要工作是?',
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 3,
type: 3,
score: 2,
question: '送配电线路架设工的主要工作是: 好好工作?',
options: [
{ label: '对', value: 'A' },
{ label: '错', value: 'B' }
]
},
{
id: 11,
// 题目类型
type: 1, // 1: 单选题, 2: 多选题, 3: 判断题
// 分数
score: 2,
// 题目
question: '送配电线路架设工的主要工作是?',
// 选项
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 21,
type: 2,
score: 2,
question: '送配电线路架设工的主要工作是?',
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 31,
type: 3,
score: 2,
question: '送配电线路架设工的主要工作是: 好好工作?',
options: [
{ label: '对', value: 'A' },
{ label: '错', value: 'B' }
]
},
{
id: 12,
// 题目类型
type: 1, // 1: 单选题, 2: 多选题, 3: 判断题
// 分数
score: 2,
// 题目
question: '送配电线路架设工的主要工作是?',
// 选项
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 22,
type: 2,
score: 2,
question: '送配电线路架设工的主要工作是?',
options: [
{ label: '电力设备的安装、调试、维护和检修', value: 'A' },
{ label: '电力设备的安装、调试、维护和检修', value: 'B' },
{ label: '电力设备的安装、调试、维护和检修', value: 'C' },
{ label: '电力设备的安装、调试、维护和检修', value: 'D' }
]
},
{
id: 32,
type: 3,
score: 2,
question: '送配电线路架设工的主要工作是: 好好工作?',
options: [
{ label: '对', value: 'A' },
{ label: '错', value: 'B' }
]
2024-08-15 17:47:52 +08:00
}
2024-08-14 18:55:18 +08:00
]
}
},
2024-08-15 17:47:52 +08:00
onShow: function () {
if (this.screenCount > 0) {
// 提示切屏次数
this.$refs.uToast.show({
message: '切屏次数: ' + this.screenCount,
duration: 1000
})
}
},
onHide: function () {
this.screenCount++
},
2024-08-14 18:55:18 +08:00
mounted() {
this.getList()
2024-08-15 17:47:52 +08:00
this.random1 = Math.floor(Math.random() * 100000) + 420000 // random1 在 7-13分钟之间
this.random2 = Math.floor(Math.random() * 100000) + 900000 // random2 在 15-19分钟之间
console.log('🚀 ~ mounted ~ this.random1:', this.random1, this.random2)
2024-08-14 18:55:18 +08:00
},
methods: {
// 获取列表
getList() {
if (this.questionList.length > 0) {
this.questionList.forEach((item, index) => {
this.$set(item, 'isShow', index < 7)
this.$set(item, 'isActive', false)
if (item.options) {
item.options.forEach(option => {
this.$set(option, 'isActive', false)
})
}
})
console.log('🚀 ~ this.questionList.forEach ~ this.questionList:', this.questionList)
this.$refs.countDown.start()
}
},
changeCountDown(time) {
// console.log('🚀 ~ changeCountDown ~ time:', time)
this.answerTime =
this.time - (time.days * 24 * 60 * 60 + time.hours * 60 * 60 + time.minutes * 60 + time.seconds) * 1000
2024-08-20 17:44:53 +08:00
// console.log('🚀 ~ changeCountDown ~ this.answerTime:', this.answerTime)
if (this.answerTime > this.random1 && this.answerTime < this.random2 && !this.hasScanned) {
this.openFaceScan()
this.hasScanned = true
} else if (this.answerTime > this.random2 && this.hasScanned) {
this.openFaceScan()
this.hasScanned = false
}
2024-08-14 18:55:18 +08:00
if (this.answerTime == this.time) {
// 提示: 时间结束, 自动提交
this.$refs.uToast.show({
message: '考试时间结束, 系统将自动提交',
duration: 1000
})
this.handleConfirmSubmit()
setTimeout(() => {
this.isEnd = true
}, 1000)
}
},
// 点击题号
handleQuestionNumber(item, index) {
console.log('🚀 ~ handleQuestionNumber ~ item:', item)
this.currentIndex = index
},
// 展开
handleUnfold() {
this.questionList.forEach((item, index) => {
if (index > 6) {
this.$set(item, 'isShow', !item.isShow)
}
})
this.isRotating = !this.isRotating
console.log('🚀 ~ this.questionList.forEach ~ this.isRotating:', this.isRotating)
},
handleSelectOption(item, index, option, optionIndex) {
console.log('🚀 ~ handleSelectOption ~ option:', option, optionIndex)
item.isActive = true
// 如果是单选题与判断题 则只能选中一个 多选题可以选中多个
if (item.type == 1 || item.type == 3) {
this.$set(option, 'isActive', true)
item.options.forEach((option, optIndex) => {
// 除了当前选中的其他都设置为未选中
if (optIndex != optionIndex) {
this.$set(option, 'isActive', false)
}
})
} else {
this.$set(option, 'isActive', !option.isActive)
// 如果所有选项都是未选中状态, 则题目也是未选中状态
let isActive = item.options.some(option => option.isActive)
item.isActive = isActive
}
},
openConfirmModal() {
this.unDoCount = this.questionList.filter(item => !item.isActive).length
this.showConfirmModal = true
},
// 答题卡
handleAnswerCard() {
// 根据questionList.options.isActive 计算答题卡
this.questionList.forEach((item, index) => {
if (item.type == 1 || item.type == 3) {
item.options.forEach(option => {
if (option.isActive) {
this.answerCard.push({
id: item.id,
answer: option.value
})
}
})
} else {
let answer = []
item.options.forEach(option => {
if (option.isActive) {
answer.push(option.value)
}
})
this.answerCard.push({
id: item.id,
answer
})
}
})
},
// 确认提交
handleConfirmSubmit() {
this.handleAnswerCard()
// 停止计时
this.$refs.countDown.pause()
console.log('🚀 ~ handleConfirmSubmit ~ this.answerCard:', this.answerCard, this.answerTime)
this.showConfirmModal = false
uni.navigateTo({
url: '/pages/YNEduApp/exam/examinationDetails'
})
2024-08-15 17:47:52 +08:00
},
// 人脸识别
openFaceScan() {
face.open(['a', 'c'], e => {
console.log('🚀 ~ e-人脸识别:', e)
face.close()
uni.showToast({
title: '人脸识别成功',
icon: 'none'
})
// uni.request({
// url: publicPath + '/backstage/app/uploadPersonPhoto',
// method: 'POST',
// header: {
// 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
// Authorization: 'Bearer ' + uni.getStorageSync('token')
// },
// data: {
// base: e,
// idCard: uni.getStorageSync('idCard'),
// type: 1
// },
// success: res => {
// console.log(JSON.stringify(res))
// if (res.data.resMsg == '上传成功') {
// uni.showToast({
// icon: 'none',
// title: '上传成功'
// })
// } else if (res.data.resMsg == '不符合特征值') {
// uni.showToast({
// icon: 'none',
// title: '不符合人脸特征,请重新录入!'
// })
// } else {
// uni.showToast({
// icon: 'none',
// title: '操作失败,请重试!'
// })
// }
// },
// fail() {}
// })
})
2024-08-14 18:55:18 +08:00
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 10px;
.top-content {
background: #fff;
padding: 10px;
border-radius: 5px;
}
.top-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
.time {
display: flex;
justify-content: flex-start;
}
}
.center-wrapper {
display: flex;
justify-content: space-between;
.unfold {
height: 50px;
line-height: 50px;
text-align: center;
display: flex;
justify-content: center;
}
.answer-wrapper {
width: 86%;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
.item-wrapper {
padding: 5px 5px 0 0;
width: 12%;
height: 45px;
display: flex;
justify-content: center;
align-items: center;
.answer-item {
width: 33px;
height: 33px;
line-height: 33px;
text-align: center;
border-radius: 5px;
background: #f4f9fe;
color: #333;
&.isActive {
background: #1989fa;
}
}
}
}
}
.question-wrapper {
.question-type-wrapper {
margin: 20px 0;
display: flex;
justify-content: flex-start;
align-items: center;
.line {
width: 2px;
height: 11px;
background: #1989fa;
margin-right: 3px;
}
.question-type {
color: #8a8a8a;
}
}
.question {
font-weight: 800;
font-size: 15px;
color: #333333;
}
}
.options {
margin-top: 10px;
.option {
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 10px;
background: #f4f9fe;
border-radius: 5px;
&.isActive {
background: #8cbff1;
color: #fff;
}
.option-item {
width: 33px;
height: 33px;
line-height: 33px;
text-align: center;
color: #333;
}
.option-content {
margin-left: 10px;
color: #333;
}
}
}
.bottom-btn {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #fff;
padding: 15px 0;
display: flex;
justify-content: flex-end;
align-items: center;
.btn {
width: 100px;
margin-right: 10px;
}
}
}
::v-deep .u-count-down__text {
font-weight: 700;
color: #1989fa;
}
</style>