<template>
|
<div class="login-container">
|
<!-- <div class="login-background">-->
|
<!-- <div class="gradient-overlay"></div>-->
|
<!-- </div>-->
|
|
<el-card class="login-card">
|
<div class="brand-section">
|
<img
|
src="~@/assets/images/img.png"
|
class="brand-logo"
|
alt="系统logo"
|
/>
|
<h1 class="system-name">接口自动化平台</h1>
|
</div>
|
|
<el-form
|
ref="loginForm"
|
@submit.native.prevent="submitForm"
|
class="login-form"
|
>
|
<el-form-item>
|
<el-input
|
v-model="loginForm.username"
|
placeholder="账号"
|
prefix-icon="el-icon-user-solid"
|
class="custom-input"
|
:class="{ 'input-error': usernameInvalid }"
|
@blur="validateUserName"
|
/>
|
<transition name="el-zoom-in-top">
|
<div v-if="usernameInvalid" class="error-msg">{{ usernameInvalid }}</div>
|
</transition>
|
</el-form-item>
|
|
<el-form-item>
|
<el-input
|
v-model="loginForm.password"
|
type="password"
|
placeholder="密码"
|
prefix-icon="el-icon-lock"
|
show-password
|
class="custom-input"
|
:class="{ 'input-error': passwordInvalid }"
|
@blur="validatePassword"
|
/>
|
<transition name="el-zoom-in-top">
|
<div v-if="passwordInvalid" class="error-msg">{{ passwordInvalid }}</div>
|
</transition>
|
</el-form-item>
|
|
<el-button
|
type="primary"
|
class="login-button"
|
:loading="isLoading"
|
@click="submitForm"
|
>
|
{{ isLoading ? '登录中...' : '立即登录' }}
|
</el-button>
|
</el-form>
|
</el-card>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: "Login",
|
|
data() {
|
return {
|
isLoading: false,
|
loginForm: {
|
username: "",
|
password: ""
|
},
|
usernameInvalid: "",
|
passwordInvalid: ""
|
};
|
},
|
|
methods: {
|
validateUserName() {
|
if (this.loginForm.username.replace(/(^\s*)/g, "") === "") {
|
this.usernameInvalid = "用户名不能为空";
|
return false;
|
}
|
return true;
|
},
|
validatePassword() {
|
if (this.loginForm.password.replace(/(^\s*)/g, "") === "") {
|
this.passwordInvalid = "密码不能为空";
|
return false;
|
}
|
return true;
|
},
|
handleLoginSuccess(resp) {
|
if (resp.success) {
|
// 显示登录信息提示
|
this.showLoginNotification(resp);
|
|
// 原有路由跳转和存储逻辑
|
this.$router.push({ name: "ProjectList" });
|
this.$store.commit("isLogin", resp.token);
|
this.$store.commit("setUser", resp.user);
|
this.$store.commit("setName", resp.name);
|
this.$store.commit("setId", resp.id);
|
this.$store.commit("setIsSuperuser", resp.is_superuser);
|
this.$store.commit("setRouterName", "ProjectList");
|
this.$store.commit("setShowHosts", resp.show_hosts);
|
|
this.setLocalValue("token", resp.token);
|
this.setLocalValue("user", resp.user);
|
this.setLocalValue("name", resp.name);
|
this.setLocalValue("id", resp.id);
|
this.setLocalValue("is_superuser", resp.is_superuser);
|
this.setLocalValue("routerName", "ProjectList");
|
this.setLocalValue("show_hosts", resp.show_hosts);
|
} else {
|
this.$message.error({
|
message: resp.msg,
|
duration: 2000,
|
center: true
|
});
|
}
|
},
|
|
showLoginNotification(resp) {
|
const currentTime = new Date().toLocaleString();
|
|
this.$notify({
|
title: '登录成功',
|
message: `登录时间: ${currentTime}`,
|
type: 'success',
|
duration: 3000,
|
position: 'top-right'
|
});
|
},
|
submitForm() {
|
if (this.validateUserName() && this.validatePassword()) {
|
this.isLoading = true;
|
this.$api.login(this.loginForm).then(resp => {
|
this.handleLoginSuccess(resp);
|
this.isLoading = false;
|
});
|
}
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.login-container {
|
min-height: 100vh;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
position: relative;
|
overflow: hidden;
|
}
|
|
.login-background {
|
position: absolute;
|
width: 100%;
|
height: 100%;
|
background: rgba(255, 255, 255, 0.1);
|
opacity: 0.1;
|
}
|
|
.gradient-overlay {
|
position: absolute;
|
width: 100%;
|
height: 100%;
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2) 0%, rgba(118, 75, 162, 0.2) 100%);
|
}
|
|
.login-card {
|
width: 420px;
|
border-radius: 12px;
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
|
border: none;
|
z-index: 1;
|
background: rgba(255, 255, 255, 0.95);
|
}
|
|
.brand-section {
|
text-align: center;
|
margin-bottom: 2rem;
|
}
|
|
.brand-logo {
|
width: 120px; /* 尺寸放大50% */
|
height: auto;
|
margin-bottom: 1.5rem; /* 增加下边距保持间距 */
|
transition: transform 0.3s ease; /* 添加悬停动效 */
|
}
|
|
/* 可选悬停效果 */
|
.brand-logo:hover {
|
transform: scale(1.05);
|
}
|
|
.system-name {
|
font-size: 2rem; /* 同步放大系统名称字号 */
|
margin-top: 0.5rem; /* 增加与LOGO的间距 */
|
}
|
|
.system-name {
|
color: #2c3e50;
|
font-size: 1.8rem;
|
font-weight: 600;
|
letter-spacing: 1px;
|
margin: 0;
|
}
|
|
.login-form {
|
margin: 2rem 0;
|
}
|
|
.custom-input {
|
transition: all 0.3s ease;
|
}
|
|
.custom-input:hover {
|
transform: translateY(-2px);
|
}
|
|
.input-error >>> .el-input__inner {
|
border-color: #ff4757;
|
}
|
|
.error-msg {
|
color: #ff4757;
|
font-size: 0.85rem;
|
margin-top: 4px;
|
animation: shake 0.4s ease;
|
}
|
|
@keyframes shake {
|
0%, 100% { transform: translateX(0); }
|
25% { transform: translateX(5px); }
|
75% { transform: translateX(-5px); }
|
}
|
|
.login-button {
|
width: 100%;
|
height: 45px;
|
font-size: 1.1rem;
|
letter-spacing: 2px;
|
border-radius: 8px;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
border: none;
|
transition: all 0.3s ease;
|
}
|
|
.login-button:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 5px 15px rgba(118, 75, 162, 0.3);
|
}
|
</style>
|