|
|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import React, { useState, useMemo } from 'react';
|
|
|
|
|
import styles from './style/sideBar.module.less';
|
|
|
|
|
import { Button, Input, Tree } from '@arco-design/web-react';
|
|
|
|
|
import { IconSearch } from '@arco-design/web-react/icon';
|
|
|
|
|
@ -6,6 +6,55 @@ import { IconSearch } from '@arco-design/web-react/icon';
|
|
|
|
|
const TreeNode = Tree.Node;
|
|
|
|
|
|
|
|
|
|
const SideBar = ({ compList, onSelect }) => {
|
|
|
|
|
const [searchValue, setSearchValue] = useState('');
|
|
|
|
|
|
|
|
|
|
// 处理搜索输入变化
|
|
|
|
|
const handleSearchChange = (value) => {
|
|
|
|
|
setSearchValue(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理搜索按钮点击
|
|
|
|
|
const handleSearch = () => {
|
|
|
|
|
// 搜索逻辑将在树形结构渲染时处理
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 递归过滤树节点
|
|
|
|
|
const filterTreeData = (data, searchValue) => {
|
|
|
|
|
if (!searchValue) return data;
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(data)) {
|
|
|
|
|
return data.filter(item => {
|
|
|
|
|
const name = item.name || item?.main?.name || '';
|
|
|
|
|
return name.toLowerCase().includes(searchValue.toLowerCase());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof data === 'object' && data !== null) {
|
|
|
|
|
const filteredData = {};
|
|
|
|
|
Object.keys(data).forEach(key => {
|
|
|
|
|
if (Array.isArray(data[key])) {
|
|
|
|
|
const filteredArray = filterTreeData(data[key], searchValue);
|
|
|
|
|
if (filteredArray.length > 0) {
|
|
|
|
|
filteredData[key] = filteredArray;
|
|
|
|
|
}
|
|
|
|
|
} else if (typeof data[key] === 'object' && data[key] !== null) {
|
|
|
|
|
const filteredObject = filterTreeData(data[key], searchValue);
|
|
|
|
|
if (Object.keys(filteredObject).length > 0) {
|
|
|
|
|
filteredData[key] = filteredObject;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return filteredData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 根据搜索值过滤组件列表
|
|
|
|
|
const filteredCompList = useMemo(() => {
|
|
|
|
|
if (!searchValue) return compList;
|
|
|
|
|
return filterTreeData(compList, searchValue);
|
|
|
|
|
}, [compList, searchValue]);
|
|
|
|
|
|
|
|
|
|
const renderTreeNode = (menuItems, parentKey = '0') => {
|
|
|
|
|
// 标题枚举值
|
|
|
|
|
@ -45,13 +94,14 @@ const SideBar = ({ compList, onSelect }) => {
|
|
|
|
|
// 如果是数组,表示是最底层的子节点,直接渲染
|
|
|
|
|
if (Array.isArray(menuItems)) {
|
|
|
|
|
return menuItems.map((item, index) => {
|
|
|
|
|
const name = item.name || item?.main?.name || '';
|
|
|
|
|
const treeNodeProps = {
|
|
|
|
|
dataRef: item // 传递原始数据
|
|
|
|
|
};
|
|
|
|
|
return (<TreeNode
|
|
|
|
|
{...treeNodeProps}
|
|
|
|
|
key={`${parentKey}-${index}`}
|
|
|
|
|
title={item.name || item?.main?.name}
|
|
|
|
|
title={name}
|
|
|
|
|
icon={<img src={'/ideContainer/icon/compItem.png'} style={{ width: 17, height: 17 }} />}
|
|
|
|
|
/>);
|
|
|
|
|
});
|
|
|
|
|
@ -61,11 +111,21 @@ const SideBar = ({ compList, onSelect }) => {
|
|
|
|
|
return Object.keys(menuItems).map((key, index) => {
|
|
|
|
|
const child = menuItems[key];
|
|
|
|
|
const currentKey = `${parentKey}-${index}`;
|
|
|
|
|
const title = titleMap.get(key)?.title || key;
|
|
|
|
|
const icon = titleMap.get(key)?.icon || null;
|
|
|
|
|
const titleInfo = titleMap.get(key) || { title: key, icon: null };
|
|
|
|
|
const title = titleInfo.title;
|
|
|
|
|
const icon = titleInfo.icon;
|
|
|
|
|
|
|
|
|
|
// 如果子节点是数组或对象,继续递归
|
|
|
|
|
if (Array.isArray(child) || typeof child === 'object') {
|
|
|
|
|
// 如果搜索值存在,但当前节点下没有匹配的子节点,则不渲染该节点
|
|
|
|
|
const filteredChild = filterTreeData(child, searchValue);
|
|
|
|
|
if (searchValue && (
|
|
|
|
|
(Array.isArray(filteredChild) && filteredChild.length === 0) ||
|
|
|
|
|
(typeof filteredChild === 'object' && Object.keys(filteredChild).length === 0)
|
|
|
|
|
)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<TreeNode key={currentKey} title={title} icon={icon}>
|
|
|
|
|
{renderTreeNode(child, currentKey)}
|
|
|
|
|
@ -74,24 +134,28 @@ const SideBar = ({ compList, onSelect }) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 否则直接渲染叶子节点
|
|
|
|
|
return <TreeNode key={currentKey} title={title} />;
|
|
|
|
|
return <TreeNode key={currentKey} title={title} icon={icon} />;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理输入框回车事件
|
|
|
|
|
const handleKeyPress = (e) => {
|
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
|
handleSearch();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles['side-bar']}>
|
|
|
|
|
<div className={styles['handle-box']}>
|
|
|
|
|
<Input
|
|
|
|
|
prefix={<IconSearch />}
|
|
|
|
|
placeholder={'搜索组件'}
|
|
|
|
|
style={{ width: '90%' }}
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
value={searchValue}
|
|
|
|
|
onChange={handleSearchChange}
|
|
|
|
|
onPressEnter={handleSearch}
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
style={{ marginLeft: 5 }}
|
|
|
|
|
>
|
|
|
|
|
搜索
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles['comp-list']}>
|
|
|
|
|
<Tree
|
|
|
|
|
@ -100,11 +164,14 @@ const SideBar = ({ compList, onSelect }) => {
|
|
|
|
|
selectedKeys={[]} // 移除选中样式
|
|
|
|
|
style={{ background: 'transparent' }} // 移除背景色
|
|
|
|
|
onSelect={(value, info) => {
|
|
|
|
|
if (info.node.props.dataRef.hasOwnProperty('children')) return;
|
|
|
|
|
if (info.node.props.dataRef?.hasOwnProperty('children')) return;
|
|
|
|
|
onSelect(info.node?.props?.dataRef || null);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{renderTreeNode({ projectCompDto: compList.projectCompDto, projectFlowDto: compList.projectFlowDto })}
|
|
|
|
|
{renderTreeNode({
|
|
|
|
|
projectCompDto: filteredCompList.projectCompDto,
|
|
|
|
|
projectFlowDto: filteredCompList.projectFlowDto
|
|
|
|
|
})}
|
|
|
|
|
</Tree>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|