feat(flowEditor): 实现流程图中在边上添加节点的功能
- 在 CustomEdge 组件中添加悬停状态和添加节点按钮 - 在 EdgeContextMenu 中添加"添加节点"选项 - 在 FlowEditor组件中实现添加节点的逻辑 - 新增 AddNodeMenu、EdgeAddNodeButton 和 PaneContextMenu 组件用于添加节点 - 优化流程图的右键菜单,支持在画布空白处添加节点production
parent
09222ca3b9
commit
c0f7ffabf8
@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Menu } from '@arco-design/web-react';
|
||||||
|
import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData';
|
||||||
|
|
||||||
|
interface AddNodeMenuProps {
|
||||||
|
onAddNode: (nodeType: string) => void;
|
||||||
|
position?: { x: number; y: number }; // 用于画布上下文菜单
|
||||||
|
edgeId?: string; // 用于边上下文菜单
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddNodeMenu: React.FC<AddNodeMenuProps> = ({
|
||||||
|
onAddNode
|
||||||
|
}) => {
|
||||||
|
// 按分组组织节点数据
|
||||||
|
const groupedNodes = localNodeData.reduce((acc, node) => {
|
||||||
|
if (!acc[node.nodeGroup]) {
|
||||||
|
acc[node.nodeGroup] = [];
|
||||||
|
}
|
||||||
|
acc[node.nodeGroup].push(node);
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, typeof localNodeData>);
|
||||||
|
|
||||||
|
const handleAddNode = (nodeType: string) => {
|
||||||
|
onAddNode(nodeType);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分组名称映射
|
||||||
|
const groupNames: Record<string, string> = {
|
||||||
|
'common': '系统组件'
|
||||||
|
// 可以根据需要添加更多分组
|
||||||
|
// 'application': '应用组件',
|
||||||
|
// 'composite': '复合组件'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
style={{
|
||||||
|
width: 200,
|
||||||
|
border: '1px solid #e4e7ed',
|
||||||
|
borderRadius: 4,
|
||||||
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
|
||||||
|
}}
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddNodeMenu;
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Button } from '@arco-design/web-react';
|
||||||
|
import { IconPlus } from '@arco-design/web-react/icon';
|
||||||
|
|
||||||
|
interface EdgeAddNodeButtonProps {
|
||||||
|
onClick: () => void;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EdgeAddNodeButton: React.FC<EdgeAddNodeButtonProps> = ({
|
||||||
|
onClick,
|
||||||
|
style
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
pointerEvents: 'all',
|
||||||
|
...style
|
||||||
|
}}
|
||||||
|
className="nodrag nopan"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
size="mini"
|
||||||
|
icon={<IconPlus />}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onClick();
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
minWidth: 20,
|
||||||
|
padding: 0,
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: '#1890ff', // 使用项目主题蓝色
|
||||||
|
borderColor: '#1890ff',
|
||||||
|
color: '#ffffff'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EdgeAddNodeButton;
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Menu } from '@arco-design/web-react';
|
||||||
|
import AddNodeMenu from './addNodeMenu';
|
||||||
|
|
||||||
|
interface PaneContextMenuProps {
|
||||||
|
onAddNode: (nodeType: string, position: { x: number; y: number }) => void;
|
||||||
|
position: { x: number; y: number };
|
||||||
|
}
|
||||||
|
|
||||||
|
const PaneContextMenu: React.FC<PaneContextMenuProps> = ({
|
||||||
|
onAddNode,
|
||||||
|
position
|
||||||
|
}) => {
|
||||||
|
// 包装onAddNode函数以适配AddNodeMenu组件的接口
|
||||||
|
const handleAddNode = (nodeType: string) => {
|
||||||
|
onAddNode(nodeType, position);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
mode="pop"
|
||||||
|
style={{
|
||||||
|
minWidth: 200,
|
||||||
|
border: '1px solid #e4e7ed',
|
||||||
|
borderRadius: 4,
|
||||||
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu.SubMenu
|
||||||
|
key="add-node"
|
||||||
|
title="添加节点"
|
||||||
|
popup
|
||||||
|
>
|
||||||
|
<div style={{
|
||||||
|
padding: '4px 0'
|
||||||
|
}}>
|
||||||
|
<AddNodeMenu onAddNode={handleAddNode} />
|
||||||
|
</div>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaneContextMenu;
|
||||||
Loading…
Reference in New Issue