diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java index 221f5a61..b3ebe60d 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java @@ -10,10 +10,12 @@ import com.red.circle.other.app.dto.clientobject.activity.LotteryMultiDrawResult import com.red.circle.other.app.dto.clientobject.activity.LotteryRankCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryRecordCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO; +import com.red.circle.other.app.dto.clientobject.activity.LotteryWinnerHistoryCO; import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryMultiDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRankQryCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd; +import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd; import com.red.circle.other.app.service.activity.LotteryActivityRestService; import java.util.List; @@ -165,4 +167,17 @@ public class LotteryActivityRestController extends BaseController { return lotteryActivityRestService.getRankList(cmd); } + /** + * 查询历史中奖记录用户(滚动展示). + * + * @eo.name 查询历史中奖记录用户. + * @eo.url /winner-history + * @eo.method get + * @eo.request-type formdata + */ + @GetMapping("/winner-history") + public List getWinnerHistory(LotteryWinnerHistoryQryCmd cmd) { + return lotteryActivityRestService.getWinnerHistory(cmd); + } + } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWinnerHistoryQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWinnerHistoryQryExe.java new file mode 100644 index 00000000..c4ef241b --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWinnerHistoryQryExe.java @@ -0,0 +1,212 @@ +package com.red.circle.other.app.command.activity; + +import com.red.circle.other.app.dto.clientobject.activity.LotteryWinnerHistoryCO; +import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd; +import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity; +import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize; +import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord; +import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService; +import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService; +import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService; +import com.red.circle.other.inner.endpoint.user.user.UserProfileClient; +import com.red.circle.other.inner.model.dto.user.UserProfileDTO; +import com.red.circle.tool.core.text.StringUtils; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 查询历史中奖记录用户(用于滚动展示). + * + * @author system + * @since 2025-10-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class LotteryWinnerHistoryQryExe { + + private final LotteryRecordService lotteryRecordService; + private final LotteryPrizeService lotteryPrizeService; + private final LotteryActivityService lotteryActivityService; + private final UserProfileClient userProfileClient; + + public List execute(LotteryWinnerHistoryQryCmd cmd) { + // 1. 查询中奖记录 + List records = queryWinRecords(cmd); + + if (records.isEmpty()) { + return new ArrayList<>(); + } + + // 2. 获取用户信息 + List userIds = records.stream() + .map(LotteryRecord::getUserId) + .distinct() + .collect(Collectors.toList()); + + Map userMap = getUserProfiles(userIds); + + // 3. 获取奖品信息 + List prizeIds = records.stream() + .map(LotteryRecord::getPrizeId) + .distinct() + .collect(Collectors.toList()); + + Map prizeMap = getPrizes(prizeIds); + + // 4. 获取活动信息 + List activityIds = records.stream() + .map(LotteryRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); + + Map activityMap = getActivities(activityIds); + + // 5. 组装结果 + List result = new ArrayList<>(); + + for (LotteryRecord record : records) { + UserProfileDTO user = userMap.get(record.getUserId()); + LotteryPrize prize = prizeMap.get(record.getPrizeId()); + LotteryActivity activity = activityMap.get(record.getActivityId()); + + if (user == null || prize == null) { + continue; + } + + LotteryWinnerHistoryCO historyCO = new LotteryWinnerHistoryCO(); + historyCO.setUserId(record.getUserId()); + historyCO.setNickname(maskNickname(user.getUserNickname())); + historyCO.setAvatar(user.getUserAvatar()); + historyCO.setPrizeName(prize.getPrizeName()); + historyCO.setPrizeType(prize.getPrizeType()); + historyCO.setPrizeValue(prize.getPrizeValue()); + historyCO.setPrizeIcon(prize.getPrizeImage()); + historyCO.setDrawTime(record.getDrawTime()); + historyCO.setActivityName(activity != null ? activity.getActivityName() : ""); + + result.add(historyCO); + } + + return result; + } + + /** + * 查询中奖记录. + */ + private List queryWinRecords(LotteryWinnerHistoryQryCmd cmd) { + var query = lotteryRecordService.query() + .eq(LotteryRecord::getIsWin, 1) + .isNotNull(LotteryRecord::getPrizeId) + .orderByDesc(LotteryRecord::getDrawTime); + + // 如果指定了活动ID + if (cmd.getActivityId() != null) { + query.eq(LotteryRecord::getActivityId, cmd.getActivityId()); + } + + // 如果指定了最小奖品价值,需要关联查询 + if (StringUtils.isNotBlank(cmd.getMinPrizeValue())) { + BigDecimal minValue = new BigDecimal(cmd.getMinPrizeValue()); + List prizeIds = lotteryPrizeService.query() + .ge(LotteryPrize::getPrizeValue, minValue) + .list() + .stream() + .map(LotteryPrize::getId) + .collect(Collectors.toList()); + + if (!prizeIds.isEmpty()) { + query.in(LotteryRecord::getPrizeId, prizeIds); + } else { + return new ArrayList<>(); + } + } + + // 限制数量 + Integer limit = cmd.getLimit() != null ? cmd.getLimit() : 50; + query.last("LIMIT " + limit); + + return query.list(); + } + + /** + * 获取用户信息. + */ + private Map getUserProfiles(List userIds) { + try { + List users = userProfileClient.listByUserId(new HashSet<>(userIds)).getBody(); + if (users != null) { + return users.stream() + .collect(Collectors.toMap(UserProfileDTO::getId, user -> user, (a, b) -> a)); + } + } catch (Exception e) { + log.error("Failed to get user profiles", e); + } + return Map.of(); + } + + /** + * 获取奖品信息. + */ + private Map getPrizes(List prizeIds) { + if (prizeIds.isEmpty()) { + return Map.of(); + } + + List prizes = lotteryPrizeService.query() + .in(LotteryPrize::getId, prizeIds) + .list(); + + return prizes.stream() + .collect(Collectors.toMap(LotteryPrize::getId, prize -> prize, (a, b) -> a)); + } + + /** + * 获取活动信息. + */ + private Map getActivities(List activityIds) { + if (activityIds.isEmpty()) { + return Map.of(); + } + + List activities = lotteryActivityService.query() + .in(LotteryActivity::getId, activityIds) + .list(); + + return activities.stream() + .collect(Collectors.toMap(LotteryActivity::getId, activity -> activity, (a, b) -> a)); + } + + /** + * 脱敏昵称(保护隐私). + */ + private String maskNickname(String nickname) { + if (StringUtils.isBlank(nickname)) { + return "匿名用户"; + } + + if (nickname.length() <= 2) { + return nickname.charAt(0) + "*"; + } + + // 保留首尾字符,中间用*代替 + int len = nickname.length(); + StringBuilder masked = new StringBuilder(); + masked.append(nickname.charAt(0)); + + for (int i = 1; i < len - 1; i++) { + masked.append('*'); + } + + masked.append(nickname.charAt(len - 1)); + return masked.toString(); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java index b4f029a0..55fe5066 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java @@ -10,6 +10,7 @@ import com.red.circle.other.app.command.activity.LotteryRankQryExe; import com.red.circle.other.app.command.activity.LotteryRecordQryExe; import com.red.circle.other.app.command.activity.LotteryTicketCountQryExe; import com.red.circle.other.app.command.activity.LotteryTicketQryExe; +import com.red.circle.other.app.command.activity.LotteryWinnerHistoryQryExe; import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityDetailCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO; @@ -17,10 +18,12 @@ import com.red.circle.other.app.dto.clientobject.activity.LotteryMultiDrawResult import com.red.circle.other.app.dto.clientobject.activity.LotteryRankCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryRecordCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO; +import com.red.circle.other.app.dto.clientobject.activity.LotteryWinnerHistoryCO; import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryMultiDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRankQryCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd; +import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -43,6 +46,7 @@ public class LotteryActivityRestServiceImpl implements LotteryActivityRestServic private final LotteryTicketQryExe lotteryTicketQryExe; private final LotteryTicketCountQryExe lotteryTicketCountQryExe; private final LotteryRankQryExe lotteryRankQryExe; + private final LotteryWinnerHistoryQryExe lotteryWinnerHistoryQryExe; @Override public List listValidActivities(AppExtCommand cmd) { @@ -84,4 +88,9 @@ public class LotteryActivityRestServiceImpl implements LotteryActivityRestServic return lotteryRankQryExe.execute(cmd); } + @Override + public List getWinnerHistory(LotteryWinnerHistoryQryCmd cmd) { + return lotteryWinnerHistoryQryExe.execute(cmd); + } + } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryWinnerHistoryCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryWinnerHistoryCO.java new file mode 100644 index 00000000..caae9345 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryWinnerHistoryCO.java @@ -0,0 +1,66 @@ +package com.red.circle.other.app.dto.clientobject.activity; + +import com.red.circle.framework.dto.ClientObject; +import java.math.BigDecimal; +import java.sql.Timestamp; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 历史中奖记录用户CO(滚动展示用). + * + * @author system + * @since 2025-10-21 + */ +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class LotteryWinnerHistoryCO extends ClientObject { + + /** + * 用户ID. + */ + private Long userId; + + /** + * 用户昵称. + */ + private String nickname; + + /** + * 用户头像. + */ + private String avatar; + + /** + * 奖品名称. + */ + private String prizeName; + + /** + * 奖品类型. + */ + private String prizeType; + + /** + * 奖品价值. + */ + private BigDecimal prizeValue; + + /** + * 奖品图标. + */ + private String prizeIcon; + + /** + * 中奖时间. + */ + private Timestamp drawTime; + + /** + * 活动名称. + */ + private String activityName; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWinnerHistoryQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWinnerHistoryQryCmd.java new file mode 100644 index 00000000..ce2183d2 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWinnerHistoryQryCmd.java @@ -0,0 +1,34 @@ +package com.red.circle.other.app.dto.cmd.activity; + +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 历史中奖记录查询CMD. + * + * @author system + * @since 2025-10-21 + */ +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class LotteryWinnerHistoryQryCmd extends AppExtCommand { + + /** + * 活动ID(可选,不传则查询所有活动). + */ + private Long activityId; + + /** + * 查询数量(默认50,用于滚动展示). + */ + private Integer limit = 50; + + /** + * 最小奖品价值(可选,只展示大奖). + */ + private String minPrizeValue; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java index 1b6bb4ae..2e52c0a4 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java @@ -9,10 +9,12 @@ import com.red.circle.other.app.dto.clientobject.activity.LotteryMultiDrawResult import com.red.circle.other.app.dto.clientobject.activity.LotteryRankCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryRecordCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO; +import com.red.circle.other.app.dto.clientobject.activity.LotteryWinnerHistoryCO; import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryMultiDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRankQryCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd; +import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd; import java.util.List; /** @@ -63,4 +65,9 @@ public interface LotteryActivityRestService { */ List getRankList(LotteryRankQryCmd cmd); + /** + * 查询历史中奖记录用户. + */ + List getWinnerHistory(LotteryWinnerHistoryQryCmd cmd); + }