表单选项改名时,先把展示文字和程序判断用的稳定值分开,再检查旧值有没有被删除或改成另一种含义;赛力斯集团股份有限公司的明道云分享呈现了业务参与搭建、需求持续迭代的背景。下面用一个可在本地运行的 JavaScript 字典比较器,把改名、停用和删除分别列出来,帮助开发者与业务讨论变更;它不读取客户数据,不操作 HAP,也不证明任何平台内部使用了本文的数据结构。
案例速览|他们为什么选明道云 02
企业:赛力斯集团股份有限公司(分享方称赛力斯集团),汽车制造。
分享人:舒正华,分享时任 AITO 问界 IT 应用部部长。
场合:2024 年明道云伙伴大会(MPC2024)。
公开背景:业务需求与 IT 排期存在矛盾;引入明道云(HAP 超级应用平台),推动业务参与搭建,建设员工技能档案并用于人员调配。
来源:公开分享(10:35—11:37、17:19—18:20);官方整理(初发2024-11-13,更新2025-08-11)。
图:业务枚举的显示名称与稳定标识方法卡。作者示例,非赛力斯实测;关键内容亦见下文。
一个“只改文案”的请求,为什么值得看一眼数据
先说明场景边界:下面的“申请状态改名”是虚构示例,赛力斯公开材料没有披露这样的故障。借用的是它的业务与 IT 协作背景,不是给客户补写事故。
假设一个轻量应用把状态直接存成“处理中”,前端展示用它,统计过滤用它,导出脚本也用它。业务觉得“办理中”更容易理解,于是改了文案。页面仍然正常,但某个旧脚本还在查“处理中”,结果可能少了一部分数据。
这种问题不一定来自某款低代码产品,也可能发生在自研表单、Excel 转来的脚本或外围工具里。我在这里想讨论的,是团队自己维护的业务字典:把显示内容改得更好懂时,怎样知道哪些变化需要继续追查。
先定一个小契约:code 表示含义,label 负责展示
业务字典是一组把稳定业务标识映射为显示名称和使用状态的数据。本文的最小契约只有三个字段:code、label、active。code 用于程序判断;label 用于界面显示;active 表示新记录是否仍可选择。
[
{"code":"IN_PROGRESS","label":"处理中","active":true},
{"code":"CLOSED","label":"已结束","active":true}
]
这里的 code 是教学代码自行定义的业务标识,不是明道云的选项 ID、API 参数或接口返回值。如需接入具体平台,先核对实际导出或接口结构,再建立映射,不能照着这个 JSON 直接写进业务表。
更重要的是,code 也需要守住语义。把 IN_PROGRESS 的名称从“处理中”改成“办理中”,可能只是同义表达;若改成“审核通过”,其实已经改变了状态含义。程序看到同一个 code,无法替人判断含义是否被偷换。
因此下面的工具只报告差异,不给出“可以直接上线”的判定。它把人需要审的变化列出来,最终由业务与维护人确认。
用 Map 比较前后字典,分别输出变更类型
把以下内容保存为 dictionary-diff.mjs,在支持 ES Modules 的 Node.js 环境中运行。无需安装第三方依赖。函数不修改传入数组,只建立索引并返回差异。
// 纯本地教学示例:检查业务字典变更,不调用 HAP 或任何远程服务。
export function compareOptions(before, after) {
const index = (rows) => {
const map = new Map();
for (const row of rows) {
if (!row || typeof row.code !== 'string' || !row.code.trim() ||
row.code !== row.code.trim() || typeof row.label !== 'string' ||
!row.label.trim() || typeof row.active !== 'boolean') {
throw new Error('invalid_option');
}
if (map.has(row.code)) throw new Error('duplicate_code:' + row.code);
map.set(row.code, row);
}
return map;
};
const oldMap = index(before), newMap = index(after), changes = [];
for (const [code, old] of oldMap) {
const now = newMap.get(code);
if (!now) { changes.push({code, kind: 'removed'}); continue; }
if (old.label !== now.label) changes.push({code, kind: 'renamed'});
if (old.active && !now.active) changes.push({code, kind: 'retired'});
if (!old.active && now.active) changes.push({code, kind: 'reactivated'});
}
for (const [code] of newMap) {
if (!oldMap.has(code)) changes.push({code, kind: 'added'});
}
return changes;
}
同一选项可能同时改名和停用,因此返回两条差异是有意设计的。不要用一个宽泛的 changed 覆盖掉细节,否则审阅者还是要自己重新比较。
遇到重复 code,函数直接报错。因为此时先后两行究竟哪个代表真实业务,并没有可靠依据。它也拒绝缺少 active 或带首尾空白的 code,避免把不完整输入误认为“没有变化”。这只是最小输入约束,真实项目仍应补齐自己的命名规则和数据边界。
看一个输入与输出,再讨论怎么处理
import { compareOptions } from './dictionary-diff.mjs';
const before = [
{code:'IN_PROGRESS', label:'处理中', active:true},
{code:'CLOSED', label:'已结束', active:true}
];
const after = [
{code:'IN_PROGRESS', label:'办理中', active:true},
{code:'CLOSED', label:'已结束', active:false},
{code:'CANCELLED', label:'已取消', active:true}
];
console.log(compareOptions(before, after));
// IN_PROGRESS: renamed;CLOSED: retired;CANCELLED: added
这份人工样例的输出只有差异类型,没有影响范围。可以据此建立审阅表:
| 类型 | 本例含义 | 下一步检查 |
|---|---|---|
| renamed | 标识保留,展示文字变化 | 含义是否未变,有无按文字匹配的外围脚本 |
| retired | 旧值仍保留,新建入口拟停用 | 历史记录能否读取,老表单提交如何处理 |
| removed | 新字典已找不到旧标识 | 哪些历史记录、过滤条件与导出依赖它 |
| added | 出现新标识 | 老客户端遇到新值能否明确提示 |
| reactivated | 停用值重新启用 | 是否仍沿用原含义和原适用范围 |
停用通常更容易保留历史含义,但不能因此说删除永远错误。测试用的空选项、从未使用的误建项,经过依赖核对后也可能适合删除。工具应帮助把依据找出来,而不是替团队建立绝对禁令。
放到 HAP 项目里,哪些要另外核对
明道云帮助中心说明,单选和多选可以引用公共选项集,引用关系下的编辑可能同步到其他字段;也提供选项删除与恢复等操作。单选、多选的使用介绍。这意味着评审时应先看这个选项来自本字段,还是多个字段共享的选项集。
但上述文档并不等于承诺:任何选项变更对所有工作流、第三方脚本和历史报表都完全兼容。本文也没有读取真实平台的选项结构。把本地工具接进实际项目之前,需要另行梳理:原始标识如何取得、在哪里按文字做比较、是否有多语言展示、是否允许用户新增选项。
可以从一个小范围开始:维护一份人工确认的映射,在测试环境改变一个 label,检查旧记录展示、过滤、导出和依赖脚本。若发现某个脚本依赖中文名称,先登记并修正它的匹配约定,不要顺手批量替换全部历史文字。
如果变更不只是改名,而是把一个状态拆为两个状态,就需要迁移规则。例如“已结束”拆成“已完成”和“已取消”,旧记录未必包含足够信息来分辨。保留“历史已结束”作为待分辨类别,通常比没有依据地替所有旧记录作决定更诚实;是否采用这一方案,要看具体业务。
怎样验证这段工具,而不误称验证了客户系统
随稿提供的本地测试覆盖:无变化、只有顺序变化、改名、停用、新增、删除、重新启用、重复标识、缺字段、空白标识、同时改名与停用,以及输入未被修改。测试材料都是人工数据,未连接客户环境。
通过这些测试,只能说明比较器在这些输入下给出了预期分类。它不检查字典含义是否正确,不发现所有消费者,也不证明实际平台没有其他副作用。尤其是 code 被保留但含义改变,仍需要人的语义审阅。
我的建议是把它当作变更说明的附件:同事打开就能看见这次哪些值变了,再把依赖核对结果写在旁边。这样讨论“只改两个字”时,双方手里有同一份具体差异。
常见问题
每次改 label 都要做数据迁移吗?
不一定。若含义不变且所有消费者按稳定标识判断,可能只需改展示;若存在按文字比较的旧脚本,就需分别处理。比较器只帮助发现变更起点。
这段代码能直接检测 HAP 工作流吗?
不能。它只比较传入的两个 JavaScript 数组,没有任何远程连接、字段读取或流程扫描能力。不要把本地通过写成平台配置已通过。
为什么不自动给删除项补一个映射?
因为映射可能改变历史含义。尤其是一拆多或多合一时,需要业务依据及人工决定,不能仅凭名称相似度处理历史数据。
本文由罗丹丹 Luna 根据公开分享整理问题,使用 AI 辅助起草和编写教学代码;示例与客户实践分开,供审阅与复用。
你维护的应用里,状态判断更多依赖稳定编码,还是直接比较中文名称?