优化登录页面布局和动画效果

This commit is contained in:
bakaECC 2025-12-10 16:28:16 +08:00
parent 2fe89ff491
commit 906b5f37a7

View File

@ -11,9 +11,32 @@
--> -->
<template> <template>
<div class="login"> <div class="login">
<!-- 动态 Blob 背景 -->
<div class="blob-container">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<div class="shell">
<section class="brand-card">
<!-- <div class="brand-chip">AEROSPACE · DIGITAL MISSION CONTROL</div> -->
<h1 class="headline">凌能空间 · AI大模型 应用系统</h1>
<p class="subline">
面向航天任务的智能中台支持知识与模型的协同编排
</p>
</section>
<el-form class="form" :model="model" :rules="rules" ref="loginForm"> <el-form class="form" :model="model" :rules="rules" ref="loginForm">
<!-- <h1 class="title">Vue3 Element Admin</h1>--> <div class="form-meta">
<h1 class="title">凌空天行 AI大模型 应用系统</h1> <div>
<p class="eyebrow">LOGIN</p>
<h2 class="title">登录工作台</h2>
<p class="title-desc">使用企业账户或SSO登录</p>
</div>
<!-- <div class="tag gradient">凌能空间</div> -->
</div>
<el-form-item prop="userName"> <el-form-item prop="userName">
<el-input <el-input
class="text" class="text"
@ -34,7 +57,6 @@
/> />
</el-form-item> </el-form-item>
<!-- 页面结构 -->
<el-form-item prop="captcha"> <el-form-item prop="captcha">
<div class="captcha"> <div class="captcha">
<el-input <el-input
@ -42,7 +64,7 @@
v-model="model.captcha" v-model="model.captcha"
prefix-icon="Picture" prefix-icon="Picture"
placeholder="请输入验证码" placeholder="请输入验证码"
></el-input> />
<img :src="captchaSrc" @click="refreshCaptcha" /> <img :src="captchaSrc" @click="refreshCaptcha" />
</div> </div>
</el-form-item> </el-form-item>
@ -58,8 +80,22 @@
{{ btnText }} {{ btnText }}
</el-button> </el-button>
</el-form-item> </el-form-item>
<div class="divider">
<span></span>
</div>
<el-button
class="btn-sso"
size="large"
plain
@click="handleSsoLogin"
>
企业SSO 一键登录
</el-button>
</el-form> </el-form>
</div> </div>
</div>
<div class="change-lang"> <div class="change-lang">
<change-lang /> <change-lang />
</div> </div>
@ -140,6 +176,13 @@ export default defineComponent({
state.loading ? ctx.$t('login.logining') : ctx.$t('login.login') state.loading ? ctx.$t('login.logining') : ctx.$t('login.login')
), ),
loginForm: ref(null), loginForm: ref(null),
ssoEndpoint: import.meta.env.VITE_SSO_URL || '/sso/login',
handleSsoLogin: () => {
const redirect = route.query.redirect || window.location.href
window.location.href = `${state.ssoEndpoint}?redirect=${encodeURIComponent(
redirect
)}`
},
submit: () => { submit: () => {
if (state.loading) { if (state.loading) {
return return
@ -188,32 +231,191 @@ export default defineComponent({
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px; margin-bottom: 10px;
gap: 12px;
} }
.captcha img { .captcha img {
cursor: pointer; cursor: pointer;
margin-left: 20px; border-radius: 8px;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
} }
// end // end
.login { .login {
transition: transform 1s; position: relative;
transform: scale(1);
width: 100%; width: 100%;
height: 100%; min-height: 100vh;
overflow: hidden; overflow: hidden;
background: #2d3a4b; padding: 64px 24px;
.form { display: flex;
align-items: center;
background: radial-gradient(circle at 15% 20%, rgba(120, 190, 255, 0.2), transparent 25%),
radial-gradient(circle at 80% 10%, rgba(132, 165, 255, 0.16), transparent 22%),
linear-gradient(135deg, #f5f8ff 0%, #eef4ff 45%, #e9f3ff 100%);
// Blob
.blob-container {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 0;
}
.blob {
position: absolute;
border-radius: 50%;
filter: blur(90px);
opacity: 0.55;
pointer-events: none;
mix-blend-mode: screen;
}
.blob-1 {
width: 520px; width: 520px;
max-width: 100%; height: 520px;
padding: 0 24px; background: linear-gradient(135deg, rgba(93, 156, 255, 0.22), rgba(141, 198, 255, 0.26));
top: -160px;
right: -180px;
animation: blob-float 18s ease-in-out infinite;
}
.blob-2 {
width: 480px;
height: 480px;
background: linear-gradient(135deg, rgba(126, 211, 180, 0.2), rgba(121, 189, 255, 0.24));
bottom: -150px;
left: -140px;
animation: blob-float-2 22s ease-in-out infinite;
}
.blob-3 {
width: 420px;
height: 420px;
background: linear-gradient(135deg, rgba(255, 214, 165, 0.24), rgba(161, 196, 253, 0.22));
top: 48%;
left: 50%;
transform: translate(-50%, -50%);
animation: blob-float-3 26s ease-in-out infinite;
}
.shell {
position: relative;
z-index: 10;
width: min(1200px, 100%);
margin: 0 auto;
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 32px;
align-items: stretch;
}
.brand-card {
padding: 32px;
border-radius: 24px;
background: linear-gradient(160deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.78) 100%);
border: 1px solid #e3eaf5;
box-shadow: 0 20px 60px rgba(47, 85, 151, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.9);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
color: #1f2b3d;
display: flex;
flex-direction: column;
gap: 16px;
}
.brand-chip {
display: inline-flex;
align-items: center;
padding: 6px 12px;
border-radius: 999px;
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
background: #eef3ff;
border: 1px solid #dce6f7;
color: #2e4b82;
}
.headline {
margin: 0;
font-size: 32px;
font-weight: 800;
color: #0f172a;
line-height: 1.2;
text-shadow: none;
}
.subline {
margin: 0;
font-size: 15px;
color: #4b5563;
line-height: 1.7;
}
.form {
position: relative;
z-index: 10;
width: 100%;
padding: 36px 32px;
box-sizing: border-box; box-sizing: border-box;
margin: 160px auto 0; background: #ffffff;
border: 1px solid #d7e0ef;
border-radius: 24px;
box-shadow:
0 18px 60px rgba(0, 0, 0, 0.25),
inset 0 1px 0 rgba(255, 255, 255, 0.4);
transition: all 0.3s ease;
&:hover {
box-shadow:
0 22px 70px rgba(15, 23, 42, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.95);
}
:deep { :deep {
.el-input__wrapper { .el-input__wrapper {
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1) inset; background: #f3f6fb;
background: rgba(0, 0, 0, 0.1); border: 1px solid #d7e0ef;
border-radius: 12px;
box-shadow:
0 2px 10px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.95);
transition: all 0.25s ease;
&:hover {
background: #ffffff;
border-color: #c2cfe4;
} }
&.is-focus {
background: #ffffff;
border-color: #4f8dfd;
box-shadow:
0 6px 18px rgba(79, 141, 253, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.95),
0 0 0 3px rgba(79, 141, 253, 0.16);
}
}
.el-input__inner {
color: #0f172a;
font-weight: 500;
&::placeholder {
color: #6b7280;
}
}
.el-input__prefix {
.el-icon {
color: #6b7280;
}
}
.el-input-group--append > .el-input__wrapper { .el-input-group--append > .el-input__wrapper {
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
@ -223,38 +425,183 @@ export default defineComponent({
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
} }
.title {
color: #fff; .form-meta {
text-align: center; display: flex;
font-size: 24px; justify-content: space-between;
margin: 0 0 24px; align-items: flex-start;
gap: 12px;
margin-bottom: 16px;
} }
.eyebrow {
margin: 0;
color: #6b7280;
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.title {
color: #0f172a;
font-size: 26px;
font-weight: 800;
margin: 4px 0 6px;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
.title-desc {
margin: 0;
color: #4b5563;
font-size: 13px;
}
.tag {
height: 28px;
padding: 0 12px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
color: #0b1628;
font-weight: 700;
font-size: 12px;
}
.gradient {
background: linear-gradient(120deg, #34d399 0%, #22d3ee 50%, #60a5fa 100%);
box-shadow: 0 10px 25px rgba(52, 211, 153, 0.4);
}
.text { .text {
font-size: 16px; font-size: 16px;
:deep(.el-input__inner) { :deep(.el-input__inner) {
color: #fff; color: #0f172a;
height: 48px; height: 48px;
line-height: 48px; line-height: 48px;
&::placeholder { &::placeholder {
color: rgba(255, 255, 255, 0.2); color: #6b7280;
} }
} }
} }
.btn { .btn {
width: 100%; width: 100%;
height: 48px;
font-size: 16px;
font-weight: 700;
border-radius: 12px;
background: linear-gradient(135deg, hsl(217 91% 60%) 0%, hsl(189 94% 50%) 100%);
border: none;
box-shadow:
0 4px 16px rgba(56, 189, 248, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
&:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow:
0 8px 24px rgba(56, 189, 248, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
&:active:not(:disabled) {
transform: translateY(0);
}
}
.divider {
display: flex;
align-items: center;
gap: 12px;
color: rgba(255, 255, 255, 0.6);
font-size: 12px;
margin: 6px 0 12px;
&::before,
&::after {
content: '';
flex: 1;
height: 1px;
background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0));
}
}
.btn-sso {
width: 100%;
height: 46px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.45);
color: #f8fbff;
font-weight: 700;
letter-spacing: 0.02em;
background: rgba(255, 255, 255, 0.12);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
transition: all 0.25s ease;
&:hover {
background: rgba(255, 255, 255, 0.18);
border-color: rgba(255, 255, 255, 0.7);
transform: translateY(-2px);
}
} }
} }
} }
@keyframes blob-float {
0% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(-20px, 20px, 0) scale(1.05);
}
100% {
transform: translate3d(0, 0, 0) scale(1);
}
}
@keyframes blob-float-2 {
0% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(24px, -16px, 0) scale(1.08);
}
100% {
transform: translate3d(0, 0, 0) scale(1);
}
}
@keyframes blob-float-3 {
0% {
transform: translate(-50%, -50%) scale(1);
}
50% {
transform: translate(-48%, -52%) scale(1.06);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}
.change-lang { .change-lang {
position: fixed; position: fixed;
right: 20px; right: 20px;
top: 20px; top: 20px;
z-index: 100;
:deep { :deep {
.change-lang { .change-lang {
height: 24px; height: 24px;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 8px;
padding: 4px 8px;
transition: all 0.3s ease;
&:hover { &:hover {
background: none; background: rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.4);
} }
.icon { .icon {
color: #fff; color: #fff;
} }