2025-01-16 16:35:46 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<!-- 左侧答题卡 -->
|
|
|
|
|
|
<el-col :span="6" :offset="0">
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
|
|
|
<div class="top-content">
|
|
|
|
|
|
<div class="title">答题卡</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-divider></el-divider>
|
|
|
|
|
|
<!-- 正确,错误,未答 三种颜色提示 -->
|
|
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<div class="color-box" style="background-color: #67c23a"></div>
|
|
|
|
|
|
<span>正确</span>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<div class="color-box" style="background-color: #f56c6c"></div>
|
|
|
|
|
|
<span>错误</span>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<div class="color-box" style="background-color: #909399"></div>
|
|
|
|
|
|
<span>未答</span>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<!-- 单选题 -->
|
|
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
|
|
<div style="margin: 5px">单选题</div>
|
|
|
|
|
|
<el-col
|
|
|
|
|
|
:span="4.8"
|
|
|
|
|
|
v-for="(item, index) in questionList.filter(item => item.questionType == 1)"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style="margin-bottom: 5px">
|
|
|
|
|
|
<el-tag v-if="item.isPass" type="success">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isError" type="danger">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isNotAnswer" type="info">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<!-- 多选题 -->
|
|
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
|
|
<div style="margin: 5px">多选题</div>
|
|
|
|
|
|
<el-col
|
|
|
|
|
|
:span="4.8"
|
|
|
|
|
|
v-for="(item, index) in questionList.filter(item => item.questionType == 2)"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style="margin-bottom: 5px">
|
|
|
|
|
|
<el-tag v-if="item.isPass" type="success">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isError" type="danger">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isNotAnswer" type="info">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<!-- 判断题 -->
|
|
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
|
|
<div style="margin: 5px">判断题</div>
|
|
|
|
|
|
<el-col
|
|
|
|
|
|
:span="4.8"
|
|
|
|
|
|
v-for="(item, index) in questionList.filter(item => item.questionType == 3)"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style="margin-bottom: 5px">
|
|
|
|
|
|
<el-tag v-if="item.isPass" type="success">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isError" type="danger">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isNotAnswer" type="info">{{ item.questionIndex }}</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<!-- 简答题 -->
|
|
|
|
|
|
<!-- <el-row :gutter="10" class="mb8">
|
|
|
|
|
|
<div style="margin: 5px">简答题</div>
|
|
|
|
|
|
<el-col :span="4.8" v-for="(item, index) in shortAnswerTopic" :key="index">
|
|
|
|
|
|
<div style="margin-bottom: 5px">
|
|
|
|
|
|
<el-tag v-if="item.isPass" type="success">{{ item.item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isError" type="danger">{{ item.item.questionIndex }}</el-tag>
|
|
|
|
|
|
<el-tag v-if="item.isNotAnswer" type="info">{{ item.item.questionIndex }}</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row> -->
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<!-- 右侧试卷详情 -->
|
|
|
|
|
|
<el-col :span="18" :offset="0">
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
|
|
|
<div class="top-content">
|
|
|
|
|
|
<div class="title">{{ paperData.paperName }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style="margin-left: 10px">共{{ questionList.length }}道练习题</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 题目 -->
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
|
|
|
<div class="question-wrapper">
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="question-list"
|
|
|
|
|
|
v-for="(item, index) in questionList"
|
|
|
|
|
|
:key="item.id"
|
|
|
|
|
|
v-show="index == currentIndex"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="question-type">
|
|
|
|
|
|
<div class="line"></div>
|
|
|
|
|
|
<div class="type">
|
|
|
|
|
|
<div v-if="item.questionType == 1">单选题</div>
|
|
|
|
|
|
<div v-else-if="item.questionType == 2">多选题</div>
|
|
|
|
|
|
<div v-else-if="item.questionType == 3">判断题</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="question-title">{{ index + 1 }}. {{ item.content }}</div>
|
|
|
|
|
|
<div class="question-img-list">
|
|
|
|
|
|
<div class="img" v-for="(img, imgIndex) in item.questionPictureVoList">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:key="imgIndex"
|
|
|
|
|
|
:src="img.url"
|
|
|
|
|
|
:showLoading="true"
|
|
|
|
|
|
width="60px"
|
|
|
|
|
|
height="60px"
|
|
|
|
|
|
:preview-src-list="[img.url]"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="question-item">
|
|
|
|
|
|
<div v-if="item.questionType == 1 || item.questionType == 3">
|
|
|
|
|
|
<!-- 单选题 -->
|
|
|
|
|
|
<el-radio-group v-model="item.radioValue">
|
|
|
|
|
|
<el-radio
|
|
|
|
|
|
:customStyle="{ marginBottom: '8px' }"
|
|
|
|
|
|
v-for="(question, index) in item.questionAnswerVoList"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:label="question.options + '. ' + question.answerOptions"
|
|
|
|
|
|
:name="question.options + '. ' + question.answerOptions"
|
|
|
|
|
|
:disabled="question.disabled"
|
|
|
|
|
|
@change="radioChange(question)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="radio-item">
|
|
|
|
|
|
<div class="radio-name">{{ question.options + '. ' + question.answerOptions }}</div>
|
|
|
|
|
|
<div class="question-img-list">
|
|
|
|
|
|
<div class="img" v-for="(img, imgIndex) in question.questionPictureVoList">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:key="imgIndex"
|
|
|
|
|
|
:src="img.url"
|
|
|
|
|
|
:showLoading="true"
|
|
|
|
|
|
width="60px"
|
|
|
|
|
|
height="60px"
|
|
|
|
|
|
:preview-src-list="[img.url]"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-radio>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="item.questionType == 2">
|
|
|
|
|
|
<!-- 多选题 -->
|
|
|
|
|
|
<el-checkbox-group v-model="item.checkboxValue">
|
|
|
|
|
|
<div v-for="(question, index) in item.questionAnswerVoList">
|
|
|
|
|
|
<el-checkbox
|
|
|
|
|
|
:customStyle="{ marginBottom: '8px' }"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:label="question.options + '. ' + question.answerOptions"
|
|
|
|
|
|
:name="question.options + '. ' + question.answerOptions"
|
|
|
|
|
|
:disabled="question.disabled"
|
|
|
|
|
|
@change="radioChange(question)"
|
|
|
|
|
|
></el-checkbox>
|
|
|
|
|
|
<div class="radio-item">
|
|
|
|
|
|
<div class="question-img-list" style="margin: 10px">
|
|
|
|
|
|
<div class="img" v-for="(img, imgIndex) in question.questionPictureVoList">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:key="imgIndex"
|
|
|
|
|
|
:src="img.url"
|
|
|
|
|
|
:showLoading="true"
|
|
|
|
|
|
width="60px"
|
|
|
|
|
|
height="60px"
|
|
|
|
|
|
:preview-src-list="[img.url]"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-checkbox-group>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 标签 -->
|
|
|
|
|
|
<div class="tag-list">
|
|
|
|
|
|
<el-tag :key="tag.id" v-for="(tag, tagIndex) in item.tagList" style="margin-right: 10px">
|
|
|
|
|
|
{{ tag.name }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div style="padding: 10px">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
shape="circle"
|
|
|
|
|
|
@click="handleOption(item)"
|
|
|
|
|
|
v-show="!item.chooseAnswer"
|
|
|
|
|
|
>
|
|
|
|
|
|
确定选择
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="item.chooseAnswer">
|
|
|
|
|
|
<div style="color: #5ac725" v-if="item.chooseAnswer == item.correctAnswer">回答正确</div>
|
|
|
|
|
|
<div style="color: #ff4d4f" v-else>回答错误</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="answer-wrap" v-if="item.chooseAnswer">
|
|
|
|
|
|
<div class="answer-item">
|
|
|
|
|
|
<div>正确答案</div>
|
|
|
|
|
|
<div style="color: #5ac725">{{ item.correctAnswer1 }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="answer-line"></div>
|
|
|
|
|
|
<div class="answer-item">
|
|
|
|
|
|
<div>已选答案</div>
|
|
|
|
|
|
<div :style="{ color: item.chooseAnswer == item.correctAnswer ? '#5ac725' : '#ff4d4f' }">
|
|
|
|
|
|
{{ item.chooseAnswer1 }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 解析 -->
|
|
|
|
|
|
<div v-if="item.chooseAnswer">
|
|
|
|
|
|
<div style="margin: 20px 0 10px; font-weight: 800">解析:</div>
|
|
|
|
|
|
<div class="analysis">{{ item.analysis }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 按钮 -->
|
|
|
|
|
|
<div class="bottom-wrapper">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
class="btn"
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
shape="circle"
|
|
|
|
|
|
@click="currentIndex--"
|
|
|
|
|
|
:disabled="currentIndex == 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
上一题
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
class="btn"
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
shape="circle"
|
|
|
|
|
|
@click="currentIndex++"
|
|
|
|
|
|
:disabled="
|
|
|
|
|
|
currentIndex == questionList.length - 1 ||
|
|
|
|
|
|
(questionList[currentIndex] && questionList[currentIndex].chooseAnswer == '')
|
|
|
|
|
|
"
|
|
|
|
|
|
>
|
|
|
|
|
|
下一题
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button class="btn" type="primary" size="small" shape="circle" @click="dialogVisible = true">
|
|
|
|
|
|
结束练习
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
<div class="box"></div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
|
2025-02-13 15:47:39 +08:00
|
|
|
|
<span style="margin-left: 15px; font-weight: 800; font-size: 16px" v-preventReClick="3000">
|
|
|
|
|
|
确定退出本次练习吗?
|
|
|
|
|
|
</span>
|
2025-01-16 16:35:46 +08:00
|
|
|
|
<span slot="footer" class="dialog-footer">
|
|
|
|
|
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
2025-01-17 17:22:39 +08:00
|
|
|
|
<el-button type="primary" @click="openDialog2" v-preventReClick="5000">确 定</el-button>
|
2025-01-16 16:35:46 +08:00
|
|
|
|
</span>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
title="练习结果"
|
|
|
|
|
|
:visible.sync="dialogVisible2"
|
|
|
|
|
|
width="30%"
|
|
|
|
|
|
:before-close="handleClose"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
:close-on-press-escape="false"
|
|
|
|
|
|
@close="handleClose"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="exercise-result">
|
|
|
|
|
|
<div class="top-content">本次练习结果</div>
|
|
|
|
|
|
<el-divider></el-divider>
|
|
|
|
|
|
<div class="content">
|
|
|
|
|
|
<div>{{ correctNum + errorNum > 0 ? ((correctNum / (correctNum + errorNum)) * 100).toFixed(0) : 0 }}%</div>
|
|
|
|
|
|
<div>正确率</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="bt-content">
|
|
|
|
|
|
<div class="content-item">
|
|
|
|
|
|
<div>{{ correctNum + errorNum }}</div>
|
|
|
|
|
|
<div>答题数</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="content-item">
|
|
|
|
|
|
<div>{{ correctNum }}</div>
|
|
|
|
|
|
<div>正确题数</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="content-item">
|
|
|
|
|
|
<div>{{ timeCount }}</div>
|
|
|
|
|
|
<div>答题时长</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span slot="footer" class="dialog-footer">
|
2025-01-17 17:22:39 +08:00
|
|
|
|
<el-button type="primary" @click="handleClose" v-preventReClick="5000">确 定</el-button>
|
2025-01-16 16:35:46 +08:00
|
|
|
|
</span>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { lookFile } from '@/utils/bonus'
|
|
|
|
|
|
import { getWebQuestion, updateQuestionAnswer, getWebTestQuestion, wenEndPractice } from '@/api/educTrainLearn'
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
dialogVisible: false,
|
|
|
|
|
|
dialogVisible2: false,
|
|
|
|
|
|
currentIndex: 0,
|
|
|
|
|
|
paperData: {
|
|
|
|
|
|
paperName: '2021年度考试题', // 名称
|
|
|
|
|
|
allQuestionNum: 20, // 总题数
|
|
|
|
|
|
},
|
|
|
|
|
|
correctNum: 0, // 正确题数
|
|
|
|
|
|
errorNum: 0, // 错误题数
|
|
|
|
|
|
time: 0, // 时间
|
|
|
|
|
|
timeCount: '', // 时间 00:00:00
|
|
|
|
|
|
item: {},
|
|
|
|
|
|
opt: {
|
|
|
|
|
|
isStudyTask: false, // 是否学习任务
|
|
|
|
|
|
practiceId: '', // 练习id
|
|
|
|
|
|
practiceType: 1, // 练习类型
|
|
|
|
|
|
lastPracticeQuestionId: '', // 上次练习的题目id
|
|
|
|
|
|
id: 1, // 试卷id/题库id
|
|
|
|
|
|
},
|
|
|
|
|
|
// 题目列表
|
|
|
|
|
|
questionList: [],
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
created() {
|
|
|
|
|
|
this.opt = this.$route.query
|
|
|
|
|
|
console.log('🚀 ~ created ~ this.opt:', this.opt)
|
|
|
|
|
|
// this.item = this.$route.query.row
|
|
|
|
|
|
// this.isStudyTask = this.$route.query.isStudyTask
|
|
|
|
|
|
this.getQuestionList()
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 获取题目列表
|
|
|
|
|
|
async getQuestionList() {
|
|
|
|
|
|
let res = {}
|
|
|
|
|
|
if (!this.opt.isStudyTask) {
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
practiceId: this.opt.id,
|
|
|
|
|
|
practiceType: this.opt.practiceType,
|
|
|
|
|
|
lastPracticeQuestionId: this.opt.lastPracticeQuestionId || '',
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ getQuestionList ~ params:', params)
|
|
|
|
|
|
res = await getWebTestQuestion(params)
|
|
|
|
|
|
this.questionList = res.data.data
|
|
|
|
|
|
if (this.opt.practiceType == 1) {
|
|
|
|
|
|
// 过滤出包含 lastPracticeQuestionId 的题目, lastPracticeQuestionId 是未答题目所有id拼接的字符串
|
|
|
|
|
|
this.opt.lastPracticeQuestionId = this.opt.lastPracticeQuestionId.split(',')
|
|
|
|
|
|
this.questionList = this.questionList.filter(item =>
|
|
|
|
|
|
this.opt.lastPracticeQuestionId.includes(item.questionId)
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
res = await getWebQuestion({ examId: this.opt.id })
|
|
|
|
|
|
this.questionList = res.data
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ 题目列表 ~ res:', res)
|
|
|
|
|
|
this.questionList.forEach((item, index) => {
|
|
|
|
|
|
item.questionIndex = this.$set(item, 'questionIndex', index + 1)
|
|
|
|
|
|
item.isPass = false
|
|
|
|
|
|
item.isError = false
|
|
|
|
|
|
item.isNotAnswer = true
|
|
|
|
|
|
if (item.questionPictureVoList && item.questionPictureVoList.length > 0) {
|
|
|
|
|
|
item.questionPictureVoList.forEach(img => {
|
|
|
|
|
|
img.url = lookFile() + img.pictureUrl
|
|
|
|
|
|
// img.url = lookFile + img.pictureUrl.replace(/\\/g, '/')
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
|
|
|
|
if (item.questionAnswerVoList && item.questionAnswerVoList.length > 0) {
|
|
|
|
|
|
// 添加一个 radiovalue 字段,用于记录用户选择的答案
|
|
|
|
|
|
if (item.questionType == 1 || item.questionType == 3) {
|
|
|
|
|
|
item.radioValue = ''
|
|
|
|
|
|
} else if (item.questionType == 2) {
|
|
|
|
|
|
item.checkboxValue = this.$set(item, 'checkboxValue', [])
|
|
|
|
|
|
}
|
|
|
|
|
|
item.chooseAnswer = ''
|
|
|
|
|
|
item.questionAnswerVoList.forEach(answer => {
|
|
|
|
|
|
if (answer.questionPictureVoList && answer.questionPictureVoList.length > 0) {
|
|
|
|
|
|
// 图片路径拼接
|
|
|
|
|
|
answer.questionPictureVoList.forEach(opt => {
|
|
|
|
|
|
opt.url = lookFile() + opt.pictureUrl
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
console.log('🚀 ~ getQuestionList ~ this.题目列表:', this.questionList)
|
|
|
|
|
|
this.startTimer()
|
|
|
|
|
|
},
|
|
|
|
|
|
// 开启计时器
|
|
|
|
|
|
startTimer() {
|
|
|
|
|
|
this.timer = setInterval(() => {
|
|
|
|
|
|
this.time++
|
|
|
|
|
|
// 时间格式 00:00:00
|
|
|
|
|
|
const hour = Math.floor(this.time / 3600)
|
|
|
|
|
|
const minute = Math.floor((this.time % 3600) / 60)
|
|
|
|
|
|
const second = this.time % 60
|
|
|
|
|
|
this.timeCount = `${hour < 10 ? '0' + hour : hour}:${minute < 10 ? '0' + minute : minute}:${
|
|
|
|
|
|
second < 10 ? '0' + second : second
|
|
|
|
|
|
}`
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
},
|
|
|
|
|
|
radioChange(item) {
|
|
|
|
|
|
console.log('🚀 ~ radioChange ~ item:', item)
|
|
|
|
|
|
},
|
|
|
|
|
|
// 选择选项
|
|
|
|
|
|
handleOption(item) {
|
|
|
|
|
|
console.log('🚀 ~ handleOption ~ item:', item)
|
|
|
|
|
|
if (item.questionType == 1 || item.questionType == 3) {
|
|
|
|
|
|
if (!item.radioValue) {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
message: '请选择答案',
|
|
|
|
|
|
type: 'warning',
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ handleOption ~ 确认选择-单选:', item)
|
|
|
|
|
|
item.chooseAnswer = String(item.radioValue.split('')[0].charCodeAt() - 65)
|
|
|
|
|
|
item.correctAnswer1 = String.fromCharCode(65 + Number(item.correctAnswer))
|
|
|
|
|
|
item.chooseAnswer1 = String.fromCharCode(65 + Number(item.chooseAnswer))
|
|
|
|
|
|
item.questionAnswerVoList.forEach(answer => {
|
|
|
|
|
|
answer.disabled = true
|
|
|
|
|
|
})
|
|
|
|
|
|
// 判断答案是否正确
|
|
|
|
|
|
if (item.chooseAnswer == item.correctAnswer) {
|
|
|
|
|
|
this.correctNum++
|
|
|
|
|
|
item.isPass = true
|
|
|
|
|
|
item.isError = false
|
|
|
|
|
|
item.isNotAnswer = false
|
|
|
|
|
|
if (item.questionType == 1) {
|
|
|
|
|
|
item.scorePerQuestion = this.opt.singleScore
|
|
|
|
|
|
} else if (item.questionType == 3) {
|
|
|
|
|
|
item.scorePerQuestion = this.opt.judgeScore
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.errorNum++
|
|
|
|
|
|
item.isPass = false
|
|
|
|
|
|
item.isError = true
|
|
|
|
|
|
item.isNotAnswer = false
|
|
|
|
|
|
item.scorePerQuestion = '0'
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (item.questionType == 2) {
|
|
|
|
|
|
if (item.checkboxValue.length == 0) {
|
|
|
|
|
|
this.$message({
|
|
|
|
|
|
message: '请选择答案',
|
|
|
|
|
|
type: 'warning',
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ handleOption ~ 确认选择-多选:', item)
|
|
|
|
|
|
let chooseAnswer = item.checkboxValue.map(item => item.split('')[0].charCodeAt() - 65)
|
|
|
|
|
|
chooseAnswer.sort((a, b) => a - b)
|
|
|
|
|
|
console.log('🚀 ~ handleOption ~ chooseAnswer:', chooseAnswer)
|
|
|
|
|
|
item.chooseAnswer = chooseAnswer.join(',')
|
|
|
|
|
|
console.log('🚀 ~ handleOption ~ item.chooseAnswer:', item.chooseAnswer)
|
|
|
|
|
|
item.correctAnswer1 = item.correctAnswer
|
|
|
|
|
|
.split(',')
|
|
|
|
|
|
.map(item => String.fromCharCode(65 + Number(item)))
|
|
|
|
|
|
.join(',')
|
|
|
|
|
|
item.chooseAnswer1 = chooseAnswer.map(item => String.fromCharCode(65 + Number(item))).join(',')
|
|
|
|
|
|
item.questionAnswerVoList.forEach(answer => {
|
|
|
|
|
|
answer.disabled = true
|
|
|
|
|
|
})
|
|
|
|
|
|
// 判断答案是否正确
|
|
|
|
|
|
if (item.chooseAnswer == item.correctAnswer) {
|
|
|
|
|
|
this.correctNum++
|
|
|
|
|
|
item.isPass = true
|
|
|
|
|
|
item.isError = false
|
|
|
|
|
|
item.isNotAnswer = false
|
|
|
|
|
|
item.scorePerQuestion = this.opt.multipleScore
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.errorNum++
|
|
|
|
|
|
item.isPass = false
|
|
|
|
|
|
item.isError = true
|
|
|
|
|
|
item.isNotAnswer = false
|
|
|
|
|
|
item.scorePerQuestion = '0'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
async openDialog2() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.dialogVisible = false
|
|
|
|
|
|
this.dialogVisible2 = true
|
|
|
|
|
|
clearInterval(this.timer)
|
|
|
|
|
|
console.log('🚀 ~ handleClose ~ this.timeCount:', this.timeCount, this.time)
|
|
|
|
|
|
if (this.opt.isStudyTask) {
|
|
|
|
|
|
let scoringRete = 0
|
|
|
|
|
|
if (this.correctNum + this.errorNum != 0) {
|
|
|
|
|
|
scoringRete = ((this.correctNum / (this.correctNum + this.errorNum)) * 100).toFixed(2)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 保存答案
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
userId: this.opt.userId,
|
|
|
|
|
|
examPaperId: this.opt.id,
|
|
|
|
|
|
scoringRete,
|
|
|
|
|
|
answerTime: this.time,
|
|
|
|
|
|
score: 0,
|
|
|
|
|
|
selectAnswerList: this.questionList,
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ openDialog2 ~ params:', params)
|
|
|
|
|
|
const res = await updateQuestionAnswer(params)
|
|
|
|
|
|
console.log('🚀 ~ openDialog2 ~ 提交:', res)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const questionId = this.questionList
|
|
|
|
|
|
.filter(item => !item.chooseAnswer)
|
|
|
|
|
|
.map(item => item.questionId)
|
|
|
|
|
|
.join(',') // 未答题目id
|
|
|
|
|
|
// errorQuestionList 错题列表
|
|
|
|
|
|
const errorQuestionList = this.questionList.filter(
|
|
|
|
|
|
item => item.chooseAnswer && item.chooseAnswer != item.correctAnswer
|
|
|
|
|
|
)
|
|
|
|
|
|
// correctQuestionList 正确题列表
|
|
|
|
|
|
const correctQuestionList = this.questionList.filter(
|
|
|
|
|
|
item => item.chooseAnswer && item.chooseAnswer == item.correctAnswer
|
|
|
|
|
|
)
|
|
|
|
|
|
// 保存答案
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
practiceId: this.opt.id, // 题库id
|
|
|
|
|
|
practiceType: this.opt.practiceType, // 题库类型
|
|
|
|
|
|
// personId: this.userId, // 用户id
|
|
|
|
|
|
practiceNum: this.correctNum + this.errorNum, // 练习题数
|
|
|
|
|
|
correctNum: this.correctNum, // 正确题数
|
|
|
|
|
|
errorNum: this.errorNum, // 错误题数
|
|
|
|
|
|
practiceTime: this.time, // 练习时间
|
|
|
|
|
|
lastPracticeQuestionId: questionId, // 最后一题id
|
|
|
|
|
|
errorQuestionList, // 错题列表
|
|
|
|
|
|
correctQuestionList, // 正确题列表
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log('🚀 ~ handleEnd ~ params:', params)
|
|
|
|
|
|
const res = await wenEndPractice(params)
|
|
|
|
|
|
console.log('🚀 ~ handleEnd ~ 自主练习提交:', res)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log('🚀 ~ openDialog2 ~ error:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
handleClose() {
|
|
|
|
|
|
this.dialogVisible2 = false
|
|
|
|
|
|
// 关闭页面
|
2025-02-13 15:47:39 +08:00
|
|
|
|
this.$tab.closePage()
|
|
|
|
|
|
// this.$tab.closePage().then(() => {
|
|
|
|
|
|
// this.$router.push({ path: '/educTrainLearn/libertyLearn/index' })
|
|
|
|
|
|
// })
|
2025-01-16 16:35:46 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.box-card {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.top-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.lf-line {
|
|
|
|
|
|
width: 2px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
background-color: #ccc;
|
|
|
|
|
|
margin: 0 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tab-wrapper {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.item {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
padding: 5px 10px;
|
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
border: 1px solid #409eff;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
|
background-color: #409eff;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.color-box {
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-wrapper {
|
|
|
|
|
|
width: 60px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center; // 垂直居中
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
background: #67c23a;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
// 不及格整体背景色
|
|
|
|
|
|
&.is-not-pass {
|
|
|
|
|
|
background: #f56c6c;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.top-item {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.question-wrapper {
|
|
|
|
|
|
margin-top: 30px;
|
|
|
|
|
|
.question-type {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
.line {
|
|
|
|
|
|
width: 3px;
|
|
|
|
|
|
height: 15px;
|
|
|
|
|
|
background-color: #1989fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
.type {
|
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.question-title {
|
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
.question-img-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.img {
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
width: 60px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.radio-item {
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
.radio-name {
|
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.question-item {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.answer-wrap {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
|
background-color: #edf2f7;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
.answer-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
div {
|
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.answer-line {
|
|
|
|
|
|
width: 1px;
|
|
|
|
|
|
height: 45px;
|
|
|
|
|
|
background-color: #ccc;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.analysis {
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
min-height: 100px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.el-radio-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
.el-radio {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.box {
|
|
|
|
|
|
height: 5vh;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bottom-wrapper {
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
.btn {
|
|
|
|
|
|
margin: 0 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.exercise-result {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-self: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
.top-content {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
}
|
|
|
|
|
|
.content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bt-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
.content-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
& > :nth-child(2) {
|
|
|
|
|
|
margin: 0 39px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|