考生登录和ExamineeHome页
This commit is contained in:
parent
fd2a4bc6eb
commit
3f61b5eb72
41
src/components/user/ExamineeLayout.vue
Normal file
41
src/components/user/ExamineeLayout.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<el-container class="examinee-layout-container">
|
||||||
|
<!-- Header -->
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<!-- Main content area -->
|
||||||
|
<el-main class="content-container">
|
||||||
|
<router-view />
|
||||||
|
</el-main>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<Footer />
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ExamineeLayout',
|
||||||
|
components: {
|
||||||
|
Header: require('../common/Header.vue').default,
|
||||||
|
Footer: require('../common/Footer.vue').default,
|
||||||
|
ElContainer: require('element-ui').Container,
|
||||||
|
ElMain: require('element-ui').Main
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.examinee-layout-container,
|
||||||
|
.el-container {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
@ -52,7 +52,8 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||||||
questionRemove: (questionId) => ipcRenderer.invoke('question-remove', questionId),
|
questionRemove: (questionId) => ipcRenderer.invoke('question-remove', questionId),
|
||||||
// 添加新的questionDelete方法,调用主进程中已注册的'question-delete'通道
|
// 添加新的questionDelete方法,调用主进程中已注册的'question-delete'通道
|
||||||
questionDelete: (questionId) => ipcRenderer.invoke('question-delete', questionId),
|
questionDelete: (questionId) => ipcRenderer.invoke('question-delete', questionId),
|
||||||
questionGetStatistics: () => ipcRenderer.invoke('question-get-statistics'),
|
// 修改后
|
||||||
|
questionGetStatistics: () => ipcRenderer.invoke('question-get-count-and-score'),
|
||||||
questionGetQuestionById: (questionId) => ipcRenderer.invoke('question-get-question-by-id', questionId),
|
questionGetQuestionById: (questionId) => ipcRenderer.invoke('question-get-question-by-id', questionId),
|
||||||
|
|
||||||
// 考试服务相关接口
|
// 考试服务相关接口
|
||||||
|
@ -2,11 +2,13 @@ import Vue from 'vue'
|
|||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import WelcomeView from '../views/WelcomeView.vue'
|
import WelcomeView from '../views/WelcomeView.vue'
|
||||||
import AdminLayout from '../components/admin/AdminLayout.vue'
|
import AdminLayout from '../components/admin/AdminLayout.vue'
|
||||||
|
import ExamineeLayout from '../components/user/ExamineeLayout.vue'
|
||||||
import AdminHomeView from '../views/admin/AdminHomeView.vue'
|
import AdminHomeView from '../views/admin/AdminHomeView.vue'
|
||||||
import QuestionManagementView from '../views/admin/QuestionManagementView.vue'
|
import QuestionManagementView from '../views/admin/QuestionManagementView.vue'
|
||||||
import ExamineeManagementView from '../views/admin/ExamineeManagementView.vue'
|
import ExamineeManagementView from '../views/admin/ExamineeManagementView.vue'
|
||||||
// 添加考试管理组件导入
|
|
||||||
import ExamManagementView from '../views/admin/ExamManagementView.vue'
|
import ExamManagementView from '../views/admin/ExamManagementView.vue'
|
||||||
|
// 导入考生相关组件
|
||||||
|
import ExamineeHomeView from '../views/user/ExamineeHomeView.vue'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -20,45 +22,81 @@ const routes = [
|
|||||||
path: '/admin',
|
path: '/admin',
|
||||||
name: 'AdminLayout',
|
name: 'AdminLayout',
|
||||||
component: AdminLayout,
|
component: AdminLayout,
|
||||||
meta: {
|
meta: { requiresAuth: true },
|
||||||
requiresAuth: true
|
|
||||||
},
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{ path: 'home', name: 'AdminHome', component: AdminHomeView },
|
||||||
path: 'home',
|
{ path: 'question', name: 'QuestionManagement', component: QuestionManagementView },
|
||||||
name: 'AdminHome',
|
{ path: 'examinee', name: 'ExamineeManagement', component: ExamineeManagementView },
|
||||||
component: AdminHomeView
|
{ path: 'exam', name: 'ExamManagement', component: ExamManagementView }
|
||||||
},
|
]
|
||||||
{
|
},
|
||||||
path: 'question',
|
// 添加考生相关路由
|
||||||
name: 'QuestionManagement',
|
{
|
||||||
component: QuestionManagementView
|
path: '/examinee',
|
||||||
},
|
name: 'Examinee',
|
||||||
{
|
component: ExamineeLayout,
|
||||||
path: 'examinee',
|
meta: { requiresAuth: true },
|
||||||
name: 'ExamineeManagement',
|
children: [
|
||||||
component: ExamineeManagementView
|
{ path: 'home', name: 'ExamineeHome', component: ExamineeHomeView },
|
||||||
},
|
// 可以在这里添加更多考生相关的路由
|
||||||
{
|
|
||||||
path: 'exam',
|
|
||||||
name: 'ExamManagement',
|
|
||||||
component: ExamManagementView
|
|
||||||
}
|
|
||||||
// 可以在这里添加更多子路由
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
mode: 'hash', // 将history改为hash
|
|
||||||
base: process.env.BASE_URL,
|
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
// 添加路由守卫
|
// 添加路由守卫,检查登录状态
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// 这里可以添加实际的认证逻辑
|
const store = require('../store/index.js').default
|
||||||
next()
|
|
||||||
|
// 检查路由是否需要认证
|
||||||
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
|
// 检查是否已登录
|
||||||
|
if (!store.state.isLoggedIn) {
|
||||||
|
// 如果未登录且不是去欢迎页,则重定向到欢迎页
|
||||||
|
if (to.path !== '/') {
|
||||||
|
next({
|
||||||
|
path: '/',
|
||||||
|
query: { redirect: to.fullPath }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 不需要认证的路由直接通过
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加路由守卫,检查登录状态
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
const store = require('../store/index.js').default
|
||||||
|
|
||||||
|
// 检查路由是否需要认证
|
||||||
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
|
// 检查是否已登录
|
||||||
|
if (!store.state.isLoggedIn) {
|
||||||
|
// 如果未登录且不是去欢迎页,则重定向到欢迎页
|
||||||
|
if (to.path !== '/') {
|
||||||
|
next({
|
||||||
|
path: '/',
|
||||||
|
query: { redirect: to.fullPath }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 不需要认证的路由直接通过
|
||||||
|
next()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
@ -6,16 +6,28 @@ Vue.use(Vuex)
|
|||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
examinee: null, // 保存考生信息
|
examinee: null, // 保存考生信息
|
||||||
isLoggedIn: false // 登录状态
|
admin: null, // 保存管理员信息
|
||||||
|
isLoggedIn: false, // 通用登录状态
|
||||||
|
userType: null // 用户类型: 'examinee' 或 'admin'
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setExaminee(state, examineeInfo) {
|
setExaminee(state, examineeInfo) {
|
||||||
state.examinee = examineeInfo
|
state.examinee = examineeInfo
|
||||||
|
state.admin = null
|
||||||
state.isLoggedIn = true
|
state.isLoggedIn = true
|
||||||
|
state.userType = 'examinee'
|
||||||
},
|
},
|
||||||
clearExaminee(state) {
|
setAdmin(state, adminInfo) {
|
||||||
|
state.admin = adminInfo
|
||||||
state.examinee = null
|
state.examinee = null
|
||||||
|
state.isLoggedIn = true
|
||||||
|
state.userType = 'admin'
|
||||||
|
},
|
||||||
|
clearUser(state) {
|
||||||
|
state.examinee = null
|
||||||
|
state.admin = null
|
||||||
state.isLoggedIn = false
|
state.isLoggedIn = false
|
||||||
|
state.userType = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -7,14 +7,16 @@
|
|||||||
<el-main>
|
<el-main>
|
||||||
<div class="d-flex align-items-center justify-content-center p-4" style="padding: 0; width: 600px;">
|
<div class="d-flex align-items-center justify-content-center p-4" style="padding: 0; width: 600px;">
|
||||||
<!-- 数据库初始化提示卡片 -->
|
<!-- 数据库初始化提示卡片 -->
|
||||||
<div class="login-card bg-white rounded shadow-lg p-5 w-100 max-w-md" id="init-section" v-show="!isDatabaseInitialized">
|
<div class="login-card bg-white rounded shadow-lg p-5 w-100 max-w-md" id="init-section"
|
||||||
|
v-show="!isDatabaseInitialized">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<i class="fa fa-database text-primary" style="font-size: 64px;"></i>
|
<i class="fa fa-database text-primary" style="font-size: 64px;"></i>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="display-6 mb-4">系统未初始化</h2>
|
<h2 class="display-6 mb-4">系统未初始化</h2>
|
||||||
<p class="fs-5 mb-6 text-muted">请点击下方按钮进行系统初始化,初始化完成后将自动显示登录界面</p>
|
<p class="fs-5 mb-6 text-muted">请点击下方按钮进行系统初始化,初始化完成后将自动显示登录界面</p>
|
||||||
<button id="initialize-db" @click="initializeDatabase" class="btn btn-primary px-8 py-3 fs-5" :disabled="isInitializing">
|
<button id="initialize-db" @click="initializeDatabase" class="btn btn-primary px-8 py-3 fs-5"
|
||||||
|
:disabled="isInitializing">
|
||||||
<i v-if="isInitializing" class="fa fa-spinner fa-spin me-2"></i>
|
<i v-if="isInitializing" class="fa fa-spinner fa-spin me-2"></i>
|
||||||
<i v-else class="fa fa-refresh me-2"></i>
|
<i v-else class="fa fa-refresh me-2"></i>
|
||||||
{{ isInitializing ? '初始化中...' : '数据初始化' }}
|
{{ isInitializing ? '初始化中...' : '数据初始化' }}
|
||||||
@ -23,17 +25,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bootstrap登录卡片 -->
|
<!-- Bootstrap登录卡片 -->
|
||||||
<div class="login-card bg-white rounded shadow-lg p-5 w-100 max-w-md" id="login-section" style="height: 500px;" v-show="isDatabaseInitialized">
|
<div class="login-card bg-white rounded shadow-lg p-5 w-100 max-w-md" id="login-section"
|
||||||
|
style="height: 500px;" v-show="isDatabaseInitialized">
|
||||||
<!-- 登录类型切换标签页 -->
|
<!-- 登录类型切换标签页 -->
|
||||||
<ul class="nav nav-tabs fs-4" id="loginTab" role="tablist">
|
<ul class="nav nav-tabs fs-4" id="loginTab" role="tablist">
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
<li class="nav-item flex-fill" role="presentation">
|
||||||
<button class="nav-link rounded-0 active w-100" id="exam-tab" data-toggle="tab" data-target="#exam-login" type="button" role="tab" aria-controls="exam-login" aria-selected="true">
|
<button class="nav-link rounded-0 active w-100" id="exam-tab" data-toggle="tab"
|
||||||
|
data-target="#exam-login" type="button" role="tab" aria-controls="exam-login" aria-selected="true">
|
||||||
<i class="fa fa-graduation-cap me-2"></i>
|
<i class="fa fa-graduation-cap me-2"></i>
|
||||||
考生登录
|
考生登录
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
<li class="nav-item flex-fill" role="presentation">
|
||||||
<button class="nav-link rounded-0 w-100" id="admin-tab" data-toggle="tab" data-target="#admin-login" type="button" role="tab" aria-controls="admin-login" aria-selected="false">
|
<button class="nav-link rounded-0 w-100" id="admin-tab" data-toggle="tab" data-target="#admin-login"
|
||||||
|
type="button" role="tab" aria-controls="admin-login" aria-selected="false">
|
||||||
<i class="fa fa-cog me-2"></i>
|
<i class="fa fa-cog me-2"></i>
|
||||||
系统管理
|
系统管理
|
||||||
</button>
|
</button>
|
||||||
@ -41,7 +46,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- 登录表单内容 -->
|
<!-- 登录表单内容 -->
|
||||||
<div class="tab-content fs-5 p-4 border border-left border-right border-bottom" id="loginTabContent" style="height: calc(100% - 60px);">
|
<div class="tab-content fs-5 p-4 border border-left border-right border-bottom" id="loginTabContent"
|
||||||
|
style="height: calc(100% - 60px);">
|
||||||
<!-- 考生登录表单 -->
|
<!-- 考生登录表单 -->
|
||||||
<div class="h-100 tab-pane fade show active" id="exam-login" role="tabpanel" aria-labelledby="exam-tab">
|
<div class="h-100 tab-pane fade show active" id="exam-login" role="tabpanel" aria-labelledby="exam-tab">
|
||||||
<form @submit.prevent="handleExamineeLogin" class="d-flex flex-column h-100">
|
<form @submit.prevent="handleExamineeLogin" class="d-flex flex-column h-100">
|
||||||
@ -60,7 +66,8 @@
|
|||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<font-awesome-icon :icon="['fas', 'key']" />
|
<font-awesome-icon :icon="['fas', 'key']" />
|
||||||
</span>
|
</span>
|
||||||
<input type="text" class="form-control" id="examineeAdmissionTicket" v-model="examineeAdmissionTicket" required>
|
<input type="text" class="form-control" id="examineeAdmissionTicket"
|
||||||
|
v-model="examineeAdmissionTicket" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex-grow-1 d-flex flex-column justify-content-end">
|
<div class="mt-4 flex-grow-1 d-flex flex-column justify-content-end">
|
||||||
@ -109,6 +116,8 @@
|
|||||||
import Header from '../components/common/Header.vue'
|
import Header from '../components/common/Header.vue'
|
||||||
import Footer from '../components/common/Footer.vue'
|
import Footer from '../components/common/Footer.vue'
|
||||||
import { Message } from 'element-ui'
|
import { Message } from 'element-ui'
|
||||||
|
// 导入Vuex store
|
||||||
|
import store from '../store/index.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WelcomeView',
|
name: 'WelcomeView',
|
||||||
@ -116,7 +125,7 @@ export default {
|
|||||||
Header,
|
Header,
|
||||||
Footer
|
Footer
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
examineeIdCard: '', // 身份证号
|
examineeIdCard: '', // 身份证号
|
||||||
examineeAdmissionTicket: '', // 准考证号
|
examineeAdmissionTicket: '', // 准考证号
|
||||||
@ -126,158 +135,179 @@ export default {
|
|||||||
isLoading: false // 添加加载状态
|
isLoading: false // 添加加载状态
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
this.checkDatabaseStatus()
|
this.checkDatabaseStatus()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async checkDatabaseStatus() {
|
async checkDatabaseStatus () {
|
||||||
try {
|
try {
|
||||||
console.log('组件挂载 - 开始检查数据库初始化状态');
|
console.log('组件挂载 - 开始检查数据库初始化状态')
|
||||||
const initialized = await window.electronAPI.checkDatabaseInitialized();
|
const initialized = await window.electronAPI.checkDatabaseInitialized()
|
||||||
console.log('组件挂载 - 数据库初始化状态检查完成:', initialized);
|
console.log('组件挂载 - 数据库初始化状态检查完成:', initialized)
|
||||||
this.isDatabaseInitialized = initialized;
|
this.isDatabaseInitialized = initialized
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('检查数据库初始化状态失败:', error);
|
console.error('检查数据库初始化状态失败:', error)
|
||||||
Message.error('检查数据库初始化状态失败,请重试');
|
Message.error('检查数据库初始化状态失败,请重试')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async initializeDatabase() {
|
async initializeDatabase () {
|
||||||
try {
|
try {
|
||||||
console.log('初始化数据库 - 开始');
|
console.log('初始化数据库 - 开始')
|
||||||
this.isInitializing = true;
|
this.isInitializing = true
|
||||||
Message.info('开始初始化数据库...');
|
Message.info('开始初始化数据库...')
|
||||||
|
|
||||||
const result = await window.electronAPI.initializeDatabase();
|
const result = await window.electronAPI.initializeDatabase()
|
||||||
console.log('初始化数据库 - 结果:', result);
|
console.log('初始化数据库 - 结果:', result)
|
||||||
|
|
||||||
// 修复:同时处理布尔值true和带success属性的对象
|
// 修复:同时处理布尔值true和带success属性的对象
|
||||||
if (result === true || (result && result.success)) {
|
if (result === true || (result && result.success)) {
|
||||||
Message.success('数据库初始化成功!');
|
Message.success('数据库初始化成功!')
|
||||||
console.log('初始化数据库 - 成功,更新初始化状态');
|
console.log('初始化数据库 - 成功,更新初始化状态')
|
||||||
this.isDatabaseInitialized = true;
|
this.isDatabaseInitialized = true
|
||||||
} else {
|
} else {
|
||||||
const errorMessage = result && result.error ? result.error : '未知错误';
|
const errorMessage = result && result.error ? result.error : '未知错误'
|
||||||
Message.error(`数据库初始化失败: ${errorMessage}`);
|
Message.error(`数据库初始化失败: ${errorMessage}`)
|
||||||
console.error('初始化数据库 - 失败:', errorMessage);
|
console.error('初始化数据库 - 失败:', errorMessage)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('数据库初始化失败:', error);
|
console.error('数据库初始化失败:', error)
|
||||||
Message.error(`数据库初始化失败: ${error.message || '未知错误'}`);
|
Message.error(`数据库初始化失败: ${error.message || '未知错误'}`)
|
||||||
} finally {
|
} finally {
|
||||||
console.log('初始化数据库 - 结束');
|
console.log('初始化数据库 - 结束')
|
||||||
this.isInitializing = false;
|
this.isInitializing = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleExamineeLogin() {
|
async handleExamineeLogin () {
|
||||||
console.log('考生登录 - 开始', {
|
console.log('考生登录 - 开始', {
|
||||||
examineeIdCard: this.examineeIdCard,
|
examineeIdCard: this.examineeIdCard,
|
||||||
examineeAdmissionTicket: this.examineeAdmissionTicket
|
examineeAdmissionTicket: this.examineeAdmissionTicket
|
||||||
});
|
})
|
||||||
|
|
||||||
// 清除首尾空格
|
// 清除首尾空格
|
||||||
const idCard = this.examineeIdCard.trim();
|
const idCard = this.examineeIdCard.trim()
|
||||||
const admissionTicket = this.examineeAdmissionTicket.trim();
|
const admissionTicket = this.examineeAdmissionTicket.trim()
|
||||||
|
|
||||||
// 前端验证
|
// 前端验证
|
||||||
if (!idCard || !admissionTicket) {
|
if (!idCard || !admissionTicket) {
|
||||||
console.warn('考生登录 - 验证失败: 身份证号和准考证号不能为空');
|
console.warn('考生登录 - 验证失败: 身份证号和准考证号不能为空')
|
||||||
Message.error('请输入身份证号和准考证号');
|
Message.error('请输入身份证号和准考证号')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置加载状态
|
// 设置加载状态
|
||||||
this.isLoading = true;
|
this.isLoading = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用登录API
|
// 调用登录API - 使用正确的参数格式
|
||||||
const result = await window.electronAPI.userLogin(idCard, admissionTicket);
|
const result = await window.electronAPI.userLogin({ idCard, admissionTicket })
|
||||||
console.log(result);
|
console.log('考生登录 - 结果:', result)
|
||||||
|
|
||||||
if (result && result.id) {
|
if (result && result.id) {
|
||||||
console.log('考生登录 - 成功', result);
|
console.log('考生登录 - 成功', result)
|
||||||
// 保存用户信息到store - 在Vue 2中通常使用Vuex
|
// 保存用户信息到store
|
||||||
if (this.$store && this.$store.commit) {
|
this.$store.commit('setExaminee', result)
|
||||||
this.$store.commit('setExaminee', result);
|
Message.success('登录成功')
|
||||||
}
|
|
||||||
Message.success('登录成功');
|
|
||||||
// 跳转到考生首页
|
// 跳转到考生首页
|
||||||
this.$router.push('/examinee/home');
|
this.$router.push('/examinee/home')
|
||||||
} else {
|
} else {
|
||||||
console.warn('考生登录 - 失败:', result);
|
console.warn('考生登录 - 失败:', result)
|
||||||
Message.error(result.error || '登录失败,请检查身份证号和准考证号');
|
Message.error(result && result.error ? result.error : '登录失败,请检查身份证号和准考证号')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('考生登录 - 异常:', error);
|
console.error('考生登录 - 异常:', error)
|
||||||
Message.error('登录失败,请重试');
|
Message.error(`登录失败: ${error.message || '未知错误'}`)
|
||||||
} finally {
|
} finally {
|
||||||
// 无论成功失败,都关闭加载状态
|
// 无论成功失败,都关闭加载状态
|
||||||
this.isLoading = false;
|
this.isLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleAdminLogin() {
|
// 修改handleAdminLogin方法
|
||||||
console.log('管理员登录 - 开始', { passwordLength: this.adminPassword.length });
|
async handleAdminLogin () {
|
||||||
|
console.log('管理员登录 - 开始', { passwordLength: this.adminPassword.length })
|
||||||
|
|
||||||
// 前端密码验证
|
// 前端密码验证
|
||||||
const passwordError = this.validateAdminPassword(this.adminPassword);
|
const passwordError = this.validateAdminPassword(this.adminPassword)
|
||||||
if (passwordError) {
|
if (passwordError) {
|
||||||
console.warn('管理员登录 - 验证失败:', passwordError);
|
console.warn('管理员登录 - 验证失败:', passwordError)
|
||||||
const errorElement = document.getElementById('admin-error-message');
|
const errorElement = document.getElementById('admin-error-message')
|
||||||
if (errorElement) {
|
if (errorElement) {
|
||||||
errorElement.textContent = passwordError;
|
errorElement.textContent = passwordError
|
||||||
errorElement.style.display = 'block';
|
errorElement.style.display = 'block'
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除之前的错误信息
|
// 清除之前的错误信息
|
||||||
const errorElement = document.getElementById('admin-error-message');
|
const errorElement = document.getElementById('admin-error-message')
|
||||||
if (errorElement) {
|
if (errorElement) {
|
||||||
errorElement.style.display = 'none';
|
errorElement.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('管理员登录 - 调用主进程登录方法');
|
console.log('管理员登录 - 调用主进程登录方法')
|
||||||
// 使用新的adminLogin方法
|
// 使用新的adminLogin方法
|
||||||
const result = await window.electronAPI.adminLogin({
|
const result = await window.electronAPI.adminLogin({
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
password: this.adminPassword
|
password: this.adminPassword
|
||||||
});
|
})
|
||||||
console.log('管理员登录 - 登录结果:', result);
|
console.log('管理员登录 - 登录结果:', result)
|
||||||
|
|
||||||
if (result && result.success) {
|
if (result && result.success) {
|
||||||
console.log('管理员登录 - 成功,跳转到管理首页');
|
console.log('管理员登录 - 成功,更新store状态并跳转')
|
||||||
Message.success('登录成功');
|
// 使用新的setAdmin mutation
|
||||||
this.$router.push('/admin/home');
|
this.$store.commit('setAdmin', { username: 'admin' })
|
||||||
|
Message.success('登录成功')
|
||||||
|
this.$router.push('/admin/home')
|
||||||
} else {
|
} else {
|
||||||
const errorMessage = result && result.message ? result.message : '登录失败';
|
const errorMessage = result && result.message ? result.message : '登录失败'
|
||||||
console.warn('管理员登录 - 失败:', errorMessage);
|
console.warn('管理员登录 - 失败:', errorMessage)
|
||||||
Message.error(errorMessage);
|
Message.error(errorMessage)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('管理员登录 - 异常:', error);
|
console.error('管理员登录 - 异常:', error)
|
||||||
Message.error(`登录异常: ${error.message || '未知错误'}`);
|
Message.error(`登录异常: ${error.message || '未知错误'}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validateAdminPassword(password) {
|
validateAdminPassword (password) {
|
||||||
// 检查密码是否为空
|
// 检查密码是否为空
|
||||||
if (!password) {
|
if (!password) {
|
||||||
return '请输入管理员密码';
|
return '请输入管理员密码'
|
||||||
}
|
}
|
||||||
// 检查密码长度
|
// 检查密码长度
|
||||||
if (password.length < 4 || password.length > 32) {
|
if (password.length < 4 || password.length > 32) {
|
||||||
return '密码长度必须在4-32个字符之间';
|
return '密码长度必须在4-32个字符之间'
|
||||||
}
|
}
|
||||||
// 检查密码是否只包含英文大小写和数字
|
// 检查密码是否只包含英文大小写和数字
|
||||||
const regex = /^[A-Za-z0-9]+$/;
|
const regex = /^[A-Za-z0-9]+$/
|
||||||
if (!regex.test(password)) {
|
if (!regex.test(password)) {
|
||||||
return '密码只能包含英文大小写字母和数字';
|
return '密码只能包含英文大小写字母和数字'
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
}
|
},
|
||||||
|
// 修改exitExam方法
|
||||||
|
async exitExam () {
|
||||||
|
this.$confirm(
|
||||||
|
'确定要退出考试吗?',
|
||||||
|
'退出确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 完全清除store中的数据
|
||||||
|
this.$store.commit('clearUser')
|
||||||
|
// 重定向到欢迎页
|
||||||
|
this.$router.push('/')
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消操作
|
||||||
|
console.log('用户取消退出')
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -311,9 +341,12 @@ export default {
|
|||||||
|
|
||||||
.main-background {
|
.main-background {
|
||||||
background-image: url('../assets/bg.jpeg');
|
background-image: url('../assets/bg.jpeg');
|
||||||
background-size: 100% 100%; /* 拉伸背景图以填满容器 */
|
background-size: 100% 100%;
|
||||||
background-position: center; /* 保持居中 */
|
/* 拉伸背景图以填满容器 */
|
||||||
background-repeat: no-repeat; /* 避免重复 */
|
background-position: center;
|
||||||
|
/* 保持居中 */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
/* 避免重复 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 适配移动设备 */
|
/* 适配移动设备 */
|
||||||
|
413
src/views/user/ExamineeHomeView.vue
Normal file
413
src/views/user/ExamineeHomeView.vue
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 添加外层容器确保占满整个空间 -->
|
||||||
|
<div class="student-home-container">
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- 考试须知卡片 -->
|
||||||
|
<div class="exam-card rounded-lg shadow-lg p-4 border-2">
|
||||||
|
<div class="flex justify-between text-center mb-2">
|
||||||
|
<h2 class="text-2xl font-bold text-primary">考生信息</h2>
|
||||||
|
</div>
|
||||||
|
<!-- 考生信息部分 -->
|
||||||
|
<el-descriptions class="margin-top" :column="3" :size="size" border>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-user mr-2" :style="iconStyle"></i>
|
||||||
|
姓名
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ examinee && examinee.examinee_name }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-id-card mr-2" :style="iconStyle"></i>
|
||||||
|
身份证号
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ formatIdCard(examinee && examinee.examinee_id_card) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-ticket mr-2" :style="iconStyle"></i>
|
||||||
|
准考证号
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ examinee && examinee.examinee_admission_ticket }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-divider />
|
||||||
|
<div class="flex justify-between text-center mt-4 mb-2">
|
||||||
|
<h2 class="text-2xl font-bold text-primary">考试信息</h2>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<el-descriptions class="margin-top" :column="2" :size="size" border>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-clock-o mr-2" :style="iconStyle"></i>
|
||||||
|
考试时长
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ lastExam && lastExam.exam_minutes }}分钟
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-hourglass-half mr-2" :style="iconStyle"></i>
|
||||||
|
最短考试时长
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ lastExam && lastExam.exam_minutes_min }}分钟
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-list-ol mr-2" :style="iconStyle"></i>
|
||||||
|
考题数量
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span class="text-gray-500">{{ totalQuestions }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template slot="label">
|
||||||
|
<div class="cell-item">
|
||||||
|
<i class="fa fa-list-ol mr-2" :style="iconStyle"></i>
|
||||||
|
考试总分
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span class="text-gray-500">{{ totalScore }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</div>
|
||||||
|
<el-divider />
|
||||||
|
<div class="flex justify-between text-center mt-4 mb-4">
|
||||||
|
<h2 class="text-2xl font-bold text-primary">考试须知</h2>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div v-if="!examLoading && examNotices.length > 0" class="space-y-2 pl-4">
|
||||||
|
<ol class="list-decimal pl-4 space-y-2">
|
||||||
|
<li v-for="(notice, index) in examNotices" :key="index" class="text-gray-700">
|
||||||
|
{{ notice }}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="examLoading" class="text-center text-gray-500 py-4">
|
||||||
|
加载考试信息中...
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-center text-gray-500 py-4">
|
||||||
|
暂无考试须知
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-6">
|
||||||
|
<el-button type="info" @click="exitExam">返回</el-button>
|
||||||
|
<el-button type="primary" @click="startExam" :loading="isLoading">开始考试</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ExamineeHomeView',
|
||||||
|
components: {
|
||||||
|
ElDescriptions: require('element-ui').Descriptions,
|
||||||
|
ElDescriptionsItem: require('element-ui').DescriptionsItem,
|
||||||
|
ElDivider: require('element-ui').Divider,
|
||||||
|
ElButton: require('element-ui').Button
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
size: 'default',
|
||||||
|
lastExam: null,
|
||||||
|
examLoading: true,
|
||||||
|
examNotices: [],
|
||||||
|
totalQuestions: 0,
|
||||||
|
totalScore: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
examinee() {
|
||||||
|
return this.$store.state.examinee
|
||||||
|
},
|
||||||
|
isLoggedIn() {
|
||||||
|
return this.$store.state.isLoggedIn
|
||||||
|
},
|
||||||
|
iconStyle() {
|
||||||
|
const marginMap = {
|
||||||
|
large: '8px',
|
||||||
|
default: '6px',
|
||||||
|
small: '4px'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
marginRight: marginMap[this.size] || marginMap.default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lastExam(newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
this.examLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isLoggedIn(newVal) {
|
||||||
|
if (!newVal) {
|
||||||
|
// 如果未登录,重定向到欢迎页
|
||||||
|
this.$router.push('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 检查是否已登录
|
||||||
|
if (!this.isLoggedIn) {
|
||||||
|
this.$router.push('/')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fetchLastExam()
|
||||||
|
this.getQuestionsCountAndScore()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 所有方法保持不变
|
||||||
|
// 格式化身份证号(第11-15位替换为*)
|
||||||
|
formatIdCard(idCard) {
|
||||||
|
if (!idCard || idCard.length !== 18) return idCard
|
||||||
|
return idCard.substring(0, 9) + '*****' + idCard.substring(14)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化考试时长(分钟转小时)
|
||||||
|
formatExamDuration(minutes) {
|
||||||
|
if (!minutes) return '未知'
|
||||||
|
const hours = Math.floor(minutes / 60)
|
||||||
|
const mins = minutes % 60
|
||||||
|
return `${hours}小时${mins}分钟`
|
||||||
|
},
|
||||||
|
|
||||||
|
// 得到考题数量和总分
|
||||||
|
async getQuestionsCountAndScore() {
|
||||||
|
try {
|
||||||
|
// 注意:这里需要确认接口是否存在
|
||||||
|
// 如果不存在,可能需要创建或修改现有接口
|
||||||
|
const result = await window.electronAPI.questionGetStatistics()
|
||||||
|
this.totalQuestions = result.totalQuestions || 0
|
||||||
|
this.totalScore = result.totalScore || 0
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取考题数量和总分失败:', error)
|
||||||
|
this.$message.error(`获取考题数量和总分失败: ${error.message || '未知错误'}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取最新考试信息
|
||||||
|
async fetchLastExam() {
|
||||||
|
this.examLoading = true
|
||||||
|
try {
|
||||||
|
// 调用Electron API获取最新考试信息
|
||||||
|
const examData = await window.electronAPI.examFetchLast()
|
||||||
|
this.lastExam = examData
|
||||||
|
|
||||||
|
// 解析考试须知数组
|
||||||
|
if (this.lastExam && this.lastExam.exam_notice) {
|
||||||
|
try {
|
||||||
|
// 尝试解析JSON字符串
|
||||||
|
if (typeof this.lastExam.exam_notice === 'string') {
|
||||||
|
this.examNotices = JSON.parse(this.lastExam.exam_notice)
|
||||||
|
} else if (Array.isArray(this.lastExam.exam_notice)) {
|
||||||
|
this.examNotices = this.lastExam.exam_notice
|
||||||
|
} else {
|
||||||
|
this.examNotices = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('解析考试须知失败,使用原始数据:', error)
|
||||||
|
this.examNotices = [this.lastExam.exam_notice]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.examNotices = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取考试信息失败:', error)
|
||||||
|
this.$message.error(`获取考试信息失败: ${error.message || '未知错误'}`)
|
||||||
|
} finally {
|
||||||
|
this.examLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 退出考试
|
||||||
|
exitExam() {
|
||||||
|
this.$confirm(
|
||||||
|
'确定要退出考试吗?',
|
||||||
|
'退出确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 完全清除store中的数据
|
||||||
|
this.$store.commit('clearExaminee')
|
||||||
|
// 重定向到欢迎页
|
||||||
|
this.$router.push('/')
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消操作
|
||||||
|
console.log('用户取消退出')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开始考试方法
|
||||||
|
async startExam() {
|
||||||
|
if (!this.lastExam) {
|
||||||
|
this.$message.warning('请先获取考试信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.examinee) {
|
||||||
|
this.$message.warning('未获取到考生信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('开始生成试卷...')
|
||||||
|
|
||||||
|
// 创建可序列化的考生数据对象
|
||||||
|
const examineeData = {
|
||||||
|
id: this.examinee.id,
|
||||||
|
examinee_name: this.examinee.examinee_name || '',
|
||||||
|
examinee_id_card: this.examinee.examinee_id_card || '',
|
||||||
|
examinee_admission_ticket: this.examinee.examinee_admission_ticket || '',
|
||||||
|
examinee_gender: this.examinee.examinee_gender || '',
|
||||||
|
examinee_unit: this.examinee.examinee_unit || '',
|
||||||
|
written_exam_room: this.examinee.written_exam_room || '',
|
||||||
|
written_exam_seat: this.examinee.written_exam_seat || '',
|
||||||
|
computer_exam_room: this.examinee.computer_exam_room || '',
|
||||||
|
computer_exam_seat: this.examinee.computer_exam_seat || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用JSON序列化/反序列化确保对象可克隆
|
||||||
|
const examData = JSON.parse(JSON.stringify({
|
||||||
|
id: this.lastExam.id,
|
||||||
|
exam_name: this.lastExam.exam_name || '',
|
||||||
|
exam_description: this.lastExam.exam_description || '',
|
||||||
|
exam_minutes: this.lastExam.exam_minutes || 0,
|
||||||
|
exam_minutes_min: this.lastExam.exam_minutes_min || 0,
|
||||||
|
exam_notice: this.lastExam.exam_notice || []
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 调用生成试卷API
|
||||||
|
const result = await window.electronAPI.examingGeneratePaper({
|
||||||
|
examineeId: examineeData.id,
|
||||||
|
examId: examData.id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result && result.success) {
|
||||||
|
console.log('生成试卷成功:', result)
|
||||||
|
// 由于Vuex store中没有setPaper方法,这里可以考虑添加或者直接传递参数
|
||||||
|
this.$alert(
|
||||||
|
'已完成组卷,点击"进入考试"开始答题',
|
||||||
|
'组卷完成',
|
||||||
|
{
|
||||||
|
confirmButtonText: '进入考试',
|
||||||
|
type: 'success'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 使用命名路由传递参数
|
||||||
|
this.$router.push({
|
||||||
|
name: 'examinee-examing',
|
||||||
|
params: { paperId: result.data.id }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error('生成试卷失败:', result)
|
||||||
|
this.$message.error(`生成试卷失败: ${result.message || '未知错误'}`)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('生成试卷异常:', error)
|
||||||
|
this.$message.error(`无法生成试卷: ${error.message || '未知错误'}`)
|
||||||
|
} finally {
|
||||||
|
this.isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 自定义样式 */
|
||||||
|
.bg-primary {
|
||||||
|
background-color: #1E88E5 !important;
|
||||||
|
/* 蓝色主题,与WelcomeView保持一致 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-primary {
|
||||||
|
color: #1E88E5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保容器占满可用空间 */
|
||||||
|
.student-home-container {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容包装器,用于居中卡片并使其可扩展 */
|
||||||
|
.content-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 考试卡片样式 - 响应式设计 */
|
||||||
|
.exam-card {
|
||||||
|
width: 100%;
|
||||||
|
min-height: calc(100vh - 4rem);
|
||||||
|
background-color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 适配中小屏幕 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.exam-card {
|
||||||
|
max-width: 100%;
|
||||||
|
min-height: calc(100vh - 2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 适配大屏幕 - 适当增加最大宽度但保留边距 */
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.exam-card {
|
||||||
|
max-width: 80vw;
|
||||||
|
max-height: 90vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 适配超大屏幕 - 进一步增加最大宽度 */
|
||||||
|
@media (min-width: 1600px) {
|
||||||
|
.exam-card {
|
||||||
|
max-width: 90vw;
|
||||||
|
max-height: 90vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-top {
|
||||||
|
margin-top: 20px !important;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user