新增模块的接口地址为:
POST /api/changguchuan/seal/approval-complete
GET /api/changguchuan/seal/health
新增接口:POST /api/changguchuan/seal/approval-records。只需传业务表单的宜搭数据 ID,不需要传审批人、审批时间、节点或模板 URL:
{
"formInstanceId": "FINST-实际业务数据ID"
}
也支持 query 参数 formInstanceId,以及 formInstId、instanceId、processInstanceId 同义字段。
如果已设置 SEAL_CONNECTOR_TOKEN,同样需要请求头 X-Seal-Connector-Token。
处理范围固定为以下用户指定的表单和字段:
| 用途 | 表单 / 字段 |
|---|---|
| 业务审批表单 | FORM-64A9D5065C234383AB2ACF7AB4F20975DW6M |
| 审批人个人模板表单 | FORM-EADCA8349AB34236A8873ECA7BCFBE7CDMG4 |
| 模板人员字段 | employeeField_mv7hjsv3,按审批人的钉钉 userId 精确匹配 |
| 模板图片字段 | imageField_mubc5ugk |
| 回写子表 | tableField_mv7h9ypq |
| 子表节点名称 | textField_mv7h9yps |
| 子表填表人 | textField_mvafdu7s,发起人或当前节点审批人名称,与返回值 approverName 一致 |
| 子表时间戳印章 | imageField_mv7h9ypr,图片对象数组 |
接口先通过 v2.0 流程实例详情取得真实 processInstanceId 并验证所属表单,再通过
GetOperationRecords(/v1.0/yida/processes/operationRecords)获取审批历史。
首行固定生成一条发起人印章:按流程实例 originator.userId 匹配个人模板,姓名优先取
originator.name.nameInChinese,为空时取 nameInEnglish,日期使用数据创建时间 createTimeGMT。
该行节点名称为“发起人”,返回的 approvalAction 为 submit,approvalTime 为创建时间。
即使发起人同时参与后续审批,其发起人行与审批行也分别保留;操作记录中的提交动作不会再次生成发起人行。
没有审批记录时仍生成并回写发起人一行;缺少发起人、姓名、创建时间或个人模板时返回错误,不回写部分子表。
会签 domainList 会展开为每个实际审批人;同意及拒绝/驳回记录均保留,并在返回值中标明
approvalAction。抄送、转交和待审批记录不会盖章。同一人在不同节点或重新审批时
分别保留,只有完全相同的任务、人员、时间、节点和动作才去重;发起人之后的审批行按实际审批时间升序排列。
图片使用对应人员的模板,仅绘制一行数字日期(yy.MM.dd),例如 26.10.20,不显示时分秒。
接口返回的 approvalTime 仍为
yyyy-MM-dd HH:mm:ss。默认时区
Asia/Shanghai。Unix 时间戳和明确的非零偏移时间(如 +08:00)转换至配置时区;无偏移
文本按配置时区解读。针对当前组织反馈的审批时间多加 8 小时,默认启用
seal.approval-records.utc-text-is-local=true:将审批记录中带 Z / +00:00 / +0000 的
文本按已是本地时间处理,例如 2026-10-16T09:33:00Z 盖为 26.10.16。
发起人的 createTimeGMT 复用同一时间解析和兼容规则。
该兼容基于线上时差现象,需用原始 operateTimeGMT 与宜搭页面时间核实。如果数据源返回的是
真正的 UTC 时间,应配置 seal.approval-records.utc-text-is-local=false,恢复标准时区转换
(例如 2026-10-16T01:33:00Z 转为北京时间 09:33:00)。兼容规则仅作用于本接口的审批
记录,不修改服务器、邮件同步或旧单张印章接口的时区。日志 [seal.records.time] 包含原始字段、
配置时区及最终盖戳时间,便于核查。审批时间缺失或无法解析会报错,不使用服务器当前日期代替。
所有图片生成成功后,通过流程 UpdateInstance 一次性回写完整子表,仅提交该子表字段。
这会替换指定子表的原有行,而不是追加;请将该子表作为此接口生成的审批印章明细使用。
模板缺失、模板不唯一、图片为空或下载失败时返回错误,不写入部分列表,
也不清空已有子表。个人模板下载失败不会使用旧接口的固定底图或本地通用底图替代。
错误发生前已生成的本地图片可能留在 sealFile 中;重复请求会重新生成图片并替换子表行。
成功返回的 data.list 示例(省略图片文件大小等元数据):
{
"success": true,
"code": 200,
"data": {
"formInstanceId": "FINST-实际业务数据ID",
"list": [
{
"approverUserId": "钉钉userId",
"approverName": "审批人姓名",
"approvalTime": "2026-10-14 09:02:03",
"approvalAction": "agree",
"nodeName": "部门审核",
"fileUrl": "http://139.196.11.100:8101/sealFile/2026/10/14/seal-FINST-xxx-uuid.png",
"sealImages": [{"url": "http://139.196.11.100:8101/sealFile/2026/10/14/seal-FINST-xxx-uuid.png"}]
}
]
}
}
服务仍使用现有 seal.yida.* 凭证和 sealFile 静态目录。目标应用需授权流程实例读取、审批记录
读取、模板表单查询、图片免登以及流程实例更新权限。首次联调使用真实业务数据 ID,验证返回的
节点、审批时间和个人印章,以及宜搭子表的显示;本地测试均使用模拟宜搭响应,没有修改线上记录。
验证命令(只运行隔离的印章测试,避免执行旧的真实接口测试):
mvn "-Dtest=ApprovalRecordParserTest,SealApprovalRecordsServiceTest,SealApprovalRecordsControllerTest,SealControllerTest,SealServiceImplTest" test
mvn clean package -DskipTests
原 approval-complete 接口的请求体最少需要传入当前宜搭流程实例 ID:
{
"processInstanceId": "${当前流程实例ID}",
"approvalTime": "2026-09-21"
}
默认配置已经对应当前宜搭应用、底图表单和业务表单:
APP_RP2SE56YJWMECIWYN4BRFORM-97B11108942B4DEA86E7207834FA76392Y23FINST-F9D667D180C9S8YBMFJKL57SI9WL3EY87CBUM8UUimageField_mubc5ugkFORM-64A9D5065C234383AB2ACF7AB4F20975DW6MimageField_mubc0xwk服务会把图片写入运行目录下的 sealFile/yyyy/MM/dd/,并返回类似:
http://139.196.11.100:8101/sealFile/2026/09/21/seal-FINST-xxx-uuid.png
目标应用 APP_RP2SE56YJWMECIWYN4BR 必须配置它自己的宜搭 systemToken(应用密钥):
SEAL_YIDA_SYSTEM_TOKEN=目标应用的 systemToken
现有 myapp.yida.appSecret 属于旧应用时不能直接复用,否则宜搭会返回 HTTP 400。钉钉 AccessToken 仍由现有 AccessTokenService 获取。
钉钉 AccessToken 和宜搭 systemToken 是两种不同凭证:本服务会把钉钉 AccessToken 放到
x-acs-dingtalk-access-token 请求头,把目标宜搭应用密钥放到 systemToken 参数。
实例读取和表单回写使用宜搭 v2.0 接口,对应接口路径为 /v2.0/yida/...;不要再用旧的
v1.0 GetInstanceById 调用替代它。普通底图表单读取使用原始 HTTP 解析,因为当前 v2.0
SDK 的 GetFormDataByIDResponse 未映射 formData 字段。
审批流程实例读取使用 /v2.0/yida/processes/instancesInfos/{instanceId};印章底图是普通
表单实例,使用 /v2.0/yida/forms/instances/{formInstId} 读取。两者不能混用。
如果日志出现 code=innerError、statusCode=500、没有权限,而旧宜搭应用可以正常读取,
说明当前钉钉应用尚未被目标宜搭应用授权。需要在宜搭目标应用的开放接口/应用授权设置中,
授权当前 AccessTokenService 使用的钉钉应用,并开通表单实例读取和更新权限;这不是 Java
参数顺序问题。服务日志会输出脱敏参数和宜搭 requestId,便于在宜搭后台继续定位。
服务会优先调用宜搭官方 GetOpenUrl 免登文件接口,将底图地址换成临时 OSS URL 后下载,不依赖浏览器 Cookie。若目标应用权限或接口版本不支持免登地址,可把当前组织 Cookie 以环境变量 SEAL_YIDA_COOKIE 注入服务;也可以设置 SEAL_TEMPLATE_IMAGE_FILE 指向服务器上的底图 PNG 作为最终回退。不要把 Cookie 写进代码或提交到仓库。
可选的 Spring 环境变量:
SEAL_YIDA_COOKIE=...
SEAL_TEMPLATE_IMAGE_FILE=C:\\app\\sealFile\\template\\seal-template.png
SEAL_CONNECTOR_TOKEN=一段随机字符串
SEAL_PUBLIC_BASE_URL=http://139.196.11.100:8101/sealFile
如果设置了 SEAL_CONNECTOR_TOKEN,宜搭连接器需要增加同名请求头 X-Seal-Connector-Token。
将下面的 alias 指向 Java 程序运行目录下的 sealFile;Nginx 对外监听 8101,Java 服务监听 8102:
location /sealFile/ {
alias C:/app/changguchuan/sealFile/;
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000";
}
location /api/changguchuan/ {
proxy_pass http://127.0.0.1:8102/api/changguchuan/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
.cache/openyida/changguchuan/connector/seal-operations.json 是连接器动作定义。连接器域名使用 139.196.11.100:8101,基础路径填写 /api/changguchuan/,动作路径填写 seal/approval-complete,最终请求地址为 /api/changguchuan/seal/approval-complete,请求体映射:
processInstanceId:当前审批流程实例 ID(必填)approvalTime:审批通过时间(可选)在“禀议书”流程自动化中选择“审批通过”作为触发条件,再调用该连接器动作即可。接口会读取底图、叠加 yy.MM.dd 日期(例如 26.10.20)、保存图片,并把 URL 写入 imageField_mubc0xwk。
当前已创建并发布自动化逻辑流:
审批通过生成印章processCode:LPROC-PZA668C1YOF95MEJMNH236O34G1W2FTSMBCUMQprocessFinishagreeprocessInstanceId 映射为系统变量 __masterdata_form_inst_id