From b3ae76ea4511fb324104d2b14c535aa331bfcd99 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Thu, 6 Nov 2025 16:31:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=92=E8=A1=8C=E6=A6=9C?= =?UTF-8?q?=E5=8E=86=E5=8F=B2top1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RankingActivityRestController.java | 17 +++ .../activity/query/HistoricalTop1QryExe.java | 135 ++++++++++++++++++ .../activity/query/RankingListQryExe.java | 4 +- .../activity/RankingActivityServiceImpl.java | 9 ++ .../activity/HistoricalTop1ListCO.java | 30 ++++ .../activity/HistoricalWeekTop1CO.java | 29 ++++ .../cmd/activity/HistoricalTop1QueryCmd.java | 29 ++++ .../activity/RankingActivityService.java | 10 ++ .../infra/gateway/PropCouponGatewayImpl.java | 2 +- 9 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/HistoricalTop1QryExe.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalTop1ListCO.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalWeekTop1CO.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/HistoricalTop1QueryCmd.java diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java index ea19853f..c591ee23 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java @@ -1,12 +1,15 @@ package com.red.circle.other.adapter.app.activity; import com.red.circle.framework.web.controller.BaseController; +import com.red.circle.other.app.dto.clientobject.activity.HistoricalTop1ListCO; import com.red.circle.other.app.dto.clientobject.activity.RankingListCO; import com.red.circle.other.app.dto.clientobject.activity.UserRankInfoCO; import com.red.circle.other.app.dto.cmd.UserRankQueryCmd; +import com.red.circle.other.app.dto.cmd.activity.HistoricalTop1QueryCmd; import com.red.circle.other.app.service.activity.RankingActivityService; import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd; import com.red.circle.other.app.dto.cmd.activity.RankingListQueryCmd; +import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; @@ -46,6 +49,20 @@ public class RankingActivityRestController extends BaseController { */ @PostMapping("/list") public RankingListCO getRankingList(@RequestBody @Validated RankingListQueryCmd cmd) { + cmd.setCycleKey(ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt().toString()); return rankingActivityService.getRankingList(cmd); } + + /** + * 查询历史Top1列表(周榜) + * + * 用途:查询指定活动的历史周榜Top1用户,最多返回近10周 + * + * @param cmd 查询命令 + * @return 历史Top1列表 + */ + @PostMapping("/historical-top1") + public HistoricalTop1ListCO getHistoricalTop1List(@RequestBody @Validated HistoricalTop1QueryCmd cmd) { + return rankingActivityService.getHistoricalTop1List(cmd); + } } \ No newline at end of file diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/HistoricalTop1QryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/HistoricalTop1QryExe.java new file mode 100644 index 00000000..845c8a16 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/HistoricalTop1QryExe.java @@ -0,0 +1,135 @@ +package com.red.circle.other.app.command.activity.query; + +import com.red.circle.other.app.dto.clientobject.activity.HistoricalTop1ListCO; +import com.red.circle.other.app.dto.clientobject.activity.HistoricalWeekTop1CO; +import com.red.circle.other.app.dto.clientobject.activity.RankingActivityRecordCO; +import com.red.circle.other.app.dto.cmd.activity.HistoricalTop1QueryCmd; +import com.red.circle.other.app.dto.cmd.activity.RankingListQueryCmd; +import com.red.circle.other.app.service.activity.RankingActivityService; +import com.red.circle.other.domain.ranking.RankingActivityType; +import com.red.circle.other.domain.ranking.RankingCycleType; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.time.temporal.WeekFields; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +/** + * 历史Top1查询执行器 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class HistoricalTop1QryExe { + + private final RankingListQryExe rankingListQryExe; + + /** + * 执行查询 + */ + public HistoricalTop1ListCO execute(HistoricalTop1QueryCmd cmd) { + // 获取活动类型 + RankingActivityType activityType = RankingActivityType.getByCode(cmd.getActivityType()); + if (Objects.isNull(activityType)) { + throw new IllegalArgumentException("无效的活动类型"); + } + + // 构建结果 + HistoricalTop1ListCO result = new HistoricalTop1ListCO(); + result.setActivityType(activityType.getCode()); + result.setActivityTypeName(activityType.getName()); + + // 查询最近10周的Top1 + List historicalList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + // 获取往前推i周的周一cycleKey + String cycleKey = getWeekMondayCycleKey(i); + + // 查询该周的Top1 + RankingListQueryCmd queryCmd = new RankingListQueryCmd(); + queryCmd.setActivityType(cmd.getActivityType()); + queryCmd.setCycleType(RankingCycleType.WEEKLY.getCode()); + queryCmd.setCycleKey(cycleKey); + queryCmd.setUserSex(cmd.getUserSex()); + queryCmd.setTopN(1); // 只查询Top1 + queryCmd.setReqSysOrigin(cmd.getReqSysOrigin()); + queryCmd.setIncludeCurrentUser(false); // 不需要查询当前用户排名 + + try { + var rankingList = rankingListQryExe.execute(queryCmd); + + // 如果有数据,添加到结果中 + if (Objects.nonNull(rankingList) && + Objects.nonNull(rankingList.getRankingList()) && + !rankingList.getRankingList().isEmpty()) { + + HistoricalWeekTop1CO weekTop1 = new HistoricalWeekTop1CO(); + weekTop1.setCycleKey(cycleKey); + weekTop1.setCycleDisplay(generateCycleDisplay(cycleKey)); + weekTop1.setTopUser(rankingList.getRankingList().get(0)); + historicalList.add(weekTop1); + } + } catch (Exception e) { + log.warn("查询历史Top1失败, cycleKey={}", cycleKey, e); + } + } + + result.setHistoricalList(historicalList); + return result; + } + + /** + * 获取往前推N周的周一cycleKey + * + * @param weeksAgo 往前推的周数(0表示本周) + * @return cycleKey(格式:yyyyMMdd) + */ + private String getWeekMondayCycleKey(int weeksAgo) { + // 使用亚洲/利雅得时区 + ZoneId riyadhZone = ZoneId.of("Asia/Riyadh"); + ZonedDateTime now = ZonedDateTime.now(riyadhZone); + + // 获取本周周一 + LocalDate monday = now.toLocalDate().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); + + // 往前推N周 + if (weeksAgo > 0) { + monday = monday.minusWeeks(weeksAgo); + } + + // 格式化为yyyyMMdd + return monday.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } + + /** + * 生成周期显示文本 + * + * @param cycleKey 周期标识(yyyyMMdd格式) + * @return 周期显示文本(示例:2025年第1周) + */ + private String generateCycleDisplay(String cycleKey) { + try { + LocalDate date = LocalDate.parse(cycleKey, DateTimeFormatter.ofPattern("yyyyMMdd")); + int year = date.getYear(); + + // 获取周数(ISO 8601标准) + WeekFields weekFields = WeekFields.of(Locale.getDefault()); + int weekOfYear = date.get(weekFields.weekOfWeekBasedYear()); + + return String.format("%d年第%d周", year, weekOfYear); + } catch (Exception e) { + log.warn("生成周期显示文本失败, cycleKey={}", cycleKey, e); + return cycleKey; + } + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/RankingListQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/RankingListQryExe.java index 3c72a946..08e9fdb9 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/RankingListQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/query/RankingListQryExe.java @@ -50,9 +50,9 @@ public class RankingListQryExe { // 查询排行榜列表 List records = rankingActivityGateway.getRankingList( cmd.getReqSysOrigin().getOrigin(), - activityType, + activityType, cycleType, - ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt().toString(), + cmd.getCycleKey(), null, cmd.getTopN() ); diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java index 76e99b91..eea363c2 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java @@ -1,11 +1,14 @@ package com.red.circle.other.app.service.activity; +import com.red.circle.other.app.command.activity.query.HistoricalTop1QryExe; import com.red.circle.other.app.command.activity.query.RankingDataAccumulateCmdExe; import com.red.circle.other.app.command.activity.query.RankingListQryExe; import com.red.circle.other.app.command.activity.query.UserRankQryExe; +import com.red.circle.other.app.dto.clientobject.activity.HistoricalTop1ListCO; import com.red.circle.other.app.dto.clientobject.activity.RankingListCO; import com.red.circle.other.app.dto.clientobject.activity.UserRankInfoCO; import com.red.circle.other.app.dto.cmd.UserRankQueryCmd; +import com.red.circle.other.app.dto.cmd.activity.HistoricalTop1QueryCmd; import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd; import com.red.circle.other.app.dto.cmd.activity.RankingListQueryCmd; import lombok.RequiredArgsConstructor; @@ -24,6 +27,7 @@ public class RankingActivityServiceImpl implements RankingActivityService { private final RankingDataAccumulateCmdExe rankingDataAccumulateCmdExe; private final RankingListQryExe rankingListQryExe; private final UserRankQryExe userRankQryExe; + private final HistoricalTop1QryExe historicalTop1QryExe; @Override public Boolean accumulateRankingData(RankingDataUpdateCmd cmd) { @@ -39,4 +43,9 @@ public class RankingActivityServiceImpl implements RankingActivityService { public UserRankInfoCO getUserRank(UserRankQueryCmd cmd) { return userRankQryExe.execute(cmd); } + + @Override + public HistoricalTop1ListCO getHistoricalTop1List(HistoricalTop1QueryCmd cmd) { + return historicalTop1QryExe.execute(cmd); + } } \ No newline at end of file diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalTop1ListCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalTop1ListCO.java new file mode 100644 index 00000000..6f200471 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalTop1ListCO.java @@ -0,0 +1,30 @@ +package com.red.circle.other.app.dto.clientobject.activity; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 历史Top1列表 CO + */ +@Data +public class HistoricalTop1ListCO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 活动类型编码 + */ + private Integer activityType; + + /** + * 活动类型名称 + */ + private String activityTypeName; + + /** + * 历史周榜Top1列表(最近10周) + */ + private List historicalList; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalWeekTop1CO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalWeekTop1CO.java new file mode 100644 index 00000000..3eed2c38 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/HistoricalWeekTop1CO.java @@ -0,0 +1,29 @@ +package com.red.circle.other.app.dto.clientobject.activity; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 历史周榜Top1记录 CO + */ +@Data +public class HistoricalWeekTop1CO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 周期标识(格式:yyyyMMdd,周一日期) + */ + private String cycleKey; + + /** + * 周期显示文本(示例:2025年第1周) + */ + private String cycleDisplay; + + /** + * Top1用户信息 + */ + private RankingActivityRecordCO topUser; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/HistoricalTop1QueryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/HistoricalTop1QueryCmd.java new file mode 100644 index 00000000..6f4aea60 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/HistoricalTop1QueryCmd.java @@ -0,0 +1,29 @@ +package com.red.circle.other.app.dto.cmd.activity; + +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 历史Top1查询命令 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class HistoricalTop1QueryCmd extends AppExtCommand { + + /** + * 活动类型 + * + * RankingActivityType + */ + @NotNull(message = "活动类型不能为空") + private Integer activityType; + + /** + * 用户性别筛选 + * + * 0-女, 1-男, null-全部 + */ + private Integer userSex; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java index 8c9f8731..92383017 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java @@ -1,8 +1,10 @@ package com.red.circle.other.app.service.activity; +import com.red.circle.other.app.dto.clientobject.activity.HistoricalTop1ListCO; import com.red.circle.other.app.dto.clientobject.activity.RankingListCO; import com.red.circle.other.app.dto.clientobject.activity.UserRankInfoCO; import com.red.circle.other.app.dto.cmd.UserRankQueryCmd; +import com.red.circle.other.app.dto.cmd.activity.HistoricalTop1QueryCmd; import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd; import com.red.circle.other.app.dto.cmd.activity.RankingListQueryCmd; @@ -34,4 +36,12 @@ public interface RankingActivityService { * @return 用户排名信息 */ UserRankInfoCO getUserRank(UserRankQueryCmd cmd); + + /** + * 查询历史Top1列表(周榜) + * + * @param cmd 查询命令 + * @return 历史Top1列表(最近10周) + */ + HistoricalTop1ListCO getHistoricalTop1List(HistoricalTop1QueryCmd cmd); } \ No newline at end of file diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/PropCouponGatewayImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/PropCouponGatewayImpl.java index fefc024f..7e9f365f 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/PropCouponGatewayImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/PropCouponGatewayImpl.java @@ -85,7 +85,7 @@ public class PropCouponGatewayImpl implements PropCouponGateway { if (status != null) { wrapper.eq(PropCouponDO::getStatus, status.getCode()); } - wrapper.lt(PropCouponDO::getExpireTime, LocalDateTime.now()); + wrapper.gt(PropCouponDO::getExpireTime, LocalDateTime.now()); wrapper.orderByDesc(PropCouponDO::getCreateTime); Page page = new Page<>(pageNo, pageSize);