Files
zkxw/docs/superpowers/specs/2026-07-22-oa-related-approval-design.md
T
2026-08-11 11:13:01 +08:00

9.9 KiB
Raw Blame History

OA「关联审批单」控件设计文档

日期: 2026-07-22
状态: 已批准(实现计划见 docs/superpowers/plans/2026-07-22-oa-related-approval.md)
方案: 方案 1 — form_data 仅存 instanceId[],展示时 enrichment 实时拼装概要;提交写 oa_relation
界面模式: 对齐钉钉「关联审批单」;视觉遵循 Fresh Mint(docs/web-admin-ui-spec-fresh-mint.md)
前置文档: docs/superpowers/specs/2026-07-14-oa-approval-dingtalk-design.md §4.5 / §5.5

决策记录:

  • 产品意图:引用 + 展示历史单字段内容 + 可跳转详情;不自动串子流程、不自动回填当前单其它字段
  • 选单范围:当前用户本人发起、任意审批应用、仅实例状态 completed(已通过);支持多选
  • 展示:标签流;展开=全部可展示业务字段;收起=应用名 + 时间 + 前 3 个字段
  • 端差异:Web 横排充分利用宽度;移动端 / 窄屏逐行展示(同一 enrichment 数据,不同布局壳)
  • 实现底座:按 FormCreate / FcDesigner 四层扩展注册自定义控件(官方扩展路径),禁止沿用「改写内置 upload」式补丁
  • 兼容:双端契约(schema + form_data)、Fresh Mint UI、主应用与 oa-fc-host 对称注册、无该控件的旧应用行为不变

1. 目标与范围

1.1 目标

在 OA 审批「2 表单设计」中提供可拖拽的「关联审批单」控件;发起时可选择本人已通过的历史申请,在当前单中展示概要(可展开看全字段),并支持跳转历史单详情。

1.2 包含(V1)

能力 说明
设计器控件 左侧可拖;type=relatedApproval;右侧基础属性(标题、必填、提示)
发起选单 弹窗;本人 + 已通过 + 任意应用;关键词/分页;多选;已选项禁用
概要展示 收起/展开;Web 标签流横排;移动逐行
持久化 form_data[field]=string[];提交写 oa_relation(含 field_key)
详情回显 只读同一控件;可展开/跳转
权限 选单与 enrichment 服务端校验;防越权点选

1.3 不包含(V1)

  • 设计器配置「可选应用 / 可选状态」
  • 选中后自动映射/回填当前表单其它字段
  • 因关联自动发起子流程或改变对方实例状态
  • 被关联方详情展示「谁关联了我」(二期可选)
  • 小程序运行时完整交互(Schema/值契约必须先兼容;运行时壳可二期)

2. FormCreate 扩展方式(兼容性核心)

参考 FcDesigner 添加新组件,必须补齐四层:

层 要求
Runtime 组件 Vue 组件(如 OaRelatedApproval.vue):选单、列表、展开收起、v-model 为 string[]
form-create 注册 formCreate.component('relatedApproval', Comp)(必要时双写大小写/别名,但对外 type 固定 relatedApproval)
DragRule menu: 'main'(基础组件);name/label/icon/input/rule()/props();validate 对齐数组/必填
设计器注册 FcDesigner.component(...) + designer.addComponent(dragRule) 或全局 FcDesigner.addDragRule

对称注册(SHALL):

  • web-admin/src/main.ts(发起/详情运行时)
  • web-admin/src/oa-fc-host/main.ts(设计器 iframe)

禁止:

  • 仅改写内置 upload/input 冒充关联控件(与本仓附件补丁路径不同)
  • rule.type 与后端 oa_publish.ALLOWED_CONTROL_TYPES 不一致(现已含 relatedApproval)

UI 样式(SHALL):

  • Web 使用 Fresh Mint / Element Plus,与发起页、详情页一致
  • 不引入 FormCreate 设计器默认高饱和蓝作为业务主色
  • 弹窗使用现有 dialog-form-layout / 列表习惯,遮罩无 backdrop blur

3. 数据契约

3.1 Schema

{
  "type": "relatedApproval",
  "field": "<uniqueId>",
  "title": "关联审批单",
  "info": "",
  "$required": false,
  "props": {}
}

V1 props 可不扩展业务过滤项;后续若开放设计器过滤,再增显式字段,保持向后兼容。

3.2 form_data 值

控件 JSON 形态
关联审批单 string[](instanceId 列表;去重;顺序=用户选择顺序)

符合 OA 双端契约(§4.6):禁止 DOM / 组件实例 / 本地 File 进入 form_data。

3.3 oa_relation

沿用现表:

字段 含义
from_instance_id 当前新实例
to_instance_id 被关联历史实例
field_key 表单字段 field(多控件时区分)
tenant_no 等 公共字段规范

提交时:扫描当前版本 schema 中所有 relatedApproval 字段 → 取其 form_data 数组 → 写关系行。
顶层请求体 relatedInstanceIds 保留作兜底(无 field_key);主路径以 form_data 为准。


4. API

