# 审批印章模块部署说明 新增模块的接口地址为: ```text POST /api/changguchuan/seal/approval-complete GET /api/changguchuan/seal/health ``` ## 按审批记录生成个人时间戳印章 新增接口:`POST /api/changguchuan/seal/approval-records`。只需传业务表单的宜搭数据 ID,不需要传审批人、审批时间、节点或模板 URL: ```json { "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` | | 子表时间戳印章 | `imageField_mv7h9ypr`,图片对象数组 | 接口先通过 v2.0 流程实例详情取得真实 `processInstanceId` 并验证所属表单,再通过 `GetOperationRecords`(`/v1.0/yida/processes/operationRecords`)获取审批历史。 会签 `domainList` 会展开为每个实际审批人;同意及拒绝/驳回记录均保留,并在返回值中标明 `approvalAction`。提交、抄送、转交和待审批记录不会盖章。同一人在不同节点或重新审批时 分别保留,只有完全相同的任务、人员、时间、节点和动作才去重,结果按实际审批时间升序排列。 图片使用该审批人的模板,日期和时分秒分两行绘制(`yyyy-MM-dd` / `HH:mm:ss`),默认时区 `Asia/Shanghai`。带时区时间和 Unix 时间戳先转换至配置时区,无偏移的时间文本按配置时区 解读。审批时间缺失或无法解析会报错,不使用服务器当前日期代替。 所有图片生成成功后,通过流程 `UpdateInstance` 一次性回写完整子表,仅提交该子表字段。 这会**替换指定子表的原有行**,而不是追加;请将该子表作为此接口生成的审批印章明细使用。 模板缺失、模板不唯一、图片为空、下载失败或没有已执行审批记录时返回错误,不写入部分列表, 也不清空已有子表。个人模板下载失败不会使用旧接口的固定底图或本地通用底图替代。 错误发生前已生成的本地图片可能留在 `sealFile` 中;重复请求会重新生成图片并替换子表行。 成功返回的 `data.list` 示例(省略图片文件大小等元数据): ```json { "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,验证返回的 节点、审批时间和个人印章,以及宜搭子表的显示;本地测试均使用模拟宜搭响应,没有修改线上记录。 验证命令(只运行隔离的印章测试,避免执行旧的真实接口测试): ```powershell mvn "-Dtest=ApprovalRecordParserTest,SealApprovalRecordsServiceTest,SealApprovalRecordsControllerTest,SealControllerTest,SealServiceImplTest" test mvn clean package -DskipTests ``` ## 原审批通过单张印章接口 原 `approval-complete` 接口的请求体最少需要传入当前宜搭流程实例 ID: ```json { "processInstanceId": "${当前流程实例ID}", "approvalTime": "2026-09-21" } ``` ## Windows 配置 默认配置已经对应当前宜搭应用、底图表单和业务表单: - 应用:`APP_RP2SE56YJWMECIWYN4BR` - 底图表单:`FORM-97B11108942B4DEA86E7207834FA76392Y23` - 底图实例:`FINST-F9D667D180C9S8YBMFJKL57SI9WL3EY87CBUM8UU` - 底图字段:`imageField_mubc5ugk` - 业务表单:`FORM-64A9D5065C234383AB2ACF7AB4F20975DW6M` - 回写字段:`imageField_mubc0xwk` 服务会把图片写入运行目录下的 `sealFile/yyyy/MM/dd/`,并返回类似: ```text http://139.196.11.100:8101/sealFile/2026/09/21/seal-FINST-xxx-uuid.png ``` 目标应用 `APP_RP2SE56YJWMECIWYN4BR` 必须配置它自己的宜搭 systemToken(应用密钥): ```text 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 环境变量: ```text 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`。 ## Nginx 将下面的 `alias` 指向 Java 程序运行目录下的 `sealFile`;Nginx 对外监听 8101,Java 服务监听 8102: ```nginx 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`:审批通过时间(可选) 在“禀议书”流程自动化中选择“审批通过”作为触发条件,再调用该连接器动作即可。接口会读取底图、叠加 `yyyy-MM-dd` 日期、保存图片,并把 URL 写入 `imageField_mubc0xwk`。 当前已创建并发布自动化逻辑流: - 逻辑流名称:`审批通过生成印章` - `processCode`:`LPROC-PZA668C1YOF95MEJMNH236O34G1W2FTSMBCUMQ` - 触发事件:`processFinish` - 审批动作:`agree` - 连接器参数:`processInstanceId` 映射为系统变量 `__masterdata_form_inst_id`