ufutx_official_website/src/components/mobile/examGuide.vue
2026-03-03 15:50:38 +08:00

624 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.

<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">-->
<!-- &lt;!&ndash; <div class="dialog-btn cancel" @click="dialogTableVisible = false">继续答题</div>&ndash;&gt;-->
<!-- <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>