init
This commit is contained in:
175
frontend/src/components/Layout.tsx
Normal file
175
frontend/src/components/Layout.tsx
Normal file
@ -0,0 +1,175 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Layout as AntLayout,
|
||||
Menu,
|
||||
Button,
|
||||
Avatar,
|
||||
Dropdown,
|
||||
Typography,
|
||||
Space,
|
||||
MenuProps,
|
||||
} from 'antd';
|
||||
import {
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
UserOutlined,
|
||||
TeamOutlined,
|
||||
SafetyOutlined,
|
||||
AppstoreOutlined,
|
||||
LogoutOutlined,
|
||||
SettingOutlined,
|
||||
DashboardOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useAuth } from '../hooks/useAuth';
|
||||
import { useNavigate, useLocation, Outlet } from 'react-router-dom';
|
||||
|
||||
const { Header, Sider, Content } = AntLayout;
|
||||
const { Title } = Typography;
|
||||
|
||||
const Layout: React.FC = () => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const { user, logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
key: '/dashboard',
|
||||
icon: React.createElement(DashboardOutlined),
|
||||
label: '仪表盘',
|
||||
},
|
||||
{
|
||||
key: '/users',
|
||||
icon: React.createElement(UserOutlined),
|
||||
label: '用户管理',
|
||||
},
|
||||
{
|
||||
key: '/roles',
|
||||
icon: React.createElement(TeamOutlined),
|
||||
label: '角色管理',
|
||||
},
|
||||
{
|
||||
key: '/permissions',
|
||||
icon: React.createElement(SafetyOutlined),
|
||||
label: '权限管理',
|
||||
},
|
||||
{
|
||||
key: '/menus',
|
||||
icon: React.createElement(AppstoreOutlined),
|
||||
label: '菜单管理',
|
||||
},
|
||||
];
|
||||
|
||||
const handleMenuClick = ({ key }: { key: string }) => {
|
||||
navigate(key);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
navigate('/login');
|
||||
};
|
||||
|
||||
const userMenuItems: MenuProps['items'] = [
|
||||
{
|
||||
key: 'profile',
|
||||
icon: React.createElement(SettingOutlined),
|
||||
label: '个人设置',
|
||||
onClick: () => navigate('/profile'),
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
key: 'logout',
|
||||
icon: React.createElement(LogoutOutlined),
|
||||
label: '退出登录',
|
||||
onClick: handleLogout,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<AntLayout style={{ minHeight: '100vh' }}>
|
||||
<Sider
|
||||
trigger={null}
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
style={{
|
||||
background: '#fff',
|
||||
boxShadow: '2px 0 8px rgba(0,0,0,0.15)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: 64,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
}}
|
||||
>
|
||||
{!collapsed ? (
|
||||
<Title level={3} style={{ margin: 0, color: '#1890ff' }}>
|
||||
UAdmin
|
||||
</Title>
|
||||
) : (
|
||||
<Title level={3} style={{ margin: 0, color: '#1890ff' }}>
|
||||
U
|
||||
</Title>
|
||||
)}
|
||||
</div>
|
||||
<Menu
|
||||
mode="inline"
|
||||
selectedKeys={[location.pathname]}
|
||||
items={menuItems}
|
||||
onClick={handleMenuClick}
|
||||
style={{ border: 'none' }}
|
||||
/>
|
||||
</Sider>
|
||||
<AntLayout>
|
||||
<Header
|
||||
style={{
|
||||
padding: '0 16px',
|
||||
background: '#fff',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
icon={collapsed ? React.createElement(MenuUnfoldOutlined) : React.createElement(MenuFoldOutlined)}
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
style={{
|
||||
fontSize: '16px',
|
||||
width: 64,
|
||||
height: 64,
|
||||
}}
|
||||
/>
|
||||
<Space>
|
||||
<span>欢迎,{user?.username}</span>
|
||||
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
|
||||
<Avatar
|
||||
style={{ backgroundColor: '#1890ff', cursor: 'pointer' }}
|
||||
icon={React.createElement(UserOutlined)}
|
||||
/>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Header>
|
||||
<Content
|
||||
style={{
|
||||
margin: '16px',
|
||||
padding: '24px',
|
||||
background: '#fff',
|
||||
borderRadius: '8px',
|
||||
minHeight: 'calc(100vh - 112px)',
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
</Content>
|
||||
</AntLayout>
|
||||
</AntLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
Reference in New Issue
Block a user