diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchivePublicController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchivePublicController.java index 19ed444..1df02ea 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchivePublicController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/CustomerArchivePublicController.java @@ -35,13 +35,11 @@ import org.springblade.core.mp.support.Query; import org.springblade.core.secure.annotation.PreAuth; import org.springblade.core.secure.constant.AuthConstant; import org.springblade.core.tenant.annotation.TenantIgnore; -import org.springblade.core.tool.api.FR; import org.springblade.core.tool.api.R; -import org.springblade.core.tool.utils.StringUtil; -import org.springblade.process.feign.IBusinessProcessClient; import org.springblade.transport.pojo.vo.CustomerArchiveVO; import org.springblade.transport.pojo.vo.CustomerChangeRecordVO; import org.springblade.transport.service.ICustomerArchiveService; +import org.springblade.transport.service.impl.CustomerArchivePublicProcessService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -49,9 +47,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** @@ -69,7 +64,7 @@ import java.util.Map; public class CustomerArchivePublicController { private final ICustomerArchiveService customerArchiveService; - private final IBusinessProcessClient businessProcessClient; + private final CustomerArchivePublicProcessService customerArchivePublicProcessService; /** * 公开详情 @@ -93,121 +88,15 @@ public class CustomerArchivePublicController { } /** - * 公开接收流程页 postMessage 数据(当前仅打印,便于联调) + * 公开接收流程页 postMessage 数据 */ @PostMapping("/process-message") @ApiOperationSupport(order = 3) - @Operation(summary = "公开接收流程消息", description = "无需登录,接收后查询当前节点、流程实例详情并同步客商当前节点") + @Operation(summary = "公开接收流程消息", description = "无需登录,立即查询当前节点,5秒后查询流程实例详情并同步客商") public R processMessage(@RequestBody Map body) { log.info("客商公开页收到流程消息:{}", JSON.toJSONString(body)); - Map formValues = asMap(body == null ? null : body.get("formValues")); - String processId = firstText(formValues, "processId"); - if (StringUtil.isBlank(processId) && body != null) { - processId = firstText(body, "processId"); - } - String loginName = firstText(formValues, "mkLoginName", "loginName"); - if (StringUtil.isBlank(processId)) { - log.warn("客商公开页流程消息未找到 processId,跳过查询当前节点"); - return R.success("ok"); - } - String customerIdText = firstText(asMap(body == null ? null : body.get("formData")), "id"); - try { - FR result = businessProcessClient.getCurrentNodes(processId, loginName); - Object nodeData = result == null ? null : result.getData(); - log.info("客商公开页流程消息当前节点详情 processId={} loginName={} result={}", - processId, loginName, JSON.toJSONString(nodeData)); - } catch (Exception e) { - log.error("客商公开页查询当前节点失败 processId={} loginName={}", processId, loginName, e); - } - try { - FR processInfoResult = businessProcessClient.getProcessInfo(processId, loginName); - Object processInfo = processInfoResult == null ? null : processInfoResult.getData(); - log.info("客商公开页流程消息流程实例详情 processId={} loginName={} result={}", - processId, loginName, JSON.toJSONString(processInfo)); - if (isProcessFinished(processInfo)) { - applyProcessResult(customerIdText, processId, formValues, true); - } else if (isProcessRejected(processInfo)) { - applyProcessResult(customerIdText, processId, formValues, false); - } else if (StringUtil.isNotBlank(customerIdText)) { - try { - customerArchiveService.syncProcessNodeFromProcessInfo(Long.valueOf(customerIdText), processInfo); - } catch (NumberFormatException e) { - log.warn("客商公开页流程消息客商id格式不正确:{}", customerIdText); - } - } - } catch (Exception e) { - log.error("客商公开页查询流程实例详情失败 processId={} loginName={}", processId, loginName, e); - } + customerArchivePublicProcessService.handleProcessMessage(body); return R.success("ok"); } - private static boolean isProcessFinished(Object processInfo) { - return "30".equals(firstText(asMap(processInfo), "fdProcessStatus")); - } - - private static boolean isProcessRejected(Object processInfo) { - Map info = asMap(processInfo); - if (!"20".equals(firstText(info, "fdProcessStatus"))) { - return false; - } - if (hasItems(info.get("currentHandlers"))) { - return false; - } - return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos")); - } - - private static boolean hasItems(Object value) { - return value instanceof Collection collection && !collection.isEmpty(); - } - - private void applyProcessResult(String customerIdText, String processId, Map formValues, - boolean approved) { - String action = approved ? "审核通过" : "审核驳回"; - if (StringUtil.isBlank(customerIdText)) { - log.warn("流程{}但未找到客商id,跳过同步 processId={}", action, processId); - return; - } - try { - String processorName = firstText(formValues, "mkUserName", "mkLoginName"); - Long customerId = Long.valueOf(customerIdText); - if (approved) { - customerArchiveService.approveFromProcess(customerId, processorName); - } else { - customerArchiveService.rejectFromProcess(customerId, processorName); - } - } catch (NumberFormatException e) { - log.warn("流程{}但客商id格式不正确:{}", action, customerIdText); - } - } - - private static Map asMap(Object value) { - if (!(value instanceof Map map)) { - return Collections.emptyMap(); - } - Map result = new HashMap<>(); - map.forEach((key, nested) -> { - if (key != null) { - result.put(String.valueOf(key), nested); - } - }); - return result; - } - - private static String firstText(Map source, String... keys) { - if (source == null || keys == null) { - return null; - } - for (String key : keys) { - Object value = source.get(key); - if (value == null) { - continue; - } - String text = String.valueOf(value).trim(); - if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) { - return text; - } - } - return null; - } - } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchivePublicProcessService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchivePublicProcessService.java new file mode 100644 index 0000000..56a22a3 --- /dev/null +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/CustomerArchivePublicProcessService.java @@ -0,0 +1,182 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + */ +package org.springblade.transport.service.impl; + +import com.alibaba.fastjson2.JSON; +import jakarta.annotation.PreDestroy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.transport.service.ICustomerArchiveService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 客商公开页流程消息处理:当前节点立即查询,流程实例详情延迟查询。 + */ +@Slf4j +@Service +@TenantIgnore +@RequiredArgsConstructor +public class CustomerArchivePublicProcessService { + + private static final long PROCESS_INFO_DELAY_SECONDS = 5L; + + private final ICustomerArchiveService customerArchiveService; + private final IBusinessProcessClient businessProcessClient; + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, runnable -> { + Thread thread = new Thread(runnable, "customer-archive-process-info-" + THREAD_INDEX.incrementAndGet()); + thread.setDaemon(true); + return thread; + }); + + private static final AtomicInteger THREAD_INDEX = new AtomicInteger(); + + @PreDestroy + public void shutdown() { + scheduler.shutdown(); + } + + public void handleProcessMessage(Map body) { + Map formValues = asMap(body == null ? null : body.get("formValues")); + String processId = firstText(formValues, "processId"); + if (StringUtil.isBlank(processId) && body != null) { + processId = firstText(body, "processId"); + } + String loginName = firstText(formValues, "mkLoginName", "loginName"); + if (StringUtil.isBlank(processId)) { + log.warn("客商公开页流程消息未找到 processId,跳过查询当前节点"); + return; + } + String customerIdText = firstText(asMap(body == null ? null : body.get("formData")), "id"); + queryCurrentNodes(processId, loginName); + scheduleProcessInfo(processId, loginName, customerIdText, formValues); + } + + private void queryCurrentNodes(String processId, String loginName) { + try { + FR result = businessProcessClient.getCurrentNodes(processId, loginName); + Object nodeData = result == null ? null : result.getData(); + log.info("客商公开页流程消息当前节点详情 processId={} loginName={} result={}", + processId, loginName, JSON.toJSONString(nodeData)); + } catch (Exception e) { + log.error("客商公开页查询当前节点失败 processId={} loginName={}", processId, loginName, e); + } + } + + private void scheduleProcessInfo(String processId, String loginName, String customerIdText, + Map formValues) { + Map formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues); + log.info("客商公开页将在{}秒后查询流程实例详情 processId={}", PROCESS_INFO_DELAY_SECONDS, processId); + scheduler.schedule( + () -> queryProcessInfo(processId, loginName, customerIdText, formValuesCopy), + PROCESS_INFO_DELAY_SECONDS, + TimeUnit.SECONDS + ); + } + + private void queryProcessInfo(String processId, String loginName, String customerIdText, + Map formValues) { + try { + FR processInfoResult = businessProcessClient.getProcessInfo(processId, loginName); + Object processInfo = processInfoResult == null ? null : processInfoResult.getData(); + log.info("客商公开页流程消息流程实例详情 processId={} loginName={} result={}", + processId, loginName, JSON.toJSONString(processInfo)); + if (isProcessFinished(processInfo)) { + applyProcessResult(customerIdText, processId, formValues, true); + } else if (isProcessRejected(processInfo)) { + applyProcessResult(customerIdText, processId, formValues, false); + } else if (StringUtil.isNotBlank(customerIdText)) { + try { + customerArchiveService.syncProcessNodeFromProcessInfo(Long.valueOf(customerIdText), processInfo); + } catch (NumberFormatException e) { + log.warn("客商公开页流程消息客商id格式不正确:{}", customerIdText); + } + } + } catch (Exception e) { + log.error("客商公开页查询流程实例详情失败 processId={} loginName={}", processId, loginName, e); + } + } + + private static boolean isProcessFinished(Object processInfo) { + return "30".equals(firstText(asMap(processInfo), "fdProcessStatus")); + } + + private static boolean isProcessRejected(Object processInfo) { + Map info = asMap(processInfo); + if (!"20".equals(firstText(info, "fdProcessStatus"))) { + return false; + } + if (hasItems(info.get("currentHandlers"))) { + return false; + } + return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos")); + } + + private static boolean hasItems(Object value) { + return value instanceof Collection collection && !collection.isEmpty(); + } + + private void applyProcessResult(String customerIdText, String processId, Map formValues, + boolean approved) { + String action = approved ? "审核通过" : "审核驳回"; + if (StringUtil.isBlank(customerIdText)) { + log.warn("流程{}但未找到客商id,跳过同步 processId={}", action, processId); + return; + } + try { + String processorName = firstText(formValues, "mkUserName", "mkLoginName"); + Long customerId = Long.valueOf(customerIdText); + if (approved) { + customerArchiveService.approveFromProcess(customerId, processorName); + } else { + customerArchiveService.rejectFromProcess(customerId, processorName); + } + } catch (NumberFormatException e) { + log.warn("流程{}但客商id格式不正确:{}", action, customerIdText); + } + } + + private static Map asMap(Object value) { + if (!(value instanceof Map map)) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + map.forEach((key, nested) -> { + if (key != null) { + result.put(String.valueOf(key), nested); + } + }); + return result; + } + + private static String firstText(Map source, String... keys) { + if (source == null || keys == null) { + return null; + } + for (String key : keys) { + Object value = source.get(key); + if (value == null) { + continue; + } + String text = String.valueOf(value).trim(); + if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) { + return text; + } + } + return null; + } +}