Files
ks-app-employment-service/packageB/train/mockExam/startExam.vue
2025-11-10 15:27:34 +08:00

645 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-box">
<image src="/packageB/static/images/train/bj.jpg" class="bjImg" mode=""></image>
<div class="con-box">
<div class="header">
<div style="font-weight: 600;font-size: 32rpx;">{{rows.name}}</div>
<div class="headerCon">
<div>考试时长{{rows.timeLimit}}分钟</div>
<div>{{formattedTime}}</div>
<div class="headBtn" @click="exit()">退出</div>
</div>
</div>
<div class="problemCard">
<div v-for="(item,index) in problemData" :key="index">
<template v-if="questionIndex==(index+1)">
<div class="problemTitle">
<span class="titleType" v-if="item.type=='single'">单选题</span>
<span class="titleType" v-if="item.type=='multiple'">多选题</span>
<span class="titleType" v-if="item.type=='judge'">判断题</span>
<span>{{item.content}}</span>
</div>
<div class="options" v-if="item.type=='single'">
<div class="opt" @click="selected(i,index)" :class="item.choice!==''&&i==item.choice?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
<div class="optLab">{{indexToLetter(i)}}</div>
<span>{{val}}</span>
</div>
</div>
<div class="options" v-if="item.type=='multiple'">
<div class="opt" @click="selected2(i,index)" :class="judgment(i,index)?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
<div class="optLab">{{indexToLetter(i)}}</div>
<span>{{val}}</span>
</div>
</div>
<div class="options" v-if="item.type=='judge'">
<div class="opt" @click="selected3('正确',index)" :class="item.choice=='正确'?'active':''">
<span>正确</span>
</div>
<div class="opt" @click="selected3('错误',index)" :class="item.choice=='错误'?'active':''">
<span>错误</span>
</div>
</div>
<div class="problemBtns">
<div :class="(problemData[questionIndex-1].type=='multiple'?problemData[questionIndex-1].choice.length==0:problemData[questionIndex-1].choice==='')?'events':''" @click="submit()">提交答案</div>
</div>
</template>
</div>
</div>
<div class="footer">
<div class="footerLeft">
<div class="zuo" :class="questionIndex==1?'events':''" @click="questionIndex-=1"></div>
<div class="you" :class="questionIndex==problemData.length?'events':''" @click="questionIndex+=1"></div>
</div>
<div class="footerBtn" @click="complete()">完成练习</div>
<div class="footerLeft">
<div @click="dialogVisible=true">
<div><span style="color: #1CADF5;">{{questionIndex}}</span>/{{problemData.length}}</div>
<div>题号</div>
</div>
</div>
</div>
</div>
<div class="cards" v-if="dialogVisible">
<div class="cardCon">
<div class="cardHead">
<div>题号</div>
<div style="font-size: 40rpx;" @click="clones()">×</div>
</div>
<div class="questionNums">
<div class="questions" :class="item.whether=='正确'?'questionCorrect':item.whether=='错误'?'questionError':questionIndex==(index+1)?'questionsActive':''" @click="switchs(index)" v-for="(item,index) in problemList" :key="index">{{index+1}}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, inject, watch, ref, onMounted,onBeforeUnmount,computed } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
const { $api,urls , navTo,navBack , vacanciesTo, formatTotal, config } = inject('globalFunction');
import useUserStore from '@/stores/useUserStore';
import useDictStore from '@/stores/useDictStore';
const userInfo = ref({});
const rows = ref({});
const Authorization = ref('');
const radio = ref('');
const radio2 = ref('');
const checkList = ref([]);
const questionIndex = ref(1);
const correctIndex = ref(0);
const errorsIndex = ref(0);
const elapsedTime = ref(0);
const judgWhether = ref('');
const isRunning = ref(false);
const dialogVisible = ref(false);
const problemData = ref([]);
const problemList = ref([]);
let timer = null;
const formattedTime = computed(() => {
const minutes = Math.floor(elapsedTime.value / 60)
const seconds = elapsedTime.value % 60
return `${padTime(minutes)}:${padTime(seconds)}`
});
watch(questionIndex, (newVal, oldVal) => {
radio.value=""
radio2.value=""
checkList.value=[]
judgWhether.value=""
});
// watch(problemData, (newVal, oldVal) => {
// problemList.value=[];
// newVal.forEach((item,i)=>{
// problemList.value.push({index:i+1,whether:""})
// })
// });
onLoad((options) => {
rows.value=options
Authorization.value=uni.getStorageSync('Padmin-Token')||''
getHeart();
});
onShow(()=>{
})
onBeforeUnmount(() => {
if (timer) {
clearInterval(timer); // 清除定时器
timer = null; // 防止内存泄漏,确保下次不会再误用已清除的定时器
}
});
function getHeart() {
const raw =Authorization.value;
const token = typeof raw === "string" ? raw.trim() : "";
const headers = token ? { 'Authorization': raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
if (resData.code == 200) {
getUserInfo();
} else {
navTo('/packageB/login')
}
});
};
function getUserInfo(){
let header={
'Authorization':Authorization.value
}
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
userInfo.value = resData.info || {};
// userId.value=resData.info.userId
queryData()
});
};
function queryData(){
problemData.value=[]
let header={
'Authorization':Authorization.value,
'Content-Type':"application/x-www-form-urlencoded"
}
if(rows.value.types==1){
$api.myRequest('/train/public/trainExamDash/getExamTopicNoAnswer', {
userId: userInfo.value.userId,
examPaperId:rows.value.examPaperId
},'post',9100,header).then((resData) => {
if(resData&&resData.code==200){
elapsedTime.value=(rows.value.timeLimit*60)
resData.data.forEach((item,i)=>{
if(item.type=='multiple'){
item.choice=[]
}else{
item.choice=""
}
problemData.value.push(item)
problemList.value.push({index:i+1,whether:""})
})
start()
}
});
}else if(rows.value.types==2){
$api.myRequest('/train/public/trainExamDash/continueExam', {
userId: userInfo.value.userId,
examPaperId:rows.value.examPaperId
},'post',9100,header).then((resData) => {
if(resData&&resData.code==200){
elapsedTime.value=(rows.value.timeLimit*60)
resData.data.forEach((item,i)=>{
if(item.type=='multiple'){
if(item.choosed){
item.choice=item.choosed.split(",");
item.submitAnswers=true
}else{
item.choice=[]
item.submitAnswers=false
}
}else{
if(item.choosed){
item.choice=item.choosed;
item.submitAnswers=true
}else{
item.choice=""
item.submitAnswers=false
}
}
problemData.value.push(item)
problemList.value.push({index:i+1,whether:""})
})
start()
}
});
}
}
function collect(is){
let header={
'Authorization':Authorization.value,
'Content-Type':"application/x-www-form-urlencoded"
}
$api.myRequest('/train/public/questionUser/addOrUpdateCollect', {
userId: userInfo.value.userId,
questionId:problemData.value[questionIndex.value-1].questionId,
collect:is
},'post',9100,header).then((resData) => {
problemData.value[questionIndex.value-1].isCollect=is
});
};
//提交答案
function submit(){
let indexs=questionIndex.value-1
let parm={
examPaperId:rows.value.examPaperId,
questionId:problemData.value[indexs].questionId,
userId:userInfo.value.userId,
answer:problemData.value[indexs].type=='multiple'?problemData.value[indexs].choice.join(","):problemData.value[indexs].choice,
examId:problemData.value[indexs].examId
}
let header={
'Authorization':Authorization.value,
'Content-Type':"application/x-www-form-urlencoded"
}
$api.myRequest('/train/public/trainExamDash/submitAnswer', parm,'post',9100,header).then((resData) => {
if(resData&&resData.code==200){
problemData.value[indexs].submitAnswers=true
if(problemData.value.length==questionIndex.value){
$api.msg('已经是最后一题了,请仔细检查后交卷!')
}else{
questionIndex.value+=1
}
}
});
};
//完成练习
function complete(){
let arr=[]
problemData.value.forEach((item,index)=>{
if(!item.submitAnswers){
arr.push(index+1)
}
})
wx.showModal({
title: '提示',
content: (arr.length>0?'第'+arr.join(",")+'题还未作答,':'请仔细检查试卷 ')+'确认是否交卷?',
success (res) {
if (res.confirm) {
onpaper()
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
};
function onpaper(){
let indexs=questionIndex.value-1
let parm={
examPaperId:rows.value.examPaperId,
userId:userInfo.value.userId,
examId:problemData.value[indexs].examId,
useTime:(rows.value.timeLimit*60) - elapsedTime.value,
}
let header={
'Authorization':Authorization.value,
'Content-Type':"application/x-www-form-urlencoded"
}
$api.myRequest('/train/public/trainExamDash/submitExam', parm,'post',9100,header).then((resData) => {
if(resData&&resData.code==200){
$api.msg('提交成功!')
navBack()
}
});
};
function selected(i,index){
problemData.value[index].choice=i
problemData.value=JSON.parse(JSON.stringify(problemData.value))
};
//多选
function selected2(i,indexs){
let arr=problemData.value[indexs].choice.join(",")
if(arr.indexOf(i) !== -1){
const index = problemData.value[indexs].choice.indexOf(i);
if (index !== -1) {
problemData.value[indexs].choice.splice(index, 1);
}
}else{
problemData.value[indexs].choice.push(i)
}
problemData.value=JSON.parse(JSON.stringify(problemData.value))
};
function judgment(i,indexs){
let arr=problemData.value[indexs].choice.join(",")
if(arr.indexOf(i) !== -1){
return true
}else{
return false
}
};
function selected3(i,index){
// radio2.value=i
problemData.value[index].choice=i
problemData.value=JSON.parse(JSON.stringify(problemData.value))
};
// 解析选项
function parseOptions(options) {
if (!options) return [];
// 假设options是字符串格式以分号分隔
if (typeof options === 'string') {
return options.split(',').filter(opt => opt.trim());
}
// 如果是数组,直接返回
if (Array.isArray(options)) {
return options;
}
return [];
};
function indexToLetter(index) {
// 将索引转换为对应的字母
return String.fromCharCode(65 + index);
};
function padTime(time) {
return time < 10 ? `0${time}` : time
};
function start() {
if (isRunning.value) return
isRunning.value = true
timer = setInterval(() => {
elapsedTime.value-=1
if(elapsedTime.value==0){
// this.$message({
// message: '考试时间已结束,系统将自动交卷',
// type: 'warning'
// });
onpaper()
}
}, 1000)
};
function clones(){
dialogVisible.value=false
};
function switchs(i){
questionIndex.value=(i+1)
dialogVisible.value=false
};
function exit(){
wx.showModal({
title: '提示',
content: '直接退出是不计分的, 确定要退出吗?',
success (res) {
if (res.confirm) {
navBack()
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
</script>
<style lang="stylus" scoped>
.app-box{
width: 100%;
height: 100vh;
position: relative;
.bjImg{
position: absolute;
width: 100%;
height: 100%;
}
.con-box{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top:0;
z-index: 10;
padding: 20rpx 28rpx;
box-sizing: border-box;
.header{
height: 110rpx;
padding: 10rpx 10rpx 0;
background: linear-gradient(0deg, #4285EC 0%, #0BBAFB 100%);
color: #fff;
font-size: 26rpx;
border-radius: 10rpx
.headerCon{
display: flex;
align-items: center;
justify-content: space-between;
.headBtn{
background: #499FFF;
border-radius: 4px;
width: 100rpx;
text-align: center;
height: 50rpx;
line-height: 50rpx;
}
}
}
.problemCard{
margin-top: 30rpx;
.problemTitle{
font-size: 30rpx;
.titleType{
display: inline-block;
background-color: #499FFF;
border-radius: 10rpx 10rpx 10rpx 0;
padding: 8rpx 12rpx;
color: #fff;
font-size: 26rpx;
margin-right: 20rpx;
}
}
.options{
margin-top: 30rpx;
.opt{
height: 60rpx;
/* background-color: #F8F9FA; */
border-radius: 5px;
margin-bottom: 15px;
display: flex;
align-items: center;
padding-left: 30rpx;
box-sizing: border-box;
color: #808080;
font-size: 30rpx;
.optLab{
width: 40rpx;
height: 40rpx;
text-align: center;
line-height: 40rpx;
border-radius: 50%;
background-color: #8C8C8C;
color: #fff;
font-weight: 600;
font-size: 32rpx;
margin-right: 20rpx;
}
}
.active{
background: linear-gradient(90deg, #25A9F5 0%, #B1DBFF 100%);
color: #fff!important;
font-weight: bold;
}
.active>view{
background-color: #fff!important;
color: #25A9F5!important;
}
}
.analysis{
margin-top: 30rpx;
background-color: #fff;
border-radius: 6px;
margin-bottom: 15rpx;
border: 1px solid #10A8FF;
padding: 20rpx;
box-sizing: border-box;
.analysisHead{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
font-family: Microsoft YaHei;
font-weight: bold;
letter-spacing: 2px;
}
.correct{
color: #67C23A;
}
.errors{
color: #F06A6A;
}
.analysisCon{
margin-top: 30rpx;
.parse1{
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: bold;
}
.parse2{
font-size: 26rpx;
color: #333;
margin-top: 10px;
}
}
}
.problemBtns{
display: flex
align-items: center
justify-content: center
view{
width: 140rpx
height: 50rpx
text-align: center
line-height: 50rpx
background-color: #10A8FF
color: #fff
font-size: 28rpx
border-radius: 5rpx
margin-right: 10rpx;
}
}
}
.footer{
width: 100%;
height: 120rpx;
border-top: 1px solid #ddd
position: fixed
bottom: 0
left: 0
display: flex
align-items: center
justify-content: space-between
.footerLeft{
display: flex
align-items: center
font-size: 30rpx;
text-align: center
.zuo{
width: 26rpx;
height: 26rpx;
border-top: 2px solid #666
border-left: 2px solid #666
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
margin-left: 60rpx;
}
.you{
width: 26rpx;
height: 26rpx;
border-right: 2px solid #666
border-bottom: 2px solid #666
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
// margin-left: 30rpx;
margin-right: 50rpx;
}
.icons{
width: 30rpx;
height: 30rpx;
color: #fff;
text-align: center;
line-height: 30rpx;
border-radius: 50%
}
.texts{
font-size: 24rpx;
}
}
.footerLeft>view{
margin-right: 40rpx;
}
.footerBtn{
width: 140rpx
height: 50rpx
text-align: center
line-height: 50rpx
background-color: #67C23A
color: #fff
font-size: 28rpx
border-radius: 5rpx
}
}
}
.cards{
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100vh;
background-color: rgba(0,0,0,0.5);
z-index: 1000;
padding: 100rpx 50rpx;
box-sizing: border-box;
.cardCon{
height: 100%;
background-color: #fff;
padding: 20rpx;
box-sizing: border-box;
.cardHead{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 30rpx;
font-weight: 600;
}
.questionNums{
width: 100%;
display: flex;
flex-wrap: wrap;
}
.questions{
width: 60rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
border-radius: 8rpx;
border: 2px solid #E0E0E0;
font-size: 28rpx;
margin-right: 15px;
cursor: pointer;
}
.questionsActive{
background-color: #F0F9FF;
border: 2px solid #409EFF;
}
.questionCorrect{
background-color: #F0F9FF;
border: 2px solid #64BC38;
color: #6BC441;
}
.questionError{
background-color: #FFF1F0;
border: 2px solid #F56C6C;
color: #F36B6B;
}
}
}
}
.events{
pointer-events: none; /* 这会禁用所有指针事件 */
opacity: 0.5; /* 可选:改变透明度以视觉上表示不可点击 */
cursor: not-allowed; /* 可选:改变鼠标光标样式 */
}
</style>