From c7016d5ae46eeb61efd74eca51b741ef15cac771 Mon Sep 17 00:00:00 2001 From: hy001 Date: Tue, 9 Jun 2026 15:43:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=A2=E5=8D=95=E5=AF=BC?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/inapp/InAppPurchaseDetailsQryCmd.java | 15 +- .../order/InAppPurchaseRestController.java | 39 +++-- .../InAppPurchaseDetailsExportModel.java | 88 +++++++++++ .../order/InAppPurchaseBackServiceImpl.java | 142 ++++++++++++++---- .../app/order/InAppPurchaseBackService.java | 22 ++- .../impl/InAppPurchaseDetailsServiceImpl.java | 29 ++-- .../query/InAppPurchaseDetailsQuery.java | 15 +- ...InAppPurchaseDetailsClientServiceImpl.java | 14 +- .../sys/query/GameListConfigQryExe.java | 100 +++++++++--- 9 files changed, 368 insertions(+), 96 deletions(-) create mode 100644 rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/excel/model/order/InAppPurchaseDetailsExportModel.java diff --git a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/inapp/InAppPurchaseDetailsQryCmd.java b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/inapp/InAppPurchaseDetailsQryCmd.java index 38c65c4e..b7a42647 100644 --- a/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/inapp/InAppPurchaseDetailsQryCmd.java +++ b/rc-service/rc-inner-api/order-inner/order-inner-model/src/main/java/com/red/circle/order/inner/model/cmd/inapp/InAppPurchaseDetailsQryCmd.java @@ -98,8 +98,13 @@ public class InAppPurchaseDetailsQryCmd extends Command { */ private String lastId; - /** - * 条数. - */ - private Integer limit; -} + /** + * 条数. + */ + private Integer limit; + + /** + * 是否导出全部筛选结果;导出时不使用 lastId 和 limit 分页. + */ + private Boolean exportAll; +} diff --git a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/order/InAppPurchaseRestController.java b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/order/InAppPurchaseRestController.java index 789a31ab..8513fef0 100644 --- a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/order/InAppPurchaseRestController.java +++ b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/order/InAppPurchaseRestController.java @@ -1,12 +1,15 @@ package com.red.circle.console.adapter.app.order; -import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; -import com.red.circle.console.app.service.app.order.InAppPurchaseBackService; -import com.red.circle.framework.web.controller.BaseController; -import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; -import java.util.List; -import java.util.Map; -import lombok.RequiredArgsConstructor; +import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; +import com.red.circle.console.app.service.app.order.InAppPurchaseBackService; +import com.red.circle.console.infra.annotations.OpsOperationReqLog; +import com.red.circle.framework.web.controller.BaseController; +import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -45,9 +48,19 @@ public class InAppPurchaseRestController extends BaseController { /** * 订单统计查询 - 返回金额总数和订单总数 */ - @GetMapping("/statistics") - public Map statistics(InAppPurchaseDetailsQryCmd query) { - return inAppPurchaseBackService.statistics(query); - } - -} + @GetMapping("/statistics") + public Map statistics(InAppPurchaseDetailsQryCmd query) { + return inAppPurchaseBackService.statistics(query); + } + + /** + * 订单详情导出. + */ + @OpsOperationReqLog(value = "导出-订单详情", ignoreRequestParam = true) + @GetMapping("/details/export") + public void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query) + throws IOException { + inAppPurchaseBackService.exportDetails(response, query); + } + +} diff --git a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/excel/model/order/InAppPurchaseDetailsExportModel.java b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/excel/model/order/InAppPurchaseDetailsExportModel.java new file mode 100644 index 00000000..bdb485a8 --- /dev/null +++ b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/excel/model/order/InAppPurchaseDetailsExportModel.java @@ -0,0 +1,88 @@ +package com.red.circle.console.app.excel.model.order; + +import com.alibaba.excel.annotation.ExcelProperty; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 内购订单详情导出模型. + */ +@Data +@Accessors(chain = true) +public class InAppPurchaseDetailsExportModel implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "Env") + private String env; + + @ExcelProperty(value = "Sys Origin") + private String sysOrigin; + + @ExcelProperty(value = "Platform") + private String platform; + + @ExcelProperty(value = "Factory") + private String factoryCode; + + @ExcelProperty(value = "Channel") + private String channel; + + @ExcelProperty(value = "Buyer User ID") + private String buyerUserId; + + @ExcelProperty(value = "Buyer Account") + private String buyerAccount; + + @ExcelProperty(value = "Buyer Nickname") + private String buyerNickname; + + @ExcelProperty(value = "Accept User ID") + private String acceptUserId; + + @ExcelProperty(value = "Accept Account") + private String acceptAccount; + + @ExcelProperty(value = "Accept Nickname") + private String acceptNickname; + + @ExcelProperty(value = "Amount(USD)") + private BigDecimal amountUsd; + + @ExcelProperty(value = "Amount") + private BigDecimal amount; + + @ExcelProperty(value = "Currency") + private String currency; + + @ExcelProperty(value = "Description") + private String productDescriptor; + + @ExcelProperty(value = "Status") + private String status; + + @ExcelProperty(value = "Receipt Type") + private String receiptType; + + @ExcelProperty(value = "Third Party Order ID") + private String orderId; + + @ExcelProperty(value = "App Order ID") + private String appOrderId; + + @ExcelProperty(value = "Track ID") + private String trackId; + + @ExcelProperty(value = "Country Code") + private String countryCode; + + @ExcelProperty(value = "Create Time") + private String createTime; + + @ExcelProperty(value = "Update Time") + private String updateTime; +} diff --git a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackServiceImpl.java b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackServiceImpl.java index f93ed493..d05d1302 100644 --- a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackServiceImpl.java +++ b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackServiceImpl.java @@ -1,21 +1,30 @@ -package com.red.circle.console.app.service.app.order; - -import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; -import com.red.circle.console.infra.database.rds.entity.admin.User; -import com.red.circle.console.infra.database.rds.service.admin.UserService; -import com.red.circle.framework.core.asserts.ResponseAssert; -import com.red.circle.order.inner.asserts.OrderErrorCode; -import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient; -import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; -import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO; -import com.red.circle.tool.core.collection.CollectionUtils; -import com.red.circle.other.inner.model.dto.user.UserProfileDTO; -import com.red.circle.other.inner.endpoint.user.user.UserProfileClient; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +package com.red.circle.console.app.service.app.order; + +import com.alibaba.excel.EasyExcel; +import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; +import com.red.circle.console.app.excel.EasyExcelUtils; +import com.red.circle.console.app.excel.model.order.InAppPurchaseDetailsExportModel; +import com.red.circle.console.infra.database.rds.entity.admin.User; +import com.red.circle.console.infra.database.rds.service.admin.UserService; +import com.red.circle.framework.core.asserts.ResponseAssert; +import com.red.circle.order.inner.asserts.OrderErrorCode; +import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient; +import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; +import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseFactoryDTO; +import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO; +import com.red.circle.tool.core.collection.CollectionUtils; +import com.red.circle.tool.core.text.StringUtils; +import com.red.circle.other.inner.model.dto.user.UserProfileDTO; +import com.red.circle.other.inner.endpoint.user.user.UserProfileClient; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -126,11 +135,92 @@ public class InAppPurchaseBackServiceImpl implements InAppPurchaseBackService { }).collect(Collectors.toList()); } - @Override - public Map statistics(InAppPurchaseDetailsQryCmd query) { - return ResponseAssert.requiredSuccess( - inAppPurchaseDetailsClient.statistics(query) - ); - } - -} + @Override + public Map statistics(InAppPurchaseDetailsQryCmd query) { + return ResponseAssert.requiredSuccess( + inAppPurchaseDetailsClient.statistics(query) + ); + } + + @Override + public void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query) + throws IOException { + query.setLastId(null); + query.setLimit(null); + query.setExportAll(Boolean.TRUE); + + List exportRows = listDetails(query).stream() + .map(this::toExportModel) + .collect(Collectors.toList()); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + String fileName = URLEncoder.encode("InAppPurchaseOrders", StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + EasyExcel.write(response.getOutputStream(), InAppPurchaseDetailsExportModel.class) + .registerWriteHandler(EasyExcelUtils.getStyleStrategy()) + .sheet("Orders") + .doWrite(exportRows); + } + + private InAppPurchaseDetailsExportModel toExportModel(InAppPurchaseDetailsCO co) { + InAppPurchaseDetailsDTO details = co.getDetails(); + InAppPurchaseFactoryDTO factory = Objects.isNull(details) ? null : details.getFactory(); + UserProfileDTO buyer = pickBuyerProfile(co, details); + UserProfileDTO accept = co.getAcceptUserProfile(); + + return new InAppPurchaseDetailsExportModel() + .setEnv(text(Objects.isNull(details) ? null : details.getEnv())) + .setSysOrigin(text(Objects.isNull(details) ? null : details.getSysOrigin())) + .setPlatform(text(Objects.isNull(factory) ? null : factory.getPlatform())) + .setFactoryCode(text(Objects.isNull(factory) ? null : factory.getFactoryCode())) + .setChannel(text(Objects.isNull(factory) ? null : factory.getFactoryChannelCode())) + .setBuyerUserId(userId(buyer, Objects.isNull(details) ? null : details.getCreateUser())) + .setBuyerAccount(text(Objects.isNull(buyer) ? null : buyer.getAccount())) + .setBuyerNickname(buyerNickname(co, buyer)) + .setAcceptUserId(userId(accept, Objects.isNull(details) ? null : details.getAcceptUserId())) + .setAcceptAccount(text(Objects.isNull(accept) ? null : accept.getAccount())) + .setAcceptNickname(text(Objects.isNull(accept) ? null : accept.getUserNickname())) + .setAmountUsd(Objects.isNull(details) ? null : details.getAmountUsd()) + .setAmount(Objects.isNull(details) ? null : details.getAmount()) + .setCurrency(text(Objects.isNull(details) ? null : details.getCurrency())) + .setProductDescriptor(text(Objects.isNull(details) ? null : details.getProductDescriptor())) + .setStatus(text(Objects.isNull(details) ? null : details.getStatus())) + .setReceiptType(text(Objects.isNull(details) ? null : details.getReceiptType())) + .setOrderId(text(Objects.isNull(details) ? null : details.getOrderId())) + .setAppOrderId(text(Objects.isNull(details) ? null : details.getId())) + .setTrackId(text(Objects.isNull(details) ? null : details.getTrackId())) + .setCountryCode(text(Objects.isNull(details) ? null : details.getCountryCode())) + .setCreateTime(text(Objects.isNull(details) ? null : details.getCreateTime())) + .setUpdateTime(text(Objects.isNull(details) ? null : details.getUpdateTime())); + } + + private UserProfileDTO pickBuyerProfile(InAppPurchaseDetailsCO co, InAppPurchaseDetailsDTO details) { + if (Objects.nonNull(co.getCreateUserProfile())) { + return co.getCreateUserProfile(); + } + if (Objects.nonNull(details) && Objects.equals(details.getCreateUser(), details.getAcceptUserId())) { + return co.getAcceptUserProfile(); + } + return null; + } + + private String buyerNickname(InAppPurchaseDetailsCO co, UserProfileDTO buyer) { + if (StringUtils.isNotBlank(co.getCreateNickname())) { + return co.getCreateNickname(); + } + return text(Objects.isNull(buyer) ? null : buyer.getUserNickname()); + } + + private String userId(UserProfileDTO profile, Long fallback) { + if (Objects.nonNull(profile) && Objects.nonNull(profile.getId())) { + return Objects.toString(profile.getId()); + } + return text(fallback); + } + + private String text(Object value) { + return Objects.isNull(value) ? "" : Objects.toString(value); + } + +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackService.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackService.java index 12d24f52..1f6975ce 100644 --- a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackService.java +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/order/InAppPurchaseBackService.java @@ -1,9 +1,11 @@ package com.red.circle.console.app.service.app.order; -import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; -import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; -import java.util.List; -import java.util.Map; +import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO; +import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; /** * 内购服务. @@ -25,6 +27,12 @@ public interface InAppPurchaseBackService extends IOrderService { /** * 订单统计查询 - 返回金额总数和订单总数 */ - Map statistics(InAppPurchaseDetailsQryCmd query); - -} + Map statistics(InAppPurchaseDetailsQryCmd query); + + /** + * 按筛选条件导出订单详情,不使用分页条件. + */ + void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query) + throws IOException; + +} diff --git a/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/impl/InAppPurchaseDetailsServiceImpl.java b/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/impl/InAppPurchaseDetailsServiceImpl.java index 7f230692..fdab4ec9 100644 --- a/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/impl/InAppPurchaseDetailsServiceImpl.java +++ b/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/impl/InAppPurchaseDetailsServiceImpl.java @@ -153,10 +153,11 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ ).getModifiedCount() > 0; } - @Override - public List list(InAppPurchaseDetailsQuery query) { - + @Override + public List list(InAppPurchaseDetailsQuery query) { + Criteria criteria = new Criteria(); + boolean exportAll = Boolean.TRUE.equals(query.getExportAll()); if (StringUtils.isNotBlank(query.getId())) { query.setLastId(null); @@ -205,18 +206,20 @@ public class InAppPurchaseDetailsServiceImpl implements InAppPurchaseDetailsServ ); } - if (StringUtils.isNotBlank(query.getLastId())) { + if (!exportAll && StringUtils.isNotBlank(query.getLastId())) { criteria.and(ID_FIELD).lt(query.getLastId()); } - - if (Objects.isNull(query.getLimit()) || query.getLimit() <= 0) { - query.setLimit(PageConstant.DEFAULT_LIMIT_SIZE); - } - - return mongoTemplate - .find(Query.query(criteria) - .with(Sort.by(Sort.Order.desc(ID_FIELD))) - .limit(query.getLimit()), InAppPurchaseDetails.class); + + Query mongoQuery = Query.query(criteria) + .with(Sort.by(Sort.Order.desc(ID_FIELD))); + if (!exportAll) { + if (Objects.isNull(query.getLimit()) || query.getLimit() <= 0) { + query.setLimit(PageConstant.DEFAULT_LIMIT_SIZE); + } + mongoQuery.limit(query.getLimit()); + } + + return mongoTemplate.find(mongoQuery, InAppPurchaseDetails.class); } @Override diff --git a/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/query/InAppPurchaseDetailsQuery.java b/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/query/InAppPurchaseDetailsQuery.java index 575cc460..2074b9c5 100644 --- a/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/query/InAppPurchaseDetailsQuery.java +++ b/rc-service/rc-service-order/order-infrastructure/src/main/java/com/red/circle/order/infra/database/mongo/order/query/InAppPurchaseDetailsQuery.java @@ -96,8 +96,13 @@ public class InAppPurchaseDetailsQuery implements Serializable { */ private String lastId; - /** - * 条数. - */ - private Integer limit; -} + /** + * 条数. + */ + private Integer limit; + + /** + * 是否导出全部筛选结果;导出时不使用 lastId 和 limit 分页. + */ + private Boolean exportAll; +} diff --git a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/InAppPurchaseDetailsClientServiceImpl.java b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/InAppPurchaseDetailsClientServiceImpl.java index ddae2b28..1e6fd000 100644 --- a/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/InAppPurchaseDetailsClientServiceImpl.java +++ b/rc-service/rc-service-order/order-inner-endpoint/src/main/java/com/red/circle/order/inner/service/impl/InAppPurchaseDetailsClientServiceImpl.java @@ -63,17 +63,21 @@ public class InAppPurchaseDetailsClientServiceImpl implements InAppPurchaseDetai @Override public List list(InAppPurchaseDetailsQryCmd qryCmd) { + boolean exportAll = Boolean.TRUE.equals(qryCmd.getExportAll()); List mongoOrders = safeList( inAppPurchaseDetailsInnerConvert.toListInAppPurchaseDetailsDTO( inAppPurchaseDetailsService.list( inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsQuery(qryCmd)) )); - List miFaPayOrders = listMiFaPayOrders(qryCmd, true).stream() + List miFaPayOrders = listMiFaPayOrders(qryCmd, !exportAll).stream() .map(order -> inAppPurchaseDetailsInnerConvert.toInAppPurchaseDetailsDTO( toMiFaPayDetails(order, false))) .filter(Objects::nonNull) .collect(Collectors.toList()); + if (exportAll) { + return mergeAll(mongoOrders, miFaPayOrders); + } return mergePage(mongoOrders, miFaPayOrders, normalizeLimit(qryCmd.getLimit())); } @@ -230,6 +234,13 @@ public class InAppPurchaseDetailsClientServiceImpl implements InAppPurchaseDetai private List mergePage(List first, List second, int limit) { + return mergeAll(first, second).stream() + .limit(limit) + .collect(Collectors.toList()); + } + + private List mergeAll(List first, + List second) { List result = new ArrayList<>(); result.addAll(first); result.addAll(second); @@ -237,7 +248,6 @@ public class InAppPurchaseDetailsClientServiceImpl implements InAppPurchaseDetai .filter(Objects::nonNull) .sorted(Comparator.comparing(InAppPurchaseDetailsDTO::getId, this::compareIdDesc)) - .limit(limit) .collect(Collectors.toList()); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/sys/query/GameListConfigQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/sys/query/GameListConfigQryExe.java index 98c91bce..f49b418a 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/sys/query/GameListConfigQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/sys/query/GameListConfigQryExe.java @@ -5,12 +5,13 @@ import com.google.common.collect.Lists; import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.other.app.convertor.sys.SysConfigAppConvertor; import com.red.circle.other.app.dto.clientobject.sys.GameListConfigCO; -import com.red.circle.other.app.dto.cmd.game.GameListQryCmd; -import com.red.circle.other.domain.gateway.user.UserProfileGateway; -import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; -import com.red.circle.other.domain.model.user.UserProfile; -import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService; -import com.red.circle.other.infra.database.cache.service.other.GameListCacheService; +import com.red.circle.other.app.dto.cmd.game.GameListQryCmd; +import com.red.circle.other.domain.gateway.user.UserProfileGateway; +import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; +import com.red.circle.other.domain.model.user.UserConsumptionLevel; +import com.red.circle.other.domain.model.user.UserProfile; +import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService; +import com.red.circle.other.infra.database.cache.service.other.GameListCacheService; import com.red.circle.other.infra.database.rds.service.live.RoomMemberService; import com.red.circle.other.infra.database.rds.service.sys.GameListConfigService; import com.red.circle.other.infra.database.rds.service.sys.VersionManageService; @@ -44,10 +45,13 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class GameListConfigQryExe { - private static final String COMMON = "COMMON"; - private static final String IOS_GAME_USER_WHITE_LIST = "IOS_GAME_USER_WHITE_LIST"; - private final UserRegionGateway userRegionGateway; - private final UserProfileGateway userProfileGateway; + private static final String COMMON = "COMMON"; + private static final String IOS_GAME_USER_WHITE_LIST = "IOS_GAME_USER_WHITE_LIST"; + private static final String GAME_LIST_TARGET_SYS_ORIGIN = "LIKEI"; + private static final String GAME_LIST_TARGET_COUNTRY_CODE = "TR"; + private static final int GAME_LIST_MIN_WEALTH_LEVEL = 2; + private final UserRegionGateway userRegionGateway; + private final UserProfileGateway userProfileGateway; private final EnumConfigCacheService enumConfigCacheService; private final SysConfigAppConvertor sysConfigAppConvertor; private final GameListCacheService gameListCacheService; @@ -63,21 +67,67 @@ public class GameListConfigQryExe { return configs; } - if (StringUtils.isBlank(cmd.getRoomSessionId())) { - configs = configs.stream().filter(e -> !"CHAT_ROOM".equals(e.getGameMode())).toList(); - } - - // 获得用户区域 - String regionId = userRegionGateway.getRegionId(cmd.requiredReqUserId()); - - return configs.stream() - .filter(configCO -> - StringUtils.isBlank(configCO.getRegions()) || configCO.getRegions() - .contains(regionId) - ).toList(); - } - - private List isBarrageGame(AppExtCommand cmd, List configs) { + if (StringUtils.isBlank(cmd.getRoomSessionId())) { + configs = configs.stream().filter(e -> !"CHAT_ROOM".equals(e.getGameMode())).toList(); + } + + if (!canShowGameList(cmd)) { + return Lists.newArrayList(); + } + + // 获得用户区域;配置为空代表全区域,配置有值时按逗号拆分后精确匹配区域 ID。 + String regionId = userRegionGateway.getRegionId(cmd.requiredReqUserId()); + + return configs.stream() + .filter(configCO -> matchRegion(configCO.getRegions(), regionId)) + .toList(); + } + + private boolean canShowGameList(GameListQryCmd cmd) { + if (!GAME_LIST_TARGET_SYS_ORIGIN.equalsIgnoreCase(cmd.requireReqSysOrigin())) { + return true; + } + + // LIKEI 游戏列表需要同时满足用户区域、财富等级和当前 IP 国家,任一条件不满足直接返回空列表。 + Long userId = cmd.requiredReqUserId(); + if (!GAME_LIST_TARGET_COUNTRY_CODE.equalsIgnoreCase(userRegionGateway.getRegionCode(userId))) { + return false; + } + + UserConsumptionLevel level = userProfileGateway.getUserConsumptionLevel( + cmd.requireReqSysOriginEnum(), userId); + int wealthLevel = Optional.ofNullable(level) + .map(UserConsumptionLevel::getWealthLevel) + .orElse(0); + if (wealthLevel < GAME_LIST_MIN_WEALTH_LEVEL) { + return false; + } + + return GAME_LIST_TARGET_COUNTRY_CODE.equalsIgnoreCase(ipCountryUtils.getCountryCode(resolveClientIp(cmd))); + } + + private boolean matchRegion(String regions, String regionId) { + if (StringUtils.isBlank(regions)) { + return true; + } + if (StringUtils.isBlank(regionId)) { + return false; + } + return Arrays.stream(regions.split(",")) + .map(String::trim) + .anyMatch(regionId::equals); + } + + private String resolveClientIp(GameListQryCmd cmd) { + if (StringUtils.isNotBlank(cmd.getReqIp())) { + return cmd.getReqIp(); + } + return Optional.ofNullable(latestMobileDeviceService.getByUserId(cmd.requiredReqUserId())) + .map(LatestMobileDevice::getIp) + .orElse(null); + } + + private List isBarrageGame(AppExtCommand cmd, List configs) { // 是否弹幕游戏 configs.forEach( config -> {