浏览代码

feat(品类再分享分析): 添加hover提示,显示点击UV

- 列头显示再分享品类总UV
- 行头显示头部品类总UV
- 单元格显示品类组合和UV

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
yangxiaohui 2 月之前
父节点
当前提交
ec0dec9cbc
共有 1 个文件被更改,包括 18 次插入5 次删除
  1. 18 5
      tasks/品类再分享分析/visualize.py

+ 18 - 5
tasks/品类再分享分析/visualize.py

@@ -324,24 +324,37 @@ html_content = f"""<!DOCTYPE html>
         const rows = currentRowOrder.filter(r => data.rows.includes(r));
         const cols = currentColOrder.filter(c => data.cols.includes(c));
 
-        // 生成表头(可点击排序)
+        // 计算行/列的UV总和(用于tooltip)
+        const uvData = data.uv;
+        const rowUvTotals = {{}};
+        const colUvTotals = {{}};
+        rows.forEach(r => {{
+            rowUvTotals[r] = cols.reduce((sum, c) => sum + (uvData[r]?.[c] || 0), 0);
+        }});
+        cols.forEach(c => {{
+            colUvTotals[c] = rows.reduce((sum, r) => sum + (uvData[r]?.[c] || 0), 0);
+        }});
+
+        // 生成表头(可点击排序,带tooltip)
         const metricLabels = {{ uv: '点击UV', ror: '整体裂变率', orig: '头部裂变率', rec: '推荐裂变率' }};
         document.getElementById('matrix-header').innerHTML = `
             <tr>
                 <th style="cursor:pointer;font-size:10px;line-height:1.3" onclick="sortByRowSum()">头部品类(行) ↕<br>再分享品类(列)→</th>
-                ${{cols.map(c => `<th style="cursor:pointer" onclick="sortByCol('${{c}}')">${{c}}</th>`).join('')}}
+                ${{cols.map(c => `<th style="cursor:pointer" onclick="sortByCol('${{c}}')" title="再分享品类: ${{c}}&#10;点击UV: ${{colUvTotals[c].toLocaleString()}}">${{c}}</th>`).join('')}}
             </tr>
         `;
 
-        // 生成数据行(行头可点击排序)
+        // 生成数据行(行头可点击排序,带tooltip
         document.getElementById('matrix-body').innerHTML = rows.map(r => {{
             const cells = cols.map(c => {{
                 const val = metricData[r]?.[c] || 0;
+                const cellUv = uvData[r]?.[c] || 0;
                 const bg = getGradient(val, maxVal);
                 const display = metric === 'uv' ? parseInt(val).toLocaleString() : val.toFixed(4);
-                return `<td style="background:${{bg}}">${{display}}</td>`;
+                const tipMetric = metric === 'uv' ? '' : `${{metricLabels[metric]}}: ${{val.toFixed(4)}}&#10;`;
+                return `<td style="background:${{bg}}" title="头部: ${{r}}&#10;再分享: ${{c}}&#10;${{tipMetric}}点击UV: ${{cellUv.toLocaleString()}}">${{display}}</td>`;
             }}).join('');
-            return `<tr><td style="cursor:pointer;background:#f5f5f5" onclick="sortByRow('${{r}}')">${{r}}</td>${{cells}}</tr>`;
+            return `<tr><td style="cursor:pointer;background:#f5f5f5" onclick="sortByRow('${{r}}')" title="头部品类: ${{r}}&#10;点击UV: ${{rowUvTotals[r].toLocaleString()}}">${{r}}</td>${{cells}}</tr>`;
         }}).join('');
     }}