feat(flow):为多种节点类型添加运行状态指示器

master
钟良源 4 months ago
parent c13e0c1619
commit 28b423e208

@ -3,6 +3,8 @@ import { useStore } from '@xyflow/react';
import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
import DynamicIcon from '@/components/DynamicIcon'; import DynamicIcon from '@/components/DynamicIcon';
import NodeContentCode from '@/pages/flowEditor/components/nodeContentCode'; import NodeContentCode from '@/pages/flowEditor/components/nodeContentCode';
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
import { useStore as useFlowStore } from '@xyflow/react';
const setIcon = () => { const setIcon = () => {
return <DynamicIcon type="IconCode" style={{ fontSize: '16px', marginRight: '5px' }} />; return <DynamicIcon type="IconCode" style={{ fontSize: '16px', marginRight: '5px' }} />;
@ -15,12 +17,23 @@ const CodeNode = ({ data, id }: { data: any; id: string }) => {
const isSelected = useStore((state) => const isSelected = useStore((state) =>
state.nodeLookup.get(id)?.selected || false state.nodeLookup.get(id)?.selected || false
); );
// 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
);
// 获取运行状态可见性
const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible
);
return ( return (
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}> <div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}> <div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{setIcon()} {setIcon()}
{title} {title}
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
</div> </div>
<NodeContentCode data={data} /> <NodeContentCode data={data} />
</div> </div>

@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import { useStore } from '@xyflow/react'; import { useStore } from '@xyflow/react';
// import styles from '@/pages/flowEditor/node/style/base.module.less';
import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
import DynamicIcon from '@/components/DynamicIcon'; import DynamicIcon from '@/components/DynamicIcon';
import NodeContentImage from '@/pages/flowEditor/components/nodeContentImage'; import NodeContentImage from '@/pages/flowEditor/components/nodeContentImage';
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
import { useStore as useFlowStore } from '@xyflow/react';
const setIcon = () => { const setIcon = () => {
return <DynamicIcon type="IconImage" style={{ fontSize: '16px', marginRight: '5px' }} />; return <DynamicIcon type="IconImage" style={{ fontSize: '16px', marginRight: '5px' }} />;
@ -16,12 +17,23 @@ const ImageNode = ({ data, id }: { data: any; id: string }) => {
const isSelected = useStore((state) => const isSelected = useStore((state) =>
state.nodeLookup.get(id)?.selected || false state.nodeLookup.get(id)?.selected || false
); );
// 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
);
// 获取运行状态可见性
const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible
);
return ( return (
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}> <div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}> <div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{setIcon()} {setIcon()}
{title} {title}
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
</div> </div>
<NodeContentImage data={data} /> <NodeContentImage data={data} />
</div> </div>

@ -4,13 +4,23 @@ import StartNode from './startNode/StartNode';
import EndNode from './endNode/EndNode'; import EndNode from './endNode/EndNode';
import BasicNode from './basicNode/BasicNode'; import BasicNode from './basicNode/BasicNode';
import AppNode from './appNode/AppNode'; import AppNode from './appNode/AppNode';
import CodeNode from './codeNode/CodeNode';
import ImageNode from './imageNode/ImageNode';
import RestNode from './restNode/RestNode';
import SwitchNode from './switchNode/SwitchNode';
import LoopNode from './loopNode/LoopNode';
// 定义所有可用的节点类型 // 定义所有可用的节点类型
export const nodeTypes: NodeTypes = { export const nodeTypes: NodeTypes = {
start: StartNode, start: StartNode,
end: EndNode, end: EndNode,
BASIC: BasicNode, BASIC: BasicNode,
APP: AppNode APP: AppNode,
CODE: CodeNode,
IMAGE: ImageNode,
REST: RestNode,
SWITCH: SwitchNode,
LOOP: LoopNode
}; };
// 节点类型映射,用于创建节点时的类型查找 // 节点类型映射,用于创建节点时的类型查找
@ -18,7 +28,12 @@ export const nodeTypeMap: Record<string, string> = {
'start': 'start', 'start': 'start',
'end': 'end', 'end': 'end',
'basic': 'BASIC', 'basic': 'BASIC',
'app': 'APP' 'app': 'APP',
'code': 'CODE',
'image': 'IMAGE',
'rest': 'REST',
'switch': 'SWITCH',
'loop': 'LOOP'
}; };
// 节点显示名称映射 // 节点显示名称映射
@ -26,7 +41,12 @@ export const nodeTypeNameMap: Record<string, string> = {
'start': '开始节点', 'start': '开始节点',
'end': '结束节点', 'end': '结束节点',
'basic': '基础节点', 'basic': '基础节点',
'app': '应用节点' 'app': '应用节点',
'code': '代码节点',
'image': '图片节点',
'rest': 'REST节点',
'switch': '条件节点',
'loop': '循环节点'
}; };
// 注册新节点类型的函数 // 注册新节点类型的函数

