docs(iwork): 添加用印流程集成开发文档

- 新增完整的 iWork 用印流程集成开发文档
- 包含整体架构图和完整流程时序图
- 详细说明数据库设计和状态流转机制
- 提供 API 接口说明和请求参数定义
- 描述 MQ 消息机制和消息格式定义
- 编写业务模块接入指南和消费者实现示例
- 说明重试机制配置和手工重试接口
- 提供本地开发调试和常见问题解决方案
- 列出相关代码位置便于查阅和维护
This commit is contained in:
wuzongyong
2026-01-30 10:12:45 +08:00
parent bcdba608c7
commit 42c01dc0a4

View File

@@ -0,0 +1,514 @@
# 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
<dependency>
<groupId>com.zt.plat</groupId>
<artifactId>zt-module-system-api</artifactId>
</dependency>
```
### 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<IWorkBizCallbackMessage> {
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` |