Browse Source

Separate tree directory and canvas data in simplified view

- Tree directory uses full data (752 nodes)
  - Shows complete Round/Step structure
  - Displays all query node instances across rounds

- Canvas uses simplified data (399 nodes)
  - Query nodes merged by text
  - Post nodes merged by note_id
  - Round/Step nodes hidden

- Add tree-to-canvas node mapping
  - Map full node IDs (q_川西_r0_0) to simplified IDs (query_川西)
  - Enable clicking tree nodes to jump to canvas nodes
  - Handle query nodes, post nodes, and non-existent nodes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
yangxiaohui 4 tuần trước cách đây
mục cha
commit
ffda97bc18
1 tập tin đã thay đổi với 77 bổ sung13 xóa
  1. 77 13
      visualization/sug_v6_1_2_8/index.js

+ 77 - 13
visualization/sug_v6_1_2_8/index.js

@@ -1091,13 +1091,26 @@ function transformData(data) {
 }
 
 function FlowContent() {
+  // 画布使用简化数据
   const { nodes: initialNodes, edges: initialEdges } = useMemo(() => {
-    console.log('🔍 Transforming data...');
+    console.log('🔍 Transforming data for canvas...');
     const result = transformData(data);
-    console.log('✅ Transformed:', result.nodes.length, 'nodes,', result.edges.length, 'edges');
+    console.log('✅ Canvas data:', result.nodes.length, 'nodes,', result.edges.length, 'edges');
     return result;
   }, []);
 
+  // 目录使用完整数据(如果存在)
+  const { nodes: fullNodes, edges: fullEdges } = useMemo(() => {
+    if (data.fullData) {
+      console.log('🔍 Transforming full data for tree directory...');
+      const result = transformData(data.fullData);
+      console.log('✅ Directory data:', result.nodes.length, 'nodes,', result.edges.length, 'edges');
+      return result;
+    }
+    // 如果没有 fullData,使用简化数据
+    return { nodes: initialNodes, edges: initialEdges };
+  }, [initialNodes, initialEdges]);
+
   // 初始化:找出所有有子节点的节点,默认折叠(画布节点)
   const initialCollapsedNodes = useMemo(() => {
     const nodesWithChildren = new Set();
@@ -1328,9 +1341,11 @@ function FlowContent() {
   }, [initialNodes, initialEdges, collapsedNodes, hiddenNodes, focusMode, focusedNodeId, getDescendants, toggleNodeCollapse, selectedNodeId]);
 
   // 构建树形结构 - 允许一个节点有多个父节点
+  // 为目录构建树(使用完整数据)
   const buildTree = useCallback(() => {
+    // 使用完整数据构建目录树
     const nodeMap = new Map();
-    initialNodes.forEach(node => {
+    fullNodes.forEach(node => {
       nodeMap.set(node.id, node);
     });
 
@@ -1350,7 +1365,7 @@ function FlowContent() {
     const parentToChildren = new Map();
     const childToParents = new Map();
 
-    initialEdges.forEach(edge => {
+    fullEdges.forEach(edge => {
       // 记录父->子关系(去重:同一个父节点到同一个子节点只记录一次)
       if (!parentToChildren.has(edge.source)) {
         parentToChildren.set(edge.source, []);
@@ -1393,12 +1408,12 @@ function FlowContent() {
 
     // 找出所有根节点(没有入边的节点)
     const hasParent = new Set();
-    initialEdges.forEach(edge => {
+    fullEdges.forEach(edge => {
       hasParent.add(edge.target);
     });
 
     const roots = [];
-    initialNodes.forEach((node, index) => {
+    fullNodes.forEach((node, index) => {
       if (!hasParent.has(node.id)) {
         const treeNode = buildSubtree(node.id, 'root-' + node.id + '-' + index, new Set());
         if (treeNode) roots.push(treeNode);
@@ -1406,11 +1421,11 @@ function FlowContent() {
     });
 
     return roots;
-  }, [initialNodes, initialEdges]);
+  }, [fullNodes, fullEdges]);
 
   const treeRoots = useMemo(() => buildTree(), [buildTree]);
 
-  // 生成树形文本结构
+  // 生成树形文本结构(使用完整数据)
   const generateTreeText = useCallback(() => {
     const lines = [];
 
@@ -1418,7 +1433,7 @@ function FlowContent() {
     const traverse = (nodes, prefix = '', isLast = true, depth = 0) => {
       nodes.forEach((node, index) => {
         const isLastNode = index === nodes.length - 1;
-        const nodeData = initialNodes.find(n => n.id === node.id)?.data || {};
+        const nodeData = fullNodes.find(n => n.id === node.id)?.data || {};
         const nodeType = nodeData.nodeType || node.data?.nodeType || 'unknown';
         const title = nodeData.title || node.data?.title || node.id;
 
@@ -1457,7 +1472,7 @@ function FlowContent() {
     };
 
     // 添加标题
-    const rootNode = initialNodes.find(n => n.data?.level === 0);
+    const rootNode = fullNodes.find(n => n.data?.level === 0);
     if (rootNode) {
       lines.push(\`📊 查询扩展树形结构\`);
       lines.push(\`原始问题: \${rootNode.data.title || rootNode.data.query}\`);
@@ -1467,7 +1482,7 @@ function FlowContent() {
     traverse(treeRoots);
 
     return lines.join('\\n');
-  }, [treeRoots, initialNodes]);
+  }, [treeRoots, fullNodes]);
 
   // 复制树形结构到剪贴板
   const copyTreeToClipboard = useCallback(async () => {
@@ -1501,6 +1516,44 @@ function FlowContent() {
     setCollapsedTreeNodes(getAllTreeKeys(treeRoots));
   }, [treeRoots]);
 
+  // 映射完整节点ID到画布简化节点ID
+  const mapTreeNodeToCanvasNode = useCallback((treeNodeId) => {
+    // 如果是简化模式,需要映射
+    if (data.fullData) {
+      // 从完整数据中找到节点
+      const fullNode = fullNodes.find(n => n.id === treeNodeId);
+      if (!fullNode) return treeNodeId;
+
+      // 根据节点类型和文本找到画布上的简化节点
+      const nodeText = fullNode.data.title || fullNode.data.query;
+      const nodeType = fullNode.data.nodeType || fullNode.type;
+
+      // Query类节点:找 query_xxx
+      if (['q', 'seg', 'sug', 'add_word', 'query'].includes(nodeType)) {
+        const canvasNode = initialNodes.find(n =>
+          (n.data.title === nodeText || n.data.query === nodeText) &&
+          ['query'].includes(n.type)
+        );
+        return canvasNode ? canvasNode.id : treeNodeId;
+      }
+
+      // Post节点:按note_id查找
+      if (nodeType === 'post' || nodeType === 'note') {
+        const noteId = fullNode.data.note_id;
+        if (noteId) {
+          const canvasNode = initialNodes.find(n => n.data.note_id === noteId);
+          return canvasNode ? canvasNode.id : treeNodeId;
+        }
+      }
+
+      // 其他节点类型(Round/Step等):直接返回
+      return treeNodeId;
+    }
+
+    // 非简化模式,直接返回
+    return treeNodeId;
+  }, [data.fullData, fullNodes, initialNodes]);
+
   const renderTree = useCallback((treeNodes, level = 0) => {
     return treeNodes.map(node => {
       // 使用 treeKey 来区分树中的不同实例
@@ -1526,7 +1579,18 @@ function FlowContent() {
             });
           }}
           onSelect={() => {
-            const nodeId = node.id;
+            // 将目录节点ID映射到画布节点ID
+            const treeNodeId = node.id;
+            const canvasNodeId = mapTreeNodeToCanvasNode(treeNodeId);
+
+            // 检查画布上是否存在这个节点
+            const canvasNodeExists = initialNodes.some(n => n.id === canvasNodeId);
+            if (!canvasNodeExists) {
+              console.warn(\`节点 \${canvasNodeId} 在画布上不存在(可能被简化了)\`);
+              return;
+            }
+
+            const nodeId = canvasNodeId;
 
             // 展开所有祖先节点
             const ancestorIds = [nodeId];
@@ -1582,7 +1646,7 @@ function FlowContent() {
         </TreeNode>
       );
     });
-  }, [collapsedTreeNodes, selectedNodeId, nodes, setCenter, initialEdges, setCollapsedNodes, fitView]);
+  }, [collapsedTreeNodes, selectedNodeId, nodes, setCenter, initialEdges, setCollapsedNodes, fitView, mapTreeNodeToCanvasNode, initialNodes, setHiddenNodes]);
 
   console.log('📊 Rendering with', nodes.length, 'visible nodes and', edges.length, 'visible edges');