日期: 2026-07-14
状态: 已批准(实现计划见 docs/superpowers/plans/2026-07-14-oa-approval-dingtalk.md)
界面模式: 对标钉钉「OA审批」;视觉遵循 docs/web-admin-ui-spec-fresh-mint.md
建设方案: 方案 2 — 前端借用开源设计器能力改造,后端 Python 自研引擎
决策记录:
#10b981),不照搬钉钉蓝sys_role:另建独立「工作流角色」;动态审批人含「发起人部门负责人」「发起人的主管」;「总经理 / 董事长」等为预置工作流角色(全局成员,非按发起人部门变化)form_schema_json 为唯一真相;Web 管理端先交付填报/审批;控件与交互须可适配移动端,为后续小程序/H5 复用同一 Schema(见 §4.6)取代关系: 本设计取代 docs/superpowers/specs/2026-05-13-workflow-module-design.md 作为后续实现权威;旧 wf_* / X6 路径标记废弃。
在 zkxw 的 web-admin + Python backend 中交付独立的钉钉式审批能力:管理员可配置审批应用(基础设置 / 表单设计 / 流程设计 / 高级设置),全员可在审批中心发起与办理。
| 能力 | 说明 |
|---|---|
| 审批分组与应用列表 | 类似钉钉模板管理入口 |
| 四步配置向导 | 基础设置 → 表单设计 → 流程设计 → 高级设置 → 发布 |
| 表单控件(V1 清单) | 见 §4.5;按钉钉控件库裁剪,排除 AI/手写签名/通讯录人员类/身份证等 |
| 附件上传 | 「附件」控件;发起/详情可上传、预览、下载、删除;存储 MinIO(见 §4.3) |
| 公式、数据联动 | 「计算公式」控件 + 字段级联动;后端权威求值 |
| 关联审批 | 「关联审批单」控件;详情可跳转;不自动串子流程 |
| 竖向流程树 | 发起人、审批人、抄送人、条件分支、结束;中间「+」插入 |
| 工作流角色 | 独立于 sys_role:含自定义角色 + 预置角色(总经理、董事长等,见 §3.3) |
| 审批人策略 | 指定成员、工作流角色(含预置)、发起人部门负责人、发起人的主管、发起人自选;或签 / 会签 |
| 高级设置(子集) | 撤销、审批人去重、意见是否必填、允许加签;无直属主管时回退部门负责人(默认开) |
| 审批中心 | 发起、待处理、已处理、我发起的、抄送我的、详情(Web 先做) |
| 表单双端适配 | 设计器 PC/手机预览;Schema 与控件语义可复用到移动端(见 §4.6);V1 移动端运行时可为占位/二期,但控件不得绑死仅 PC 组件 |
| 租户隔离与版本锁定 | 发布版本;实例绑定发起时版本 |
sys_role(菜单/数据权限角色)作为审批人解析来源wf_* 历史数据(当前未使用,可放弃)web-admin · 「OA审批」独立模块
├── 审批管理(配置)
│ ├── 应用列表 / 分组
│ ├── 工作流角色管理(独立于系统角色)
│ └── 四步向导
│ ├── 基础设置(自研)
│ ├── 表单设计(FormCreate/VForm3 改造 + Mint)
│ ├── 流程设计(AntFlow 风格树改造 + Mint)
│ └── 高级设置(自研,V1 子集)
└── 审批中心(办理)
├── 发起(模板列表 → 填单)
├── 待处理 / 已处理 / 我发起的 / 抄送我的
└── 详情(表单回显 + 进度 + 关联审批)
backend Python · oa_approval 子系统
├── 定义层:应用、版本、分组、工作流角色、发布校验
├── 运行时:发起、任务、条件、公式、联动、关联、审批人解析、高级设置生效
└── 数据:oa_* 表(见第 3 节)
边界:
sys_role 只负责菜单/数据权限;审批人解析只读 oa_role* 与组织(sys_dept / 用户部门),不读 sys_role 成员backend/app/**/workflow* 与 web-admin/src/views/system/workflow/** 不再演进,菜单隐藏或提示迁移所有表遵循工程公共字段规范:id → 业务字段 → tenant_no … → del_flag。
| 表名 | 用途 |
|---|---|
oa_app_group |
审批分组 |
oa_app |
审批应用(图标、名称、说明、发起范围、管理员范围等) |
oa_app_version |
版本:form_schema_json、flow_tree_json、advanced_settings_json、status=draft|published、version_no、is_latest_published |
oa_role |
工作流角色(与 sys_role 无关):名称、编码、role_kind=custom|preset、备注、启用状态 |
oa_role_user |
工作流角色成员:oa_role_id + user_id |
oa_instance |
实例:app_id、app_version_id、form_data_json、status、发起人、initiator_dept_id 等 |
| (组织补齐) | sys_user.supervisor_user_id(或等价):直属主管,供「发起人的主管」解析;sys_dept.leader_user_id(或等价):部门负责人稳定关联用户 |
oa_task |
任务:实例、节点 key、类型(approval/cc)、处理人、状态、意见 |
oa_relation |
关联审批:from_instance_id、to_instance_id、可选控件 field_key |
published,并对新发起生效。app_version_id;此后改应用不影响已发起单据。form_schema_json 字段属性内。advanced_settings_json,由任务 API 读取。props(标题、必填、公式、联动规则、关联审批过滤等)type、name、approverConfig、conditionGroups、children 等users — 指定成员(user_id 列表)oa_roles — 指定工作流角色(oa_role_id / 预置编码,运行时展开成员;含总经理、董事长)dept_leader — 发起人部门负责人(动态)direct_supervisor — 发起人的主管(动态,读发起人直属主管)initiator_select — 发起人自选具体字段级 schema 在实现计划中固化,并提供前后端 TypeScript / Pydantic 镜像类型。
| 机制 | 配置侧文案(建议) | 用途 | 是否按发起人变化 |
|---|---|---|---|
sys_role |
(不出现在流程选人里) | 菜单 / 数据权限 | 否;审批引擎不读取 |
oa_role 自定义 |
工作流角色 | 如「财务审批」「法务审批」 | 否;展开 oa_role_user |
oa_role 预置 |
总经理 / 董事长 等 | 公司级特殊岗位,一人或少数人 | 否;全局同一批人 |
dept_leader |
发起人部门负责人 | 审「部门头」 | 是(按发起人部门) |
direct_supervisor |
发起人的主管 | 审「直属上级」 | 是(按发起人本人) |
users / initiator_select |
指定成员 / 发起人自选 | 定点人或发起时点人 | 视配置 |
禁止:把「所有部门负责人」或「所有主管」收成一个静态角色,来冒充 dept_leader / direct_supervisor。
租户初始化(或模块首次启用)时种子写入,编码固定、不可删、可改成员与显示名备注:
| 预置编码 | 默认名称 | 说明 |
|---|---|---|
GM |
总经理 | 节点可选「工作流角色 → 总经理」 |
CHAIRMAN |
董事长 | 节点可选「工作流角色 → 董事长」 |
role_kind=preset;管理员只维护成员,不可删除预置行。dept_leader 解析(发起人部门负责人)initiator_dept_id(发起时写入;多部门时按发起页选定,默认主部门)。leader_user_id(须稳定关联 sys_user.id,见 §9)。direct_supervisor 解析(发起人的主管)与「部门负责人」语义分离:主管是人对人的汇报关系,不一定等于所在部门负责人。
sys_user.supervisor_user_id),在用户管理中可维护。supervisor_user_id(有效且未停用)。dept_leader 规则解析发起人部门负责人。advanced_settings_json(建议键名 supervisorFallbackToDeptLeader,默认 true);关闭后主管缺失则创建任务失败并提示「请维护直属主管或部门负责人」。OA审批
├── 审批管理 → 应用列表 / 进入四步配置
├── 工作流角色 → oa_role 维护与成员绑定(不进系统角色菜单)
├── 发起审批 → 按分组展示可发起模板
├── 待处理
├── 已处理
├── 我发起的
└── 抄送我的
详情不单独挂菜单:从列表进入路由 /oa-approval/instances/:id(名称以实现时路由表为准)。
UI Token:按钮、标签、步骤高亮使用 Fresh Mint;布局密度与信息架构对齐钉钉,不混用小程序 #0a9f6d。
模式索引:实现前在 docs/web-admin-ui-pattern-index.md / OpenSpec ui-conventions 登记(可沿用或扩展 P24)。
对齐钉钉「附件」控件能力,并遵循本仓 ui-conventions 附件上传卡片化布局与 architecture-conventions 对象存储约定:
| 项 | 要求 |
|---|---|
| 设计器 | 控件库提供「附件」;属性至少支持:标题、是否必填、允许的文件类型(可选)、最大个数、单文件大小上限提示 |
| 发起 / 编辑填报 | 选择文件后立即上传(复用现有 fetchUploadAttachment 或等价 admin 上传 API);上传触发区与已传文件卡片同一行;支持预览 / 下载 / 删除 |
| 详情 / 审批页 | 只读展示附件列表,可预览、下载;审批人默认不可改发起人已传附件(除非后续扩展「可编辑字段」权限,V1 不做) |
| 存储 | MinIO 对象存储;form_data_json 中该字段存 URL 列表(多个以逗号分隔 URL,与现有附件字段惯例一致) |
| 校验 | 必填时无附件不可提交;类型/个数超限前端拦截并提示,后端发起接口再次校验 |
权威 UI 参考:ProtocolFormDialog.vue「协议附件」卡片交互;色与尺寸跟 Fresh Mint,不自造第二套上传样式。
| 页面 | 行为 |
|---|---|
| 发起 | 模板宫格/分组 → 填单(含附件即时上传)→(发起人自选时)选人 → 提交 |
| 待处理 | 列表 → 详情:表单只读(附件可预览下载)+ 同意/拒绝/意见/加签 + 进度时间轴 |
| 已处理 | 列表 → 详情只读 |
| 我发起的 | 列表 → 详情;按高级设置允许撤销 |
| 抄送我的 | 列表 → 详情只读知会 |
| 详情 | 表单回显、进度、关联审批跳转 |
列表页遵循 web-admin 标准列表骨架(筛选 / 工具栏 / 表格 / 分页);详情可用抽屉或独立页,优先信息结构清晰。
对照钉钉 OA「表单设计」左侧控件库;本次做 / 不做如下。
| 分组 | 控件 | 说明 |
|---|---|---|
| 布局 | 分栏 | 两列等布局 |
| 基础 | 单行输入框 | |
| 基础 | 多行输入框 | |
| 基础 | 数字输入框 | |
| 基础 | 单选框 | |
| 基础 | 多选框 | |
| 基础 | 日期 | |
| 基础 | 日期区间 | |
| 基础 | 说明文字 | 只读提示 |
| 基础 | 电话 | 手机号等,可校验格式 |
| 增强 | 图片 | 上传图片 |
| 增强 | 金额 | 金额录入(千分位等按现有金额组件习惯) |
| 增强 | 附件 | MinIO;见 §4.3 |
| 增强 | 部门 | 选本系统组织树(非行业通讯录) |
| 增强 | 省市区 | 省/市/区级联 |
| 增强 | 计算公式 | 与字段公式能力一致 |
| 增强 | 关联审批单 | 见关联审批 |
字段属性侧:必填、标题、提示文字、默认值;以及已定的数据联动配置(不单独占控件位)。
| 控件 | 原因 |
|---|---|
| AI 控件 | 产品排除 |
| 手写签名 | 产品排除 / 复杂项 |
| 身份证 | 产品排除 |
| 联系人 | 产品排除 |
| 外部联系人 | 产品排除 |
| 行业通讯录部门 | 产品排除(用本系统「部门」代替组织选择) |
明细/表格、地点、评分、级联/分类(非省市区)。若业务急需可单项加开,不默认出现在 V1 控件库。
产品意图:同一审批应用须能在 Web 端与移动端 发起、填写、审批查看;兼容性是一等约束,不是「以后再说的样式问题」。
配置只做一次(Web 设计器);表达式层(Schema + form_data + 校验 + 引擎)两端共用;各端只负责自家 UI 皮肤与交互壳。
| # | 契约 | 要求 |
|---|---|---|
| C1 | 同一 Schema | Web / 移动只消费同一份 form_schema_json;禁止「Web 一份、手机再配一份」 |
| C2 | 同一 form_data | 字段值的 JSON 形状、类型两端一致;任一端提交的数据另一端必须能回显与再编辑(权限允许时) |
| C3 | 同一后端校验 | 必填、格式、附件个数、公式/联动结果以服务端为准;移动端不得绕过 |
| C4 | 同一控件字典 | 每个控件有稳定 type(如 input/textarea/number/radio/checkbox/date/dateRange/html/phone/image/money/attachment/dept/region/formula/relatedApproval/column);禁止仅存在于 FormCreate 内部的未登记 type 进已发布版本 |
| C5 | 布局可降级 | column(分栏)在宽度 < 768(或手机预览)时 必须 降为单列;Schema 可带 layout.mobile 提示,但缺省行为已定 |
| C6 | 无端锁定依赖 | Schema / form_data 禁止 出现:DOM 引用、Element Plus 组件实例、仅浏览器 File 对象、本地绝对路径;附件只存可访问 URL |
| C7 | API 共用 | 发起/详情/待办等走同一套 /api/admin/oa-approval/*(或后续为小程序增加的同语义网关);移动端不另造业务存储 |
form_data 值类型约定(兼容核心)两端写入/读取必须遵循(实现计划落成 TypeScript + Pydantic 镜像):
| 控件 | JSON 值形态 | 说明 |
|---|---|---|
| 单行/多行/说明/电话 | string |
|
| 数字/金额 | number 或可解析数字字符串(发布时锁定一种,全局一致) |
两端展示格式可不同,存储一致 |
| 单选 | string(选项 value) |
|
| 多选 | string[] |
|
| 日期 | string(YYYY-MM-DD) |
|
| 日期区间 | { start: string, end: string } |
|
| 图片/附件 | string(多个 URL 英文逗号拼接,与现有附件惯例一致) |
|
| 部门 | string(deptId)或 { id, name }(发布时锁定一种) |
回显名可由端补全 |
| 省市区 | string[] 或 { province, city, district }(锁定一种) |
|
| 关联审批单 | string(instanceId)或 string[] |
|
| 计算公式 | 与所引用字段同类型;只读展示 | 以服务端计算结果为准 |
选项类控件的 options[].value / label 必须是纯 JSON 可序列化数据,禁止函数。
| 能力 | Web | 移动端 |
|---|---|---|
| 文本/数字/金额/电话 | Element 输入框 | uni-app input;键盘类型匹配(number/tel) |
| 单选/多选 | radio/checkbox | radio/checkbox 或行动面板,值仍走 C2 |
| 日期/区间 | 日期面板 | picker / 日历弹层 |
| 部门/省市区 | 下拉树/级联 | 全屏或半屏选择器(禁止依赖宽屏下拉才能选完) |
| 图片/附件 | 卡片上传 + 预览 | 相册/相机 + 预览;上传同一 MinIO API |
| 分栏 | 多列 grid | 自动单列 |
| 触达 | 常规 | 可点区域建议 ≥44×44 |
| 皮肤 | Fresh Mint | 三墙 Token;禁止混用主色 |
type 或违反值形态约定的草稿不可发布。| 阶段 | 交付 | 兼容要求 |
|---|---|---|
| V1 | Web 配置 + Web 办理;控件字典、值类型、手机预览、服务端校验全部到位 | Schema/form_data 已按双端契约实现,不得留下只能 Web 跑的结构 |
| 移动端运行时(可紧随或并行立项) | 小程序/H5:发起、待办、详情渲染器 | 只加渲染器与路由,不改编排模型 |
不做:为移动端复制第二套表单配置;「仅 PC / 仅手机可见」字段(除非另开需求)。
published 版本(或指定版本策略,默认最新已发布)form_data(含附件必填、URL 合法性、个数上限);执行公式与数据联动(服务端权威)oa_instance,绑定版本oa_relation(若有)oa_taskcompleted / rejected(拒绝 = 整单结束;打回 = 同实例退回重提,见 2026-07-15-oa-approval-progress-timeline-design.md。原「V1 不做复杂回退」表述已废止,打回按该文档分阶段 P1 落地)引擎按节点 approverConfig.assigneeType 解析处理人集合,不得查询 sys_role / sys_user_role:
| assigneeType | 解析逻辑 |
|---|---|
users |
直接使用配置的 user_ids(租户内有效用户) |
oa_roles |
查 oa_role_user 展开成员并去重(含预置 GM / CHAIRMAN) |
dept_leader |
按 §3.3 从发起人部门解析部门负责人 |
direct_supervisor |
按 §3.3:先直属主管,缺省则默认回退部门负责人(高级设置可关) |
initiator_select |
使用发起时提交的自选人列表 |
空集合:创建任务前失败并返回可读错误(除非高级设置未来定义「审批人为空」策略;V1 默认失败)。
示例(验收用):
dept_leader:部门 A 张三发起 → A 负责人待办;部门 B 李四发起 → B 负责人待办。direct_supervisor:指向张三的 supervisor_user_id,与是否部门负责人无关。oa_roles + GM / CHAIRMAN:无论谁发起,均由绑定的总经理/董事长处理。IF/SUM 等白名单)oa_relation在对应 API 中读取实例绑定版本的 advanced_settings_json:撤销窗口、去重、意见必填、加签开关、supervisorFallbackToDeptLeader(默认 true)。
role_code 固定为 GM / CHAIRMANoa_role(预置置顶分组)发布前必须通过:
users / oa_roles 引用非空,或 dept_leader / direct_supervisor / initiator_select 已明确选择| 场景 | 规则 |
|---|---|
| 编辑应用 / 工作流角色 | 具备 OA 审批管理类系统菜单权限的用户(仍用 sys_role 控制能否进入配置台);表单管理员可编对应应用 |
| 看到并发起模板 | 「谁可发起」为全部,或命中指定成员 |
| 处理待办 | 仅任务指派人 |
| 看详情 | 发起人、任务参与人(审批/抄送)、表单管理员、系统管理员(租户内) |
| 租户 | 所有读写带当前用户 tenant_no,不信任客户端租户覆盖 |
说明:进菜单用 sys_role,批给谁用 oa_role / dept_leader / 指定人 —— 两套职责分离。数据权限与多角色并集语义遵循现有 permission-conventions(仅作用于是否能访问配置/列表等系统能力)。
注册于 app/api/__init__.py 与 app/main.py,走现有 admin 鉴权 / 加密 / 审计中间件。
GET/POST /api/admin/oa-approval/groupsGET/POST/PUT /api/admin/oa-approval/appsGET/PUT .../apps/{id}/draft(三份 JSON + 基础信息)POST .../apps/{id}/publishGET/POST/PUT/DELETE .../oa-roles(工作流角色)PUT .../oa-roles/{id}/users(成员绑定)GET .../templates(可发起列表)POST .../instances(发起)GET .../tasks/pending|done|mine|ccGET .../instances/{id}POST .../tasks/{id}/approve|reject|add-sign|withdraw具体路径与 schema 在实现计划中展开。
| 项 | 动作 |
|---|---|
菜单 system/workflow/* |
隐藏或跳转提示「请使用 OA审批」 |
wf_* 表 |
保留库表不影响上线;后续迭代删除 |
FlowDesigner.vue (X6) |
停止维护 |
OpenSpec workflow-conventions |
后续独立变更修订,对齐本设计的钉钉模型措辞 |
| 风险 / 开放点 | 处理 |
|---|---|
| FormCreate vs VForm3 选型 | 实现计划第 0 步做短 spike(许可证、Element Plus 亲和、公式扩展成本)后锁定 |
| 公式引擎安全性 | 白名单 AST,禁止 eval 任意代码 |
| 关联审批权限过滤 | 必须复用详情可见性规则,防越权点选 |
| 开源设计器 UI 与 Mint 冲突 | 仅复用交互与数据结构思想,样式统一走本项目 Token |
| 与需求 §2.1.11 措辞 | 需求原文写「配置角色 / SQL 模式」;本设计以独立 oa_role + dept_leader 覆盖同等场景,不采用 SQL 任意语句,避免注入面;引擎语言仍为 Python |
sys_dept.leader 与 user_id |
部门页已按用户选择负责人,但列类型历史为字符串;V1 必须补齐稳定的 leader_user_id(或等价)以便 dept_leader 解析 |
| 用户无直属主管字段 | V1 必须增加 sys_user.supervisor_user_id(或等价)并在用户管理可维护,否则「发起人的主管」无法落地 |
| 总经理/董事长人数 | 预置角色允许多成员时按节点或签/会签执行;通常各绑 1 人 |
form_schema_json 控件类型可映射到未来移动端渲染(无端绑定死结)。sys_role。docs/中科兴皖需求V0.3.md §2.1.11openspec/changes/zkxw-engineering-standards/specs/workflow-conventions/spec.md(将后续修订)docs/web-admin-ui-spec-fresh-mint.mddocs/superpowers/specs/2026-05-13-workflow-module-design.md(废弃主路径)