七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s

This commit is contained in:
2026-07-25 17:06:58 +08:00
parent ad9f613dd6
commit 73f5125d3d
249 changed files with 17137 additions and 877 deletions

View File

@@ -0,0 +1,202 @@
# 企业微信审批官方接口调研
> 调研范围:企业微信开发者中心官方文档
> 访问日期2026-07-24
> 结论口径:文中“官方明确”均来自企业微信官方页面;“建议”是基于官方约束形成的系统接入方案,不代表企业微信额外承诺。
## 一、结论摘要
1. 管理员手工绑定系统账号与企业微信成员是可行的。系统应保存企业标识与 `userid` 的绑定关系,并用姓名、部门辅助管理员辨认。`userid` 是企业内唯一、对应管理端账号的成员标识;手机号和邮箱属于敏感字段,不能假定一定能取得,也不应作为唯一绑定依据。[读取成员][1]
2. 审批模板通常可以在企业微信管理后台维护,模板 ID 可从模板编辑页 URL、审批回调或审批详情取得系统再调用“获取审批模板详情”读取控件 ID、类型、必填属性和选项 key。自建应用和代开发应用也可以通过接口创建模板因此“模板只能由管理员在后台创建”的设想不成立但第三方应用不支持创建模板接口。[获取审批模板详情][6] [创建审批模板][7]
3. 系统发起审批时,必须使用已绑定且位于应用可见范围内的申请人 `userid`,提交模板 ID、审批流程选择、控件值和摘要。附件须先上传为临时素材再将返回的 `media_id` 作为附件控件的 `file_id` 提交。[提交审批申请][8] [上传临时素材][9]
4. 审批结果同步不能只依赖回调。官方明确说明回调不能保证 100% 成功,应采用“回调实时处理 + 批量获取审批单号 + 获取审批详情”的主动补偿机制。[回调配置][12] [批量获取审批单号][11] [获取审批申请详情][10]
5. 上线前必须具备正确应用 Secret、按应用缓存的 `access_token`、审批接口权限、应用可见范围、可信 IP以及可完成签名校验和 AES 解密的回调服务。[开发前必读][15] [获取 access_token][14] [审批状态变化回调][13]
## 二、通讯录能力与手工绑定方案
### 2.1 官方接口能取得什么
| 信息 | 官方能力 | 主要限制 |
| --- | --- | --- |
| `userid` | “读取成员”返回成员标识;“获取部门成员/详情”可按部门返回成员;“获取成员 ID 列表”可分页返回 `userid` 与部门 ID 关系 | 只能读取应用可见范围;“获取成员 ID 列表”只支持“通讯录同步 secret”调用。[读取成员][1] [获取部门成员][2] [获取成员 ID 列表][4] |
| 姓名 | 自建应用可在权限范围内通过成员接口取得;代开发自建应用需要管理员授权 | 第三方应用通常不能直接取得真实姓名,接口可能以 `userid` 代替,需要使用通讯录展示组件。[读取成员][1] |
| 部门 | 成员接口返回部门 ID部门成员接口也返回成员所属部门列表 | 只返回应用有查看权限的部门;要取得部门名称还需结合部门列表接口。成员授权模式下,部门信息还可能固定为根部门。[读取成员][1] [获取部门列表][5] |
| 手机号、邮箱 | 接口字段存在;自建应用与代开发应用可在满足授权条件后获取 | 2022-06-20 之后新建的自建应用和代开发应用,敏感字段需管理员在应用详情选择,并由成员通过 OAuth2 授权;第三方应用不可通过“获取访问用户敏感信息”取得手机、邮箱。[读取成员][1] [获取访问用户敏感信息][3] |
`userid` 对应企业微信管理端账号,在企业内必须唯一、不区分大小写,长度为 164 字节。对于企业内部自建应用,建议将 `(corp_id, userid)` 作为企业微信身份键;不要仅保存姓名,也不要用手机号或邮箱充当稳定主键。[读取成员][1]
### 2.2 推荐的管理员手工绑定流程
1. 为企业微信自建应用配置足够但最小化的通讯录可见范围。
2. 系统按部门拉取可见成员,向管理员展示 `userid`、姓名和部门。若使用通讯录同步能力,可用“获取成员 ID 列表”分页取得完整 `userid`/部门关系;该接口不能用普通应用 Secret 替代通讯录同步 Secret。[获取部门成员详情][2] [获取成员 ID 列表][4]
3. 管理员在系统账号页面选择一个企业微信成员,系统保存系统账号 ID、企业 ID、`userid`,并保存姓名/部门快照用于展示和审计。
4. 发起审批前再次确认绑定仍有效,且该成员仍在审批调用应用的可见范围内;否则“提交审批申请”会因无权限或提单者不可见失败。[提交审批申请][8]
5. 手机号、邮箱只能作为获得成员明确授权后的辅助核对信息。没有敏感字段时,绑定流程仍应可完成。[获取访问用户敏感信息][3]
此方案是“管理员明确选择并绑定”,不是依据姓名、手机号自动猜测成员。重名、敏感字段缺失和通讯录权限变化都使自动匹配存在误绑风险。
## 三、审批模板与控件配置
### 3.1 模板从哪里来
企业微信提供两条路径:
- 管理后台创建和维护:模板 ID 可从模板编辑页面的浏览器 URL 取得,也会出现在审批状态回调和审批详情中。[获取审批模板详情][6]
- 接口创建:自建应用需被配置到“审批 - 可调用接口的应用”,代开发应用需具有“审批”权限;第三方应用暂不支持。创建成功后,管理后台和审批应用内会生成对应模板,并生效默认流程和规则配置。[创建审批模板][7]
因此,本项目若由客户企业管理员掌控流程,优先采用“后台建模板 + 系统配置模板 ID”若模板由平台标准化交付且应用权限满足要求可以评估调用创建模板接口。系统不应假定存在“列出企业全部模板”的接口官方“获取审批模板详情”要求调用方已知 `template_id`。[获取审批模板详情][6]
### 3.2 系统应如何配置控件
配置模板 ID 后,系统调用:
```text
POST https://qyapi.weixin.qq.com/cgi-bin/oa/gettemplatedetail?access_token=ACCESS_TOKEN
{"template_id":"TEMPLATE_ID"}
```
返回的 `template_content.controls` 包含:
- `property.control`:控件类型,如 `Text``Money``Date``Selector``Contact``File``Table` 等;
- `property.id`:提交审批时必须使用的控件唯一 ID
- `property.title``placeholder`:控件名称和填写说明;
- `property.require`:是否必填;
- `config`:日期精度、单/多选、成员/部门模式、明细子控件等配置;
- 选择控件的 `options[].key`:提交选择值时使用的稳定选项键。[获取审批模板详情][6]
建议系统保存“业务字段 → 控件 ID/类型/选项 key”的显式映射并在保存配置及发起审批前校验模板结构。不能仅按控件中文标题赋值因为提交接口以控件 ID 和选项 key 为准,管理员修改模板后原映射可能失效。
## 四、发起审批申请
### 4.1 请求与关键字段
接口为:
```text
POST https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent?access_token=ACCESS_TOKEN
```
核心字段如下:[提交审批申请][8]
| 字段 | 含义与约束 |
| --- | --- |
| `creator_userid` | 申请人 `userid`;审批将以该员工身份提交,且申请人必须在应用可见范围内 |
| `template_id` | 审批模板 ID |
| `use_template_approver` | `0` 表示接口通过 `process` 指定审批人/抄送人;`1` 表示使用后台模板流程 |
| `choose_department` | 提单部门 ID不填时默认主部门 |
| `process.node_list` | 接口指定流程时必填;节点类型可为审批人、抄送人、办理人,并配置人员及多人处理方式 |
| `apply_data.contents` | 控件赋值数组,每项必须携带 `control``id``value`;模板必填控件必须有值 |
| `summary_list` | 审批通知卡片和审批列表摘要,最多 3 行,每行文字不超过 20 个字符 |
`use_template_approver=1`,后台审批流程中不能存在“申请人自选”节点。若为 `0``process` 必填。接口当前不支持提交“打卡补卡”“调班”模板审批单。[提交审批申请][8]
不同控件的 `value` 结构不同,例如文本使用 `text`,金额使用 `new_money`,日期使用 `date`,选择控件使用 `selector.options[].key`,成员控件使用 `members[].userid`,部门控件使用 `departments[].openapi_id`。具体结构必须同时服从模板详情和提交接口附录,不能用一个通用字符串值替代。[获取审批模板详情][6] [提交审批申请][8]
提交成功返回审批单号 `sp_no`,系统应立即将其与本地业务单据关联,作为后续回调去重、详情查询和补偿对账的关键标识。[提交审批申请][8]
### 4.2 附件
附件需先调用临时素材上传接口:
```text
POST https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=file
Content-Type: multipart/form-data
```
上传结果中的 `media_id` 仅 3 天有效;提交附件控件时将其写入 `value.files[].file_id`。审批提单后,企业微信会将其转换为长期文件。单个审批申请全局最多支持 6 个附件;普通文件上传上限为 20 MB且所有文件必须大于 5 字节。[上传临时素材][9] [提交审批申请][8]
## 五、审批结果回传与主动补偿
### 5.1 状态变化回调
审批回调事件名为 `sys_approval_change`。回调包含 `SpNoStr``SpStatus``TemplateId`、申请人、流程节点、备注及 `StatuChangeEvent` 等信息。官方推荐使用字符串字段 `SpNoStr` 代替原有数值字段 `SpNo`。[审批状态变化回调][13]
申请单状态包括审批中、已通过、已驳回、已撤销、通过后撤销、已删除、已支付;状态变化类型还覆盖提单、同意、驳回、转审、催办、撤销、添加备注、退回、加签、办理和转交等。[审批状态变化回调][13]
回调处理建议:
1. 校验签名并解密消息;验证解密后的 `receiveid` 与企业 `corpid` 一致。[加解密方案][16]
2. 持久化必要的接收记录并快速应答,把详情拉取和业务状态更新交给异步任务。
3.`SpNoStr` 查询“获取审批申请详情”,以详情中的最终状态、流程和表单值更新本地数据,而不是仅依赖一次回调载荷。[获取审批申请详情][10]
4. 业务处理必须幂等。企业微信在网络失败或超时时会重试,且状态变化可能多次发生;本地应允许同一审批单重复对齐到最新详情。
企业微信服务器在 5 秒内未收到响应会断开连接并重新发起请求,总共重试 3 次,但仅针对网络连接失败或超时。官方同时明确说明无法保证 100% 回调成功,并建议不要强依赖回调、增加额外机制对齐业务数据。[回调配置][12]
### 5.2 主动查询与轮询补偿
补偿链路使用两个接口:
1. “批量获取审批单号”按审批单提交时间范围拉取 `sp_no_list`,可按模板 ID、申请人、部门、审批状态筛选单次最多 100 条,通过 `new_cursor`/`new_next_cursor` 分页。时间跨度不能超过 31 天,频率上限 600 次/分钟。[批量获取审批单号][11]
2. 对每个审批单号调用“获取审批申请详情”,取得 `sp_status`、模板、申请人、流程、表单控件值、备注和附件等完整信息;频率上限同样为 600 次/分钟。[获取审批申请详情][10]
建议定时任务按模板 ID 拉取最近时间窗,并保留重叠回看区间,以覆盖任务延迟、分页中断和回调丢失;本地以 `sp_no` 幂等更新。时间窗应以“提交时间”理解,因为批量接口的 `starttime`/`endtime` 定义为审批单提交时间,而不是最后状态更新时间。因此,对仍处于审批中的历史单据,还应单独维护待终态集合并周期性查询详情,不能只扫描最近新提交的单据。[批量获取审批单号][11]
## 六、接入前置条件
### 6.1 凭证与权限
- `access_token` 必须由后端使用企业 ID 和正确应用 Secret 获取,禁止返回给前端。每个应用的 Secret 和 Token 相互独立,必须按应用分别缓存。[获取 access_token][14]
- Token 正常有效期为 7200 秒,但可能提前失效;系统需按 `expires_in` 缓存,并在失效时重新获取,不能高频调用获取接口。[获取 access_token][14]
- 自建应用必须配置到“审批 - 可调用接口的应用”;代开发应用和第三方应用必须具有“审批”权限。提交人还必须在应用可见范围内。[获取审批模板详情][6] [提交审批申请][8]
- 自 2023-12-01 起,审批接口不再支持通过系统应用 Secret 调用,存量企业暂不受影响;新接入不能依赖系统应用 Secret。[获取审批模板详情][6]
- 2022-06-20 之后新开启的通讯录同步助手及新创建的自建应用,必须在管理端配置可信 IP只有配置的 IP 才能调用接口。[开发前必读][15]
### 6.2 回调服务
自建应用需在应用详情的“设置 API 接收”中配置 `URL``Token``EncodingAESKey`,并打开审批状态通知事件;其中 Token 用于签名43 位 `EncodingAESKey` 用于消息体加密。[审批状态变化回调][13] [回调配置][12]
回调端点必须同时支持:
- `GET`:校验 `msg_signature`,解密 `echostr`,在 1 秒内原样返回明文且不能带引号、BOM 或换行;
- `POST`:校验签名,解密 XML 中的 `Encrypt`,处理明文事件并正确响应;
- AES-256-CBC、PKCS#7 填充、签名计算及 `receiveid` 校验。官方提供 Go 等语言的加解密库,宜优先使用官方库。[回调配置][12] [加解密方案][16]
如防火墙按来源 IP 放行,可调用官方回调 IP 接口获取网段。官方提示 IP 段可能变化,建议每天定时拉取并更新防火墙。[回调配置][12]
## 七、不成立或存在明确限制的设想
| 设想 | 官方结论 |
| --- | --- |
| 只要能调审批接口,就一定能读取全企业通讯录 | 不成立。通讯录接口受应用可见范围、通讯录权限和 Secret 类型限制;审批权限不等于全通讯录权限。[读取成员][1] [获取成员 ID 列表][4] |
| 总能取得员工手机号或邮箱,用它自动匹配系统账号 | 不成立。新自建/代开发应用需管理员选择敏感字段并获得成员 OAuth2 授权;第三方应用还存在更严格限制。[获取访问用户敏感信息][3] |
| `userid` 可以跨企业直接当全局用户 ID | 不成立。官方定义的是企业内唯一;本地应与企业 ID 组合存储。第三方应用的成员接口还可能返回 `open_userid`。[读取成员][1] |
| 审批模板只能在企业微信后台人工创建 | 不成立。自建和代开发应用可调用创建模板接口;但第三方应用暂不支持。[创建审批模板][7] |
| 系统可以不保存模板 ID启动时自动枚举全部模板 | 官方“获取模板详情”接口要求已知 `template_id`,官方给出的来源是编辑页 URL、回调、审批详情或创建接口返回值不能据此假定存在全量模板枚举能力。[获取审批模板详情][6] [创建审批模板][7] |
| 修改模板控件标题不会影响系统提交 | 有限制。提交依赖控件 `id`、类型及选择项 `key`,不是只按标题匹配;模板变化后应重新校验映射。[获取审批模板详情][6] [提交审批申请][8] |
| 使用后台模板流程时,任何流程配置都能直接发起 | 不成立。`use_template_approver=1` 时,后台流程不能含“申请人自选”节点。[提交审批申请][8] |
| 所有审批模板都能通过接口发起 | 不成立。官方明确暂不支持“打卡补卡”“调班”模板。[提交审批申请][8] |
| 回调成功配置后可保证每次审批变化都送达一次 | 不成立。官方明确无法保证 100% 回调成功,超时重试也仅有限次数;必须主动补偿并实现幂等。[回调配置][12] |
| 回调就是完整审批详情,不需要再查询 | 有限制。状态回调提供状态和流程信息;完整表单控件值以“获取审批申请详情”为准。[审批状态变化回调][13] [获取审批申请详情][10] |
| 上传得到的附件 ID 可长期暂存,审批单附件数量不限 | 不成立。临时素材 `media_id` 仅 3 天有效,单个审批申请全局最多 6 个附件。[上传临时素材][9] [提交审批申请][8] |
| 可继续使用系统应用 Secret 接入新企业 | 不成立。审批接口自 2023-12-01 起不再支持系统应用 Secret只有存量企业暂不受影响。[获取审批模板详情][6] |
## 八、建议的最小接入闭环
1. 企业管理员创建并启用自建应用,配置应用可见范围、审批可调用应用、可信 IP、回调 URL/Token/EncodingAESKey。
2. 系统按应用维度安全保存 Secret并在后端缓存 `access_token`
3. 管理员通过可见成员列表,把本地账号绑定到 `(corp_id, userid)`
4. 管理员填写模板 ID系统拉取模板详情保存并校验业务字段与控件 ID/选项 key 的映射。
5. 发起审批时使用已绑定 `userid`;附件即时上传后随审批提交;保存返回的 `sp_no`
6. 回调服务验签解密、快速应答并异步按 `sp_no` 拉取详情,幂等更新本地业务状态。
7. 定时通过“批量获取审批单号 + 获取审批申请详情”补偿回调遗漏,同时周期性刷新未终态审批单。
## 九、官方资料
以下页面均为企业微信开发者中心官方文档,访问日期均为 **2026-07-24**
[1]: https://developer.work.weixin.qq.com/document/path/90196 "读取成员"
[2]: https://developer.work.weixin.qq.com/document/path/90201 "获取部门成员详情"
[3]: https://developer.work.weixin.qq.com/document/path/95833 "获取访问用户敏感信息"
[4]: https://developer.work.weixin.qq.com/document/path/96067 "获取成员ID列表"
[5]: https://developer.work.weixin.qq.com/document/path/90208 "获取部门列表"
[6]: https://developer.work.weixin.qq.com/document/path/91982 "获取审批模板详情"
[7]: https://developer.work.weixin.qq.com/document/path/97437 "创建审批模板"
[8]: https://developer.work.weixin.qq.com/document/path/91853 "提交审批申请"
[9]: https://developer.work.weixin.qq.com/document/path/90253 "上传临时素材"
[10]: https://developer.work.weixin.qq.com/document/path/91983 "获取审批申请详情"
[11]: https://developer.work.weixin.qq.com/document/path/91816 "批量获取审批单号"
[12]: https://developer.work.weixin.qq.com/document/path/90930 "回调配置"
[13]: https://developer.work.weixin.qq.com/document/path/91815 "审批申请状态变化回调通知"
[14]: https://developer.work.weixin.qq.com/document/path/91039 "获取access_token"
[15]: https://developer.work.weixin.qq.com/document/path/90664 "开发前必读"
[16]: https://developer.work.weixin.qq.com/document/path/90968 "加解密方案说明"