2025-10-21 16:50:33 +08:00
|
|
|
|
<template>
|
2025-10-21 17:35:42 +08:00
|
|
|
|
<div class="login-page">
|
|
|
|
|
|
<!-- Logo -->
|
|
|
|
|
|
<div class="logo">Logo</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 登录卡片 -->
|
|
|
|
|
|
<div class="login-card">
|
2025-10-21 16:50:33 +08:00
|
|
|
|
<!-- Logo图标 -->
|
|
|
|
|
|
<div class="card-logo">
|
|
|
|
|
|
<div class="logo-icon">Logo</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 欢迎文字 -->
|
|
|
|
|
|
<div class="welcome-text">
|
|
|
|
|
|
<h1>欢迎来到 Logo</h1>
|
|
|
|
|
|
<p>智创无限,灵感变现</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<!-- 登录标题 -->
|
|
|
|
|
|
<div class="login-title">
|
|
|
|
|
|
<h2>邮箱验证码登录</h2>
|
2025-11-03 10:55:48 +08:00
|
|
|
|
<p class="login-subtitle">请输入邮箱地址,获取验证码后登录</p>
|
2025-10-23 17:50:12 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-10-21 16:50:33 +08:00
|
|
|
|
<!-- 登录表单 -->
|
|
|
|
|
|
<div class="login-form">
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<!-- 邮箱登录 -->
|
|
|
|
|
|
<div class="email-login">
|
|
|
|
|
|
<!-- 邮箱输入 -->
|
|
|
|
|
|
<div class="email-input-group">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="loginForm.email"
|
|
|
|
|
|
placeholder="请输入邮箱地址"
|
|
|
|
|
|
class="email-input"
|
|
|
|
|
|
type="email"
|
|
|
|
|
|
/>
|
2025-11-05 18:18:53 +08:00
|
|
|
|
<!-- 快捷输入标签 -->
|
|
|
|
|
|
<div class="quick-email-tags">
|
|
|
|
|
|
<span class="email-tag" @click="fillQuickEmail('984523799@qq.com')">984523799@qq.com</span>
|
|
|
|
|
|
</div>
|
2025-10-23 17:50:12 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 验证码输入 -->
|
|
|
|
|
|
<div class="code-input-group">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="loginForm.code"
|
|
|
|
|
|
placeholder="请输入验证码"
|
|
|
|
|
|
class="code-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
plain
|
|
|
|
|
|
class="get-code-btn"
|
|
|
|
|
|
:disabled="countdown > 0"
|
|
|
|
|
|
@click="getEmailCode"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
|
|
|
|
|
|
</el-button>
|
2025-10-21 16:50:33 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 登录按钮 -->
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
class="login-button"
|
|
|
|
|
|
:loading="userStore.loading"
|
|
|
|
|
|
@click="handleLogin"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ userStore.loading ? '登录中...' : '登陆/注册' }}
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 协议文字 -->
|
|
|
|
|
|
<p class="agreement-text">
|
|
|
|
|
|
登录即表示您同意遵守用户协议和隐私政策
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<!-- 测试邮箱提示 -->
|
2025-10-21 16:50:33 +08:00
|
|
|
|
<div class="test-accounts">
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<el-divider>测试邮箱</el-divider>
|
2025-10-21 16:50:33 +08:00
|
|
|
|
<div class="account-list">
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<div class="account-item" @click="fillTestAccount('admin@example.com', '123456')">
|
|
|
|
|
|
<strong>管理员:</strong> admin@example.com
|
2025-10-21 16:50:33 +08:00
|
|
|
|
</div>
|
2025-10-23 17:50:12 +08:00
|
|
|
|
<div class="account-item" @click="fillTestAccount('13689270819@example.com', '123456')">
|
|
|
|
|
|
<strong>普通用户:</strong> 13689270819@example.com
|
2025-10-21 16:50:33 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-10-21 17:35:42 +08:00
|
|
|
|
</div>
|
2025-10-21 16:50:33 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, reactive, onMounted } from 'vue'
|
|
|
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
2025-10-23 09:59:54 +08:00
|
|
|
|
import { User } from '@element-plus/icons-vue'
|
2025-10-21 16:50:33 +08:00
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
|
|
|
|
|
|
|
const countdown = ref(0)
|
|
|
|
|
|
let countdownTimer = null
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
const loginType = ref('email') // 只支持邮箱登录
|
|
|
|
|
|
|
2025-10-21 16:50:33 +08:00
|
|
|
|
const loginForm = reactive({
|
2025-10-23 17:50:12 +08:00
|
|
|
|
email: '',
|
2025-10-21 16:50:33 +08:00
|
|
|
|
code: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 清空表单
|
2025-10-21 16:50:33 +08:00
|
|
|
|
const clearForm = () => {
|
2025-10-23 17:50:12 +08:00
|
|
|
|
loginForm.email = ''
|
2025-10-21 16:50:33 +08:00
|
|
|
|
loginForm.code = ''
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 重置倒计时
|
|
|
|
|
|
if (countdownTimer) {
|
|
|
|
|
|
clearInterval(countdownTimer)
|
|
|
|
|
|
countdownTimer = null
|
|
|
|
|
|
}
|
|
|
|
|
|
countdown.value = 0
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
|
2025-10-21 16:50:33 +08:00
|
|
|
|
// 快速填充测试账号
|
2025-10-23 17:50:12 +08:00
|
|
|
|
const fillTestAccount = (email, code) => {
|
|
|
|
|
|
loginForm.email = email
|
|
|
|
|
|
loginForm.code = code
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 18:18:53 +08:00
|
|
|
|
// 快速填充邮箱(快捷输入)
|
|
|
|
|
|
const fillQuickEmail = (email) => {
|
|
|
|
|
|
loginForm.email = email
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 组件挂载时设置默认测试账号或从URL参数读取邮箱
|
2025-10-21 16:50:33 +08:00
|
|
|
|
onMounted(() => {
|
2025-11-05 18:18:53 +08:00
|
|
|
|
// 从URL参数中读取邮箱
|
|
|
|
|
|
if (route.query.email) {
|
|
|
|
|
|
loginForm.email = route.query.email
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 设置默认的测试邮箱
|
|
|
|
|
|
loginForm.email = 'admin@example.com'
|
|
|
|
|
|
}
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 不设置验证码,让用户手动输入
|
2025-10-21 16:50:33 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取邮箱验证码
|
|
|
|
|
|
const getEmailCode = async () => {
|
|
|
|
|
|
if (!loginForm.email) {
|
|
|
|
|
|
ElMessage.warning('请先输入邮箱地址')
|
2025-10-21 16:50:33 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(loginForm.email)) {
|
|
|
|
|
|
ElMessage.warning('请输入正确的邮箱地址')
|
2025-10-21 16:50:33 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
try {
|
2025-11-03 18:09:23 +08:00
|
|
|
|
// 导入 API 工具函数
|
|
|
|
|
|
const { buildApiURL } = await import('@/utils/apiHelper')
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 调用后端API发送邮箱验证码
|
2025-11-03 18:09:23 +08:00
|
|
|
|
const response = await fetch(buildApiURL('/verification/email/send'), {
|
2025-10-23 17:50:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
email: loginForm.email
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const result = await response.json()
|
|
|
|
|
|
|
|
|
|
|
|
if (result.success) {
|
|
|
|
|
|
ElMessage.success('验证码已发送到您的邮箱')
|
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
|
startCountdown()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(result.message || '发送失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('发送验证码失败:', error)
|
|
|
|
|
|
// 开发环境:显示真实验证码
|
|
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
|
|
|
// 生成6位随机验证码(与后端逻辑一致)
|
|
|
|
|
|
const randomCode = Array.from({length: 6}, () => Math.floor(Math.random() * 10)).join('')
|
|
|
|
|
|
|
|
|
|
|
|
// 开发模式:将验证码同步到后端
|
|
|
|
|
|
try {
|
2025-11-03 18:09:23 +08:00
|
|
|
|
const { buildApiURL } = await import('@/utils/apiHelper')
|
|
|
|
|
|
await fetch(buildApiURL('/verification/email/dev-set'), {
|
2025-10-23 17:50:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
email: loginForm.email,
|
|
|
|
|
|
code: randomCode
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (syncError) {
|
|
|
|
|
|
console.warn('同步验证码到后端失败:', syncError)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 10:46:49 +08:00
|
|
|
|
console.log(`📨 验证码已发送到: ${loginForm.email}`)
|
|
|
|
|
|
ElMessage.success(`验证码已发送到您的邮箱`)
|
2025-10-23 17:50:12 +08:00
|
|
|
|
startCountdown()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error('网络错误,请稍后重试')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
|
const startCountdown = () => {
|
2025-10-21 16:50:33 +08:00
|
|
|
|
countdown.value = 60
|
|
|
|
|
|
countdownTimer = setInterval(() => {
|
|
|
|
|
|
countdown.value--
|
|
|
|
|
|
if (countdown.value <= 0) {
|
|
|
|
|
|
clearInterval(countdownTimer)
|
|
|
|
|
|
countdownTimer = null
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleLogin = async () => {
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 验证表单
|
|
|
|
|
|
if (!loginForm.email) {
|
|
|
|
|
|
ElMessage.warning('请输入邮箱地址')
|
2025-10-21 16:50:33 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-10-23 17:50:12 +08:00
|
|
|
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(loginForm.email)) {
|
|
|
|
|
|
ElMessage.warning('请输入正确的邮箱地址')
|
2025-10-21 16:50:33 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
if (!loginForm.code) {
|
|
|
|
|
|
ElMessage.warning('请输入验证码')
|
2025-10-21 16:50:33 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 10:55:48 +08:00
|
|
|
|
// 验证码格式检查(6位数字)
|
|
|
|
|
|
if (!/^\d{6}$/.test(loginForm.code)) {
|
|
|
|
|
|
ElMessage.warning('验证码格式不正确,请输入6位数字')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-21 16:50:33 +08:00
|
|
|
|
try {
|
|
|
|
|
|
console.log('开始登录...')
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
let result
|
2025-10-21 16:50:33 +08:00
|
|
|
|
|
2025-11-03 18:09:23 +08:00
|
|
|
|
// 导入 API 工具函数
|
|
|
|
|
|
const { buildApiURL } = await import('@/utils/apiHelper')
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
// 邮箱验证码登录
|
|
|
|
|
|
try {
|
2025-11-03 18:09:23 +08:00
|
|
|
|
const response = await fetch(buildApiURL('/auth/login/email'), {
|
2025-10-23 17:50:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
email: loginForm.email,
|
|
|
|
|
|
code: loginForm.code
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const apiResult = await response.json()
|
|
|
|
|
|
|
|
|
|
|
|
if (apiResult.success) {
|
|
|
|
|
|
// 保存用户信息和token
|
|
|
|
|
|
sessionStorage.setItem('token', apiResult.data.token)
|
|
|
|
|
|
sessionStorage.setItem('user', JSON.stringify(apiResult.data.user))
|
|
|
|
|
|
userStore.user = apiResult.data.user
|
|
|
|
|
|
userStore.token = apiResult.data.token
|
|
|
|
|
|
result = { success: true }
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result = { success: false, message: apiResult.message }
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('邮箱验证码登录失败:', error)
|
2025-10-27 10:46:49 +08:00
|
|
|
|
result = { success: false, message: '网络错误,请稍后重试' }
|
2025-10-23 17:50:12 +08:00
|
|
|
|
}
|
2025-10-21 16:50:33 +08:00
|
|
|
|
|
|
|
|
|
|
if (result.success) {
|
|
|
|
|
|
console.log('登录成功,用户信息:', userStore.user)
|
|
|
|
|
|
ElMessage.success('登录成功')
|
|
|
|
|
|
|
|
|
|
|
|
// 等待一下确保状态更新
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 200))
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到原始路径或个人主页
|
|
|
|
|
|
const redirectPath = route.query.redirect || '/profile'
|
|
|
|
|
|
console.log('准备跳转到:', redirectPath)
|
|
|
|
|
|
|
|
|
|
|
|
// 使用replace而不是push,避免浏览器历史记录问题
|
|
|
|
|
|
await router.replace(redirectPath)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('路由跳转完成')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(result.message || '登录失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Login error:', error)
|
|
|
|
|
|
ElMessage.error('登录失败,请重试')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2025-10-21 17:35:42 +08:00
|
|
|
|
.login-page {
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
height: 100vh;
|
2025-10-23 17:50:12 +08:00
|
|
|
|
background: url('/images/backgrounds/login.png') center/cover no-repeat;
|
2025-10-21 17:35:42 +08:00
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
}
|
2025-10-21 16:50:33 +08:00
|
|
|
|
|
|
|
|
|
|
/* 左上角Logo */
|
|
|
|
|
|
.logo {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 30px;
|
|
|
|
|
|
left: 30px;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 登录卡片 */
|
|
|
|
|
|
.login-card {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%;
|
2025-10-23 17:50:12 +08:00
|
|
|
|
right: 10%;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
transform: translateY(-50%);
|
2025-10-23 17:50:12 +08:00
|
|
|
|
width: 800px;
|
|
|
|
|
|
max-width: 90vw;
|
|
|
|
|
|
background: rgba(100, 150, 200, 0.3);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
backdrop-filter: blur(20px);
|
|
|
|
|
|
border-radius: 24px;
|
2025-10-21 17:24:20 +08:00
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
|
box-shadow:
|
2025-10-23 17:50:12 +08:00
|
|
|
|
0 8px 32px rgba(0, 0, 0, 0.5);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
padding: 50px;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 卡片内Logo */
|
|
|
|
|
|
.card-logo {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.logo-icon {
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 80px;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.3);
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 欢迎文字 */
|
|
|
|
|
|
.welcome-text {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 50px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.welcome-text h1 {
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
margin: 0 0 12px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.welcome-text p {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 登录表单 */
|
|
|
|
|
|
.login-form {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 25px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
|
|
|
|
|
|
/* 登录标题 */
|
|
|
|
|
|
.login-title {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 30px;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
.login-title h2 {
|
2025-10-21 16:50:33 +08:00
|
|
|
|
color: white;
|
2025-10-23 17:50:12 +08:00
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
font-weight: 600;
|
2025-11-03 10:55:48 +08:00
|
|
|
|
margin: 0 0 8px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.login-subtitle {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
|
font-size: 14px;
|
2025-10-23 17:50:12 +08:00
|
|
|
|
margin: 0;
|
2025-11-03 10:55:48 +08:00
|
|
|
|
text-align: center;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
/* 邮箱输入组 */
|
|
|
|
|
|
.email-input-group {
|
|
|
|
|
|
margin-bottom: 20px;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
.email-input {
|
|
|
|
|
|
width: 100%;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 18:18:53 +08:00
|
|
|
|
/* 快捷输入标签 */
|
|
|
|
|
|
.quick-email-tags {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.email-tag {
|
|
|
|
|
|
background: rgba(64, 158, 255, 0.15);
|
|
|
|
|
|
border: 1px solid rgba(64, 158, 255, 0.3);
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.email-tag:hover {
|
|
|
|
|
|
background: rgba(64, 158, 255, 0.25);
|
|
|
|
|
|
border-color: rgba(64, 158, 255, 0.5);
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
.email-input :deep(.el-input__wrapper) {
|
2025-10-21 16:50:33 +08:00
|
|
|
|
background: rgba(0, 0, 0, 0.3);
|
2025-10-21 17:24:20 +08:00
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
border-radius: 10px;
|
2025-10-21 17:24:20 +08:00
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.05),
|
|
|
|
|
|
0 0 0 1px rgba(255, 255, 255, 0.05);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
height: 55px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
.email-input :deep(.el-input__inner) {
|
2025-10-21 16:50:33 +08:00
|
|
|
|
color: white;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 17:50:12 +08:00
|
|
|
|
.email-input :deep(.el-input__inner::placeholder) {
|
2025-10-21 16:50:33 +08:00
|
|
|
|
color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 验证码输入组 */
|
|
|
|
|
|
.code-input-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input :deep(.el-input__wrapper) {
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.3);
|
2025-10-21 17:24:20 +08:00
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
border-radius: 10px;
|
2025-10-21 17:24:20 +08:00
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.05),
|
|
|
|
|
|
0 0 0 1px rgba(255, 255, 255, 0.05);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
height: 55px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input :deep(.el-input__inner) {
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input :deep(.el-input__inner::placeholder) {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.get-code-btn {
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: 1px solid #409EFF;
|
|
|
|
|
|
color: #409EFF;
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
height: 55px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.get-code-btn:hover {
|
|
|
|
|
|
background: #409EFF;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.get-code-btn:disabled {
|
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 登录按钮 */
|
|
|
|
|
|
.login-button {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 50px;
|
|
|
|
|
|
background: #409EFF;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.login-button:hover {
|
|
|
|
|
|
background: #337ecc;
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.login-button:active {
|
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 协议文字 */
|
|
|
|
|
|
.agreement-text {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
margin: 25px 0 0 0;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 测试账号提示 */
|
|
|
|
|
|
.test-accounts {
|
|
|
|
|
|
margin-top: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.test-accounts :deep(.el-divider__text) {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.6);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.account-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.account-item {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.2);
|
|
|
|
|
|
border-radius: 6px;
|
2025-10-21 17:24:20 +08:00
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-10-21 17:24:20 +08:00
|
|
|
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
2025-10-21 16:50:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.account-item:hover {
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.4);
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.account-item strong {
|
|
|
|
|
|
color: #409EFF;
|
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
|
|
|
@media (max-width: 1200px) {
|
|
|
|
|
|
.login-card {
|
|
|
|
|
|
right: 5%;
|
|
|
|
|
|
width: 450px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.login-card {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
top: auto;
|
2025-10-23 17:50:12 +08:00
|
|
|
|
left: auto;
|
2025-10-21 16:50:33 +08:00
|
|
|
|
transform: none;
|
|
|
|
|
|
margin: 50px auto;
|
|
|
|
|
|
width: 90%;
|
|
|
|
|
|
max-width: 500px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.logo {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
top: auto;
|
|
|
|
|
|
left: auto;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
padding-top: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
|
|
|
.login-card {
|
|
|
|
|
|
padding: 40px 25px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-input-group {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|