<template>
<div class="login_container">
<!-- 登录盒子 -->
<div class="login-box">
<h2 class="title">欢迎回来</h2>
<p class="subtitle">请登录您的账户</p>
<!-- 登录表单 -->
<el-form
ref="loginForm"
:model="form"
:rules="rules"
label-width="0px"
class="login-form"
>
<!-- 用户名 -->
<el-form-item prop="username">
<el-input
v-model="form.username"
prefix-icon="el-icon-user"
placeholder="用户名 / 邮箱"
clearable
@keydown.enter.native="login"
/>
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<el-input
v-model="form.password"
prefix-icon="el-icon-key"
placeholder="请输入密码"
type="password"
clearable
@keydown.enter.native="login"
/>
</el-form-item>
<!-- 验证码 -->
<el-form-item prop="validCode">
<div class="captcha-container">
<el-input
v-model="form.validCode"
prefix-icon="el-icon-lock"
placeholder="验证码"
@keydown.enter.native="login"
style="flex: 1; margin-right: 10px"
/>
<ValidCode @input="getValidCode" ref="child" class="unselectable" />
</div>
</el-form-item>
<!-- 按钮组 -->
<el-form-item class="btn-group">
<el-button
type="primary"
class="btn login-btn"
@click="login"
:loading="loading"
>
{{ loading ? "登录中..." : "登 录" }}
</el-button>
<el-button
type="info"
class="btn register-btn"
@click="$router.push('/register')"
>
注 册
</el-button>
<el-button type="warning" class="btn admin-btn" @click="jump">
管理员入口
</el-button>
<el-button type="warning" class="btn admin-btn" @click="jump">
站长入口
</el-button>
</el-form-item>
</el-form>
<!-- 渐隐提示 -->
<p class="footer-tip">游客体验:guest / 123456</p>
</div>
</div>
</template>
<script>
import ValidCode from "@/components/ValidCode.vue";
import request from "@/utils/request";
export default {
name: "Login",
components: { ValidCode },
created() {
document.title = "团购商城 - 登录";
},
data() {
return {
form: {
username: "",
password: "",
validCode: "",
},
validCode: "",
loading: false,
rules: {
username: [
{ required: true, message: "请输入用户名!", trigger: "blur" },
{
min: 2,
max: 25,
message: "长度在 2 到 25 个字符",
trigger: "blur",
},
],
password: [
{ required: true, message: "请输入密码!", trigger: "blur" },
{
min: 6,
max: 15,
message: "建议密码长度为 6-15 位",
trigger: "blur",
},
],
validCode: [
{ required: true, message: "请输入验证码!", trigger: "blur" },
],
},
};
},
methods: {
getValidCode(data) {
this.validCode = data;
},
login() {
this.$refs.loginForm.validate((valid) => {
if (!valid) return;
if (
this.form.validCode.toLowerCase() !== this.validCode.toLowerCase()
) {
this.$message.error("验证码错误");
this.$refs.child.refreshCode();
return;
}
this.loading = true;
request
.post("/user/login", this.form)
.then((res) => {
if (res.code === "0") {
this.$message.success("登录成功!");
sessionStorage.setItem("user", JSON.stringify(res.data));
this.$router.push("/shop");
} else {
this.$message.error(res.msg || "登录失败");
this.$refs.child.refreshCode();
}
})
.catch(() => {
this.$message.error("网络异常,请稍后重试");
})
.finally(() => {
this.loading = false;
});
});
},
jump() {
this.$router.push("/manageLogin");
},
jumptwo() {
this.$router.push("/adsenseLogin");
},
},
};
</script>
<style lang="less" scoped>
// 超美渐变背景 + SVG 光点纹理
.login_container {
height: 100vh;
background: linear-gradient(135deg, #7f7fd5, #86a8e7, #91eae4);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
display: flex;
justify-content: center;
align-items: center;
font-family: "Segoe UI", "Helvetica Neue", "Microsoft YaHei", sans-serif;
position: relative;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='0.08' fill-rule='evenodd'%3E%3Ccircle cx='2' cy='2' r='2'/%3E%3C/g%3E%3C/svg%3E");
pointer-events: none;
opacity: 0.6;
}
}
@keyframes gradientBG {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
// 登录框:毛玻璃 + 投影 + 圆角
.login-box {
width: 440px;
padding: 55px 60px 45px;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.12),
0 1px 10px rgba(255, 255, 255, 0.6) inset;
border: 1px solid rgba(255, 255, 255, 0.4);
text-align: center;
z-index: 10;
transition: transform 0.3s ease;
&:hover {
transform: translateY(-5px);
}
.title {
color: #333;
font-size: 32px;
margin-bottom: 10px;
font-weight: 700;
letter-spacing: 1px;
}
.subtitle {
color: #666;
font-size: 15px;
margin-bottom: 35px;
font-weight: 400;
}
}
// 表单样式优化
.login-form {
/deep/ .el-input__inner {
height: 52px !important;
line-height: 52px !important;
border-radius: 16px;
border: 1px solid #ddd;
background-color: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 15px;
padding-left: 45px;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
&:focus {
border-color: #7f7fd5;
box-shadow: 0 0 0 4px rgba(127, 127, 213, 0.2);
transform: scale(1.03);
}
}
/deep/ .el-input__prefix {
display: flex;
align-items: center;
margin-left: 12px;
color: #aaa;
font-size: 18px;
}
}
.captcha-container {
display: flex;
align-items: center;
gap: 10px;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 14px;
margin-top: 20px !important;
.btn {
height: 52px;
border-radius: 16px;
font-size: 17px;
font-weight: 600;
letter-spacing: 1px;
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
&:hover {
transform: translateY(-3px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
&:active {
transform: translateY(0);
}
}
.login-btn {
background: linear-gradient(to right, #6a11cb, #2575fc);
border: none;
color: white;
box-shadow: 0 6px 18px rgba(106, 17, 203, 0.3);
}
.register-btn {
background: rgba(255, 255, 255, 0.9);
border: 1px solid #ddd;
color: #555;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.admin-btn {
background: linear-gradient(to right, #f79533, #f37055);
border: none;
color: white;
font-weight: bold;
box-shadow: 0 6px 16px rgba(243, 112, 85, 0.3);
}
}
.footer-tip {
margin-top: 25px;
font-size: 13px;
color: rgba(0, 0, 0, 0.4);
font-style: italic;
}
</style>
美化一下\