Files
ks-app-employment-service/packageB/train/mockExam/examList.vue
2025-11-08 14:05:56 +08:00

520 lines
15 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">
<div class="con-box">
<template #headContent>
<view class="collection-search">
<view class="search-content">
<view class="header-input button-click">
<uni-icons class="iconsearch" color="#6A6A6A" type="search" size="22"></uni-icons>
<input
class="input"
v-model="searchKeyword"
@confirm="searchVideo"
placeholder="输入考试名称"
placeholder-class="inputplace"
/>
<uni-icons
v-if="searchKeyword"
class="clear-icon"
type="clear"
size="24"
color="#999"
@click="clearSearch"
/>
</view>
</view>
</view>
</template>
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
<div class="cards" v-for="(item,index) in dataList">
<div class="cardHead">
<div class="cardHeadLeft">
<div class="cardTitle">{{item.name}}</div>
<div class="titleType success" v-if="item.score">已完成</div>
<div class="titleType info" v-else-if="dates<item.startDate">未开始</div>
<div class="titleType primary" v-else-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate">
进行中
</div>
<div class="titleType info" v-else-if="dates>item.dueDate">已过期</div>
</div>
<div class="rightBtn" v-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate&&item.isContinue!=1" @click="handleOperation(item,1)">开始考试</div>
<div class="rightBtn" v-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate&&item.isContinue==1" @click="handleOperation(item,2)">继续考试</div>
</div>
<div class="heng"></div>
<div class="cardCon">
<div class="conten">考试时长{{item.timeLimit}}分钟</div>
<div class="conten">题目数量{{item.totalQuestions}}</div>
<div class="conten">分类
<span v-for="(val, key) in classification">
<template v-if="item.category==val.dictValue">{{ val.dictLabel }}</template>
</span>
</div>
<div class="conten">成绩
<span v-if="item.gradeUser" >{{ item.gradeUser.score }}</span>
<span v-else>--</span>
</div>
<div class="conten">开始时间{{item.startDate}}</div>
<div class="conten">截止时间{{item.dueDate}}</div>
</div>
<div class="flooter">
<div v-if="item.gradeUser" @click="jumps(item)">查看成绩</div>
<div @click="handleDetail(item)">详情</div>
<div @click="collects(item,1)" v-if="item.isCollect==0">
<image :src="urls+'wsc.png'" mode="" style="width: 32rpx;height: 30rpx;"></image>
收藏
</div>
<div v-else @click="collects(item,0)">
<image :src="urls+'video-sc.png'" mode="" style="width: 32rpx;height: 30rpx;"></image>
取消
</div>
</div>
</div>
</scroll-view>
</div>
<div class="cards2" v-if="dialogVisible">
<div class="cardCon">
<div class="cardHead" style="margin-bottom: 20rpx;">
<div>{{examInfo.name}}</div>
<div style="font-size: 40rpx;" @click="clones()">×</div>
</div>
<div class="status-tags">
<div class="titleType success" v-if="examInfo.score">已完成</div>
<div class="titleType info" v-else-if="dates<examInfo.startDate">未开始</div>
<div class="titleType primary" v-else-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate">
进行中
</div>
<div class="titleType info" v-else-if="dates>examInfo.dueDate">已过期</div>
<div class="titleType success" v-if="examInfo.difficulty=='easy'">初级</div>
<div class="titleType tertiary" v-if="examInfo.difficulty=='medium'">中级</div>
<div class="titleType primary2" v-if="examInfo.difficulty=='hard'">高级</div>
</div>
<div class="detailTitle">考试简介</div>
<div class="detailCon">{{ examInfo.description }}</div>
<div class="exam-info">
<div class="info-item">
<div class="info-value">{{ examInfo.timeLimit }}</div>
<div class="info-label">考试时长</div>
<div class="info-label">(分钟)</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-value">{{ examInfo.totalQuestions }}</div>
<div class="info-label">题目总数</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-value">{{ examInfo.passScore }}</div>
<div class="info-label">及格分数</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-value">{{ examInfo.totalScore }}</div>
<div class="info-label">总分</div>
</div>
</div>
<div class="detailTitle">考试要求</div>
<div class="detailCon">考试过程中请勿刷新页面或关闭浏览器</div>
<div class="detailCon">请在规定时间内完成所有题目</div>
<div class="detailCon">考试开始后不可暂停请确保网络连接稳定</div>
<div class="detailCon">考试结束后可查看成绩和答案解析</div>
<div style="display: flex;justify-content: center;margin-top: 30rpx;">
<div class="rightBtn" v-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate&&examInfo.isContinue!=1" @click="handleOperation(examInfo,1)">开始考试</div>
<div class="rightBtn" v-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate&&examInfo.isContinue==1" @click="handleOperation(examInfo,2)">继续考试</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { inject, ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack,urls } = inject('globalFunction');
import config from "@/config.js"
const userInfo = ref({});
const Authorization = ref('');
const searchKeyword = ref('');
const dataList=ref([])
const pageSize=ref(10)
const pageNum=ref(1)
const totalNum=ref(0)
const dates=ref('')
const classification=ref([])
const levalLabels=ref([])
const examInfo = ref({})
const baseUrl = config.imgBaseUrl
const dialogVisible = ref(false);
const handleScrollToLower = () => {
};
onLoad(() => {
getDictionary()
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1; // 月份从0开始需要加1
let day = date.getDate();
month=month>9?month:'0'+month
day=day>9?day:'0'+day
dates.value=year+'-'+month+'-'+day
Authorization.value=uni.getStorageSync('Padmin-Token')||''
getHeart();
});
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 || {};
getDataList('refresh');
});
};
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/question_classification', {},'get',9100).then((resData) => {
classification.value=resData.data
});
$api.myRequest('/system/public/dict/data/type/question_level', {},'get',9100).then((resData) => {
levalLabels.value=resData.data
});
}
// 搜索视频
function searchVideo() {
getDataList('refresh');
}
// 清除搜索内容
function clearSearch() {
searchKeyword.value = '';
getDataList('refresh');
}
// 获取考试列表
function getDataList(type = 'add') {
let maxPage=Math.ceil(totalNum.value/pageSize.value)
let params={}
if (type === 'refresh') {
pageNum.value = 1;
params={
name:searchKeyword.value,
pageSize:pageSize.value,
pageNum:pageNum.value,
userId:userInfo.value.userId
}
$api.myRequest('/train/public/trainExamDash/getExamPublishTable', params).then((resData) => {
if(resData.code==200){
dataList.value=resData.rows
totalNum.value=resData.total
}
});
}
if (type === 'add' && pageNum.value < maxPage) {
pageNum.value += 1;
params={
name:searchKeyword.value,
pageSize:pageSize.value,
pageNum:pageNum.value,
userId:userInfo.value.userId
}
$api.myRequest('/train/public/trainExamDash/getExamPublishTable', params).then((resData) => {
if(resData.code==200){
dataList.value=dataList.value.concat(resData.rows)
totalNum.value=resData.total
}
});
}
}
function collects(row,i){
$api.myRequest('/train/public/examUser/addOrUpdateExamUser', {
userId:userInfo.value.userId,
examPaperId:row.examPaperId,
collect:i,
}).then((resData) => {
if(resData.code==200){
if(i==1){
$api.msg('收藏成功',2000)
}else{
$api.msg('已取消收藏',2000)
}
getDataList('refresh');
}
});
}
function handleDetail(row){
$api.myRequest('/train/public/trainExamDash/getExamPublishModel', {
userId:userInfo.value.userId,
examPaperId:row.examPaperId,
}).then((resData) => {
if(resData&&resData.code==200){
examInfo.value=resData.data
dialogVisible.value=true;
}
});
}
function jumps(row){
navTo('/packageB/train/mockExam/viewGrades?examPaperId='+row.examPaperId);
}
function clones(){
dialogVisible.value=false
}
function handleOperation(row,i) {
navTo(`/packageB/train/mockExam/startExam?examPaperId=${row.examPaperId}&timeLimit=${row.timeLimit}&name=${row.name}&types=${i}`);
}
</script>
<style lang="stylus" scoped>
.app-box{
width: 100%;
height: 100vh;
position: relative;
.con-box{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top:0;
z-index: 10;
padding: 20rpx 28rpx;
box-sizing: border-box;
overflow: hidden;
.collection-search{
padding: 10rpx 20rpx;
.search-content{
position: relative
display: flex
align-items: center
padding: 14rpx 0
.header-input{
padding: 0
width: calc(100%);
position: relative
.iconsearch{
position: absolute
left: 30rpx;
top: 50%
transform: translate(0, -50%)
z-index: 1
}
.input{
padding: 0 80rpx 0 80rpx
height: 80rpx;
background: #FFFFFF;
border-radius: 75rpx 75rpx 75rpx 75rpx;
border: 2rpx solid #ECECEC
font-size: 28rpx;
}
.clear-icon{
position: absolute
right: 30rpx;
top: 50%
transform: translate(0, -50%)
z-index: 1
cursor: pointer
}
.inputplace{
font-weight: 400;
font-size: 28rpx;
color: #B5B5B5;
}
}
}
}
.main-scroll {
width: 100%;
height: 90%;
.cards{
width: 100%;
height: 280rpx;
background: linear-gradient(0deg, #E3EFFF 0%, #FBFDFF 100%);
// box-shadow: 0px 0px 6px 0px rgba(0,71,200,0.32);
border-radius: 12rpx;
border: 2px solid #EDF5FF;
margin-bottom: 30rpx;
padding: 30rpx 40rpx 0;
box-sizing: border-box
.cardHead{
display: flex;
align-items: center;
justify-content: space-between;
.cardHeadLeft{
display: flex;
align-items: center
width: 75%;
.cardTitle{
font-weight: bold;
font-size: 28rpx;
color: #0069CB;
max-width: 75%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.titleType{
border-radius: 4px;
font-size: 22rpx;
color: #157EFF;
width: 100rpx;
height: 38rpx;
text-align: center;
line-height: 38rpx;
margin-left: 10rpx;
}
}
}
.heng{
width: 120rpx;
height: 4rpx;
background: linear-gradient(88deg, #015EEA 0%, #00C0FA 100%);
margin: 10rpx 0 20rpx;
}
.cardCon{
display: flex;
flex-wrap: wrap;
.conten{
width: 50%;
font-size: 22rpx;
color: #666666;
display: flex;
align-items: center
margin-bottom: 10rpx;
}
.status-tags{
display: flex;
align-items: center;
}
}
.flooter{
border-top: 1px solid #ccc;
display: flex;
justify-content: flex-end;
align-items: center;
view{
font-size: 28rpx;
margin-left: 30rpx;
color: #2175F3;
padding-top: 14rpx;
}
}
}
}
}
.cards2{
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100vh;
background-color: rgba(0,0,0,0.5);
z-index: 10000;
padding: 100rpx 50rpx;
box-sizing: border-box;
.cardCon{
height: 70%;
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;
}
}
}
}
.titleType{
display: inline-block
border-radius: 4px;
font-size: 22rpx;
color: #157EFF;
width: 100rpx;
height: 38rpx;
text-align: center;
line-height: 38rpx;
margin-left: 10rpx;
}
.primary{
border: 1px solid #157EFF!important;
color: #157EFF!important
}
.success{
border: 1px solid #05A636!important;
color: #05A636!important
}
.info{
border: 1px solid #898989!important;
color: #898989!important
}
.tertiary{
border: 1px solid #E6A340!important;
color: #E6A340!important
}
.primary2{
border: 1px solid #F56C6C!important;
color: #F56C6C!important
}
.rightBtn{
width: 140rpx;
height: 44rpx;
line-height: 44rpx;
background: linear-gradient(90deg, #00C0FA 0%, #1271FF 100%);
border-radius: 4px;
color: #fff;
font-size: 24rpx;
text-align: center;
}
.detailTitle{
font-size: 32rpx;
font-weight: 600;
margin: 30rpx 0;
}
.detailCon{
font-size: 28rpx;
line-height: 40rpx;
}
.exam-info {
display: flex;
justify-content: space-between;
margin-bottom: 35rpx;
margin-top: 20rpx;
}
.info-item {
flex: 1;
text-align: center;
}
.info-value {
font-family: 'D-DIN-Medium';
font-size: 26rpx;
font-weight: 600;
color: #409EFF;
margin-bottom: 8rpx;
}
.info-label {
font-size: 26rpx;
color: #333;
}
.info-divider {
width: 2px;
background-color: #C3E1FF;
}
</style>