Files
jurong_circle_program_black…/src/views/Login.vue
2025-10-10 17:27:55 +08:00

358 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="login-container">
<div class="login-background">
<div class="bg-shape shape-1"></div>
<div class="bg-shape shape-2"></div>
<div class="bg-shape shape-3"></div>
</div>
<div class="login-card">
<div class="login-header">
<div class="logo">
<el-icon class="logo-icon"><Setting /></el-icon>
<h1 class="title">项目后台管理系统</h1>
</div>
<p class="subtitle">欢迎回来请登录您的账户</p>
</div>
<el-form
ref="loginFormRef"
:model="loginForm"
:rules="loginRules"
class="login-form"
@keyup.enter="handleLogin"
>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
placeholder="电话号码"
size="large"
prefix-icon="User"
clearable
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="密码"
size="large"
prefix-icon="Lock"
show-password
clearable
/>
</el-form-item>
<el-form-item prop="captcha">
<Captcha
ref="captchaRef"
v-model="loginForm.captcha"
placeholder="请输入验证码"
size="large"
/>
</el-form-item>
<div class="login-options">
<el-checkbox v-model="loginForm.remember">记住我</el-checkbox>
<el-link type="primary" :underline="false">忘记密码</el-link>
</div>
<el-button
type="primary"
size="large"
class="login-btn"
:loading="userStore.loading"
@click="handleLogin"
>
{{ userStore.loading ? '登录中...' : '登录' }}
</el-button>
</el-form>
<div class="login-footer">
<p>还没有账户<el-link type="primary" :underline="false" @click="goToRegister">立即注册</el-link></p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import { Setting } from '@element-plus/icons-vue'
import Captcha from '@/components/Captcha.vue'
const router = useRouter()
const userStore = useUserStore()
// 表单引用
const loginFormRef = ref()
const captchaRef = ref()
// 登录表单数据
const loginForm = reactive({
username: '',
password: '',
captcha: '',
remember: false
})
// 表单验证规则
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 {
await loginFormRef.value.validate()
// 验证验证码
// const captchaValid = await captchaRef.value.verifyCaptcha(loginForm.captcha)
const captchaInfo = captchaRef.value.getCaptchaInfo()
const result = await userStore.login({
username: loginForm.username,
password: loginForm.password,
captchaId: captchaInfo.captchaId,
captchaText: captchaInfo.captchaText
})
if (result.success) {
// 保存记住我状态
if (loginForm.remember) {
localStorage.setItem('admin_remember', 'true')
localStorage.setItem('admin_username', loginForm.username)
} else {
localStorage.removeItem('admin_remember')
localStorage.removeItem('admin_username')
}
// 跳转到仪表盘
router.push('/dashboard')
}
} catch (error) {
console.error('登录失败:', error)
}
}
// 跳转到注册页
const goToRegister = () => {
ElMessage.info('注册功能暂未开放,请联系管理员')
}
// 组件挂载时恢复记住的用户名
onMounted(() => {
const remember = localStorage.getItem('admin_remember')
const username = localStorage.getItem('admin_username')
if (remember === 'true' && username) {
loginForm.username = username
loginForm.remember = true
}
})
</script>
<style scoped>
.login-container {
position: relative;
width: 100vw;
height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.login-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.bg-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-card {
position: relative;
width: 400px;
padding: 40px;
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
z-index: 1;
}
.login-header {
text-align: center;
margin-bottom: 30px;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}
.logo-icon {
font-size: 32px;
color: #409eff;
margin-right: 10px;
}
.title {
font-size: 24px;
font-weight: 600;
color: #2c3e50;
margin: 0;
}
.subtitle {
color: #7f8c8d;
font-size: 14px;
margin: 0;
}
.login-form {
margin-bottom: 20px;
}
.login-form .el-form-item {
margin-bottom: 20px;
}
.login-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
}
.login-btn {
width: 100%;
height: 45px;
font-size: 16px;
font-weight: 500;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 8px;
transition: all 0.3s ease;
}
.login-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.quick-login {
margin: 20px 0;
}
.quick-login-buttons {
display: flex;
gap: 10px;
justify-content: center;
}
.login-footer {
text-align: center;
margin-top: 20px;
}
.login-footer p {
color: #7f8c8d;
font-size: 14px;
margin: 0;
}
/* 响应式设计 */
@media (max-width: 480px) {
.login-card {
width: 90%;
padding: 30px 20px;
}
.title {
font-size: 20px;
}
.quick-login-buttons {
flex-direction: column;
}
}
/* 输入框样式优化 */
.login-form :deep(.el-input__wrapper) {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.login-form :deep(.el-input__wrapper:hover) {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.login-form :deep(.el-input__wrapper.is-focus) {
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}
/* 按钮动画 */
.quick-login-buttons .el-button {
transition: all 0.3s ease;
}
.quick-login-buttons .el-button:hover {
transform: translateY(-2px);
}
</style>