blob: fb85c7056157f781471c0fd0528e831cfbd4f585 [file] [log] [blame]
<template>
<div class="login-page">
<!-- 背景装饰 -->
<div class="bg-decoration">
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
</div>
<!-- 登录表单容器 -->
<div class="login-container">
<div class="login-card">
<!-- 头部信息 -->
<div class="login-header">
<div class="logo">
<el-icon size="48" color="#667eea"><Operation /></el-icon>
</div>
<h1 class="title">PT Tracker</h1>
<p class="subtitle">私有种子分享社区</p>
</div>
<!-- 登录表单 -->
<el-form
ref="loginFormRef"
:model="loginForm"
:rules="loginRules"
class="login-form"
size="large"
>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
placeholder="请输入用户名或邮箱"
clearable
:prefix-icon="User"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码"
show-password
:prefix-icon="Lock"
@keyup.enter="handleLogin"
/>
</el-form-item>
<el-form-item>
<div class="login-options">
<el-checkbox v-model="rememberMe">记住登录</el-checkbox>
<el-link type="primary" :underline="false">忘记密码?</el-link>
</div>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:loading="loading"
style="width: 100%"
@click="handleLogin"
>
<span v-if="!loading">登录</span>
<span v-else>登录中...</span>
</el-button>
</el-form-item>
</el-form>
<!-- 底部链接 -->
<div class="login-footer">
<span class="footer-text">还没有账号?</span>
<el-link
type="primary"
:underline="false"
@click="$router.push('/register')"
>
立即注册
</el-link>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { User, Lock, Operation } from '@element-plus/icons-vue'
export default {
name: 'LoginView',
components: {
Operation
},
setup() {
const router = useRouter()
const loginFormRef = ref()
const loading = ref(false)
const rememberMe = ref(false)
// 表单数据
const loginForm = reactive({
username: '',
password: ''
})
// 验证规则
const loginRules = {
username: [
{ required: true, message: '请输入用户名或邮箱', trigger: 'blur' },
{ min: 3, message: '用户名至少3个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码至少6个字符', trigger: 'blur' }
]
}
// 登录处理
const handleLogin = async () => {
try {
// 表单验证
const valid = await loginFormRef.value.validate()
if (!valid) return
loading.value = true
// 模拟登录API请求
await new Promise(resolve => setTimeout(resolve, 1000))
// 简单的登录验证(实际项目中应该调用后端API)
if (loginForm.username === 'admin' && loginForm.password === '123456') {
// 登录成功
localStorage.setItem('isLoggedIn', 'true')
localStorage.setItem('username', loginForm.username)
localStorage.setItem('loginTime', new Date().toISOString())
if (rememberMe.value) {
localStorage.setItem('rememberLogin', 'true')
}
ElMessage.success('登录成功!欢迎回来')
router.push('/home')
} else {
ElMessage.error('用户名或密码错误,请重试')
}
} catch (error) {
console.error('登录失败:', error)
ElMessage.error('登录失败,请稍后重试')
} finally {
loading.value = false
}
}
return {
loginFormRef,
loginForm,
loginRules,
loading,
rememberMe,
handleLogin,
User,
Lock
}
}
}
</script>
<style lang="scss" scoped>
.login-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
// 背景装饰
.bg-decoration {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 1;
.shape {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
animation: float 6s ease-in-out infinite;
&.shape-1 {
width: 200px;
height: 200px;
top: 10%;
left: 10%;
animation-delay: 0s;
}
&.shape-2 {
width: 150px;
height: 150px;
top: 60%;
right: 10%;
animation-delay: -2s;
}
&.shape-3 {
width: 100px;
height: 100px;
bottom: 20%;
left: 20%;
animation-delay: -4s;
}
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-20px) rotate(180deg);
}
}
// 登录容器
.login-container {
position: relative;
z-index: 10;
width: 100%;
max-width: 420px;
}
.login-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.login-header {
text-align: center;
margin-bottom: 32px;
.logo {
margin-bottom: 16px;
}
.title {
font-size: 32px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 8px;
letter-spacing: -0.5px;
}
.subtitle {
font-size: 15px;
color: #7f8c8d;
margin: 0;
font-weight: 400;
}
}
.login-form {
.el-form-item {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
}
.login-options {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.el-checkbox {
:deep(.el-checkbox__label) {
font-size: 14px;
color: #606266;
}
}
.el-link {
font-size: 14px;
}
}
.el-button {
font-size: 16px;
font-weight: 500;
height: 48px;
border-radius: 8px;
}
}
.login-footer {
text-align: center;
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid #ebeef5;
.footer-text {
color: #909399;
font-size: 14px;
margin-right: 8px;
}
.el-link {
font-size: 14px;
font-weight: 500;
}
}
}
// 响应式设计
@media (max-width: 768px) {
.login-page {
padding: 16px;
}
.login-card {
padding: 32px 24px;
.login-header .title {
font-size: 28px;
}
}
}
</style>