/** * Append 拼接节点组件 * 用于拼接多个字符串片段 * * 特点: * - 没有执行端口(纯数据节点) * - 左边:动态数量的输入端口(文本片段 + 变量引用) * - 右边:一个输出端口(拼接结果) * - 蓝色主题 */ import { useState, useEffect } from 'react'; import { parseEchoValue } from '../echo/echo-node.js'; import { NodeRenderer } from '../node-renderer.jsx'; import './append-node.css'; export function AppendNode(props) { const { node, connections, onPortMouseDown, onPortMouseUp } = props; const [segments, setSegments] = useState([]); console.log(`🎨 [AppendNode] 渲染 Append 节点:`, { id: node.id, x: node.x, y: node.y, value: node.data?.value }); // 解析 value 获取片段 useEffect(() => { const value = node.data?.value || ''; const parsed = parseEchoValue(value); console.log(` 📊 [AppendNode useEffect] 更新 segments:`, parsed); setSegments(parsed); }, [node.data?.value]); // 检查端口是否已连接 const isPortConnected = (portId) => { if (!connections || !Array.isArray(connections)) return false; return connections.some(conn => (conn.target === node.id && conn.targetPort === portId) || (conn.source === node.id && conn.sourcePort === portId) ); }; // 数据端口 const inputPorts = node.inputs || []; const outputPort = node.outputs?.[0]; console.log(` 🔌 [AppendNode] 端口信息 - inputPorts:`, inputPorts.length, `outputPort:`, !!outputPort); // 自定义内容渲染 const renderCustomBody = () => { console.log(` 🎨 [AppendNode renderCustomBody] 开始渲染,segments 数量: ${segments.length}, inputPorts 数量: ${inputPorts.length}`); return (
{/* 左侧:输入片段 */}
{segments.map((segment, index) => { const port = inputPorts.find(p => p.segmentIndex === index); console.log(` 🔍 渲染 segment[${index}]:`, segment, `找到的 port:`, port); if (!port) { console.log(` ⚠️ segment[${index}] 没有对应的 port,跳过渲染`); return null; } const connected = isPortConnected(port.id); const portClass = 'port-string'; // 文本片段:空心圆 + 输入框(既可输入也可连接) if (segment.type === 'text') { console.log(` ✅ 渲染 segment[${index}] (text) - 空心圆 + 输入框`); return (
{ e.stopPropagation(); onPortMouseDown?.(node.id, port.id); }} onMouseUp={(e) => { e.stopPropagation(); onPortMouseUp?.(node.id, port.id); }} title="文本输入(可连接变量)" >
e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onChange={(e) => { // TODO: 更新 value 字段 const newValue = e.target.value; // 需要重新组合整个 value }} />
); } // 变量引用:实心圆 + 标签(专门连接变量) if (segment.type === 'variable') { console.log(` ✅ 渲染 segment[${index}] (variable) - 实心圆 + 标签`); return (
{ e.stopPropagation(); onPortMouseDown?.(node.id, port.id); }} onMouseUp={(e) => { e.stopPropagation(); onPortMouseUp?.(node.id, port.id); }} title={`变量: ${segment.content}`} >
{segment.content}
); } return null; })}
{/* 右侧:输出端口 */} {outputPort && (
{ e.stopPropagation(); onPortMouseDown?.(node.id, outputPort.id); }} onMouseUp={(e) => { e.stopPropagation(); onPortMouseUp?.(node.id, outputPort.id); }} title="拼接结果" > Result
)}
); }; return ( ); }