You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
zhishifufei_uniapp/pages/topic/question_detail.vue

577 lines
17 KiB

<template>
<BaseContainer class="honor-list-page">
<NavBar title="考试难题" />
<view class="question-paper" v-if="questions.length">
<view class="header">
<div class="message">温馨提示请点击答题卡前去提交练习哦</div>
<view class="header-bd">
<navigator
open-type="redirect"
:url="`/pages/topic/question_sheet?test_id=${test_id}&record_id=${e_id}&index=${activeIndex}&is_analysis=${is_analysis}&txamination_time=${txamination_time}&exam_time=${duration}`"
>答题卡</navigator
>
<view v-if="!is_analysis">{{ duration | formatTime }}</view>
</view>
</view>
<view class="swiper-container pos">
<view
v-for="(item, idx) of questions"
:key="item.id"
class="swiper-slide abs"
:class="activeIndex == idx ? '' : 'on'"
:style="{ left: `${(activeIndex - idx) * -100}vw` }"
>
<view class="type">{{ item.questionType }}</view>
<view class="question">
<view>{{ item.stem }}</view>
<image mode="widthFix" v-if="item.image" :src="item.image" />
<view
:class="{ image: item.is_img }"
class="label-group"
@click="handleClickOptions"
>
<template v-for="(option, idx) in item.options">
<view class="label" v-if="option.value" :key="option.code">
<view
:data-idx="idx"
class="label-item"
:class="{
checked: item.user_answer.includes(option.code),
ok:
option.right &&
item.user_answer.includes(option.code) &&
is_analysis,
no:
!option.right &&
item.user_answer.includes(option.code) &&
is_analysis,
}"
>
<image v-if="option.is_img" :src="option.value" />
<template v-else>{{ option.value }}</template>
</view>
</view>
</template>
</view>
</view>
<view v-if="item.is_correct && is_analysis" class="analysis">
<view :class="{ no: item.is_correct === 1 }">
回答{{ item.is_correct === 2 ? "正确" : "错误" }}
</view>
<view>
<view>
正确答案:
<view>{{ item.answer }}</view>
</view>
<view>
您的答案:
<view>{{ item.user_answer.toString() || "未作答" }}</view>
</view>
</view>
<view>
试题难度:<span
v-for="star in 5"
:key="star"
:class="{ on: item.difficulty >= star }"
class="iconfont iconxing"
></span>
</view>
<view>答案解析:</view>
<mpHtml container-style="background: #ffffff;" :content="item.analysis"></mpHtml>
<view v-if="item.special.length">关联知识点:</view>
<navigator
open-type="redirect"
v-for="special in item.special"
:key="special.id"
:url="`/pages/special/${
special.is_light ? 'single_details' : 'details'
}?id=${special.id}`"
>{{ special.title }}</navigator
>
</view>
<view class="pl_per"></view>
</view>
<view class="swiper-pagination abs">
<text class="swiper-pagination-current">{{ activeIndex + 1 }}</text>
<text class="swiper-pagination-line"> / </text>
<text class="swiper-pagination-total">{{ questions.length }}</text>
</view>
</view>
<view class="footer">
<view
class="button flex flex-column flex-center"
:class="{ disabled: !activeIndex }"
@click="slidePrev"
>
<i class="iconfont iconshangyige"></i>
<view class="tips">上一题</view>
</view>
<view
class="button flex flex-column flex-center"
:class="{ disabled: !!questions[activeIndex].is_correct }"
@click="submitQuestion"
>
<i class="iconfont icontijiao"></i>
<view class="tips">确认提交</view>
</view>
<view
class="button flex flex-column flex-center"
:class="{ disabled: activeIndex === questions.length - 1 }"
@click="slideNext"
>
<i class="iconfont iconxiayige"></i>
<view class="tips">下一题</view>
</view>
</view>
</view>
<QuestionGuide :visible.sync="guideVisible"></QuestionGuide>
</BaseContainer>
</template>
<script>
import QuestionGuide from "@/components/QuestionGuide/index.vue";
import mpHtml from "mp-html/dist/uni-app/components/mp-html/mp-html.vue";
import { PROBLEM_GUIDE } from "@/constants/storage-keys";
import {
submitQuestions,
getSituation,
getQuestion,
getAnswerAgain,
getAnswerContinue,
getQuestionDetail,
getAnswer
} from "@/api/topic";
export default {
components: {
QuestionGuide,
mpHtml,
},
filters: {
formatTime(time) {
let hour = Math.floor(time / 3600000);
let minute = Math.floor((time - hour * 3600000) / 60000);
let second = Math.floor((time - hour * 3600000 - minute * 60000) / 1000);
if (hour < 10) {
hour = "0" + hour;
}
if (minute < 10) {
minute = "0" + minute;
}
if (second < 10) {
second = "0" + second;
}
return hour + ":" + minute + ":" + second;
},
},
data() {
return {
questions: [], // 考题列表
test_id: "",
e_id: "",
isWechat: false,
is_analysis: 0,
activeIndex: 0,
virtualData: {
slides: [],
},
questionSwiper: null,
startTime: new Date(),
duration: 0,
txamination_time: 0,
guideVisible: false,
submitProblem: {},
};
},
watch: {
guideVisible(value) {
if (!value) {
this.$util.setStorage(PROBLEM_GUIDE, new Date());
}
},
},
onLoad({ test_id, type, index = 0, e_id, is_analysis }) {
this.test_id = test_id;
this.activeIndex = Number(index);
const task = this.getData();
const exam_time = this.$util.getStorage(`exam_time${this.test_id}`);
if (exam_time) {
if (Number.isNaN(parseInt(exam_time))) {
this.exam_time = 0;
} else {
this.exam_time = parseInt(exam_time);
}
} else {
this.exam_time = 0;
}
if (parseInt(is_analysis)) {
this.is_analysis = 1;
}
if (e_id) {
this.e_id = e_id || '';
this.getQuestions();
} else {
this.getSituation();
task.then(this.setTimer);
}
},
onHide(){
// 清除定时器
clearTimeout(this.timer);
},
onUnload(){
// 清除定时器
clearTimeout(this.timer);
},
methods: {
getData() {
return getQuestionDetail(this.test_id).then(({ data }) => {
const { titles, txamination_time } = data;
Object.assign(this, {
titles,
txamination_time,
});
});
},
setTimer() {
this.timer = setInterval(() => {
this.duration = new Date() - this.startTime + this.exam_time;
this.$util.setStorage(`exam_time${this.test_id}`, this.duration);
if (this.txamination_time * 60000 <= this.duration) {
clearInterval(timer);
this.$util.showMsg("考试时间已到");
this.submit();
}
}, 1000);
},
async submit() {
const submitProblem = this.questions[this.activeIndex];
if (submitProblem.user_answer.length) {
const question = submitProblem;
const data = {
e_id: this.e_id,
questions_id: question.questions_id,
answer: question.answer,
score: question.score,
type: 2,
};
if (typeof question.user_answer === "string") {
data.user_answer = question.user_answer;
data.is_correct = question.answer === question.user_answer ? 2 : 1;
} else {
const answer = question.answer.split(",");
if (answer.length === question.user_answer.length) {
if (answer.toString() === question.user_answer.toString()) {
data.is_correct = 2;
} else {
data.is_correct =
answer.sort().toString() === question.user_answer.sort().toString()
? 2
: 1;
}
} else {
data.is_correct = 1;
}
data.user_answer = question.user_answer.sort().toString();
}
uni.showLoading({ mask: true });
try {
const resData = await submitQuestions(data);
uni.hideLoading();
if (resData.code === 200) {
question.is_correct = data.is_correct;
uni.navigateTo({
url:
"/pages/topic/question_sheet?" +
this.$util.objToParam({
test_id: this.test_id,
record_id: this.e_id,
index: this.activeIndex,
is_analysis: this.is_analysis,
txamination_time: this.txamination_time,
}),
});
} else {
this.$util.showMsg(resData.msg);
}
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err.msg);
}
} else {
uni.navigateTo({
url:
"/pages/topic/question_sheet?" +
this.$util.objToParam({
test_id: this.test_id,
record_id: this.e_id,
index: this.activeIndex,
is_analysis: this.is_analysis,
txamination_time: this.txamination_time,
}),
});
}
},
handleClickOptions({ target }) {
const { idx } = target.dataset;
if (idx === undefined) return;
const item = this.questions[this.activeIndex];
const option = item.options[idx];
if (!item || !option) return;
if (!!item.is_correct) return;
if (item.question_type === 2) {
const existIdx = item.user_answer.findIndex((i) => i === option.code);
if (existIdx === -1) {
item.user_answer.push(option.code);
} else {
item.user_answer.splice(existIdx, 1);
}
} else {
if (item.user_answer.includes(option.code)) {
item.user_answer = "";
} else {
item.user_answer = option.code;
}
}
},
// 获取状态
getSituation() {
getSituation(this.test_id).then(({ code, msg, data }) => {
if (code === 400) {
return this.$util.showMsg(msg);
}
switch (data) {
case 0:
this.getAnswer();
break;
case 1:
this.getAnswerAgain();
break;
case 2:
this.getAnswerContinue();
break;
}
});
},
// 开始答题
getAnswer() {
getAnswer({
test_id: this.test_id,
type: 2,
}).then(({ code, msg, data }) => {
if (code === 200) {
this.e_id = data;
// this.$util.setCookie("e_id", this.e_id);
this.getQuestions();
} else {
this.$util.showMsg(msg);
uni.navigateTo({
url: "/pages/topic/question_user?type=2",
});
}
});
},
// 再次答题
getAnswerAgain() {
getAnswerAgain({
test_id: this.test_id,
type: 2,
})
.then(({ code, data, msg }) => {
if (code === 200) {
this.e_id = data;
this.$util.setCookie("e_id", this.e_id);
this.getQuestions();
} else {
this.$util.showMsg(msg);
uni.navigateTo({
url: "/pages/topic/question_user?type=2",
});
}
})
.catch((err) => {
this.$util.showMsg(err.msg);
setTimeout(() => {
uni.navigateBack({
delta: 2
});
}, 2000);
});
},
// 继续答题
getAnswerContinue() {
getAnswerContinue({
test_id: this.test_id,
type: 2,
}).then(({ code, data, msg }) => {
if (code === 200) {
this.e_id = data;
this.$util.setCookie("e_id", this.e_id);
this.getQuestions();
} else {
this.$util.showMsg(msg);
uni.navigateTo({
url: "/pages/topic/question_user?type=2",
});
}
});
},
// 获取练习题
async getQuestions() {
uni.showLoading({ mask: true });
try {
const { data: questions } = await getQuestion({
test_id: this.test_id,
record_id: this.e_id,
type: 2,
});
uni.hideLoading();
questions.forEach((question) => {
question.options = [];
if (Array.isArray(question.option)) {
question.option.forEach((option, index) => {
let code = String.fromCharCode(index + 65);
question.options.push({
code,
value: option,
right: question.answer.includes(code),
});
});
} else {
for (let key in question.option) {
if (Object.hasOwnProperty.call(question.option, key)) {
question.options.push({
code: key,
value: question.option[key],
right: question.answer.includes(key),
});
}
}
}
if (!Array.isArray(question.userAnswer)) {
Object.assign(question, question.userAnswer);
}
if (!("is_correct" in question)) {
question.is_correct = 0;
}
if (!("user_answer" in question)) {
question.user_answer = "";
}
if (question.question_type === 2) {
question.user_answer = question.user_answer
? question.user_answer.split(",")
: [];
}
switch (question.question_type) {
case 1:
question.questionType = "单选题";
break;
case 2:
question.questionType = "多选题";
break;
case 3:
question.questionType = "判断题";
break;
}
});
this.questions = questions;
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err);
}
},
// 提交本题
async submitQuestion() {
let question = this.questions[this.activeIndex];
if (!!question.is_correct) return;
let data = {
e_id: this.e_id,
questions_id: question.questions_id,
answer: question.answer,
score: question.score,
type: 2,
};
if (!question.user_answer.length) {
return this.$util.showMsg("请作答后提交本题");
}
if (question.question_type === 2) {
question.user_answer.sort();
data.user_answer = question.user_answer.toString();
} else {
data.user_answer = question.user_answer;
}
data.is_correct = data.user_answer === question.answer ? 2 : 1;
uni.showLoading({ mask: true });
try {
const { code, msg } = await submitQuestions(data);
uni.hideLoading();
if (code === 200) {
question.is_correct = data.is_correct;
} else {
this.$util.showMsg(msg);
}
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err);
}
},
// 上一题
slidePrev() {
if (this.activeIndex) {
this.activeIndex--;
}
},
// 下一题
slideNext() {
if (this.activeIndex !== this.questions.length - 1) {
this.activeIndex++;
if (this.activeIndex === this.questions.length - 1) {
this.$util.showMsg("答完全部考题后\n点击左上角“答题卡”前去提交考试");
}
}
},
},
};
</script>
<style>
page {
background-color: #f5f5f5;
}
.pl_per{
/* #ifdef MP-WEIXIN */
height:100rpx;
/* #endif */
}
</style>
<style scoped lang="scss">
@import "@/static/style/question.scss";
.message{
height: 80rpx;
border-radius: 12rpx 12rpx 0 0;
background-color: #FFF0E5;
text-align: center;
font-size: 24rpx;
line-height: 80rpx;
color: #FF6B00;
}
.abs.on{
display: none;
}
</style>