From 7ac5363a676588078fdce082a45a28300479e158 Mon Sep 17 00:00:00 2001
From: 马宇豪 <978517621@qq.com>
Date: Mon, 22 Jul 2024 14:09:22 +0800
Subject: [PATCH] 提交
---
pages/tabBar/firstPage/exam.vue | 501 +++++++++++++++++++++++++++++++++++++++++--------------
1 files changed, 369 insertions(+), 132 deletions(-)
diff --git a/pages/tabBar/firstPage/exam.vue b/pages/tabBar/firstPage/exam.vue
index 72f2f06..9a64d19 100644
--- a/pages/tabBar/firstPage/exam.vue
+++ b/pages/tabBar/firstPage/exam.vue
@@ -16,13 +16,17 @@
</view>
</view>
<view class="m-p-15">
- <u-divider
- :text="'第'+ (currentIndex+1) +'题'"
- textColor="#2979ff"
- lineColor="#2979ff"
- textSize="16"
- style="margin: 40px 0"
- ></u-divider>
+ <view class="timer" v-if="viewType == 1">
+ <u--image :showLoading="true" :src="sandPic" width="18px" height="18px"></u--image>
+ <view class="timer-b">
+ <span>开考时间:</span>
+ <span>{{ formattedTime }}</span>
+ </view>
+ </view>
+ <view class="top">
+ <view class="ind">{{'第 ' + (curTotalIndex+1) + ' 题'}}</view>
+ <view class="panelBtn" @click="openPanel">答题卡</view>
+ </view>
<view class="questions">
<view class="title">
<span>【{{currentQ.questionType == 1?'单选题':currentQ.questionType == 2?'多选题':'判断题'}}】</span>
@@ -31,8 +35,10 @@
<view class="content">
<u-checkbox-group
v-if="currentQ.questionType==2"
- v-model="currentQ.exExerciseAnswer.answer"
+ v-model="currentB"
placement="column"
+ class="myRadio"
+ iconPlacement="right"
:disabled="viewType==1?false:true"
@change="checkboxChange"
>
@@ -42,10 +48,11 @@
:key="index"
:label="item.prefix +':'+ item.content"
:name="item.prefix"
+ :class="{'picked': currentB.includes(item.prefix)}"
>
</u-checkbox>
</u-checkbox-group>
- <u-radio-group v-model="currentQ.exExerciseAnswer.answer" placement="column" @change="groupChange" v-if="currentQ.questionType==1||currentQ.questionType==3" :disabled="viewType==1?false:true">
+ <u-radio-group v-model="currentA" class="myRadio" iconPlacement="right" placement="column" @change="groupChange" v-if="currentQ.questionType==1||currentQ.questionType==3" :disabled="viewType==1?false:true">
<u-radio
:customStyle="{marginBottom: '15px'}"
v-for="(item, index) in currentQ.content.items"
@@ -54,18 +61,18 @@
:label="item.prefix +':'+ item.content"
:name="item.prefix"
@change="radioChange"
+ :class="{'picked': currentA == item.prefix}"
>
</u-radio>
</u-radio-group>
+
<u-button style="width: 80%;margin: 30px auto"
- v-if="viewType ==1 && (currentQ.exExerciseAnswer && currentQ.exExerciseAnswer.answer && (typeof currentQ.exExerciseAnswer.answer == String?currentQ.exExerciseAnswer.answer !=='':currentQ.exExerciseAnswer.answer.length>0))"
- type="primary" shape="circle" text="确认答案"
- @click="confirmAnswer">
- </u-button>
+ v-if="currentQ.questionType==2 && currentB.length>0 && viewType ==1"
+ type="primary" shape="circle" text="确认答案" @click="confirmAnswer"></u-button>
<view class="answers" v-if="viewType == 2 && currentQ.studentAnswer && currentQ.studentAnswer.answer">
<view>你的答案:
- <span v-if="currentQ.questionType==2" :class="currentQ.answer == currentQ.studentAnswer.answer?'right':'wrong'">{{currentQ.studentAnswer.answer}}</span>
- <span v-else :class="currentQ.answer == currentQ.studentAnswer.answer?'right':'wrong'">{{currentQ.studentAnswer.answer}}</span>
+ <span :class="currentQ.answer == currentQ.studentAnswer.answer?'right':'wrong'">{{currentQ.studentAnswer.answer}}</span>
+<!-- <span v-else :class="currentQ.answer == currentQ.studentAnswer.answer?'right':'wrong'">{{currentQ.studentAnswer.answer}}</span>-->
</view>
<view>正确答案:<span class="right">{{currentQ.answer}}</span></view>
</view>
@@ -74,20 +81,34 @@
</view>
<view class="btns">
<u-button style="width: 30%" type="error" shape="circle" size="small" text="上一题" @click="prevQ"></u-button>
-<!-- <u-button style="width: 30%" type="error" shape="circle" plain size="small" text="查看答案" @click="showA"></u-button>-->
- <u-button v-if="currentIndex<questionList.length - 1" style="width: 30%" type="error" shape="circle" size="small" text="下一题" @click="nextQ"></u-button>
- <u-button v-if="currentIndex==questionList.length - 1 && viewType == 1" style="width: 30%" type="primary" shape="circle" size="small" text="保存退出" @click="endExam"></u-button>
- <u-button v-if="currentIndex==questionList.length - 1 && viewType == 2" style="width: 30%" type="primary" shape="circle" size="small" text="退出" @click="goBack"></u-button>
+ <u-button v-if="viewType == 1" style="width: 30%" type="primary" shape="circle" size="small" text="交卷" @click="endExam"></u-button>
+ <u-button v-if="curTotalIndex < idList.length - 1" style="width: 30%" type="error" shape="circle" size="small" text="下一题" @click="nextQ"></u-button>
+ <u-button v-if="curTotalIndex == idList.length - 1 && viewType == 2" style="width: 30%" type="primary" shape="circle" size="small" text="退出" @click="goBack"></u-button>
</view>
+ <u-popup :show="showPanel" :round="40" mode="right" @close="close" @open="open">
+ <view class="panel">
+ <view :class="item.passed==1?'right-a':item.passed==0?'wrong-a':''" v-for="(item,index) in idList" @click="toQuestion(item,index)">
+ {{index + 1}}
+ </view>
+ </view>
+ </u-popup>
</view>
</template>
<script>
import {
getExamIdIdList,
- getExamListByIds, postExamAnswer,postEndExam
+ getExamListByIds,
+ postExamAnswer,
+ postEndExam,
+ getQuestionIdList,
+ getErrorsIdList,
+ getQuestionByIds,
+ postExerciseAnswer
} from '../../../api/wearhouse.js'
import Vue from 'vue'
+import {loginOut} from "../../../api";
+import sand from '../../../static/sand.gif'
export default {
components: {
@@ -96,14 +117,19 @@
data() {
return {
statusBarHeight: 0,
+ sandPic: sand,
bank: {},
idList: [],
questionList: [],
- currentIndex: 0,
+ curTotalIndex: 0,
currentQ: {},
currentA: '',
currentB: [],
- viewType: null
+ viewType: null,
+ startTime: null,
+ elapsedTime: 0,
+ timerInterval: null,
+ showPanel: false
}
},
onReady(){
@@ -112,54 +138,94 @@
this.statusBarHeight = uni.getSystemInfoSync()['statusBarHeight']
this.bank = e.bank && JSON.parse(decodeURIComponent(e.bank))
this.viewType = e.type && JSON.parse(decodeURIComponent(e.type))
+ this.startTime = this.bank.startTime?this.bank.startTime:0
this.getQuestionIds(this.bank.paperId)
+
},
onShow(){
},
mounted() {
-
+ if(this.viewType == 1){
+ this.startTimer()
+ }
},
computed: {
-
+ formattedTime() {
+ const totalSeconds = Math.floor(this.elapsedTime / 1000);
+ const hours = Math.floor(totalSeconds / 3600);
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
+ const seconds = totalSeconds % 60;
+ return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
+ }
},
beforeUnmount() {
},
beforeDestroy() {
-
+ clearInterval(this.timerInterval)
},
-
methods: {
+ async openPanel(){
+ const t = this
+ t.showPanel = true
+ const res = await getExamIdIdList({paperId: this.bank.paperId,viewType: this.viewType})
+ if(res.code == 200){
+ let list = res.data || []
+ if(list.length>0){
+ t.idList = list.sort((a, b) => a.id - b.id)
+ }else{
+ t.idList = []
+ uni.showToast({
+ title: '本题库暂无题目',
+ duration: 1000
+ });
+ }
+ }else{
+ uni.$u.toast(res.message)
+ }
+ },
+
+ async toQuestion(item,index){
+ this.curTotalIndex = index
+ const curIdList = this.idList.slice(this.curTotalIndex,this.curTotalIndex + 20)
+ this.currentId = this.idList[this.curTotalIndex].id
+ await this.getQuestionsByIds(curIdList)
+ this.currentQ = this.questionList[0]
+ this.showAnswer()
+ this.showPanel = false
+ },
+
+ open() {
+ // console.log('open');
+ },
+ close() {
+ this.showPanel = false
+ // console.log('close');
+ },
+
+ updateTimer() {
+ const currentTime = Date.now();
+ this.elapsedTime = currentTime - this.startTimestamp;
+ },
+ startTimer() {
+ this.startTimestamp = this.startTime ? this.startTime : Date.now();
+ this.timerInterval = setInterval(this.updateTimer, 1000);
+ },
+
async getQuestionIds(id){
const res = await getExamIdIdList({paperId: id,viewType: this.viewType})
if(res.code == 200){
let list = res.data || []
if(list.length>0){
- this.idList = list
- getExamListByIds({paperId: id,questionIds: list.map(i=>i.id)}).then(re=>{
- if(re.code == 200){
- this.questionList = re.data.map(i=>{
- i.content = JSON.parse(i.content)
- Vue.set(i,'passed',null)
- if(i.studentAnswer){
- i.exExerciseAnswer.answer = i.studentAnswer.answer
- i.exExerciseAnswer.passed = i.studentAnswer.passed
- }
- if(i.questionType == 2){
- if(i.exExerciseAnswer.answer){
- i.exExerciseAnswer.answer = i.exExerciseAnswer.answer.split(',')
- }
- }
- return i
- })
- this.currentQ = this.questionList[this.currentIndex]
- console.log(this.currentQ,'当前问题')
- }else{
- uni.$u.toast(res.message)
- }
- })
+ this.idList = list.sort((a, b) => a.id - b.id)
+ this.curTotalIndex = this.bank.questionId ? this.idList.findIndex(i=>i.id == this.bank.questionId):0
+ const curIdList = this.idList.slice(this.curTotalIndex,this.curTotalIndex + 20)
+ this.currentId = this.idList[this.curTotalIndex].id
+ await this.getQuestionsByIds(curIdList)
+ this.currentQ = this.questionList[0]
+ this.showAnswer()
}else{
this.idList = []
uni.showToast({
@@ -171,11 +237,50 @@
uni.$u.toast(res.message)
}
},
+
+ async getErrorIds(id){
+ const res = await getErrorsIdList({bankId: id})
+ if(res.code == 200){
+ let list = res.data || []
+ if(list.length>0){
+ this.idList = list.sort((a, b) => a - b)
+ this.curTotalIndex = 0
+ const curIdList = this.idList.slice(0,20)
+ this.currentId = this.idList[0].id
+ await this.getQuestionsByIds(curIdList)
+ this.currentQ = this.questionList[0]
+ this.showAnswer()
+ }else{
+ this.idList = []
+ uni.showToast({
+ title: '本题库暂无错题',
+ duration: 1000
+ });
+ }
+ }else{
+ uni.$u.toast(res.message)
+ }
+ },
+
+ async getQuestionsByIds(idList){
+ const res = await getExamListByIds({paperId: this.bank.paperId,questionIds: idList.map(i=>i.id)})
+ if(res.code == 200){
+ this.questionList = res.data.map(i=>{
+ i.content = JSON.parse(i.content)
+ return i
+ })
+ }else{
+ uni.$u.toast(res.message)
+ }
+ },
+
checkboxChange(n) {
console.log('change', n);
},
groupChange(n) {
- console.log('groupChange', n);
+ if(this.currentA !== ''){
+ this.confirmAnswer()
+ }
},
radioChange(n) {
console.log('radioChange', n);
@@ -183,7 +288,7 @@
confirmAnswer(){
const data = {
- answer: this.currentQ.questionType==2?this.currentQ.exExerciseAnswer.answer.join(','):this.currentQ.exExerciseAnswer.answer,
+ answer: this.currentQ.questionType==2?this.currentB.join(','):this.currentA,
paperId: this.bank.paperId,
questionId: this.currentQ.id,
studentId: uni.getStorageSync('uid')
@@ -191,7 +296,9 @@
postExamAnswer(data).then(res=>{
if(res.code == 200){
this.currentQ.passed = res.data
- uni.$u.toast('答案已提交')
+ // this.currentQ.exExerciseAnswer.passed = res.data.passed
+ this.currentQ.studentAnswer.answer = res.data.answer
+ // uni.$u.toast('答案已提交')
}else{
uni.$u.toast(res.message)
}
@@ -199,9 +306,29 @@
},
prevQ(){
- if(this.currentIndex - 1>=0){
- this.currentIndex--
- this.currentQ = this.questionList[this.currentIndex]
+ if(this.curTotalIndex - 1>=0){
+ this.curTotalIndex--
+ if(this.curTotalIndex == 0){
+ this.getQuestionsByIds([this.idList[0]]).then(()=>{
+ // this.currentQ = this.questionList[this.questionList.length-1]
+ this.$set(this, 'currentQ', this.questionList[this.questionList.length-1])
+ this.showAnswer()
+ })
+ }else{
+ this.currentId = this.idList[this.curTotalIndex].id
+ if(this.questionList.find(i=>i.id == this.currentId)){
+ this.$set(this, 'currentQ', this.questionList.find(i=>i.id == this.currentId))
+ this.showAnswer()
+ }else{
+ const startIndex = Math.max(0, this.curTotalIndex - 19);
+ const curIdList = this.idList.slice(startIndex, this.curTotalIndex+1);
+ this.getQuestionsByIds(curIdList).then(()=>{
+ // this.currentQ = this.questionList[this.questionList.length-1]
+ this.$set(this, 'currentQ', this.questionList[this.questionList.length-1])
+ this.showAnswer()
+ })
+ }
+ }
}else{
uni.showToast({
title: '已经是第一题了',
@@ -211,76 +338,45 @@
},
nextQ(){
- if(this.currentQ.passed==null && this.currentQ.exExerciseAnswer.passed == null){
- uni.$u.toast('请先完成当前题目')
- return
- }
- if(this.currentIndex + 1<this.questionList.length){
- this.currentIndex++
- this.currentQ = this.questionList[this.currentIndex]
+ if(this.curTotalIndex + 1<this.idList.length){
+ this.curTotalIndex++
+ this.currentId = this.idList[this.curTotalIndex].id
+ if(this.questionList.find(i=>i.id == this.currentId)){
+ this.$set(this, 'currentQ', this.questionList.find(i=>i.id == this.currentId))
+ this.showAnswer()
+ }else{
+ const curIdList = this.idList.slice(this.curTotalIndex,this.curTotalIndex + 20)
+ this.getQuestionsByIds(curIdList).then(()=>{
+ this.$set(this, 'currentQ', this.questionList[0])
+ // this.currentQ = this.questionList[0]
+ this.showAnswer()
+ })
+ }
}else{
uni.showToast({
title: '已经是最后一题了',
duration: 1000
});
}
- console.log(this.currentQ,'current')
},
- endExam(){
- if(this.currentQ.passed==null && this.currentQ.exExerciseAnswer.passed == null){
- uni.$u.toast('请先完成当前题目')
- return
- }
- const data = {
- id: this.bank.id,
- // paperId: this.bank.paperId,
- // studentId: uni.getStorageSync('uid')
- }
- postEndExam(data).then(res=>{
- if(res.code == 200){
- uni.showToast({
- title: '本次考试结束',
- duration: 1500
- })
- setTimeout(()=>{
- const url = uni.getStorageSync("prevPage");
- if(url){
- if(url == '/pages/tabBar/firstPage/firstPage'){
- uni.reLaunch({
- url:'/pages/tabBar/firstPage/firstPage'
- });
- }else{
- uni.navigateTo({
- url: url
- })
- }
- } else{
- uni.reLaunch({
- url: '/pages/tabBar/firstPage/firstPage'
- })
- }
- },1500)
+ showAnswer(){
+ if(this.currentQ.studentAnswer && this.currentQ.studentAnswer.answer){
+ if(this.currentQ.questionType == 2){
+ this.currentB = this.currentQ.studentAnswer.answer.split(',')
}else{
- uni.$u.toast(res.message)
+ this.currentA = this.currentQ.studentAnswer.answer
}
- })
+ }else{
+ this.currentB = []
+ this.currentA = ''
+ }
},
- showA(){
- uni.showModal({
- title: '正确答案',
- content: this.currentQ.answer,
- showCancel: false,
- success: function (res) {
- if (res.confirm) {
- console.log('用户点击确定');
- }
- }
- });
- },
+
goBack(){
+ clearInterval(this.timerInterval);
const url = uni.getStorageSync("prevPage");
if(url){
uni.reLaunch({
@@ -291,6 +387,51 @@
url: '/pages/tabBar/firstPage/firstPage'
})
}
+ },
+
+ endExam(){
+ const t = this
+ uni.showModal({
+ title: '提示',
+ content: '交卷后将无法再次做题,是否继续?',
+ success: async function (res) {
+ if (res.confirm) {
+ const data = {
+ id: t.bank.id,
+ }
+ postEndExam(data).then(res=>{
+ if(res.code == 200){
+ uni.showToast({
+ title: '本次考试结束',
+ duration: 1500
+ })
+ setTimeout(()=>{
+ const url = uni.getStorageSync("prevPage");
+ if(url){
+ if(url == '/pages/tabBar/firstPage/firstPage'){
+ uni.reLaunch({
+ url:'/pages/tabBar/firstPage/firstPage'
+ });
+ }else{
+ uni.navigateTo({
+ url: url
+ })
+ }
+ } else{
+ uni.reLaunch({
+ url: '/pages/tabBar/firstPage/firstPage'
+ })
+ }
+ },1500)
+ }else{
+ uni.$u.toast(res.message)
+ }
+ })
+ } else if (res.cancel) {
+ console.log('用户点击取消');
+ }
+ }
+ })
}
}
};
@@ -322,15 +463,110 @@
margin-right: 10rpx;
}
+.panel{
+ height: 100vh;
+ width: 60vw;
+ background: #f2f2f2;
+ overflow-y: auto;
+ padding: 15px;
+ box-sizing: border-box;
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 15px;
+ grid-auto-rows: min-content;
+
+ &>view{
+ padding: 5px;
+ min-width: calc(20% - 12px);
+ border-radius: 4px;
+ text-align: center;
+ background: rgba(41,121,255,0);
+ border: 1px solid #fff;
+ color: #333;
+ background: #f2f2f2;
+ transition: all 100ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ box-shadow: 0px -6px 10px rgba(255, 255, 255, 1), 0px 4px 15px rgba(0, 0, 0, 0.15);
+ cursor: pointer;
+
+ &:active {
+ box-shadow: 0 15px 20px rgba(0, 0, 0, 0.02);
+ &:after {
+ box-shadow: inset 0px -2px 5px rgb(255, 255, 255),
+ inset 0px 2px 5px rgba(0, 0, 0, 0.15);
+ }
+ }
+
+ }
+
+ .right-a{
+ background: rgba(41,121,255,.1);
+ border: 1px solid #2979ff;
+ color: #2979ff;
+ }
+
+ .wrong-a{
+ background: rgba(237,100,100,.1);
+ border: 1px solid #ed6464;
+ color: #ed6464;
+ }
+}
+
.m-p-15{
width: 100%;
padding: 0 15px;
box-sizing: border-box;
+ .timer{
+ background: #fff;
+ width: auto;
+ margin: 10px auto;
+ padding: 10px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 99px;
+
+ .timer-b{
+ margin-left: 5px;
+ display: flex;
+ align-items: center;
+ span:last-of-type{
+ font-size: 16px;
+ font-weight: bold;
+ color: #0f7ff9;
+ }
+ }
+
+ }
+
.top{
- text-align: center;
- margin: 20rpx 0;
- font-weight: bolder;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 20px 0;
+
+ .ind{
+ font-size: 16px;
+ font-weight: bold;
+ color: #2979ff
+ }
+ .panelBtn{
+ width: 25%;
+ margin: 0;
+ text-align: center;
+ padding: 4px 0;
+ border-radius: 4px;
+ color: #2979ff;
+ background: #f5f7fa;
+ border: 1px solid rgba(41,121,255,.4);
+ box-shadow: 0px -6px 10px rgba(255, 255, 255, 1), 0px 4px 15px rgba(0, 0, 0, 0.1);
+ transition: box-shadow .25s ease !important;
+ }
+ .panelBtn:active{
+ background: #f5f7fa;
+ border: 1px solid rgba(41,121,255,1);
+ box-shadow: 0 15px 20px rgba(0, 0, 0, 0.02);
+ }
}
.questions{
@@ -387,31 +623,32 @@
border-radius: 8px;
background: #f5f7fa;
border: 1px solid #fff;
- box-shadow: 7px 7px 15px rgba(55, 84, 170, .15),
- -7px -7px 20px rgba(255, 255, 255, 1),
- inset 0px 0px 4px rgba(255, 255, 255, .2),
- inset 7px 7px 15px rgba(55, 84, 170, 0),
- inset -7px -7px 20px rgba(255, 255, 255, 0),
- 0px 0px 4px rgba(255, 255, 255, 0) !important;
+ box-shadow: 0px -6px 10px rgba(255, 255, 255, 1), 0px 4px 15px rgba(0, 0, 0, 0.1);
transition: box-shadow .25s ease !important;
}
+.myRadio{
+ /deep/ .picked{
+ border: 2px solid #2979ff;
+
+ .u-radio__icon-wrap,.u-checkbox__icon-wrap{
+ border-color: #fff !important;
+ span{
+ color: #fff !important;
+ }
+ }
+ span{
+ color: #2979ff
+ }
+ }
+}
+
/deep/ .u-checkbox:active {
- box-shadow: 7px 7px 15px rgba(55, 84, 170, .15),
- -7px -7px 20px rgba(255, 255, 255, 1),
- inset 0px 0px 4px rgba(255, 255, 255, 0),
- inset 7px 7px 15px rgba(55, 84, 170, .15),
- inset -7px -7px 20px rgba(255, 255, 255, 1),
- 0px 0px 4px rgba(255, 255, 255, .2) !important;
+ box-shadow: 0 15px 20px rgba(0, 0, 0, 0.02);
}
/deep/ .u-radio:active {
- box-shadow: 7px 7px 15px rgba(55, 84, 170, .15),
- -7px -7px 20px rgba(255, 255, 255, 1),
- inset 0px 0px 4px rgba(255, 255, 255, 0),
- inset 7px 7px 15px rgba(55, 84, 170, .15),
- inset -7px -7px 20px rgba(255, 255, 255, 1),
- 0px 0px 4px rgba(255, 255, 255, .2) !important;
+ box-shadow: 0 15px 20px rgba(0, 0, 0, 0.02);
}
</style>
--
Gitblit v1.9.2