All checks were successful
Build and Deploy Web / build-and-deploy (push) Successful in 1m38s
153 lines
5.6 KiB
TypeScript
153 lines
5.6 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { Form, Input, Button, message, Typography } from 'antd';
|
|
import { UserOutlined, LockOutlined } from '@ant-design/icons';
|
|
import { login } from '../../api/auth';
|
|
import { useAuthStore } from '../../store/useAuthStore';
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
const LoginPage: React.FC = () => {
|
|
const [loading, setLoading] = useState(false);
|
|
const navigate = useNavigate();
|
|
const { setAuth } = useAuthStore();
|
|
|
|
const onFinish = async (values: { username: string; password: string }) => {
|
|
setLoading(true);
|
|
try {
|
|
const res = await login(values);
|
|
setAuth(res.data.token.access, res.data.token.refresh, res.data.admin);
|
|
message.success('登录成功');
|
|
navigate('/dashboard');
|
|
} catch (error) {
|
|
message.error(error instanceof Error ? error.message : '登录失败');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
minHeight: '100vh',
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
background: 'linear-gradient(135deg, #312e81 0%, #6366f1 50%, #8b5cf6 100%)',
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
{/* Decorative elements */}
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
width: 400,
|
|
height: 400,
|
|
borderRadius: '50%',
|
|
background: 'rgba(255,255,255,0.05)',
|
|
top: -100,
|
|
right: -100,
|
|
}}
|
|
/>
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
width: 300,
|
|
height: 300,
|
|
borderRadius: '50%',
|
|
background: 'rgba(255,255,255,0.03)',
|
|
bottom: -80,
|
|
left: -80,
|
|
}}
|
|
/>
|
|
|
|
<div
|
|
style={{
|
|
width: 420,
|
|
padding: 40,
|
|
background: 'rgba(255, 255, 255, 0.95)',
|
|
backdropFilter: 'blur(20px)',
|
|
borderRadius: 20,
|
|
boxShadow: '0 25px 50px rgba(99, 102, 241, 0.25), 0 0 0 1px rgba(255,255,255,0.2)',
|
|
position: 'relative',
|
|
zIndex: 1,
|
|
}}
|
|
>
|
|
<div style={{ textAlign: 'center', marginBottom: 36 }}>
|
|
<div
|
|
style={{
|
|
width: 56,
|
|
height: 56,
|
|
borderRadius: 16,
|
|
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginBottom: 16,
|
|
boxShadow: '0 8px 20px rgba(99, 102, 241, 0.3)',
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 24, fontWeight: 800, color: '#fff' }}>R</span>
|
|
</div>
|
|
<Title level={3} style={{ marginBottom: 4, color: '#1f2937' }}>
|
|
RTC 管理后台
|
|
</Title>
|
|
<Text type="secondary" style={{ fontSize: 14 }}>
|
|
设备管理 · 库存管理 · 用户管理
|
|
</Text>
|
|
</div>
|
|
|
|
<Form
|
|
name="login"
|
|
onFinish={onFinish}
|
|
size="large"
|
|
autoComplete="off"
|
|
>
|
|
<Form.Item
|
|
name="username"
|
|
rules={[{ required: true, message: '请输入用户名' }]}
|
|
>
|
|
<Input
|
|
prefix={<UserOutlined style={{ color: '#9ca3af' }} />}
|
|
placeholder="用户名"
|
|
style={{ height: 48, borderRadius: 10 }}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="password"
|
|
rules={[{ required: true, message: '请输入密码' }]}
|
|
>
|
|
<Input.Password
|
|
prefix={<LockOutlined style={{ color: '#9ca3af' }} />}
|
|
placeholder="密码"
|
|
style={{ height: 48, borderRadius: 10 }}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item style={{ marginBottom: 0, marginTop: 8 }}>
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
loading={loading}
|
|
block
|
|
style={{
|
|
height: 48,
|
|
fontSize: 16,
|
|
fontWeight: 600,
|
|
borderRadius: 10,
|
|
boxShadow: '0 4px 12px rgba(99, 102, 241, 0.4)',
|
|
}}
|
|
>
|
|
登 录
|
|
</Button>
|
|
</Form.Item>
|
|
</Form>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LoginPage;
|