|
|
|
@ -15,86 +15,105 @@ interface NodeContentData {
|
|
|
|
[key: string]: any;
|
|
|
|
[key: string]: any;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染特殊节点(开始/结束节点)的句柄
|
|
|
|
// 定义通用的句柄样式
|
|
|
|
const renderSpecialNodeHandles = (isStartNode: boolean, isEndNode: boolean, dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
|
|
|
const handleStyles = {
|
|
|
|
return (
|
|
|
|
mainSource: {
|
|
|
|
<>
|
|
|
|
|
|
|
|
{isStartNode ?
|
|
|
|
|
|
|
|
apiOuts.map((_, index) => (
|
|
|
|
|
|
|
|
<Handle
|
|
|
|
|
|
|
|
key={`start-output-handle-${index}`}
|
|
|
|
|
|
|
|
type="source"
|
|
|
|
|
|
|
|
position={Position.Right}
|
|
|
|
|
|
|
|
id={apiOuts[index].name || `start-output-${index}`}
|
|
|
|
|
|
|
|
style={{
|
|
|
|
|
|
|
|
background: '#2290f6',
|
|
|
|
background: '#2290f6',
|
|
|
|
top: `${40 + index * 20}px`,
|
|
|
|
|
|
|
|
width: '8px',
|
|
|
|
width: '8px',
|
|
|
|
height: '8px',
|
|
|
|
height: '8px',
|
|
|
|
border: '2px solid #fff',
|
|
|
|
border: '2px solid #fff',
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
}}
|
|
|
|
},
|
|
|
|
className="node-handle"
|
|
|
|
mainTarget: {
|
|
|
|
/>
|
|
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
:
|
|
|
|
|
|
|
|
apiIns.map((_, index) => (
|
|
|
|
|
|
|
|
<Handle
|
|
|
|
|
|
|
|
key={`end-input-handle-${index}`}
|
|
|
|
|
|
|
|
type="target"
|
|
|
|
|
|
|
|
position={Position.Left}
|
|
|
|
|
|
|
|
id={apiIns[index].name || `end-input-${index}`}
|
|
|
|
|
|
|
|
style={{
|
|
|
|
|
|
|
|
background: '#2290f6',
|
|
|
|
background: '#2290f6',
|
|
|
|
top: `${40 + index * 20}px`,
|
|
|
|
|
|
|
|
width: '8px',
|
|
|
|
width: '8px',
|
|
|
|
height: '8px',
|
|
|
|
height: '8px',
|
|
|
|
border: '2px solid #fff',
|
|
|
|
border: '2px solid #fff',
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
}}
|
|
|
|
},
|
|
|
|
className="node-handle"
|
|
|
|
data: {
|
|
|
|
/>
|
|
|
|
background: '#555',
|
|
|
|
))
|
|
|
|
width: '6px',
|
|
|
|
|
|
|
|
height: '6px',
|
|
|
|
|
|
|
|
border: '1px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染特殊节点(开始/结束节点)的句柄
|
|
|
|
|
|
|
|
const renderSpecialNodeHandles = (isStartNode: boolean, isEndNode: boolean, dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => {
|
|
|
|
|
|
|
|
const renderStartNodeHandles = () => {
|
|
|
|
|
|
|
|
if (!isStartNode) return null;
|
|
|
|
|
|
|
|
|
|
|
|
{/* 为特殊节点的参数也添加句柄 */}
|
|
|
|
return (
|
|
|
|
{isStartNode && dataOuts.map((_, index) => (
|
|
|
|
<>
|
|
|
|
|
|
|
|
{apiOuts.map((_, index) => (
|
|
|
|
|
|
|
|
<Handle
|
|
|
|
|
|
|
|
key={`start-output-handle-${index}`}
|
|
|
|
|
|
|
|
type="source"
|
|
|
|
|
|
|
|
position={Position.Right}
|
|
|
|
|
|
|
|
id={apiOuts[index].name || `start-output-${index}`}
|
|
|
|
|
|
|
|
style={{
|
|
|
|
|
|
|
|
...handleStyles.mainSource,
|
|
|
|
|
|
|
|
top: `${40 + index * 20}px`
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
{dataOuts.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`output-handle-${index}`}
|
|
|
|
key={`output-handle-${index}`}
|
|
|
|
type="source"
|
|
|
|
type="source"
|
|
|
|
position={Position.Right}
|
|
|
|
position={Position.Right}
|
|
|
|
id={dataOuts[index].name || `output-${index}`}
|
|
|
|
id={dataOuts[index].name || `output-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#555',
|
|
|
|
...handleStyles.data,
|
|
|
|
top: `${60 + index * 20}px`,
|
|
|
|
top: `${60 + index * 20}px`
|
|
|
|
width: '6px',
|
|
|
|
|
|
|
|
height: '6px',
|
|
|
|
|
|
|
|
border: '1px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
|
|
|
|
</>
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
{isEndNode && dataIns.map((_, index) => (
|
|
|
|
const renderEndNodeHandles = () => {
|
|
|
|
|
|
|
|
if (!isEndNode) return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
<>
|
|
|
|
|
|
|
|
{apiIns.map((_, index) => (
|
|
|
|
|
|
|
|
<Handle
|
|
|
|
|
|
|
|
key={`end-input-handle-${index}`}
|
|
|
|
|
|
|
|
type="target"
|
|
|
|
|
|
|
|
position={Position.Left}
|
|
|
|
|
|
|
|
id={apiIns[index].name || `end-input-${index}`}
|
|
|
|
|
|
|
|
style={{
|
|
|
|
|
|
|
|
...handleStyles.mainTarget,
|
|
|
|
|
|
|
|
top: `${40 + index * 20}px`
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
{dataIns.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`input-handle-${index}`}
|
|
|
|
key={`input-handle-${index}`}
|
|
|
|
type="target"
|
|
|
|
type="target"
|
|
|
|
position={Position.Left}
|
|
|
|
position={Position.Left}
|
|
|
|
id={dataIns[index].name || `input-${index}`}
|
|
|
|
id={dataIns[index].name || `input-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#555',
|
|
|
|
...handleStyles.data,
|
|
|
|
top: `${60 + index * 20}px`,
|
|
|
|
top: `${60 + index * 20}px`
|
|
|
|
width: '6px',
|
|
|
|
|
|
|
|
height: '6px',
|
|
|
|
|
|
|
|
border: '1px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
</>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
<>
|
|
|
|
|
|
|
|
{renderStartNodeHandles()}
|
|
|
|
|
|
|
|
{renderEndNodeHandles()}
|
|
|
|
|
|
|
|
</>
|
|
|
|
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染普通节点的句柄
|
|
|
|
// 渲染普通节点的句柄
|
|
|
|
@ -103,74 +122,54 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[]
|
|
|
|
<>
|
|
|
|
<>
|
|
|
|
{apiOuts.map((_, index) => (
|
|
|
|
{apiOuts.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`output-handle-${index}`}
|
|
|
|
key={`api-output-handle-${index}`}
|
|
|
|
type="source"
|
|
|
|
type="source"
|
|
|
|
position={Position.Right}
|
|
|
|
position={Position.Right}
|
|
|
|
id={apiOuts[index].name || `output-${index}`}
|
|
|
|
id={apiOuts[index].name || `output-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#2290f6',
|
|
|
|
...handleStyles.mainSource,
|
|
|
|
top: `${40 + index * 20}px`,
|
|
|
|
top: `${40 + index * 20}px`
|
|
|
|
width: '8px',
|
|
|
|
|
|
|
|
height: '8px',
|
|
|
|
|
|
|
|
border: '2px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
{apiIns.map((_, index) => (
|
|
|
|
{apiIns.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`input-handle-${index}`}
|
|
|
|
key={`api-input-handle-${index}`}
|
|
|
|
type="target"
|
|
|
|
type="target"
|
|
|
|
position={Position.Left}
|
|
|
|
position={Position.Left}
|
|
|
|
id={apiIns[index].name || `input-${index}`}
|
|
|
|
id={apiIns[index].name || `input-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#2290f6',
|
|
|
|
...handleStyles.mainTarget,
|
|
|
|
top: `${40 + index * 20}px`,
|
|
|
|
top: `${40 + index * 20}px`
|
|
|
|
width: '8px',
|
|
|
|
|
|
|
|
height: '8px',
|
|
|
|
|
|
|
|
border: '2px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 4px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 输入参数连接端点 */}
|
|
|
|
{/* 输入参数连接端点 */}
|
|
|
|
{dataIns.map((_, index) => (
|
|
|
|
{dataIns.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`input-handle-${index}`}
|
|
|
|
key={`data-input-handle-${index}`}
|
|
|
|
type="target"
|
|
|
|
type="target"
|
|
|
|
position={Position.Left}
|
|
|
|
position={Position.Left}
|
|
|
|
id={dataIns[index].name || `input-${index}`}
|
|
|
|
id={dataIns[index].name || `input-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#555',
|
|
|
|
...handleStyles.data,
|
|
|
|
top: `${40 + (index + 1) * 20}px`,
|
|
|
|
top: `${40 + (index + 1) * 20}px`
|
|
|
|
width: '6px',
|
|
|
|
|
|
|
|
height: '6px',
|
|
|
|
|
|
|
|
border: '1px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 输出参数连接端点 */}
|
|
|
|
{/* 输出参数连接端点 */}
|
|
|
|
{dataOuts.map((_, index) => (
|
|
|
|
{dataOuts.map((_, index) => (
|
|
|
|
<Handle
|
|
|
|
<Handle
|
|
|
|
key={`output-handle-${index}`}
|
|
|
|
key={`data-output-handle-${index}`}
|
|
|
|
type="source"
|
|
|
|
type="source"
|
|
|
|
position={Position.Right}
|
|
|
|
position={Position.Right}
|
|
|
|
id={dataOuts[index].name || `output-${index}`}
|
|
|
|
id={dataOuts[index].name || `output-${index}`}
|
|
|
|
style={{
|
|
|
|
style={{
|
|
|
|
background: '#555',
|
|
|
|
...handleStyles.data,
|
|
|
|
top: `${40 + (index + 1) * 20}px`,
|
|
|
|
top: `${40 + (index + 1) * 20}px`
|
|
|
|
width: '6px',
|
|
|
|
|
|
|
|
height: '6px',
|
|
|
|
|
|
|
|
border: '1px solid #fff',
|
|
|
|
|
|
|
|
boxShadow: '0 0 2px rgba(0,0,0,0.2)'
|
|
|
|
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
className="node-handle"
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
</>
|
|
|
|
</>
|
|
|
|
@ -206,7 +205,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
|
|
|
|
{dataOuts.length > 0 && !isEndNode && (
|
|
|
|
{dataOuts.length > 0 && !isEndNode && (
|
|
|
|
<div className={styles['node-outputs']}>
|
|
|
|
<div className={styles['node-outputs']}>
|
|
|
|
{dataOuts.map((output, index) => (
|
|
|
|
{dataOuts.map((output, index) => (
|
|
|
|
<div key={`output-${index}`} style={{ fontSize: '12px', padding: '2px 0' }}>
|
|
|
|
<div key={`output-${index}`} className={styles['node-input-label']}>
|
|
|
|
{output.name || `输出${index + 1}`}
|
|
|
|
{output.name || `输出${index + 1}`}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
|