Files
AIGC/demo/frontend/src/views/Login.vue

519 lines
11 KiB
Vue
Raw Normal View History

2025-10-21 16:50:33 +08:00
<template>
<div class="login-page">
<!-- Logo -->
<div class="logo">Logo</div>
<!-- 登录卡片 -->
<div class="login-card">
<!-- Logo图标 -->
<div class="card-logo">
<div class="logo-icon">Logo</div>
</div>
<!-- 欢迎文字 -->
<div class="welcome-text">
<h1>欢迎来到 Logo</h1>
<p>智创无限,灵感变现</p>
</div>
<!-- 登录表单 -->
<div class="login-form">
<!-- 手机号输入 -->
<div class="phone-input-group">
<div class="country-code">
<span>+86</span>
<el-icon><ArrowDown /></el-icon>
</div>
<el-input
v-model="loginForm.phone"
placeholder="请输入手机号"
class="phone-input"
/>
</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="getCode"
>
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</el-button>
</div>
<!-- 登录按钮 -->
<el-button
type="primary"
class="login-button"
:loading="userStore.loading"
@click="handleLogin"
>
{{ userStore.loading ? '登录中...' : '登陆/注册' }}
</el-button>
<!-- 协议文字 -->
<p class="agreement-text">
登录即表示您同意遵守用户协议和隐私政策
</p>
<!-- 测试账号提示 -->
<div class="test-accounts">
<el-divider>测试账号</el-divider>
<div class="account-list">
<div class="account-item" @click="fillTestAccount('15538239326', '0627')">
<strong>普通用户:</strong> 15538239326 / 0627
</div>
<div class="account-item" @click="fillTestAccount('15538239327', 'admin123')">
<strong>管理员:</strong> 15538239327 / admin123
</div>
<div class="account-item" @click="fillTestAccount('15538239328', 'test123')">
<strong>测试用户:</strong> 15538239328 / test123
</div>
<div class="account-item" @click="fillTestAccount('15538239329', '123456')">
<strong>个人主页:</strong> 15538239329 / 123456
</div>
</div>
</div>
</div>
</div>
</div>
</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'
import { ArrowDown } from '@element-plus/icons-vue'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const countdown = ref(0)
let countdownTimer = null
const loginForm = reactive({
phone: '',
code: ''
})
// 清除可能的缓存数据
const clearForm = () => {
loginForm.phone = ''
loginForm.code = ''
}
// 快速填充测试账号
const fillTestAccount = (username, password) => {
loginForm.phone = username
loginForm.code = password
}
// 组件挂载时清除表单
onMounted(() => {
clearForm()
})
// 获取验证码
const getCode = () => {
if (!loginForm.phone) {
ElMessage.warning('请先输入手机号')
return
}
if (!/^1[3-9]\d{9}$/.test(loginForm.phone)) {
ElMessage.warning('请输入正确的手机号')
return
}
// 模拟发送验证码
ElMessage.success('验证码已发送')
// 开始倒计时
countdown.value = 60
countdownTimer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
clearInterval(countdownTimer)
countdownTimer = null
}
}, 1000)
}
const handleLogin = async () => {
if (!loginForm.phone) {
ElMessage.warning('请输入手机号')
return
}
if (!loginForm.code) {
ElMessage.warning('请输入验证码')
return
}
if (!/^1[3-9]\d{9}$/.test(loginForm.phone)) {
ElMessage.warning('请输入正确的手机号')
return
}
try {
console.log('开始登录...')
// 模拟验证码登录这里可以调用实际的API
// 为了演示,我们使用手机号作为用户名,验证码作为密码
const mockForm = {
username: loginForm.phone,
password: loginForm.code
}
const result = await userStore.loginUser(mockForm)
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>
.login-page {
min-height: 100vh;
width: 100vw;
height: 100vh;
background: transparent;
position: fixed;
top: 0;
left: 0;
2025-10-21 16:50:33 +08:00
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 0;
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%;
right: 8%;
transform: translateY(-50%);
width: 500px;
background: rgba(26, 26, 46, 0.8);
backdrop-filter: blur(20px);
border-radius: 24px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
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;
}
/* 手机号输入组 */
.phone-input-group {
display: flex;
gap: 12px;
}
.country-code {
width: 100px;
height: 55px;
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
2025-10-21 16:50:33 +08:00
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
2025-10-21 16:50:33 +08:00
}
.country-code:hover {
background: rgba(0, 0, 0, 0.5);
}
.country-code .el-icon {
margin-left: 6px;
font-size: 14px;
}
.phone-input {
flex: 1;
}
.phone-input :deep(.el-input__wrapper) {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
2025-10-21 16:50:33 +08:00
border-radius: 10px;
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;
}
.phone-input :deep(.el-input__inner) {
color: white;
background: transparent;
font-size: 16px;
}
.phone-input :deep(.el-input__inner::placeholder) {
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);
border: 1px solid rgba(255, 255, 255, 0.1);
2025-10-21 16:50:33 +08:00
border-radius: 10px;
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;
border: 1px solid rgba(255, 255, 255, 0.05);
2025-10-21 16:50:33 +08:00
cursor: pointer;
transition: all 0.3s ease;
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;
right: auto;
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;
}
.phone-input-group,
.code-input-group {
flex-direction: column;
gap: 15px;
}
.country-code {
width: 100%;
}
}
</style>