From 0bcb3550792be4008271c6e7c0beeac2488db72b Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Sat, 17 Oct 2026 15:35:20 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20=E4=BF=AE=E5=A4=8DMK=E5=85=AC=E5=BC=80?= =?UTF-8?q?=E9=A1=B5=E5=AE=A1=E6=89=B9=E5=9B=9E=E5=86=99=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81OA=E9=83=A8=E9=97=A8=E6=8C=89=E5=85=AC?= =?UTF-8?q?=E5=8F=B8oaId=E8=BD=AE=E8=AF=A2=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../system/pojo/vo/OaOrgSyncPageVO.java | 15 ++ .../system/controller/DeptController.java | 7 +- .../system/service/IOASyncService.java | 7 +- .../service/impl/OASyncServiceImpl.java | 138 +++++++++++------- .../transport/mk/MkProcessBizHandlers.java | 24 ++- .../transport/mk/MkProcessMessageService.java | 103 +++++++++---- 6 files changed, 205 insertions(+), 89 deletions(-) diff --git a/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/vo/OaOrgSyncPageVO.java b/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/vo/OaOrgSyncPageVO.java index bd1bd7a4..b58f8e73 100644 --- a/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/vo/OaOrgSyncPageVO.java +++ b/blade-service-api/blade-system-api/src/main/java/org/springblade/system/pojo/vo/OaOrgSyncPageVO.java @@ -72,4 +72,19 @@ public class OaOrgSyncPageVO implements Serializable { @Schema(description = "全量同步结束后原始数据层级 JSON 文件路径") private String dumpFilePath; + + @Schema(description = "当前同步的公司 OA 主键(部门阶段按公司轮询时使用)") + private String companyOaId; + + @Schema(description = "当前公司序号,从 1 开始") + private Integer companyIndex; + + @Schema(description = "待同步公司总数") + private Integer companyTotal; + + @Schema(description = "当前公司的部门是否已同步完") + private Boolean companyFinished; + + @Schema(description = "下一公司 OA 主键;当前公司完成后回传,前端据此切换并重置页码") + private String nextCompanyOaId; } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/controller/DeptController.java b/blade-service/blade-system/src/main/java/org/springblade/system/controller/DeptController.java index 39d60f72..47ef9a82 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/controller/DeptController.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/controller/DeptController.java @@ -204,7 +204,7 @@ public class DeptController extends BladeController { } /** - * 从OA按页同步部门(需先完成公司同步) + * 从OA按页同步部门(需先完成公司同步;按公司 oaId 轮询查询) */ @IsAdmin @PostMapping("/sync-oa-department") @@ -214,8 +214,9 @@ public class DeptController extends BladeController { @RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "20") Integer size, @RequestParam(defaultValue = "false") Boolean incremental, - @RequestParam(required = false) String modifiedSince) { - return R.data(oaSyncService.syncDepartmentPage(current, size, Boolean.TRUE.equals(incremental), modifiedSince)); + @RequestParam(required = false) String modifiedSince, + @RequestParam(required = false) String companyOaId) { + return R.data(oaSyncService.syncDepartmentPage(current, size, Boolean.TRUE.equals(incremental), modifiedSince, companyOaId)); } /** diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/IOASyncService.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/IOASyncService.java index 3b003897..266b9e57 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/IOASyncService.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/IOASyncService.java @@ -52,13 +52,14 @@ public interface IOASyncService { OaOrgSyncPageVO syncCompanyPage(int current, int size, boolean incremental, String modifiedSince); /** - * 按页从 OA 部门接口同步部门;最后一页完成后更新祖级列表 + * 按页从 OA 部门接口同步部门;须先完成公司同步,再按公司 oaId 轮询查询部门 * - * @param current 当前页,从 1 开始 + * @param current 当前页,从 1 开始(相对当前公司) * @param size 每页条数 * @param incremental 是否增量同步(按本地最大 oaModified 过滤 OA) * @param modifiedSince 增量起始时间;首屏可空,后续分页回传首屏返回值 + * @param companyOaId 当前公司 OA 主键;首屏可空(自动取第一家),后续回传 * @return 本页同步结果 */ - OaOrgSyncPageVO syncDepartmentPage(int current, int size, boolean incremental, String modifiedSince); + OaOrgSyncPageVO syncDepartmentPage(int current, int size, boolean incremental, String modifiedSince, String companyOaId); } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java index 4cb3487f..72930c52 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java @@ -153,10 +153,10 @@ public class OASyncServiceImpl implements IOASyncService { @Transactional(rollbackFor = Exception.class) @Override - public OaOrgSyncPageVO syncDepartmentPage(int current, int size, boolean incremental, String modifiedSince) { + public OaOrgSyncPageVO syncDepartmentPage(int current, int size, boolean incremental, String modifiedSince, String companyOaId) { try { ComposeLogUtil.addLog(log); - return this.syncDepartmentFromOaPage(current, size, incremental, modifiedSince); + return this.syncDepartmentFromOaPage(current, size, incremental, modifiedSince, companyOaId); } finally { ComposeLogUtil.removeLastLog(); } @@ -224,29 +224,28 @@ public class OASyncServiceImpl implements IOASyncService { } /** - * 同步部门 + * 同步部门:先整理已同步公司,再按公司 oaId 逐个轮询查询部门 * @param startTime 查询开始时间 */ private void syncDept(Date startTime) { - String subCompanyIds = getOaSubCompanyIds(false); - if (StringUtils.isEmpty(subCompanyIds)) { + List companyOaIds = listAllowedCompanyOaIds(false); + if (CollectionUtil.isEmpty(companyOaIds)) { ComposeLogUtil.getLastLog().warn("未查询到子公司查询参数"); return; } // 未处理的数据 List notHandleList = new ArrayList<>(); - // 1. 设置查询参数 - OADepartmentSearch departmentSearch = buildDepartmentSearch(startTime, subCompanyIds); - // 2. 分页查询并处理数据 - OAUtils.pageSyncHandler(departmentSearch, param -> oaClient.queryDepartmentPage(new OASearch<>(param)), response -> { - ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 {}", JSON.toJSONString(response)); - return new ServiceException("调用OA接口查询部门信息失败"); - }, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> { - // 处理数据 - OrgSyncCount syncCount = handleDept(list, false); - notHandleList.addAll(syncCount.getNotHandledList()); - }); - // 3. 未处理的数据 + for (String companyOaId : companyOaIds) { + ComposeLogUtil.getLastLog().info("按公司轮询同步部门 companyOaId={}", companyOaId); + OADepartmentSearch departmentSearch = buildDepartmentSearch(startTime, companyOaId); + OAUtils.pageSyncHandler(departmentSearch, param -> oaClient.queryDepartmentPage(new OASearch<>(param)), response -> { + ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 companyOaId={} {}", companyOaId, JSON.toJSONString(response)); + return new ServiceException("调用OA接口查询部门信息失败"); + }, 10000, ComposeLogUtil.getLastLog()::info).accept(list -> { + OrgSyncCount syncCount = handleDept(list, false); + notHandleList.addAll(syncCount.getNotHandledList()); + }); + } if (CollectionUtil.isNotEmpty(notHandleList)) { ComposeLogUtil.getLastLog().warn("同步部门,还有未处理的数据:{}", JSON.toJSONString(notHandleList)); } @@ -398,34 +397,55 @@ public class OASyncServiceImpl implements IOASyncService { } /** - * 按页从 OA 部门接口同步部门 + * 按页从 OA 部门接口同步部门:公司数据整理完成后,按公司 oaId 逐个轮询查询 * - * @param current 当前页 + * @param current 当前页(相对当前公司) * @param size 每页条数 * @param incremental 是否增量同步 * @param modifiedSince 增量起始时间(后续分页回传) + * @param companyOaId 当前公司 OA 主键;空则从第一家开始 * @return 本页同步结果 */ - private OaOrgSyncPageVO syncDepartmentFromOaPage(int current, int size, boolean incremental, String modifiedSince) { + private OaOrgSyncPageVO syncDepartmentFromOaPage(int current, int size, boolean incremental, String modifiedSince, + String companyOaId) { int pageNo = current < 1 ? 1 : current; int pageSize = size < 1 ? 20 : Math.min(size, 200); - String subCompanyIds = getOaSubCompanyIds(true); - if (StringUtils.isEmpty(subCompanyIds)) { + // 先整理已同步企业列表,再按企业轮询 + List companyOaIds = listAllowedCompanyOaIds(true); + if (CollectionUtil.isEmpty(companyOaIds)) { ComposeLogUtil.getLastLog().warn("未查询到已同步的OA公司,跳过部门同步"); OaOrgSyncPageVO emptyPageVO = buildOrgSyncPageVO("department", pageNo, pageSize, 0L, 0, OrgSyncCount.empty()); emptyPageVO.setFinished(true); + emptyPageVO.setCompanyFinished(true); + emptyPageVO.setCompanyIndex(0); + emptyPageVO.setCompanyTotal(0); if (!incremental) { emptyPageVO.setDumpFilePath(oaSyncRawDumpHelper.finishOrgFullDump()); } return emptyPageVO; } + int companyIndex = 0; + String currentCompanyOaId = companyOaIds.get(0); + if (StringUtils.isNotBlank(companyOaId)) { + int foundIndex = companyOaIds.indexOf(companyOaId.trim()); + if (foundIndex >= 0) { + companyIndex = foundIndex; + currentCompanyOaId = companyOaIds.get(foundIndex); + } else { + ComposeLogUtil.getLastLog().warn("回传公司oaId不在待同步列表中,回退第一家 companyOaId={}", companyOaId); + } + } IncrementalStart incrementalStart = resolveIncrementalStart(incremental, modifiedSince, DeptCategory.DEPT); - OADepartmentSearch departmentSearch = buildDepartmentSearch(incrementalStart.getStartTime(), subCompanyIds); + // 查询部门时只传当前公司的 oa_id + OADepartmentSearch departmentSearch = buildDepartmentSearch(incrementalStart.getStartTime(), currentCompanyOaId); departmentSearch.setCurPage(pageNo); departmentSearch.setPageSize(pageSize); + ComposeLogUtil.getLastLog().info("按公司查询OA部门 companyOaId={} companyIndex={}/{} page={}/{}", + currentCompanyOaId, companyIndex + 1, companyOaIds.size(), pageNo, pageSize); OAResponse oaResponse = oaClient.queryDepartmentPage(new OASearch<>(departmentSearch)); if (oaResponse == null || !OAConstant.OA_SUCCESS_CODE.equals(oaResponse.getCode()) || oaResponse.getData() == null) { - ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 {}", JSON.toJSONString(oaResponse)); + ComposeLogUtil.getLastLog().error("调用OA接口查询部门信息失败 companyOaId={} {}", + currentCompanyOaId, JSON.toJSONString(oaResponse)); throw new ServiceException("调用OA接口查询部门信息失败"); } OAResponseData responseData = oaResponse.getData(); @@ -437,25 +457,44 @@ public class OASyncServiceImpl implements IOASyncService { } OrgSyncCount syncCount = handleDept(oaDepartments, true); if (CollectionUtil.isNotEmpty(syncCount.getNotHandledList())) { - ComposeLogUtil.getLastLog().warn("同步部门,本页未处理数据:{}", JSON.toJSONString(syncCount.getNotHandledList())); + ComposeLogUtil.getLastLog().warn("同步部门,本页未处理数据 companyOaId={}:{}", + currentCompanyOaId, JSON.toJSONString(syncCount.getNotHandledList())); } OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("department", pageNo, pageSize, totalSize, oaDepartments.size(), syncCount); pageVO.setModifiedSince(incrementalStart.getModifiedSince()); - if (Boolean.TRUE.equals(pageVO.getFinished())) { - // 部门分批同步完成后,清理白名单外组织、重建层级、清理无法挂载数据并刷新祖级列表 - this.removeOutsideWhitelistOrgs(); - deptService.rebuildOaHierarchy(); - deptService.removeOaOrphansWithoutParent(); - deptService.updateAncestors(null); - if (!incremental) { - pageVO.setDumpFilePath(oaSyncRawDumpHelper.finishOrgFullDump()); + pageVO.setCompanyOaId(currentCompanyOaId); + pageVO.setCompanyIndex(companyIndex + 1); + pageVO.setCompanyTotal(companyOaIds.size()); + boolean companyPageFinished = Boolean.TRUE.equals(pageVO.getFinished()); + if (companyPageFinished) { + if (companyIndex + 1 < companyOaIds.size()) { + // 当前公司部门已拉完,进入下一公司(整体未结束,不重建层级) + pageVO.setCompanyFinished(true); + pageVO.setNextCompanyOaId(companyOaIds.get(companyIndex + 1)); + pageVO.setFinished(false); + } else { + // 全部公司轮询完成:清理白名单外组织、重建层级、清理无法挂载数据并刷新祖级列表 + pageVO.setCompanyFinished(true); + pageVO.setNextCompanyOaId(null); + pageVO.setFinished(true); + this.removeOutsideWhitelistOrgs(); + deptService.rebuildOaHierarchy(); + deptService.removeOaOrphansWithoutParent(); + deptService.updateAncestors(null); + if (!incremental) { + pageVO.setDumpFilePath(oaSyncRawDumpHelper.finishOrgFullDump()); + } } + } else { + pageVO.setCompanyFinished(false); + pageVO.setNextCompanyOaId(currentCompanyOaId); + pageVO.setFinished(false); } CacheUtil.clear(SYS_CACHE); CacheUtil.clear(SYS_CACHE, Boolean.FALSE); - ComposeLogUtil.getLastLog().info("OA部门分页同步完成 mode={} {}/{},成功{},跳过{}", - incremental ? "incremental" : "full", pageNo, totalSize, - syncCount.getSyncedCount(), syncCount.getSkippedCount()); + ComposeLogUtil.getLastLog().info("OA部门分页同步完成 mode={} companyOaId={} company={}/{} page={}/{},成功{},跳过{}", + incremental ? "incremental" : "full", currentCompanyOaId, companyIndex + 1, companyOaIds.size(), + pageNo, totalSize, syncCount.getSyncedCount(), syncCount.getSkippedCount()); return pageVO; } @@ -604,15 +643,15 @@ public class OASyncServiceImpl implements IOASyncService { /** * 组装 OA 部门分页查询参数 * - * @param startTime 增量查询开始时间 - * @param subCompanyIds 子公司 id 列表 + * @param startTime 增量查询开始时间 + * @param companyOaId 当前公司 OA 主键(单次只传一家公司) * @return 查询参数 */ - private OADepartmentSearch buildDepartmentSearch(Date startTime, String subCompanyIds) { + private OADepartmentSearch buildDepartmentSearch(Date startTime, String companyOaId) { OADepartmentSearch departmentSearch = new OADepartmentSearch(); departmentSearch.setCurPage(1); departmentSearch.setPageSize(20); - departmentSearch.setSubcompanyid1(subCompanyIds); + departmentSearch.setSubcompanyid1(companyOaId); if (startTime != null) { departmentSearch.setModified(DateUtil.format(startTime, DateUtil.PATTERN_DATETIME)); } @@ -1145,12 +1184,12 @@ public class OASyncServiceImpl implements IOASyncService { } /** - * 获取 OA 部门查询使用的子公司 id + * 整理部门同步用的公司 OA 主键列表(公司阶段完成后调用) * * @param syncAll true=取已同步的全部 OA 公司;false=仅取字典配置的公司 - * @return 逗号分隔的 OA 公司 id + * @return 白名单内公司 oaId 列表(去重、保序) */ - private String getOaSubCompanyIds(boolean syncAll) { + private List listAllowedCompanyOaIds(boolean syncAll) { List companyList; if (syncAll) { companyList = deptService.list(Wrappers.lambdaQuery() @@ -1161,7 +1200,7 @@ public class OASyncServiceImpl implements IOASyncService { } else { Set companyNames = this.getCompanyNames(); if (companyNames.isEmpty()) { - return null; + return Collections.emptyList(); } companyList = deptService.list(Wrappers.lambdaQuery() .in(Dept::getDeptName, companyNames) @@ -1170,20 +1209,17 @@ public class OASyncServiceImpl implements IOASyncService { .ne(Dept::getOaId, "") ); } - Map companyByOaId = new HashMap<>(); + Map companyByOaId = new LinkedHashMap<>(); for (Dept company : companyList) { String oaId = this.resolveOaCompanyId(company); if (StringUtils.isNotBlank(oaId)) { - companyByOaId.put(oaId, company); + companyByOaId.putIfAbsent(oaId, company); } } Set allowedCompanyOaIds = resolveAllowedCompanyOaIds(companyByOaId); - return companyList.stream() - .map(this::resolveOaCompanyId) - .filter(StringUtils::isNotBlank) + return companyByOaId.keySet().stream() .filter(allowedCompanyOaIds::contains) - .distinct() - .collect(Collectors.joining(",")); + .collect(Collectors.toList()); } /** diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java index 68aabb25..b96c8469 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java @@ -1,6 +1,7 @@ package org.springblade.transport.mk; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springblade.core.tenant.annotation.TenantIgnore; import org.springblade.core.tool.utils.Func; import org.springblade.transport.pojo.dto.BillPaymentStatusRequest; @@ -270,6 +271,7 @@ public final class MkProcessBizHandlers { } } + @Slf4j @Component @TenantIgnore @RequiredArgsConstructor @@ -290,6 +292,12 @@ public final class MkProcessBizHandlers { public boolean syncFromProcessInfo(Long id, Object processInfo) { FormalSettlement entity = service.getById(id); if (entity == null) { + log.warn("MK同步当前节点失败,正式结算单不存在 id={}", id); + return false; + } + // 已终态单据禁止再写回审批中,避免流程结束后的节点刷新把状态打回 reviewing + if ("approved".equals(entity.getApprovalStatus()) || "returned".equals(entity.getApprovalStatus()) + || "voided".equals(entity.getApprovalStatus())) { return false; } String node = MkProcessNodeHelper.currentNode(processInfo); @@ -310,8 +318,12 @@ public final class MkProcessBizHandlers { @Override public boolean approveFromProcess(Long id, String processorName) { FormalSettlement entity = service.getById(id); - if (entity == null || "approved".equals(entity.getApprovalStatus())) { - return entity != null; + if (entity == null) { + log.error("MK审批通过同步失败,正式结算单不存在 id={}", id); + return false; + } + if ("approved".equals(entity.getApprovalStatus())) { + return true; } // 统一走 service.approve:与手动审批同一入口(补变更记录),审批事务提交后自动触发金蝶推送事件; // 仅审批中单据允许通过,重复回调被状态校验拒绝,不重复推送 @@ -330,8 +342,12 @@ public final class MkProcessBizHandlers { @Override public boolean rejectFromProcess(Long id, String processorName) { FormalSettlement entity = service.getById(id); - if (entity == null || "returned".equals(entity.getApprovalStatus())) { - return entity != null; + if (entity == null) { + log.error("MK审批驳回同步失败,正式结算单不存在 id={}", id); + return false; + } + if ("returned".equals(entity.getApprovalStatus())) { + return true; } entity.setApprovalStatus("returned"); entity.setCurrentNode("审核不通过"); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessMessageService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessMessageService.java index 2e23f078..debb8852 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessMessageService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessMessageService.java @@ -4,10 +4,12 @@ import com.alibaba.fastjson2.JSON; import jakarta.annotation.PreDestroy; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springblade.core.tenant.TenantUtil; import org.springblade.core.tenant.annotation.TenantIgnore; import org.springblade.core.tool.api.FR; import org.springblade.core.tool.utils.StringUtil; import org.springblade.process.feign.IBusinessProcessClient; +import org.springblade.process.pojo.vo.MkFormBindVO; import org.springframework.stereotype.Service; import java.util.Collections; @@ -69,9 +71,9 @@ public class MkProcessMessageService { log.warn("公开页流程消息未找到 processId,跳过查询当前节点 bizType={}", bizType); return; } - String bizIdText = firstText(asMap(body == null ? null : body.get("formData")), "id", "formInstanceId"); + Long bizId = resolveBizId(asMap(body == null ? null : body.get("formData"))); queryCurrentNodes(bizType, processId, loginName); - scheduleProcessInfo(handler, bizType, processId, loginName, bizIdText, formValues); + scheduleProcessInfo(handler, bizType, processId, loginName, bizId, formValues); } private void queryCurrentNodes(String bizType, String processId, String loginName) { @@ -86,36 +88,35 @@ public class MkProcessMessageService { } private void scheduleProcessInfo(IMkProcessBizHandler handler, String bizType, String processId, - String loginName, String bizIdText, Map formValues) { + String loginName, Long bizId, Map formValues) { Map formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues); - log.info("公开页将在{}秒后查询流程实例详情 bizType={} processId={}", PROCESS_INFO_DELAY_SECONDS, bizType, processId); + log.info("公开页将在{}秒后查询流程实例详情 bizType={} processId={} bizId={}", + PROCESS_INFO_DELAY_SECONDS, bizType, processId, bizId); + // 延迟任务跑在独立线程,请求态 @TenantIgnore 已丢失,必须显式 ignore,否则 getById 可能因租户条件查空 scheduler.schedule( - () -> queryProcessInfo(handler, bizType, processId, loginName, bizIdText, formValuesCopy), + () -> TenantUtil.ignore(() -> queryProcessInfo(handler, bizType, processId, loginName, bizId, formValuesCopy)), PROCESS_INFO_DELAY_SECONDS, TimeUnit.SECONDS ); } private void queryProcessInfo(IMkProcessBizHandler handler, String bizType, String processId, - String loginName, String bizIdText, Map formValues) { + String loginName, Long bizId, Map formValues) { try { FR processInfoResult = businessProcessClient.getProcessInfo(processId, loginName); Object processInfo = processInfoResult == null ? null : processInfoResult.getData(); - log.info("公开页流程消息流程实例详情 bizType={} processId={} loginName={} result={}", - bizType, processId, loginName, JSON.toJSONString(processInfo)); + log.info("公开页流程消息流程实例详情 bizType={} processId={} loginName={} bizId={} result={}", + bizType, processId, loginName, bizId, JSON.toJSONString(processInfo)); if (isProcessFinished(processInfo)) { - applyProcessResult(handler, bizType, bizIdText, processId, formValues, true); + applyProcessResult(handler, bizType, bizId, processId, formValues, true); } else if (MkProcessNodeHelper.isProcessRejected(processInfo)) { - applyProcessResult(handler, bizType, bizIdText, processId, formValues, false); - } else if (StringUtil.isNotBlank(bizIdText)) { - try { - handler.syncFromProcessInfo(Long.valueOf(bizIdText), processInfo); - } catch (NumberFormatException e) { - log.warn("公开页流程消息业务id格式不正确 bizType={} id={}", bizType, bizIdText); - } + applyProcessResult(handler, bizType, bizId, processId, formValues, false); + } else if (bizId != null) { + handler.syncFromProcessInfo(bizId, processInfo); } } catch (Exception e) { - log.error("公开页查询流程实例详情失败 bizType={} processId={} loginName={}", bizType, processId, loginName, e); + log.error("公开页查询流程实例详情失败 bizType={} processId={} loginName={} bizId={}", + bizType, processId, loginName, bizId, e); } } @@ -123,21 +124,24 @@ public class MkProcessMessageService { return "30".equals(firstText(asMap(processInfo), "fdProcessStatus")); } - private void applyProcessResult(IMkProcessBizHandler handler, String bizType, String bizIdText, + private void applyProcessResult(IMkProcessBizHandler handler, String bizType, Long bizId, String processId, Map formValues, boolean approved) { String action = approved ? "审核通过" : "审核驳回"; - if (StringUtil.isBlank(bizIdText)) { - log.warn("流程{}但未找到业务id,跳过同步 bizType={} processId={}", action, bizType, processId); + if (bizId == null) { + log.warn("流程{}但未解析到业务主键,跳过同步 bizType={} processId={}", action, bizType, processId); return; } try { String processorName = firstText(formValues, "mkUserName", "mkLoginName"); - Long bizId = Long.valueOf(bizIdText); - if (approved) { - handler.approveFromProcess(bizId, processorName); - } else { - handler.rejectFromProcess(bizId, processorName); + boolean synced = approved + ? handler.approveFromProcess(bizId, processorName) + : handler.rejectFromProcess(bizId, processorName); + if (!synced) { + log.error("流程{}同步业务状态失败(业务单据不存在或未更新) bizType={} bizId={} processId={}", + action, bizType, bizId, processId); + return; } + log.info("流程{}同步业务状态成功 bizType={} bizId={} processId={}", action, bizType, bizId, processId); try { FR markResult = businessProcessClient.markProcessFinished(processId, approved); log.info("公开页标记业务流程完结 bizType={} processId={} approved={} result={}", @@ -146,13 +150,56 @@ public class MkProcessMessageService { log.error("公开页标记业务流程完结失败 bizType={} processId={} approved={}", bizType, processId, approved, markException); } - } catch (NumberFormatException e) { - log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText); } catch (Exception e) { - log.error("流程{}同步业务状态失败 bizType={} id={} processId={}", action, bizType, bizIdText, processId, e); + log.error("流程{}同步业务状态失败 bizType={} bizId={} processId={}", action, bizType, bizId, processId, e); } } + /** + * 公开页 formData 里的 id / formInstanceId 可能是表单实例 id(与业务主键不同), + * 须先按 MkFormBind 反查业务主键,与 detail 接口保持一致。 + */ + private Long resolveBizId(Map formData) { + String formInstanceIdText = firstText(formData, "formInstanceId"); + String idText = firstText(formData, "id"); + Long resolved = resolveByFormInstanceId(formInstanceIdText); + if (resolved != null) { + return resolved; + } + resolved = resolveByFormInstanceId(idText); + if (resolved != null) { + return resolved; + } + if (StringUtil.isNotBlank(idText)) { + try { + return Long.valueOf(idText); + } catch (NumberFormatException e) { + log.warn("公开页流程消息业务id格式不正确 id={}", idText); + } + } + return null; + } + + private Long resolveByFormInstanceId(String formInstanceIdText) { + if (StringUtil.isBlank(formInstanceIdText)) { + return null; + } + try { + Long formInstanceId = Long.valueOf(formInstanceIdText); + FR result = businessProcessClient.resolveByFormInstanceId(formInstanceId); + if (result != null && result.isSuccess() && result.getData() != null && result.getData().getBizId() != null) { + Long bizId = result.getData().getBizId(); + log.info("公开页按表单实例id解析业务主键 formInstanceId={} bizId={}", formInstanceId, bizId); + return bizId; + } + } catch (NumberFormatException e) { + log.warn("公开页表单实例id格式不正确 formInstanceId={}", formInstanceIdText); + } catch (Exception e) { + log.warn("公开页按表单实例id解析业务主键失败 formInstanceId={}", formInstanceIdText, e); + } + return null; + } + private static Map asMap(Object value) { if (!(value instanceof Map map)) { return Collections.emptyMap();