624 lines
16 KiB
Vue
624 lines
16 KiB
Vue
<script setup>
|
||
import {useRouter} from "vue-router";
|
||
import { onMounted, ref } from 'vue'
|
||
import request from '@/utils/request.js'
|
||
import { ElMessage } from 'element-plus'
|
||
|
||
const router = useRouter()
|
||
|
||
const id = ref('')
|
||
const isStart = ref(false)
|
||
const isEnterStart = ref(false)
|
||
const endTime = ref(new Date('2025-4-28 10:21:00')) // 请在此设置具体结束时间
|
||
const showTimeEnd = ref(false)
|
||
const list = [
|
||
{
|
||
title:'一、考试环境',
|
||
list: [
|
||
'若在电脑上参加,请使用谷歌(Chrome)或Edge浏览器',
|
||
'考试前,请检查所有硬件设备、网络是否正常,确保硬件性能和网络稳定',
|
||
'考试中因断电、关机等退出考试界面,请务必用上次参加时使用的软件(如谷歌浏览器、微信)打开链接或扫码',
|
||
'请尽量选择一处相对安静、不易被打扰的环境',
|
||
]
|
||
},
|
||
{
|
||
title:'二、考试环境',
|
||
list: [
|
||
'考试有效时间:2025-04-28 下午14:00-15:00,超过60分钟系统将强制收卷,请在有效时间内参加',
|
||
'开考前5分钟才能进入考场系统,准点系统开放试卷',
|
||
'开考15分钟之后,无法进入考试系统',
|
||
'考试卷面满分为100分,及格分数线:60分',
|
||
'允许考生参加1次,答题限时为60分钟,系统采用倒计时方式',
|
||
'因未遵守本通知各项要求导致的考试迟到、网络中断、设备问题等导致考试无法正常进行的,由考生自行承担责任',
|
||
]
|
||
},
|
||
{
|
||
title:'三、考场纪律',
|
||
list: [
|
||
'考生应知悉,在整个考试过程上,考生应承诺自觉遵守考试纪律,并知悉以下行为将会被认定违反考试纪律或作弊行为。违纪考生将视为违纪并取消成绩',
|
||
'不允许出现伪造资料、身份信息等,替代他人或委托 他人代为参加考试的行为',
|
||
'考试全程不允许出现翻看书籍、资料或使用手机、计算器、平板电脑等与考试无关的行为',
|
||
'考试全程不允许以任意方式(包括但不限于抄录、截图摄屏、视频记录等行为)记录或传播考试过程及试题',
|
||
'考试全程不允许出现与考试内容相关的讨论、对话等声音;本次考试试题属于机密内容,不得对外泄露。如发现有通过摄屏、拍照并在互联网传播等渠道泄露试题的行为,将取消考生本次考试成绩并依法追究相关法律责任。',
|
||
]
|
||
},
|
||
]
|
||
const toDetail = (path) => {
|
||
router.push({
|
||
name: path,
|
||
})
|
||
}
|
||
const dialogTableVisible = ref(false)
|
||
const handleSubmit = () => {
|
||
dialogTableVisible.value = false
|
||
console.log('执行提交操作')
|
||
showToast('提交成功')
|
||
window.onbeforeunload = null
|
||
// 这里添加实际提交逻辑
|
||
// let radioKey = radioList.map(item => {
|
||
// return item.value
|
||
// })
|
||
// let checkKey = checkList.map(item => {
|
||
// return item.value
|
||
// })
|
||
// let data = {
|
||
//
|
||
// }
|
||
// request.post(``)
|
||
// .then(res => {
|
||
//
|
||
// })
|
||
}
|
||
const toastMessage = ref('')
|
||
const toastVisible = ref(false)
|
||
const toastType = ref('success')
|
||
|
||
const showToast = (message,type) => {
|
||
toastMessage.value = message
|
||
toastType.value = type
|
||
toastVisible.value = true
|
||
setTimeout(() => toastVisible.value = false, 2000)
|
||
}
|
||
const mobile = ref('')
|
||
const code = ref('')
|
||
const countdown = ref(0)
|
||
const timer = ref(null)
|
||
const showCountdown = ref(false)
|
||
|
||
// 获取验证码方法
|
||
const getCode = () => {
|
||
if (!/^1[3-9]\d{9}$/.test(mobile.value)) {
|
||
ElMessage({
|
||
dangerouslyUseHTMLString: true,
|
||
message: '<div style="font-size: 16px;">请输入有效的手机号</div>',
|
||
type: 'warning',
|
||
duration: 3 * 1000
|
||
})
|
||
// showToast('请输入有效的手机号','warning')
|
||
return
|
||
}
|
||
|
||
// 这里添加实际获取验证码逻辑
|
||
console.log('发送验证码到:', mobile.value)
|
||
let data = {
|
||
mobile: mobile.value,
|
||
area_code:86
|
||
}
|
||
request.post(`go/api/h5/v2/user/smscode`,data)
|
||
.then(res => {
|
||
// 开始倒计时
|
||
countdown.value = 60
|
||
showCountdown.value = true
|
||
timer.value = setInterval(() => {
|
||
if(countdown.value > 0) {
|
||
countdown.value--
|
||
} else {
|
||
clearInterval(timer.value)
|
||
showCountdown.value = false
|
||
}
|
||
}, 1000)
|
||
})
|
||
|
||
}
|
||
|
||
// 登录验证方法
|
||
const handleLogin = () => {
|
||
if (!mobile.value || !code.value) {
|
||
ElMessage({
|
||
dangerouslyUseHTMLString: true,
|
||
message: '<div style="font-size: 16px;">请填写完整信息</div>',
|
||
type: 'warning',
|
||
duration: 3 * 1000
|
||
})
|
||
return
|
||
}
|
||
let data = {
|
||
mobile:mobile.value,
|
||
area_code: 86,
|
||
code:code.value
|
||
}
|
||
isEnterStart.value = true
|
||
request.post(`go/api/app/v2/account/code/login`,data)
|
||
.then(res => {
|
||
// 登录成功处理
|
||
localStorage.setItem('mobile', mobile.value)
|
||
localStorage.setItem('answerToken',res.data.api_token)
|
||
|
||
ElMessage({
|
||
dangerouslyUseHTMLString: true,
|
||
message: '<div style="font-size: 16px;">登录成功</div>',
|
||
type: 'success',
|
||
duration: 1200
|
||
})
|
||
setTimeout(() => {
|
||
dialogTableVisible.value = false
|
||
isEnterStart.value = false
|
||
router.push({ name: 'onlineTest',query:{id:id.value} })
|
||
},600)
|
||
})
|
||
|
||
}
|
||
const isComposing = ref(false)
|
||
const startTest = () => {
|
||
if (localStorage.getItem('answerToken')){
|
||
isStart.value = true
|
||
request.get(`go/api/h5/v2/user/info2`)
|
||
.then(res => {
|
||
localStorage.setItem('answer_user_mobile', res.data.mobile)
|
||
localStorage.setItem('answer_user_id', res.data.user_id)
|
||
localStorage.setItem('answer_user_name', res.data.name)
|
||
setTimeout(() => {
|
||
router.push({ name: 'onlineTest',query:{id:id.value} })
|
||
},800)
|
||
}).finally(() => {
|
||
isStart.value = false
|
||
})
|
||
}else {
|
||
dialogTableVisible.value = true
|
||
}
|
||
}
|
||
onMounted(() => {
|
||
id.value = router.currentRoute.value.query.id || '1'
|
||
if (endTime.value < new Date()){
|
||
console.log('111')
|
||
showTimeEnd.value = true
|
||
return
|
||
}
|
||
if (!localStorage.getItem('answerToken')){
|
||
dialogTableVisible.value = true
|
||
}else {
|
||
// getIsJoin()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="ui-mobile-examGuide">
|
||
<div class='ui-mobile-top'>
|
||
<img src="https://images.health.ufutx.com/202504/22/39698006488f04c88e5e4390720fe3cb.png" alt="">
|
||
</div>
|
||
<div class='ui-mobile-title-card'>
|
||
<div class='testTitle'>4月份考试时间</div>
|
||
<div class='testTime'>2025-04-08 至 2025-05-01</div>
|
||
</div>
|
||
<div class="ui-examGuide-box">
|
||
<div class=" ">
|
||
<div class="ui-mb-6 font20 bold testTitle">考试须知</div>
|
||
<div class="testSubtitle ui-mb-6">为了您能顺利地完成本次考试,请阅读并注意一下事项:</div>
|
||
<div v-for="(item,index) in list" :key="index">
|
||
<div class="ui-list-title ">{{item.title}}</div>
|
||
<div class="ui-list-suttitle" v-for="(itemV2,indexV2) in item.list" :key="indexV2">
|
||
<div class="ui-list-suttitle ui-mb-6 font18">{{indexV2 + 1 + '、' + itemV2}}</div>
|
||
</div>
|
||
</div>
|
||
<!-- <div class="ui-list-suttitle">本次考试试题属于机密内容,不得对外泄露。如发现有通过摄屏、拍照并在互联网传播等渠道泄露试题的行为,将取消考生本次考试成绩并依法追究相关法律责任</div>-->
|
||
<div class='ui-btn-box'>
|
||
<div class="ui-btn font20 bold text-center" @click="startTest" :class="{disabled: isStart}">
|
||
<div class="loading-spinner" v-if="isStart"></div>
|
||
{{ isStart ? '准备中...' : '开始考试' }}
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dialog-mask" v-if="dialogTableVisible" @click="dialogTableVisible = false">
|
||
<div class="dialog-box" @click.stop>
|
||
<div class="dialog-title">请登录</div>
|
||
<div class="dialog-content">
|
||
<!-- 新增文字标签 -->
|
||
<!-- <div class="input-label">手机号</div>-->
|
||
<div class="login-input">
|
||
<input v-model="mobile" type="tel" placeholder="请输入手机号" maxlength="11">
|
||
</div>
|
||
<!-- <div class="input-label marginT32">验证码</div>-->
|
||
<div class="login-input code-input">
|
||
<input
|
||
v-model="code"
|
||
type="tel"
|
||
inputmode="numeric"
|
||
placeholder="请输入验证码"
|
||
maxlength="6"
|
||
@compositionstart="isComposing = true"
|
||
@compositionend="(e) => {
|
||
isComposing = false
|
||
e.target.value = e.target.value.replace(/[^0-9]/g, '').slice(0,6)
|
||
code = e.target.value
|
||
}"
|
||
@input="(e) => {
|
||
if (!isComposing) {
|
||
e.target.value = e.target.value.replace(/[^0-9]/g, '').slice(0,6)
|
||
code = e.target.value
|
||
}
|
||
}"
|
||
>
|
||
<button
|
||
class="get-code-btn"
|
||
@click="getCode"
|
||
:disabled="showCountdown"
|
||
>
|
||
{{ showCountdown ? `${countdown}s` : '获取验证码' }}
|
||
</button>
|
||
</div>
|
||
<!-- <div class="error-tip" v-if="errorVisible">{{ errorMessage }}</div>-->
|
||
</div>
|
||
<div class="dialog-btns">
|
||
<div class="dialog-btn confirm text-center" @click="handleLogin" :class="{disabled: isEnterStart}">
|
||
<div class="loading-spinner" v-if="isEnterStart"></div>
|
||
{{ isEnterStart ? '准备中...' : '进入考试' }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toast-mask" v-if="toastVisible">
|
||
<div class="toast-box" :class="toastType == 'warning' ? 'toast-warning-box' : ''">
|
||
{{ toastMessage }}
|
||
</div>
|
||
</div>
|
||
<div class="dialog-mask" v-if="showTimeEnd">
|
||
<div class="dialog-success-box text-center">
|
||
<img src="https://images.health.ufutx.com/202504/17/2ee13769aa745d646d4951179ade3419.png" alt="" class="dialog-success-img" />
|
||
<div class="dialog-success-title">温馨提示</div>
|
||
<div class="dialog-success-content">
|
||
考试时间已结束。
|
||
</div>
|
||
<!-- <div class="dialog-success-btns">-->
|
||
<!-- <!– <div class="dialog-btn cancel" @click="dialogTableVisible = false">继续答题</div>–>-->
|
||
<!-- <div class="dialog-success-btn confirm" @click="successSubmit" :class="{disabled: isSuccessSubmitting}">-->
|
||
<!-- <div class="loading-spinner" v-if="isSuccessSubmitting"></div>-->
|
||
<!-- {{ isSuccessSubmitting ? '正在退出...' : '好的' }}-->
|
||
<!-- </div>-->
|
||
<!-- </div>-->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.ui-mobile-examGuide{
|
||
position: relative;
|
||
padding: 0 0 100px;
|
||
width: 100vw;
|
||
height: auto;
|
||
background: #daf1fd;
|
||
|
||
/* 新增容器最小高度 */
|
||
//min-height: 100vh;
|
||
//width: 100vw;
|
||
//height: 100vh;
|
||
.ui-mobile-top{
|
||
margin-bottom: 14px;
|
||
img{
|
||
width: 375px;
|
||
height: 238px;
|
||
//max-height: 100vh;
|
||
object-fit: cover;
|
||
/* 设置宽高比保持图片比例 */
|
||
aspect-ratio: 16/9;
|
||
}
|
||
}
|
||
.ui-mobile-title-card{
|
||
display: flex;
|
||
margin: 0 10px;
|
||
padding: 16px 0px 26px 0px;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background: linear-gradient(180deg, #3178FF 0%, #409EFF 100%);
|
||
border-radius: 20px 20px 0 0 ;
|
||
font-size: 16px;
|
||
color: #ffffff;
|
||
font-weight: 600;
|
||
}
|
||
.testTitle{
|
||
color:#ffffff;
|
||
font-size: 16px;
|
||
}
|
||
.testTime{
|
||
margin: 6px 0 0;
|
||
color: #ffffff;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.ui-examGuide-box{
|
||
margin: -16px 10px 30px;
|
||
//position: absolute;
|
||
//top: 50%;
|
||
right: 160px;
|
||
//transform: translateY(-50%);
|
||
|
||
height: auto;
|
||
padding: 16px;
|
||
border-radius: 20px;
|
||
background: #FFF;
|
||
box-shadow: -4px 15px 100px 0px rgba(2, 115, 181, 0.25);
|
||
|
||
.testTitle{
|
||
font-size: 16px;
|
||
color: #0E0E0E;
|
||
font-weight: 600;
|
||
}
|
||
.testSubtitle{
|
||
color: #0E0E0E;
|
||
font-size: 16px;
|
||
}
|
||
|
||
}
|
||
.ui-mb-6{
|
||
margin-bottom: 6px;
|
||
}
|
||
.ui-list-title{
|
||
font-size: 16px;
|
||
color: #0E0E0E;
|
||
line-height: 1.5;
|
||
font-weight: 600;
|
||
}
|
||
.ui-list-suttitle{
|
||
font-size: 16px;
|
||
color: #0E0E0E;
|
||
//line-height: 27px;
|
||
line-height: 1.5;
|
||
}
|
||
.ui-btn-box{
|
||
position: fixed;
|
||
left: 0;
|
||
bottom:0;
|
||
display: flex;
|
||
width: 375px;
|
||
padding: 10px 10px 30px 10px;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background: #FFF;
|
||
}
|
||
.ui-btn{
|
||
display: flex;
|
||
width: 338px;
|
||
height: 50px;
|
||
padding: 14px 10px;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #fff;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
border-radius: 43px;
|
||
background: #409EFF;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
.dialog-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
}
|
||
.dialog-success-box{
|
||
display: flex;
|
||
width: 320px;
|
||
padding: 30px;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
border-radius: 20px;
|
||
background: #FFF;
|
||
.dialog-success-img{
|
||
width: 130px;
|
||
height: 116px;
|
||
}
|
||
.dialog-success-title{
|
||
margin: 50px auto 30px;
|
||
color: #0E0E0E;
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
}
|
||
.dialog-success-content{
|
||
margin-bottom: 50px;
|
||
color:#0E0E0E;
|
||
font-size: 18px;
|
||
}
|
||
.dialog-success-btns{
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
.dialog-success-btn{
|
||
padding: 16px 0;
|
||
border-radius: 10px;
|
||
cursor: pointer;
|
||
width: 172px;
|
||
}
|
||
}
|
||
|
||
|
||
.dialog-box {
|
||
width: 320px;
|
||
background: #fff;
|
||
border-radius: 20px;
|
||
padding: 30px;
|
||
}
|
||
|
||
.dialog-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
margin-bottom: 30px;
|
||
text-align: center;
|
||
}
|
||
|
||
.dialog-content {
|
||
margin-bottom: 50px;
|
||
font-size: 18px;
|
||
color:#0E0E0E;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.dialog-btns {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
}
|
||
|
||
.dialog-btn {
|
||
padding: 16px 0;
|
||
cursor: pointer;
|
||
width: 240px;
|
||
border-radius: 38px;
|
||
background: #409EFF;
|
||
}
|
||
.dialog-btn, .ui-btn{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
&.disabled {
|
||
opacity: 0.7;
|
||
pointer-events: none;
|
||
}
|
||
}
|
||
.loading-spinner {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-right: 8px;
|
||
border: 2px solid #fff;
|
||
border-top-color: transparent;
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
@keyframes spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
.cancel {
|
||
border: 1px solid #409EFF;
|
||
color: #409EFF;
|
||
background: #fff;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.confirm {
|
||
background: #409eff;
|
||
color: #fff;
|
||
border: 1px solid #409eff;
|
||
font-size: 18px;
|
||
}
|
||
.toast-mask {
|
||
position: fixed;
|
||
top: 100px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 1000;
|
||
|
||
.toast-box {
|
||
padding: 12px 24px;
|
||
background: rgba(231, 245, 224, 0.7);
|
||
color: #6bc340;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
border: 1px solid #6bc340;
|
||
animation: fadeInOut 2s;
|
||
}
|
||
.toast-warning-box{
|
||
background: #fdf6ec;
|
||
color:#e7a746;
|
||
border: 1px solid #e7a746;
|
||
}
|
||
}
|
||
|
||
@keyframes fadeInOut {
|
||
0%,100% { opacity: 0; }
|
||
20%,80% { opacity: 1; }
|
||
}
|
||
.input-label {
|
||
font-size: 14px;
|
||
color: #0e0e0e;
|
||
margin-bottom: 8px;
|
||
}
|
||
.login-input {
|
||
margin: 0 0 16px;
|
||
input {
|
||
width: 100%;
|
||
height: 56px;
|
||
padding: 0 20px;
|
||
border: 1px solid #DDD; /* 默认黑色边框 */
|
||
border-radius: 30px;
|
||
font-size: 14px;
|
||
/* 去除输入框默认样式 */
|
||
-webkit-appearance: none;
|
||
outline: none;
|
||
/* 隐藏数字输入框箭头 */
|
||
&[type="number"] {
|
||
-moz-appearance: textfield;
|
||
&::-webkit-outer-spin-button,
|
||
&::-webkit-inner-spin-button {
|
||
-webkit-appearance: none;
|
||
margin: 0;
|
||
}
|
||
}
|
||
&::placeholder{
|
||
color: #B2B3B5;
|
||
font-size: 16px;
|
||
}
|
||
&:focus {
|
||
border-color: #79BBFF; /* 输入时边框颜色 */
|
||
}
|
||
}
|
||
|
||
&.code-input {
|
||
position: relative;
|
||
|
||
.get-code-btn {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: none;
|
||
border: none;
|
||
color: #79BBFF; /* 按钮文字颜色 */
|
||
padding: 0;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
.dialog-content {
|
||
margin-bottom: 30px;
|
||
font-size: 14px;
|
||
}
|
||
:deep(.el-message){
|
||
font-size: 16px;
|
||
}
|
||
</style>
|
||
<style>
|
||
@media screen and (max-width: 750px) {
|
||
*{
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
</style>
|