ECS-Vue/src/views/auth/Login.vue

357 lines
7.3 KiB
Vue
Raw Normal View History

2025-02-17 23:06:19 +08:00
<template>
2025-02-18 14:02:00 +08:00
<transition name="fade" mode="out-in">
<div class="login-container">
<el-card class="login-box">
<h2>登录系统</h2>
<el-form
@submit.prevent="handleLogin"
:model="loginForm"
:rules="rules"
ref="loginForm"
>
<el-row class="form-item">
<el-col :span="6" class="label-col">
<label>用户名</label>
</el-col>
<el-col :span="14">
<el-input
v-model="loginForm.username"
placeholder="请输入用户名"
@keyup.enter="handleLogin"
></el-input>
</el-col>
</el-row>
<el-row class="form-item">
<el-col :span="6" class="label-col">
<label>密码</label>
</el-col>
<el-col :span="14">
<el-input
type="password"
v-model="loginForm.password"
placeholder="请输入密码"
@keyup.enter="handleLogin"
show-password
></el-input>
</el-col>
</el-row>
<el-button
type="primary"
@click="handleLogin"
class="submit-btn"
:class="{ 'button-loading': loading }"
@mouseenter="buttonHover = true"
@mouseleave="buttonHover = false"
>
<span class="button-text" :class="{ 'text-loading': loading }">
{{ loading ? '登录中...' : '登录' }}
</span>
<span class="button-effect"></span>
</el-button>
</el-form>
<div class="form-footer">
<p>还没有账号
<router-link to="/register" class="link-btn">
立即注册
<span class="arrow"></span>
</router-link>
</p>
2025-02-17 23:06:19 +08:00
</div>
2025-02-18 14:02:00 +08:00
</el-card>
2025-02-17 23:06:19 +08:00
</div>
2025-02-18 14:02:00 +08:00
</transition>
2025-02-17 23:06:19 +08:00
</template>
<script>
2025-03-26 17:38:40 +08:00
import { login } from '@/api/auth'
2025-02-17 23:06:19 +08:00
export default {
2025-02-18 14:02:00 +08:00
name: 'LoginPage',
2025-02-17 23:06:19 +08:00
data () {
return {
2025-02-18 14:02:00 +08:00
loginForm: {
username: '',
password: ''
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
]
},
loading: false,
buttonHover: false
2025-02-17 23:06:19 +08:00
}
},
methods: {
2025-03-26 17:38:40 +08:00
async handleLogin () {
// const params = {
// userName: this.loginForm.username,
// password: this.loginForm.password
// }
2025-02-18 14:02:00 +08:00
if (this.loading) return
2025-03-26 17:38:40 +08:00
this.$refs.loginForm.validate(async (valid) => {
2025-02-18 14:02:00 +08:00
if (valid) {
this.loading = true
console.log('登录信息:', this.loginForm)
2025-03-26 17:38:40 +08:00
try {
// 发送登录请求,注意这里要用 this.loginForm 作为参数
const response = await login(this.loginForm)
if (response.code === 200) {
this.$message.success('登录成功')
// 这里可以存储 token 或跳转页面
} else {
this.$message.error(response.msg || '登录失败')
}
} catch (error) {
this.$message.error(error.message || '请求失败')
} finally {
2025-02-18 14:02:00 +08:00
this.loading = false
2025-03-26 17:38:40 +08:00
}
2025-02-18 14:02:00 +08:00
} else {
return false
}
})
2025-02-17 23:06:19 +08:00
}
}
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
2025-02-18 14:02:00 +08:00
background: linear-gradient(135deg, #1abc9c 0%, #8e44ad 100%);
position: relative;
overflow: hidden;
}
.login-container::before {
content: '';
position: absolute;
width: 2000px;
height: 2000px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
top: -10%;
right: 48%;
transform: translateY(-50%);
animation: float 6s ease-in-out infinite;
}
.login-container::after {
content: '';
position: absolute;
width: 1500px;
height: 1500px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
top: -10%;
right: 52%;
transform: translateY(-50%);
animation: float 8s ease-in-out infinite;
2025-02-17 23:06:19 +08:00
}
.login-box {
2025-02-18 14:02:00 +08:00
width: 500px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
position: relative;
z-index: 1;
transform-origin: center center;
perspective: 1000px;
}
:deep(.el-card__body) {
padding: 30px;
backface-visibility: hidden;
}
h2 {
text-align: center;
margin-bottom: 30px;
color: #2c3e50;
}
.form-item {
margin-bottom: 20px;
display: flex;
align-items: center;
position: relative;
2025-02-17 23:06:19 +08:00
}
2025-02-18 14:02:00 +08:00
.label-col {
text-align: right;
padding-right: 20px;
line-height: 40px;
color: #606266;
font-weight: 500;
transition: all 0.3s ease;
2025-02-17 23:06:19 +08:00
}
2025-02-18 14:02:00 +08:00
.form-item:hover .label-col {
color: #409EFF;
2025-02-17 23:06:19 +08:00
}
2025-02-18 14:02:00 +08:00
.submit-btn {
width: 60%;
margin-top: 20px;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
height: 40px;
2025-02-17 23:06:19 +08:00
border: none;
2025-02-18 14:02:00 +08:00
}
.submit-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.submit-btn:active {
transform: translateY(0);
}
.button-text {
position: relative;
z-index: 1;
transition: all 0.3s ease;
}
.button-effect {
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255,255,255,0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: all 0.5s ease;
}
.submit-btn:hover .button-effect {
width: 300px;
height: 300px;
}
.button-loading {
background: #409EFF !important;
cursor: wait;
}
.text-loading {
animation: textLoading 1.5s infinite;
}
@keyframes textLoading {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
2025-02-17 23:06:19 +08:00
}
.form-footer {
2025-02-18 14:02:00 +08:00
margin-top: 20px;
2025-02-17 23:06:19 +08:00
text-align: center;
}
.form-footer a {
2025-02-18 14:02:00 +08:00
color: #409EFF;
2025-02-17 23:06:19 +08:00
text-decoration: none;
2025-02-18 14:02:00 +08:00
position: relative;
padding-right: 24px;
transition: all 0.3s ease;
}
.link-btn {
display: inline-flex;
align-items: center;
}
.arrow {
position: absolute;
right: 0;
opacity: 0;
transform: translateX(-8px);
transition: all 0.3s ease;
}
.link-btn:hover {
padding-right: 28px;
}
.link-btn:hover .arrow {
opacity: 1;
transform: translateX(0);
}
@keyframes float {
0% {
transform: translateY(-50%) rotate(0deg);
}
50% {
transform: translateY(-45%) rotate(180deg);
}
100% {
transform: translateY(-50%) rotate(360deg);
}
2025-02-17 23:06:19 +08:00
}
2025-02-18 14:02:00 +08:00
/* 页面过渡动画 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease, transform 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateX(-30px);
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
transform: translateX(0);
}
.el-input {
transition: all 0.3s ease;
}
.el-input:focus-within {
transform: translateX(5px);
}
/* 添加输入框焦点时的装饰线 */
.el-input:focus-within::after {
content: '';
position: absolute;
left: -10px;
top: 50%;
height: 60%;
width: 3px;
background: #409EFF;
transform: translateY(-50%);
border-radius: 3px;
animation: focusLine 0.3s ease;
}
@keyframes focusLine {
from {
opacity: 0;
transform: translateY(-50%) scaleY(0);
}
to {
opacity: 1;
transform: translateY(-50%) scaleY(1);
}
2025-02-17 23:06:19 +08:00
}
</style>