diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/ActivityErrorCode.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/ActivityErrorCode.java index f90140e0..cb32f103 100644 --- a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/ActivityErrorCode.java +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/ActivityErrorCode.java @@ -53,12 +53,14 @@ public enum ActivityErrorCode implements IResponseErrorCode { /** * 在无效的时间段内操作. */ - INVALID_TIME_OPERATION_ERROR(9507, "Please operate within the specified time period"); - /** - * 活动房间未配置. - */ + INVALID_TIME_OPERATION_ERROR(9507, "Please operate within the specified time period"), + AWARD_RECEIVED(9508, "The reward has been received, please do not receive it again"), + + + ; + private final Integer code; private final String message; diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/room/RoomContributionActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/room/RoomContributionActivityRestController.java index eaae1bb6..a2803cf8 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/room/RoomContributionActivityRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/room/RoomContributionActivityRestController.java @@ -3,11 +3,16 @@ package com.red.circle.other.adapter.app.activity.room; import com.red.circle.common.business.dto.cmd.app.AppRoomIdCmd; import com.red.circle.framework.web.controller.BaseController; import com.red.circle.other.app.dto.clientobject.activity.RoomContributionCountCO; +import com.red.circle.other.app.dto.clientobject.activity.room.RoomRewardInfoCO; +import com.red.circle.other.app.dto.cmd.activity.room.ReceiveRoomRewardCmd; import com.red.circle.other.app.service.activity.RoomContributionActivityService; +import com.red.circle.other.app.service.activity.RoomRewardService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -26,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController; public class RoomContributionActivityRestController extends BaseController { private final RoomContributionActivityService roomContributionActivityService; + private final RoomRewardService roomRewardService; /** * 数据. @@ -40,16 +46,44 @@ public class RoomContributionActivityRestController extends BaseController { } /** - * 领取奖励. + * 领取奖励(已废弃,请使用 /room-reward/receive). * - * @eo.name 领取奖励 + * @deprecated 请使用新接口 /room-reward/receive + * @eo.name 领取奖励(已废弃) * @eo.url /receive * @eo.method post * @eo.request-type json */ + @Deprecated @PostMapping("/receive") public void receive(AppRoomIdCmd cmd) { roomContributionActivityService.receive(cmd); } + /** + * 查询房间奖励信息. + * + * @eo.name 查询房间奖励信息 + * @eo.url /room-reward/info + * @eo.method get + * @eo.request-type formdata + */ + @GetMapping("/room-reward/info") + public RoomRewardInfoCO getRoomRewardInfo(@RequestParam String roomId) { + return roomRewardService.getRoomRewardInfo(roomId); + } + + /** + * 领取房间奖励房主收入. + * + * @eo.name 领取房主收入 + * @eo.url /room-reward/receive + * @eo.method post + * @eo.request-type json + */ + @PostMapping("/room-reward/receive") + public void receiveRoomReward(@RequestBody ReceiveRoomRewardCmd cmd) { + roomRewardService.receiveOwnerIncome(cmd); + } + } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/RoomContributionActivityReceiveAwardCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/RoomContributionActivityReceiveAwardCmdExe.java index 560dcaf3..f997927f 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/RoomContributionActivityReceiveAwardCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/RoomContributionActivityReceiveAwardCmdExe.java @@ -50,11 +50,6 @@ public class RoomContributionActivityReceiveAwardCmdExe { private final RoomContributionActivityCountService roomContributionActivityCountService; public void execute(AppExtCommand cmd) { - - ResponseAssert.isTrue(ActivityErrorCode.INVALID_TIME_OPERATION_ERROR, - Objects.equals(ZonedDateTimeAsiaRiyadhUtils.getThisMonday(), - ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())); - // 防止重复触发领取 3分钟后可重试领取 ResponseAssert.isTrue(UserErrorCode.AWARD_RECEIVED, redisService.setIfAbsent( GoldOrigin.ROOM_CONTRIBUTION_REWARD + ":" + cmd.getReqUserId(), @@ -158,33 +153,6 @@ public class RoomContributionActivityReceiveAwardCmdExe { String userRegionCode = userRegionGateway.getRegionCode(cmd.getReqUserId()); -// if (isExistsRegion(List.of("NG1", "NG", "PH", "PH1"), userRegionCode)) { -// -// var historyIntegral = activityCounts.stream() -// .filter(activityCount -> activityCount.getDateNumber() < 20230501) -// .map(count -> ImmutablePair.of(count.getId(), count.getContributionValue())) -// .toList(); -// -// if (CollectionUtils.isNotEmpty(historyIntegral)) { -// resultProps.put("history", roomContributionActivityCountService -// .listAvailableAmount(cmd.requireReqSysOriginEnum(),userRegionCode, historyIntegral, -// new BigDecimal("0.1"))); -// } -// -// var newIntegral = activityCounts.stream() -// .filter(activityCount -> activityCount.getDateNumber() >= 20230501) -// .map(count -> ImmutablePair.of(count.getId(), count.getContributionValue())) -// .toList(); -// -// if (CollectionUtils.isNotEmpty(newIntegral)) { -// resultProps.put("notHistory", -// roomContributionActivityCountService -// .listAvailableAmount(cmd.requireReqSysOriginEnum(),userRegionCode, newIntegral, ratio)); -// } -// -// return resultProps; -// } - resultProps.put("notHistory", roomContributionActivityCountService .listAvailableAmount(cmd.requireReqSysOriginEnum(),userRegionCode, diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/ReceiveRoomRewardCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/ReceiveRoomRewardCmdExe.java new file mode 100644 index 00000000..8e758365 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/ReceiveRoomRewardCmdExe.java @@ -0,0 +1,105 @@ +package com.red.circle.other.app.command.activity.room; + +import com.red.circle.component.redis.service.RedisService; +import com.red.circle.framework.core.asserts.ResponseAssert; +import com.red.circle.framework.core.response.CommonErrorCode; +import com.red.circle.other.app.dto.cmd.activity.room.ReceiveRoomRewardCmd; +import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount; +import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService; +import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; +import com.red.circle.other.inner.asserts.ActivityErrorCode; +import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; +import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient; +import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd; +import com.red.circle.wallet.inner.model.enums.GoldOrigin; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +/** + * 领取房间奖励房主收入执行器 + * + * @author system + * @date 2025-12-01 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class ReceiveRoomRewardCmdExe { + + private final WalletGoldClient walletGoldClient; + private final RoomProfileManagerService roomProfileManagerService; + private final RoomContributionActivityCountService roomContributionActivityCountService; + private final MongoTemplate mongoTemplate; + + @Transactional(rollbackFor = Exception.class) + public void execute(ReceiveRoomRewardCmd cmd) { + Long userId = cmd.getReqUserId(); + String roomId = cmd.getRoomId(); + + // 2. 校验用户是否是房主 + Long userRoomId = roomProfileManagerService.getRoomId(userId); + ResponseAssert.isTrue( + CommonErrorCode.DATA_ERROR, + Objects.equals(userRoomId, Long.parseLong(roomId)) + ); + + // 3. 查询上周数据 + String lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getLastWeekMonday().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + RoomContributionActivityCount lastWeekData = roomContributionActivityCountService + .findByRoomIdAndDateNumber(Long.parseLong(roomId), Integer.valueOf(lastWeekDateNumber)) + .orElse(null); + + ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, lastWeekData); + + // 4. 校验是否已领取 + ResponseAssert.isFalse(ActivityErrorCode.AWARD_RECEIVED, + Optional.ofNullable(lastWeekData.getReceived()).orElse(false)); + + // 5. 计算房主收入(流水 * ratio) + BigDecimal contributionValue = lastWeekData.getContributionValue(); + ResponseAssert.notNull(CommonErrorCode.DATA_ERROR, contributionValue); + + BigDecimal ratio = Optional.ofNullable(lastWeekData.getRatio()).orElse(new BigDecimal("0.05")); + + BigDecimal ownerIncome = contributionValue.multiply(ratio); + + ResponseAssert.isTrue( + CommonErrorCode.DATA_ERROR, + ownerIncome.compareTo(BigDecimal.ZERO) > 0 + ); + + // 6. 调用钱包服务增加金币 + walletGoldClient.changeBalance(GoldReceiptCmd.builder() + .appIncome() + .eventId(Long.parseLong(roomId)) + .userId(userId) + .sysOrigin(cmd.getReqSysOrigin().getOrigin()) + .origin(GoldOrigin.ROOM_CONTRIBUTION_REWARD) + .amount(ownerIncome) + .build()); + + // 7. 更新received状态为true + Query query = new Query(Criteria.where("_id").is(lastWeekData.getId())); + Update update = new Update().set("received", true); + mongoTemplate.updateFirst(query, update, RoomContributionActivityCount.class); + + log.info("房间奖励领取成功, userId={}, roomId={}, dateNumber={}, income={}", + userId, roomId, lastWeekDateNumber, ownerIncome); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/query/RoomRewardInfoQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/query/RoomRewardInfoQryExe.java new file mode 100644 index 00000000..88aaf413 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/room/query/RoomRewardInfoQryExe.java @@ -0,0 +1,138 @@ +package com.red.circle.other.app.command.activity.room.query; + +import com.red.circle.other.app.dto.clientobject.activity.room.RoomRewardInfoCO; +import com.red.circle.other.app.enums.RoomRewardLevelEnum; +import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount; +import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService; +import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Optional; + +/** + * 房间奖励信息查询执行器 + * + * @author system + * @date 2025-12-01 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class RoomRewardInfoQryExe { + + private final RoomContributionActivityCountService roomContributionActivityCountService; + + public RoomRewardInfoCO execute(String roomId) { + RoomRewardInfoCO result = new RoomRewardInfoCO(); + + // 1. 计算倒计时 + result.setCountdown(calculateCountdown()); + + // 2. 查询当前周数据 + Integer currentWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getThisMonday(); + RoomContributionActivityCount currentWeek = findByRoomIdAndDateNumber(roomId, currentWeekDateNumber); + result.setCurrentProgress(buildCurrentProgress(currentWeek)); + + // 3. 查询上周数据 + String lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getLastWeekMonday().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + RoomContributionActivityCount lastWeek = findByRoomIdAndDateNumber(roomId, Integer.parseInt(lastWeekDateNumber)); + result.setLastWeekProgress(buildLastWeekProgress(lastWeek)); + + return result; + } + + /** + * 计算到下周一沙特时间0点的倒计时 + */ + private RoomRewardInfoCO.CountdownCO calculateCountdown() { + ZonedDateTime now = ZonedDateTimeAsiaRiyadhUtils.now(); + ZonedDateTime nextMondayZoned = now.plusDays(7 - (now.getDayOfWeek().getValue() - 1)); + + Duration duration = Duration.between(now, nextMondayZoned); + RoomRewardInfoCO.CountdownCO countdown = new RoomRewardInfoCO.CountdownCO(); + countdown.setDays(duration.toDays()); + countdown.setHours(duration.toHours()); + countdown.setMinutes(duration.toMinutes()); + countdown.setSeconds(duration.getSeconds()); + + return countdown; + } + + /** + * 根据房间ID和日期查询数据 + */ + private RoomContributionActivityCount findByRoomIdAndDateNumber(String roomId, Integer dateNumber) { + Long roomIdLong = Long.parseLong(roomId); + return roomContributionActivityCountService + .findByRoomIdAndDateNumber(roomIdLong, dateNumber) + .orElse(null); + } + + /** + * 构建当前周进度 + */ + private RoomRewardInfoCO.CurrentProgressCO buildCurrentProgress(RoomContributionActivityCount data) { + RoomRewardInfoCO.CurrentProgressCO progress = new RoomRewardInfoCO.CurrentProgressCO(); + + if (data == null || data.getContributionValue() == null) { + progress.setAmount(0L); + progress.setLevel(null); + return progress; + } + + Long amount = data.getContributionValue().longValue(); + progress.setAmount(amount); + + RoomRewardLevelEnum level = RoomRewardLevelEnum.getLevelByAmount(amount); + progress.setLevel(level != null ? level.getLevel() : null); + + return progress; + } + + /** + * 构建上周进度 + */ + private RoomRewardInfoCO.LastWeekProgressCO buildLastWeekProgress(RoomContributionActivityCount data) { + RoomRewardInfoCO.LastWeekProgressCO progress = new RoomRewardInfoCO.LastWeekProgressCO(); + + if (data == null || data.getContributionValue() == null) { + progress.setAmount(0L); + progress.setLevel(null); + progress.setOwnerIncome(0L); + progress.setOwnerIncomeReceived(false); + progress.setRewardCoins(0L); + progress.setRewardCoinsSent(false); + return progress; + } + + Long amount = data.getContributionValue().longValue(); + progress.setAmount(amount); + + // 计算等级 + RoomRewardLevelEnum level = RoomRewardLevelEnum.getLevelByAmount(amount); + progress.setLevel(level != null ? level.getLevel() : null); + + // 计算房主收入(流水 * ratio) + BigDecimal ratio = Optional.ofNullable(data.getRatio()).orElse(new BigDecimal("0.05")); + Long ownerIncome = data.getContributionValue().multiply(ratio).longValue(); + progress.setOwnerIncome(ownerIncome); + + // 是否已领取 + progress.setOwnerIncomeReceived(Optional.ofNullable(data.getReceived()).orElse(false)); + + // 奖励金币 + Long rewardCoins = level != null ? level.getRewardCoins() : 0L; + progress.setRewardCoins(rewardCoins); + + // 奖励金币是否已发放 + progress.setRewardCoinsSent(Optional.ofNullable(data.getRewardCoinsSent()).orElse(false)); + + return progress; + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RoomRewardServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RoomRewardServiceImpl.java index 2983ae4e..561d10ff 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RoomRewardServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RoomRewardServiceImpl.java @@ -4,7 +4,12 @@ import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd; import com.red.circle.common.business.dto.cmd.app.AppRoomIdCmd; import com.red.circle.other.app.command.activity.RoomRewardReceiveCmdExe; import com.red.circle.other.app.command.activity.RoomRewardReceiveQueryExe; +import com.red.circle.other.app.command.activity.room.ReceiveRoomRewardCmdExe; +import com.red.circle.other.app.command.activity.room.query.RoomRewardInfoQryExe; import com.red.circle.other.app.dto.clientobject.activity.RoomRewardActivityCO; +import com.red.circle.other.app.dto.clientobject.activity.room.RoomRewardInfoCO; +import com.red.circle.other.app.dto.cmd.activity.room.ReceiveRoomRewardCmd; +import com.red.circle.other.app.util.DistributedLockUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -19,6 +24,10 @@ public class RoomRewardServiceImpl implements RoomRewardService { private final RoomRewardReceiveCmdExe roomRewardReceiveCmdExe; private final RoomRewardReceiveQueryExe roomRewardReceiveQueryExe; + private final RoomRewardInfoQryExe roomRewardInfoQryExe; + private final ReceiveRoomRewardCmdExe receiveRoomRewardCmdExe; + private final DistributedLockUtil distributedLockUtil; + private static final String REDIS_KEY_PREFIX = "room:reward:receive:"; @Override public RoomRewardActivityCO getReward(AppRoomIdCmd cmd) { @@ -30,4 +39,18 @@ public class RoomRewardServiceImpl implements RoomRewardService { roomRewardReceiveCmdExe.execute(cmd); } + + @Override + public RoomRewardInfoCO getRoomRewardInfo(String roomId) { + return roomRewardInfoQryExe.execute(roomId); + } + + @Override + public void receiveOwnerIncome(ReceiveRoomRewardCmd cmd) { + String key = REDIS_KEY_PREFIX + cmd.getRoomId(); + distributedLockUtil.executeWithLock(key, () -> { + receiveRoomRewardCmdExe.execute(cmd); + }); + } + } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/DistributedLockUtil.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/DistributedLockUtil.java index 3a74b808..720db079 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/DistributedLockUtil.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/DistributedLockUtil.java @@ -27,6 +27,16 @@ public class DistributedLockUtil { */ private static final long DEFAULT_LOCK_EXPIRE_TIME = 10; + /** + * 使用分布式锁执行业务逻辑(无返回值) + * + * @param lockKey 锁的key + * @param runnable 业务逻辑 + */ + public void executeWithLock(String lockKey, Runnable runnable) { + executeWithLock(lockKey, DEFAULT_LOCK_EXPIRE_TIME, runnable, "The request is too frequent. Please try again later"); + } + /** * 使用分布式锁执行业务逻辑(无返回值) * diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/room/RoomRewardInfoCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/room/RoomRewardInfoCO.java new file mode 100644 index 00000000..b1ecc310 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/room/RoomRewardInfoCO.java @@ -0,0 +1,106 @@ +package com.red.circle.other.app.dto.clientobject.activity.room; + +import lombok.Data; + +/** + * 房间奖励信息 + * + * @author system + * @date 2025-12-01 + */ +@Data +public class RoomRewardInfoCO { + + /** + * 倒计时信息 + */ + private CountdownCO countdown; + + /** + * 当前周进度 + */ + private CurrentProgressCO currentProgress; + + /** + * 上周进度 + */ + private LastWeekProgressCO lastWeekProgress; + + /** + * 倒计时对象 + */ + @Data + public static class CountdownCO { + /** + * 剩余天数 + */ + private Long days; + + /** + * 剩余小时 + */ + private Long hours; + + /** + * 剩余分钟 + */ + private Long minutes; + + /** + * 剩余秒数 + */ + private Long seconds; + } + + /** + * 当前周进度 + */ + @Data + public static class CurrentProgressCO { + /** + * 当前流水金额 + */ + private Long amount; + + /** + * 当前等级 (1-4) + */ + private Integer level; + } + + /** + * 上周进度 + */ + @Data + public static class LastWeekProgressCO { + /** + * 上周流水金额 + */ + private Long amount; + + /** + * 上周等级 (1-4) + */ + private Integer level; + + /** + * 房主收入金币数(流水的5%) + */ + private Long ownerIncome; + + /** + * 房主收入是否已领取 + */ + private Boolean ownerIncomeReceived; + + /** + * 奖励金币数量 + */ + private Long rewardCoins; + + /** + * 奖励金币是否已发放 + */ + private Boolean rewardCoinsSent; + } +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/room/ReceiveRoomRewardCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/room/ReceiveRoomRewardCmd.java new file mode 100644 index 00000000..c9db5ce7 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/room/ReceiveRoomRewardCmd.java @@ -0,0 +1,23 @@ +package com.red.circle.other.app.dto.cmd.activity.room; + +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 领取房间奖励房主收入命令 + * + * @author system + * @date 2025-12-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ReceiveRoomRewardCmd extends AppExtCommand { + + /** + * 房间ID + */ + @NotBlank(message = "房间ID不能为空") + private String roomId; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/enums/RoomRewardLevelEnum.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/enums/RoomRewardLevelEnum.java new file mode 100644 index 00000000..a8bbaa01 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/enums/RoomRewardLevelEnum.java @@ -0,0 +1,91 @@ +package com.red.circle.other.app.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 房间奖励等级枚举 + * + * @author system + * @date 2025-12-01 + */ +@Getter +@AllArgsConstructor +public enum RoomRewardLevelEnum { + + /** + * Lv.1: 100,000 - 499,999,奖励2,000金币 + */ + LEVEL_1(1, 100000L, 500000L, 2000L), + + /** + * Lv.2: 500,000 - 1,999,999,奖励15,000金币 + */ + LEVEL_2(2, 500000L, 2000000L, 15000L), + + /** + * Lv.3: 2,000,000 - 4,999,999,奖励80,000金币 + */ + LEVEL_3(3, 2000000L, 5000000L, 80000L), + + /** + * Lv.4: 5,000,000+,奖励250,000金币 + */ + LEVEL_4(4, 5000000L, Long.MAX_VALUE, 250000L); + + /** + * 等级 + */ + private final Integer level; + + /** + * 最小流水金额(包含) + */ + private final Long minAmount; + + /** + * 最大流水金额(不包含) + */ + private final Long maxAmount; + + /** + * 奖励金币数量 + */ + private final Long rewardCoins; + + /** + * 根据流水金额获取等级 + * + * @param amount 流水金额 + * @return 等级枚举,如果未达到最低要求则返回null + */ + public static RoomRewardLevelEnum getLevelByAmount(Long amount) { + if (amount == null || amount < LEVEL_1.minAmount) { + return null; + } + + return Arrays.stream(values()) + .filter(level -> amount >= level.minAmount && amount < level.maxAmount) + .findFirst() + .orElse(null); + } + + /** + * 根据等级数字获取枚举 + * + * @param level 等级数字 + * @return 等级枚举 + */ + public static RoomRewardLevelEnum getByLevel(Integer level) { + if (level == null) { + return null; + } + + return Arrays.stream(values()) + .filter(e -> e.level.equals(level)) + .findFirst() + .orElse(null); + } +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RoomRewardService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RoomRewardService.java index 33df3a64..12080f00 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RoomRewardService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RoomRewardService.java @@ -4,6 +4,8 @@ package com.red.circle.other.app.service.activity; import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd; import com.red.circle.common.business.dto.cmd.app.AppRoomIdCmd; import com.red.circle.other.app.dto.clientobject.activity.RoomRewardActivityCO; +import com.red.circle.other.app.dto.clientobject.activity.room.RoomRewardInfoCO; +import com.red.circle.other.app.dto.cmd.activity.room.ReceiveRoomRewardCmd; /** * 房间奖励相关. @@ -16,4 +18,19 @@ public interface RoomRewardService { void receive(AppIdLongCmd cmd); + /** + * 查询房间奖励信息 + * + * @param roomId 房间ID + * @return 房间奖励信息 + */ + RoomRewardInfoCO getRoomRewardInfo(String roomId); + + /** + * 领取房主收入 + * + * @param cmd 领取命令 + */ + void receiveOwnerIncome(ReceiveRoomRewardCmd cmd); + } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java index 13f3637b..912c1db4 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java @@ -57,6 +57,11 @@ public class RoomContributionActivityCount extends Convert implements Serializab */ Boolean received; + /** + * 奖励金币是否已发放. + */ + Boolean rewardCoinsSent; + /** * 比例. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java index fbe87afe..f9ad0ad4 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java @@ -5,6 +5,7 @@ import com.red.circle.framework.dto.PageResult; import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount; import java.math.BigDecimal; import java.util.List; +import java.util.Optional; import org.apache.commons.lang3.tuple.ImmutablePair; /** @@ -106,4 +107,13 @@ public interface RoomContributionActivityCountService { */ List getAllRoomsLastWeekData(); + /** + * 根据房间ID和日期查询数据 + * + * @param roomId 房间ID + * @param dateNumber 日期编号(格式:yyyyMMdd) + * @return 房间贡献数据 + */ + Optional findByRoomIdAndDateNumber(Long roomId, Integer dateNumber); + } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java index d431aa65..9fcfbbbf 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java @@ -16,6 +16,7 @@ import java.math.RoundingMode; import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.RequiredArgsConstructor; @@ -302,4 +303,17 @@ public class RoomContributionActivityCountServiceImpl implements return mongoTemplate.find(Query.query(criteria), RoomContributionActivityCount.class); } + @Override + public Optional findByRoomIdAndDateNumber(Long roomId, Integer dateNumber) { + Criteria criteria = Criteria.where("roomId").is(roomId) + .and("dateNumber").is(dateNumber); + + RoomContributionActivityCount result = mongoTemplate.findOne( + Query.query(criteria), + RoomContributionActivityCount.class + ); + + return Optional.ofNullable(result); + } + } diff --git a/rc-service/rc-service-other/other-start/src/test/java/TeamMonthBillTest.java b/rc-service/rc-service-other/other-start/src/test/java/TeamMonthBillTest.java index 3441a48f..7051f1b0 100644 --- a/rc-service/rc-service-other/other-start/src/test/java/TeamMonthBillTest.java +++ b/rc-service/rc-service-other/other-start/src/test/java/TeamMonthBillTest.java @@ -76,7 +76,7 @@ public class TeamMonthBillTest { */ @Test public void processTeamBillSettle() { - String json = "['1984235784268349441']"; + String json = "['1989278352807731201']"; List teamList = JSON.parseArray(json, String.class); for (String teamId : teamList) { Long id = Long.parseLong(teamId);