This commit is contained in:
2026-09-20 19:03:13 +08:00
parent 780cd56ffe
commit 86adb47392
2 changed files with 187 additions and 116 deletions
@@ -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<String, Object> body) {
log.info("客商公开页收到流程消息:{}", JSON.toJSONString(body));
Map<String, Object> 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<Object> 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<Object> 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<String, Object> 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<String, Object> 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<String, Object> asMap(Object value) {
if (!(value instanceof Map<?, ?> map)) {
return Collections.emptyMap();
}
Map<String, Object> result = new HashMap<>();
map.forEach((key, nested) -> {
if (key != null) {
result.put(String.valueOf(key), nested);
}
});
return result;
}
private static String firstText(Map<String, Object> 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;
}
}
@@ -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<String, Object> body) {
Map<String, Object> 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<Object> 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<String, Object> formValues) {
Map<String, Object> 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<String, Object> formValues) {
try {
FR<Object> 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<String, Object> 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<String, Object> 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<String, Object> asMap(Object value) {
if (!(value instanceof Map<?, ?> map)) {
return Collections.emptyMap();
}
Map<String, Object> result = new HashMap<>();
map.forEach((key, nested) -> {
if (key != null) {
result.put(String.valueOf(key), nested);
}
});
return result;
}
private static String firstText(Map<String, Object> 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;
}
}