36 KiB
iWork 集成 API 与使用指南
本文面向 调用方后端开发者,介绍如何在 System 模块中使用现有的 iWork 集成能力:流程发起/作废、附件回调、人力组织代理与全量同步。文档按“流程调用能力 / 组织同步能力”拆分,并包含 Mermaid 流程图、字段映射表及禁用策略说明,便于快速自助集成。
背景与适用范围
- 所有接口位于
zt-module-system-server的IWorkIntegrationController下,统一前缀/system/integration/iwork。 - Service 层提供
IWorkIntegrationService、IWorkOrgRestService、IWorkSyncService三个 Bean,可在任意业务模块注入调用。 - 调用 iWork 之前会实时执行 register + apply-token,不保留本地缓存;组织同步则通过 key+ts 鉴权代理 iWork HR 接口并写入本地组织/用户表。
快速开始清单
application.yml或配置中心已填写iwork.*参数。- 确认所在网络能访问 iWork register/apply-token/HR 接口。
- 明确调用方向:流程调用 or 组织同步,两种能力可独立使用。
- 若使用文件回调,已约定业务附件的
businessCode与租户。 - 管理端
admin-api/system/integration/iwork/**已放通权限。
配置清单
YAML 示例
iwork:
base-url: https://iwork.example.com
app-id: my-iwork-app
client-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
user-id: system
workflow:
seal-workflow-id: 54
paths:
register: /api/ec/dev/auth/regist
apply-token: /api/ec/dev/auth/applytoken
user-info: /api/workflow/paService/getUserInfo
create-workflow: /api/workflow/paService/doCreateRequest
void-workflow: /api/workflow/paService/doCancelRequest
token:
ttl-seconds: 3600
client:
connect-timeout: 5s
response-timeout: 30s
org:
token-seed: 5936562a-d47c-4a29-9b74-b310e6c971b7
paths:
subcompany-page: /api/hrm/resful/getHrmsubcompanyWithPage
department-page: /api/hrm/resful/getHrmdepartmentWithPage
job-title-page: /api/hrm/resful/getJobtitleInfoWithPage
user-page: /api/hrm/resful/getHrmUserInfoWithPage
sync-subcompany: /api/hrm/resful/synSubcompany
sync-department: /api/hrm/resful/synDepartment
sync-job-title: /api/hrm/resful/synJobtitle
sync-user: /api/hrm/resful/synHrmresource
| 配置键 | 说明 | 必填 | 默认值 |
|---|---|---|---|
iwork.base-url |
iWork 网关地址,需与网络互通 | 是 | - |
iwork.app-id |
平台分配的 AppId,用于申请 token | 是 | - |
iwork.client-public-key |
iWork 端提供的 RSA 公钥,系统用其加密凭证 | 是 | - |
iwork.workflow.seal-workflow-id |
盖章流程模板 ID,其他流程可扩展 | 是 | - |
iwork.paths.* |
控制器访问 iWork 的后端路由 | 是 | - |
iwork.token.ttl-seconds |
token 缓存时长,单位秒 | 否 | 3600 |
iwork.client.connect-timeout |
OkHttp 建连超时 | 否 | 5s |
iwork.org.token-seed |
HR 组织同步签名盐值 | 是 | - |
流程调用 API
端到端互动图
sequenceDiagram
participant Client as 调用方服务
participant Gateway as ZTCloud /system 接口
participant IWork as iWork 平台
Client->>Gateway: POST /auth/register
Gateway->>IWork: /api/ec/dev/auth/regist
IWork-->>Gateway: 返回 secret + spk
Client->>Gateway: POST /auth/token
Gateway->>IWork: /api/ec/dev/auth/applytoken
IWork-->>Gateway: token
Client->>Gateway: POST /workflow/create
Gateway->>IWork: /api/workflow/paService/doCreateRequest
IWork-->>Gateway: requestId
IWork-->>Gateway: 文件回调
Gateway-->>Client: 业务附件 ID
HTTP 接口分组
| 功能 | Method & Path | 对应 iWork 接口 | 说明 |
|---|---|---|---|
| 注册凭证 | POST /system/integration/iwork/auth/register |
/api/ec/dev/auth/regist |
生成 secret + spk,用于后续 token 申请 |
| 申请 token | POST /system/integration/iwork/auth/token |
/api/ec/dev/auth/applytoken |
以 secret + operatorUserId 换取 token |
| 用户解析 | POST /system/integration/iwork/user/resolve |
/api/workflow/paService/getUserInfo |
通过工号/手机号等标识查询 iWork 用户 ID |
| 发起流程 | POST /system/integration/iwork/workflow/create |
/api/workflow/paService/doCreateRequest |
将本地业务单推送至 iWork 指定流程 |
| 作废流程 | POST /system/integration/iwork/workflow/void |
/api/workflow/paService/doCancelRequest |
针对 requestId 触发终止/回收 |
| 文件回调 | POST /system/integration/iwork/callback/file |
iWork 自定义回调 | 将 iWork 附件落地并与业务编码关联 |
关键参数与 VO
| 接口 | 请求体 | 核心字段 | 说明 |
|---|---|---|---|
| 注册凭证 | IWorkAuthRegisterReqVO |
forceRefreshRegistration |
true 时会重新向 iWork 注册,常用于公钥被重置的场景 |
| 申请 token | IWorkAuthTokenReqVO |
operatorUserId、forceRefreshToken |
operatorUserId 默认读取 iwork.user-id,必要时可传入办件人 ID |
| 用户解析 | IWorkUserInfoReqVO |
identifierKey、identifierValue |
支持 workCode、mobile、loginId 等键值组合 |
| 创建流程 | IWorkWorkflowCreateReqVO |
workflowId、mainData、attachments |
workflowId 缺省则采用 iwork.workflow.seal-workflow-id,mainData 为流程主表字段 |
| 作废流程 | IWorkWorkflowVoidReqVO |
requestId、reason |
reason 最长 400 字,系统会自动截断超长字符 |
| 文件回调 | IWorkFileCallbackReqVO |
fileUrl、businessCode |
将远程文件下载后与业务附件绑定,businessCode 对应已有 BusinessFile 记录 |
发起流程示例
curl -X POST https://{host}/system/integration/iwork/workflow/create ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer <your-token>" ^
-d @payload.json
payload 示意:
{
"operatorUserId": "1001",
"forceRefreshToken": false,
"jbr": "1001",
"yybm": "2001",
"fb": "3001",
"sqsj": "2025-01-01",
"yyqx": "寄送客户",
"yyfkUrl": "https://oss.example.com/依据附件.pdf",
"yysy": "与 XX 公司签订框架合同",
"xyywjUrl": "https://oss.example.com/材料附件.pdf",
"xyywjFileName": "材料附件.pdf",
"yysx": "合同用印",
"ywxtdjbh": "DJ-2025-00018"
}
Java 调用片段
IWorkWorkflowCreateReqVO req = new IWorkWorkflowCreateReqVO();
req.setWorkflowId(54);
req.setOperatorUserId("1001");
req.setMainData(Map.of("title", "盖章申请", "amount", 128000));
req.setForceRefreshToken(false);
CommonResult<IWorkOperationRespVO> resp = restTemplate.postForObject(
baseUrl + "/system/integration/iwork/workflow/create",
req,
new ParameterizedTypeReference<>() {});
if (resp == null || !resp.isSuccess()) {
throw new IllegalStateException("iWork 调用失败" + Optional.ofNullable(resp).map(CommonResult::getMsg).orElse(""));
}
String requestId = resp.getData().getRequestId();
通用请求字段(IWorkBaseReqVO)
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
appId |
string | 否 | 覆盖默认的 iWork 应用编号;为空时取配置 | iwork-app |
operatorUserId |
string | 否 | 作为 iWork 操作人的用户编号;为空时取 iwork.user-id |
1001 |
forceRefreshToken |
boolean | 否 | true 时忽略本地缓存并强制重新申请 token | false |
所有接口均返回
CommonResult<T>结构,通用包体为{ "code": 0, "data": T, "msg": "success", "traceId": "..." }。下文的响应字段默认落在data节点内。
流程接口字段详解
POST /system/integration/iwork/auth/register
请求字段(/auth/register)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
forceRefreshRegistration |
boolean | 否 | true 时即使已有注册信息也会重新向 iWork 注册,以获取新的 secret + serverPublicKey |
响应字段(/auth/register)
| 字段 | 类型 | 说明 |
|---|---|---|
appId |
string | 实际使用的 iWork 应用编号 |
clientPublicKey |
string(Base64) | 系统用于加密 secret 的客户端公钥 |
clientPrivateKey |
string(Base64) | 仅在动态生成公钥时回传,用于后续持久化 |
serverPublicKey |
string(Base64) | iWork 返回的服务端公钥,需用于加密 secret 与 userId |
secret |
string | iWork 发放的密钥,结合公钥加密后才能申请 token |
JSON 示例(/auth/register)
请求:
POST /system/integration/iwork/auth/register HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ***
{
"forceRefreshRegistration": true
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"appId": "iwork-app",
"clientPublicKey": "MIIBIjANBgkq...",
"clientPrivateKey": "MIIEvAIBADANBg...",
"serverPublicKey": "MIIBCgKCAQEAv...",
"secret": "d9e7f3e4c5"
},
"traceId": "efdb73a0e9f7"
}
失败示例(iWork 接口异常):
HTTP/1.1 502 Bad Gateway
Content-Type: application/json
{
"code": 100500,
"msg": "向 iWork 注册失败: upstream timeout",
"data": null,
"traceId": "c4019de7c3aa"
}
POST /system/integration/iwork/auth/token
请求字段(/auth/token)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
operatorUserId |
string | 否 | 不填则取配置的默认操作者 |
forceRefreshToken |
boolean | 否 | true 时忽略缓存直接调 iWork 申请新 token |
forceRefreshRegistration |
boolean | 否 | true 时在申请 token 前重新注册,以应对 serverPublicKey 失效 |
响应字段(/auth/token)
| 字段 | 类型 | 说明 |
|---|---|---|
appId |
string | 本次 token 绑定的应用编号 |
operatorUserId |
string | 实际用于发起流程的 iWork 用户 |
token |
string | iWork 访问令牌 |
encryptedUserId |
string | 使用 serverPublicKey 加密后的 userId,调用 iWork 接口时需要写入 Header |
expiresAtEpochSecond |
long | 预计过期时间(Epoch 秒) |
serverPublicKey |
string | token 对应的 server 公钥 |
JSON 示例(/auth/token)
请求:
POST /system/integration/iwork/auth/token HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ***
{
"operatorUserId": "1001",
"forceRefreshToken": false,
"forceRefreshRegistration": false
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"appId": "iwork-app",
"operatorUserId": "1001",
"token": "389a6d30-2f7a-4a1a",
"encryptedUserId": "Q0ZCU0RmVz...",
"expiresAtEpochSecond": 1764825600,
"serverPublicKey": "MIIBCgKCAQEAv..."
},
"traceId": "9012ab34cd56"
}
失败示例(secret 失效):
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"appId": "iwork-app",
"operatorUserId": "1001",
"token": null,
"encryptedUserId": null,
"expiresAtEpochSecond": null,
"serverPublicKey": "MIIBCgKCAQEAv...",
"success": false,
"message": "iWork: secret expired, please re-register"
},
"traceId": "70e9570f218b"
}
POST /system/integration/iwork/user/resolve
请求字段(/user/resolve)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
identifierKey |
string | 是 | 写入 iWork 所需的字段名,如 workcode、mobile、loginid |
identifierValue |
string | 是 | 对应字段的取值 |
payload |
map | 否 | 附加在请求体的扩展参数,会与识别字段一起发送 |
queryParams |
map | 否 | 附加在 URL 上的查询参数 |
响应字段(/user/resolve)
| 字段 | 类型 | 说明 |
|---|---|---|
payload |
map | iWork 原始返回 JSON |
success |
boolean | 是否判定为成功(根据 code/success 等字段自动推断) |
message |
string | 友好提示或错误信息 |
userId |
string | 从返回体解析出的 iWork 用户编号 |
JSON 示例(/user/resolve)
请求:
POST /system/integration/iwork/user/resolve HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ***
{
"identifierKey": "workcode",
"identifierValue": "A10086",
"queryParams": {
"tenant": "ztcloud"
}
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"success": true,
"message": "OK",
"userId": "1001",
"payload": {
"code": "SUCCESS",
"data": {
"userid": "1001",
"lastname": "张三",
"loginid": "zhangsan"
}
}
},
"traceId": "b8c1d5fe1039"
}
失败示例(未找到用户):
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"success": false,
"message": "iWork 返回空数据",
"userId": null,
"payload": {
"code": "SUCCESS",
"data": []
}
},
"traceId": "4ea7a1dd6281"
}
POST /system/integration/iwork/workflow/create
请求字段(/workflow/create)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
jbr |
string | 是 | 用印经办人(iWork 用户 ID) |
yybm |
string | 是 | 用印部门 ID |
fb |
string | 是 | 用印单位(分部 ID) |
sqsj |
string(yyyy-MM-dd) | 是 | 申请时间 |
yyqx |
string | 是 | 用印去向/流向 |
yyfkUrl |
string | 否 | 用印依据附件 URL |
yysy |
string | 否 | 用印事由 |
xyywjUrl |
string | 是 | 待用印材料附件 URL,系统会封装成 iWork 需要的数组结构 |
xyywjFileName |
string | 否 | 待用印材料附件名称,默认从 URL 截取 |
yysx |
string | 是 | 用印事项(流程标题关键字段) |
ywxtdjbh |
string | 是 | 业务系统单据编号,用于生成流程标题与追溯 |
响应字段(/workflow/create)
| 字段 | 类型 | 说明 |
|---|---|---|
payload.code |
string | iWork 返回的业务状态,如 SUCCESS |
payload.data.requestId |
long | iWork 流程请求编号,后续作废/查询需要使用 |
payload.errMsg |
map | 错误附加信息(失败时) |
payload.reqFailMsg.keyParameters |
map | 失败时的关键参数回显 |
success |
boolean | SDK 根据 code/success 判断的结果 |
message |
string | 统一的提示文案 |
JSON 示例(/workflow/create)
请求:
POST /system/integration/iwork/workflow/create HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ***
{
"operatorUserId": "1001",
"forceRefreshToken": false,
"jbr": "1001",
"yybm": "2001",
"fb": "3001",
"sqsj": "2025-01-01",
"yyqx": "寄送客户",
"yyfkUrl": "https://oss.example.com/依据附件.pdf",
"yysy": "与 XX 公司签订框架合同",
"xyywjUrl": "https://oss.example.com/材料附件.pdf",
"xyywjFileName": "材料附件.pdf",
"yysx": "合同用印",
"ywxtdjbh": "DJ-2025-00018"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"success": true,
"message": "流程创建成功",
"payload": {
"code": "SUCCESS",
"data": {
"requestid": 9623451
},
"errMsg": {},
"reqFailMsg": null
}
},
"traceId": "0af7c8f2c7a1"
}
失败示例(字段缺失):
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"code": 100001,
"msg": "参数校验失败",
"data": {
"success": false,
"message": "缺少必填字段: yysx",
"payload": {
"code": "FAIL",
"reqFailMsg": {
"keyParameters": {
"missingField": "yysx"
},
"msgInfo": {
"message": "Please provide seal reason"
}
}
}
},
"traceId": "f91c1c3772af"
}
POST /system/integration/iwork/workflow/void
请求字段(/workflow/void)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
requestId |
string | 是 | 需要作废的 iWork 流程编号 |
reason |
string | 否 | 作废原因,将映射到 iWork 的 remark 字段(超长会被截断) |
extraParams |
map | 否 | 直接透传给 iWork 的附加 JSON 字段 |
formExtras |
map<string,string> | 否 | 会被追加到 payload 中的额外 form 字段 |
响应字段(/workflow/void)
与 /workflow/create 使用的 IWorkOperationRespVO 结构完全一致。
JSON 示例(/workflow/void)
请求:
POST /system/integration/iwork/workflow/void HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer ***
{
"requestId": "REQ-9623451",
"reason": "业务单据撤回,需终止流程"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"success": true,
"message": "流程已成功作废",
"payload": {
"code": "SUCCESS",
"data": {
"requestid": 9623451
}
}
},
"traceId": "5c7f0a9b1d23"
}
失败示例(requestId 不存在):
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"success": false,
"message": "iWork 返回失败: request not found",
"payload": {
"code": "FAIL",
"reqFailMsg": {
"keyParameters": {
"requestid": "REQ-999999"
},
"msgInfo": {
"msg": "流程不存在或已处理"
}
}
}
},
"traceId": "98d73ae0bf12"
}
POST /system/integration/iwork/callback/file
请求字段(/callback/file)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileUrl |
string | 是 | iWork 可访问的文件下载地址 |
businessCode |
string | 是 | 已存在的业务附件编码,将使用该编码定位租户与业务ID |
fileName |
string | 否 | 覆盖默认文件名,不填则从 URL 末尾截取 |
响应字段(/callback/file)
| 字段 | 类型 | 说明 |
|---|---|---|
data |
long | 成功创建的业务附件关联 ID |
JSON 示例(/callback/file)
请求:
POST /system/integration/iwork/callback/file HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"fileUrl": "https://oss.example.com/files/abc.pdf",
"businessCode": "DJ-2025-00018",
"fileName": "电子合同.pdf"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": 8823451990123,
"traceId": "6f1b0c7d8e91"
}
失败示例(业务编码不存在):
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"code": 100210,
"msg": "业务编码不存在,无法创建附件",
"data": null,
"traceId": "72e4fa109d55"
}
组织同步 API
数据流示意
flowchart LR
IWork[(iWork HR)] -->|分页接口| RestProxy[/IWorkOrgRestService/]
RestProxy -->|BatchResult| SyncService{{IWorkSyncService}}
SyncService -->|Dept/Post/UserSaveReqVO| LocalDB[(ZTCloud 系统库)]
SyncService -->|统计| 调用方
接口矩阵
| 功能 | Method & Path | 请求体 | 备注 |
|---|---|---|---|
| 分部分页 | POST /system/integration/iwork/hr/subcompany/page |
IWorkSubcompanyQueryReqVO |
透传 subcompanycode/subcompanyname 条件 |
| 部门分页 | POST /system/integration/iwork/hr/department/page |
IWorkDepartmentQueryReqVO |
支持按照 subcompanyId、名称过滤 |
| 岗位分页 | POST /system/integration/iwork/hr/job-title/page |
IWorkJobTitleQueryReqVO |
可按岗位编码、名称筛选 |
| 人员分页 | POST /system/integration/iwork/hr/user/page |
IWorkUserQueryReqVO |
支持工号、手机号、状态等组合查询 |
| 分部全量同步 | POST /system/integration/iwork/hr/subcompanies/full-sync |
IWorkFullSyncReqVO |
默认 scopes=subcompany,按分页批量落库 |
| 部门全量同步 | POST /system/integration/iwork/hr/departments/full-sync |
IWorkFullSyncReqVO |
自动处理父子依赖,多次遍历确保 parent ready |
| 岗位全量同步 | POST /system/integration/iwork/hr/job-titles/full-sync |
IWorkFullSyncReqVO |
岗位编码固定为 IWORK_JOB_${id} |
| 人员全量同步 | POST /system/integration/iwork/hr/users/full-sync |
IWorkFullSyncReqVO |
工号优先映射为用户名,自动建档岗位 |
Full Sync 请求参数
| 字段 | 默认值 | 说明 |
|---|---|---|
startPage |
1 | 开始拉取的页码,对应 iWork curpage |
pageSize |
100 | 单页数量(1-500) |
maxPages |
null | 限制最大页数,null 表示直到 iWork 返回空页 |
scopes |
全量 | 枚举 subcompany、department、jobTitle、user,可多选 |
id |
null | 指定单个 iWork 实体 ID,主要用于补偿 |
includeCanceled |
false | true 时同步 iWork 失效记录并将其禁用 |
allowUpdate |
false | 是否允许更新本地已有但来源为 iWork 的记录 |
系统内部始终启用
createIfMissing=true,因此全量同步会自动建档缺失的分部/部门/岗位/人员。
字段映射(组织)
| iWork 字段 | 本地字段 | 说明 |
|---|---|---|
subcompanyname / departmentname |
DeptDO.name |
自动截断到 30 字符,缺失时使用“未命名*” |
subcompanycode / departmentcode |
DeptDO.code |
空字符串会被置空,保持与 iWork 编码一致 |
supsubcomid / supdepid |
DeptDO.parentId |
优先使用部门父级,退化到分部或根节点 |
showorder |
DeptDO.sort |
为空则落地 999 |
canceled |
DeptDO.status |
1/true/yes 视为禁用(CommonStatusEnum.DISABLE) |
字段映射(人员与岗位)
| iWork 字段 | 本地字段 | 处理规则 |
|---|---|---|
jobtitleid |
PostDO.code=IWORK_JOB_${id} |
若本地不存在则自动建档,jobtitlename 作为名称 |
lastname |
AdminUserDO.nickname |
超过 30 字符会截断 |
workcode → loginid |
AdminUserDO.username |
首选工号,缺失时使用登录账号,均为空则跳过 |
departmentid → subcompanyid1 |
AdminUserDO.deptIds |
优先部门,空则落地分部,仍为空则允许为空继续 |
jobtitleid / jobtitlename |
AdminUserDO.postIds |
通过岗位编码命中缓存,否则按名称动态创建 |
email / mobile |
AdminUserDO.email/mobile |
同步时跳过重复验证,兼容历史数据 |
password |
AdminUserDO.password |
直接使用 iWork 原始密码,避免哈希不一致 |
status |
AdminUserDO.status |
0 视为启用,其余状态视为禁用 |
sex |
AdminUserDO.sex |
自动适配 0/1/2 与 男/女/M/F 等多种格式 |
组织同步禁用策略
| 场景 | 判定条件 | 本地处理 | 备注 |
|---|---|---|---|
| 分部/部门被禁用 | canceled = 1/true/yes |
若 includeCanceled=false:跳过;否则创建/更新并设置为禁用 |
可通过 includeCanceled 控制是否同步 |
| 岗位被禁用 | canceled 标记为真 |
同步后 PostDO.status=DISABLE,同时记入统计 |
|
| 人员离职 | status ≠ 0 |
创建/更新为 DISABLE,并统计在 disabled 数量 |
status 字段通常为字符串 |
| 非 iWork 数据 | deptSource/userSource ≠ iWork |
永远跳过修改,保证手工数据安全 | 相关日志输出 Skipped 提示 |
鉴权与签名
组织接口统一由 IWorkOrgRestService 代理,鉴权方式为:
- 读取
iwork.org.token-seed。 - 运行时生成
ts = System.currentTimeMillis()。 - 计算
key = MD5(tokenSeed + ts)并转大写。 - 将
{ key, ts }作为token字段写入请求体,iWork 会基于相同算法校验。
请确保 ZTCloud 所在网络与 iWork 可直接互通,否则需在接口网关上放通上述 URL。
组织接口字段详解
通用分页请求字段(IWorkOrgBaseQueryReqVO)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
curpage |
integer | 否 | 当前页码,默认 1 |
pagesize |
integer | 否 | 每页条数,默认 20,最大 500 |
params |
map | 否 | 额外查询条件,直接透传给 iWork |
POST /system/integration/iwork/hr/subcompany/page
请求字段(subcompany/page)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
curpage |
integer | 否 | 继承自通用分页字段 |
pagesize |
integer | 否 | 同上 |
subcompanyCode |
string | 否 | 按分部编码模糊查询 |
subcompanyName |
string | 否 | 按分部名称模糊查询 |
响应字段(IWorkHrSubcompanyPageRespVO)
| 字段 | 类型 | 说明 |
|---|---|---|
code |
string | iWork 返回码 |
message |
string | 提示信息 |
success |
boolean | 是否成功 |
totalSize |
integer | 总记录数 |
totalPage |
integer | 总页数 |
pageSize |
integer | 单页条数 |
pageNumber |
integer | 当前页码 |
dataList[] |
array | 分部列表 |
dataList[] 主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
integer | 分部 ID(也是本地部门 ID) |
subcompanycode |
string | 分部编码 |
subcompanyname |
string | 分部名称 |
companyid / companyname |
integer/string | 总部标识 |
supsubcomid / supsubcomname |
integer/string | 上级分部信息 |
showorder |
integer | 排序号 |
description |
string | 描述 |
canceled |
string | 是否失效(0/1/true/false) |
alllevel |
string | 层级路径 |
attributes |
map | iWork 额外字段的承载容器 |
JSON 示例(/hr/subcompany/page)
请求:
POST /system/integration/iwork/hr/subcompany/page HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"curpage": 1,
"pagesize": 50,
"subcompanyCode": "HZ",
"subcompanyName": "杭州"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": "SUCCESS",
"message": "OK",
"success": true,
"totalSize": 2,
"totalPage": 1,
"pageSize": 50,
"pageNumber": 1,
"dataList": [
{
"id": 1001,
"subcompanycode": "HZ01",
"subcompanyname": "杭州总部",
"supsubcomid": 0,
"showorder": 1,
"canceled": "0"
},
{
"id": 1002,
"subcompanycode": "HZ02",
"subcompanyname": "杭州制造分部",
"supsubcomid": 1001,
"showorder": 2,
"canceled": "0"
}
]
}
失败示例(鉴权失败):
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": "401",
"message": "key invalid",
"success": false,
"totalSize": 0,
"totalPage": 0,
"pageSize": 0,
"pageNumber": 0,
"dataList": []
}
POST /system/integration/iwork/hr/department/page
请求字段(department/page)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
curpage |
integer | 否 | 分页参数 |
pagesize |
integer | 否 | 分页参数 |
departmentCode |
string | 否 | 部门编码 |
departmentName |
string | 否 | 部门名称 |
subcompanyId |
string | 否 | 所属分部 ID |
响应字段(IWorkHrDepartmentPageRespVO)
顶层字段:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
string | iWork 返回码 |
message |
string | 提示信息 |
success |
boolean | 是否成功 |
data.totalSize |
integer | 总记录数 |
data.totalPage |
integer | 总页数 |
data.pageSize |
integer | 每页条数 |
data.page |
integer | 当前页码 |
data.dataList[] |
array | 部门列表 |
data.dataList[] 关键字段:部门 ID(id)、部门编码(departmentcode)、部门名称(departmentname)、所属分部(subcompanyid1 / subcompanyname)、父部门(supdepid)、显示顺序(showorder)、失效标记(canceled)等,其余原样透传在 attributes 中。
JSON 示例(/hr/department/page)
请求:
POST /system/integration/iwork/hr/department/page HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"curpage": 1,
"pagesize": 100,
"subcompanyId": "1001"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": "SUCCESS",
"message": "OK",
"success": true,
"data": {
"totalSize": 120,
"totalPage": 2,
"pageSize": 100,
"page": 1,
"dataList": [
{
"id": 2001,
"departmentcode": "R-D",
"departmentname": "研发一部",
"subcompanyid1": 1001,
"supdepid": 0,
"showorder": 10,
"canceled": "0"
}
]
}
}
POST /system/integration/iwork/hr/job-title/page
请求字段(job-title/page)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
curpage |
integer | 否 | 分页参数 |
pagesize |
integer | 否 | 分页参数 |
jobTitleCode |
string | 否 | 岗位编码 |
jobTitleName |
string | 否 | 岗位名称 |
响应字段(IWorkHrJobTitlePageRespVO)
| 字段 | 类型 | 说明 |
|---|---|---|
code |
string | iWork 返回码 |
message |
string | 提示信息 |
success |
boolean | 是否成功 |
totalSize / totalPage / pageSize / pageNumber |
integer | 分页信息 |
dataList[] |
array | 岗位集合 |
dataList[] 字段包含 id、jobtitlecode、jobtitlename、jobgroupid、jobgroupname、jobfunction、showorder、canceled 等,可直接映射到本地岗位表。
POST /system/integration/iwork/hr/user/page
请求字段(user/page)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
curpage / pagesize |
integer | 否 | 分页参数 |
workCode |
string | 否 | 人员工号 |
lastName |
string | 否 | 姓名模糊匹配 |
departmentId / subcompanyId |
string | 否 | 组织过滤 |
jobTitleId |
string | 否 | 岗位过滤 |
status |
string | 否 | 人员状态(0:在职,其余为非在职) |
mobile / email |
string | 否 | 联系方式过滤 |
响应字段(IWorkHrUserPageRespVO)
| 字段 | 类型 | 说明 |
|---|---|---|
code / message / success |
string/string/boolean | 通用响应字段 |
totalSize / totalPage / pageSize / pageNumber |
integer | 分页信息 |
dataList[] |
array | 人员数据 |
dataList[] 主要字段:id、lastname、loginid、workcode、sex、departmentid、subcompanyid1、jobtitleid、mobile、email、status、password、hiredate、leavedate 等,以及 attributes 中的扩展数据。同步服务会根据这些字段计算用户名、岗位与状态。
JSON 示例(/hr/user/page)
请求:
POST /system/integration/iwork/hr/user/page HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"curpage": 1,
"pagesize": 100,
"departmentId": "2001",
"status": "0"
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": "SUCCESS",
"message": "OK",
"success": true,
"totalSize": 320,
"totalPage": 4,
"pageSize": 100,
"pageNumber": 1,
"dataList": [
{
"id": 30001,
"lastname": "李四",
"loginid": "lisi",
"workcode": "A10086",
"departmentid": 2001,
"subcompanyid1": 1001,
"jobtitleid": 5001,
"mobile": "13800001111",
"email": "lisi@example.com",
"status": "0",
"password": "4a7d1ed414934d1c4b"
}
]
}
Full Sync 请求参数(IWorkFullSyncReqVO)
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
startPage |
integer | 1 | 起始页码,对应 iWork curpage |
pageSize |
integer | 100 | 单页记录数 (1-500) |
maxPages |
integer | null | 限制最大处理页数,null 表示遍历至空页 |
scopes |
array<string> |
["subcompany","department","jobTitle","user"] |
指定同步范围 |
id |
string | null | 仅同步指定 iWork 主键,常用于补偿 |
includeCanceled |
boolean | false | true 时会同步并禁用 iWork 标记为失效的数据 |
allowUpdate |
boolean | false | true 时允许覆盖已有的 iWork 来源记录 |
系统内部始终启用
createIfMissing=true,因此全量同步会自动建档缺失的分部/部门/岗位/人员。
Full Sync 响应字段(IWorkFullSyncRespVO)
| 字段 | 类型 | 说明 |
|---|---|---|
processedPages |
integer | 实际处理的页数总和 |
pageSize |
integer | 每批次请求的页大小回显 |
subcompanyStat / departmentStat / jobTitleStat / userStat |
IWorkSyncEntityStatVO |
各实体的累计统计 |
batches[] |
IWorkSyncBatchStatVO |
每个分页批次的明细 |
IWorkSyncEntityStatVO 字段:pulled(拉取条数)、created(新建)、skippedExisting(跳过)、disabled(禁用)、failed(失败)。
IWorkSyncBatchStatVO 字段:entityType(subcompany/department/job_title/user)、pageNumber、pulled、created、skippedExisting、disabled、failed。借助这些字段可以直观看到失败批次并进行定向补偿。
JSON 示例(/hr/users/full-sync)
请求:
POST /system/integration/iwork/hr/users/full-sync HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"startPage": 1,
"pageSize": 200,
"scopes": ["department", "user"],
"includeCanceled": false,
"allowUpdate": true
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 0,
"msg": "success",
"data": {
"processedPages": 6,
"pageSize": 200,
"departmentStat": {
"pulled": 600,
"created": 120,
"skippedExisting": 470,
"disabled": 5,
"failed": 5
},
"userStat": {
"pulled": 1200,
"created": 320,
"skippedExisting": 780,
"disabled": 60,
"failed": 40
},
"batches": [
{
"entityType": "DEPARTMENT",
"pageNumber": 1,
"pulled": 200,
"created": 40,
"skippedExisting": 150,
"disabled": 2,
"failed": 8
}
]
},
"traceId": "0cc5de912f40"
}
失败示例(iWork 远端异常):
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"code": 200501,
"msg": "调用 iWork 失败: 拉取人员接口超时",
"data": {
"processedPages": 3,
"pageSize": 200,
"userStat": {
"pulled": 600,
"created": 160,
"failed": 20
},
"batches": [
{
"entityType": "USER",
"pageNumber": 3,
"pulled": 200,
"failed": 20
}
]
},
"traceId": "ab771c30d4ee"
}
故障排查与常见问题
1. Token 申请失败
- 现象:
IWORK_APPLY_TOKEN_FAILED,日志提示 “返回缺少 token”。 - 处理:
- 确认
iwork.base-url是否指向正式域名; - 核对 appId、client 公钥是否与 iWork 后台一致;
- 如需重新注册,将
/auth/register与/auth/token的forceRefreshRegistration=true、forceRefreshToken=true同时置为 true。
- 确认
2. 组织分页 401 或“key 无效”
- 现象:iWork 返回
code=401或success=false,message 包含key invalid。 - 处理:
- 校验服务器时间是否与 iWork 相差 < 60s;
- 确保
token-seed未被误填为空; - 通过日志中输出的 cURL(
[iWork-Org] curl)复现请求,核对 key/ts 是否被代理层篡改。
3. 人员同步缺少岗位
- 现象:
BatchResult中failed大量增加,日志提示 “岗位缺少标识”。 - 处理:
- 确认先执行岗位全量同步;
- 若 iWork 未维护岗位,可在本地预建岗位并记录在字典,再由 iWork 返回
jobtitlename供系统创建。
4. 附件回调 404
- 现象:iWork 回调
/callback/file返回 “业务编码不能为空”。 - 处理:
- 需要提前在业务流程中调用
BusinessFileApi建立businessCode; - 回调只接受 POST JSON,并且必须包含
fileUrl、businessCode。
- 需要提前在业务流程中调用
诊断 checklist
- 查看
logs/system/iwork*.log,定位请求链路与响应体; - 通过
IWorkFullSyncRespVO的batches字段复盘每页统计; - 若同步停在某一批次,可使用
id+scopes方式做定向补偿; - 启用
includeCanceled=true可帮助确认 iWork 的状态标记是否准确。