# iWork 用印流程集成开发文档 ## 1. 概述 本文档描述了 ZT Cloud 平台与 iWork 系统的用印流程集成方案,包括流程发起、回调处理、消息通知及重试机制。 ### 1.1 功能特性 - **流程发起**:支持用印专用流程和通用流程两种创建方式 - **回调处理**:接收 iWork 回调,自动通知业务模块 - **消息队列**:基于 RocketMQ 的异步消息通知机制 - **自动重试**:失败回调自动重试,支持配置重试次数和间隔 - **日志追踪**:完整记录流程创建和回调处理全生命周期 ### 1.2 整体架构 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 业务系统 │────▶│ System 模块 │────▶│ iWork 系统 │ │ (调用方) │ │ (集成层) │ │ (OA 流程) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ▲ ▲ │ │ │ │ │ └───────────────────────┘ │ iWork 流程完成后回调 │ ┌─────────────────┐ │ │ RocketMQ │ │ │ (消息队列) │ └───────────────┴─────────────────┘ ``` ### 1.3 完整流程时序图 ``` ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ 业务系统 │ │ System │ │ iWork │ │RocketMQ│ │业务消费者│ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ │ │ │ │ │ │ 1.发起用印流程 │ │ │ │ │──────────────▶│ │ │ │ │ │ 2.创建流程 │ │ │ │ │──────────────▶│ │ │ │ │ 返回requestId│ │ │ │ │◀──────────────│ │ │ │ 返回结果 │ │ │ │ │◀──────────────│ │ │ │ │ │ │ │ │ │ │ │ 3.OA流程审批 │ │ │ │ │ (异步进行) │ │ │ │ │ │ │ │ │ 4.流程完成回调 │ │ │ │ │◀──────────────│ │ │ │ │ │ │ │ │ │ 5.发送MQ消息 │ │ │ │ │──────────────────────────────▶│ │ │ │ │ │ 6.投递消息 │ │ │ │ │──────────────▶│ │ │ │ │ │ │ │ │ │ 7.返回处理结果 │ │ │ │ │◀──────────────│ │ │ 8.接收结果 │ │ │ │ │◀──────────────────────────────│ │ │ │ │ │ │ │ │ 9.更新日志状态 │ │ │ │ │ (成功/重试) │ │ │ └───────────────┴───────────────┴───────────────┴───────────────┘ ``` **流程说明**: 1. **发起流程**:业务系统调用 System 模块的流程创建接口 2. **创建流程**:System 模块调用 iWork API 创建 OA 流程,获取 `requestId` 3. **OA 审批**:流程在 iWork 系统中流转(审批、签章等),此过程异步进行 4. **iWork 回调**:流程完成后,iWork 系统主动回调 System 模块的回调接口 5. **MQ 通知**:System 模块将回调数据通过 RocketMQ 发送给业务消费者 6. **业务处理**:业务消费者接收消息并处理(如保存签章文件、更新业务状态) 7. **返回结果**:业务消费者处理完成后,发送处理结果消息 8. **接收结果**:System 模块接收处理结果 9. **状态更新**:根据结果更新日志状态,失败则触发重试机制 ## 2. 数据库设计 ### 2.1 流程日志表 (system_iwork_workflow_log) | 字段名 | 类型 | 说明 | |--------|------|------| | id | BIGINT | 主键 | | request_id | VARCHAR(128) | iWork 请求编号(唯一) | | workflow_id | BIGINT | 流程模板 ID | | business_code | VARCHAR(128) | 业务编码 | | biz_callback_key | VARCHAR(255) | 业务回调标识(MQ tag) | | raw_request | VARCHAR(2000) | 创建请求原文 | | status | VARCHAR(32) | 流程状态 | | callback_status | INTEGER | 回调处理状态 | | retry_count | INTEGER | 已重试次数 | | max_retry | INTEGER | 最大重试次数 | | last_error_message | VARCHAR(512) | 最后错误信息 | | raw_callback | VARCHAR(2000) | 回调原文 | | last_callback_time | TIMESTAMP | 最近回调时间 | | tenant_id | BIGINT | 租户编号 | ### 2.2 回调状态枚举 (callback_status) | 值 | 状态 | 说明 | |----|------|------| | 0 | CREATE_PENDING | 创建中 | | 1 | CREATE_SUCCESS | 创建成功 | | 2 | CREATE_FAILED | 创建失败 | | 3 | CALLBACK_PENDING | 回调待处理 | | 4 | CALLBACK_SUCCESS | 回调处理成功 | | 5 | CALLBACK_FAILED | 回调处理失败 | | 6 | CALLBACK_RETRYING | 回调重试中 | | 7 | CALLBACK_RETRY_FAILED | 回调重试失败 | ### 2.3 状态流转图 ``` ┌─────────────────────────────────────────────────────┐ │ 流程创建阶段 │ │ ┌──────────┐ 成功 ┌──────────┐ │ │ │ PENDING │ ─────────▶ │ SUCCESS │ │ │ │ (0) │ │ (1) │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ 失败 │ │ ▼ │ │ ┌──────────┐ │ │ │ FAILED │ │ │ │ (2) │ │ │ └──────────┘ │ └─────────────────────────────────────────────────────┘ │ │ iWork 回调 ▼ ┌─────────────────────────────────────────────────────┐ │ 回调处理阶段 │ │ ┌──────────┐ 成功 ┌──────────┐ │ │ │ CALLBACK │ ─────────▶ │ CALLBACK │ │ │ │ PENDING │ │ SUCCESS │ │ │ │ (3) │ │ (4) │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ 失败 │ │ ▼ │ │ ┌──────────┐ 重试中 ┌──────────┐ │ │ │ CALLBACK │ ◀───────▶ │ CALLBACK │ │ │ │ FAILED │ │ RETRYING │ │ │ │ (5) │ │ (6) │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ 重试次数耗尽 │ │ ▼ │ │ ┌──────────┐ │ │ │ RETRY │ │ │ │ FAILED(7)│ │ │ └──────────┘ │ └─────────────────────────────────────────────────────┘ ``` ## 3. API 接口说明 ### 3.1 用印流程创建 **接口地址**:`POST /admin-api/system/integration/iwork/workflow/create` **请求参数**: ```json { "operatorUserId": "1001", "jbr": "1001", "yybm": "2001", "fb": "3001", "sqsj": "2025-01-30", "yyqx": "内部使用", "yyfkUrl": "https://example.com/attachment.pdf", "yysy": "合同盖章", "xyywjUrl": "https://example.com/contract.pdf", "yysx": "公章", "ywxtdjbh": "DJ-2025-0001", "bizCallbackKey": "seal-callback" } ``` | 参数 | 必填 | 说明 | |------|------|------| | operatorUserId | 是 | 操作人 iWork 用户 ID | | jbr | 是 | 用印申请人 | | yybm | 是 | 用印部门 ID | | fb | 是 | 用印单位(分部 ID) | | sqsj | 是 | 申请时间 (yyyy-MM-dd) | | yyqx | 是 | 用印去向 | | xyywjUrl | 是 | 用印材料附件 URL | | yysx | 是 | 用印事项 | | ywxtdjbh | 是 | 业务系统单据编号 | | bizCallbackKey | 否 | 业务回调标识 | | yyfkUrl | 否 | 用印依据附件 URL | | yysy | 否 | 用印事由 | ### 3.2 通用流程创建 **接口地址**:`POST /admin-api/system/integration/iwork/workflow/create-generic` **请求参数**: ```json { "operatorUserId": "1001", "workflowId": 54, "payload": { "requestName": "用印-DJ-2025-0001", "mainData": [ {"fieldName": "jbr", "fieldValue": "1001"}, {"fieldName": "yybm", "fieldValue": "2001"} ] }, "ywxtdjbh": "DJ-2025-0001", "bizCallbackKey": "seal-callback" } ``` | 参数 | 必填 | 说明 | |------|------|------| | operatorUserId | 是 | 操作人 iWork 用户 ID | | workflowId | 是 | 流程模板 ID | | payload | 是 | 透传给 iWork 的业务参数 | | ywxtdjbh | 否 | 业务编码 | | bizCallbackKey | 否 | 业务回调标识 | ### 3.3 iWork 回调接口 **接口地址**:`POST /admin-api/system/integration/iwork/callback/file` **说明**:此接口供 iWork 系统回调,无需认证(@PermitAll, @TenantIgnore) **iWork 侧配置**:需要在 iWork 系统中配置回调地址,当流程完成时自动调用此接口。 **请求参数**: ```json { "requestId": "3603649", "businessCode": "DJ-2025-0001", "fileUrl": "https://iwork.example.com/signed-file.pdf", "fileName": "已签章合同.pdf", "status": "COMPLETED" } ``` | 参数 | 必填 | 说明 | |------|------|------| | requestId | 是 | iWork 请求编号(与创建流程时返回的一致) | | businessCode | 是 | 业务编码(与创建流程时传入的 ywxtdjbh 一致) | | fileUrl | 是 | 签章后文件 URL | | fileName | 否 | 文件名称 | | status | 否 | 业务状态 | **回调处理逻辑**: 1. 根据 `requestId` 查询流程创建日志,获取 `bizCallbackKey` 2. 更新日志状态为 `CALLBACK_PENDING` 3. 发送 MQ 消息通知业务模块(仅当 `bizCallbackKey` 存在时) 4. 返回处理结果 ## 4. MQ 消息机制 ### 4.1 消息流程图 ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ iWork 回调 │───▶│ System 模块 │───▶│ RocketMQ │───▶│ 业务消费者 │ │ │ │ (Producer) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 更新日志状态 │◀───│ System 模块 │◀───│ RocketMQ │◀───│ 返回处理结果 │ │ │ │ (Listener) │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ ``` ### 4.2 Topic 定义 | Topic | 说明 | |-------|------| | SYSTEM_IWORK_BIZ_CALLBACK | 回调通知消息(System → 业务模块) | | SYSTEM_IWORK_BIZ_CALLBACK_RESULT | 处理结果消息(业务模块 → System) | ### 4.3 回调通知消息 (IWorkBizCallbackMessage) ```java { "requestId": "3603649", "bizCallbackKey": "seal-callback", "payload": { /* 回调原始数据 */ }, "attempt": 0, "maxAttempts": 3 } ``` **Tag 规则**:消息 tag = `bizCallbackKey`,业务模块按 tag 订阅 ### 4.4 处理结果消息 (IWorkBizCallbackResultMessage) ```java { "requestId": "3603649", "bizCallbackKey": "seal-callback", "success": true, "errorMessage": null, "attempt": 0, "maxAttempts": 3, "payload": { /* 原始数据,用于重试 */ } } ``` ## 5. 业务模块接入指南 ### 5.1 添加依赖 ```xml com.zt.plat zt-module-system-api ``` ### 5.2 实现消费者 ```java @Slf4j @Component @RequiredArgsConstructor @RocketMQMessageListener( topic = IWorkBizCallbackMessage.TOPIC, consumerGroup = IWorkBizCallbackMessage.TOPIC + "_YOUR_BIZ_KEY", selectorExpression = "your-biz-callback-key" // 与 bizCallbackKey 一致 ) public class YourBizCallbackConsumer implements RocketMQListener { private final RocketMQTemplate rocketMQTemplate; @Override public void onMessage(IWorkBizCallbackMessage message) { log.info("收到 iWork 回调: requestId={}", message.getRequestId()); IWorkBizCallbackResultMessage result; try { // 处理业务逻辑 processCallback(message); result = IWorkBizCallbackResultMessage.builder() .requestId(message.getRequestId()) .bizCallbackKey(message.getBizCallbackKey()) .success(true) .attempt(message.getAttempt()) .maxAttempts(message.getMaxAttempts()) .payload(message.getPayload()) .build(); } catch (Exception e) { log.error("处理回调失败", e); result = IWorkBizCallbackResultMessage.builder() .requestId(message.getRequestId()) .bizCallbackKey(message.getBizCallbackKey()) .success(false) .errorMessage(e.getMessage()) .attempt(message.getAttempt()) .maxAttempts(message.getMaxAttempts()) .payload(message.getPayload()) .build(); } // 发送处理结果 rocketMQTemplate.syncSend(IWorkBizCallbackResultMessage.TOPIC, result); } private void processCallback(IWorkBizCallbackMessage message) { // 业务处理逻辑 // 1. 解析 payload 获取回调数据 // 2. 更新业务状态 // 3. 保存签章文件等 } } ``` ### 5.3 关键配置项 | 配置项 | 说明 | |--------|------| | consumerGroup | 消费者组,建议格式:`TOPIC + "_" + bizCallbackKey` | | selectorExpression | Tag 过滤,必须与发起流程时的 `bizCallbackKey` 一致 | ### 5.4 注意事项 1. **bizCallbackKey 唯一性**:每个业务场景使用独立的 bizCallbackKey 2. **幂等处理**:消费者需实现幂等,同一 requestId 可能重复投递 3. **必须返回结果**:处理完成后必须发送 `IWorkBizCallbackResultMessage` 4. **错误信息**:失败时填写 errorMessage,便于问题排查 ## 6. 重试机制 ### 6.1 重试流程 ``` 业务处理失败 → 返回 success=false → System Listener 接收 ↓ 检查 attempt < maxAttempts? ↓ ↓ 是 否 ↓ ↓ 延迟后重新投递 标记最终失败 ``` ### 6.2 配置参数 ```yaml iwork: callback: retry: max-attempts: 3 # 最大重试次数 delay-seconds: 5 # 重试间隔(秒) ``` ### 6.3 手工重试 **接口地址**:`POST /admin-api/system/integration/iwork/log/retry` ```json { "requestId": "3603649" } ``` ## 7. 日志查询 ### 7.1 分页查询接口 **接口地址**:`POST /admin-api/system/integration/iwork/log/page` **请求参数**: ```json { "requestId": "3603649", "businessCode": "DJ-2025-0001", "bizCallbackKey": "seal-callback", "status": 4, "pageNo": 1, "pageSize": 10 } ``` ## 8. 本地开发调试 ### 8.1 隔离测试环境 为避免与测试环境消息冲突,本地开发时需修改: 1. **Listener 消费者组**:添加本地标识后缀 ```java consumerGroup = IWorkBizCallbackResultMessage.TOPIC + "_CONSUMER_local" ``` 2. **Listener Tag 过滤**:使用本地专用 tag ```java selectorExpression = "local_test" ``` 3. **业务消费者**:同样使用本地专用 bizCallbackKey ```java selectorExpression = "your-biz-key_local" ``` 4. **数据库记录**:将 `biz_callback_key` 设为本地专用值 ### 8.2 调试建议 - 使用独立的 `bizCallbackKey` 避免消息串扰 - 检查 RocketMQ 控制台确认消息投递情况 - 关注日志中的 `requestId` 进行链路追踪 ## 9. 常见问题 ### Q1: 业务消费者收不到消息? 检查项: - `selectorExpression` 是否与 `bizCallbackKey` 一致 - 消费者组名是否正确 - RocketMQ 连接是否正常 ### Q2: 收到重复消息? 可能原因: - 多个环境的 Listener 都在消费同一 topic - 解决:使用独立的消费者组和 tag 过滤 ### Q3: 重试不生效? 检查项: - 是否正确返回了 `IWorkBizCallbackResultMessage` - `success` 字段是否为 `false` - 配置的 `max-attempts` 是否大于当前 `attempt` ## 10. 相关代码位置 | 组件 | 路径 | |------|------| | Controller | `zt-module-system-server/.../controller/admin/integration/iwork/IWorkIntegrationController.java` | | Service | `zt-module-system-server/.../service/integration/iwork/impl/IWorkIntegrationServiceImpl.java` | | 日志 Service | `zt-module-system-server/.../service/integration/iwork/impl/IWorkWorkflowLogServiceImpl.java` | | MQ Producer | `zt-module-system-server/.../mq/iwork/IWorkBizCallbackProducer.java` | | MQ Listener | `zt-module-system-server/.../mq/iwork/IWorkBizCallbackListener.java` | | 消息定义 | `zt-module-system-api/.../mq/iwork/IWorkBizCallbackMessage.java` | | 配置类 | `zt-module-system-server/.../framework/integration/iwork/config/IWorkProperties.java` |