复核方式:云机 Chromium 真渲染(~/render-env/browse.js --desktop)+ 物理 grep + 色值 L* 实算。
被查文件:/home/dev2/reports/shared/org-insights-redesign-v5.html(属主 dev3,我无写权限,未改动;补丁在 /tmp/v5-fixed.html 供对照)。
浏览器控制台报 1 条错,render() 在第三步就抛异常中断:
TypeError: Cannot set properties of null (setting 'innerHTML')
at renderRank (org-insights-redesign-v5.html:1891)
at renderOverview (:1955)
at render (:1958)
根因(带对照组自证):
grep -c 'id="rankList"' org-insights-redesign-v5.html → 0 # v5 删了「活跃排行榜」的 DOM
grep -c 'id="rankList"' org-insights-redesign-v4.html → 1 # 对照组:v4 里有,证明查法有效
grep -c 'id="heatmap"' org-insights-redesign-v5.html → 1 # 对照组:同样查法能查到别的 id
v5 删掉了排行榜的 HTML,但 renderOverview() 里的 renderRank() 调用没删。
render() 的执行顺序是 renderOverview() → renderTriage() → renderTodayBar() → 机构列表,
所以异常一抛,后面三步全部不执行。
实测后果(打补丁前后对比,数字是 innerHTML 字符数):
| 区块 | 现在线上 | 加一行 guard 后 |
|---|---|---|
| 今天先做这 N 家 | 0(空白) | 1119 |
| 四个分诊格 | 0(空白) | 2211 |
| 分层机构列表 | 0(空白) | 26716 |
也就是说,现在打开这张图,看得见的只有页头、筛选条和「全局视图」里的 KPI + 热力图。
整个方案最核心的「今天先联系谁 + 为什么 + 该说什么」一个字都没显示。
修法(一行):
function renderRank(){
if(!document.getElementById('rankList')) return; // ← 补这一行
var days = ...
实算 CIE L*(越大越浅):
| 档 | 色值 | L* | 与上一档差 |
|---|---|---|---|
| 0 没用 | #f1f5f9 |
96.3 | — |
| l1 | #d1fae5 |
95.0 | ΔL*=1.4 ⚠️ |
| l2 | #6ee7b7 |
83.9 | 11.1 |
| l3 | #34d399 |
75.8 | 8.1 |
| l4 | #10b981 |
66.8 | 9.0 |
| l5 | #047857 |
44.4 | 22.4 |
饱和度 S:0.16 → 0.52 → 0.75 → 0.91 → 0.97。中高三档 S ≥ 0.75。
格子实测 24.25 × 24.25 px(GitHub 贡献图是 10~11px)。
300 个 24px 的高饱和色块铺满一屏 = 大面积色域冲击,这就是「晃眼」的直接来源。
热力图的信息载体是图案形态,格子越小越容易看出形态;格子放大到 24px,它就变成马赛克墙了。
| 出现位置 | 绿色代表 |
|---|---|
| 热力格深浅 | 当天用量多少 |
| 机构名前的状态点 | 状态 = 正常 |
| 排行榜/归因分段条 | 来源 = 席位登录 |
| 使用频率分布 | 档位 = 高频 |
同一颜色四种语义,读者建立不起稳定映射,只能每看一处重新查图例。
renderHeatmap() 按 30 天总次数降序:最健康的赵阳眼科(1185 次)排第一,
最该救的亮点眼光(断崖,图上肉眼可见断续空白)排第四。
页面自己的主张是「今天先联系谁」,热力图却把最不用管的排在最上面。
CFG.heatMax 还是可调的0=#ffffff+1px 边框 / 低 #d1fae5(L*95) / 中 #34d399(L*76) / 高 #047857(L*44)。不画 30×N 网格,每家只画一条横条,只编码两件事:
最后一次使用是几天前(条长)+ 本周 vs 上周用量变化(右侧数字 + 箭头)。
明视眼科 ████████░░░░░░░░░░░░ 停用 8 天 42 → 0 次 ↓100%
亮点眼光 ███░░░░░░░░░░░░░░░░░ 停用 3 天 58 → 41 次 ↓29%
赵阳眼科 █░░░░░░░░░░░░░░░░░░░ 昨天还在用 276 → 291 次 ↑5%
只有一种颜色 + 灰,物理上不可能眼花。
理由:这一页要回答的是「谁快跑了」,读者要的是停了多久、掉了多少,
不是「第 17 天用了 3 次」。方案说明第九节自己也写了「热力图是看形态的工具,
人要盯几秒才读得出意思」—— 那它就不该在总览里承担 10 家 × 30 天的扫描任务。
每家一条 30 天迷你折线(sparkSvg() 函数页面里现成的,KPI 卡已经在用)。
趋势方向比色块深浅好读一个量级,断崖表现为「掉到 0 的一段平线」,比「变灰」直观得多。
全图单色(灰蓝),只有断崖那一段标红。
总览用 B,热力图降级成「点开某一家时才展开」的证据视图,并按 A 的规格重做。
总览要的是排序 + 一个数字,热力图放在钻取层才用得其所。
顺带:行内迷你热力条实测每格 4.16px,那个尺寸下 30 格就是一条虚线,读不出任何信息,
建议在行内也换成 B 的停用时长条。
renderTodayBar() 的 pick 逻辑只按 bucket==='urgent' 筛 + 按掉量排,两个都没排除:
o.handled:标了「已处理」的机构,明天打开还在第一位。fu[].next 字段只在展开区渲染(line 1712–1716),grep -n "\.next" 全文只有那一处,完全不参与筛选排序。实证:明视眼科的数据是 fu:[{when:'08-02', next:'08-20'}],页面数据截至 08-18
—— 已经跟院长约好 8/20 再确认,今天却被排在「今天先做这 2 家」的第 1 位。
做客成的人每天打开看到同样两家,「帮你做减法」这个卖点就废了。
建议:pick 加两个排除条件(已处理 / 今天早于约定日),并在卡片上直接显示
「上次联系 08-02 · 约好 08-20 再确认」——这条信息现在藏在展开区里。
5 个桶、8 个状态、排序维度有 5 个(紧急/掉量/到期/次数/转化率),没有一个是金额。
两家同样断崖,一家年费 30 万一家 3 千,现在按「掉得最狠」排会把小客户排前面。
数据里有 quoted 字段,但只用于展示,没进排序。
(顺带:明视眼科 quoted:0,但它的 evts 里写着「07-28 成单 2.1 万」—— 示意数据自相矛盾。)
「1185 次」是多是少?6 席位的机构用 176 次和 30 席位的机构用 176 次是两回事。
建议至少给一个每席位日均,或同规模机构的中位数。
有「记跟进」「标记已处理」,但没有「这条跟进后来救回来没有」。
没有闭环,这个页面无法自证有用 —— 三个月后没人能回答「用了它续费率提高没有」。
页头有 7/30/90 切换,但热力图写死 30 天。续费判断需要看「上个合同周期 vs 这个周期」,
30 天窗口对年费客户太短。
.triage{grid-template-columns:repeat(4,1fr)},实测 #triage 有 5 个子元素,
computed 列宽 275px ×4 → 第五个「正常」单独掉到第二行,右边空 3 格。
改 repeat(5,1fr),或把「正常」并进右侧做成小字统计。
云机截图里 💡 该做什么、✎ 记跟进、📊 全局视图、🔍 搜索 都是 ▯。
⚙ ✓ 正常。原因是这几个字符在 emoji 平面,云机没装 Noto Color Emoji。
Mac/Windows 上大概率正常显示,所以这条优先级低;但既然规范里已经写了禁 emoji,
建议统一换成 SVG 图标或纯文字,免得截图交付时再出问题。
# 真渲染 + 抓控制台错误 + 量尺寸
cd ~/render-env && node browse.js "file:///home/dev2/reports/shared/org-insights-redesign-v5.html" \
--desktop --script /tmp/hm-steps.js
# 色阶 L* 实算
python3 -c "..." # 见本文第二节表格
# 缺失 DOM 对照组
grep -c 'id="rankList"' org-insights-redesign-v5.html # 0
grep -c 'id="rankList"' org-insights-redesign-v4.html # 1(对照组)
未做:没有在 test 环境跑、没有连真数据 —— 本文全部结论基于这张静态原型图本身。