diff --git a/src/main/java/com/rj/controller/LbBuyerShoppingController.java b/src/main/java/com/rj/controller/LbBuyerShoppingController.java index b8ed89e..1a79fa6 100644 --- a/src/main/java/com/rj/controller/LbBuyerShoppingController.java +++ b/src/main/java/com/rj/controller/LbBuyerShoppingController.java @@ -56,6 +56,9 @@ public class LbBuyerShoppingController { description = "按 tenantId 从 lb_third_integration_config 读取 login_api_path、buyer_order_list_path 等配置," + "对每个买方手机号模拟登录获取 token,再分页调用买方订单列表 API 并解析入库;" + + "拉取过程中将订单中的卖家手机号缓存到 cacheSellerPhones(已拉取过的号码不再缓存)," + + "买方手机号全部处理完成后,仅对尚未拉取过的卖家手机号模拟登录、拉取订单并保存;" + + "同一请求内重复手机号自动跳过,卖家阶段不再扩展缓存,避免重复拉取与死循环;" + "未传 password 时默认密码为 123456") public ResponseEntity> pullFromThird( @Parameter(description = "租户 id 与买方手机号列表", required = true) diff --git a/src/main/java/com/rj/service/impl/LbBuyerShoppingServiceImpl.java b/src/main/java/com/rj/service/impl/LbBuyerShoppingServiceImpl.java index 576a0a8..a3e80ba 100644 --- a/src/main/java/com/rj/service/impl/LbBuyerShoppingServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbBuyerShoppingServiceImpl.java @@ -27,9 +27,11 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; /** * 买方购物表 lb_buyer_shopping 服务实现 @@ -340,16 +342,24 @@ public class LbBuyerShoppingServiceImpl } HxrUserLoginApiContext loginCtx = loginCtxOpt.get(); + Set cacheSellerPhones = new LinkedHashSet<>(); + Set processedMobiles = new LinkedHashSet<>(); + List> items = new ArrayList<>(); int successCount = 0; int failCount = 0; + int skippedCount = 0; int totalSaved = 0; int totalFetched = 0; String requestPassword = request.getPassword() != null ? request.getPassword().trim() : ""; + String password = !requestPassword.isEmpty() + ? requestPassword + : DEFAULT_SIMULATE_LOGIN_PASSWORD; for (String rawMobile : request.getMobiles()) { - Map item = new LinkedHashMap<>(); - if (rawMobile == null || rawMobile.trim().isEmpty()) { + String mobile = rawMobile != null ? rawMobile.trim() : ""; + if (mobile.isEmpty()) { + Map item = new LinkedHashMap<>(); item.put("mobile", rawMobile); item.put("loginSuccess", false); item.put("orderFetchSuccess", false); @@ -359,69 +369,58 @@ public class LbBuyerShoppingServiceImpl failCount++; continue; } + if (processedMobiles.contains(mobile)) { + Map item = buildSkippedPullItem(mobile, "手机号已拉取,跳过重复"); + items.add(item); + skippedCount++; + continue; + } + processedMobiles.add(mobile); - String mobile = rawMobile.trim(); - item.put("mobile", mobile); - String password = !requestPassword.isEmpty() - ? requestPassword - : DEFAULT_SIMULATE_LOGIN_PASSWORD; - - try { - HxrAdminUserLoginService.LoginApiResult loginResult = - hxrAdminUserLoginService.login(mobile, password, loginCtx); - item.put("httpStatus", loginResult.httpStatus()); - item.put("apiCode", loginResult.apiCode()); - item.put("apiMsg", loginResult.apiMsg()); - item.put("loginSuccess", loginResult.success()); - item.put("parsed", loginResult.parsed()); - - if (!loginResult.success()) { - item.put("orderFetchSuccess", false); - failCount++; - items.add(item); - continue; - } - - String token = HxrAdminUserLoginService.extractToken(loginResult.parsed()); - if (token == null || token.isBlank()) { - item.put("orderFetchSuccess", false); - item.put("orderFetchMsg", "响应中无 data.userinfo.token"); - failCount++; - items.add(item); - continue; - } - - Optional orderCtxOpt = - lbThirdIntegrationConfigService.resolveBuyerOrderApiContext(tenantId, token); - if (orderCtxOpt.isEmpty()) { - item.put("orderFetchSuccess", false); - item.put("orderFetchMsg", - "未找到买方订单 API 配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)"); - failCount++; - items.add(item); - continue; - } - HxrBuyerOrderApiContext orderCtx = orderCtxOpt.get(); - item.put("buyerOrderListUrl", orderCtx.buyerOrderListBaseUrl()); - - Map fetchResult = fetchAndSaveBuyerOrders(orderCtx, mobile); - item.putAll(fetchResult); - if (Boolean.TRUE.equals(fetchResult.get("orderFetchSuccess"))) { - successCount++; - totalSaved += toInt(fetchResult.get("ordersSaved")); - totalFetched += toInt(fetchResult.get("ordersFetched")); - } else { - failCount++; - } - } catch (Exception e) { - log.warn("买方购物第三方拉取异常 mobile={} tenantId={}", mobile, tenantId, e); - item.put("loginSuccess", false); - item.put("orderFetchSuccess", false); - item.put("apiCode", -1); - item.put("apiMsg", "请求异常:" + e.getMessage()); + Map item = pullOrdersForMobile( + mobile, password, tenantId, loginCtx, cacheSellerPhones, processedMobiles); + items.add(item); + if (Boolean.TRUE.equals(item.get("orderFetchSuccess"))) { + successCount++; + totalSaved += toInt(item.get("ordersSaved")); + totalFetched += toInt(item.get("ordersFetched")); + } else { failCount++; } - items.add(item); + } + + List sellerQueue = new ArrayList<>(); + for (String sellerMobile : cacheSellerPhones) { + if (!processedMobiles.contains(sellerMobile)) { + sellerQueue.add(sellerMobile); + } + } + + List> sellerItems = new ArrayList<>(); + int sellerSuccessCount = 0; + int sellerFailCount = 0; + int sellerSkippedCount = 0; + int sellerTotalSaved = 0; + int sellerTotalFetched = 0; + for (String sellerMobile : sellerQueue) { + if (processedMobiles.contains(sellerMobile)) { + sellerItems.add(buildSkippedPullItem(sellerMobile, "卖家手机号已拉取,跳过重复")); + sellerSkippedCount++; + continue; + } + processedMobiles.add(sellerMobile); + + Map sellerItem = pullOrdersForMobile( + sellerMobile, password, tenantId, loginCtx, null, processedMobiles); + sellerItem.put("source", "cacheSellerPhones"); + sellerItems.add(sellerItem); + if (Boolean.TRUE.equals(sellerItem.get("orderFetchSuccess"))) { + sellerSuccessCount++; + sellerTotalSaved += toInt(sellerItem.get("ordersSaved")); + sellerTotalFetched += toInt(sellerItem.get("ordersFetched")); + } else { + sellerFailCount++; + } } result.put("success", true); @@ -429,8 +428,18 @@ public class LbBuyerShoppingServiceImpl result.put("data", items); result.put("successCount", successCount); result.put("failCount", failCount); + result.put("skippedCount", skippedCount); result.put("ordersSaved", totalSaved); result.put("ordersFetched", totalFetched); + result.put("cacheSellerPhones", new ArrayList<>(cacheSellerPhones)); + result.put("sellerQueue", sellerQueue); + result.put("sellerData", sellerItems); + result.put("sellerSuccessCount", sellerSuccessCount); + result.put("sellerFailCount", sellerFailCount); + result.put("sellerSkippedCount", sellerSkippedCount); + result.put("sellerOrdersSaved", sellerTotalSaved); + result.put("sellerOrdersFetched", sellerTotalFetched); + result.put("processedMobiles", new ArrayList<>(processedMobiles)); result.put("loginApiUrl", loginCtx.loginApiUrl()); return result; } catch (Exception e) { @@ -441,7 +450,75 @@ public class LbBuyerShoppingServiceImpl } } - private Map fetchAndSaveBuyerOrders(HxrBuyerOrderApiContext ctx, String buyerMobile) { + private Map buildSkippedPullItem(String mobile, String reason) { + Map item = new LinkedHashMap<>(); + item.put("mobile", mobile); + item.put("skipped", true); + item.put("skipReason", reason); + item.put("loginSuccess", false); + item.put("orderFetchSuccess", false); + return item; + } + + private Map pullOrdersForMobile( + String mobile, + String password, + String tenantId, + HxrUserLoginApiContext loginCtx, + Set sellerPhoneCollector, + Set processedMobiles) { + Map item = new LinkedHashMap<>(); + item.put("mobile", mobile); + try { + HxrAdminUserLoginService.LoginApiResult loginResult = + hxrAdminUserLoginService.login(mobile, password, loginCtx); + item.put("httpStatus", loginResult.httpStatus()); + item.put("apiCode", loginResult.apiCode()); + item.put("apiMsg", loginResult.apiMsg()); + item.put("loginSuccess", loginResult.success()); + item.put("parsed", loginResult.parsed()); + + if (!loginResult.success()) { + item.put("orderFetchSuccess", false); + return item; + } + + String token = HxrAdminUserLoginService.extractToken(loginResult.parsed()); + if (token == null || token.isBlank()) { + item.put("orderFetchSuccess", false); + item.put("orderFetchMsg", "响应中无 data.userinfo.token"); + return item; + } + + Optional orderCtxOpt = + lbThirdIntegrationConfigService.resolveBuyerOrderApiContext(tenantId, token); + if (orderCtxOpt.isEmpty()) { + item.put("orderFetchSuccess", false); + item.put("orderFetchMsg", + "未找到买方订单 API 配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)"); + return item; + } + HxrBuyerOrderApiContext orderCtx = orderCtxOpt.get(); + item.put("buyerOrderListUrl", orderCtx.buyerOrderListBaseUrl()); + + Map fetchResult = + fetchAndSaveBuyerOrders(orderCtx, mobile, sellerPhoneCollector, processedMobiles); + item.putAll(fetchResult); + } catch (Exception e) { + log.warn("买方购物第三方拉取异常 mobile={} tenantId={}", mobile, tenantId, e); + item.put("loginSuccess", false); + item.put("orderFetchSuccess", false); + item.put("apiCode", -1); + item.put("apiMsg", "请求异常:" + e.getMessage()); + } + return item; + } + + private Map fetchAndSaveBuyerOrders( + HxrBuyerOrderApiContext ctx, + String loginMobile, + Set sellerPhoneCollector, + Set processedMobiles) { Map result = new LinkedHashMap<>(); int page = 1; int totalSaved = 0; @@ -495,8 +572,9 @@ public class LbBuyerShoppingServiceImpl if (entity.getId() == null) { continue; } + collectSellerPhone(entity, sellerPhoneCollector, processedMobiles); if (entity.getBuyerMobile() == null || entity.getBuyerMobile().isBlank()) { - entity.setBuyerMobile(buyerMobile); + entity.setBuyerMobile(loginMobile); } applyDefaults(entity); if (entity.getCreatedAt() == null) { @@ -539,7 +617,7 @@ public class LbBuyerShoppingServiceImpl result.put("orderPages", page); return result; } catch (Exception e) { - log.warn("拉取买方订单异常 buyerMobile={}", buyerMobile, e); + log.warn("拉取买方订单异常 loginMobile={}", loginMobile, e); result.put("orderFetchSuccess", false); result.put("orderFetchMsg", "拉取买方订单异常:" + e.getMessage()); result.put("ordersSaved", totalSaved); @@ -791,6 +869,22 @@ public class LbBuyerShoppingServiceImpl private record StatAggregate(BigDecimal totalMoney, int orderCount, BigDecimal avgAmount) { } + private static void collectSellerPhone( + LbBuyerShopping entity, Set collector, Set processedMobiles) { + if (collector == null || entity == null) { + return; + } + String phone = entity.getSellerMobile(); + if (phone == null || phone.isBlank()) { + return; + } + String trimmed = phone.trim(); + if (processedMobiles != null && processedMobiles.contains(trimmed)) { + return; + } + collector.add(trimmed); + } + private static int toInt(Object value) { if (value instanceof Number number) { return number.intValue();