feat: 迭代

This commit is contained in:
2026-05-15 19:06:32 +08:00
parent 8c908ea557
commit 848df4c873
22 changed files with 1545 additions and 355 deletions
+267
View File
@@ -0,0 +1,267 @@
.login-container {
display: flex;
min-height: 100vh;
background: #0a0e27;
}
/* 左侧装饰区域 - 深色科技风 */
.login-left {
flex: 1;
background: linear-gradient(135deg, #1a1f3a 0%, #0a0e27 100%);
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.login-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.decoration-circle {
position: absolute;
border-radius: 50%;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(118, 75, 162, 0.15) 100%);
animation: float 20s infinite ease-in-out;
border: 1px solid rgba(102, 126, 234, 0.2);
}
.decoration-circle.circle-1 {
width: 500px;
height: 500px;
top: -150px;
right: -150px;
animation-delay: 0s;
}
.decoration-circle.circle-2 {
width: 350px;
height: 350px;
bottom: -100px;
left: -100px;
animation-delay: 5s;
}
.decoration-circle.circle-3 {
width: 250px;
height: 250px;
top: 50%;
left: 15%;
animation-delay: 10s;
}
@keyframes float {
0%, 100% {
transform: translateY(0) rotate(0deg);
}
50% {
transform: translateY(-40px) rotate(180deg);
}
}
.login-brand {
position: relative;
z-index: 1;
text-align: center;
color: #fff;
padding: 40px;
}
.brand-icon {
width: 140px;
height: 140px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2) 0%, rgba(118, 75, 162, 0.2) 100%);
backdrop-filter: blur(20px);
border-radius: 32px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 40px;
box-shadow: 0 12px 48px rgba(102, 126, 234, 0.3);
border: 2px solid rgba(102, 126, 234, 0.3);
}
.brand-title {
font-size: 56px;
font-weight: 800;
margin: 0 0 16px;
color: #fff;
letter-spacing: 3px;
text-shadow: 0 4px 12px rgba(102, 126, 234, 0.5);
}
.brand-subtitle {
font-size: 22px;
margin: 0 0 80px;
color: rgba(255, 255, 255, 0.85);
font-weight: 600;
letter-spacing: 1px;
}
.brand-features {
display: flex;
gap: 50px;
justify-content: center;
margin-top: 80px;
}
.feature-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.feature-icon {
width: 56px;
height: 56px;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.25) 0%, rgba(118, 75, 162, 0.25) 100%);
backdrop-filter: blur(10px);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
font-weight: 700;
color: #667eea;
border: 2px solid rgba(102, 126, 234, 0.4);
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
}
.feature-text {
font-size: 17px;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
}
/* 右侧登录表单 */
.login-right {
width: 520px;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
padding: 50px;
box-shadow: -8px 0 32px rgba(0, 0, 0, 0.15);
}
.login-form-wrapper {
width: 100%;
max-width: 420px;
}
.login-header {
margin-bottom: 56px;
text-align: center;
}
.login-title {
font-size: 36px;
font-weight: 800;
color: #0a0e27;
margin: 0 0 16px;
letter-spacing: -0.5px;
}
.login-subtitle {
font-size: 17px;
color: #666;
margin: 0;
font-weight: 500;
}
.login-form {
margin-bottom: 32px;
}
.login-input {
height: 52px;
border-radius: 10px;
font-size: 15px;
border: 2px solid #e8e8e8;
transition: all 0.3s;
}
.login-input:hover {
border-color: #667eea;
}
.login-input:focus,
.login-input.ant-input-focused {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.login-input input {
height: 100%;
}
.input-icon {
color: #999;
font-size: 19px;
}
.login-button {
height: 52px;
border-radius: 10px;
font-size: 17px;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
transition: all 0.3s;
letter-spacing: 0.5px;
}
.login-button:hover {
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.5);
}
.login-button:active {
transform: translateY(-1px);
}
.login-footer {
text-align: center;
margin-top: 48px;
padding-top: 32px;
border-top: 1px solid #f0f0f0;
}
.footer-text {
font-size: 14px;
color: #999;
margin: 0;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.login-left {
display: none;
}
.login-right {
width: 100%;
}
}
@media (max-width: 640px) {
.login-right {
padding: 20px;
}
.login-form-wrapper {
max-width: 100%;
}
.login-title {
font-size: 28px;
}
}
+83 -18
View File
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Form, Input, Button, Card, message } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import { Form, Input, Button, message } from 'antd';
import { UserOutlined, LockOutlined, SafetyOutlined } from '@ant-design/icons';
import { loginByPassword } from '@/api/admin';
import { useAuthStore } from '@/store/auth';
import './Login.css';
const Login: React.FC = () => {
const [loading, setLoading] = useState(false);
@@ -25,22 +26,86 @@ const Login: React.FC = () => {
};
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', background: '#001529' }}>
<Card style={{ width: 400 }} title={<div style={{ textAlign: 'center', fontSize: 20, fontWeight: 600, color: '#1890ff' }}></div>}>
<Form onFinish={onFinish} size="large">
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}>
<Input prefix={<UserOutlined />} placeholder="管理员用户名" />
</Form.Item>
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password prefix={<LockOutlined />} placeholder="密码" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={loading} block>
</Button>
</Form.Item>
</Form>
</Card>
<div className="login-container">
{/* 左侧装饰区域 */}
<div className="login-left">
<div className="login-decoration">
<div className="decoration-circle circle-1"></div>
<div className="decoration-circle circle-2"></div>
<div className="decoration-circle circle-3"></div>
</div>
<div className="login-brand">
<div className="brand-icon">
<SafetyOutlined style={{ fontSize: 64, color: '#fff' }} />
</div>
<h1 className="brand-title"></h1>
<p className="brand-subtitle"></p>
<div className="brand-features">
<div className="feature-item">
<div className="feature-icon"></div>
<div className="feature-text"></div>
</div>
<div className="feature-item">
<div className="feature-icon"></div>
<div className="feature-text"></div>
</div>
<div className="feature-item">
<div className="feature-icon"></div>
<div className="feature-text"></div>
</div>
</div>
</div>
</div>
{/* 右侧登录表单 */}
<div className="login-right">
<div className="login-form-wrapper">
<div className="login-header">
<h2 className="login-title"></h2>
<p className="login-subtitle"></p>
</div>
<Form onFinish={onFinish} size="large" className="login-form">
<Form.Item
name="username"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input
prefix={<UserOutlined className="input-icon" />}
placeholder="管理员用户名"
className="login-input"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入密码' }]}
>
<Input.Password
prefix={<LockOutlined className="input-icon" />}
placeholder="密码"
className="login-input"
/>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
loading={loading}
block
className="login-button"
>
</Button>
</Form.Item>
</Form>
<div className="login-footer">
<p className="footer-text">© 2026 . All rights reserved.</p>
</div>
</div>
</div>
</div>
);
};