| <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> |