9.9 KiB
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 中:
- 解析 form_data 中 relatedApproval 字段 →
to_instance_id列表(去重) - 服务端再次校验每条可关联
- 写入
oa_relation(带field_key) - 合并/兼容旧
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. 验收标准
- 设计器可拖入「关联审批单」,导出 JSON
type为relatedApproval,发布校验通过 - 主应用发起页与设计器预览均能渲染控件(双侧注册)
- 选单仅本人
completed实例;可多选、可删 - 收起/展开符合 §5;Web 横排、移动预览逐行
- 提交后
oa_relation正确且含field_key;详情可回显并跳转 - 越权 ID 无法提交;无控件旧应用回归通过
- UI 主色与间距符合 Fresh Mint,无设计器默认蓝污染业务页
9. 测试建议
- 后端:选单过滤、enrichment 越权、start 写 relation、去重
- 前端:FormCreate 注册 spike(拖 → 导出 → 发起渲染);展开收起;必填
- 手工:设计器 PC/手机预览切换下的布局
10. 实现顺序建议
- Spike:空壳四层注册打通
- 选单 API + enrichment + 扁平化
- Runtime 控件 UI(含展开收起、响应式布局)
- start 写
oa_relation(field_key) - 详情只读与跳转
- 回归旧应用 + 发布校验
11. 修订说明
相对 2026-07-14 总设 §5.5「选择有权查看的实例」:本需求收窄为 本人发起 + 已通过;展示从「可跳转」增强为 可展开的全字段概要。若与总设冲突,以本文为关联审批单专项权威,总设可在归档时回写一句交叉引用。
2026-07-22 嵌套/打印修订:屏幕嵌套与打印递归行为以 2026-07-22-oa-related-approval-nested-print-design.md 为准(本文 §5 嵌套行已改为交叉引用)。