浏览代码

修复了set模块拖拽问题

yichael 4 月之前
父节点
当前提交
59838fe6a1

+ 65 - 56
src/pages/blueprint/blueprint-core.js

@@ -48,21 +48,21 @@ export function useBlueprint(workflowName = null) {
    */
   const loadWorkflow = useCallback(async (folderName) => {
     try {
-      console.log('loadWorkflow 被调用,folderName:', folderName);
+      // console.log('loadWorkflow 被调用,folderName:', folderName);
       if (!folderName) {
-        console.log('folderName 为空,返回');
+        // console.log('folderName 为空,返回');
         return;
       }
       
       if (!window.electronAPI || !window.electronAPI.readProcessingJson) {
-        console.log('electronAPI 不可用,返回');
+        // console.log('electronAPI 不可用,返回');
         return;
       }
       
       const processingData = await window.electronAPI.readProcessingJson(folderName);
-      console.log('读取到的 processingData:', processingData);
+      // console.log('读取到的 processingData:', processingData);
       if (!processingData) {
-        console.log('processingData 为空,返回');
+        // console.log('processingData 为空,返回');
         return;
       }
       
@@ -77,7 +77,7 @@ export function useBlueprint(workflowName = null) {
       
       // 转换为蓝图节点图
       const blueprint = workflowToBlueprint(processingData);
-      console.log('转换后的 blueprint:', blueprint);
+      // console.log('转换后的 blueprint:', blueprint);
       
       // 分析需要创建哪些变量节点(Get/Set)
       const variables = processingData.variables || {};
@@ -89,6 +89,7 @@ export function useBlueprint(workflowName = null) {
       // 创建变量节点(根据引用类型创建 Get 或 Set 节点)
       // 使用固定的 ID 格式,确保每次加载时 ID 一致
       const variableNodes = [];
+      let varNodeX = 150;  // 变量节点的初始 X 坐标,确保在可见区域
       let yOffset = 200;
       varNames.forEach((varName) => {
         const varValue = variables[varName];
@@ -98,7 +99,7 @@ export function useBlueprint(workflowName = null) {
         if (refs.asInput) {
           // 使用固定的 ID 格式:var_get_变量名
           const fixedId = `var_get_${varName}`;
-          const getNode = createVariableNode(varName, varValue, 50, yOffset, 'get', fixedId);
+          const getNode = createVariableNode(varName, varValue, varNodeX, yOffset, 'get', fixedId);
           variableNodes.push(getNode);
           yOffset += 80;
         }
@@ -107,7 +108,7 @@ export function useBlueprint(workflowName = null) {
         if (refs.asOutput) {
           // 使用固定的 ID 格式:var_set_变量名
           const fixedId = `var_set_${varName}`;
-          const setNode = createVariableNode(varName, varValue, 50, yOffset, 'set', fixedId);
+          const setNode = createVariableNode(varName, varValue, varNodeX, yOffset, 'set', fixedId);
           variableNodes.push(setNode);
           yOffset += 80;
         }
@@ -115,12 +116,11 @@ export function useBlueprint(workflowName = null) {
         // 如果变量没有被引用,默认创建一个 Get 节点
         if (!refs.asInput && !refs.asOutput) {
           const fixedId = `var_get_${varName}`;
-          const getNode = createVariableNode(varName, varValue, 50, yOffset, 'get', fixedId);
+          const getNode = createVariableNode(varName, varValue, varNodeX, yOffset, 'get', fixedId);
           variableNodes.push(getNode);
           yOffset += 80;
         }
       });
-      console.log('创建的变量节点数量:', variableNodes.length);
       
       // 根据 inVars 中的变量引用创建从变量节点到流程节点的连接
       const variableConnResult = createVariableConnections(blueprint.nodes, variableNodes, processingData, blueprint.connections || []);
@@ -140,9 +140,9 @@ export function useBlueprint(workflowName = null) {
         modifiedConnectionIds = variableConnResult.modifiedConnections || [];
       }
       
-      console.log('创建的变量数据连接数量:', variableDataConnections.length);
-      console.log('创建的变量执行连接数量:', variableExecConnections.length);
-      console.log('需要修改的执行连接数量:', modifiedConnectionIds.length);
+      // console.log('创建的变量数据连接数量:', variableDataConnections.length);
+      // console.log('创建的变量执行连接数量:', variableExecConnections.length);
+      // console.log('需要修改的执行连接数量:', modifiedConnectionIds.length);
       
       // 删除需要修改的旧连接(这些连接将被新的连接替代)
       let finalConnections = (blueprint.connections || []).filter(conn => !modifiedConnectionIds.includes(conn.id));
@@ -150,8 +150,8 @@ export function useBlueprint(workflowName = null) {
       // 合并所有新的变量连接(数据连接 + 执行连接)
       blueprint.connections = [...finalConnections, ...variableDataConnections, ...variableExecConnections];
       
-      console.log('blueprint.nodes 是否存在:', !!blueprint.nodes);
-      console.log('blueprint.nodes 长度:', blueprint.nodes?.length);
+      // console.log('blueprint.nodes 是否存在:', !!blueprint.nodes);
+      // console.log('blueprint.nodes 长度:', blueprint.nodes?.length);
       
       // 加载位置信息和连线信息
       let nodePositions = null;
@@ -159,40 +159,49 @@ export function useBlueprint(workflowName = null) {
       if (window.electronAPI && window.electronAPI.readBlueprintJson) {
         try {
           const bpData = await window.electronAPI.readBlueprintJson(folderName);
-          console.log('读取到的 bpData:', bpData);
+          // console.log('读取到的 bpData:', bpData);
           if (bpData && bpData.nodePositions) {
             nodePositions = bpData.nodePositions;
-            console.log('nodePositions:', nodePositions);
+            // console.log('nodePositions:', nodePositions);
           }
           if (bpData && bpData.connections) {
             savedConnections = bpData.connections;
-            console.log('savedConnections:', savedConnections);
+            // console.log('savedConnections:', savedConnections);
           }
         } catch (error) {
-          console.log('读取位置信息失败:', error);
+          // console.log('读取位置信息失败:', error);
           // 读取位置信息失败,忽略错误
         }
       }
       
-      console.log('检查 blueprint.nodes:', blueprint.nodes && blueprint.nodes.length > 0);
+      // console.log('检查 blueprint.nodes:', blueprint.nodes && blueprint.nodes.length > 0);
       if (blueprint.nodes && blueprint.nodes.length > 0) {
-        console.log('进入节点设置分支');
+        // console.log('进入节点设置分支');
         // 合并流程节点和变量节点
         let finalNodes = [...blueprint.nodes, ...variableNodes];
         let needsLayout = false;
         
         if (nodePositions) {
-          console.log('nodePositions 中的节点ID:', Object.keys(nodePositions));
-          console.log('finalNodes 中的节点ID:', finalNodes.map(n => n.id));
+          // console.log('nodePositions 中的节点ID:', Object.keys(nodePositions));
+          // console.log('finalNodes 中的节点ID:', finalNodes.map(n => n.id));
           // 应用保存的位置信息(包括变量节点)
           finalNodes = finalNodes.map(node => {
             const savedPos = nodePositions[node.id];
             if (savedPos && typeof savedPos.x === 'number' && typeof savedPos.y === 'number') {
-              return {
-                ...node,
-                x: savedPos.x,
-                y: savedPos.y
-              };
+              // 检查保存的坐标是否合理(X 坐标至少为 100,避免节点在屏幕外)
+              const isValidPosition = savedPos.x >= 100;
+              
+              if (isValidPosition) {
+                // 使用保存的坐标
+                return {
+                  ...node,
+                  x: savedPos.x,
+                  y: savedPos.y
+                };
+              } else {
+                // 保存的坐标不合理,保持节点创建时的默认坐标
+                return node;
+              }
             }
             return node;
           });
@@ -203,7 +212,7 @@ export function useBlueprint(workflowName = null) {
             return savedPos && typeof savedPos.x === 'number' && typeof savedPos.y === 'number';
           });
           
-          console.log('有位置信息的节点数量:', nodesWithPosition.length, '/', finalNodes.length);
+          // console.log('有位置信息的节点数量:', nodesWithPosition.length, '/', finalNodes.length);
           
           // 如果有节点没有位置信息,需要自动布局
           if (nodesWithPosition.length < finalNodes.length) {
@@ -235,15 +244,15 @@ export function useBlueprint(workflowName = null) {
         }
         
         // 调试:检查节点数据
-        console.log('加载的节点数量:', finalNodes.length);
+        // console.log('加载的节点数量:', finalNodes.length);
         if (finalNodes.length > 0) {
-          console.log('第一个节点:', finalNodes[0]);
-          console.log('节点坐标范围:', {
-            minX: Math.min(...finalNodes.map(n => n.x || 0)),
-            maxX: Math.max(...finalNodes.map(n => n.x || 0)),
-            minY: Math.min(...finalNodes.map(n => n.y || 0)),
-            maxY: Math.max(...finalNodes.map(n => n.y || 0))
-          });
+          // console.log('第一个节点:', finalNodes[0]);
+          // console.log('节点坐标范围:', {
+          //   minX: Math.min(...finalNodes.map(n => n.x || 0)),
+          //   maxX: Math.max(...finalNodes.map(n => n.x || 0)),
+          //   minY: Math.min(...finalNodes.map(n => n.y || 0)),
+          //   maxY: Math.max(...finalNodes.map(n => n.y || 0))
+          // });
         }
         
         setNodes(finalNodes);
@@ -251,10 +260,10 @@ export function useBlueprint(workflowName = null) {
         // 优先使用保存的连线信息,否则使用从工作流解析的连线
         let connectionsToUse = [];
         if (savedConnections && savedConnections.length > 0) {
-          console.log('使用保存的连线信息,数量:', savedConnections.length);
+          // console.log('使用保存的连线信息,数量:', savedConnections.length);
           connectionsToUse = savedConnections;
         } else {
-          console.log('使用解析的连线信息,数量:', blueprint.connections?.length || 0);
+          // console.log('使用解析的连线信息,数量:', blueprint.connections?.length || 0);
           connectionsToUse = blueprint.connections || [];
         }
         
@@ -264,7 +273,7 @@ export function useBlueprint(workflowName = null) {
           if (targetNode && targetNode.type === 'variable' && targetNode.varMode === 'set') {
             // 如果目标是 SET 节点,并且使用的是旧端口 ID
             if (conn.targetPort === 'input_0') {
-              console.log('迁移 SET 节点连接端口 ID:', conn.id, 'input_0 -> input_value');
+              // console.log('迁移 SET 节点连接端口 ID:', conn.id, 'input_0 -> input_value');
               return {
                 ...conn,
                 targetPort: 'input_value'
@@ -277,8 +286,8 @@ export function useBlueprint(workflowName = null) {
         setConnections(connectionsToUse);
         setIsDirty(false); // 加载完成后,标记为未修改
       } else {
-        console.log('blueprint.nodes 为空或长度为 0,设置空数组');
-        console.log('blueprint:', blueprint);
+        // console.log('blueprint.nodes 为空或长度为 0,设置空数组');
+        // console.log('blueprint:', blueprint);
         setNodes([]);
         setConnections([]);
       }
@@ -304,30 +313,30 @@ export function useBlueprint(workflowName = null) {
    * 保存工作流
    */
   const saveWorkflow = useCallback(async (folderName) => {
-    console.log('saveWorkflow 被调用,folderName:', folderName);
+    // console.log('saveWorkflow 被调用,folderName:', folderName);
     if (!folderName) {
       console.error('saveWorkflow: folderName 为空');
       return { success: false, error: '工作流名称为空' };
     }
     
     try {
-      console.log('saveWorkflow: 开始转换蓝图到工作流,nodes:', nodes.length, 'connections:', connections.length);
+      // console.log('saveWorkflow: 开始转换蓝图到工作流,nodes:', nodes.length, 'connections:', connections.length);
       const workflow = blueprintToWorkflow({ nodes, connections });
-      console.log('saveWorkflow: 转换完成,workflow:', workflow);
+      // console.log('saveWorkflow: 转换完成,workflow:', workflow);
       const fullWorkflow = {
         ...workflow,
         variables: variables || {}
       };
-      console.log('saveWorkflow: fullWorkflow:', fullWorkflow);
+      // console.log('saveWorkflow: fullWorkflow:', fullWorkflow);
       
       if (!window.electronAPI || !window.electronAPI.saveProcessingJson) {
         console.error('saveWorkflow: electronAPI 或 saveProcessingJson 不可用');
         return { success: false, error: '保存 API 不可用' };
       }
       
-      console.log('saveWorkflow: 调用 electronAPI.saveProcessingJson');
+      // console.log('saveWorkflow: 调用 electronAPI.saveProcessingJson');
       const result = await window.electronAPI.saveProcessingJson(folderName, fullWorkflow);
-      console.log('saveWorkflow: 保存结果:', result);
+      // console.log('saveWorkflow: 保存结果:', result);
       
       // 同时保存节点位置和连线信息到 bp.json
       // 注意:连线坐标需要从 DOM 获取,这里只保存连线的基本信息
@@ -357,12 +366,12 @@ export function useBlueprint(workflowName = null) {
             targetY: conn.targetY
           }));
           
-          console.log('saveWorkflow: 保存节点位置和连线到 bp.json,节点数量:', nodes.length, '连线数量:', connections.length);
+          // console.log('saveWorkflow: 保存节点位置和连线到 bp.json,节点数量:', nodes.length, '连线数量:', connections.length);
           await window.electronAPI.saveBlueprintJson(folderName, { 
             nodePositions,
             connections: connectionData
           });
-          console.log('saveWorkflow: 节点位置和连线保存成功');
+          // console.log('saveWorkflow: 节点位置和连线保存成功');
         } catch (bpError) {
           console.error('saveWorkflow: 保存节点位置失败:', bpError);
           // 节点位置保存失败不影响主流程
@@ -372,7 +381,7 @@ export function useBlueprint(workflowName = null) {
       // 保存成功后,标记为未修改
       if (result && result.success !== false) {
         setIsDirty(false);
-        console.log('saveWorkflow: 保存成功,isDirty 设为 false');
+        // console.log('saveWorkflow: 保存成功,isDirty 设为 false');
       }
       
       return result;
@@ -780,14 +789,14 @@ export function useBlueprint(workflowName = null) {
       const processNodes = nodes.filter(n => n.type !== 'variable');
       const varNodes = nodes.filter(n => n.type === 'variable');
       
-      console.log('开始手动整理布局,流程节点数量:', processNodes.length, '变量节点数量:', varNodes.length);
+      // console.log('开始手动整理布局,流程节点数量:', processNodes.length, '变量节点数量:', varNodes.length);
       
       // 使用进度回调
       const layoutedProcessNodes = autoLayoutBlueprint(
         processNodes, 
         connections,
         (progress, message) => {
-          console.log(`布局进度: ${progress}% - ${message}`);
+          // console.log(`布局进度: ${progress}% - ${message}`);
           setLayoutProgress(progress * 0.8); // 0-80% 用于布局
           setLayoutMessage(message);
         }
@@ -805,8 +814,8 @@ export function useBlueprint(workflowName = null) {
         if (node.x < minX) minX = node.x;
       });
       
-      // Get 变量节点放在左下方
-      let varX = minX;
+      // Get 变量节点放在左下方(确保 X 坐标至少为 100)
+      let varX = Math.max(minX, 100);
       let varY = maxY + 200;
       const layoutedGetVarNodes = getVarNodes.map((node, index) => {
         const newNode = { ...node, x: varX, y: varY };
@@ -833,7 +842,7 @@ export function useBlueprint(workflowName = null) {
       
       const finalNodes = [...layoutedProcessNodes, ...layoutedGetVarNodes, ...layoutedSetVarNodes];
       
-      console.log('整理布局完成,节点数量:', finalNodes.length);
+      // console.log('整理布局完成,节点数量:', finalNodes.length);
       
       setLayoutProgress(90);
       setLayoutMessage('正在保存位置信息...');

+ 5 - 5
src/pages/blueprint/blueprint.js

@@ -109,9 +109,9 @@ export function useBlueprintLogic(propWorkflowName) {
         if ((e.ctrlKey || e.metaKey) && e.key === 's') {
           e.preventDefault();
           if (workflowName) {
-            console.log('Ctrl+S 触发保存(输入框内),workflowName:', workflowName);
+            // console.log('Ctrl+S 触发保存(输入框内),workflowName:', workflowName);
             saveWorkflow(workflowName).then(result => {
-              console.log('保存结果:', result);
+              // console.log('保存结果:', result);
             }).catch(err => {
               console.error('保存出错:', err);
             });
@@ -124,11 +124,11 @@ export function useBlueprintLogic(propWorkflowName) {
       if ((e.ctrlKey || e.metaKey) && e.key === 's') {
         e.preventDefault();
         if (workflowName) {
-          console.log('Ctrl+S 触发保存,workflowName:', workflowName);
+          // console.log('Ctrl+S 触发保存,workflowName:', workflowName);
           saveWorkflow(workflowName).then(result => {
-            console.log('保存结果:', result);
+            // console.log('保存结果:', result);
             if (result && result.success !== false) {
-              console.log('保存成功');
+              // console.log('保存成功');
             } else {
               console.error('保存失败:', result?.error);
             }

+ 21 - 18
src/pages/blueprint/canvas/blueprint-canvas.jsx

@@ -4,7 +4,7 @@
 
 import { useEffect, useRef } from 'react';
 import './canvas.css';
-import { NodeRenderer } from '../node-renderer/node-renderer.jsx';
+import { getNodeComponent } from '../node-renderer/index.js';
 import { useCanvasLogic, useCanvasEventHandlers, createEventHandlers, getConnectionClass, calculateGridStyle, handleVariableDrop, handleVariableDragOver } from './canvas.js';
 import { createBezierPath } from '../utils/connection-manager.js';
 
@@ -58,7 +58,7 @@ export function BlueprintCanvas({
         lastConnectionIdsRef.current = currentConnectionIds;
         const coords = getAllConnectionCoords(connections);
         if (coords.length > 0) {
-          console.log('更新连线坐标,数量:', coords.length);
+          // console.log('更新连线坐标,数量:', coords.length);
           onUpdateConnectionCoords(coords);
         }
       }
@@ -150,9 +150,9 @@ export function BlueprintCanvas({
                 endX: parseFloat(pathMatch[7]),
                 endY: parseFloat(pathMatch[8])
               } : null;
-              console.log(`连线${index}渲染成功:`, connection.id, '从', connection.source, connection.sourcePort, '到', connection.target, connection.targetPort);
-              console.log(`  坐标:`, coords ? `(${coords.startX}, ${coords.startY}) -> (${coords.endX}, ${coords.endY})` : '无法解析');
-              console.log(`  路径:`, pathInfo.path);
+              // console.log(`连线${index}渲染成功:`, connection.id, '从', connection.source, connection.sourcePort, '到', connection.target, connection.targetPort);
+              // console.log(`  坐标:`, coords ? `(${coords.startX}, ${coords.startY}) -> (${coords.endX}, ${coords.endY})` : '无法解析');
+              // console.log(`  路径:`, pathInfo.path);
             }
             
             // 根据端口类型确定连线样式类
@@ -186,19 +186,22 @@ export function BlueprintCanvas({
         </svg>
         
         {/* 渲染节点 */}
-        {nodes.map(node => (
-          <NodeRenderer
-            key={node.id}
-            node={node}
-            isSelected={selectedNodeIds.includes(node.id)}
-            connections={connections}
-            onPortMouseDown={handlePortMouseDown}
-            onPortMouseUp={handlePortMouseUp}
-            onNodeMouseDown={handleNodeMouseDown}
-            onNodeDoubleClick={onNodeDoubleClick}
-            onPortValueChange={onPortValueChange}
-          />
-        ))}
+        {nodes.map(node => {
+          const NodeComponent = getNodeComponent(node);
+          return NodeComponent ? (
+            <NodeComponent
+              key={node.id}
+              node={node}
+              isSelected={selectedNodeIds.includes(node.id)}
+              connections={connections}
+              onPortMouseDown={handlePortMouseDown}
+              onPortMouseUp={handlePortMouseUp}
+              onNodeMouseDown={handleNodeMouseDown}
+              onNodeDoubleClick={onNodeDoubleClick}
+              onPortValueChange={onPortValueChange}
+            />
+          ) : null;
+        })}
       </div>
     </div>
   );

+ 20 - 3
src/pages/blueprint/canvas/canvas.js

@@ -27,6 +27,15 @@ export function useCanvasLogic(connections, externalControllerRef, nodes = []) {
   const [connectingStart, setConnectingStart] = useState(null);
   const [connectingEnd, setConnectingEnd] = useState(null);
   
+  // 监控 transform 变化(检测背景是否被拖动)
+  // useEffect(() => {
+  //   console.log('🔴 Canvas transform 变化:', {
+  //     translateX: transform.translateX.toFixed(1),
+  //     translateY: transform.translateY.toFixed(1),
+  //     scale: transform.scale.toFixed(2)
+  //   });
+  // }, [transform.translateX, transform.translateY, transform.scale]);
+  
   // 使用节点拖拽管理 hook(集中管理拖拽逻辑)
   const {
     draggedNodeId,
@@ -394,6 +403,14 @@ export function useCanvasLogic(connections, externalControllerRef, nodes = []) {
    */
   const handleMouseMove = (e, onNodeMove) => {
     const rect = canvasRef.current.getBoundingClientRect();
+
+    // console.log('🟢 canvas handleMouseMove 触发:', {
+    //   '是否正在拖动节点': !!getDraggedNodeId(),
+    //   '拖动的节点ID': getDraggedNodeId(),
+    //   '是否正在连线': !!connectingStart,
+    //   '鼠标位置 (clientX, clientY)': `(${e.clientX}, ${e.clientY})`,
+    //   '画布变换': `(translateX: ${transform.translateX.toFixed(1)}, translateY: ${transform.translateY.toFixed(1)})`
+    // });
     
     // 如果正在连线,更新连线预览的终点位置
     if (connectingStart) {
@@ -509,9 +526,9 @@ export function useCanvasLogic(connections, externalControllerRef, nodes = []) {
     // 调试:记录端口索引信息(前3个连线)
     const connectionIndex = connections?.indexOf?.(connection) ?? -1;
     if (connectionIndex >= 0 && connectionIndex < 3) {
-      console.log(`端口索引计算[${connectionIndex}]:`, connection.id);
-      console.log(`  源节点:`, connection.source, `端口:`, connection.sourcePort, `索引:`, sourcePortIndex, `(共${sourceNode.outputs?.length || 0}个输出端口)`);
-      console.log(`  目标节点:`, connection.target, `端口:`, connection.targetPort, `索引:`, targetPortIndex, `(共${targetNode.inputs?.length || 0}个输入端口)`);
+      // console.log(`端口索引计算[${connectionIndex}]:`, connection.id);
+      // console.log(`  源节点:`, connection.source, `端口:`, connection.sourcePort, `索引:`, sourcePortIndex, `(共${sourceNode.outputs?.length || 0}个输出端口)`);
+      // console.log(`  目标节点:`, connection.target, `端口:`, connection.targetPort, `索引:`, targetPortIndex, `(共${targetNode.inputs?.length || 0}个输入端口)`);
     }
     
     // 使用缓存方案获取端口坐标(优先从 DOM 获取,带有节点偏移量计算)

+ 1 - 1
src/pages/blueprint/node-renderer/get/get-node.css

@@ -37,7 +37,7 @@
   text-align: center;
   padding: 0 16px;
   white-space: nowrap;
-  visibility: hidden; /* 占位但不可见 */
+  visibility: visible; /* 可见 */
 }
 
 .Blueprint-get-node .Blueprint-variable-node-body {

+ 1 - 1
src/pages/blueprint/node-renderer/get/get-node.js

@@ -6,7 +6,7 @@
  * 配置:是否显示暗色区域(节点主体背景)
  * @type {boolean}
  */
-export const SHOW_DARK_AREA = false;
+export const SHOW_DARK_AREA = true;
 
 /**
  * 创建 Get 节点数据

+ 7 - 0
src/pages/blueprint/node-renderer/index.js

@@ -3,6 +3,13 @@
  * 提供所有节点类型的组件和工具函数
  */
 
+// 导入各类节点组件(用于 getNodeComponent 函数)
+import { BeginNode } from './begin/begin-node.jsx';
+import { SetNode } from './set/set-node.jsx';
+import { GetNode } from './get/get-node.jsx';
+import { FuncNode } from './func/func-node.jsx';
+import { EchoNode } from './echo/echo-node.jsx';
+
 // 导出基础节点渲染器
 export { NodeRenderer } from './node-renderer.jsx';
 

+ 8 - 1
src/pages/blueprint/node-renderer/node-renderer.js

@@ -132,7 +132,14 @@ export function handleNodeDragMove(e, canvasRect, transform, getDraggedNodeId, g
   const containerY = e.clientY - canvasRect.top;
   const canvasX = (containerX - transform.translateX) / transform.scale - dragOffset.x;
   const canvasY = (containerY - transform.translateY) / transform.scale - dragOffset.y;
-  
+
+  // console.log('🔵 节点拖动:', {
+  //   节点ID: draggedNodeId,
+  //   '新坐标 (canvasX, canvasY)': `(${canvasX.toFixed(1)}, ${canvasY.toFixed(1)})`,
+  //   '鼠标位置 (clientX, clientY)': `(${e.clientX}, ${e.clientY})`,
+  //   '画布变换 (translateX, translateY, scale)': `(${transform.translateX.toFixed(1)}, ${transform.translateY.toFixed(1)}, ${transform.scale.toFixed(2)})`
+  // });
+
   onNodeMove?.(draggedNodeId, canvasX, canvasY);
 }
 

+ 45 - 1
src/pages/blueprint/node-renderer/node-renderer.jsx

@@ -8,6 +8,7 @@
  * - 节点的差异主要体现在:端口数量(通过node.inputs/outputs定义)、节点尺寸(通过CSS控制)、样式主题(通过className控制)
  */
 
+import { useEffect, useRef } from 'react';
 import './node-renderer.css';
 import { 
   getNodeStyle, 
@@ -35,6 +36,7 @@ import {
  * @param {boolean} props.showHeader - 是否显示标题(GET节点不显示)
  * @param {Function} props.renderCustomBody - 自定义主体渲染(可选,用于特殊节点如Begin)
  * @param {string} props.layoutType - 布局类型:'standard'(标准), 'variable'(GET变量), 'set-variable'(SET变量)
+ * @param {boolean} props.debugSizeInfo - 是否打印DOM尺寸调试信息
  */
 export function NodeRenderer({ 
   node, 
@@ -49,7 +51,8 @@ export function NodeRenderer({
   headerText,
   showHeader = true,
   renderCustomBody,
-  layoutType = 'standard'
+  layoutType = 'standard',
+  debugSizeInfo = false
 }) {
   if (!node) return null;
   
@@ -59,6 +62,46 @@ export function NodeRenderer({
   const nodeClassName = getNodeClassName(isSelected, node);
   const finalClassName = className ? `${nodeClassName} ${className}` : nodeClassName;
   
+  // 用于获取实际 DOM 元素的尺寸
+  const nodeRef = useRef(null);
+  
+  // 打印 DOM 尺寸调试信息(只在初始化时打印一次)
+  useEffect(() => {
+    if (debugSizeInfo && nodeRef.current) {
+      const rect = nodeRef.current.getBoundingClientRect();
+      const computedStyle = window.getComputedStyle(nodeRef.current);
+      
+      console.log('🔍 SET 节点 DOM 尺寸信息(初始化):', {
+        节点ID: node?.id,
+        节点类型: node?.type,
+        变量名: node?.varName,
+        varMode: node?.varMode,
+        className: nodeRef.current.className,
+        '=== 尺寸信息 ===': '',
+        '实际渲染宽度 (offsetWidth)': nodeRef.current.offsetWidth + 'px',
+        '实际渲染高度 (offsetHeight)': nodeRef.current.offsetHeight + 'px',
+        '可视宽度 (clientWidth)': nodeRef.current.clientWidth + 'px',
+        '可视高度 (clientHeight)': nodeRef.current.clientHeight + 'px',
+        'getBoundingClientRect宽度': rect.width + 'px',
+        'getBoundingClientRect高度': rect.height + 'px',
+        '屏幕位置 (left, top)': `(${rect.left}, ${rect.top})`,
+        '=== CSS 样式 ===': '',
+        'CSS width': computedStyle.width,
+        'CSS height': computedStyle.height,
+        'CSS display': computedStyle.display,
+        'CSS position': computedStyle.position,
+        '=== 轮廓样式(检查红色虚线)===': '',
+        'CSS outline': computedStyle.outline,
+        'CSS outlineWidth': computedStyle.outlineWidth,
+        'CSS outlineStyle': computedStyle.outlineStyle,
+        'CSS outlineColor': computedStyle.outlineColor,
+        'CSS outlineOffset': computedStyle.outlineOffset,
+        '=== 边框样式 ===': '',
+        'CSS border': computedStyle.border
+      });
+    }
+  }, [debugSizeInfo, node?.id, node?.varMode]);
+  
   // 分离端口类型(通过node.inputs/outputs获取端口数量和类型)
   const executionInputs = node.inputs?.filter(p => p.type === 'execution') || [];
   const executionOutputs = node.outputs?.filter(p => p.type === 'execution') || [];
@@ -67,6 +110,7 @@ export function NodeRenderer({
   
   return (
     <div
+      ref={nodeRef}
       className={finalClassName}
       style={nodeStyle}
       data-node-id={node.id}

+ 10 - 10
src/pages/blueprint/utils/auto-layout.js

@@ -24,9 +24,9 @@ const START_Y = 100;
  */
 export function autoLayoutBlueprint(nodes, connections, onProgress = null) {
   try {
-    console.log('autoLayoutBlueprint 开始,节点数量:', nodes?.length);
+    // console.log('autoLayoutBlueprint 开始,节点数量:', nodes?.length);
     if (!nodes || nodes.length === 0) {
-      console.log('节点为空,直接返回');
+      // console.log('节点为空,直接返回');
       return nodes;
     }
 
@@ -37,32 +37,32 @@ export function autoLayoutBlueprint(nodes, connections, onProgress = null) {
     };
 
     reportProgress(20, '正在分析节点结构...');
-    console.log('步骤1: 构建执行连接图');
+    // console.log('步骤1: 构建执行连接图');
 
     // 构建执行连接图(只考虑执行端口连接)
     const executionGraph = buildExecutionGraph(nodes, connections);
-    console.log('执行连接图:', executionGraph);
+    // console.log('执行连接图:', executionGraph);
     
     reportProgress(40, '正在计算节点层级...');
-    console.log('步骤2: 计算节点层级');
+    // console.log('步骤2: 计算节点层级');
     
     // 计算节点层级(简化版BFS)
     const levels = calculateNodeLevelsFast(nodes, executionGraph);
-    console.log('节点层级:', levels);
+    // console.log('节点层级:', levels);
     
     reportProgress(60, '正在计算节点位置...');
-    console.log('步骤3: 计算节点位置');
+    // console.log('步骤3: 计算节点位置');
     
     // 计算每层节点的位置(优化版,减少交叉)
     const positions = calculateNodePositionsFast(nodes, levels, executionGraph);
-    console.log('节点位置:', positions);
+    // console.log('节点位置:', positions);
     
     reportProgress(80, '正在优化布局避免重叠...');
-    console.log('步骤4: 应用位置');
+    // console.log('步骤4: 应用位置');
     
     // 应用位置并快速解决重叠
     const finalNodes = applyPositionsFast(nodes, positions, connections);
-    console.log('步骤5: 布局完成,返回节点数量:', finalNodes.length);
+    // console.log('步骤5: 布局完成,返回节点数量:', finalNodes.length);
     
     reportProgress(100, '布局完成');
     

+ 9 - 2
src/pages/blueprint/utils/canvas-controller.js

@@ -35,8 +35,15 @@ export function initCanvasController(canvasElement, onTransformChange) {
   
   // 平移开始
   function handleMouseDown(e) {
-    // 检查是否点击的是节点或端口(包括流程节点和变量节点)
-    const isClickingNode = e.target.closest('.Blueprint-node') || e.target.closest('.Blueprint-variable-node');
+    // 检查是否点击的是节点或端口(包括流程节点和所有类型的变量节点)
+    const isClickingNode = e.target.closest('.Blueprint-node') || 
+                           e.target.closest('.Blueprint-variable-node') ||
+                           e.target.closest('.Blueprint-variable-set-node') ||
+                           e.target.closest('.Blueprint-begin-node') ||
+                           e.target.closest('.Blueprint-set-node') ||
+                           e.target.closest('.Blueprint-get-node') ||
+                           e.target.closest('.Blueprint-echo-node') ||
+                           e.target.closest('.Blueprint-func-node');
     const isClickingPort = e.target.closest('.Blueprint-node-port');
     
     // 检查是否点击在 canvas-area 内(包括红色边框区域)

+ 15 - 15
src/pages/blueprint/utils/workflow-converter.js

@@ -10,9 +10,9 @@ import { getNodePortsFromType } from './node-operations.js';
  * @returns {Object} 蓝图节点图数据 {nodes: [], connections: []}
  */
 export function workflowToBlueprint(workflow) {
-  console.log('workflowToBlueprint 被调用,workflow:', workflow);
+  // console.log('workflowToBlueprint 被调用,workflow:', workflow);
   if (!workflow) {
-    console.log('workflow 为空,返回空数组');
+    // console.log('workflow 为空,返回空数组');
     return { nodes: [], connections: [] };
   }
   
@@ -20,17 +20,17 @@ export function workflowToBlueprint(workflow) {
   let executeArray = null;
   if (workflow.execute && Array.isArray(workflow.execute)) {
     executeArray = workflow.execute;
-    console.log('使用 workflow.execute,长度:', executeArray.length);
+    // console.log('使用 workflow.execute,长度:', executeArray.length);
   } else if (workflow.actions && Array.isArray(workflow.actions)) {
     executeArray = workflow.actions;
-    console.log('使用 workflow.actions,长度:', executeArray.length);
+    // console.log('使用 workflow.actions,长度:', executeArray.length);
   } else if (Array.isArray(workflow)) {
     executeArray = workflow;
-    console.log('workflow 是数组,长度:', executeArray.length);
+    // console.log('workflow 是数组,长度:', executeArray.length);
   }
   
   if (!executeArray || executeArray.length === 0) {
-    console.log('executeArray 为空或长度为 0,返回空数组');
+    // console.log('executeArray 为空或长度为 0,返回空数组');
     return { nodes: [], connections: [] };
   }
 
@@ -149,7 +149,7 @@ export function workflowToBlueprint(workflow) {
   }
   
   parseActions(executeArray, x, y);
-  console.log('parseActions 完成,节点数量:', nodes.length, '连线数量:', connections.length);
+  // console.log('parseActions 完成,节点数量:', nodes.length, '连线数量:', connections.length);
   
   // 检查是否有 Begin 节点,如果没有则创建一个并连接到第一个节点
   const hasBeginNode = nodes.some(node => node.type === 'begin');
@@ -181,7 +181,7 @@ export function workflowToBlueprint(workflow) {
     }
   }
   
-  console.log('workflowToBlueprint 返回,节点数量:', nodes.length, '连线数量:', connections.length);
+  // console.log('workflowToBlueprint 返回,节点数量:', nodes.length, '连线数量:', connections.length);
   return { nodes, connections };
 }
 
@@ -358,13 +358,13 @@ export function createVariableConnections(processNodes, variableNodes, workflow,
             return; // 在 forEach 中使用 return 跳过当前迭代
           }
           
-          console.log('创建 SET 节点数据连接:', {
-            source: processNode.id,
-            sourcePort: outputPort.id,
-            target: setNode.id,
-            targetPort: varInputPort.id,
-            varName
-          });
+          // console.log('创建 SET 节点数据连接:', {
+          //   source: processNode.id,
+          //   sourcePort: outputPort.id,
+          //   target: setNode.id,
+          //   targetPort: varInputPort.id,
+          //   varName
+          // });
           
           dataConnections.push({
             id: `conn_var_out_${processNode.id}_${outputPort.id}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,

+ 7 - 7
static/processing/测试/bp.json

@@ -1,20 +1,20 @@
 {
 	"nodePositions": {
 		"node_begin": {
-			"x": -120,
-			"y": 180
+			"x": -40,
+			"y": 100
 		},
 		"node_0": {
-			"x": 200,
-			"y": 180
+			"x": 220,
+			"y": 200
 		},
 		"var_get_mini": {
-			"x": -80,
+			"x": 40,
 			"y": 360
 		},
 		"var_set_swipeDirection": {
-			"x": 620,
-			"y": 260
+			"x": 660,
+			"y": 200
 		}
 	}
 }