|
|
|
|
@ -1,7 +1,8 @@
|
|
|
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
import { Menu, Tabs } from '@arco-design/web-react';
|
|
|
|
|
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
|
|
|
|
import { Input, Menu, Tabs } from '@arco-design/web-react';
|
|
|
|
|
import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData';
|
|
|
|
|
import { useSelector } from 'react-redux';
|
|
|
|
|
import { IconSearch } from '@arco-design/web-react/icon';
|
|
|
|
|
|
|
|
|
|
const TabPane = Tabs.TabPane;
|
|
|
|
|
|
|
|
|
|
@ -17,6 +18,7 @@ const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
|
|
|
|
|
const { projectComponentData, info } = useSelector((state: any) => state.ideContainer);
|
|
|
|
|
const [groupedNodes, setGroupedNodes] = useState<Record<string, any[]>>({});
|
|
|
|
|
const [activeTab, setActiveTab] = useState('common');
|
|
|
|
|
const [searchValue, setSearchValue] = useState(''); // 添加搜索状态
|
|
|
|
|
|
|
|
|
|
// 按分组组织节点数据
|
|
|
|
|
const formattedNodes = useCallback(() => {
|
|
|
|
|
@ -76,10 +78,56 @@ const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
|
|
|
|
|
setGroupedNodes(initialGroupedNodes);
|
|
|
|
|
}, [projectComponentData, info.id]);
|
|
|
|
|
|
|
|
|
|
// 根据搜索值过滤节点
|
|
|
|
|
const filteredGroupedNodes = useMemo(() => {
|
|
|
|
|
if (!searchValue) return groupedNodes;
|
|
|
|
|
|
|
|
|
|
const filteredNodes: Record<string, any[]> = {};
|
|
|
|
|
|
|
|
|
|
Object.keys(groupedNodes).forEach(group => {
|
|
|
|
|
const nodes = groupedNodes[group];
|
|
|
|
|
const filtered = nodes.filter(node => {
|
|
|
|
|
const nodeName = node.nodeName || node.name || '';
|
|
|
|
|
return nodeName.toLowerCase().includes(searchValue.toLowerCase());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (filtered.length > 0) {
|
|
|
|
|
filteredNodes[group] = filtered;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return filteredNodes;
|
|
|
|
|
}, [groupedNodes, searchValue]);
|
|
|
|
|
|
|
|
|
|
// 获取第一个有数据的tab
|
|
|
|
|
const getFirstAvailableTab = useCallback(() => {
|
|
|
|
|
const groupKeys = Object.keys(filteredGroupedNodes);
|
|
|
|
|
if (groupKeys.length > 0) {
|
|
|
|
|
return groupKeys[0];
|
|
|
|
|
}
|
|
|
|
|
return 'common';
|
|
|
|
|
}, [filteredGroupedNodes]);
|
|
|
|
|
|
|
|
|
|
// 当搜索值改变时,自动选中第一个有结果的tab
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (searchValue) {
|
|
|
|
|
const firstTab = getFirstAvailableTab();
|
|
|
|
|
setActiveTab(firstTab);
|
|
|
|
|
} else {
|
|
|
|
|
// 如果搜索值为空,恢复默认选中tab
|
|
|
|
|
setActiveTab('common');
|
|
|
|
|
}
|
|
|
|
|
}, [searchValue, getFirstAvailableTab]);
|
|
|
|
|
|
|
|
|
|
const handleAddNode = (nodeType: string, node: any) => {
|
|
|
|
|
onAddNode(nodeType, node);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理搜索输入变化
|
|
|
|
|
const handleSearchChange = (value: string) => {
|
|
|
|
|
setSearchValue(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 分组名称映射
|
|
|
|
|
const groupNames: Record<string, string> = {
|
|
|
|
|
'application': '基础组件',
|
|
|
|
|
@ -106,8 +154,16 @@ const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
|
|
|
|
|
flexDirection: 'column'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Tabs defaultActiveTab="common" style={{ flex: '0 0 auto' }} onChange={handleTabChange}>
|
|
|
|
|
{Object.entries(groupedNodes).map(([group, nodes]) => (
|
|
|
|
|
<Input
|
|
|
|
|
size="large"
|
|
|
|
|
placeholder="搜索节点"
|
|
|
|
|
prefix={<IconSearch />}
|
|
|
|
|
style={{ marginRight: 16 }}
|
|
|
|
|
value={searchValue}
|
|
|
|
|
onChange={handleSearchChange}
|
|
|
|
|
/>
|
|
|
|
|
<Tabs activeTab={activeTab} style={{ flex: '0 0 auto' }} onChange={handleTabChange}>
|
|
|
|
|
{Object.entries(filteredGroupedNodes).map(([group, nodes]) => (
|
|
|
|
|
<TabPane key={group} title={groupNames[group] || group}>
|
|
|
|
|
{/* 只有在当前 tab 激活时才渲染内容 */}
|
|
|
|
|
{activeTab === group && (
|
|
|
|
|
|