feat(flowEditor): 优化节点添加功能和界面

- 新增分组标签页,优化节点分类展示
- 改进边添加节点功能,支持在特定位置添加- 调整节点添加按钮样式和布局
- 优化画布点击事件处理,清除节点添加状态
master
钟良源 5 months ago
parent c0f7ffabf8
commit 79ae68ce92

@ -1,7 +1,9 @@
import React from 'react';
import { Menu } from '@arco-design/web-react';
import { Menu, Tabs } from '@arco-design/web-react';
import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData';
const TabPane = Tabs.TabPane;
interface AddNodeMenuProps {
onAddNode: (nodeType: string) => void;
position?: { x: number; y: number }; // 用于画布上下文菜单
@ -9,8 +11,8 @@ interface AddNodeMenuProps {
}
const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
onAddNode
}) => {
onAddNode
}) => {
// 按分组组织节点数据
const groupedNodes = localNodeData.reduce((acc, node) => {
if (!acc[node.nodeGroup]) {
@ -26,46 +28,55 @@ const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
// 分组名称映射
const groupNames: Record<string, string> = {
'common': '系统组件'
// 可以根据需要添加更多分组
// 'application': '应用组件',
// 'composite': '复合组件'
'common': '系统组件',
'application': '应用组件',
'composite': '复合组件'
};
return (
<Menu
style={{
width: 200,
border: '1px solid #e4e7ed',
borderRadius: 4,
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
<div
style={{
backgroundColor: '#ffffff',
padding: '10px',
borderRadius: '10px',
maxHeight: '400px',
display: 'flex',
flexDirection: 'column'
}}
mode="vertical"
hasCollapseButton={false}
>
{Object.entries(groupedNodes).map(([group, nodes]) => (
<Menu.SubMenu
key={group}
title={groupNames[group] || group}
popup
trigger="hover"
>
{nodes.map((node) => (
<Menu.Item
key={node.nodeType}
onClick={() => handleAddNode(node.nodeType)}
style={{
padding: '0 16px',
height: 36,
lineHeight: '36px'
}}
>
{node.nodeName}
</Menu.Item>
))}
</Menu.SubMenu>
))}
</Menu>
<Tabs defaultActiveTab="common" style={{ flex: '0 0 auto' }}>
{Object.entries(groupedNodes).map(([group, nodes]) => (
<TabPane key={group} title={groupNames[group] || group}>
<div style={{ maxHeight: '300px', overflowY: 'auto' }}>
<Menu
style={{
width: 200,
border: '1px solid #e4e7ed',
borderRadius: 4,
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
}}
mode="vertical"
hasCollapseButton={false}
>
{nodes.map((node) => (
<Menu.Item
key={node.nodeType}
onClick={() => handleAddNode(node.nodeType)}
style={{
padding: '0 16px',
height: 36,
lineHeight: '36px'
}}
>
{node.nodeName}
</Menu.Item>
))}
</Menu>
</div>
</TabPane>
))}
</Tabs>
</div>
);
};

@ -15,7 +15,7 @@ const CustomEdge: React.FC<EdgeProps> = ({
selected,
data
}) => {
const [edgePath, labelX, labelY] = getBezierPath({
const [edgePath, labelX, labelY, offsetX, offsetY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
@ -26,13 +26,12 @@ const CustomEdge: React.FC<EdgeProps> = ({
// 从数据中获取悬停状态
const hovered = data?.hovered || false;
// 使用useReactFlow钩子获取setEdges方法
const { setEdges } = useReactFlow();
// 边点击处理函数
const handleEdgeAddNode = () => {
console.log('handleEdgeAddNode called for edge:', id);
const handleEdgeAddNode = (e) => {
// 更新边的数据,触发边上添加节点的流程
setEdges(eds => eds.map(edge => {
if (edge.id === id) {
@ -40,7 +39,9 @@ const CustomEdge: React.FC<EdgeProps> = ({
...edge,
data: {
...edge.data,
addNodeTrigger: true
addNodeTrigger: true,
clientX: e.clientX,
clientY: e.clientY
}
};
}
@ -71,20 +72,11 @@ const CustomEdge: React.FC<EdgeProps> = ({
>
{hovered && (
<EdgeAddNodeButton
onClick={handleEdgeAddNode}
onClick={(e) => handleEdgeAddNode(e)}
/>
)}
</div>
</EdgeLabelRenderer>
{/* 悬停时显示的高亮线条 */}
{hovered && (
<path
d={edgePath}
fill="none"
stroke="#1890ff"
strokeWidth={2}
/>
)}
</>
);
};

@ -3,16 +3,16 @@ import { Button } from '@arco-design/web-react';
import { IconPlus } from '@arco-design/web-react/icon';
interface EdgeAddNodeButtonProps {
onClick: () => void;
onClick: (e) => void;
style?: React.CSSProperties;
}
const EdgeAddNodeButton: React.FC<EdgeAddNodeButtonProps> = ({
onClick,
style
}) => {
const EdgeAddNodeButton: React.FC<EdgeAddNodeButtonProps> = ({
onClick,
style
}) => {
return (
<div
<div
style={{
position: 'absolute',
transform: 'translate(-50%, -50%)',
@ -26,12 +26,12 @@ const EdgeAddNodeButton: React.FC<EdgeAddNodeButtonProps> = ({
icon={<IconPlus />}
onClick={(e) => {
e.stopPropagation();
onClick();
onClick(e);
}}
style={{
width: 20,
height: 20,
minWidth: 20,
width: 12,
height: 12,
minWidth: 12,
padding: 0,
borderRadius: '50%',
display: 'flex',

@ -2,6 +2,8 @@ import React from 'react';
import { Menu } from '@arco-design/web-react';
import AddNodeMenu from './addNodeMenu';
const SubMenu = Menu.SubMenu;
interface PaneContextMenuProps {
onAddNode: (nodeType: string, position: { x: number; y: number }) => void;
position: { x: number; y: number };
@ -18,7 +20,6 @@ const PaneContextMenu: React.FC<PaneContextMenuProps> = ({
return (
<Menu
mode="pop"
style={{
minWidth: 200,
border: '1px solid #e4e7ed',
@ -26,17 +27,16 @@ const PaneContextMenu: React.FC<PaneContextMenuProps> = ({
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
}}
>
<Menu.SubMenu
<SubMenu
key="add-node"
title="添加节点"
popup
triggerProps={{
popupStyle: { height: 'auto', maxHeight: 'none' }
}}
>
<div style={{
padding: '4px 0'
}}>
<AddNodeMenu onAddNode={handleAddNode} />
</div>
</Menu.SubMenu>
<AddNodeMenu onAddNode={handleAddNode} />
</SubMenu>
</Menu>
);
};

@ -289,8 +289,10 @@ const FlowEditor: React.FC = () => {
// 监听边的变化,处理添加节点的触发
useEffect(() => {
const edgeToAddNode = edges.find(edge => edge.data?.addNodeTrigger);
const pane = reactFlowWrapper.current?.getBoundingClientRect();
if (edgeToAddNode) {
console.log('Triggering add node for edge:', edgeToAddNode.id);
edgeToAddNode.data.y = (edgeToAddNode.data.clientY as number) - pane.top;
edgeToAddNode.data.x = (edgeToAddNode.data.clientX as number) - pane.left;
setEdgeForNodeAdd(edgeToAddNode);
// 清除触发标志
@ -380,7 +382,12 @@ const FlowEditor: React.FC = () => {
);
// 点击画布其他区域关闭菜单
const onPaneClick = useCallback(() => setMenu(null), [setMenu]);
const onPaneClick = useCallback(() => {
setMenu(null);
// 关闭添加节点菜单
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
}, [setMenu]);
// 关闭编辑弹窗
const closeEditModal = useCallback(() => {
@ -546,7 +553,7 @@ const FlowEditor: React.FC = () => {
else if (positionForNodeAdd) {
addNodeOnPane(nodeType, positionForNodeAdd);
}
// 清除状态
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
@ -711,14 +718,19 @@ const FlowEditor: React.FC = () => {
<div
style={{
position: 'absolute',
top: edgeForNodeAdd ? '50%' : (positionForNodeAdd?.y || 0),
left: edgeForNodeAdd ? '50%' : (positionForNodeAdd?.x || 0),
top: edgeForNodeAdd ? (edgeForNodeAdd.data?.y as number || 0) : (positionForNodeAdd?.y || 0),
left: edgeForNodeAdd ? ((edgeForNodeAdd.data?.x as number || 0) + 20) : (positionForNodeAdd?.x || 0),
zIndex: 1000,
transform: edgeForNodeAdd ? 'translate(-50%, -50%)' : 'none'
transform: 'none'
}}
>
<AddNodeMenu
onAddNode={handleAddNode}
onAddNode={(nodeType) => {
handleAddNode(nodeType);
// 关闭菜单
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
}}
position={positionForNodeAdd || undefined}
edgeId={edgeForNodeAdd?.id}
/>

Loading…
Cancel
Save