From fb5f7dfd7d28a6679820cd7bc18d551cdb7e1e34 Mon Sep 17 00:00:00 2001 From: cst61 Date: Mon, 1 Jun 2026 01:12:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A2=E5=8D=95=E8=B4=A6=E5=8F=B7=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rj/controller/LbBuyAccountController.java | 24 ++ .../controller/LbPurchaseApplyController.java | 8 +- .../rj/dto/hxr/HxrAdminUserApiContext.java | 1 + src/main/java/com/rj/entity/LbBuyAccount.java | 16 ++ .../com/rj/service/HxrAdminUserService.java | 76 +++++- .../com/rj/service/ILbBuyAccountService.java | 7 + .../impl/LbAssessmentApplyServiceImpl.java | 4 +- .../service/impl/LbBuyAccountServiceImpl.java | 246 ++++++++++++++++++ .../impl/LbPurchaseApplyServiceImpl.java | 46 +++- .../LbThirdIntegrationConfigServiceImpl.java | 1 + .../rj/util/LbThirdIntegrationConfigUtil.java | 13 + 11 files changed, 428 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/rj/controller/LbBuyAccountController.java b/src/main/java/com/rj/controller/LbBuyAccountController.java index 68154bb..6dab369 100644 --- a/src/main/java/com/rj/controller/LbBuyAccountController.java +++ b/src/main/java/com/rj/controller/LbBuyAccountController.java @@ -1,5 +1,6 @@ package com.rj.controller; +import com.rj.dto.LbBuyAccountRushBuyRequest; import com.rj.entity.LbBuyAccount; import com.rj.service.ILbBuyAccountService; import io.swagger.v3.oas.annotations.Operation; @@ -81,4 +82,27 @@ public class LbBuyAccountController { } return ResponseEntity.internalServerError().body(result); } + + @PostMapping("/rush-buy") + @Operation( + summary = "按抢单账号批量抢购", + description = + "根据 ids 查询 lb_buy_account,按 tenant_id 关联 lb_third_integration_config 获取 URL 与 appStr;" + + "每个账号使用 token_front 作为 hxrd 请求 Token,max_grab_count 作为最大成功抢购笔数," + + "抢购逻辑同 LbGoodsController#rushBuy") + public ResponseEntity> rushBuy( + @Parameter(description = "抢单账号 ID 列表", required = true) + @RequestBody LbBuyAccountRushBuyRequest request) { + Map result = lbBuyAccountService.rushBuyByIds(request.getIds()); + Boolean success = (Boolean) result.get("success"); + if (success != null && success) { + return ResponseEntity.ok(result); + } + if (result.get("message") != null + && (result.get("message").toString().contains("不能为空") + || result.get("message").toString().contains("必须大于0"))) { + return ResponseEntity.badRequest().body(result); + } + return ResponseEntity.ok(result); + } } diff --git a/src/main/java/com/rj/controller/LbPurchaseApplyController.java b/src/main/java/com/rj/controller/LbPurchaseApplyController.java index 96442bb..4a64983 100644 --- a/src/main/java/com/rj/controller/LbPurchaseApplyController.java +++ b/src/main/java/com/rj/controller/LbPurchaseApplyController.java @@ -162,8 +162,8 @@ public class LbPurchaseApplyController { @Operation(summary = "按用户ID列表批量开通或关闭 hxrd 用户特权", description = "根据入参 userIds 逐条调用 POST /app/admin/user/update," + "不计算 viptime,直接使用请求体中的 vipTime、maxOrder、isVip(1 开通,0 关闭);" - + "maxOrder 为 0 时不传 max_order,不修改第三方该字段。" - + "需配置 hxr.admin.cookie 或 hxr.admin.phpsid。") + + "maxOrder 为 0 时不传 max_order,不修改第三方该字段;" + + "cookie、URL、Referer 等从 lb_third_integration_config 按 tenantId 读取") public ResponseEntity> updateHxrAdminUserVipByUserIds( @Parameter(description = "租户、用户列表及特权参数", required = true) @Valid @RequestBody UpdateHxrAdminUserVipRequest body) { @@ -182,8 +182,8 @@ public class LbPurchaseApplyController { + "仅当 colleague_name 能在 lb_daily_user_trade(同租户 nickname)中查到时才开通;" + "以 colleague_phone 查询 /app/admin/user/select," + "以每条记录的 apply_date 为起算日计算 viptime(周末先对齐到下一工作日,再顺延 2 个工作日)," - + "再 POST /app/admin/user/update(max_order 使用 select 返回的 HxrUserRow.max_order)。" - + "需配置 hxr.admin.cookie 或 hxr.admin.phpsid。") + + "再 POST /app/admin/user/update(max_order 使用 select 返回的 HxrUserRow.max_order);" + + "cookie、URL、Referer 等从 lb_third_integration_config 按 tenantId 读取") public ResponseEntity> syncHxrAdminColleagueVip( @Parameter(description = "申请开始日期(yyyy-MM-dd)", required = true) @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate applyDateStart, diff --git a/src/main/java/com/rj/dto/hxr/HxrAdminUserApiContext.java b/src/main/java/com/rj/dto/hxr/HxrAdminUserApiContext.java index 0cadfbf..bd31168 100644 --- a/src/main/java/com/rj/dto/hxr/HxrAdminUserApiContext.java +++ b/src/main/java/com/rj/dto/hxr/HxrAdminUserApiContext.java @@ -5,6 +5,7 @@ package com.rj.dto.hxr; */ public record HxrAdminUserApiContext( String userSelectBaseUrl, + String userUpdateUrl, int pageLimit, String cookieHeader, String referer) { diff --git a/src/main/java/com/rj/entity/LbBuyAccount.java b/src/main/java/com/rj/entity/LbBuyAccount.java index 2dd4321..b4ea1fd 100644 --- a/src/main/java/com/rj/entity/LbBuyAccount.java +++ b/src/main/java/com/rj/entity/LbBuyAccount.java @@ -54,6 +54,10 @@ public class LbBuyAccount implements Serializable { @Schema(description = "登录网址") private String loginUrl; + @TableField("token_front") + @Schema(description = "前端 Token") + private String tokenFront; + @TableField("max_grab_amount") @Schema(description = "抢单最大金额(整数)") private Integer maxGrabAmount; @@ -74,6 +78,18 @@ public class LbBuyAccount implements Serializable { @Schema(description = "累计点数") private Integer totalPoints; + @TableField("enabled") + @Schema(description = "是否启用:1启用 0禁用") + private Integer enabled; + + @TableField("rush_buy_result") + @Schema(description = "抢单结果:成功含货品ID与金额,失败含原因及接口返回信息") + private String rushBuyResult; + + @TableField("last_rush_buy_time") + @Schema(description = "最后一次抢单时间") + private LocalDateTime lastRushBuyTime; + @TableField("create_time") @Schema(description = "创建时间") private LocalDateTime createTime; diff --git a/src/main/java/com/rj/service/HxrAdminUserService.java b/src/main/java/com/rj/service/HxrAdminUserService.java index ce9195e..e8adea6 100644 --- a/src/main/java/com/rj/service/HxrAdminUserService.java +++ b/src/main/java/com/rj/service/HxrAdminUserService.java @@ -115,6 +115,7 @@ public class HxrAdminUserService { } HxrAdminUserApiContext ctx = new HxrAdminUserApiContext( stripQuery(properties.getUserSelectUrl()), + stripQuery(properties.getUserUpdateUrl()), USER_SELECT_PAGE_SIZE, cookieHeader, "https://22222/app/admin/user/index"); @@ -204,11 +205,44 @@ public class HxrAdminUserService { log.warn("hxr.admin 未配置 cookie 或 phpsid,跳过 user/select"); return Optional.empty(); } + HxrAdminUserApiContext ctx = new HxrAdminUserApiContext( + stripQuery(properties.getUserSelectUrl()), + stripQuery(properties.getUserUpdateUrl()), + USER_SELECT_PAGE_SIZE, + cookieHeader, + "https://22222/app/admin/user/index"); + return fetchFirstUserByMobile(mobile, ctx); + } + + /** + * 按手机号查询用户列表,返回第一条(使用租户 {@code lb_third_integration_config} 解析出的运行时配置)。 + */ + public Optional fetchFirstUserByMobile(String mobile, HxrAdminUserApiContext ctx) + throws Exception { + if (ctx == null) { + log.warn("用户 API 配置为空,跳过 user/select"); + return Optional.empty(); + } + String cookieHeader = ctx.cookieHeader(); + if (cookieHeader == null || cookieHeader.isBlank()) { + log.warn("未配置 cookie 或 phpsid,跳过 user/select"); + return Optional.empty(); + } if (mobile == null || mobile.isBlank()) { return Optional.empty(); } + String userSelectBaseUrl = ctx.userSelectBaseUrl(); + if (userSelectBaseUrl == null || userSelectBaseUrl.isBlank()) { + log.warn("未配置 userSelectBaseUrl,跳过 user/select"); + return Optional.empty(); + } + String referer = ctx.referer(); + if (referer == null || referer.isBlank()) { + log.warn("未配置 referer,跳过 user/select"); + return Optional.empty(); + } - String uri = UriComponentsBuilder.fromUriString(properties.getUserSelectUrl()) + String uri = UriComponentsBuilder.fromUriString(userSelectBaseUrl) .replaceQueryParam("mobile", mobile.trim()) .replaceQueryParam("id", "") .replaceQueryParam("pid", "") @@ -228,7 +262,7 @@ public class HxrAdminUserService { .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") .header("Cookie", cookieHeader) .header("Priority", "u=1, i") - .header("Referer", "https://22222/app/admin/user/index") + .header("Referer", referer) .header("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") .GET() .build(); @@ -280,6 +314,40 @@ public class HxrAdminUserService { log.warn("hxr.admin 未配置 cookie 或 phpsid,跳过 user/update"); return false; } + HxrAdminUserApiContext ctx = new HxrAdminUserApiContext( + stripQuery(properties.getUserSelectUrl()), + stripQuery(properties.getUserUpdateUrl()), + USER_SELECT_PAGE_SIZE, + cookieHeader, + "https://22222/app/admin/user/index"); + return updateUserVipFields(userId, maxOrder, viptimeFormatted, isVip, ctx); + } + + /** + * 更新用户 VIP 相关字段(使用租户 {@code lb_third_integration_config} 解析出的运行时配置)。 + */ + public boolean updateUserVipFields( + long userId, Integer maxOrder, String viptimeFormatted, int isVip, HxrAdminUserApiContext ctx) + throws Exception { + if (ctx == null) { + log.warn("用户 API 配置为空,跳过 user/update"); + return false; + } + String cookieHeader = ctx.cookieHeader(); + if (cookieHeader == null || cookieHeader.isBlank()) { + log.warn("未配置 cookie 或 phpsid,跳过 user/update"); + return false; + } + String userUpdateUrl = ctx.userUpdateUrl(); + if (userUpdateUrl == null || userUpdateUrl.isBlank()) { + log.warn("未配置 userUpdateUrl,跳过 user/update"); + return false; + } + String referer = ctx.referer(); + if (referer == null || referer.isBlank()) { + log.warn("未配置 referer,跳过 user/update"); + return false; + } String form = buildUpdateFormBody(userId, maxOrder, viptimeFormatted, isVip); @@ -289,12 +357,12 @@ public class HxrAdminUserService { .build(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(properties.getUserUpdateUrl())) + .uri(URI.create(userUpdateUrl.trim())) .timeout(java.time.Duration.ofSeconds(120)) .header("Accept", "application/json, text/javascript, */*; q=0.01") .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .header("Cookie", cookieHeader) - .header("Referer", "https://22222/app/admin/user/index") + .header("Referer", referer) .header("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") .POST(HttpRequest.BodyPublishers.ofString(form, StandardCharsets.UTF_8)) .build(); diff --git a/src/main/java/com/rj/service/ILbBuyAccountService.java b/src/main/java/com/rj/service/ILbBuyAccountService.java index 72e486c..9d6adbb 100644 --- a/src/main/java/com/rj/service/ILbBuyAccountService.java +++ b/src/main/java/com/rj/service/ILbBuyAccountService.java @@ -3,6 +3,7 @@ package com.rj.service; import com.baomidou.mybatisplus.extension.service.IService; import com.rj.entity.LbBuyAccount; +import java.util.List; import java.util.Map; public interface ILbBuyAccountService extends IService { @@ -23,4 +24,10 @@ public interface ILbBuyAccountService extends IService { String referrerName, String createTimeStart, String createTimeEnd); + + /** + * 按账号 ID 列表批量抢购:每个账号使用其 token_front 与 max_grab_count, + * tenant_id 关联 lb_third_integration_config 解析 URL 与 appStr。 + */ + Map rushBuyByIds(List ids); } diff --git a/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java b/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java index ab2efe5..12ea52d 100644 --- a/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java @@ -634,9 +634,7 @@ public class LbAssessmentApplyServiceImpl if (meetingNumber != null && !meetingNumber.trim().isEmpty()) { queryWrapper.like(LbAssessmentApply::getMeetingNumber, meetingNumber.trim()); } - queryWrapper.orderByAsc(LbAssessmentApply::getSortedNum) - .orderByDesc(LbAssessmentApply::getUpdatedAt) - .orderByDesc(LbAssessmentApply::getCreatedAt); + queryWrapper.orderByDesc(LbAssessmentApply::getUpdatedAt) ; return queryWrapper; } diff --git a/src/main/java/com/rj/service/impl/LbBuyAccountServiceImpl.java b/src/main/java/com/rj/service/impl/LbBuyAccountServiceImpl.java index 6fd6063..9f04186 100644 --- a/src/main/java/com/rj/service/impl/LbBuyAccountServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbBuyAccountServiceImpl.java @@ -6,12 +6,17 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.rj.entity.LbBuyAccount; import com.rj.mapper.LbBuyAccountMapper; import com.rj.service.ILbBuyAccountService; +import com.rj.service.ILbGoodsService; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; 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.UUID; @@ -21,9 +26,15 @@ public class LbBuyAccountServiceImpl extends ServiceImpl implements ILbBuyAccountService { + /** 与表字段 rush_buy_result(TEXT)长度上限一致 */ + private static final int RUSH_BUY_RESULT_MAX_LEN = 65535; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + @Autowired + private ILbGoodsService lbGoodsService; + @Override public Map add(LbBuyAccount entity) { Map result = new HashMap<>(); @@ -185,6 +196,113 @@ public class LbBuyAccountServiceImpl } } + @Override + public Map rushBuyByIds(List ids) { + Map result = new HashMap<>(); + try { + if (ids == null || ids.isEmpty()) { + result.put("success", false); + result.put("message", "ids不能为空"); + return result; + } + + List normalizedIds = new ArrayList<>(); + for (String id : ids) { + if (id != null && !id.trim().isEmpty()) { + normalizedIds.add(id.trim()); + } + } + if (normalizedIds.isEmpty()) { + result.put("success", false); + result.put("message", "ids不能为空"); + return result; + } + + List accounts = this.listByIds(normalizedIds); + Map accountMap = new LinkedHashMap<>(); + for (LbBuyAccount account : accounts) { + if (account != null && account.getId() != null) { + accountMap.put(account.getId(), account); + } + } + + List> accountResults = new ArrayList<>(); + int successAccounts = 0; + int failAccounts = 0; + + for (String id : normalizedIds) { + Map item = new LinkedHashMap<>(); + item.put("accountId", id); + + LbBuyAccount account = accountMap.get(id); + if (account == null) { + item.put("success", false); + item.put("message", "抢单账号不存在"); + accountResults.add(item); + failAccounts++; + continue; + } + + item.put("loginAccount", account.getLoginAccount()); + item.put("tenantId", account.getTenantId()); + item.put("nickname", account.getNickname()); + + String resultMessage; + Boolean rushSuccess = false; + LocalDateTime rushBuyTime = LocalDateTime.now(); + + if (account.getEnabled() != null && account.getEnabled() == 0) { + resultMessage = formatPreRushBuyFailure("账号未启用"); + } else if (account.getTenantId() == null || account.getTenantId().trim().isEmpty()) { + resultMessage = formatPreRushBuyFailure("tenantId不能为空"); + } else if (account.getTokenFront() == null || account.getTokenFront().trim().isEmpty()) { + resultMessage = formatPreRushBuyFailure("token_front不能为空"); + } else { + Integer maxGrabCount = account.getMaxGrabCount(); + if (maxGrabCount == null || maxGrabCount <= 0) { + resultMessage = formatPreRushBuyFailure("maxGrabCount必须大于0"); + } else { + Map rushBuyResult = lbGoodsService.rushBuy( + account.getTenantId().trim(), + account.getTokenFront().trim(), + maxGrabCount); + item.put("rushBuyResult", rushBuyResult); + rushSuccess = rushBuyResult.get("success") instanceof Boolean + ? (Boolean) rushBuyResult.get("success") + : null; + resultMessage = formatRushBuyResultMessage(rushBuyResult); + } + } + + item.put("success", Boolean.TRUE.equals(rushSuccess)); + item.put("message", resultMessage); + accountResults.add(item); + persistRushBuyOutcome(account.getId(), resultMessage, rushBuyTime); + + if (Boolean.TRUE.equals(rushSuccess)) { + successAccounts++; + } else { + failAccounts++; + } + } + + result.put("success", successAccounts > 0); + result.put("message", successAccounts > 0 + ? "批量抢购完成,成功账号 " + successAccounts + " 个,失败 " + failAccounts + " 个" + : "批量抢购未成功"); + result.put("totalAccounts", normalizedIds.size()); + result.put("successAccounts", successAccounts); + result.put("failAccounts", failAccounts); + result.put("accountResults", accountResults); + return result; + } catch (Exception e) { + log.error("抢单账号批量抢购异常", e); + result.put("success", false); + result.put("message", "批量抢购异常:" + e.getMessage()); + return result; + } + } + private Map validateRequiredForAdd(LbBuyAccount entity) { Map result = new HashMap<>(); if (entity.getTenantId() == null || entity.getTenantId().trim().isEmpty()) { @@ -235,6 +353,9 @@ public class LbBuyAccountServiceImpl if (entity.getLoginUrl() != null) { entity.setLoginUrl(entity.getLoginUrl().trim()); } + if (entity.getTokenFront() != null) { + entity.setTokenFront(entity.getTokenFront().trim()); + } } private static void defaultIntegerFields(LbBuyAccount entity) { @@ -253,6 +374,131 @@ public class LbBuyAccountServiceImpl if (entity.getTotalPoints() == null) { entity.setTotalPoints(0); } + if (entity.getEnabled() == null) { + entity.setEnabled(1); + } + } + + /** + * 将本次抢单结果与抢单时间写入 lb_buy_account(rush_buy_result、last_rush_buy_time)。 + */ + private void persistRushBuyOutcome(String accountId, String resultMessage, LocalDateTime rushBuyTime) { + if (accountId == null || accountId.trim().isEmpty()) { + return; + } + String storedResult = truncateRushBuyResult( + resultMessage != null && !resultMessage.isEmpty() ? resultMessage : "未知抢单结果"); + LocalDateTime time = rushBuyTime != null ? rushBuyTime : LocalDateTime.now(); + try { + boolean ok = this.lambdaUpdate() + .eq(LbBuyAccount::getId, accountId.trim()) + .set(LbBuyAccount::getRushBuyResult, storedResult) + .set(LbBuyAccount::getLastRushBuyTime, time) + .set(LbBuyAccount::getUpdateTime, LocalDateTime.now()) + .update(); + if (!ok) { + log.warn("抢单结果落库未更新任何行,accountId={}", accountId); + } + } catch (Exception e) { + log.error("抢单结果落库异常,accountId={}", accountId, e); + } + } + + private static String formatPreRushBuyFailure(String reason) { + return "【失败】原因:" + reason; + } + + /** + * 根据 rushBuy 返回结构生成落库文案:成功记录货品 ID 与金额;失败记录原因与接口返回信息。 + */ + private static String formatRushBuyResultMessage(Map rushBuyResult) { + if (rushBuyResult == null || rushBuyResult.isEmpty()) { + return formatPreRushBuyFailure("抢购未返回结果"); + } + + Object summaryMsg = rushBuyResult.get("message"); + Object detailsObj = rushBuyResult.get("details"); + if (!(detailsObj instanceof List details) || details.isEmpty()) { + return formatRushBuyWithoutDetails(rushBuyResult, summaryMsg); + } + + List successLines = new ArrayList<>(); + List failLines = new ArrayList<>(); + for (Object detailObj : details) { + if (!(detailObj instanceof Map detail)) { + continue; + } + Object successFlag = detail.get("success"); + boolean itemSuccess = Boolean.TRUE.equals(successFlag); + if (itemSuccess) { + successLines.add(formatRushBuySuccessDetail(detail)); + } else { + failLines.add(formatRushBuyFailDetail(detail)); + } + } + + StringBuilder sb = new StringBuilder(); + if (summaryMsg != null) { + sb.append("汇总:").append(summaryMsg); + } + Object successCount = rushBuyResult.get("successCount"); + Object failCount = rushBuyResult.get("failCount"); + if (successCount != null || failCount != null) { + sb.append("(成功").append(successCount).append("笔,失败").append(failCount).append("笔)"); + } + + if (!successLines.isEmpty()) { + sb.append(" | 【成功】").append(String.join("; ", successLines)); + } + if (!failLines.isEmpty()) { + sb.append(" | 【失败】").append(String.join("; ", failLines)); + } + if (successLines.isEmpty() && failLines.isEmpty()) { + sb.append(" | 【失败】原因:无有效抢购明细"); + if (summaryMsg != null) { + sb.append(";返回信息:").append(summaryMsg); + } + } + return truncateRushBuyResult(sb.toString()); + } + + /** rushBuy 未产生逐笔明细(配置缺失、无可抢货品、异常等) */ + private static String formatRushBuyWithoutDetails(Map rushBuyResult, Object summaryMsg) { + Boolean overallSuccess = rushBuyResult.get("success") instanceof Boolean + ? (Boolean) rushBuyResult.get("success") + : null; + String summary = summaryMsg != null ? summaryMsg.toString() : "无返回信息"; + if (Boolean.TRUE.equals(overallSuccess)) { + return truncateRushBuyResult("【成功】返回信息:" + summary); + } + return truncateRushBuyResult("【失败】原因:" + summary + ";返回信息:" + summary); + } + + private static String formatRushBuySuccessDetail(Map detail) { + return "货品ID=" + detail.get("id") + + ",金额=" + detail.get("totalMoney"); + } + + private static String formatRushBuyFailDetail(Map detail) { + Object apiCode = detail.get("apiCode"); + Object apiMsg = detail.get("message"); + String reason = apiCode != null + ? "接口返回码=" + apiCode + (apiMsg != null ? "," + apiMsg : "") + : (apiMsg != null ? apiMsg.toString() : "未知原因"); + return "货品ID=" + detail.get("id") + + ",金额=" + detail.get("totalMoney") + + ",原因=" + reason + + ",返回信息=" + (apiMsg != null ? apiMsg : "无"); + } + + private static String truncateRushBuyResult(String text) { + if (text == null) { + return null; + } + if (text.length() <= RUSH_BUY_RESULT_MAX_LEN) { + return text; + } + return text.substring(0, RUSH_BUY_RESULT_MAX_LEN); } private static LocalDateTime parseDateTime(String text) { diff --git a/src/main/java/com/rj/service/impl/LbPurchaseApplyServiceImpl.java b/src/main/java/com/rj/service/impl/LbPurchaseApplyServiceImpl.java index 67be393..934fc35 100644 --- a/src/main/java/com/rj/service/impl/LbPurchaseApplyServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbPurchaseApplyServiceImpl.java @@ -11,6 +11,7 @@ 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.fasterxml.jackson.databind.ObjectMapper; +import com.rj.dto.hxr.HxrAdminUserApiContext; import com.rj.dto.hxr.HxrUserRow; import com.rj.entity.LbDailyUserTrade; import com.rj.entity.LbDailyUserTradeReport; @@ -25,6 +26,7 @@ import com.rj.mapper.LbPurchaseApplyMapper; import com.rj.mapper.LbUserMapper; import com.rj.service.HxrAdminUserService; import com.rj.service.ILbPurchaseApplyService; +import com.rj.service.ILbThirdIntegrationConfigService; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -71,6 +73,9 @@ public class LbPurchaseApplyServiceImpl @Autowired private HxrAdminUserService hxrAdminUserService; + @Autowired + private ILbThirdIntegrationConfigService lbThirdIntegrationConfigService; + @Autowired private LbUserMapper lbUserMapper; @@ -907,6 +912,22 @@ public class LbPurchaseApplyServiceImpl return result; } + String tid = tenantId.trim(); + Optional apiContextOpt = + lbThirdIntegrationConfigService.resolveAdminUserApiContext(tid); + if (apiContextOpt.isEmpty()) { + result.put("success", false); + result.put("message", + "未找到该租户的第三方集成配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)"); + result.put("totalRecords", userIds.size()); + result.put("successCount", 0); + result.put("failCount", userIds.size()); + result.put("details", List.of()); + result.put("tenantId", tid); + return result; + } + HxrAdminUserApiContext apiContext = apiContextOpt.get(); + List> details = new ArrayList<>(); int ok = 0; int fail = 0; @@ -926,7 +947,8 @@ public class LbPurchaseApplyServiceImpl try { Integer maxOrderForApi = maxOrder == 0 ? null : maxOrder; boolean updated = - hxrAdminUserService.updateUserVipFields(userId, maxOrderForApi, vipTimeStr, isVip); + hxrAdminUserService.updateUserVipFields( + userId, maxOrderForApi, vipTimeStr, isVip, apiContext); if (updated) { one.put("success", true); one.put("message", "user/update 成功"); @@ -985,6 +1007,24 @@ public class LbPurchaseApplyServiceImpl return result; } + String tid = tenantId.trim(); + Optional apiContextOpt = + lbThirdIntegrationConfigService.resolveAdminUserApiContext(tid); + if (apiContextOpt.isEmpty()) { + result.put("success", false); + result.put("message", + "未找到该租户的第三方集成配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)"); + result.put("totalRecords", rows.size()); + result.put("successCount", 0); + result.put("failCount", rows.size()); + result.put("details", List.of()); + result.put("applyDateStart", applyDateStart); + result.put("applyDateEnd", applyDateEnd); + result.put("tenantId", tid); + return result; + } + HxrAdminUserApiContext apiContext = apiContextOpt.get(); + Set tradeMatchedNicknames = ctx.tradeMatchedNicknames(); List> details = new ArrayList<>(); int ok = 0; @@ -1010,7 +1050,7 @@ public class LbPurchaseApplyServiceImpl String vipTimeStr = HxrAdminUserService.formatVipTime(vipTime); one.put("viptime", vipTimeStr); - Optional userOpt = hxrAdminUserService.fetchFirstUserByMobile(phone); + Optional userOpt = hxrAdminUserService.fetchFirstUserByMobile(phone, apiContext); if (userOpt.isEmpty()) { one.put("success", false); one.put("message", "user/select 无用户或接口失败"); @@ -1031,7 +1071,7 @@ public class LbPurchaseApplyServiceImpl } one.put("maxOrder", maxOrder); boolean updated = - hxrAdminUserService.updateUserVipFields(hxrUserId, maxOrder, vipTimeStr); + hxrAdminUserService.updateUserVipFields(hxrUserId, maxOrder, vipTimeStr, 1, apiContext); if (updated) { one.put("success", true); one.put("message", "user/update 成功"); diff --git a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java index 319c3b4..df05b2f 100644 --- a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java @@ -362,6 +362,7 @@ public class LbThirdIntegrationConfigServiceImpl try { return Optional.of(new HxrAdminUserApiContext( LbThirdIntegrationConfigUtil.resolveUserSelectBaseUrl(config), + LbThirdIntegrationConfigUtil.resolveUserUpdateUrl(config), LbThirdIntegrationConfigUtil.resolveUserPageLimit(config), cookieHeader.trim(), LbThirdIntegrationConfigUtil.resolveUserReferer(config))); diff --git a/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java b/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java index 2d7162a..da3b58e 100644 --- a/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java +++ b/src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java @@ -73,6 +73,19 @@ public final class LbThirdIntegrationConfigUtil { return base + path; } + public static String resolveUserUpdateUrl(LbThirdIntegrationConfig config) { + String base = trimTrailingSlash(requireText(config.getAdminBaseUrl(), "adminBaseUrl")); + String path = config.getUserUpdatePath(); + if (!StringUtils.hasText(path)) { + path = LbThirdIntegrationConstants.DEFAULT_USER_UPDATE_PATH; + } + path = path.trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + return base + path; + } + public static String resolveUserReferer(LbThirdIntegrationConfig config) { if (StringUtils.hasText(config.getUserReferer())) { return config.getUserReferer().trim();