Files
live-hub-py/web/frontend/src/pages/LoginPage.tsx
T
2026-07-05 12:25:18 +08:00

81 lines
2.8 KiB
TypeScript

import { useState } from 'react';
import { Card, Form, Input, Button, message, Typography } from 'antd';
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { authApi } from '../api/modules';
import { setAuth, type AuthUser } from '../store/auth';
import { getErrorMessage } from '../utils/error';
import { useTheme } from '../store/useTheme';
import { useAppInfo } from '../hooks/useAppInfo';
const { Title, Text } = Typography;
export default function LoginPage({ onLogin }: { onLogin?: () => void }) {
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const { isDark } = useTheme();
const appInfo = useAppInfo();
const versionText = appInfo?.version ? `v${appInfo.version}` : 'v--';
const onFinish = async (values: { username: string; password: string }) => {
setLoading(true);
try {
const result = await authApi.login(values.username, values.password);
const user: AuthUser = {
id: 0,
username: result.username,
role: result.role,
permissions: result.permissions,
};
setAuth(user);
message.success('登录成功');
onLogin?.(); // 触发 App 重渲染
navigate('/', { replace: true });
} catch (e: unknown) {
message.error(getErrorMessage(e) || '登录失败');
} finally {
setLoading(false);
}
};
return (
<div style={{
minHeight: '100vh',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
background: isDark
? 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)'
: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
}}>
<Card style={{ width: 380, boxShadow: isDark ? '0 8px 24px rgba(0,0,0,0.4)' : '0 8px 24px rgba(0,0,0,0.15)' }}>
<Title level={3} style={{ textAlign: 'center', marginBottom: 32 }}>
直播运营后台
</Title>
<Text type="secondary" style={{
display: 'block',
textAlign: 'center',
marginTop: -20,
marginBottom: 24,
fontSize: 12,
}}>
当前版本 {versionText}
</Text>
<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>
);
}