2025-08-05 01:57:49 +00:00
|
|
|
|
import {
|
2025-08-05 08:54:53 +00:00
|
|
|
|
AppstoreOutlined,
|
|
|
|
|
|
LogoutOutlined,
|
|
|
|
|
|
MenuFoldOutlined,
|
|
|
|
|
|
MenuUnfoldOutlined,
|
|
|
|
|
|
UserOutlined,
|
2025-08-05 01:57:49 +00:00
|
|
|
|
} from '@ant-design/icons';
|
2025-08-05 08:54:53 +00:00
|
|
|
|
import { Avatar, Button, Dropdown, Layout, Menu, message } from 'antd';
|
|
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
|
import { history, Outlet, useLocation } from 'umi';
|
2025-08-06 10:06:10 +00:00
|
|
|
|
import { ConfigProvider } from 'antd';
|
|
|
|
|
|
import zhCN from 'antd/lib/locale/zh_CN';
|
2025-08-05 01:57:49 +00:00
|
|
|
|
import './index.less';
|
|
|
|
|
|
|
|
|
|
|
|
const { Header, Sider, Content } = Layout;
|
|
|
|
|
|
|
|
|
|
|
|
const MainLayout: React.FC = () => {
|
2025-08-05 08:54:53 +00:00
|
|
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
|
|
|
|
const [username, setUsername] = useState('');
|
2025-08-07 07:22:25 +00:00
|
|
|
|
const [selectedKey, setSelectedKey] = useState('images'); // 添加选中状态
|
2025-08-05 08:54:53 +00:00
|
|
|
|
const location = useLocation();
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
// 检查登录状态
|
|
|
|
|
|
const isLoggedIn = localStorage.getItem('isLoggedIn');
|
|
|
|
|
|
const currentUsername = localStorage.getItem('username');
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
if (!isLoggedIn) {
|
|
|
|
|
|
message.error('请先登录!');
|
|
|
|
|
|
history.push('/login');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
setUsername(currentUsername || '');
|
2025-08-07 07:22:25 +00:00
|
|
|
|
setSelectedKey(getSelectedKeyFromPath(location.pathname));
|
2025-08-05 08:54:53 +00:00
|
|
|
|
}, []);
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-07 07:22:25 +00:00
|
|
|
|
// 监听路由变化,更新选中菜单
|
|
|
|
|
|
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';
|
2025-08-29 09:51:17 +00:00
|
|
|
|
if (path.startsWith('/network')) return 'network';
|
|
|
|
|
|
if (path.startsWith('/storage')) return 'storage';
|
2025-08-07 07:22:25 +00:00
|
|
|
|
return 'images'; // 默认选中镜像列表
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMenuClick = (item: any) => {
|
|
|
|
|
|
// 更新选中状态
|
|
|
|
|
|
setSelectedKey(item.key);
|
|
|
|
|
|
// 使用路由导航
|
|
|
|
|
|
history.push(`/${item.key}`);
|
|
|
|
|
|
};
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
const handleLogout = () => {
|
|
|
|
|
|
localStorage.removeItem('isLoggedIn');
|
|
|
|
|
|
localStorage.removeItem('username');
|
|
|
|
|
|
message.success('已退出登录');
|
|
|
|
|
|
history.push('/login');
|
|
|
|
|
|
};
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
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>
|
|
|
|
|
|
);
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-05 08:54:53 +00:00
|
|
|
|
return (
|
2025-08-06 10:06:10 +00:00
|
|
|
|
<ConfigProvider locale={zhCN}>
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<Layout className="main-layout">
|
|
|
|
|
|
<Sider
|
|
|
|
|
|
trigger={null}
|
|
|
|
|
|
collapsible
|
|
|
|
|
|
collapsed={collapsed}
|
|
|
|
|
|
className="main-sider"
|
2025-08-05 08:54:53 +00:00
|
|
|
|
>
|
2025-08-14 09:23:11 +00:00
|
|
|
|
<div className="logo">{!collapsed && <span>NEXSPACE</span>}</div>
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<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 />}>
|
|
|
|
|
|
镜像列表
|
2025-08-29 09:51:17 +00:00
|
|
|
|
</Menu.Item>
|
|
|
|
|
|
<Menu.Item key="network" icon={<AppstoreOutlined />}>
|
|
|
|
|
|
网络
|
|
|
|
|
|
</Menu.Item>
|
|
|
|
|
|
<Menu.Item key="storage" icon={<AppstoreOutlined />}>
|
|
|
|
|
|
存储池
|
2025-08-13 08:34:32 +00:00
|
|
|
|
</Menu.Item>
|
|
|
|
|
|
<Menu.Item key="profile" icon={<UserOutlined />}>
|
|
|
|
|
|
我的
|
|
|
|
|
|
</Menu.Item>
|
|
|
|
|
|
</Menu>
|
|
|
|
|
|
</Sider>
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<Layout>
|
|
|
|
|
|
<Header className="main-header">
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
|
|
|
|
onClick={() => setCollapsed(!collapsed)}
|
|
|
|
|
|
className="trigger"
|
|
|
|
|
|
/>
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<div className="header-right">
|
|
|
|
|
|
<span className="welcome-text">欢迎,{username}</span>
|
|
|
|
|
|
<Dropdown overlay={userMenu} placement="bottomRight">
|
|
|
|
|
|
<Avatar icon={<UserOutlined />} className="user-avatar" />
|
|
|
|
|
|
</Dropdown>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Header>
|
2025-08-05 01:57:49 +00:00
|
|
|
|
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<Content
|
|
|
|
|
|
className="main-content"
|
|
|
|
|
|
style={{ height: 'calc(100vh - 64px)', overflow: 'auto' }}
|
2025-08-07 03:28:17 +00:00
|
|
|
|
>
|
2025-08-13 08:34:32 +00:00
|
|
|
|
<Outlet />
|
|
|
|
|
|
</Content>
|
|
|
|
|
|
</Layout>
|
2025-08-05 08:54:53 +00:00
|
|
|
|
</Layout>
|
2025-08-06 10:06:10 +00:00
|
|
|
|
</ConfigProvider>
|
2025-08-05 08:54:53 +00:00
|
|
|
|
);
|
2025-08-05 01:57:49 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default MainLayout;
|