Capture the approved OA form designer dept control contract (multi/single,
{id,name} path snapshot, mobile full-screen picker) and a Fresh Mint HTML demo.
Co-authored-by: Cursor <cursoragent@cursor.com>
7.1 KiB
7.1 KiB
OA「部门选择」控件设计文档
日期: 2026-07-27
范围: web-admin 审批设计器步骤 2(表单设计)+ 发起/详情运行时;backend 发布白名单已有 dept,补齐值形态校验与打印
状态: 已评审待实现
1. 背景与目标
OA 审批「2 表单设计」需提供可拖拽的 部门 控件,供发起人选择本租户组织树(sys_dept),与钉钉式「部门」及既有规格 docs/superpowers/specs/2026-07-14-oa-approval-dingtalk-design.md §4.5 / §4.6 对齐。
当前发布字典已允许 type: "dept",但设计器与运行时尚未落地自定义控件。
1.1 产品结论(已确认)
| 项 | 结论 |
|---|---|
| 选择能力 | 默认可多选;设计器属性可改为仅单选 |
| 存值 | 单选 { id, name };多选同结构数组 |
name |
全路径快照(分隔符 /) |
| 可选范围 | 任意层级均可选(非仅末级) |
| 实现路径 | 自定义 type=dept(对齐关联审批四层扩展);PC 用 el-tree-select |
| 移动兼容 | 窄屏禁止仅依赖宽屏下拉;须全屏/半屏选择器;Schema/form_data 双端同一份 |
1.2 非目标
- 行业通讯录部门
- 用本控件结果改写审批人解析(仍用发起人部门 /
oa_role等既有策略) - 本期实现小程序页面(但契约与交互必须可映射)
- 本控件「参与流程条件分支」(对象/多选不便进比较器;需要时二期单开)
2. 架构
对齐 FormCreate / FcDesigner 四层扩展(与「关联审批单」同路径):
| 层 | 内容 |
|---|---|
| Runtime | OaDeptSelect.vue:v-model 为对象或对象数组 |
| FormCreate 组件注册 | formCreate.component('dept', …) |
| DragRule | menu: 'main';name/label 为部门;props.multiple 默认 true |
| 双侧注册 | 主应用(发起/详情)+ oa-fc-host(设计器 iframe)均调用 setupOaDeptSelect |
数据源:现有 fetchDeptTree()(本租户组织树),不另造 API。
[设计器 DragRule] → form_schema_json.type = "dept"
↓
[OaDeptSelect] ← fetchDeptTree
↓
form_data[field] = { id, name } | { id, name }[]
↓
[后端发起校验] → 详情 / 打印优先展示 name 快照
3. Schema 与属性
3.1 规则形态(示例)
{
"type": "dept",
"field": "Fxxxx",
"title": "所属部门",
"info": "",
"$required": false,
"props": {
"multiple": true,
"max": null
}
}
3.2 设计器可配属性
| 属性 | 说明 |
|---|---|
| 标题 / 提示信息 / 必填 | 与现有控件一致 |
| 允许多选 | Switch,默认 true;false 时仅单选 |
| 最大可选数 | 可选;仅多选时生效;不填则不限制 |
树下拉节点文案:本级名称;选中后输入框 / 发起页 / 详情 / 打印:全路径(与 tree-path 约定一致)。
4. form_data 契约(锁定)
type DeptValueItem = {
id: string // sys_dept.id
name: string // 提交时全路径快照,如 "中科兴皖 / 研发中心 / 前端组"
}
// 单选(props.multiple === false)
type DeptFormValueSingle = DeptValueItem | null
// 多选(props.multiple === true,默认)
type DeptFormValueMulti = DeptValueItem[]
约束:
id、name均为非空字符串。- 禁止写入 DOM、组件实例、仅本级名却标注为全路径、或与
multiple不一致的标量/对象混用。 - 组织改名/调整后,历史实例 SHALL 仍展示提交时的
name快照;不强制按id重算路径。 - 后端 SHALL NOT 强制校验
id仍存在于当前组织树(允许已删/历史部门快照可读)。
本决定更新钉钉规格 §4.6 值类型表中「部门」一行的歧义:发布锁定为 { id, name } / 数组,不再使用裸 string deptId。
5. 运行时交互
5.1 PC(视口宽度 ≥ 768)
- 使用
el-tree-select(或等价树选)。 multiple跟随props.multiple。- 触发条/标签展示全路径;多选以 chip 展示,可删除单条。
5.2 窄屏 / 设计器手机预览(宽度 < 768)
对齐双端规格:「部门/省市区 → 移动端 全屏或半屏选择器,禁止依赖宽屏下拉才能选完」。
- 表单项为触发条(展示已选全路径或占位「请选择部门」)。
- 点击后打开 抽屉或全屏面板:搜索 + 组织树 +(多选)勾选 + 取消/确定。
- 未点「确定」前不写回
v-model。 - 与 PC 共用同一
v-model形态,仅交互壳不同。
5.3 只读
详情 / 审批页:仅展示路径文案(单选一个 name;多选多个 name 用中文顿号「、」拼接),不可打开选择器。
5.4 条件分支
dept 不注册「参与流程条件分支」开关;CONDITION_ELIGIBLE_TYPES 不包含 dept。
6. 校验
6.1 前端
- 必填:单选无值或
null;多选空数组 → 拦截提示。 - 多选且配置了
max:达到上限不可再选并提示。 - 窄屏面板未确认不算变更。
6.2 后端(发起 / 再次提交)
- 按 schema 遍历
type === "dept"。 - 单选:非必填允许缺省/
null;否则须为{ id, name }。 - 多选:须为数组;每项为
{ id, name };必填则length >= 1;有max则length <= max。 - 发布:
ALLOWED_CONTROL_TYPES已含dept,保持即可。
7. 打印与详情
- 单选:输出
name。 - 多选:多个
name用中文顿号「、」拼接。 - SHALL NOT 将对象 JSON 原样打印到纸面。
- 实现落点:
oa-approval-print(及详情只读渲染)对type === "dept"特判。
8. 主要改动面
| 区域 | 文件(预期) |
|---|---|
| Runtime | web-admin/src/components/oa-approval/OaDeptSelect.vue |
| DragRule | web-admin/src/utils/oa-dept-select-rule.ts |
| 注册 | web-admin/src/utils/oa-form-create-dept.ts;oa-fc-host/main.ts;主应用 form-create 注册点 |
| 打印 | web-admin/src/utils/oa-approval-print.ts |
| 后端校验 | backend/app/services/oa_publish.py 或发起校验模块中的 form_data 校验 |
| Demo(可选) | docs/mockups/oa-dept-select-demo.html 与实现对齐 |
9. 验收标准
- 「2 表单设计」左侧组件库出现「部门」,可拖入画布;属性可关闭多选。
- PC:树选可用;设计器切换手机预览(或窄视口)时可用半屏/全屏选完,不必依赖宽屏下拉。
- 提交后
form_data形态符合 §4;组织改名后旧实例仍显示快照路径。 - 含
dept的应用可发布;未知type仍拒绝。 - 无该控件的旧应用行为不变。
- 详情与打印展示人类可读路径,不出现原始 JSON。
10. 测试建议
- 单元:
form_data形态校验(单选/多选/必填/max)。 - 手工:设计器拖入 → 发起多选/单选 → 详情/打印;窄屏或手机预览走完选择;改部门名称后回看历史单。
11. 开放问题
无。若二期要做「部门字段参与条件分支」或小程序原生页,另开变更,不修改本节契约。