Merge branch 'refs/heads/master' into production
commit
dfe80b1ee8
@ -0,0 +1,20 @@
|
||||
import axios from 'axios';
|
||||
import { apiResData } from '@/api/interface/index';
|
||||
|
||||
// 公共路径
|
||||
const urlPrefix = '/api/v1/bpms-workbench';
|
||||
|
||||
// 获取应用事件
|
||||
export function getAppEventData(id: any) {
|
||||
return axios.get<apiResData>(`${urlPrefix}/appEvent/${id}`);
|
||||
}
|
||||
|
||||
// 获取工程下的所有应用事件
|
||||
export function getAppEventList(id: any) {
|
||||
return axios.get<apiResData>(`${urlPrefix}/appEvent/${id}/list`);
|
||||
}
|
||||
|
||||
// 更新事件
|
||||
export function updateAppEvent(id: any, data: any) {
|
||||
return axios.post<apiResData>(`${urlPrefix}/appEvent/${id}/update`, data);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import styles from './node/style/baseOther.module.less';
|
||||
|
||||
// 定义节点状态类型
|
||||
export type NodeStatus = 'waiting' | 'running' | 'success' | 'failed';
|
||||
|
||||
// 节点状态指示器组件
|
||||
const NodeStatusIndicator: React.FC<{ status: NodeStatus, isVisible: boolean }> = ({ status, isVisible }) => {
|
||||
// 如果不可见,不渲染任何内容
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据状态返回相应的指示器样式
|
||||
const getStatusIndicator = () => {
|
||||
switch (status) {
|
||||
case 'waiting':
|
||||
return <div className={styles['status-waiting']} />;
|
||||
case 'running':
|
||||
return <div className={styles['status-running']} />;
|
||||
case 'success':
|
||||
return <div className={styles['status-success']} />;
|
||||
case 'failed':
|
||||
return <div className={styles['status-failed']} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['node-status-indicator']}>
|
||||
{getStatusIndicator()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeStatusIndicator;
|
||||
@ -0,0 +1,43 @@
|
||||
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 NodeContentCode from '@/pages/flowEditor/components/nodeContentCode';
|
||||
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
|
||||
import { useStore as useFlowStore } from '@xyflow/react';
|
||||
|
||||
const setIcon = () => {
|
||||
return <DynamicIcon type="IconCode" style={{ fontSize: '16px', marginRight: '5px' }} />;
|
||||
};
|
||||
|
||||
const CodeNode = ({ data, id }: { data: any; id: string }) => {
|
||||
const title = data.title || '代码编辑器';
|
||||
|
||||
// 获取节点选中状态 - 适配React Flow v12 API
|
||||
const isSelected = useStore((state) =>
|
||||
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 (
|
||||
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
|
||||
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
|
||||
{setIcon()}
|
||||
{title}
|
||||
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
|
||||
</div>
|
||||
<NodeContentCode data={data} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeNode;
|
||||
@ -0,0 +1,43 @@
|
||||
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 NodeContentImage from '@/pages/flowEditor/components/nodeContentImage';
|
||||
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
|
||||
import { useStore as useFlowStore } from '@xyflow/react';
|
||||
|
||||
const setIcon = () => {
|
||||
return <DynamicIcon type="IconImage" style={{ fontSize: '16px', marginRight: '5px' }} />;
|
||||
};
|
||||
|
||||
const ImageNode = ({ data, id }: { data: any; id: string }) => {
|
||||
const title = data.title || '图片展示';
|
||||
|
||||
// 获取节点选中状态 - 适配React Flow v12 API
|
||||
const isSelected = useStore((state) =>
|
||||
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 (
|
||||
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
|
||||
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
|
||||
{setIcon()}
|
||||
{title}
|
||||
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
|
||||
</div>
|
||||
<NodeContentImage data={data} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageNode;
|
||||
@ -0,0 +1,43 @@
|
||||
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 NodeContentREST from '@/pages/flowEditor/components/nodeContentREST';
|
||||
import NodeStatusIndicator, { NodeStatus } from '@/components/FlowEditor/NodeStatusIndicator';
|
||||
import { useStore as useFlowStore } from '@xyflow/react';
|
||||
|
||||
const setIcon = () => {
|
||||
return <DynamicIcon type="IconCloudDownload" style={{ fontSize: '16px', marginRight: '5px' }} />;
|
||||
};
|
||||
|
||||
const RestNode = ({ data, id }: { data: any; id: string }) => {
|
||||
const title = data.title || 'REST调用';
|
||||
|
||||
// 获取节点选中状态 - 适配React Flow v12 API
|
||||
const isSelected = useStore((state) =>
|
||||
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 (
|
||||
<div className={`${styles['node-container']} ${isSelected ? styles.selected : ''}`}>
|
||||
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
|
||||
{setIcon()}
|
||||
{title}
|
||||
<NodeStatusIndicator status={nodeStatus} isVisible={isStatusVisible} />
|
||||
</div>
|
||||
<NodeContentREST data={data} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RestNode;
|
||||
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { NodeEditorProps } from '@/components/FlowEditor/nodeEditors';
|
||||
import { Typography } from '@arco-design/web-react';
|
||||
import { IconUnorderedList } from '@arco-design/web-react/icon';
|
||||
import ParamsTable from './ParamsTable';
|
||||
|
||||
const ConditionEditor: React.FC<NodeEditorProps> = ({ nodeData, updateNodeData }) => {
|
||||
return (
|
||||
<>
|
||||
<Typography.Title heading={5}><IconUnorderedList style={{ marginRight: 5 }} />输入参数</Typography.Title>
|
||||
<ParamsTable
|
||||
initialData={nodeData.parameters.dataIns || []}
|
||||
onUpdateData={(data) => {
|
||||
updateNodeData('parameters', {
|
||||
...nodeData.parameters,
|
||||
dataIns: data
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConditionEditor;
|
||||
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { NodeEditorProps } from '@/components/FlowEditor/nodeEditors';
|
||||
import { Typography } from '@arco-design/web-react';
|
||||
import { IconUnorderedList } from '@arco-design/web-react/icon';
|
||||
import ParamsTable from './ParamsTable';
|
||||
import ConditionsTable from '@/components/FlowEditor/nodeEditors/components/ConditionsTable';
|
||||
|
||||
const SwitchEditor: React.FC<NodeEditorProps> = ({ nodeData, updateNodeData }) => {
|
||||
return (
|
||||
<>
|
||||
<Typography.Title heading={5}><IconUnorderedList style={{ marginRight: 5 }} />输入参数</Typography.Title>
|
||||
<ParamsTable
|
||||
initialData={nodeData.parameters.dataIns || []}
|
||||
onUpdateData={(data) => {
|
||||
updateNodeData('parameters', {
|
||||
...nodeData.parameters,
|
||||
dataIns: data
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Typography.Title heading={5}>
|
||||
<IconUnorderedList style={{ marginRight: 5, marginTop: 20 }} />
|
||||
条件表达式
|
||||
</Typography.Title>
|
||||
<ConditionsTable
|
||||
initialData={nodeData.component || {}}
|
||||
nodeData={nodeData || null}
|
||||
onUpdateData={(data) => {
|
||||
updateNodeData('component', {
|
||||
...data.component
|
||||
});
|
||||
updateNodeData('parameters', {
|
||||
...nodeData.parameters,
|
||||
apiOuts: data.parameters.apiOuts
|
||||
});
|
||||
}}
|
||||
type="switch"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwitchEditor;
|
||||
@ -0,0 +1 @@
|
||||
export * from './nodeValidators';
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,185 @@
|
||||
import React from 'react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import { Handle, Position, useStore } from '@xyflow/react';
|
||||
import { deserializeValue, isJSON } from '@/utils/common';
|
||||
import cronstrue from 'cronstrue/i18n';
|
||||
|
||||
interface NodeContentData {
|
||||
parameters?: {
|
||||
dataIns?: any[];
|
||||
dataOuts?: any[];
|
||||
apiIns?: any[];
|
||||
apiOuts?: any[];
|
||||
};
|
||||
showFooter?: boolean;
|
||||
type?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义通用的句柄样式
|
||||
const handleStyles = {
|
||||
mainSource: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
mainTarget: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
data: {
|
||||
background: '#555',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
border: '1px solid #fff',
|
||||
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染普通节点的句柄
|
||||
const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
||||
return (
|
||||
<>
|
||||
{apiOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={apiOuts[index].name || apiOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainSource,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{apiIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={apiIns[index].name || apiIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainTarget,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输入参数连接端点 */}
|
||||
{dataIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={dataIns[index].name || dataIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiIns.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输出参数连接端点 */}
|
||||
{dataOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={dataOuts[index].name || dataOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const NodeContent = ({ data }: { data: NodeContentData }) => {
|
||||
const apiIns = data.parameters?.apiIns || [];
|
||||
const apiOuts = data.parameters?.apiOuts || [];
|
||||
const dataIns = data.parameters?.dataIns || [];
|
||||
const dataOuts = data.parameters?.dataOuts || [];
|
||||
const showFooter = data?.component?.customDef || false;
|
||||
|
||||
// 判断节点类型
|
||||
const isStartNode = data.type === 'start';
|
||||
const isEndNode = data.type === 'end';
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*content栏-api部分*/}
|
||||
<div className={styles['node-api-box']}>
|
||||
<div className={styles['node-content-api']}>
|
||||
{apiIns.length > 0 && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{apiIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiOuts.length > 0 && (
|
||||
<div className={styles['node-outputs-api']}>
|
||||
{apiOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(dataIns.length > 0 || dataOuts.length > 0) && (
|
||||
<>
|
||||
{/*分割*/}
|
||||
<div
|
||||
className={styles['node-split-line']}
|
||||
>
|
||||
|
||||
</div>
|
||||
|
||||
{/*content栏-data部分*/}
|
||||
<div className={styles['node-data-box']}>
|
||||
<div className={styles['node-content']}>
|
||||
{dataIns.length > 0 && !isStartNode && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{dataIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.id || `输入${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dataOuts.length > 0 && !isEndNode && (
|
||||
<div className={styles['node-outputs']}>
|
||||
{dataOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{`${output.id} ${output.dataType}` || `输出${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{/* 根据节点类型渲染不同的句柄 */}
|
||||
{renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeContent;
|
||||
@ -0,0 +1,189 @@
|
||||
import React from 'react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import { Handle, Position, useStore } from '@xyflow/react';
|
||||
import { Image } from '@arco-design/web-react';
|
||||
|
||||
interface NodeContentData {
|
||||
parameters?: {
|
||||
dataIns?: any[];
|
||||
dataOuts?: any[];
|
||||
apiIns?: any[];
|
||||
apiOuts?: any[];
|
||||
};
|
||||
showFooter?: boolean;
|
||||
type?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义通用的句柄样式
|
||||
const handleStyles = {
|
||||
mainSource: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
mainTarget: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
data: {
|
||||
background: '#555',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
border: '1px solid #fff',
|
||||
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染普通节点的句柄
|
||||
const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
||||
return (
|
||||
<>
|
||||
{apiOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={apiOuts[index].name || apiOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainSource,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{apiIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={apiIns[index].name || apiIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainTarget,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输入参数连接端点 */}
|
||||
{dataIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={dataIns[index].name || dataIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiIns.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输出参数连接端点 */}
|
||||
{dataOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={dataOuts[index].name || dataOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const NodeContent = ({ data }: { data: NodeContentData }) => {
|
||||
const apiIns = data.parameters?.apiIns || [];
|
||||
const apiOuts = data.parameters?.apiOuts || [];
|
||||
const dataIns = data.parameters?.dataIns || [];
|
||||
const dataOuts = data.parameters?.dataOuts || [];
|
||||
|
||||
// 判断节点类型
|
||||
const isStartNode = data.type === 'start';
|
||||
const isEndNode = data.type === 'end';
|
||||
const isSpecialNode = isStartNode || isEndNode;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*content栏-api部分*/}
|
||||
<div className={styles['node-api-box']}>
|
||||
<div className={styles['node-content-api']}>
|
||||
{apiIns.length > 0 && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{apiIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiOuts.length > 0 && (
|
||||
<div className={styles['node-outputs-api']}>
|
||||
{apiOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(dataIns.length > 0 || dataOuts.length > 0) && (
|
||||
<>
|
||||
{/*分割*/}
|
||||
<div className={styles['node-split-line']}></div>
|
||||
|
||||
{/*content栏-data部分*/}
|
||||
<div className={styles['node-data-box']}>
|
||||
<div className={styles['node-content']}>
|
||||
{dataIns.length > 0 && !isStartNode && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{dataIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{`${input.desc} ${input.dataType}` || `输入${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dataOuts.length > 0 && !isEndNode && (
|
||||
<div className={styles['node-outputs']}>
|
||||
{dataOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.id || `输出${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/*图片展示 TODO 需要对接接口*/}
|
||||
{/*<div className={styles['node-image-box']}>*/}
|
||||
{/* <Image*/}
|
||||
{/* width={150}*/}
|
||||
{/* src=""*/}
|
||||
{/* alt="lamp"*/}
|
||||
{/* />*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/* 根据节点类型渲染不同的句柄 */}
|
||||
{renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeContent;
|
||||
@ -0,0 +1,178 @@
|
||||
import React from 'react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import { Handle, Position, useStore } from '@xyflow/react';
|
||||
import { deserializeValue } from '@/utils/common';
|
||||
import cronstrue from 'cronstrue/i18n';
|
||||
|
||||
interface NodeContentData {
|
||||
parameters?: {
|
||||
dataIns?: any[];
|
||||
dataOuts?: any[];
|
||||
apiIns?: any[];
|
||||
apiOuts?: any[];
|
||||
};
|
||||
showFooter?: boolean;
|
||||
type?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义通用的句柄样式
|
||||
const handleStyles = {
|
||||
mainSource: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
mainTarget: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
data: {
|
||||
background: '#555',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
border: '1px solid #fff',
|
||||
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染LOOP节点的句柄
|
||||
const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
||||
return (
|
||||
<>
|
||||
{apiOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={apiOuts[index].name || apiOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainSource,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{apiIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={apiIns[index].name || apiIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainTarget,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输入参数连接端点 */}
|
||||
{dataIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={dataIns[index].name || dataIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${65 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输出参数连接端点 */}
|
||||
{dataOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={dataOuts[index].name || dataOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${65 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const NodeContent = ({ data }: { data: NodeContentData }) => {
|
||||
const apiIns = data.parameters?.apiIns || [];
|
||||
const apiOuts = data.parameters?.apiOuts || [];
|
||||
const dataIns = data.parameters?.dataIns || [];
|
||||
const dataOuts = data.parameters?.dataOuts || [];
|
||||
|
||||
// 判断节点类型
|
||||
const isStartNode = data.type === 'start';
|
||||
const isEndNode = data.type === 'end';
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*content栏-api部分*/}
|
||||
<div className={styles['node-api-box']}>
|
||||
<div className={styles['node-content-api']}>
|
||||
{apiIns.length > 0 && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{apiIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{data.type !== 'LOOP_START' ? input.desc || input.id : ''}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiOuts.length > 0 && (
|
||||
<div className={styles['node-outputs-api']}>
|
||||
{apiOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{data.type !== 'LOOP_START' ? output.desc || output.id || output.name : ''}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(dataIns.length > 0 || dataOuts.length > 0) && (
|
||||
<>
|
||||
{/*分割*/}
|
||||
<div className={styles['node-split-line']}></div>
|
||||
|
||||
{/*content栏-data部分*/}
|
||||
<div className={styles['node-data-box']}>
|
||||
<div className={styles['node-content']}>
|
||||
{dataIns.length > 0 && !isStartNode && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{dataIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.id || `输入${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dataOuts.length > 0 && !isEndNode && (
|
||||
<div className={styles['node-outputs']}>
|
||||
{dataOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.id || `输出${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeContent;
|
||||
@ -0,0 +1,182 @@
|
||||
import React from 'react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import { Handle, Position, useStore } from '@xyflow/react';
|
||||
|
||||
interface NodeContentData {
|
||||
parameters?: {
|
||||
dataIns?: any[];
|
||||
dataOuts?: any[];
|
||||
apiIns?: any[];
|
||||
apiOuts?: any[];
|
||||
};
|
||||
showFooter?: boolean;
|
||||
type?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义通用的句柄样式
|
||||
const handleStyles = {
|
||||
mainSource: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
mainTarget: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
data: {
|
||||
background: '#555',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
border: '1px solid #fff',
|
||||
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染普通节点的句柄
|
||||
const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
||||
return (
|
||||
<>
|
||||
{apiOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={apiOuts[index].name || apiOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainSource,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{apiIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={apiIns[index].name || apiIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainTarget,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输入参数连接端点 */}
|
||||
{dataIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={dataIns[index].name || dataIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiIns.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输出参数连接端点 */}
|
||||
{dataOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={dataOuts[index].name || dataOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${70 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const NodeContent = ({ data }: { data: NodeContentData }) => {
|
||||
const apiIns = data.parameters?.apiIns || [];
|
||||
const apiOuts = data.parameters?.apiOuts || [];
|
||||
const dataIns = data.parameters?.dataIns || [];
|
||||
const dataOuts = data.parameters?.dataOuts || [];
|
||||
|
||||
// 判断节点类型
|
||||
const isStartNode = data.type === 'start';
|
||||
const isEndNode = data.type === 'end';
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*content栏-api部分*/}
|
||||
<div className={styles['node-api-box']}>
|
||||
<div className={styles['node-content-api']}>
|
||||
{apiIns.length > 0 && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{apiIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiOuts.length > 0 && (
|
||||
<div className={styles['node-outputs-api']}>
|
||||
{apiOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(dataIns.length > 0 || dataOuts.length > 0) && (
|
||||
<>
|
||||
{/*分割*/}
|
||||
<div
|
||||
className={styles['node-split-line']}
|
||||
>
|
||||
|
||||
</div>
|
||||
|
||||
{/*content栏-data部分*/}
|
||||
<div className={styles['node-data-box']}>
|
||||
<div className={styles['node-content']}>
|
||||
{dataIns.length > 0 && !isStartNode && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{dataIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.id || `输入${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dataOuts.length > 0 && !isEndNode && (
|
||||
<div className={styles['node-outputs']}>
|
||||
{dataOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{`${output.id} ${output.dataType}` || `输出${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{/* 根据节点类型渲染不同的句柄 */}
|
||||
{renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeContent;
|
||||
@ -0,0 +1,176 @@
|
||||
import React from 'react';
|
||||
import styles from '@/components/FlowEditor/node/style/baseOther.module.less';
|
||||
import { Handle, Position, useStore } from '@xyflow/react';
|
||||
|
||||
interface NodeContentData {
|
||||
parameters?: {
|
||||
dataIns?: any[];
|
||||
dataOuts?: any[];
|
||||
apiIns?: any[];
|
||||
apiOuts?: any[];
|
||||
};
|
||||
showFooter?: boolean;
|
||||
type?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义通用的句柄样式
|
||||
const handleStyles = {
|
||||
mainSource: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
mainTarget: {
|
||||
background: '#2290f6',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
border: '2px solid #fff',
|
||||
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
||||
},
|
||||
data: {
|
||||
background: '#555',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
border: '1px solid #fff',
|
||||
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染普通节点的句柄
|
||||
const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
||||
return (
|
||||
<>
|
||||
{apiOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={apiOuts[index].name || apiOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainSource,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{apiIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`api-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={apiIns[index].name || apiIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.mainTarget,
|
||||
top: `${35 + index * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输入参数连接端点 */}
|
||||
{dataIns.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-input-handle-${index}`}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
id={dataIns[index].name || dataIns[index].id || `input-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${65 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* 输出参数连接端点 */}
|
||||
{dataOuts.map((_, index) => (
|
||||
<Handle
|
||||
key={`data-output-handle-${index}`}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id={dataOuts[index].name || dataOuts[index].id || `output-${index}`}
|
||||
style={{
|
||||
...handleStyles.data,
|
||||
top: `${65 + (apiOuts.length + index) * 20}px`
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const NodeContent = ({ data }: { data: NodeContentData }) => {
|
||||
const apiIns = data.parameters?.apiIns || [];
|
||||
const apiOuts = data.parameters?.apiOuts || [];
|
||||
const dataIns = data.parameters?.dataIns || [];
|
||||
const dataOuts = data.parameters?.dataOuts || [];
|
||||
|
||||
// 判断节点类型
|
||||
const isStartNode = data.type === 'start';
|
||||
const isEndNode = data.type === 'end';
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*content栏-api部分*/}
|
||||
<div className={styles['node-api-box']}>
|
||||
<div className={styles['node-content-api']}>
|
||||
{apiIns.length > 0 && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{apiIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.desc}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiOuts.length > 0 && (
|
||||
<div className={styles['node-outputs-api']}>
|
||||
{apiOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.desc || output.id || output.name}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(dataIns.length > 0 || dataOuts.length > 0) && (
|
||||
<>
|
||||
{/*分割*/}
|
||||
<div className={styles['node-split-line']}></div>
|
||||
|
||||
{/*content栏-data部分*/}
|
||||
<div className={styles['node-data-box']}>
|
||||
<div className={styles['node-content']}>
|
||||
{dataIns.length > 0 && !isStartNode && (
|
||||
<div className={styles['node-inputs']}>
|
||||
{dataIns.map((input, index) => (
|
||||
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
|
||||
{input.id || `输入${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dataOuts.length > 0 && !isEndNode && (
|
||||
<div className={styles['node-outputs']}>
|
||||
{dataOuts.map((output, index) => (
|
||||
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
|
||||
{output.id || `输出${index + 1}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeContent;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 应用编排处理
|
||||
* */
|
||||
|
||||
import { convertAppFlowData } from '@/utils/convertAppFlowData';
|
||||
import { convertFlowData } from '@/utils/convertFlowData';
|
||||
import { Edge } from '@xyflow/react';
|
||||
import { updateCanvasDataMap } from '@/store/ideContainer';
|
||||
|
||||
export const appFLowHandle = (initialData, useDefault, setNodes, setEdges, dispatch) => {
|
||||
const {
|
||||
nodes: convertedNodes,
|
||||
edges: convertedEdges
|
||||
} = convertAppFlowData(initialData);
|
||||
console.log('nodes:', convertedNodes);
|
||||
console.log('edges:', convertedEdges);
|
||||
|
||||
|
||||
// 为所有边添加类型
|
||||
const initialEdges: Edge[] = convertedEdges.map(edge => ({
|
||||
...edge,
|
||||
type: 'custom'
|
||||
}));
|
||||
|
||||
setNodes(convertedNodes);
|
||||
setEdges(initialEdges);
|
||||
|
||||
// if (initialData?.appId) {
|
||||
// dispatch(updateCanvasDataMap({
|
||||
// ...canvasDataMap,
|
||||
// [initialData.appId]: { nodes: convertedNodes, edges: initialEdges }
|
||||
// }));
|
||||
// }
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 组件编排处理
|
||||
* */
|
||||
// 组件编排画布数据处理(组件编排)
|
||||
import { convertFlowData } from '@/utils/convertFlowData';
|
||||
import { Edge } from '@xyflow/react';
|
||||
import { updateCanvasDataMap } from '@/store/ideContainer';
|
||||
|
||||
export const projectFlowHandle = (initialData, useDefault, setNodes, setEdges, dispatch, canvasDataMap) => {
|
||||
const {
|
||||
nodes: convertedNodes,
|
||||
edges: convertedEdges
|
||||
} = convertFlowData(initialData?.main?.components || initialData?.compData?.components, useDefault);
|
||||
|
||||
// 为所有边添加类型
|
||||
const initialEdges: Edge[] = convertedEdges.map(edge => ({
|
||||
...edge,
|
||||
type: 'custom'
|
||||
}));
|
||||
|
||||
setNodes(convertedNodes);
|
||||
setEdges(initialEdges);
|
||||
|
||||
if (initialData?.appId) {
|
||||
dispatch(updateCanvasDataMap({
|
||||
...canvasDataMap,
|
||||
[initialData.appId]: { nodes: convertedNodes, edges: initialEdges }
|
||||
}));
|
||||
}
|
||||
};
|
||||
@ -1,9 +1,38 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import FlowEditor from '@/pages/flowEditor/index';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { getAppEventList } from '@/api/appEvent';
|
||||
import { getTopicList } from '@/api/event';
|
||||
import { updateEventTopicList } from '@/store/ideContainer';
|
||||
|
||||
const ApplicationContainer = () => {
|
||||
const { info } = useSelector((state: any) => state.ideContainer);
|
||||
const [appFlowList, setAppFlowList] = useState([]);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const getAppFlowList = async () => {
|
||||
const res: any = await getAppEventList(info.id);
|
||||
if (res.code === 200) setAppFlowList(res.data);
|
||||
};
|
||||
|
||||
const getEventList = async () => {
|
||||
const res: any = await getTopicList(info.id);
|
||||
|
||||
if (res.code === 200) {
|
||||
dispatch(updateEventTopicList(res.data.map(v => {
|
||||
return { label: v.eventName, value: v.topic };
|
||||
})));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getEventList();
|
||||
getAppFlowList();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<FlowEditor useDefault={false} />
|
||||
<FlowEditor initialData={appFlowList} useDefault={false} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import FlowEditor from '@/pages/flowEditor/index';
|
||||
|
||||
const complexContainer = ({ selected }) => {
|
||||
|
||||
return (
|
||||
<FlowEditor initialData={selected.compData || {}} useDefault={true} />
|
||||
);
|
||||
};
|
||||
|
||||
export default complexContainer;
|
||||
@ -0,0 +1,104 @@
|
||||
import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType';
|
||||
import BasicNode from '@/components/FlowEditor/node/basicNode/BasicNode';
|
||||
import SwitchNode from '@/components/FlowEditor/node/switchNode/SwitchNode';
|
||||
import ImageNode from '@/components/FlowEditor/node/imageNode/ImageNode';
|
||||
import CodeNode from '@/components/FlowEditor/node/codeNode/CodeNode';
|
||||
import RestNode from '@/components/FlowEditor/node/restNode/RestNode';
|
||||
import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode';
|
||||
|
||||
// 获取handle类型 (api或data)
|
||||
const getHandleType = (handleId: string, nodeParams: any) => {
|
||||
// 检查是否为api类型的handle
|
||||
const apiOuts = nodeParams.apiOuts || [];
|
||||
const apiIns = nodeParams.apiIns || [];
|
||||
|
||||
if (apiOuts.some((api: any) => (api.name || api.id) === handleId) ||
|
||||
apiIns.some((api: any) => (api.name || api.id) === handleId) || (handleId.includes('loop'))) {
|
||||
return 'api';
|
||||
}
|
||||
|
||||
// 检查是否为data类型的handle
|
||||
const dataOuts = nodeParams.dataOuts || [];
|
||||
const dataIns = nodeParams.dataIns || [];
|
||||
|
||||
if (dataOuts.some((data: any) => (data.name || data.id) === handleId) ||
|
||||
dataIns.some((data: any) => (data.name || data.id) === handleId)) {
|
||||
return 'data';
|
||||
}
|
||||
|
||||
// 默认为data类型
|
||||
return 'data';
|
||||
};
|
||||
|
||||
// 验证数据类型是否匹配
|
||||
const validateDataType = (sourceNode: defaultNodeTypes, targetNode: defaultNodeTypes, sourceHandleId: string, targetHandleId: string) => {
|
||||
const sourceParams = sourceNode.data?.parameters || {};
|
||||
const targetParams = targetNode.data?.parameters || {};
|
||||
|
||||
// 获取源节点的输出参数
|
||||
let sourceDataType = '';
|
||||
const sourceApiOuts = sourceParams.apiOuts || [];
|
||||
const sourceDataOuts = sourceParams.dataOuts || [];
|
||||
|
||||
// 查找源handle的数据类型
|
||||
const sourceApi = sourceApiOuts.find((api: any) => api.name === sourceHandleId);
|
||||
const sourceData = sourceDataOuts.find((data: any) => data.name === sourceHandleId);
|
||||
|
||||
if (sourceApi) {
|
||||
sourceDataType = sourceApi.dataType || '';
|
||||
}
|
||||
else if (sourceData) {
|
||||
sourceDataType = sourceData.dataType || '';
|
||||
}
|
||||
|
||||
// 获取目标节点的输入参数
|
||||
let targetDataType = '';
|
||||
const targetApiIns = targetParams.apiIns || [];
|
||||
const targetDataIns = targetParams.dataIns || [];
|
||||
|
||||
// 查找目标handle的数据类型
|
||||
const targetApi = targetApiIns.find((api: any) => api.name === targetHandleId);
|
||||
const targetData = targetDataIns.find((data: any) => data.name === targetHandleId);
|
||||
|
||||
if (targetApi) {
|
||||
targetDataType = targetApi.dataType || '';
|
||||
}
|
||||
else if (targetData) {
|
||||
targetDataType = targetData.dataType || '';
|
||||
}
|
||||
|
||||
// 如果任一数据类型为空,则允许连接
|
||||
if (!sourceDataType || !targetDataType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 比较数据类型是否匹配
|
||||
return sourceDataType === targetDataType;
|
||||
};
|
||||
|
||||
|
||||
// 根据节点类型获取对应的节点组件
|
||||
const getNodeComponent = (nodeType: string) => {
|
||||
switch (nodeType) {
|
||||
case 'BASIC':
|
||||
case 'SUB':
|
||||
return BasicNode;
|
||||
case 'SWITCH':
|
||||
return SwitchNode;
|
||||
case 'IMAGE':
|
||||
return ImageNode;
|
||||
case 'CODE':
|
||||
return CodeNode;
|
||||
case 'REST':
|
||||
return RestNode;
|
||||
default:
|
||||
return LocalNode;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export {
|
||||
getHandleType,
|
||||
validateDataType,
|
||||
getNodeComponent
|
||||
};
|
||||
Loading…
Reference in New Issue