feat(登录页): 重新设计登录页面
- 采用居中卡片布局设计 - 左侧展示品牌区域和认证动画 - 右侧提供登录表单 - 使用灰白色背景提升视觉体验 - 添加响应式设计支持移动端 - 优化表单交互和动画效果
This commit is contained in:
parent
c781657003
commit
6d96c5b947
@ -5,6 +5,7 @@ import {
|
||||
Link,
|
||||
Button,
|
||||
Space,
|
||||
Message,
|
||||
} from '@arco-design/web-react';
|
||||
import { FormInstance } from '@arco-design/web-react/es/Form';
|
||||
import { IconLock, IconUser } from '@arco-design/web-react/icon';
|
||||
@ -75,11 +76,12 @@ export default function LoginForm() {
|
||||
|
||||
return (
|
||||
<div className={styles['login-form-wrapper']}>
|
||||
<div className={styles['login-form-title']}>{t['login.form.title']}</div>
|
||||
<div className={styles['login-form-sub-title']}>
|
||||
{t['login.form.title']}
|
||||
</div>
|
||||
<div className={styles['login-form-title']}>账号登录</div>
|
||||
|
||||
{errorMessage && (
|
||||
<div className={styles['login-form-error-msg']}>{errorMessage}</div>
|
||||
)}
|
||||
|
||||
<Form
|
||||
className={styles['login-form']}
|
||||
layout="vertical"
|
||||
@ -91,39 +93,40 @@ export default function LoginForm() {
|
||||
rules={[{ required: true, message: t['login.form.userName.errMsg'] }]}
|
||||
>
|
||||
<Input
|
||||
prefix={<IconUser />}
|
||||
placeholder={t['login.form.userName.placeholder']}
|
||||
onPressEnter={onSubmitClick}
|
||||
size="large"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
field="password"
|
||||
rules={[{ required: true, message: t['login.form.password.errMsg'] }]}
|
||||
>
|
||||
<Input.Password
|
||||
prefix={<IconLock />}
|
||||
placeholder={t['login.form.password.placeholder']}
|
||||
onPressEnter={onSubmitClick}
|
||||
size="large"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Space size={16} direction="vertical">
|
||||
<div className={styles['login-form-password-actions']}>
|
||||
|
||||
<div className={styles['login-form-actions']}>
|
||||
<Checkbox checked={rememberPassword} onChange={setRememberPassword}>
|
||||
{t['login.form.rememberPassword']}
|
||||
</Checkbox>
|
||||
<Link>{t['login.form.forgetPassword']}</Link>
|
||||
</div>
|
||||
<Button type="primary" long onClick={onSubmitClick} loading={loading}>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
long
|
||||
size="large"
|
||||
onClick={onSubmitClick}
|
||||
loading={loading}
|
||||
className={styles['login-btn']}
|
||||
>
|
||||
{t['login.form.login']}
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
long
|
||||
className={styles['login-form-register-btn']}
|
||||
>
|
||||
{t['login.form.register']}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Footer from '@/components/Footer';
|
||||
import Logo from '@/assets/logo.svg';
|
||||
import LoginForm from './form';
|
||||
import LoginBanner from './banner';
|
||||
import styles from './style/index.module.less';
|
||||
|
||||
function Login() {
|
||||
@ -12,26 +9,53 @@ function Login() {
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.logo}>
|
||||
<Logo />
|
||||
<div className={styles['logo-text']}>Arco Design Pro</div>
|
||||
</div>
|
||||
<div className={styles['login-card-wrapper']}>
|
||||
{/* 左侧插画区域 */}
|
||||
<div className={styles.banner}>
|
||||
<div className={styles['banner-inner']}>
|
||||
<LoginBanner />
|
||||
{/* Logo */}
|
||||
<div className={styles.logo}>
|
||||
<span className={styles['logo-text']}>Coder Admin</span>
|
||||
</div>
|
||||
|
||||
{/* 插画区域 */}
|
||||
<div className={styles['illustration-wrapper']}>
|
||||
<div className={styles.illustration}>
|
||||
{/* 认证卡片 */}
|
||||
<div className={styles['auth-card']}>
|
||||
<div className={styles['auth-card-header']}>
|
||||
<div className={styles['scan-line']}></div>
|
||||
</div>
|
||||
<div className={styles['auth-card-avatar']}>
|
||||
<div className={styles['avatar-circle']}></div>
|
||||
</div>
|
||||
<div className={styles['auth-card-info']}>
|
||||
<div className={styles['info-line']}></div>
|
||||
<div className={styles['info-line-short']}></div>
|
||||
</div>
|
||||
<div className={styles['check-icon']}>✓</div>
|
||||
</div>
|
||||
{/* 人物剪影 */}
|
||||
<div className={styles['person-silhouette']}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧登录表单区域 */}
|
||||
<div className={styles.content}>
|
||||
<div className={styles['content-inner']}>
|
||||
<div className={styles['content-wrapper']}>
|
||||
<LoginForm />
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<Footer />
|
||||
Copyright © 2024 Coder Admin. All Rights Reserved.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Login.displayName = 'LoginPage';
|
||||
|
||||
export default Login;
|
||||
|
||||
@ -1,120 +1,504 @@
|
||||
// 登录页面容器
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
.banner {
|
||||
width: 550px;
|
||||
background: linear-gradient(163.85deg, #1d2129 0%, #00308f 100%);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
min-height: 100vh;
|
||||
background: #f0f2f5;
|
||||
padding: 40px 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
left: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
// 登录卡片包装器
|
||||
.login-card-wrapper {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 30%);
|
||||
overflow: hidden;
|
||||
max-width: 1000px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&-text {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
font-size: 20px;
|
||||
color: var(--color-fill-1);
|
||||
}
|
||||
animation: fade-in-up 0.6s ease-out;
|
||||
}
|
||||
|
||||
// 左侧插画区域
|
||||
.banner {
|
||||
flex: 0 0 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #6b8aff 0%, #5470ff 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 60px 40px;
|
||||
}
|
||||
|
||||
&-inner {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
.banner-inner {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
// Logo 区域
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.logo-text {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
// 插画区域
|
||||
.illustration-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
height: 100%;
|
||||
|
||||
&-item {
|
||||
.illustration {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
// 认证卡片
|
||||
.auth-card {
|
||||
width: 200px;
|
||||
height: 260px;
|
||||
background: rgba(255, 255, 255, 95%);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 15%);
|
||||
position: relative;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
|
||||
&-header {
|
||||
position: relative;
|
||||
height: 60px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #e8eeff 0%, #f5f7ff 100%);
|
||||
overflow: hidden;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.scan-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, #5470ff, transparent);
|
||||
animation: scan 2s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
color: var(--color-fill-1);
|
||||
&-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.avatar-circle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #6b8aff 0%, #5470ff 100%);
|
||||
border: 4px solid rgba(84, 112, 255, 20%);
|
||||
box-shadow: 0 4px 12px rgba(84, 112, 255, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
&-sub-title {
|
||||
margin-top: 8px;
|
||||
&-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.info-line {
|
||||
height: 12px;
|
||||
background: #e8eeff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.info-line-short {
|
||||
height: 12px;
|
||||
width: 60%;
|
||||
background: #e8eeff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
right: -12px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 4px 12px rgba(82, 196, 26, 40%);
|
||||
animation: check-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
// 人物剪影
|
||||
.person-silhouette {
|
||||
width: 120px;
|
||||
height: 140px;
|
||||
background: rgba(255, 255, 255, 30%);
|
||||
border-radius: 60px 60px 80px 80px;
|
||||
position: relative;
|
||||
animation: float 3s ease-in-out infinite reverse;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 60px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 10%);
|
||||
filter: blur(4px);
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧表单区域
|
||||
.content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 50px;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
// 登录表单
|
||||
.login-form-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-form-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-form-error-msg {
|
||||
padding: 12px 16px;
|
||||
background: #ffece8;
|
||||
border: 1px solid #ffccc7;
|
||||
border-radius: 8px;
|
||||
color: #f53f3f;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
|
||||
&-image {
|
||||
margin-top: 30px;
|
||||
width: 320px;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
animation: shake 0.5s ease;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
&-wrapper {
|
||||
width: 320px;
|
||||
:global {
|
||||
.arco-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-1);
|
||||
line-height: 32px;
|
||||
.arco-input-wrapper,
|
||||
.arco-input-password {
|
||||
border-radius: 8px;
|
||||
height: 44px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #5470ff;
|
||||
}
|
||||
}
|
||||
|
||||
&-sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: var(--color-text-3);
|
||||
.arco-input-wrapper.arco-input-focus,
|
||||
.arco-input-password.arco-input-focus {
|
||||
border-color: #5470ff;
|
||||
box-shadow: 0 0 0 2px rgba(84, 112, 255, 10%);
|
||||
}
|
||||
|
||||
&-error-msg {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
color: rgb(var(--red-6));
|
||||
.arco-input {
|
||||
height: 44px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&-password-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-register-btn {
|
||||
color: var(--color-text-3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
:global {
|
||||
.arco-checkbox-text {
|
||||
color: #4e5969;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.arco-link {
|
||||
color: #5470ff;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: #6b8aff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
height: 44px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(135deg, #5470ff 0%, #6b8aff 100%);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(84, 112, 255, 40%);
|
||||
background: linear-gradient(135deg, #6b8aff 0%, #7d9aff 100%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
&:global(.arco-btn-primary):not(:global(.arco-btn-disabled)) {
|
||||
background: linear-gradient(135deg, #5470ff 0%, #6b8aff 100%);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #6b8aff 0%, #7d9aff 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部版权
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
// 动画定义
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scan {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(60px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes check-pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 4px 12px rgba(82, 196, 26, 40%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 4px 20px rgba(82, 196, 26, 60%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 1024px) {
|
||||
.login-card-wrapper {
|
||||
flex-direction: column;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
flex: 0 0 auto;
|
||||
padding: 40px 30px;
|
||||
}
|
||||
|
||||
.illustration-wrapper {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
width: 150px;
|
||||
height: 200px;
|
||||
padding: 15px;
|
||||
|
||||
&-header {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&-avatar {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.avatar-circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.person-silhouette {
|
||||
width: 80px;
|
||||
height: 100px;
|
||||
|
||||
&::before {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 40px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-card-wrapper {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.banner {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 30px;
|
||||
|
||||
.logo-text {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.illustration-wrapper {
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
width: 120px;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.person-silhouette {
|
||||
width: 60px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
.login-form-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user