前缀遵循现有 /api/admin/... OA 路由;租户取当前用户,不信任客户端覆盖。

4.1 选单列表

  • 用途: 弹窗可选实例
  • 过滤(SHALL): initiator_user_id = 当前用户、status = completed、tenant_no、del_flag=0
  • 能力: 关键词(应用名/标题)、分页、按发起时间倒序
  • 返回: id, appName, title?, applyTime, status(列表可先不带全字段,点选后再 enrichment)

4.2 概要 enrichment

  • 入参: ids: string[]
  • 校验:
    • 选单场景: 仅本人发起且 completed
    • 详情回显场景: 调用方须已能查看当前实例;对被关联 id,若无可见权则该项返回占位(unavailable: true),不导致整接口 403
  • 返回(建议):
{
  id: string
  appName: string
  applyTime: string
  status: string
  fields: Array<{ label: string; value: string; fullWidth?: boolean }>
}

4.3 发起 start 变更

在现有 start_instance 中:

  1. 解析 form_data 中 relatedApproval 字段 → to_instance_id 列表(去重)
  2. 服务端再次校验每条可关联
  3. 写入 oa_relation(带 field_key)
  4. 合并/兼容旧 relatedInstanceIds(无 field_key)

4.4 详情回显(V1 定案)

V1 不改详情主接口形状:前端根据 form_data / relatedInstanceIds 再调 enrichment。
二期若有性能问题,再给 get_instance_detail 附加 relatedSummaries。


5. 字段扁平化规则

对历史实例的 form_schema + form_data:

对方控件类型 概要展示
常规输入/选择/日期/金额等 label + 格式化后的文本值
附件 / 图片 / 上传 N 个(不内嵌文件列表)
嵌套 relatedApproval 屏幕:已关联 M 条(可跳转,不嵌套缩略卡);打印:多行递归展开业务字段,最多 3 层。细则见 2026-07-22-oa-related-approval-nested-print-design.md
布局 / 说明 / 纯展示 跳过
长文本 可标 fullWidth;展开时单独占行
  • 收起: 应用名 + 时间 + fields 的前 3 条
  • 展开: 全部 fields
  • Web: display:flex; flex-wrap 标签流,尽量一行多字段
  • 移动 / 窄屏: 每字段一行(label:value)

点击应用名(或行标题)→ 打开只读详情弹窗(盖在当前发起/详情等界面之上,不关父弹窗);权限不足时提示,不白屏。细则见 2026-08-11-oa-related-approval-detail-dialog-design.md。


6. 前端模块建议

模块 职责
OaRelatedApproval.vue 运行时控件(选单、列表、展开收起)
oa-related-approval-rule.ts DragRule
setupOaRelatedApproval(...) 双侧注册入口(对称 setupFormCreateUpload)
api/oaApproval.ts 选单 + enrichment 客户端
发起页 / 详情页 无需特殊分支(form-create 按 type 渲染);确保注册已执行

设计器预览:只读空态或示意条即可,SHALL NOT 因未登录选单 API 而报错崩溃。


7. 边界与错误处理

场景 行为
选单无数据 空态文案
篡改不可关联 ID enrichment/提交失败,明确错误,不写关系
历史单删除或对当前用户不可见 占位「无法查看」;不阻断当前单保存(已提交关系保留)
必填未选 FormCreate 校验拦截
重复 ID 选单禁用;提交去重
字段极多 展开区域可滚动
无该控件旧应用 行为不变

8. 验收标准

  1. 设计器可拖入「关联审批单」,导出 JSON type 为 relatedApproval,发布校验通过
  2. 主应用发起页与设计器预览均能渲染控件(双侧注册)
  3. 选单仅本人 completed 实例;可多选、可删
  4. 收起/展开符合 §5;Web 横排、移动预览逐行
  5. 提交后 oa_relation 正确且含 field_key;详情可回显并跳转
  6. 越权 ID 无法提交;无控件旧应用回归通过
  7. UI 主色与间距符合 Fresh Mint,无设计器默认蓝污染业务页

9. 测试建议

  • 后端:选单过滤、enrichment 越权、start 写 relation、去重
  • 前端:FormCreate 注册 spike(拖 → 导出 → 发起渲染);展开收起;必填
  • 手工:设计器 PC/手机预览切换下的布局

10. 实现顺序建议

  1. Spike:空壳四层注册打通
  2. 选单 API + enrichment + 扁平化
  3. Runtime 控件 UI(含展开收起、响应式布局)
  4. start 写 oa_relation(field_key)
  5. 详情只读与跳转
  6. 回归旧应用 + 发布校验

11. 修订说明

相对 2026-07-14 总设 §5.5「选择有权查看的实例」:本需求收窄为 本人发起 + 已通过;展示从「可跳转」增强为 可展开的全字段概要。若与总设冲突,以本文为关联审批单专项权威,总设可在归档时回写一句交叉引用。

2026-07-22 嵌套/打印修订:屏幕嵌套与打印递归行为以 2026-07-22-oa-related-approval-nested-print-design.md 为准(本文 §5 嵌套行已改为交叉引用)。