文章目录
人事分析里有几张最基础的图:「历年入职人数」「历年离职人数」「各年入职人员现状(留存)」。它们的共同点是 x 轴要按年分组——按天出数的话,一张「历年趋势」会展开成几百个数据点,完全不可用。
但在用低代码平台的 CLI 命令批量生成原生报表时,我发现日期维度的聚合粒度被硬编码成了 DAY:配置文件里写的 YEAR 根本不被读取。这篇文章记录完整的定位过程、私有补丁的生效与蒸发事件链,以及官方支持前的临时恢复方法。
现象:配置写了 YEAR,出来全是按天分组
图表配置是合法的——这个属性命名是从平台报表页保存报文学回来的:
// charts.json —— 图表配置片段
{
"xField": {
"field": "dateField_******", // 入职日期
"timeGranularityType": "YEAR" // 明确声明按年
},
"yField": { "aggregate": "COUNT" }
}
但生成的报表在页面上 x 轴密密麻麻全是具体日期。把生成的查询模型抓出来对比:字段定义里的 timeGranularityType 一律为 'DAY'——输入侧声明的粒度值被直接丢弃了。
定位:五行赋值锁定病灶
顺着调用链翻包内源码:
1
bin/yida.js — create-report 命令入口与追加模式分支↓
2
lib/report/index.js — 读入用户图表 JSON 并构建 Schema↓
3
lib/report/chart-builder.js:28 — 转发到数据模型构建器↓
4
lib/report/data-model.js — 组装查询模型并随 Schema 上传平台 ← 病灶在这data-model.js 里通用 / combo / table / pivot / gauge 五个分支,各有一行同样的代码:
// lib/report/data-model.js — 五处硬编码(52、97、152、245、298 行)
timeGranularityType: isDateField ? 'DAY' : null
// 字段对象经由 normalizeField 的 {...field} 展开透传进来,
// 输入侧通道天然存在,只是输出侧没接 —— 换句话说,透传改造只差五行。
全包检索 timeGranularity 相关逻辑,除这两处再无其他机制——不存在「换个写法实现」的隐藏入口。也就是说能力缺口是确定性的,不是用法问题。
私有补丁:生效 → 蒸发的完整事件链
1
修改 node_modules 内 data-model.js 五处赋值为读输入值透传,未声明仍回落 DAY
↓
2
重跑 create-report 上传三张年聚合图 → 平台正常按年出图并固化在服务端
补丁有效 ✓↓
3
次日执行 npm update openyida 更新依赖(例行操作)
↓
4
官方新包覆盖安装,五处恢复硬编码——补丁蒸发
能力消失 ✗npm 日志清楚记录了覆盖过程:placeDep ROOT openyida@2026.8.26 REPLACE,旧包连同可执行软链整体退役重装。已上传的三张图不受影响(服务端存自己的模型),风险集中在新建/重新生成动作上——升级后某次原样重跑脚本,产出物粒度就悄然退化成按天,而且没有任何提示。
⚠ 这正是魔改依赖的死穴:这个能力只能靠改 node_modules 获得,而任何一次常规 npm install/update 都会把它抹掉。如果团队里只有一个人知道打过补丁,ta 离开或遗忘的那一刻就是故障发生的那一刻。宁可要一个显式的报错,也不要这种静默退化。
临时恢复方法(官方支持前自用备忘)
每次升级后重新打补丁的步骤:
# 1. 重新定位五处硬编码(版本更新后行号会漂移,不要背旧行号)
grep -n "timeGranularityType: isDateField ? 'DAY' : null" \
node_modules/openyida/lib/report/data-model.js
# 2. 全部改为读输入字段声明的粒度,缺省回落 DAY(向后兼容)
timeGranularityType: isDateField ? (f.timeGranularityType || 'DAY') : null
# 3. 自检:替换计数应为 5
grep -c "f.timeGranularityType || 'DAY' node_modules/openyida/lib/report/data-model.js
# 4. 用一张 YEAR 配置图走一次 create-report 干跑,核对生成模型字段值
改 node_modules 前先备份原文件;发布前确认线上没有设计师侧的手工改动会被一起覆盖。
给平台侧的两条建议
- 补齐粒度声明:dateField 维度支持从配置读取 YEAR / QUARTER / MONTH / WEEK / DAY 并透传落地,缺省 DAY 保持向后兼容;展示层的时间格式随粒度联动(如 YEAR → yyyy);
- 非法值宁可报错也别静默回落:CLI 在校验阶段直接报错退出,好过悄悄降级成 DAY 让用户拿到错误的图而不自知。这个组织此前已经吃过两次「success 但不生效」式静默失败的亏(详见上一篇《假成功三连》),同类教训不应在第三个地方重演。
踩坑清单(可直接复用)
- 低代码 CLI 生成的报表字段模型要抽查:别只看最终图表长什么样,字段的 query model 定义才是决定行为的层;
- 配置属性不被读取 ≠ 你写错了:先全包检索该属性的读取点,零命中即能力缺口,止损换路;
- 魔改 node_modules 必须登记台账 + 写自检命令:任何碰这份代码的人都要能在一分钟内验证补丁还在不在;
- npm update 后必须回归核心产出物:本案例中三张图的粒度退化静默发生,靠的还是回读比对;
- 服务端固化的报表一般安全:运行时不回读本地 CLI,风险集中在「新建/重新生成」动作上;
- 向平台反馈带上精确到行的源码定位:研发复现和修复的成本会大幅下降,受理速度完全不同。
✅ 最终成果:问题已连同完整证据链(配置形态、五行定位、npm 覆盖日志)提交平台侧;内部建立升级后补丁自检流程,粒度退化可在干跑阶段即被发现。
评 论