优化登录页面布局和动画效果
This commit is contained in:
parent
2fe89ff491
commit
906b5f37a7
@ -11,54 +11,90 @@
|
|||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<el-form class="form" :model="model" :rules="rules" ref="loginForm">
|
<!-- 动态 Blob 背景 -->
|
||||||
<!-- <h1 class="title">Vue3 Element Admin</h1>-->
|
<div class="blob-container">
|
||||||
<h1 class="title">凌空天行 AI大模型 应用系统</h1>
|
<div class="blob blob-1"></div>
|
||||||
<el-form-item prop="userName">
|
<div class="blob blob-2"></div>
|
||||||
<el-input
|
<div class="blob blob-3"></div>
|
||||||
class="text"
|
</div>
|
||||||
v-model="model.userName"
|
|
||||||
prefix-icon="User"
|
|
||||||
clearable
|
|
||||||
:placeholder="$t('login.username')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input
|
|
||||||
class="text"
|
|
||||||
v-model="model.password"
|
|
||||||
prefix-icon="Lock"
|
|
||||||
show-password
|
|
||||||
clearable
|
|
||||||
:placeholder="$t('login.password')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 页面结构 -->
|
<div class="shell">
|
||||||
<el-form-item prop="captcha">
|
<section class="brand-card">
|
||||||
<div class="captcha">
|
<!-- <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">
|
||||||
|
<div class="form-meta">
|
||||||
|
<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-input
|
<el-input
|
||||||
class="text"
|
class="text"
|
||||||
v-model="model.captcha"
|
v-model="model.userName"
|
||||||
prefix-icon="Picture"
|
prefix-icon="User"
|
||||||
placeholder="请输入验证码"
|
clearable
|
||||||
></el-input>
|
:placeholder="$t('login.username')"
|
||||||
<img :src="captchaSrc" @click="refreshCaptcha" />
|
/>
|
||||||
</div>
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
class="text"
|
||||||
|
v-model="model.password"
|
||||||
|
prefix-icon="Lock"
|
||||||
|
show-password
|
||||||
|
clearable
|
||||||
|
:placeholder="$t('login.password')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="captcha">
|
||||||
|
<div class="captcha">
|
||||||
|
<el-input
|
||||||
|
class="text"
|
||||||
|
v-model="model.captcha"
|
||||||
|
prefix-icon="Picture"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
/>
|
||||||
|
<img :src="captchaSrc" @click="refreshCaptcha" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
:loading="loading"
|
||||||
|
type="primary"
|
||||||
|
class="btn"
|
||||||
|
size="large"
|
||||||
|
@click="submit"
|
||||||
|
>
|
||||||
|
{{ btnText }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="divider">
|
||||||
|
<span>或</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button
|
<el-button
|
||||||
:loading="loading"
|
class="btn-sso"
|
||||||
type="primary"
|
|
||||||
class="btn"
|
|
||||||
size="large"
|
size="large"
|
||||||
@click="submit"
|
plain
|
||||||
|
@click="handleSsoLogin"
|
||||||
>
|
>
|
||||||
{{ btnText }}
|
企业SSO 一键登录
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form>
|
||||||
</el-form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="change-lang">
|
<div class="change-lang">
|
||||||
<change-lang />
|
<change-lang />
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user