141 lines
4.6 KiB
TypeScript
141 lines
4.6 KiB
TypeScript
import React, {useEffect, useState} from 'react';
|
|
import {Form, Input, Button, message, Select} from 'antd';
|
|
import {useNavigate} from 'react-router-dom';
|
|
import {useDispatch} from 'react-redux';
|
|
import {login} from './service';
|
|
import {getEnabledTenants} from '@/pages/System/Tenant/service';
|
|
import {setToken, setUserInfo, setMenus} from '../../store/userSlice';
|
|
import {getCurrentUserMenus} from '@/pages/System/Menu/service';
|
|
import type { MenuResponse } from '@/pages/System/Menu/types';
|
|
import type { TenantResponse } from '@/pages/System/Tenant/types';
|
|
import styles from './index.module.css';
|
|
|
|
interface LoginForm {
|
|
tenantId: string;
|
|
username: string;
|
|
password: string;
|
|
}
|
|
|
|
const Login: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const dispatch = useDispatch();
|
|
const [form] = Form.useForm<LoginForm>();
|
|
const [loading, setLoading] = useState(false);
|
|
const [tenants, setTenants] = useState<TenantResponse[]>([]);
|
|
|
|
useEffect(() => {
|
|
const fetchTenants = async () => {
|
|
try {
|
|
const data = await getEnabledTenants();
|
|
setTenants(data);
|
|
} catch (error) {
|
|
console.error('获取租户列表失败:', error);
|
|
}
|
|
};
|
|
|
|
fetchTenants();
|
|
}, []);
|
|
|
|
// 加载菜单数据
|
|
const loadMenuData = async () => {
|
|
try {
|
|
const menuData = await getCurrentUserMenus();
|
|
if (menuData && menuData.length > 0) {
|
|
dispatch(setMenus(menuData));
|
|
}
|
|
} catch (error) {
|
|
console.error('获取菜单数据失败:', error);
|
|
}
|
|
};
|
|
|
|
const handleFinish = async (values: LoginForm) => {
|
|
setLoading(true);
|
|
try {
|
|
// 1. 登录获取 token 和用户信息
|
|
const loginData = await login(values);
|
|
dispatch(setToken(loginData.token));
|
|
dispatch(setUserInfo({
|
|
id: loginData.id,
|
|
username: loginData.username,
|
|
nickname: loginData.nickname,
|
|
email: loginData.email,
|
|
phone: loginData.phone
|
|
}));
|
|
|
|
// 2. 获取菜单数据
|
|
await loadMenuData();
|
|
|
|
message.success('登录成功');
|
|
navigate('/');
|
|
} catch (error) {
|
|
console.error('登录失败:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={styles.loginContainer}>
|
|
<div className={styles.loginBox}>
|
|
<div className={styles.logo}>
|
|
<h1>管理系统</h1>
|
|
</div>
|
|
<Form<LoginForm>
|
|
form={form}
|
|
name="login"
|
|
onFinish={handleFinish}
|
|
autoComplete="off"
|
|
size="large"
|
|
>
|
|
<Form.Item
|
|
name="tenantId"
|
|
rules={[{required: true, message: '请选择租户!'}]}
|
|
>
|
|
<Select
|
|
placeholder="请选择租户"
|
|
options={tenants.map(tenant => ({
|
|
label: tenant.name,
|
|
value: tenant.code
|
|
}))}
|
|
className={styles.input}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="username"
|
|
rules={[{required: true, message: '请输入用户名!'}]}
|
|
>
|
|
<Input
|
|
placeholder="用户名"
|
|
className={styles.input}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="password"
|
|
rules={[{required: true, message: '请输入密码!'}]}
|
|
>
|
|
<Input.Password
|
|
placeholder="密码"
|
|
className={styles.input}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item>
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
block
|
|
loading={loading}
|
|
className={styles.loginButton}
|
|
>
|
|
登录
|
|
</Button>
|
|
</Form.Item>
|
|
</Form>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Login;
|