@ -67,12 +67,12 @@ const LocalNode = ({ data, id }: { data: any; id: string }) => {
); );
// 获取节点运行状态 // 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) => const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting' (state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
); );
// 获取运行状态可见性 // 获取运行状态可见性
const isStatusVisible = useFlowStore((state) => const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible !!state.nodeLookup.get(id)?.data?.isStatusVisible
); );

@ -5,6 +5,8 @@ import DynamicIcon from '@/components/DynamicIcon';
import { Handle, Position } from '@xyflow/react'; import { Handle, Position } from '@xyflow/react';
import NodeContentLoop from '@/pages/flowEditor/components/nodeContentLoop'; import NodeContentLoop from '@/pages/flowEditor/components/nodeContentLoop';
import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType'; import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType';
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
import { useStore as useFlowStore } from '@xyflow/react';
// 循环节点组件,用于显示循环开始和循环结束节点 // 循环节点组件,用于显示循环开始和循环结束节点
const LoopNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => { const LoopNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
@ -16,6 +18,16 @@ const LoopNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
const isSelected = useStore((state) => const isSelected = useStore((state) =>
state.nodeLookup.get(id)?.selected || false state.nodeLookup.get(id)?.selected || false
); );
// 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
);
// 获取运行状态可见性
const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible
);
// 设置图标 // 设置图标
const setIcon = () => { const setIcon = () => {
@ -150,6 +162,7 @@ const LoopNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}> <div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{setIcon()} {setIcon()}
{title} {title}
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
</div> </div>
{/* 顶部连接点,用于标识循环开始和结束节点是一组 */} {/* 顶部连接点,用于标识循环开始和结束节点是一组 */}

@ -3,28 +3,41 @@ import { useStore } from '@xyflow/react';
import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
import DynamicIcon from '@/components/DynamicIcon'; import DynamicIcon from '@/components/DynamicIcon';
import NodeContentREST from '@/pages/flowEditor/components/nodeContentREST'; import NodeContentREST from '@/pages/flowEditor/components/nodeContentREST';
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
import { useStore as useFlowStore } from '@xyflow/react';
const setIcon = () => { const setIcon = () => {
return <DynamicIcon type="IconCloudDownload" style={{ fontSize: '16px', marginRight: '5px' }} />; return <DynamicIcon type="IconCloudDownload" style={{ fontSize: '16px', marginRight: '5px' }} />;
}; };
const CodeNode = ({ data, id }: { data: any; id: string }) => { const RestNode = ({ data, id }: { data: any; id: string }) => {
const title = data.title || 'REST调用'; const title = data.title || 'REST调用';
// 获取节点选中状态 - 适配React Flow v12 API // 获取节点选中状态 - 适配React Flow v12 API
const isSelected = useStore((state) => const isSelected = useStore((state) =>
state.nodeLookup.get(id)?.selected || false state.nodeLookup.get(id)?.selected || false
); );
// 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
);
// 获取运行状态可见性
const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible
);
return ( return (
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}> <div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}> <div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{setIcon()} {setIcon()}
{title} {title}
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
</div> </div>
<NodeContentREST data={data} /> <NodeContentREST data={data} />
</div> </div>
); );
}; };
export default CodeNode; export default RestNode;

@ -5,6 +5,8 @@ import DynamicIcon from '@/components/DynamicIcon';
import { Handle, Position } from '@xyflow/react'; import { Handle, Position } from '@xyflow/react';
import NodeContentSwitch from '@/pages/flowEditor/components/nodeContentSwitch'; import NodeContentSwitch from '@/pages/flowEditor/components/nodeContentSwitch';
import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType'; import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType';
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
import { useStore as useFlowStore } from '@xyflow/react';
// 循环节点组件,用于显示循环开始和循环结束节点 // 循环节点组件,用于显示循环开始和循环结束节点
const SwitchNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => { const SwitchNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
@ -15,6 +17,16 @@ const SwitchNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
const isSelected = useStore((state) => const isSelected = useStore((state) =>
state.nodeLookup.get(id)?.selected || false state.nodeLookup.get(id)?.selected || false
); );
// 获取节点运行状态
const nodeStatus: NodeStatus = useFlowStore((state) =>
(state.nodeLookup.get(id)?.data?.status as NodeStatus) || 'waiting'
);
// 获取运行状态可见性
const isStatusVisible = useFlowStore((state) =>
!!state.nodeLookup.get(id)?.data?.isStatusVisible
);
// 设置图标 // 设置图标
const setIcon = () => { const setIcon = () => {
@ -147,6 +159,7 @@ const SwitchNode = ({ data, id }: { data: defaultNodeTypes; id: string }) => {
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}> <div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{setIcon()} {setIcon()}
{title} {title}
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
</div> </div>
<NodeContentSwitch data={modifiedData} /> <NodeContentSwitch data={modifiedData} />

Loading…
Cancel
Save