From 7b3879d6b6d41aa49c24af138061885254dd58d9 Mon Sep 17 00:00:00 2001 From: cst61 Date: Wed, 3 Jun 2026 17:38:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E7=99=BB=E5=BD=95=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/LbThirdIntegrationConstants.java | 3 + .../controller/LbFanManagementController.java | 15 ++ .../com/rj/dto/LbFanSimulateLoginRequest.java | 23 +++ .../rj/dto/hxr/HxrUserLoginApiContext.java | 11 ++ .../rj/entity/LbThirdIntegrationConfig.java | 12 ++ .../rj/service/HxrAdminUserLoginService.java | 157 ++++++++++++++++++ .../rj/service/ILbFanManagementService.java | 6 + .../ILbThirdIntegrationConfigService.java | 6 + .../impl/LbFanManagementServiceImpl.java | 108 ++++++++++++ .../LbThirdIntegrationConfigServiceImpl.java | 35 ++++ .../rj/util/LbThirdIntegrationConfigUtil.java | 34 ++++ src/main/sql/lb_third_integration_config.sql | 3 + ...ntegration_config_alter_add_fans_login.sql | 10 ++ 13 files changed, 423 insertions(+) create mode 100644 src/main/java/com/rj/dto/LbFanSimulateLoginRequest.java create mode 100644 src/main/java/com/rj/dto/hxr/HxrUserLoginApiContext.java create mode 100644 src/main/java/com/rj/service/HxrAdminUserLoginService.java create mode 100644 src/main/sql/lb_third_integration_config_alter_add_fans_login.sql diff --git a/src/main/java/com/rj/common/LbThirdIntegrationConstants.java b/src/main/java/com/rj/common/LbThirdIntegrationConstants.java index 654a621..4085519 100644 --- a/src/main/java/com/rj/common/LbThirdIntegrationConstants.java +++ b/src/main/java/com/rj/common/LbThirdIntegrationConstants.java @@ -16,8 +16,11 @@ public final class LbThirdIntegrationConstants { public static final String DEFAULT_USER_UPDATE_PATH = "/app/admin/user/update"; public static final String DEFAULT_GOODS_API_PATH = "/api/order/goods"; public static final String DEFAULT_BUY_API_PATH = "/api/order/buy"; + public static final String DEFAULT_FANS_API_PATH = "/api/share/select"; + public static final String DEFAULT_LOGIN_API_PATH = "/api/user/login"; public static final int DEFAULT_ORDER_PAGE_LIMIT = 90; public static final int DEFAULT_USER_PAGE_LIMIT = 90; public static final int DEFAULT_GOODS_PAGE_LIMIT = 20; + public static final int DEFAULT_FANS_PAGE_LIMIT = 10; } diff --git a/src/main/java/com/rj/controller/LbFanManagementController.java b/src/main/java/com/rj/controller/LbFanManagementController.java index 37c90e3..6f507b9 100644 --- a/src/main/java/com/rj/controller/LbFanManagementController.java +++ b/src/main/java/com/rj/controller/LbFanManagementController.java @@ -1,5 +1,6 @@ package com.rj.controller; +import com.rj.dto.LbFanSimulateLoginRequest; import com.rj.entity.LbFanManagement; import com.rj.service.ILbFanManagementService; import io.swagger.v3.oas.annotations.Operation; @@ -49,6 +50,20 @@ public class LbFanManagementController { return toResponse(result); } + @PostMapping("/simulate-login") + @Operation( + summary = "批量模拟第三方登录", + description = + "按 tenantId 从 lb_third_integration_config 读取 login_api_path 等配置," + + "对每个手机号调用第三方登录接口并解析返回 JSON;" + + "未传 password 时默认密码为 123456") + public ResponseEntity> simulateLogin( + @Parameter(description = "租户 id 与手机号列表", required = true) + @RequestBody LbFanSimulateLoginRequest request) { + Map result = lbFanManagementService.simulateLogin(request); + return toResponse(result); + } + @GetMapping("/list") @Operation(summary = "分页查询粉丝") public ResponseEntity> list( diff --git a/src/main/java/com/rj/dto/LbFanSimulateLoginRequest.java b/src/main/java/com/rj/dto/LbFanSimulateLoginRequest.java new file mode 100644 index 0000000..d69cd5f --- /dev/null +++ b/src/main/java/com/rj/dto/LbFanSimulateLoginRequest.java @@ -0,0 +1,23 @@ +package com.rj.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 粉丝管理:按手机号批量模拟第三方登录。 + */ +@Data +@Schema(description = "粉丝模拟登录请求") +public class LbFanSimulateLoginRequest { + + @Schema(description = "租户 id,关联 lb_third_integration_config.tenant_id", requiredMode = Schema.RequiredMode.REQUIRED) + private String tenantId; + + @Schema(description = "手机号列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List mobiles; + + @Schema(description = "登录密码;未传时默认为 123456") + private String password; +} diff --git a/src/main/java/com/rj/dto/hxr/HxrUserLoginApiContext.java b/src/main/java/com/rj/dto/hxr/HxrUserLoginApiContext.java new file mode 100644 index 0000000..875edaf --- /dev/null +++ b/src/main/java/com/rj/dto/hxr/HxrUserLoginApiContext.java @@ -0,0 +1,11 @@ +package com.rj.dto.hxr; + +/** + * 调用 hxrd {@code /api/user/login} 所需的运行时配置(由 {@code lb_third_integration_config} 解析而来)。 + */ +public record HxrUserLoginApiContext( + String loginApiUrl, + String origin, + String referer, + String appStr) { +} diff --git a/src/main/java/com/rj/entity/LbThirdIntegrationConfig.java b/src/main/java/com/rj/entity/LbThirdIntegrationConfig.java index 9b3b768..26f389d 100644 --- a/src/main/java/com/rj/entity/LbThirdIntegrationConfig.java +++ b/src/main/java/com/rj/entity/LbThirdIntegrationConfig.java @@ -68,6 +68,14 @@ public class LbThirdIntegrationConfig implements Serializable { @Schema(description = "抢购 API 路径") private String buyApiPath; + @TableField("fans_api_path") + @Schema(description = "粉丝列表 API 路径") + private String fansApiPath; + + @TableField("login_api_path") + @Schema(description = "后台登录 API 路径") + private String loginApiPath; + @TableField("order_page_limit") @Schema(description = "订单分页 limit") private Integer orderPageLimit; @@ -80,6 +88,10 @@ public class LbThirdIntegrationConfig implements Serializable { @Schema(description = "货品分页 limit") private Integer goodsPageLimit; + @TableField("fans_page_limit") + @Schema(description = "粉丝分页 limit") + private Integer fansPageLimit; + @TableField("order_referer") @Schema(description = "订单 Referer") private String orderReferer; diff --git a/src/main/java/com/rj/service/HxrAdminUserLoginService.java b/src/main/java/com/rj/service/HxrAdminUserLoginService.java new file mode 100644 index 0000000..cdc7522 --- /dev/null +++ b/src/main/java/com/rj/service/HxrAdminUserLoginService.java @@ -0,0 +1,157 @@ +package com.rj.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.rj.dto.hxr.HxrUserLoginApiContext; +import com.rj.util.HxrGoodsSignUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.time.Duration; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 调用 hxrd {@code POST /api/user/login} 模拟登录并解析响应 JSON。 + */ +@Slf4j +@Service +public class HxrAdminUserLoginService { + + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final String USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + + "(KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"; + + private static final ObjectMapper JSON = new ObjectMapper() + .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + + /** + * 对单个手机号发起登录请求。 + * + * @param password 非空密码;为空时由调用方传入与手机号相同的默认值 + */ + public LoginApiResult login(String mobile, String password, HxrUserLoginApiContext ctx) throws Exception { + if (ctx == null) { + return LoginApiResult.failure(-1, "登录 API 配置为空", null, -1); + } + String loginApiUrl = ctx.loginApiUrl(); + if (!StringUtils.hasText(loginApiUrl)) { + return LoginApiResult.failure(-1, "未配置 loginApiUrl", null, -1); + } + if (!StringUtils.hasText(mobile)) { + return LoginApiResult.failure(-1, "手机号不能为空", null, -1); + } + if (!StringUtils.hasText(password)) { + return LoginApiResult.failure(-1, "密码不能为空", null, -1); + } + + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = randomNoncestr(); + + Map body = new LinkedHashMap<>(); + body.put("mobile", mobile.trim()); + body.put("password", password.trim()); + String bodyJson = JSON.writeValueAsString(body); + + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(loginApiUrl.trim())) + .timeout(Duration.ofSeconds(120)) + .header("Accept", "application/json,*/*") + .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8") + .header("Content-Type", "application/json") + .header("Origin", ctx.origin()) + .header("Referer", ctx.referer()) + .header("User-Agent", USER_AGENT); + + String appStr = ctx.appStr(); + if (StringUtils.hasText(appStr)) { + Map signParams = new LinkedHashMap<>(); + signParams.put("mobile", mobile.trim()); + signParams.put("password", password.trim()); + signParams.put("timestamp", timestamp); + signParams.put("noncestr", noncestr); + String sign = HxrGoodsSignUtil.computeSign(signParams, appStr.trim()); + builder.header("S", sign) + .header("T", String.valueOf(timestamp)) + .header("N", noncestr); + } + + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(60)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + + HttpRequest request = builder + .POST(HttpRequest.BodyPublishers.ofString(bodyJson, StandardCharsets.UTF_8)) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int httpStatus = response.statusCode(); + String bodyText = response.body(); + if (httpStatus < 200 || httpStatus >= 300) { + log.warn("hxr /api/user/login HTTP {} mobile={} bodyPrefix={}", + httpStatus, mobile, abbreviate(bodyText, 400)); + return LoginApiResult.failure(-1, "HTTP " + httpStatus, bodyText, httpStatus); + } + if (bodyText == null || bodyText.isBlank()) { + log.warn("hxr /api/user/login empty body mobile={}", mobile); + return LoginApiResult.failure(-1, "响应为空", null, httpStatus); + } + + JsonNode root = JSON.readTree(bodyText); + int code = root.path("code").asInt(-1); + String msg = root.path("msg").asText(""); + Object parsed = JSON.convertValue(root, Map.class); + boolean ok = code == 0; + if (!ok) { + log.warn("hxr /api/user/login api code={} msg={} mobile={} bodyPrefix={}", + code, msg, mobile, abbreviate(bodyText, 200)); + } + return new LoginApiResult(ok, code, msg, parsed, httpStatus); + } + + public record LoginApiResult( + boolean success, + int apiCode, + String apiMsg, + Object parsed, + int httpStatus) { + + public static LoginApiResult failure(int code, String msg, String rawBody, int httpStatus) { + Map parsed = new LinkedHashMap<>(); + if (rawBody != null && !rawBody.isBlank()) { + parsed.put("rawBody", abbreviate(rawBody, 2000)); + } + return new LoginApiResult(false, code, msg, parsed, httpStatus); + } + } + + private static String randomNoncestr() { + String base36 = Long.toUnsignedString(Math.abs(RANDOM.nextLong()), 36); + if (base36.length() >= 5) { + return base36.substring(base36.length() - 5); + } + StringBuilder sb = new StringBuilder(base36); + while (sb.length() < 5) { + sb.append(Integer.toString(RANDOM.nextInt(36), 36)); + } + return sb.toString(); + } + + private static String abbreviate(String s, int maxLen) { + if (s == null) { + return ""; + } + return s.length() <= maxLen ? s : s.substring(0, maxLen) + "..."; + } +} diff --git a/src/main/java/com/rj/service/ILbFanManagementService.java b/src/main/java/com/rj/service/ILbFanManagementService.java index 485da5b..5f4fc60 100644 --- a/src/main/java/com/rj/service/ILbFanManagementService.java +++ b/src/main/java/com/rj/service/ILbFanManagementService.java @@ -1,6 +1,7 @@ package com.rj.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.rj.dto.LbFanSimulateLoginRequest; import com.rj.entity.LbFanManagement; import java.util.Map; @@ -24,4 +25,9 @@ public interface ILbFanManagementService extends IService { Integer shareNumMax, String createdAtStart, String createdAtEnd); + + /** + * 按手机号列表模拟第三方登录:根据 tenantId 读取 lb_third_integration_config.login_api_path 调用接口并解析 JSON。 + */ + Map simulateLogin(LbFanSimulateLoginRequest request); } diff --git a/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java b/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java index 05efdc0..c1642d3 100644 --- a/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java +++ b/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java @@ -5,6 +5,7 @@ import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest; import com.rj.dto.hxr.HxrAdminOrderApiContext; import com.rj.dto.hxr.HxrAdminUserApiContext; import com.rj.dto.hxr.HxrGoodsApiContext; +import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbThirdIntegrationConfig; import java.util.Map; @@ -54,4 +55,9 @@ public interface ILbThirdIntegrationConfigService extends IService resolveAdminOrderApiContext(String tenantId); + + /** + * 按租户 id 解析用户登录 API 运行时配置(login_api_path、Origin、Referer、appStr)。 + */ + Optional resolveUserLoginApiContext(String tenantId); } diff --git a/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java b/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java index bd1130c..457b8fe 100644 --- a/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java @@ -3,18 +3,27 @@ package com.rj.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.rj.dto.LbFanSimulateLoginRequest; +import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbFanManagement; import com.rj.mapper.LbFanManagementMapper; +import com.rj.service.HxrAdminUserLoginService; import com.rj.service.ILbFanManagementService; +import com.rj.service.ILbThirdIntegrationConfigService; import com.rj.tenant.TenantContextHolder; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; /** * 粉丝管理服务实现 @@ -25,6 +34,14 @@ public class LbFanManagementServiceImpl extends ServiceImpl implements ILbFanManagementService { + @Autowired + private ILbThirdIntegrationConfigService lbThirdIntegrationConfigService; + + @Autowired + private HxrAdminUserLoginService hxrAdminUserLoginService; + + private static final String DEFAULT_SIMULATE_LOGIN_PASSWORD = "123456"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @@ -208,6 +225,97 @@ public class LbFanManagementServiceImpl } } + @Override + public Map simulateLogin(LbFanSimulateLoginRequest request) { + Map result = new HashMap<>(); + try { + if (request == null) { + result.put("success", false); + result.put("message", "请求体不能为空"); + return result; + } + if (request.getTenantId() == null || request.getTenantId().trim().isEmpty()) { + result.put("success", false); + result.put("message", "tenantId不能为空"); + return result; + } + if (request.getMobiles() == null || request.getMobiles().isEmpty()) { + result.put("success", false); + result.put("message", "手机号列表不能为空"); + return result; + } + + String tenantId = request.getTenantId().trim(); + Optional ctxOpt = + lbThirdIntegrationConfigService.resolveUserLoginApiContext(tenantId); + if (ctxOpt.isEmpty()) { + result.put("success", false); + result.put("message", + "未找到该租户的第三方集成配置,或配置未启用、URL 不完整(请检查 lb_third_integration_config)"); + return result; + } + HxrUserLoginApiContext ctx = ctxOpt.get(); + + List> items = new ArrayList<>(); + int successCount = 0; + int failCount = 0; + String requestPassword = request.getPassword() != null ? request.getPassword().trim() : ""; + + for (String rawMobile : request.getMobiles()) { + Map item = new LinkedHashMap<>(); + if (rawMobile == null || rawMobile.trim().isEmpty()) { + item.put("mobile", rawMobile); + item.put("loginSuccess", false); + item.put("apiCode", -1); + item.put("apiMsg", "手机号为空"); + items.add(item); + failCount++; + continue; + } + 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, ctx); + 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()) { + successCount++; + } else { + failCount++; + } + } catch (Exception e) { + log.warn("粉丝模拟登录异常 mobile={} tenantId={}", mobile, tenantId, e); + item.put("loginSuccess", false); + item.put("apiCode", -1); + item.put("apiMsg", "请求异常:" + e.getMessage()); + failCount++; + } + items.add(item); + } + + result.put("success", true); + result.put("message", "模拟登录完成"); + result.put("data", items); + result.put("successCount", successCount); + result.put("failCount", failCount); + result.put("loginApiUrl", ctx.loginApiUrl()); + return result; + } catch (Exception e) { + log.error("粉丝模拟登录异常", e); + result.put("success", false); + result.put("message", "模拟登录异常:" + e.getMessage()); + return result; + } + } + /** * 生成唯一ID:id + '_' + tenant_id */ diff --git a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java index df05b2f..7c0ffd8 100644 --- a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java @@ -9,6 +9,7 @@ import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest; import com.rj.dto.hxr.HxrAdminOrderApiContext; import com.rj.dto.hxr.HxrAdminUserApiContext; import com.rj.dto.hxr.HxrGoodsApiContext; +import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbThirdIntegrationConfig; import com.rj.mapper.LbThirdIntegrationConfigMapper; import com.rj.service.ILbThirdIntegrationConfigService; @@ -371,6 +372,31 @@ public class LbThirdIntegrationConfigServiceImpl } } + @Override + public Optional resolveUserLoginApiContext(String tenantId) { + if (!StringUtils.hasText(tenantId)) { + return Optional.empty(); + } + LbThirdIntegrationConfig config = getByTenantIdOrNull(tenantId.trim()); + if (config == null) { + return Optional.empty(); + } + if (config.getEnabled() == null || config.getEnabled() != 1) { + return Optional.empty(); + } + + try { + String appStr = config.getGoodsApiAppStr(); + return Optional.of(new HxrUserLoginApiContext( + LbThirdIntegrationConfigUtil.resolveLoginApiUrl(config), + LbThirdIntegrationConfigUtil.resolveGoodsApiOrigin(config), + LbThirdIntegrationConfigUtil.resolveGoodsApiReferer(config), + StringUtils.hasText(appStr) ? appStr.trim() : null)); + } catch (IllegalStateException e) { + return Optional.empty(); + } + } + @Override public Optional resolveAdminOrderApiContext(String tenantId) { if (!StringUtils.hasText(tenantId)) { @@ -523,6 +549,12 @@ public class LbThirdIntegrationConfigServiceImpl if (!StringUtils.hasText(entity.getBuyApiPath())) { entity.setBuyApiPath(LbThirdIntegrationConstants.DEFAULT_BUY_API_PATH); } + if (!StringUtils.hasText(entity.getFansApiPath())) { + entity.setFansApiPath(LbThirdIntegrationConstants.DEFAULT_FANS_API_PATH); + } + if (!StringUtils.hasText(entity.getLoginApiPath())) { + entity.setLoginApiPath(LbThirdIntegrationConstants.DEFAULT_LOGIN_API_PATH); + } if (entity.getOrderPageLimit() == null) { entity.setOrderPageLimit(LbThirdIntegrationConstants.DEFAULT_ORDER_PAGE_LIMIT); } @@ -532,6 +564,9 @@ public class LbThirdIntegrationConfigServiceImpl if (entity.getGoodsPageLimit() == null) { entity.setGoodsPageLimit(LbThirdIntegrationConstants.DEFAULT_GOODS_PAGE_LIMIT); } + if (entity.getFansPageLimit() == null) { + entity.setFansPageLimit(LbThirdIntegrationConstants.DEFAULT_FANS_PAGE_LIMIT); + } if (!StringUtils.hasText(entity.getAuthType())) { entity.setAuthType(LbThirdIntegrationConstants.AUTH_COOKIE_PHPSID); } diff --git a/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java b/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java index da3b58e..8b624d3 100644 --- a/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java +++ b/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java @@ -60,6 +60,40 @@ public final class LbThirdIntegrationConfigUtil { return limit; } + public static String resolveFansApiBaseUrl(LbThirdIntegrationConfig config) { + String base = trimTrailingSlash(requireText(config.getAdminBaseUrl(), "adminBaseUrl")); + String path = config.getFansApiPath(); + if (!StringUtils.hasText(path)) { + path = LbThirdIntegrationConstants.DEFAULT_FANS_API_PATH; + } + path = path.trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + return base + path; + } + + public static String resolveLoginApiUrl(LbThirdIntegrationConfig config) { + String base = trimTrailingSlash(requireText(config.getAdminBaseUrl(), "adminBaseUrl")); + String path = config.getLoginApiPath(); + if (!StringUtils.hasText(path)) { + path = LbThirdIntegrationConstants.DEFAULT_LOGIN_API_PATH; + } + path = path.trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + return base + path; + } + + public static int resolveFansPageLimit(LbThirdIntegrationConfig config) { + Integer limit = config.getFansPageLimit(); + if (limit == null || limit < 1) { + return LbThirdIntegrationConstants.DEFAULT_FANS_PAGE_LIMIT; + } + return limit; + } + public static String resolveUserSelectBaseUrl(LbThirdIntegrationConfig config) { String base = trimTrailingSlash(requireText(config.getAdminBaseUrl(), "adminBaseUrl")); String path = config.getUserSelectPath(); diff --git a/src/main/sql/lb_third_integration_config.sql b/src/main/sql/lb_third_integration_config.sql index 38043ad..698b37c 100644 --- a/src/main/sql/lb_third_integration_config.sql +++ b/src/main/sql/lb_third_integration_config.sql @@ -16,10 +16,13 @@ CREATE TABLE `lb_third_integration_config` ( `user_update_path` VARCHAR(128) NOT NULL DEFAULT '/app/admin/user/update' COMMENT '用户更新 API 路径', `goods_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/order/goods' COMMENT '货品列表 API 路径', `buy_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/order/buy' COMMENT '抢购 API 路径', + `fans_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/share/select' COMMENT '粉丝列表 API 路径', + `login_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/user/login' COMMENT '后台登录 API 路径', `order_page_limit` INT NOT NULL DEFAULT 90 COMMENT '订单分页 limit', `user_page_limit` INT NOT NULL DEFAULT 90 COMMENT '用户分页 limit', `goods_page_limit` INT NOT NULL DEFAULT 20 COMMENT '货品分页 limit', + `fans_page_limit` INT NOT NULL DEFAULT 10 COMMENT '粉丝分页 limit', `order_referer` VARCHAR(512) DEFAULT NULL COMMENT '订单 Referer;空则 {admin_base_url}/app/admin/order/index', `user_referer` VARCHAR(512) DEFAULT NULL COMMENT '用户 Referer;空则 {admin_base_url}/app/admin/user/index', `goods_api_origin` VARCHAR(256) DEFAULT NULL COMMENT '货品 Origin;空则 web_base_url', diff --git a/src/main/sql/lb_third_integration_config_alter_add_fans_login.sql b/src/main/sql/lb_third_integration_config_alter_add_fans_login.sql new file mode 100644 index 0000000..a9dc701 --- /dev/null +++ b/src/main/sql/lb_third_integration_config_alter_add_fans_login.sql @@ -0,0 +1,10 @@ +-- 升级脚本:lb_third_integration_config 增加粉丝/登录 API 配置列 +SET NAMES utf8mb4; + +ALTER TABLE `lb_third_integration_config` + ADD COLUMN `fans_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/share/select' + COMMENT '粉丝列表 API 路径' AFTER `buy_api_path`, + ADD COLUMN `login_api_path` VARCHAR(128) NOT NULL DEFAULT '/api/user/login' + COMMENT '后台登录 API 路径' AFTER `fans_api_path`, + ADD COLUMN `fans_page_limit` INT NOT NULL DEFAULT 10 + COMMENT '粉丝分页 limit' AFTER `goods_page_limit`;