first commit

This commit is contained in:
2026-09-02 11:44:52 +08:00
commit 0c8fa2653e
309 changed files with 57278 additions and 0 deletions
@@ -0,0 +1,345 @@
# OA 审批表单控件参考
本文档详细描述钉钉 OA 审批中每种表单控件(componentName)在**发起审批实例**时 `formComponentValues``value` 格式、约束和注意事项。
> **核心原则:** `formComponentValues[].name` 必须与审批模板中控件的 `props.label` **完全一致**`value` 为字符串类型(最大 65535 字符)。
---
## 通用约束
| 约束 | 说明 |
|------|------|
| 单表单最大控件数 | 200 |
| label / placeholder 最大长度 | 50 字符 |
| value 最大长度 | 65535 字符 |
| ID / bizAlias 唯一性 | 同一表单内不可重复 |
| TextNote | 不收集数据,不出现在 formComponentValues 中 |
---
## 基础控件
### TextField(单行输入框)
| 属性 | 说明 |
|------|------|
| `componentName` | `TextField` |
| value 格式 | 纯文本字符串 |
| 示例 | `"测试内容"` |
| 约束 | 无特殊约束 |
```json
{ "name": "单行输入框", "value": "测试内容" }
```
### TextareaField(多行输入框)
| 属性 | 说明 |
|------|------|
| `componentName` | `TextareaField` |
| value 格式 | 纯文本字符串,支持换行 |
| 示例 | `"第一行\n第二行"` |
| 约束 | 无 `ratio` 属性 |
```json
{ "name": "多行输入框", "value": "第一行\n第二行\n第三行" }
```
### NumberField(数字输入框)
| 属性 | 说明 |
|------|------|
| `componentName` | `NumberField` |
| value 格式 | 数字字符串 |
| 示例 | `"100"` |
| 约束 | 适合数量、天数等纯数字场景 |
```json
{ "name": "加班天数", "value": "3" }
```
### DDSelectField(单选框)
| 属性 | 说明 |
|------|------|
| `componentName` | `DDSelectField` |
| value 格式 | 选项文本字符串 |
| 示例 | `"同意"` |
| 约束 | **必须与模板 `options[].value` 完全匹配**,不可自行编造选项 |
模板中的选项结构(从 `form-schema` 获取):
```json
"options": [
{ "key": "option_0", "value": "同意" },
{ "key": "option_1", "value": "不同意" }
]
```
提交时传选项的 `value` 文本:
```json
{ "name": "审批意见", "value": "同意" }
```
### DDMultiSelectField(多选框)
| 属性 | 说明 |
|------|------|
| `componentName` | `DDMultiSelectField` |
| value 格式 | JSON 数组字符串,每个元素为选项文本 |
| 示例 | `'["选项A","选项B"]'` |
| 约束 | 每个选项须与模板 `options[].value` 匹配; |
```json
{ "name": "兴趣爱好", "value": "[\"阅读\",\"运动\"]" }
```
### DDDateField(日期控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `DDDateField` |
| value 格式 | `yyyy-MM-dd` 格式字符串 |
| 示例 | `"2026-07-27"` |
| 约束 | 格式固定,不可传其他日期格式 |
```json
{ "name": "请假日期", "value": "2026-07-27" }
```
### DDDateRangeField(时间区间控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `DDDateRangeField` |
| value 格式 | JSON 数组字符串 `[开始日期, 结束日期]` |
| 示例 | `'["2026-07-27","2026-07-30"]'` |
| 约束 | `props.label` 为数组 `["开始时间","结束时间"]`;提交时 `name` 使用**开始时间的 label** |
模板中的 label 结构(从 `form-schema` 获取):
```json
"props": { "label": ["开始时间", "结束时间"] }
```
提交时用**开始时间 label** 作为 name
```json
{ "name": "开始时间", "value": "[\"2026-07-27\",\"2026-07-30\"]" }
```
### PhoneField(电话控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `PhoneField` |
| value 格式 | 手机号字符串 |
| 示例 | `"13800138000"` |
| 约束 | `mode: "phone"` 为手机号 |
```json
{ "name": "联系电话", "value": "13800138000" }
```
### IdCardField(身份证控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `IdCardField` |
| value 格式 | 身份证号字符串 |
| 示例 | `"330102199001011234"` |
| 约束 | 内置格式校验,须传合法身份证号 |
```json
{ "name": "身份证号", "value": "330102199001011234" }
```
### TextNote(文字说明)
| 属性 | 说明 |
|------|------|
| `componentName` | `TextNote` |
| value 格式 | — |
| 约束 | **不收集数据**,不出现在 formComponentValues 中 |
> 遇到 TextNote 控件时直接跳过,不要尝试为它填写值。
---
## 增强控件
### MoneyField(金额控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `MoneyField` |
| value 格式 | 数字字符串 |
| 示例 | `"1500.50"` |
| 约束 | 系统自动显示大写金额(`notUpper: "0"` 时显示) |
```json
{ "name": "报销金额", "value": "1500.50" }
```
### InnerContactField(联系人控件)
| 属性 | 说明 |
|------|----------------------------------------------------|
| `componentName` | `InnerContactField` |
| value 格式 | userId 字符串,多人时为 JSON 数组字符串 |
| 示例(单选) | `"user123"` |
| 示例(多选) | `'["userId1","userId2"]'` |
| 约束 | `choice: "0"` 单选 / `"1"` 多选;userId 须为**当前组织下在职成员** |
```json
{ "name": "项目负责人", "value": "[\"userId1\",\"userId2\"]" }
```
> **严禁直接写姓名。** 必须先通过 `dws aisearch person --query "<姓名>" --dimension name --format json` 查询获取 userId;多结果时须让用户消歧确认。
### DepartmentField(部门控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `DepartmentField` |
| value 格式 | 部门 ID 字符串,多部门时为 JSON 数组字符串 |
| 示例(单选) | `"12345"` |
| 示例(多选) | `'["12345","67890"]'` |
| 约束 | `multiple: boolean` 控制单选/多选;部门 ID 须为**当前组织下存在的部门** |
```json
{ "name": "所属部门", "value": "12345" }
```
### AddressField(省市区控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `AddressField` |
| value 格式 | JSON 数组字符串 `["省","市","区"]` |
| 示例 | `'["浙江省","杭州市","西湖区"]'` |
| 约束 | 三级联动选择器;`needDetail: true` 时末尾追加详细地址文本 |
```json
{ "name": "办公地点", "value": "[\"浙江省\",\"杭州市\",\"西湖区\"]" }
```
### DDPhotoField(图片控件)
> **支持通过图片 URL 提交,不支持本地文件上传。** 如果用户已有图片 URL(如公网可访问的图片链接),可直接填入 value 提交。CLI 尚未封装本地文件上传到钉盘 CDN 的流程,若用户只有本地文件而非 URL,需告知用户在钉钉客户端补充。
| 属性 | 说明 |
|------|------|
| `componentName` | `DDPhotoField` |
| value 格式 | URL 数组转义字符串,即使只有一个 URL 也需数组形式 |
| 示例 | `"[\"http://example.com/img1.jpg\",\"http://example.com/img2.jpg\"]"` |
| 约束 | 支持 URL 直接提交;**不支持本地文件上传**(CLI 未封装钉盘上传流程); |
```json
{ "name": "图片", "value": "[\"http://example.com/photo.jpg\"]" }
```
### DDAttachment(附件控件)
> **[支持] 已支持通过 CLI 提交附件控件。** 采用两步流程:先用 `dws oa approval attachment upload --file <path>` 上传本地文件,获取 spaceId、fileName、fileSize、fileType、fileId;再将这些字段组装为 DDAttachment valueJSON 数组转义字符串)随 `create-instance` 提交。
| 属性 | 说明 |
|------|------|
| `componentName` | `DDAttachment` |
| value 格式 | JSON 数组转义字符串,每个元素包含 spaceId、fileName、fileSize、fileType、fileId |
| 示例(参考) | `"[{\"spaceId\":\"163xxx\",\"fileName\":\"2644.JPG\",\"fileSize\":\"333\",\"fileType\":\"jpg\",\"fileId\":\"643xxx\"}]"` |
| 约束 | **支持通过 CLI 提交**;先用 `dws oa approval attachment upload --file <path>` 获取 spaceId、fileName、fileSize、fileType、fileId,再组装为 value 随 `create-instance` 提交 |
### StarRatingField(评分控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `StarRatingField` |
| value 格式 | 数字字符串 |
| 示例 | `"4"` |
| 约束 | `limit` 控制最大星数(默认 5 |
```json
{ "name": "满意度评分", "value": "4" }
```
### RelateField(关联审批单)
| 属性 | 说明 |
|------|------|
| `componentName` | `RelateField` |
| value 格式 | 审批实例 ID 字符串 |
| 示例 | `"q-ZZ1sQaTIuYFpKI9aNC1g"` |
| 约束 | 须为**当前组织下已存在的审批实例 ID** |
```json
{ "name": "关联审批单", "value": "q-ZZ1sQaTIuYFpKI9aNC1g" }
```
### SignatureField(签名控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `SignatureField` |
| value 格式 | 签名图片 mediaId |
| 约束 | 需要客户端交互签名,通常不支持 API 直接提交 |
---
## 复合控件
### TableField(明细控件)
| 属性 | 说明 |
|------|------|
| `componentName` | `TableField` |
| value 格式 | JSON 数组字符串,每个元素为一行数据的键值对 |
| 示例 | `'[{"商品名":"笔记本","数量":"2"},{"商品名":"钢笔","数量":"1"}]'` |
| 约束 | **不可嵌套 TableField****不可包含 DDMultiSelectField 和 DDPhotoField**;最大 100 行;总长度不超过 65535 字符 |
模板结构(从 `form-schema` 获取):
```json
{
"componentName": "TableField",
"props": { "label": "采购明细" },
"children": [
{ "componentName": "TextField", "props": { "label": "商品名", "id": "TextField_XXX" } },
{ "componentName": "NumberField", "props": { "label": "数量", "id": "NumberField_YYY" } }
]
}
```
提交时每行用子控件 label 作 key:
```json
{
"name": "采购明细",
"value": "[{\"商品名\":\"笔记本\",\"数量\":\"2\"},{\"商品名\":\"钢笔\",\"数量\":\"1\"}]"
}
```
---
## API 不支持的控件
以下控件**不支持**通过创建实例 API 提交,遇到时应告知用户需在钉钉客户端补充:
| 控件 | componentName | 原因 |
|------|---------------|------|
| 文字说明 | `TextNote` | 纯展示,不收集数据 |
| 计算公式 | `CalculateField` | 由系统自动计算,不可手动填写 |
| 流水号 | `SeqNumberField` | 由系统自动生成 |
| OCR 文本识别 | `OcrTextField` | 需要客户端 OCR 交互 |
| OCR 身份证识别 | `OcrIdCardField` | 需要客户端 OCR 交互 |
> **部分支持的控件:** `DDPhotoField`(图片控件)**支持通过 URL 直接提交**,但不支持本地文件上传(CLI 未封装钉盘 CDN 上传流程)。若用户只有本地文件,需告知在钉钉客户端补充。详见本文 [DDPhotoField](#ddphotofield图片控件) 章节。
> **套件类控件(暂不支持)** — `InvoiceField`(发票)、`RecipientAccountField`(收款账户)等业务套件控件当前暂不支持通过 CLI 发起,包含这些控件的审批模板请直接在钉钉客户端操作。
---
## 组装优先级
1. **每次发起前都重新调用 `form-schema`**,不得复用旧结果(模板可能已被修改)
2. 先读 `form-schema` 返回的 `content`,识别所有控件的 `label``componentName``options``props.required`
3. **检查是否存在不支持控件且为必填项(`props.required: true`**,若有则直接告知用户该模板不支持通过 CLI 发起,请在钉钉客户端操作
4. 按本文档中每种控件的 value 格式组装 `formComponentValues`
5. **不要把 `form-schema` 的 `content` 当成可直接提交的模板**
6. 遇到 API 不支持的控件(非必填),跳过并告知用户
@@ -0,0 +1,374 @@
# OA 审批流程节点与审批人规则参考
本文档描述钉钉 OA 审批的流程节点类型、审批模式、条件分支和审批人选择规则,用于理解审批模板结构和正确填写 `create-instance` 的节点参数。
---
## 流程结构概览
审批流程是一个嵌套树结构:
- **根节点**:发起人节点(`type: "start"``nodeId: "sid-startevent"`),固定不可删除
- **后续节点**:通过 `childNode` 链接形成链式结构
- **分支节点**:条件分支(`route` + `condition`)或并行分支(`parallel`
- 当没有后续节点时,`childNode` 字段**必须省略**(不可设为 `null`
---
## 7 种节点类型
### 1. 发起人节点(start
| 属性 | 值 |
|------|-----|
| `type` | `start` |
| `nodeId` | `sid-startevent`(固定) |
| `properties` | `{}`(空对象) |
唯一、不可删除。是流程的起点。
### 2. 审批人节点(approver
核心决策节点,有审批/拒绝权限。
| 属性 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `actionerRules` | Array | 是 | 审批人选择规则,至少一条 |
| `activateType` | String | 是 | 多人审批模式(见下方) |
| `approvalType` | String | 是 | 固定 `"MANUAL"` |
| `agreeAll` | Boolean | 是 | `true` 全部通过 / `false` 任一通过 |
| `noneActionerAction` | String | 否 | 如 `"admin"`(找不到审批人时转管理员) |
支持全部 10 种 actionerRules 类型。
### 3. 办理人节点(handler
执行工作,无审批决策权。
| 属性 | 类型 | 必填 |
|------|------|------|
| `actionerRules` | Array | 是 |
| `activateType` | String | 是 |
支持 9 种 actionerRules(不支持 `target_matrix_approval`)。
### 4. 抄送人节点(notifier
仅接收通知,无决策权。
| 属性 | 类型 | 必填 |
|------|------|------|
| `actionerRules` | Array | 是 |
支持多条 actionerRules 组合在一个节点中,实现同时抄送多类人员。
### 5. 条件分支(route + condition
条件路由节点,包含多个条件分支。
**route 节点:**
- `type: "route"`
- `conditionNodes[]`:分支数组,按优先级排序,**默认分支必须在最后**
- `properties: {}`
**condition 节点(conditionNodes 的每个元素):**
- `type: "condition"`
- `isdefault: true`:标记默认分支
- `properties.conditions`:二维条件数组
- 外层数组:多个条件组,**OR 关系**
- 内层数组:多个条件对象,**AND 关系**
- 默认分支:`[[]]`(一个空组)
### 6. 并行分支(parallel
多个分支同时执行,全部完成后才继续。
| 属性 | 说明 |
|------|------|
| `branches[]` | 分支数组 |
| `branches[].name` | 分支名称 |
| `branches[].childNode` | 该分支的第一个节点 |
### 7. 付款人节点(payer
财务付款节点。
| 属性 | 说明 |
|------|------|
| `actionerRules` | 审批人规则 |
| `paymentConfig.amountField` | 金额控件 ID |
| `paymentConfig.accountField` | 收款账户控件 ID |
---
## 多人审批模式
| 模式 | `activateType` | `agreeAll` | 说明 |
|------|---------------|-----------|------|
| 会签 | `"ALL"` | `true` | 所有审批人都必须审批通过 |
| 或签 | `"ALL"` | `false` | 任一审批人审批即可 |
| 依次审批 | `"ONE_BY_ONE"` | `true` | 按顺序逐级审批 |
---
## 10 种审批人选择规则(actionerRules
### 1. 指定成员(target_approval
明确指定具体人员。
```json
{
"type": "target_approval",
"approvals": [
{ "userName": "张三", "workNo": "manager123" }
],
"isEmpty": false
}
```
- `workNo` 必须通过 `dws aisearch person --query "<工号>" --dimension jobNumber --format json` 获取,**严禁编造**
-`create-instance` 中对应 `directAppointedApprovers``staffIds`
### 2. 直属主管(target_formula / reportLineManager
按汇报线找到直属主管。
```json
{
"type": "target_formula",
"subType": "reportLineManager",
"formula": "ReportLineManager(corpId,originator,1)",
"isEmpty": false
}
```
- `formula` 中最后的数字 N 表示第 N 级主管
- **重要区分:** 用户说"直属主管/直属领导/汇报线主管"才用此规则;用户说"主管审批/leader审批"(模糊)时默认用 `target_management`(部门主管)
### 3. 发起人自己(target_originator
发起人自行审批。
```json
{
"type": "target_originator",
"isEmpty": false
}
```
最简单的规则,只有 `type``isEmpty`
### 4. 部门主管(target_management
从发起人所在部门层级找主管。
```json
{
"type": "target_management",
"level": 1,
"autoUp": true,
"isEmpty": false
}
```
- `level: 1`:直接部门主管
- `autoUp: true`:找不到时向上级部门搜索
- **这是"主管审批/leader审批"模糊场景的默认选择**
### 5. 表单部门主管(target_formula / managerOfDept
根据表单中部门控件选择的主管。
```json
{
"type": "target_formula",
"subType": "managerOfDept",
"formula": "ManagerOfDept(corpId,$('DepartmentField_XXX'),1)",
"isEmpty": false
}
```
- `formula` 中引用表单中的 `DepartmentField` 控件 ID
### 6. 发起人自选(target_select
发起人在提单时自行选择审批人。
```json
{
"type": "target_select",
"select": ["allStaff"],
"range": {},
"key": "manual_nodeId_xxxx_yyyy",
"multi": 1,
"isEmpty": false
}
```
- `select: ["allStaff"]`:可选全组织人员
- `multi: 1`:单选
- `key`:格式 `manual_{nodeId}_{hex}_{hex}`
-`create-instance` 中对应 `targetSelectActioners``actionerKey`
### 7. 角色标签主管(target_managers_labels
按角色标签找多级主管。
```json
{
"type": "target_managers_labels",
"labelNames": ["项目经理"],
"labels": ["labelId123"],
"levels": [1],
"isEmpty": false
}
```
- `labels` 中的 ID 必须通过 `dws contact label get --names "<角色名>" --format json` 获取;已知角色名时直接查询,否则先 `dws contact label list --format json` 获取全部角色列表后匹配
### 8. 表单联系人(target_formcomponent_approval
从表单中的联系人控件读取审批人。
```json
{
"type": "target_formcomponent_approval",
"paramKey": "InnerContactField_XXX",
"label": "项目负责人",
"isEmpty": false
}
```
- `paramKey` 指向表单中的 `InnerContactField` 控件 ID
- 该控件中填写的人即为审批人
### 9. 角色标签(target_label
按角色标签找人(如"财务"、"HR")。
```json
{
"type": "target_label",
"labelNames": "财务",
"labels": "459272424",
"isEmpty": false
}
```
- `labels`:角色标签 ID(字符串),必须通过 `dws contact label get --names "<角色名>" --format json` 获取;未知角色名时先 `dws contact label list --format json`
- `labelNames`:角色显示名称
- **严禁编造 label ID**
### 10. 审批矩阵(target_matrix_approval
按审批矩阵规则确定审批人。
```json
{
"type": "target_matrix_approval",
"matrixId": "xxx",
"roleColumnId": "yyy",
"expression": {
"subFilters": [...],
"operator": "AND"
}
}
```
- 仅适用于审批人节点
- 目前尚在完善中
---
## 条件分支详解
### 条件类型
| `type` | 依据 | 关键字段 |
|--------|------|---------|
| `dingtalk_actioner_dept_condition` | 发起人部门/人员/角色 | `paramKey: "dingtalk_origin_dept"`, `conds[]` |
| `dingtalk_actioner_dept_component_condition` | 表单部门控件 | `paramKey: 控件ID`, `conds[]` |
| `dingtalk_actioner_range_condition` | 数值/金额/时长范围 | `lowerBound`(>=) / `lowerBoundNotEqual`(>) / `upperBoundEqual`(<=) / `upperBound`(<) / `boundEqual`(=) |
| `dingtalk_actioner_value_condition` | 单选匹配 | `paramKey: 控件ID`, `paramValues[]`(选项 key |
| `dingtalk_multi_value_condition` | 多选匹配 | `paramKey: 控件ID`, `paramValues[]`, `matchType`(1=精确/2=全选/3=任一) |
| `dingtalk_actioner_cascade_component_condition` | 级联控件 | `paramValues[]`, `displayValues[]` |
| `dingtalk_actioner_boolean_condition` | 布尔值 | `boundEqual: true/false` |
| `dingtalk_rule_template` | 节假日判断 | `template`, `outVars` |
| `dingtalk_formula` | 公式 | `formula`, `formulaDisplay` |
| `dingtalk_biz_var_condition` | 业务变量 | `dsKey`, `conds[]` |
| `dingtalk_table_condition` | 明细内字段 | `parentFieldId`, `componentName`, `paramValue` |
### 范围条件操作符
| 字段 | 含义 |
|------|------|
| `lowerBound` | >= (大于等于) |
| `lowerBoundNotEqual` | > (大于) |
| `upperBoundEqual` | <= (小于等于) |
| `upperBound` | < (小于) |
| `boundEqual` | = (等于) |
### 默认分支
- `isdefault: true`
- `conditions: [[]]`(一个空的条件组)
- **必须放在 `conditionNodes[]` 的最后**
---
## create-instance 中的节点参数映射
### directAppointedApprovers(指定审批人覆盖模板流程)
当需要**不使用模板默认流程、直接指定审批人**时使用。
```json
{
"directAppointedApprovers": [
{
"staffIds": ["userId1", "userId2"],
"taskActionType": "NONE",
"staffId": ""
}
]
}
```
| 字段 | 说明 |
|------|------|
| `staffIds` | 审批人 userId 列表(通过 `dws aisearch person --query "<姓名>" --dimension name --format json` 获取;多结果须消歧) |
| `taskActionType` | `NONE`(单人)/ `AND`(会签)/ `OR`(或签) |
| `staffId` | 留空字符串 |
### targetSelectActioners(自选审批人)
当模板流程中存在**自选审批节点**`target_select` 类型)时必填。
```json
{
"targetSelectActioners": [
{
"actionerKey": "manual_nodeId_xxxx_yyyy",
"actionerStaffIds": ["userId1"]
}
]
}
```
| 字段 | 说明 |
|------|------|
| `actionerKey` | 自选节点的规则 key,从审批流程节点信息接口获取 `actorKey` |
| `actionerStaffIds` | 操作人 userId 列表 |
---
## 组装优先级
1. 先用 `forecast-process` 获取模板的流程节点结构(`workflowActivityRuleVOs`
2. 根据节点中的 `activityType``targetSelect` 判断是否需要传入 `directAppointedApprovers``targetSelectActioners`
3. 如果预测返回 `targetSelect: true` 的自选节点,`targetSelectActioners` 必填
4. 如果用户要求覆盖默认流程,使用 `directAppointedApprovers`
5. **所有 userId 必须通过 `dws aisearch person --query "<姓名>" --dimension name --format json` 获取,严禁填姓名;多结果须消歧**
> **交互优化:** 若用户在 `forecast-process` 前已指定审批人/抄送人姓名,`forecast-process` 返回自选节点后应自动映射,仅对未覆盖的自选节点追问,不要重复询问。详见 [oa.md](../oa.md) 交互优化原则。