feat(flow): 实现循环节点功能并优化编辑器
- 修改节点类型获取逻辑,从 node.data.type 获取节点类型-为组件标识符添加默认空字符串处理- 在节点编辑器接口中添加索引签名以支持动态属性 - 阻止循环开始节点展示编辑框 - 更新本地节点编辑器以支持循环开始和结束节点类型 - 添加条件表格组件用于配置循环跳出条件- 在流程回调钩子中引入循环节点组件和相关处理逻辑 - 新增循环节点组件,包含开始和结束节点的视觉表示 - 实现添加循环节点时自动创建开始和结束节点及其连接边 - 优化数据转换逻辑以支持新的循环节点结构master
parent
c6ad30b213
commit
da34978f6c
@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { useStore } from '@xyflow/react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import DynamicIcon from '@/components/DynamicIcon';
|
||||
import { Handle, Position } from '@xyflow/react';
|
||||
|
||||
// 循环节点组件,用于显示循环开始和循环结束节点
|
||||
const LoopNode = ({ data, id }: { data: any; id: string }) => {
|
||||
const title = data.title || '循环节点';
|
||||
const isStartNode = data.type === 'LOOP_START';
|
||||
|
||||
// 获取节点选中状态 - 适配React Flow v12 API
|
||||
const isSelected = useStore((state) =>
|
||||
state.nodeLookup.get(id)?.selected || false
|
||||
);
|
||||
|
||||
// 设置图标
|
||||
const setIcon = () => {
|
||||
if (isStartNode) {
|
||||
return <DynamicIcon type="IconPlayArrow" style={{ fontSize: '16px', marginRight: '5px' }} />;
|
||||
}
|
||||
else {
|
||||
return <DynamicIcon type="IconStop" style={{ fontSize: '16px', marginRight: '5px' }} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
|
||||
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
|
||||
{setIcon()}
|
||||
{title}
|
||||
</div>
|
||||
|
||||
{/* 左侧输入连接点 */}
|
||||
<Handle
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id="loop-input"
|
||||
style={{
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)',
|
||||
left: '-4px'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 右侧输出连接点 */}
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id="loop-output"
|
||||
style={{
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)',
|
||||
right: '-4px'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 顶部连接点,用于标识循环开始和结束节点是一组 */}
|
||||
<Handle
|
||||
type={id.includes('END') ? 'target' : 'source'}
|
||||
position={Position.Top}
|
||||
id={`${id}-group`}
|
||||
style={{
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)',
|
||||
top: '-4px'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 节点内容区域 */}
|
||||
<div className={styles['node-content']}>
|
||||
<div className={styles['node-inputs']}>
|
||||
<div className={styles['node-input-label']}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoopNode;
|
||||
Loading…
Reference in New Issue