vdi/web-fe/src/pages/components/Layout/index.tsx

150 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import {
AppstoreOutlined,
LogoutOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
UserOutlined,
} from '@ant-design/icons';
import { Avatar, Button, Dropdown, Layout, Menu, message } from 'antd';
import React, { useEffect, useState } from 'react';
import { history, Outlet, useLocation } from 'umi';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/lib/locale/zh_CN';
import './index.less';
const { Header, Sider, Content } = Layout;
const MainLayout: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
const [username, setUsername] = useState('');
const [selectedKey, setSelectedKey] = useState('images'); // 添加选中状态
const location = useLocation();
useEffect(() => {
// 检查登录状态
const isLoggedIn = localStorage.getItem('isLoggedIn');
const currentUsername = localStorage.getItem('username');
if (!isLoggedIn) {
message.error('请先登录!');
history.push('/login');
return;
}
setUsername(currentUsername || '');
setSelectedKey(getSelectedKeyFromPath(location.pathname));
}, []);
// 监听路由变化,更新选中菜单
useEffect(() => {
setSelectedKey(getSelectedKeyFromPath(location.pathname));
}, [location.pathname]);
const getSelectedKeyFromPath = (path: string) => {
if (path.startsWith('/userList')) return 'userList';
if (path.startsWith('/terminal')) return 'terminal';
if (path.startsWith('/images')) return 'images';
if (path.startsWith('/profile')) return 'profile';
if (path.startsWith('/network')) return 'network';
if (path.startsWith('/storage')) return 'storage';
return 'images'; // 默认选中镜像列表
};
const handleMenuClick = (item: any) => {
// 更新选中状态
setSelectedKey(item.key);
// 使用路由导航
history.push(`/${item.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>
);
return (
<ConfigProvider locale={zhCN}>
<Layout className="main-layout">
<Sider
trigger={null}
collapsible
collapsed={collapsed}
className="main-sider"
>
<div className="logo">{!collapsed && <span>NEXSPACE</span>}</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={[selectedKey]}
onClick={handleMenuClick}
>
<Menu.Item key="terminal" icon={<AppstoreOutlined />}>
</Menu.Item>
<Menu.Item key="userList" icon={<AppstoreOutlined />}>
</Menu.Item>
<Menu.Item key="images" icon={<AppstoreOutlined />}>
</Menu.Item>
<Menu.Item key="network" icon={<AppstoreOutlined />}>
</Menu.Item>
<Menu.Item key="storage" 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"
style={{ height: 'calc(100vh - 64px)', overflow: 'auto' }}
>
<Outlet />
</Content>
</Layout>
</Layout>
</ConfigProvider>
);
};
export default MainLayout;