118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
|
|
import React, { useState, useEffect } from 'react';
|
|||
|
|
import { Layout, Menu, Button, Avatar, Dropdown, message } from 'antd';
|
|||
|
|
import {
|
|||
|
|
AppstoreOutlined,
|
|||
|
|
UserOutlined,
|
|||
|
|
LogoutOutlined,
|
|||
|
|
MenuFoldOutlined,
|
|||
|
|
MenuUnfoldOutlined,
|
|||
|
|
} from '@ant-design/icons';
|
|||
|
|
import { history, useLocation, Outlet } from 'umi';
|
|||
|
|
import './index.less';
|
|||
|
|
|
|||
|
|
const { Header, Sider, Content } = Layout;
|
|||
|
|
|
|||
|
|
const MainLayout: React.FC = () => {
|
|||
|
|
const [collapsed, setCollapsed] = useState(false);
|
|||
|
|
const [username, setUsername] = useState('');
|
|||
|
|
const location = useLocation();
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
// 检查登录状态
|
|||
|
|
const isLoggedIn = localStorage.getItem('isLoggedIn');
|
|||
|
|
const currentUsername = localStorage.getItem('username');
|
|||
|
|
|
|||
|
|
if (!isLoggedIn) {
|
|||
|
|
message.error('请先登录!');
|
|||
|
|
history.push('/login');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setUsername(currentUsername || '');
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const handleMenuClick = (key: string) => {
|
|||
|
|
// 使用路由导航
|
|||
|
|
history.push(`/${key}`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleLogout = () => {
|
|||
|
|
localStorage.removeItem('isLoggedIn');
|
|||
|
|
localStorage.removeItem('username');
|
|||
|
|
message.success('已退出登录');
|
|||
|
|
history.push('/login');
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const userMenu = (
|
|||
|
|
<Menu>
|
|||
|
|
<Menu.Item key="profile" icon={<UserOutlined />} onClick={() => history.push('/profile')}>
|
|||
|
|
个人资料
|
|||
|
|
</Menu.Item>
|
|||
|
|
<Menu.Divider />
|
|||
|
|
<Menu.Item key="logout" icon={<LogoutOutlined />} onClick={handleLogout}>
|
|||
|
|
退出登录
|
|||
|
|
</Menu.Item>
|
|||
|
|
</Menu>
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 根据当前路径确定选中的菜单项
|
|||
|
|
const getSelectedKey = () => {
|
|||
|
|
const path = location.pathname;
|
|||
|
|
if (path === '/images') return 'images';
|
|||
|
|
if (path === '/profile') return 'profile';
|
|||
|
|
return 'images'; // 默认选中镜像列表
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Layout className="main-layout">
|
|||
|
|
<Sider
|
|||
|
|
trigger={null}
|
|||
|
|
collapsible
|
|||
|
|
collapsed={collapsed}
|
|||
|
|
className="main-sider"
|
|||
|
|
>
|
|||
|
|
<div className="logo">
|
|||
|
|
{!collapsed && <span>VDI 系统</span>}
|
|||
|
|
</div>
|
|||
|
|
<Menu
|
|||
|
|
theme="dark"
|
|||
|
|
mode="inline"
|
|||
|
|
selectedKeys={[getSelectedKey()]}
|
|||
|
|
onClick={({ key }) => handleMenuClick(key)}
|
|||
|
|
>
|
|||
|
|
<Menu.Item key="images" icon={<AppstoreOutlined />}>
|
|||
|
|
镜像列表
|
|||
|
|
</Menu.Item>
|
|||
|
|
<Menu.Item key="profile" icon={<UserOutlined />}>
|
|||
|
|
我的
|
|||
|
|
</Menu.Item>
|
|||
|
|
</Menu>
|
|||
|
|
</Sider>
|
|||
|
|
|
|||
|
|
<Layout>
|
|||
|
|
<Header className="main-header">
|
|||
|
|
<Button
|
|||
|
|
type="text"
|
|||
|
|
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|||
|
|
onClick={() => setCollapsed(!collapsed)}
|
|||
|
|
className="trigger"
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<div className="header-right">
|
|||
|
|
<span className="welcome-text">欢迎,{username}</span>
|
|||
|
|
<Dropdown overlay={userMenu} placement="bottomRight">
|
|||
|
|
<Avatar icon={<UserOutlined />} className="user-avatar" />
|
|||
|
|
</Dropdown>
|
|||
|
|
</div>
|
|||
|
|
</Header>
|
|||
|
|
|
|||
|
|
<Content className="main-content">
|
|||
|
|
<Outlet />
|
|||
|
|
</Content>
|
|||
|
|
</Layout>
|
|||
|
|
</Layout>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default MainLayout;
|