YNUtdPlatform/pages/YNEduApp/prac/exercises.vue

622 lines
17 KiB
Vue
Raw Normal View History

2024-08-13 19:03:13 +08:00
<template>
<view class="wrapper">
<div class="top-time">已用时间 {{ usedTime }}</div>
<div class="num-wrapper">
<div class="correct">
<u-icon name="/static/images/true.png" size="15" />
<div class="num">{{ correctNum }}</div>
</div>
<div class="error">
<u-icon name="/static/images/error.png" size="15" />
<div class="num">{{ errorNum }}</div>
</div>
<div class="total" @click="openSelect">
<u-icon name="/static/images/quanbufenlei.png" size="15" />
<div class="num">{{ currentIndex + 1 }}/{{ questionList.length }}</div>
</div>
</div>
<div class="question-wrapper" v-for="(item, index) in questionList" :key="index" v-show="index == currentIndex">
<div v-if="item.type !== 2">
<div class="title">{{ index + 1 }}. {{ item.title }}{{ item.type == 3 ? '(判断题)' : '(单选题)' }}</div>
<u--image
v-if="item.img"
:showLoading="true"
:src="item.img"
width="60px"
height="60px"
style="margin-bottom: 10px"
@click="clickImg"
/>
<div class="options">
<div
class="option"
v-for="(option, index) in item.options"
:key="index"
@click="handleOption(option, index)"
:class="{ active: option.isCorrect || option.isError }"
>
<div class="label">{{ option.value }}.{{ option.label }}</div>
<u-icon v-if="option.isCorrect" name="/static/images/对.png" size="25" />
<u-icon v-if="option.isError" name="/static/images/错.png" size="25" />
</div>
</div>
<div v-if="item.isSelect">
<div>正确答案{{ item.answer }}</div>
<div>你的答案{{ item.select }}</div>
<div v-if="item.analysis">
<div class="analysis">答案解析</div>
<div class="analysis-container">{{ item.analysis }}</div>
</div>
</div>
</div>
<!-- 多选 -->
<div v-else-if="item.type === 2">
<div class="title">{{ index + 1 }}. {{ item.title }}多选题</div>
<div class="options">
<div
class="option"
v-for="(option, index) in item.options"
:key="index"
@click="handleCheckbox(option, index)"
:class="{ active: option.isCheck }"
>
<div class="label">{{ option.value }}.{{ option.label }}</div>
<u-icon v-if="option.isCorrect" name="/static/images/对.png" size="25" />
<u-icon v-if="option.isError" name="/static/images/错.png" size="25" />
</div>
</div>
<div class="btn">
<u-button
v-show="item.options.some(option => option.isCheck)"
text="选好了"
shape="circle"
size="small"
color="linear-gradient(to right, rgba(47, 195, 255, 1), rgba(5, 70, 173, 1))"
@click="handleOk"
/>
</div>
<div v-if="item.isSelect">
<div>正确答案{{ item.answer.join('、') }}</div>
<div>你的答案{{ item.select.join('、') }}</div>
<div class="analysis">知识点</div>
<div class="analysis-container">{{ item.knowledge }}</div>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="bottom-btn">
<div class="btn">
<u-button
type="primary"
size="small"
shape="circle"
text="提交"
color="linear-gradient(to right, rgba(250, 223, 103, 1), rgba(207, 163, 14, 1)"
@click="handleSubmit"
/>
</div>
<div class="btn">
<u-button
v-show="currentIndex !== 0"
type="primary"
size="small"
shape="circle"
text="上一题"
color="linear-gradient(to right, rgba(47, 195, 255, 1), rgba(5, 70, 173, 1))"
@click="currentIndex--"
/>
</div>
<div class="btn">
<u-button
v-show="currentIndex !== questionList.length - 1"
type="primary"
size="small"
shape="circle"
text="下一题"
color="linear-gradient(to right, rgba(47, 195, 255, 1), rgba(5, 70, 173, 1))"
@click="currentIndex++"
/>
</div>
</div>
<!-- 提交弹框 -->
<u-modal
:show="showModal"
title="本次答题正确率"
showCancelButton
@cancel="handleClose"
@confirm="handleConfirm"
cancelText="结束答题"
confirmText="继续答题"
>
<view class="slot-content">
<div class="correctRate">{{ correctRate }}</div>
<div class="modal-container">
<div class="item">
<div class="num">{{ answerNum }}</div>
<div>答题数</div>
</div>
<div class="item">
<div class="num">{{ correctNum }}</div>
<div>正确数</div>
</div>
<div class="item">
<div class="num">{{ usedTime }}</div>
<div>答题时长</div>
</div>
</div>
</view>
</u-modal>
<!-- 题目选择弹框 -->
<u-modal :show="showModalSelect" title="题目选择" @confirm="showModalSelect = false">
<view class="slot-content">
<div class="topic-content">
<div
v-for="(item, index) in questionList"
:key="index"
class="topic-wrapper"
:class="{ correct: item.isCorrect, error: item.isError }"
@click="currentIndex = index"
>
<div v-if="currentIndex == index">*</div>
<div class="topic">{{ index + 1 }}</div>
</div>
</div>
</view>
</u-modal>
</view>
</template>
<script>
export default {
data() {
return {
showModal: false,
showModalSelect: false,
// 正确率
correctRate: '80%',
// 已用时间 - 计时器 - 用于显示已用时间 格式 00:00:00
usedTime: '00:00:00',
// 正确题数
correctNum: 0,
// 错误题数
errorNum: 0,
// 答题数
answerNum: 0,
// 当前题目索引
currentIndex: 0,
// 题目列表
questionList: [
// 单选题
{
type: 1,
title: '只有发生在短路事故时或者在负荷电流较大时,变流器中才会有足够的二次电流作为继电保护跳闸之用。',
options: [
{ label: '变流器供给操作电源', value: 'A' },
{ label: '交流电压供给操作电源', value: 'B' },
{ label: '直流操作电源', value: 'C' },
{ label: '选项4', value: 'D' }
],
answer: 'A',
// 答案分析
analysis: '这是答案解析'
},
// 多选题
{
type: 2,
title:
'只有发生在短路事故时或者在负荷电流较大时,变流器中才会有足够的二次电流作为继电保护跳闸之用。(多选题)',
options: [
{ label: '变流器供给操作电源', value: 'A' },
{ label: '交流电压供给操作电源', value: 'B' },
{ label: '直流操作电源', value: 'C' },
{ label: '选项4', value: 'D' }
],
answer: ['A', 'B'],
// 知识点
knowledge: '这是知识点'
},
// 判断题
{
type: 3,
title:
'只有发生在短路事故时或者在负荷电流较大时,变流器中才会有足够的二次电流作为继电保护跳闸之用。(判断题)',
options: [
{ label: '正确', value: 'A' },
{ label: '错误', value: 'B' }
],
answer: 'A'
},
// 带图片单选题
{
type: 4,
title:
'只有发生在短路事故时或者在负荷电流较大时,变流器中才会有足够的二次电流作为继电保护跳闸之用。(单选题)',
img: '/static/images/题目-bg.png',
options: [
{ label: '变流器供给操作电源', value: 'A' },
{ label: '交流电压供给操作电源', value: 'B' },
{ label: '直流操作电源', value: 'C' },
{ label: '选项4', value: 'D' }
],
answer: 'A'
},
{
id: 5
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
},
{
id: 6
}
]
}
},
mounted() {
// 开始计时
this.startTimer()
},
unmounted() {
// 清除计时器
clearInterval()
},
methods: {
// 开始计时 - 实时更新已用时间
startTimer() {
setInterval(() => {
const time = this.usedTime.split(':')
let hours = parseInt(time[0])
let minutes = parseInt(time[1])
let seconds = parseInt(time[2])
seconds++
if (seconds === 60) {
seconds = 0
minutes++
if (minutes === 60) {
minutes = 0
hours++
}
}
this.usedTime = `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${
seconds < 10 ? '0' + seconds : seconds
}`
}, 1000)
},
clickImg() {
uni.previewImage({
urls: [this.questionList[this.currentIndex].img]
})
},
// 处理选项点击事件
handleOption(option, index) {
console.log(option, index)
// 判断是否已经选择过
if (this.questionList[this.currentIndex].isSelect) {
return
} else {
// 标记已选择
this.questionList[this.currentIndex].isSelect = true
// 判断是否正确
if (option.value === this.questionList[this.currentIndex].answer) {
// 当前选择
this.questionList[this.currentIndex].select = option.value
// 给当前题目添加正确标记
this.questionList[this.currentIndex].isCorrect = true
// 正确 - 给当前选项添加正确标记
this.questionList[this.currentIndex].options[index].isCorrect = true
// 正确题数+1
this.correctNum++
} else {
// 当前选择
this.questionList[this.currentIndex].select = option.value
// 给当前题目添加错误标记
this.questionList[this.currentIndex].isError = true
// 错误 - 给当前选项添加错误标记
this.questionList[this.currentIndex].options[index].isError = true
// 并将正确选项标记
this.questionList[this.currentIndex].options.forEach(item => {
if (item.value === this.questionList[this.currentIndex].answer) {
item.isCorrect = true
}
})
// 错误题数+1
this.errorNum++
}
}
},
// 处理多选题选项点击事件
handleCheckbox(option, index) {
console.log('🚀 ~ handleCheckbox ~ option, index:', option, index)
// 给当前点击的增加边框 再次点击取消
if (!option.isCheck) {
this.questionList[this.currentIndex].options[index].isCheck = !option.isCheck
} else {
this.questionList[this.currentIndex].options[index].isCheck = false
}
// 将 isCheck: true 的选项的 value 放入 select 数组
this.questionList[this.currentIndex].select = this.questionList[this.currentIndex].options
.filter(item => item.isCheck)
.map(item => item.value)
console.log(
'🚀 ~ handleCheckbox ~ this.questionList[this.currentIndex].select:',
this.questionList[this.currentIndex].select
)
},
handleOk() {
// 判断是否已经选择过
if (this.questionList[this.currentIndex].isSelect) {
return
} else {
// 标记已选择
this.questionList[this.currentIndex].isSelect = true
const select = this.questionList[this.currentIndex].select
const answer = this.questionList[this.currentIndex].answer
// 判断是否正确
const isCorrect = select.sort().toString() === answer.sort().toString()
if (isCorrect) {
// 正确题数+1
this.correctNum++
// 给当前题目添加正确标记
this.questionList[this.currentIndex].options.forEach(item => {
if (item.isCheck) {
item.isCorrect = true
}
})
// 给正确选项添加标记
this.questionList[this.currentIndex].options.forEach(item => {
if (answer.includes(item.value)) {
item.isCorrect = true
}
})
} else {
// 错误题数+1
this.errorNum++
// 给当前题目添加错误标记
this.questionList[this.currentIndex].isError = true
// 给错误选项添加标记
this.questionList[this.currentIndex].options.forEach(item => {
if (answer.includes(item.value)) {
item.isCorrect = true
} else if (item.isCheck) {
item.isError = true
}
})
}
}
},
// 提交
handleSubmit() {
console.log('提交')
this.showModal = true
},
handleConfirm() {
console.log('确认')
this.showModal = false
},
// 结束答题
handleClose() {
console.log('结束')
this.showModal = false
},
// 打开题目选择弹框
openSelect() {
this.showModalSelect = true
}
}
}
</script>
<style lang="scss" scoped>
.wrapper {
height: 100vh;
background: url('/static/images/题目-bg.png') no-repeat;
background-size: 100% 100%;
.slot-content {
width: 100%;
.correctRate {
font-size: 30px;
text-align: center;
}
.modal-container {
display: flex;
justify-content: space-around;
align-items: center;
margin-top: 20px;
background: #f5f8fb;
border-radius: 5px;
height: 73px;
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #9d9b9b;
.num {
font-size: 20px;
color: #3185f0;
}
}
}
.topic-content {
height: 300px;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
overflow: auto;
.topic-wrapper {
width: 30px;
height: 30px;
border: 1px solid #409eff;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
margin: 10px;
.topic {
font-size: 11px;
color: #409eff;
}
// 正确背景
&.correct {
background: #67d279;
color: #fff;
.topic {
color: #fff;
}
}
// 错误背景
&.error {
background: #f0514c;
color: #fff;
.topic {
color: #fff;
}
}
}
}
}
.bottom-btn {
position: fixed;
bottom: 30px;
left: 0;
display: flex;
justify-content: space-around;
width: 100%;
.btn {
width: 100px;
display: flex;
justify-content: center;
margin: 0 auto;
}
}
.btn {
width: 100px;
display: flex;
justify-content: center;
margin: 0 auto;
margin-top: 40px;
}
.question-wrapper {
padding: 30px;
color: #08428d;
.title {
font-weight: 500;
font-size: 15px;
margin-bottom: 30px;
}
.option {
margin-bottom: 5px;
padding: 0 15px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
background: #ffffff;
border-radius: 8px;
}
.active {
border: 1px solid #1f92df;
}
.analysis {
margin-top: 20px;
font-weight: 700;
}
.analysis-container {
margin-top: 6px;
color: #475583;
text-indent: 1em;
}
}
.top-time {
text-align: center;
font-size: 13px;
color: #fff;
padding-top: 50px;
}
.num-wrapper {
display: flex;
justify-content: center;
margin-top: 20px;
.correct,
.error,
.total {
display: flex;
align-items: center;
font-size: 13px;
margin: 0 6px;
}
.correct {
color: #49ac5a;
}
.error {
color: #e34944;
}
.total {
color: #f08439;
}
.num {
margin-left: 3px;
}
}
}
</style>