You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
7.6 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import styles from './style/sideBar.module.less';
import { IconApps } from '@arco-design/web-react/icon';
import { menuData1, menuData2 } from './config/menuData';
import { ResizeBox, Tree } from '@arco-design/web-react';
import { Selected } from '@/pages/ideContainer/types';
import { useDispatch, useSelector } from 'react-redux';
import { updateMenuData } from '@/store/ideContainer';
import { getProjectEnv } from '@/api/apps';
import _ from 'lodash';
const TreeNode = Tree.Node;
interface MenuItemType {
title: string;
key?: string;
children?: MenuItemType[];
path?: string;
icon?: React.ReactNode;
[key: string]: string | MenuItemType[] | React.ReactNode;
}
interface SideBarProps {
subMenuData: any;
selectedKey?: string;
identity?: string;
onMenuSelect?: (selected: Selected) => void;
}
const compTypeMap = {
appComponent: '普通组件',
subComponent: '复合组件'
};
const SideBar: React.FC<SideBarProps> = ({ selectedKey, identity, subMenuData, onMenuSelect }) => {
const [menu, setMenu] = useState<MenuItemType[]>([]);
const [subMenuWidth, setSubMenuWidth] = useState(200); // 子菜单宽度状态
const [isSubMenuCollapsed, setIsSubMenuCollapsed] = useState(false); // 子菜单收起状态
const [activeKey, setActiveKey] = useState(0);
const [mainMenuSelectedKey, setMainMenuSelectedKey] = useState<string>('');
const { menuData } = useSelector(state => state.ideContainer);
const dispatch = useDispatch();
function getMenuData(): MenuItemType[] {
switch (identity) {
case 'scene':
const menuData = _.cloneDeep(menuData1);
const newSubMenuData = _.cloneDeep(subMenuData);
const subMenuKey = Object.keys(newSubMenuData)[0];
const subMenuValue: any = Object.values(newSubMenuData)[0];
const menuIndex = menuData.findIndex(v => v.key === subMenuKey);
// 构建数据结构,这是目录默认需要的数据结构
subMenuValue.forEach(v => {
v.title = v.name;
v.key = `compFlow-${v.id}`;
v.path = 'compFlow';
v.parentKey = menu[activeKey]?.key;
v.children = [
{
title: '事件',
children: null
},
{
title: '组件列表',
children: null
}
];
});
menuData[menuIndex]['children'] = subMenuValue;
dispatch(updateMenuData({ 'scene': menuData }));
return menuData;
case 'componentDevelopment' :
dispatch(updateMenuData({ 'componentDevelopment': menuData2 }));
return menuData2;
default:
return menuData1;
}
}
// 处理子菜单区域的拖拽调整大小
const handleSubMenuResize = (e: MouseEvent, { width }: { width: number }) => {
setSubMenuWidth(width);
};
// 切换子菜单区域的收起/展开状态
const toggleSubMenu = () => {
setIsSubMenuCollapsed(!isSubMenuCollapsed);
setSubMenuWidth(isSubMenuCollapsed ? 200 : 0);
};
// 处理菜单项点击事件
const handleMenuItemClick = (item: MenuItemType, index: number) => {
setActiveKey(index);
// 如果点击的是当前已激活的菜单项,则切换子菜单的展开/收起状态
if (selectedKey === `${item.key}`) {
toggleSubMenu();
}
else {
// 如果点击的是其他菜单项,则展开子菜单(如果已收起)
if (isSubMenuCollapsed) {
setIsSubMenuCollapsed(false);
setSubMenuWidth(200);
}
}
const mainMenuKey = `${item.key}`;
setMainMenuSelectedKey(mainMenuKey);
// 调用外部传入的菜单选择处理函数
onMenuSelect?.({ ...item });
};
const getProjectEnvData = async (data) => {
if (!data.path || !data.key) return;
const parentKey = menu[activeKey]?.key;
const currentMenu = _.cloneDeep(menuData[identity]);
const index = currentMenu.findIndex(v => v.key === parentKey);
const res: any = await getProjectEnv(data.id);
if (res.code === 200) {
const children = currentMenu[index].children.find(v => v.id === data.id);
children.children[0].children = res.data.events.map(item => {
return {
title: item,
children: null
};
});
children.children[1].children = Object.keys(res.data.compList).map(item => {
return {
title: compTypeMap[item],
children: res.data.compList[item].map(item => {
return {
title: item,
children: null
};
})
};
});
// 更新 menuData 中的数据
dispatch(updateMenuData({ ...menuData, [identity]: currentMenu }));
// 同时更新本地 menu 状态以触发重新渲染
setMenu(prevMenu => {
const newMenu = [...prevMenu];
newMenu[activeKey] = { ...newMenu[activeKey], children: currentMenu[index].children };
return newMenu;
});
}
};
// 渲染子菜单
const renderMenuItems = (menuItems?: MenuItemType[], parentKey = '0') => {
if (menuItems && menuItems.length) {
return menuItems.map((item, index) => {
const key = `${parentKey}-${index}`;
const treeNodeProps = {
title: item.title,
key: key,
dataRef: item // 传递原始数据,包含 path、key 等信息
};
if (item.children && item.children.length > 0) {
return (
<TreeNode {...treeNodeProps} title={item.title} key={key}>
{renderMenuItems(item.children, key)}
</TreeNode>
);
}
else {
return <TreeNode {...treeNodeProps} title={item.title} key={key} />;
}
});
}
return null;
};
useEffect(() => {
setMainMenuSelectedKey(selectedKey);
}, [selectedKey]);
useEffect(() => {
setMenu(getMenuData());
}, [subMenuData]);
return (
<div
className={styles['sider']}
>
<div className={styles['menu-container']}>
{menu.map((item, index) => (
<div
key={index}
className={`${styles['menu-item']} ${(selectedKey === `${item.key}` || mainMenuSelectedKey === `${item.key}`) ? styles['menu-item-active'] : ''}`}
onClick={() => handleMenuItemClick(item, index)}
>
<div className={styles['menu-item-content']}>
<span className={styles['menu-item-icon']}>
{item.icon || <IconApps />}
</span>
<span className={styles['menu-item-text']}>
{item.title}
</span>
</div>
</div>
))}
</div>
<ResizeBox
directions={['right']}
style={{
width: subMenuWidth,
height: '100%',
minHeight: 'calc(100vh - 60px)'
}}
onMoving={handleSubMenuResize}
>
<div
className={styles['sub-menu']}
>
<Tree
defaultExpandedKeys={['0-0']}
onSelect={(_selectedKeys, info) => {
const selectedNode = info.node;
const originalData = selectedNode.props.dataRef;
getProjectEnvData(originalData);
// 保持主菜单的选中状态
const mainMenuKey = `${menu[activeKey]?.key}`;
setMainMenuSelectedKey(mainMenuKey);
// 调用外部传入的菜单选择处理函数
originalData.key && onMenuSelect?.({ ...originalData } as Selected);
}}
>
{renderMenuItems(menu[activeKey]?.children)}
</Tree>
</div>
</ResizeBox>
</div>
);
};
export default SideBar;