428 lines
16 KiB
Vue
428 lines
16 KiB
Vue
<template>
|
||
<div class="welcome-container main-background">
|
||
<el-container>
|
||
<Header />
|
||
|
||
<!-- 主要内容区域 -->
|
||
<el-main>
|
||
<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="text-center">
|
||
<div class="mb-6">
|
||
<i class="fa fa-database text-primary" style="font-size: 64px;"></i>
|
||
</div>
|
||
<h2 class="display-6 mb-4">系统未初始化</h2>
|
||
<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">
|
||
<i v-if="isInitializing" class="fa fa-spinner fa-spin me-2"></i>
|
||
<i v-else class="fa fa-refresh me-2"></i>
|
||
{{ isInitializing ? '初始化中...' : '数据初始化' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 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">
|
||
<!-- 登录类型切换标签页 -->
|
||
<ul class="nav nav-tabs fs-4" id="loginTab" role="tablist">
|
||
<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">
|
||
<i class="fa fa-graduation-cap me-2"></i>
|
||
考生登录
|
||
</button>
|
||
</li>
|
||
<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">
|
||
<i class="fa fa-cog me-2"></i>
|
||
系统管理
|
||
</button>
|
||
</li>
|
||
</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="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">
|
||
<div class="mb-3 flex-grow-1 d-flex flex-column justify-content-center">
|
||
<label for="examineeIdCard" class="form-label">身份证号</label>
|
||
<div class="input-group input-group-lg">
|
||
<span class="input-group-text">
|
||
<font-awesome-icon :icon="['fas', 'id-card']" />
|
||
</span>
|
||
<input type="text" class="form-control" id="examineeIdCard" v-model="examineeIdCard" required>
|
||
</div>
|
||
</div>
|
||
<div class="mb-3 flex-grow-1 d-flex flex-column justify-content-center">
|
||
<label for="examineeAdmissionTicket" class="form-label">准考证号</label>
|
||
<div class="input-group input-group-lg">
|
||
<span class="input-group-text">
|
||
<font-awesome-icon :icon="['fas', 'key']" />
|
||
</span>
|
||
<input type="text" class="form-control" id="examineeAdmissionTicket"
|
||
v-model="examineeAdmissionTicket" required>
|
||
</div>
|
||
</div>
|
||
<div class="mt-4 flex-grow-1 d-flex flex-column justify-content-end">
|
||
<button type="submit" class="btn btn-primary w-100 py-2 fs-5">
|
||
<i class="fa fa-sign-in me-2"></i>
|
||
登录
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 管理员登录表单 -->
|
||
<div class="h-100 tab-pane fade" id="admin-login" role="tabpanel" aria-labelledby="admin-tab">
|
||
<form @submit.prevent="handleAdminLogin" class="d-flex flex-column h-100">
|
||
<div class="mb-3 flex-grow-1 d-flex flex-column justify-content-center">
|
||
<label for="password" class="form-label">管理员密码</label>
|
||
<div class="input-group input-group-lg">
|
||
<span class="input-group-text">
|
||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||
</span>
|
||
<input type="password" class="form-control" id="password" v-model="adminPassword" required>
|
||
</div>
|
||
<div id="admin-error-message" class="text-danger mt-2" style="display: none;"></div>
|
||
</div>
|
||
<div class="mt-4 flex-grow-1 d-flex flex-column justify-content-end">
|
||
<button type="submit" class="btn btn-primary w-100 py-2 fs-5" :disabled="isLoading">
|
||
<i v-if="isLoading" class="fa fa-spinner fa-spin me-2"></i>
|
||
<i v-else class="fa fa-sign-in me-2"></i>
|
||
{{ isLoading ? '登录中...' : '登录' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-main>
|
||
|
||
<Footer />
|
||
</el-container>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
// 导入组件
|
||
import Header from '../components/common/Header.vue'
|
||
import Footer from '../components/common/Footer.vue'
|
||
import { Message } from 'element-ui'
|
||
// 导入Vuex store
|
||
import store from '../store/index.js'
|
||
|
||
export default {
|
||
name: 'WelcomeView',
|
||
components: {
|
||
Header,
|
||
Footer
|
||
},
|
||
data () {
|
||
return {
|
||
examineeIdCard: '', // 身份证号
|
||
examineeAdmissionTicket: '', // 准考证号
|
||
adminPassword: '',
|
||
isDatabaseInitialized: false,
|
||
isInitializing: false,
|
||
isLoading: false // 添加加载状态
|
||
}
|
||
},
|
||
mounted () {
|
||
console.log('mounted: 调用this.checkDatabaseStatus方法')
|
||
this.checkDatabaseStatus()
|
||
console.log('mounted: 调用this.checkDatabaseStatus方法完成')
|
||
this.checkAndInitializeUserDb()
|
||
|
||
// 添加:打印路径信息,帮助排查便携模式问题
|
||
this.logPathInformation()
|
||
},
|
||
methods: {
|
||
// 新增:打印路径信息
|
||
async logPathInformation() {
|
||
try {
|
||
if (window.electronAPI) {
|
||
console.log('===== 路径信息开始 =====');
|
||
|
||
// 获取并打印appDir
|
||
try {
|
||
// 通过获取exe路径来间接获取appDir
|
||
const exePath = await window.electronAPI.getExePath();
|
||
const appDir = exePath ? exePath.substring(0, exePath.lastIndexOf('\\')) : '无法获取';
|
||
console.log('应用程序目录(appDir):', appDir);
|
||
} catch (error) {
|
||
console.error('获取appDir失败:', error);
|
||
}
|
||
|
||
// 获取并打印数据库路径
|
||
// try {
|
||
// // 由于没有直接获取数据库路径的API,我们通过检查数据库状态的日志来推断
|
||
// console.log('尝试获取数据库路径信息...');
|
||
// // 触发一次数据库检查以生成相关日志
|
||
// await window.electronAPI.checkDatabaseInitialized();
|
||
// } catch (error) {
|
||
// console.error('触发数据库检查失败:', error);
|
||
// }
|
||
|
||
// 尝试直接获取system.db和user.db路径
|
||
if (window.electronAPI.getDatabasePaths) {
|
||
try {
|
||
const paths = await window.electronAPI.getDatabasePaths();
|
||
console.log('system.db路径:', paths.systemDbPath);
|
||
console.log('user.db路径:', paths.userDbPath);
|
||
} catch (error) {
|
||
console.error('获取数据库路径失败:', error);
|
||
}
|
||
}
|
||
|
||
console.log('===== 路径信息结束 =====');
|
||
} else {
|
||
console.log('electronAPI不存在,无法获取路径信息');
|
||
}
|
||
} catch (error) {
|
||
console.error('打印路径信息时出错:', error);
|
||
}
|
||
},
|
||
|
||
// 检查并静默初始化用户数据库
|
||
async checkAndInitializeUserDb() {
|
||
try {
|
||
console.log('检查user.db是否存在...')
|
||
const userDbExists = await window.electronAPI.checkUserDbExists()
|
||
console.log('user.db存在状态:', userDbExists)
|
||
|
||
if (!userDbExists) {
|
||
console.log('user.db不存在,开始静默初始化...')
|
||
await window.electronAPI.initializeUserDatabaseSilently()
|
||
console.log('user.db静默初始化完成')
|
||
}
|
||
} catch (error) {
|
||
console.error('检查或初始化user.db失败:', error)
|
||
// 这里不显示错误信息,因为是静默初始化
|
||
}
|
||
},
|
||
|
||
async checkDatabaseStatus () {
|
||
try {
|
||
console.log('组件挂载 - 开始检查数据库初始化状态')
|
||
const initialized = await window.electronAPI.checkDatabaseInitialized()
|
||
console.log('组件挂载 - 数据库初始化状态检查完成:', initialized)
|
||
this.isDatabaseInitialized = initialized
|
||
} catch (error) {
|
||
console.error('检查数据库初始化状态失败:', error)
|
||
Message.error('检查数据库初始化状态失败,请重试')
|
||
}
|
||
},
|
||
|
||
async initializeDatabase () {
|
||
try {
|
||
console.log('初始化数据库 - 开始')
|
||
this.isInitializing = true
|
||
Message.info('开始初始化数据库...')
|
||
|
||
const result = await window.electronAPI.initializeDatabase()
|
||
console.log('初始化数据库 - 结果:', result)
|
||
|
||
// 修复:同时处理布尔值true和带success属性的对象
|
||
if (result === true || (result && result.success)) {
|
||
Message.success('数据库初始化成功!')
|
||
console.log('初始化数据库 - 成功,更新初始化状态')
|
||
this.isDatabaseInitialized = true
|
||
} else {
|
||
const errorMessage = result && result.error ? result.error : '未知错误'
|
||
Message.error(`数据库初始化失败: ${errorMessage}`)
|
||
console.error('初始化数据库 - 失败:', errorMessage)
|
||
}
|
||
} catch (error) {
|
||
console.error('数据库初始化失败:', error)
|
||
Message.error(`数据库初始化失败: ${error.message || '未知错误'}`)
|
||
} finally {
|
||
console.log('初始化数据库 - 结束')
|
||
this.isInitializing = false
|
||
}
|
||
},
|
||
|
||
async handleExamineeLogin () {
|
||
console.log('考生登录 - 开始', {
|
||
examineeIdCard: this.examineeIdCard,
|
||
examineeAdmissionTicket: this.examineeAdmissionTicket
|
||
})
|
||
|
||
// 清除首尾空格
|
||
const idCard = this.examineeIdCard.trim()
|
||
const admissionTicket = this.examineeAdmissionTicket.trim()
|
||
|
||
// 前端验证
|
||
if (!idCard || !admissionTicket) {
|
||
console.warn('考生登录 - 验证失败: 身份证号和准考证号不能为空')
|
||
Message.error('请输入身份证号和准考证号')
|
||
return
|
||
}
|
||
|
||
// 设置加载状态
|
||
this.isLoading = true
|
||
|
||
try {
|
||
// 调用登录API - 使用正确的参数格式
|
||
const result = await window.electronAPI.userLogin({ idCard, admissionTicket })
|
||
console.log('考生登录 - 结果:', result)
|
||
|
||
if (result && result.id) {
|
||
console.log('考生登录 - 成功', result)
|
||
// 保存用户信息到store
|
||
this.$store.commit('setExaminee', result)
|
||
Message.success('登录成功')
|
||
// 跳转到考生首页
|
||
this.$router.push('/examinee/home')
|
||
} else {
|
||
console.warn('考生登录 - 失败:', result)
|
||
Message.error(result && result.error ? result.error : '登录失败,请检查身份证号和准考证号')
|
||
}
|
||
} catch (error) {
|
||
console.error('考生登录 - 异常:', error)
|
||
Message.error(`登录失败: ${error.message || '未知错误'}`)
|
||
} finally {
|
||
// 无论成功失败,都关闭加载状态
|
||
this.isLoading = false
|
||
}
|
||
},
|
||
|
||
// 修改handleAdminLogin方法
|
||
async handleAdminLogin () {
|
||
console.log('管理员登录 - 开始', { passwordLength: this.adminPassword.length })
|
||
|
||
// 前端密码验证
|
||
const passwordError = this.validateAdminPassword(this.adminPassword)
|
||
if (passwordError) {
|
||
console.warn('管理员登录 - 验证失败:', passwordError)
|
||
const errorElement = document.getElementById('admin-error-message')
|
||
if (errorElement) {
|
||
errorElement.textContent = passwordError
|
||
errorElement.style.display = 'block'
|
||
}
|
||
return
|
||
}
|
||
|
||
// 清除之前的错误信息
|
||
const errorElement = document.getElementById('admin-error-message')
|
||
if (errorElement) {
|
||
errorElement.style.display = 'none'
|
||
}
|
||
|
||
try {
|
||
console.log('管理员登录 - 调用主进程登录方法')
|
||
// 使用新的adminLogin方法
|
||
const result = await window.electronAPI.adminLogin({
|
||
username: 'admin',
|
||
password: this.adminPassword
|
||
})
|
||
console.log('管理员登录 - 登录结果:', result)
|
||
|
||
if (result && result.success) {
|
||
console.log('管理员登录 - 成功,更新store状态并跳转')
|
||
// 使用新的setAdmin mutation
|
||
this.$store.commit('setAdmin', { username: 'admin' })
|
||
Message.success('登录成功')
|
||
this.$router.push('/admin/home')
|
||
} else {
|
||
const errorMessage = result && result.message ? result.message : '登录失败'
|
||
console.warn('管理员登录 - 失败:', errorMessage)
|
||
Message.error(errorMessage)
|
||
}
|
||
} catch (error) {
|
||
console.error('管理员登录 - 异常:', error)
|
||
Message.error(`登录异常: ${error.message || '未知错误'}`)
|
||
}
|
||
},
|
||
|
||
validateAdminPassword (password) {
|
||
// 检查密码是否为空
|
||
if (!password) {
|
||
return '请输入管理员密码'
|
||
}
|
||
// 检查密码长度
|
||
if (password.length < 4 || password.length > 32) {
|
||
return '密码长度必须在4-32个字符之间'
|
||
}
|
||
// 检查密码是否只包含英文大小写和数字
|
||
const regex = /^[A-Za-z0-9]+$/
|
||
if (!regex.test(password)) {
|
||
return '密码只能包含英文大小写字母和数字'
|
||
}
|
||
return null
|
||
},
|
||
// 修改exitExam方法
|
||
async exitExam () {
|
||
this.$confirm(
|
||
'确定要退出考试吗?',
|
||
'退出确认',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}
|
||
).then(() => {
|
||
// 完全清除store中的数据
|
||
this.$store.commit('clearUser')
|
||
// 重定向到欢迎页
|
||
this.$router.push('/')
|
||
}).catch(() => {
|
||
// 用户取消操作
|
||
console.log('用户取消退出')
|
||
})
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 自定义样式 */
|
||
.bg-primary {
|
||
background-color: #1E88E5 !important;
|
||
/* 蓝色主题 */
|
||
}
|
||
|
||
.text-primary {
|
||
color: #1E88E5 !important;
|
||
}
|
||
|
||
/* 确保容器占满高度 */
|
||
.welcome-container,
|
||
.el-container {
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 让主内容区自动扩展并居中 */
|
||
.el-main {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.main-background {
|
||
background-image: url('../assets/bg.jpeg');
|
||
background-size: 100% 100%;
|
||
/* 拉伸背景图以填满容器 */
|
||
background-position: center;
|
||
/* 保持居中 */
|
||
background-repeat: no-repeat;
|
||
/* 避免重复 */
|
||
}
|
||
|
||
/* 适配移动设备 */
|
||
@media (max-width: 640px) {
|
||
.max-w-md {
|
||
max-width: 100%;
|
||
}
|
||
}
|
||
</style> |