1. iwork 统一用印发起接口

This commit is contained in:
chenbowen
2025-11-27 20:19:27 +08:00
parent 00b2f6312d
commit 64d0d4e55e
6 changed files with 160 additions and 74 deletions

View File

@@ -14,9 +14,6 @@ public class IWorkOperationRespVO {
@Schema(description = "iWork 返回的原始数据")
private Map<String, Object> payload;
@Schema(description = "iWork 返回的原始字符串")
private String rawBody;
@Schema(description = "是否判断为成功")
private boolean success;

View File

@@ -14,9 +14,6 @@ public class IWorkUserInfoRespVO {
@Schema(description = "iWork 返回的原始数据")
private Map<String, Object> payload;
@Schema(description = "iWork 返回的原始字符串")
private String rawBody;
@Schema(description = "是否判断为成功")
private boolean success;

View File

@@ -1,15 +1,9 @@
package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
import java.util.Map;
/**
* 发起 iWork 流程的请求体。
*/
@@ -17,25 +11,36 @@ import java.util.Map;
@EqualsAndHashCode(callSuper = true)
public class IWorkWorkflowCreateReqVO extends IWorkBaseReqVO {
@Schema(description = "流程标题", example = "测试流程")
@NotBlank(message = "流程标题不能为空")
private String requestName;
@Schema(description = "用印申请人iWork 人员 ID", example = "1001")
private String jbr;
@Schema(description = "流程模板编号,可为空使用默认配置", example = "54")
private Long workflowId;
@Schema(description = "用印部门 ID", example = "2001")
private String yybm;
@Schema(description = "主表字段")
@NotEmpty(message = "主表字段不能为空")
@Valid
private List<IWorkFormFieldVO> mainFields;
@Schema(description = "用印单位(分部 ID", example = "3001")
private String fb;
@Schema(description = "明细表数据")
@Valid
private List<IWorkDetailTableVO> detailTables;
@Schema(description = "申请时间,格式 yyyy-MM-dd", example = "2025-01-01")
private String sqsj;
@Schema(description = "额外参数")
private Map<String, Object> otherParams;
@Schema(description = "用印去向")
private String yyqx;
@Schema(description = "额外 Form 数据")
private Map<String, String> formExtras;
@Schema(description = "用印依据附件 URL")
private String yyfkUrl;
@Schema(description = "用印事由或内容摘要")
private String yysy;
@Schema(description = "用印材料附件 URL必填")
private String xyywjUrl;
@Schema(description = "用印事项")
private String yysx;
@Schema(description = "业务系统单据编号(用于派生流程标题)", example = "DJ-2025-0001")
private String ywxtdjbh;
@Schema(description = "流程模板编号(必填)", example = "54")
private String workflowId;
}

View File

@@ -18,4 +18,5 @@ public interface IWorkIntegrationErrorCodeConstants {
ErrorCode IWORK_WORKFLOW_ID_MISSING = new ErrorCode(1_010_200_008, "缺少 iWork 流程模板编号");
ErrorCode IWORK_ORG_IDENTIFIER_MISSING = new ErrorCode(1_010_200_009, "iWork 人力组织接口缺少认证标识");
ErrorCode IWORK_ORG_REMOTE_FAILED = new ErrorCode(1_010_200_010, "iWork 人力组织接口请求失败{}");
ErrorCode IWORK_SEAL_REQUIRED_FIELD_MISSING = new ErrorCode(1_010_200_011, "缺少用印必填字段:{}");
}

View File

@@ -128,7 +128,7 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
IWorkSession session = ensureSession(appId, clientKeyPair, operatorUserId, Boolean.TRUE.equals(reqVO.getForceRefreshToken()));
Map<String, Object> payload = buildCreatePayload(reqVO);
String responseBody = executeJsonRequest(properties.getPaths().getCreateWorkflow(), null, appId, session, payload);
String responseBody = executeFormRequest(properties.getPaths().getCreateWorkflow(), null, appId, session, payload);
return buildOperationResponse(responseBody);
}
@@ -324,6 +324,39 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
return executeRequest(request, IWORK_REMOTE_REQUEST_FAILED);
}
private String executeFormRequest(String path,
Map<String, Object> queryParams,
String appId,
IWorkSession session,
Map<String, Object> formFields) {
HttpUrl baseUrl = HttpUrl.parse(resolveUrl(path));
if (baseUrl == null) {
throw ServiceExceptionUtil.exception(IWORK_REMOTE_REQUEST_FAILED, "非法的 URL");
}
HttpUrl.Builder urlBuilder = baseUrl.newBuilder();
if (queryParams != null) {
queryParams.forEach((key, value) -> {
if (value != null) {
urlBuilder.addQueryParameter(key, String.valueOf(value));
}
});
}
FormBody.Builder bodyBuilder = new FormBody.Builder();
if (formFields != null) {
formFields.forEach((key, value) -> {
if (StringUtils.hasText(key) && value != null) {
bodyBuilder.add(key, toFormValue(value));
}
});
}
Request request = new Request.Builder()
.url(urlBuilder.build())
.headers(authHeaders(appId, session).build())
.post(bodyBuilder.build())
.build();
return executeRequest(request, IWORK_REMOTE_REQUEST_FAILED);
}
private Headers.Builder authHeaders(String appId, IWorkSession session) {
return new Headers.Builder()
.set(properties.getHeaders().getAppId(), appId)
@@ -331,6 +364,19 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
.set(properties.getHeaders().getUserId(), session.getEncryptedUserId());
}
private String toFormValue(Object value) {
if (value == null) {
return "";
}
if (value instanceof CharSequence || value instanceof Number || value instanceof Boolean) {
return String.valueOf(value);
}
if (value.getClass().isArray() || value instanceof Collection<?> || value instanceof Map<?, ?>) {
return toJsonString(value);
}
return value.toString();
}
private Map<String, Object> buildUserPayload(IWorkUserInfoReqVO reqVO) {
Map<String, Object> payload = new HashMap<>();
if (reqVO.getPayload() != null) {
@@ -342,27 +388,81 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
private Map<String, Object> buildCreatePayload(IWorkWorkflowCreateReqVO reqVO) {
Map<String, Object> payload = new LinkedHashMap<>();
payload.put("requestName", reqVO.getRequestName());
payload.put("workflowId", resolveWorkflowId(reqVO.getWorkflowId()));
payload.put("mainData", convertFormFields(reqVO.getMainFields()));
if (reqVO.getDetailTables() != null && !reqVO.getDetailTables().isEmpty()) {
payload.put("detailData", convertDetailTables(reqVO.getDetailTables()));
}
if (reqVO.getOtherParams() != null && !reqVO.getOtherParams().isEmpty()) {
payload.put("otherParams", reqVO.getOtherParams());
}
appendPayloadExtras(payload, reqVO.getFormExtras());
SealRequestFields fields = resolveSealFields(reqVO);
payload.put("requestName", buildRequestName(fields.ywxtdjbh()));
payload.put("workflowId", parseWorkflowId(fields.workflowId()));
payload.put("mainData", buildSealMainData(fields));
return payload;
}
private long resolveWorkflowId(Long requestWorkflowId) {
if (requestWorkflowId != null) {
return requestWorkflowId;
private String buildRequestName(String billNo) {
return "用印-" + billNo;
}
private long parseWorkflowId(String workflowId) {
try {
return Long.parseLong(workflowId);
} catch (NumberFormatException ex) {
throw ServiceExceptionUtil.exception(IWORK_SEAL_REQUIRED_FIELD_MISSING, "workflowId");
}
if (properties.getWorkflowId() != null) {
return properties.getWorkflowId();
}
private List<Map<String, Object>> buildSealMainData(SealRequestFields fields) {
List<Map<String, Object>> main = new ArrayList<>();
addField(main, "jbr", fields.jbr());
addField(main, "yybm", fields.yybm());
addField(main, "fb", fields.fb());
addField(main, "sqsj", fields.sqsj());
addField(main, "yyqx", fields.yyqx());
addField(main, "yyfk", fields.yyfkUrl());
addField(main, "yysy", fields.yysy());
addField(main, "xyywj", fields.xyywjUrl());
addField(main, "yysx", fields.yysx());
addField(main, "lclx", SealRequestFields.DEFAULT_FLOW_TYPE);
addField(main, "qsdz", SealRequestFields.DEFAULT_SIGN_ACTION);
addField(main, "ywxtdjbh", fields.ywxtdjbh());
return main;
}
private void addField(List<Map<String, Object>> target, String name, String value) {
if (!StringUtils.hasText(value)) {
return;
}
throw ServiceExceptionUtil.exception(IWORK_WORKFLOW_ID_MISSING);
Map<String, Object> map = new HashMap<>(2);
map.put("fieldName", name);
map.put("fieldValue", value);
target.add(map);
}
private SealRequestFields resolveSealFields(IWorkWorkflowCreateReqVO reqVO) {
String jbr = requireSealField(reqVO.getJbr(), "jbr");
String yybm = requireSealField(reqVO.getYybm(), "yybm");
String fb = requireSealField(reqVO.getFb(), "fb");
String sqsj = requireSealField(reqVO.getSqsj(), "sqsj");
String yyqx = requireSealField(reqVO.getYyqx(), "yyqx");
String xyywjUrl = requireSealField(reqVO.getXyywjUrl(), "xyywjUrl");
String yysx = requireSealField(reqVO.getYysx(), "yysx");
String billNo = requireSealField(reqVO.getYwxtdjbh(), "ywxtdjbh");
String workflowId = requireSealField(reqVO.getWorkflowId(), "workflowId");
String yyfkUrl = trimToNull(reqVO.getYyfkUrl());
String yysy = trimToNull(reqVO.getYysy());
return new SealRequestFields(jbr, yybm, fb, sqsj, yyqx, yyfkUrl, yysy, xyywjUrl, yysx, billNo, workflowId);
}
private String requireSealField(String value, String fieldName) {
String trimmed = trimToNull(value);
if (trimmed == null) {
throw ServiceExceptionUtil.exception(IWORK_SEAL_REQUIRED_FIELD_MISSING, fieldName);
}
return trimmed;
}
private String trimToNull(String value) {
if (!StringUtils.hasText(value)) {
return null;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
private Map<String, Object> buildVoidPayload(IWorkWorkflowVoidReqVO reqVO) {
@@ -389,35 +489,8 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
});
}
private List<Map<String, Object>> convertFormFields(List<IWorkFormFieldVO> fields) {
return fields.stream().map(field -> {
Map<String, Object> map = new HashMap<>(2);
map.put("fieldName", field.getFieldName());
map.put("fieldValue", field.getFieldValue());
return map;
}).toList();
}
private List<Map<String, Object>> convertDetailTables(List<IWorkDetailTableVO> tables) {
return tables.stream().map(table -> {
Map<String, Object> tableMap = new HashMap<>(2);
tableMap.put("tableDBName", table.getTableDBName());
List<Map<String, Object>> records = table.getRecords().stream().map(record -> {
Map<String, Object> recordMap = new HashMap<>(2);
if (record.getRecordOrder() != null) {
recordMap.put("recordOrder", record.getRecordOrder());
}
recordMap.put("workflowRequestTableFields", convertFormFields(record.getFields()));
return recordMap;
}).toList();
tableMap.put("workflowRequestTableRecords", records);
return tableMap;
}).toList();
}
private IWorkUserInfoRespVO buildUserInfoResponse(String responseBody) {
IWorkUserInfoRespVO respVO = new IWorkUserInfoRespVO();
respVO.setRawBody(responseBody);
if (!StringUtils.hasText(responseBody)) {
return respVO;
}
@@ -432,7 +505,6 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
private IWorkOperationRespVO buildOperationResponse(String responseBody) {
IWorkOperationRespVO respVO = new IWorkOperationRespVO();
respVO.setRawBody(responseBody);
if (!StringUtils.hasText(responseBody)) {
return respVO;
}
@@ -666,6 +738,21 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
return value.replace("'", "'\"'\"'");
}
private record SealRequestFields(String jbr,
String yybm,
String fb,
String sqsj,
String yyqx,
String yyfkUrl,
String yysy,
String xyywjUrl,
String yysx,
String ywxtdjbh,
String workflowId) {
private static final String DEFAULT_FLOW_TYPE = "2979600781334966993";
private static final String DEFAULT_SIGN_ACTION = "CORPORATE";
}
private record RegistrationState(String secret, String spk, ClientKeyPair clientKeyPair) {
}

View File

@@ -109,7 +109,6 @@ iwork:
base-url: http://172.16.36.233:8080
# app-id: f47ac10b-58cc-4372-a567-0e02b2c3d479
app-id: f47ac10b-58cc-4372-a567-0e02b2c3d479
client-public-key:
user-id: 9869
workflow-id: 1753
paths: