Skip to content

approvals: 审批请求行不暴露节点的 lockRecord,客户端只能假定「有 pending 就是锁死」 #3814

Description

@baozhoutao

现象

审批节点声明 lockRecord(默认 true),记录锁由 plugin-approvalsbeforeUpdate 钩子严格执行 —— lockRecord: false 的节点上,记录在整个等待期间都可以正常写入。服务端行为一直是对的。

但这个策略没有出现在任何对外读取的字段上,客户端拿不到。

rowFromRequestpackages/plugins/plugin-approvals/src/approval-service.ts:236)确实解析了 node_config_json

const cfg = parseJson<any>(row.node_config_json, undefined);

但它只从里面挑白名单几项出来 —— __flowLabel / __nodeLabel / __round / escalation.timeoutHours / decisionOutputs —— lockRecord 从来不在这个列表里ApprovalRequestRowpackages/spec/src/contracts/approval-service.ts:34)上也没有任何其它字段承载锁信息。

于是 GET /api/v1/approvals/requests 的消费方能知道的最强事实只有「存在一条 pending 请求」,从这里只能推出「记录被锁」。

影响

这个推断在每一个 lockRecord: false 的节点上都是错的。而一条串了不同策略节点的 flow 会让它错得肉眼可见:同一个 UI 状态既表示「你可以随便改」,也表示「你按保存会被 RECORD_LOCKED 打回来」。

客户端没有第三条路 —— 反过来猜就会放出一个必然在保存时死掉的编辑入口。

下游具体表现见 objectui#2902:Console 详情页对所有 pending 节点一律渲染「审批中已锁定」band,并且连带把行内编辑整个禁掉。实际业务里审批链上的单人节点(部门负责人 / 厂长)通常正是配 lockRecord: false,本意就是让审批人在审批时补充内容 —— 这个能力等于从 UI 上消失了。

复现

  1. 一条 record_change flow 串两个 approval 节点,A 配 lockRecord: false,B 配 lockRecord: true
  2. 触发审批,停在节点 A
  3. GET /api/v1/approvals/requests?object=<obj>&recordId=<id>

实际:返回的行里没有任何字段能区分 A 和 B 的锁策略。
预期:行上带出当前节点的 lockRecord,且与钩子读的是同一来源、同一默认值。

方案

ApprovalRequestRow 增加 lock_record?: boolean,在 rowFromRequest 里从钩子读的那同一份 node_config_json 快照取值,用同一个 !== false 默认lockRecord 的 schema 默认就是 true):

lock_record: cfg?.lockRecord !== false,

这样客户端渲染的标志和服务端执行的规则不可能漂移。openNodeRequest / getRequest / listRequests 三条读路径都带上。

纯增量、向后兼容,无需迁移。老客户端忽略即可;新客户端读 request.lock_recordundefined(老后端)按锁死处理 —— 也就是现状行为。

顺带把 showcase 的 showcase_budget_approval 变成这个能力的 dogfood:单人的 Manager Review 配 lockRecord: false,多人会签的 Executive Review 保持 true,一条 flow 同时覆盖两种策略。

环境

  • @objectstack/plugin-approvals 16.1.0
  • 该行为自 Phase B autopilot 引入 lockRecord 起就存在,不是回归

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions