Prechádzať zdrojové kódy

fix: 统一节点交互样式

- 移除 text 的 pointer-events: none,文字可点击
- 统一 hover 样式:形状 brightness(1.2),文字 primary 色
- 统一 selected 样式:与 hover 一致
- 新增 match-node 基础样式和 hover/selected 样式
- 相关图中心节点改用 .selected 类
- 同层边分数标签位置调整到曲线中点

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

Co-Authored-By: Claude <noreply@anthropic.com>
yangxiaohui 1 deň pred
rodič
commit
ed9cf9d515

+ 1 - 1
script/visualization/src/App.vue

@@ -124,7 +124,7 @@ import { edgeTypeColors } from './config/edgeStyle'
 const store = useGraphStore()
 
 // 当前激活的 Tab
-const activeTab = ref('persona')
+const activeTab = ref('match')
 
 // 切换 Tab 时清除选中状态,避免干扰
 function switchTab(tab) {

+ 5 - 13
script/visualization/src/components/GraphView.vue

@@ -29,8 +29,7 @@
       <!-- 步数设置 -->
       <div class="flex items-center gap-2">
         <span class="text-base-content/60 w-16">游走步数:</span>
-        <input type="range" :min="1" :max="5" v-model.number="store.walkSteps" class="range range-xs range-primary flex-1" />
-        <span class="w-6 text-center">{{ store.walkSteps }}</span>
+        <input type="number" :min="1" :max="5" v-model.number="store.walkSteps" class="input input-xs input-bordered w-16 text-center" />
       </div>
 
       <!-- 分步设置 -->
@@ -51,8 +50,7 @@
           </div>
           <div class="flex items-center gap-2">
             <span class="text-base-content/60 w-14">最小分:</span>
-            <input type="range" :min="0" :max="1" :step="0.1" v-model.number="store.stepConfigs[step-1].minScore" class="range range-xs flex-1" />
-            <span class="w-8 text-center">{{ store.stepConfigs[step-1].minScore.toFixed(1) }}</span>
+            <input type="number" :min="0" :max="1" :step="0.1" v-model.number="store.stepConfigs[step-1].minScore" class="input input-xs input-bordered w-16 text-center" />
           </div>
         </div>
       </div>
@@ -62,13 +60,11 @@
     <div v-show="showConfig && isPostWalk" class="px-4 py-2 bg-base-200 border-b border-base-300 text-xs space-y-2">
       <div class="flex items-center gap-2">
         <span class="text-base-content/60 w-20">最大步数:</span>
-        <input type="range" :min="2" :max="6" v-model.number="store.postWalkConfig.maxSteps" class="range range-xs flex-1" />
-        <span class="w-6 text-center">{{ store.postWalkConfig.maxSteps }}</span>
+        <input type="number" :min="2" :max="6" v-model.number="store.postWalkConfig.maxSteps" class="input input-xs input-bordered w-16 text-center" />
       </div>
       <div class="flex items-center gap-2">
         <span class="text-base-content/60 w-20">最后步分数:</span>
-        <input type="range" :min="0" :max="1" :step="0.1" v-model.number="store.postWalkConfig.lastStepMinScore" class="range range-xs flex-1" />
-        <span class="w-8 text-center">{{ store.postWalkConfig.lastStepMinScore.toFixed(1) }}</span>
+        <input type="number" :min="0" :max="1" :step="0.1" v-model.number="store.postWalkConfig.lastStepMinScore" class="input input-xs input-bordered w-16 text-center" />
       </div>
       <div class="flex items-center gap-2 text-base-content/50">
         <span>路径: 帖子标签</span>
@@ -264,7 +260,7 @@ function renderGraph() {
     .selectAll('g')
     .data(nodes)
     .join('g')
-    .attr('class', d => `graph-node ${d.isCenter ? 'center' : ''}`)
+    .attr('class', d => `graph-node ${d.isCenter ? 'selected' : ''}`)
     .call(d3.drag()
       .on('start', (e, d) => {
         if (!e.active) simulation.alphaTarget(0.3).restart()
@@ -298,14 +294,10 @@ function renderGraph() {
         .attr('height', style.size)
         .attr('rx', 3)
         .attr('fill', style.color)
-        .attr('stroke', d.isCenter ? '#fff' : 'none')
-        .attr('stroke-width', d.isCenter ? 2 : 0)
     } else {
       el.append('circle')
         .attr('r', style.size/2)
         .attr('fill', style.color)
-        .attr('stroke', d.isCenter ? '#fff' : 'none')
-        .attr('stroke-width', d.isCenter ? 2 : 0)
     }
   })
 

+ 2 - 2
script/visualization/src/components/PostTreeView.vue

@@ -626,8 +626,8 @@ function renderWalkedLayer() {
     .attr('class', 'walked-score')
     .attr('transform', d => {
       const midX = (d.srcX + d.tgtX) / 2
-      // 同一层的边,分数标签放在曲线最低点
-      const midY = Math.abs(d.srcY - d.tgtY) < 10 ? d.srcY + 50 : (d.srcY + d.tgtY) / 2
+      // 同一层的边用向下弯曲曲线,分数标签放在曲线中点(t=0.5 时 y = srcY + 25)
+      const midY = Math.abs(d.srcY - d.tgtY) < 10 ? d.srcY + 25 : (d.srcY + d.tgtY) / 2
       return `translate(${midX}, ${midY})`
     })
 

+ 52 - 12
script/visualization/src/style.css

@@ -41,10 +41,51 @@
     filter: brightness(1.2);
   }
 
+  .tree-node:hover text {
+    fill: oklch(var(--p));
+  }
+
+  /* 匹配节点 */
+  .match-node {
+    cursor: pointer;
+  }
+
+  .match-node circle,
+  .match-node rect {
+    transition: all 0.2s;
+  }
+
+  .match-node:hover circle,
+  .match-node:hover rect {
+    filter: brightness(1.2);
+  }
+
+  .match-node:hover text {
+    fill: oklch(var(--p));
+  }
+
+  .match-node text {
+    @apply text-xs;
+    fill: oklch(var(--bc));
+  }
+
+  /* ========== 统一的选中样式(和 hover 一样) ========== */
   .tree-node.selected circle,
-  .tree-node.selected rect {
-    stroke: #fff;
-    stroke-width: 3;
+  .tree-node.selected rect,
+  .match-node.selected circle,
+  .match-node.selected rect,
+  .walked-node.selected circle,
+  .walked-node.selected rect,
+  .graph-node.selected circle,
+  .graph-node.selected rect {
+    filter: brightness(1.2);
+  }
+
+  .tree-node.selected text,
+  .match-node.selected text,
+  .walked-node.selected text,
+  .graph-node.selected text {
+    fill: oklch(var(--p));
   }
 
   .tree-node.highlighted circle,
@@ -101,16 +142,18 @@
     filter: brightness(1.2);
   }
 
+  .walked-node:hover text {
+    fill: oklch(var(--p));
+  }
+
   .walked-node text {
     @apply text-xs;
     fill: oklch(var(--bc));
-    pointer-events: none;
   }
 
   .tree-node text {
     @apply text-xs;
     fill: oklch(var(--bc));
-    pointer-events: none;
   }
 
   /* 树边 */
@@ -139,21 +182,18 @@
     transition: all 0.2s;
   }
 
-  .graph-node.center circle,
-  .graph-node.center rect {
-    stroke: #fff;
-    stroke-width: 3;
-  }
-
   .graph-node:hover circle,
   .graph-node:hover rect {
     filter: brightness(1.2);
   }
 
+  .graph-node:hover text {
+    fill: oklch(var(--p));
+  }
+
   .graph-node text {
     @apply text-xs;
     fill: oklch(var(--bc));
-    pointer-events: none;
   }
 
   /* 图边 */