卡片样式存成模板,下次复用很方便。可卡片一旦带上设备、时间和联动,复制就可能把原页面的依赖一起带走。新页面长得没问题,查询的却仍是原来的设备。
最近做模板和参数相关功能,我把“复制”拆成了不同意图:沿用外观、复制图表后换数据、整页连同导航一起复用。它们不能都由一个不透明的 JSON 拷贝完成。
模板里哪些值可以变化
设备看板往往有稳定的页面结构,设备、时间和组织则会变。把这些值留在每个组件内部,复制后仍要逐项修改。参数应表达目标设备、统计区间这样的业务输入,组件引用参数,而不要求使用者知道某个值在文档的第几层。
参数也不能无限增加。几十项必填会把理解内部结构的工作重新交给用户。常见变化需要明确输入,其他项保留默认值与说明;结构检查之外,设备类型、指标单位和组件兼容性仍由业务校验决定。
复制依赖时不能边建节点边猜引用
筛选器 filter-a 驱动图表 chart-a。复制图表改了标识,联动却没改,就还在读原筛选器。处理本地引用时,我采用两遍重建:给所有节点分配新标识,再按完整映射重写关系。
def instantiate(template, allocate):
ids = {node["id"]: allocate() for node in template["nodes"]}
nodes = [{**node, "id": ids[node["id"]]} for node in template["nodes"]]
edges = []
for edge in template["edges"]:
source, target = edge["from"], edge["to"]
if source not in ids or target not in ids:
raise ValueError("unresolved local dependency")
edges.append({**edge, "from": ids[source], "to": ids[target]})
return {"nodes": nodes, "edges": edges}这段函数只处理本地节点。外部数据源、指标和页面跳转单独作为外部绑定,在目标环境解析。对象标识还带资源类型,不能因为名称相同就认为是同一个依赖。
只复制图表、没有复制其导航器时,引用不会凭空有效。可以把导航输入改为模板参数,让用户绑定;无法确定正确来源,就停止导入并指出缺失项。保留旧标识继续运行,会让错误数据长期藏在正常外观下面。
创建失败不留下半份可用页面
实例化按结构、参数、引用存在、访问权限、指标与组件兼容性检查。全部通过,才创建可见实例,并记录采用的模板版本。大文件可放在暂存区,通过后发布引用。
缺字段、找不到对象、无权访问和业务不兼容应有不同错误。用户要知道是补参数、重新绑定,还是换组件。统一一个“导入失败”,通常只会让他再试一次同样的操作。
快照与持续关联是两种更新约定
快照复制后不跟模板自动变化,容易理解,但批量修复要逐个做。持续关联可以集中升级,却需要保留模板原版本与本地差异。
关联更新采用旧模板、本地实例、新模板做三方比较:仅模板变化、本地没改的字段可以更新;两边都改过,列为冲突。不能把新模板整份覆盖回去,抹掉用户已经换好的数据和布局。
第一版若只支持快照,就在界面明确说明,不以“模板”这个名字暗示自动同步。保存、导入和更新使用同一份依赖定义,用户才有办法知道这次复用带走了什么,以及下一次变更会影响哪里。