Files
zkxw/docs/superpowers/specs/2026-07-30-oa-initiator-condition-design.md
T
zlwuandCursor 22be6d8b36 feat(oa): add initiator system field to condition branches
Allow __initiator__ contains matching in publish validation and the
flow designer candidate list, excluding it from form useInCondition locks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 13:07:44 +08:00

4.8 KiB
Raw Blame History

OA 条件分支:系统变量「发起人」包含

日期: 2026-07-30
范围: web-admin 审批设计器步骤 3(流程设计)条件编辑;backend 条件匹配、发布校验、流程预览
关联: docs/superpowers/specs/2026-07-15-oa-condition-from-form-design.md(原非目标「系统变量」本期落地发起人);docs/superpowers/specs/2026-07-30-oa-person-select-design.md(contains / 人员多选 UI 可复用)
状态: 已实现


1. 背景与目标

表单驱动条件已支持勾选字段进分支;钉钉式「发起人属于某些人」仍缺失。现有规格将「系统变量(发起人等)」列为二期。本期仅落地 发起人 + 包含。

1.1 产品结论(已确认)

项 结论
候选出现方式 条件字段下拉常驻「发起人」,不依赖表单勾选
新建分支 不预填发起人规则(空规则,配置者自行添加)
运算符 仅「包含」;右侧多选用户;发起人 id ∈ value 即命中(OR)
与表单条件 同一 conditionGroup 内多条规则仍 AND
实现路径 系统伪字段 __initiator__(方案 A)

1.2 与表单「人员」控件区别

表单 person 系统「发起人」
数据 表单填报所选人员 initiator_user_id
入池 需勾选 useInCondition 始终在候选中
type person initiator(仅条件候选用)

1.3 非目标

  • 不包含 / 等于 / 不等于
  • 发起人部门、角色等其它系统变量
  • 新建条件分支自动预填发起人规则
  • 改写表单设计器或新增表单控件

2. 架构

[3 流程设计] ConditionRuleEditor
  candidates = [发起人伪字段] + listConditionCandidates(schema)
  rules: { field: '__initiator__', op: 'contains', value: userId[] }
        ↓
flow_tree_json
        ↓
[发布] validate:系统字段合法;value 非空 string[]
        ↓
[引擎 / 预览] _eval_condition_rules(..., initiator_user_id)
  field==__initiator__ → initiator_user_id ∈ value

不将 __initiator__ 写入实例 form_data_json。


3. 数据契约(锁定)

const INITIATOR_CONDITION_FIELD = '__initiator__'

// 候选
{ field: '__initiator__', title: '发起人', type: 'initiator' }

// 规则
{ field: '__initiator__', op: 'contains', value: string[] } // length >= 1 at publish

命中:String(initiator_user_id).strip() ∈ Set(value)。


4. 前端

4.1 候选注入

listConditionCandidates(或 designer 组装处)前置系统候选,再拼接表单合格字段。

4.2 编辑器

  • opsForFieldType('initiator') → 仅「包含」
  • RHS:与 person 共用人员多选(fetchUserList status=1)
  • 预览:发起人 包含 张三、李四(有 map 用姓名,否则 id)
  • 取消表单「参与条件」拦截:引用集合中的 __initiator__ 不得当作表单字段要求保留勾选

4.3 流程预览

发起页预览以当前登录用户为发起人;后端预览 API 传入该 uid 即可,前端不必另造发起人选择器。


5. 后端

5.1 引擎

  • _eval_condition_rules / _match_condition_group 增加参数 initiator_user_id: Optional[str]
  • field == '__initiator__' 且 op == 'contains':用 person_contains_match 兼容形态,或直接
    initiator_user_id in set(value)(发起人为标量 id,可构造 {"id": uid, "name": ""} 复用 helper)
  • 所有条件匹配调用点(推进、路径解析、流程预览)传入发起人 id
  • 其它 field 行为不变

5.2 发布

  • validate_condition_rules_against_form:field == '__initiator__' 不要求出现在表单 condition index
  • 校验:仅允许 op == 'contains';value 为非空字符串 id 列表
  • 非法 op / 空 value → 中文错误

6. 测试

场景 期望
发起人在 value 内 命中该组
发起人不在 value 内 走默认组
与表单金额 AND 两边都真才命中
发布仅系统字段条件 通过
发布 value=[] 失败
回归表单 person contains 通过

7. 文件清单

前端: oa-condition-fields.ts、ConditionRuleEditor.vue、designer/index.vue(若需)、取消勾选引用逻辑处

后端: oa_engine.py、oa_publish.py、tests/test_oa_engine.py、publish 相关测试


8. 验收标准

  • 条件字段下拉常驻「发起人」,无表单条件字段时仍可选
  • 仅「包含」+ 多选人;新建分支不预填
  • 运行与发起预览按发起人正确分流
  • 发布校验与单测通过;既有表单条件无回归

9. 实现顺序

  1. 引擎 + 单测
  2. 发布校验
  3. 前端候选 + 编辑器
  4. 手测设计器与发起预览