领取奖励支持多挡位一次性领取

This commit is contained in:
tianfeng 2026-03-05 11:12:17 +08:00
parent 61a65e0e1f
commit 7e89c619a1
5 changed files with 67 additions and 50 deletions

View File

@ -10,7 +10,6 @@ import com.red.circle.other.infra.database.rds.entity.task.RoomDailyTaskTier;
import com.red.circle.other.infra.database.rds.service.RoomDailyTaskDatabaseService; import com.red.circle.other.infra.database.rds.service.RoomDailyTaskDatabaseService;
import com.red.circle.other.inner.asserts.user.UserErrorCode; import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.tuple.PennyAmount; import com.red.circle.tool.core.tuple.PennyAmount;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient; 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.cmd.GoldReceiptCmd;
@ -22,9 +21,12 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* 领取任务奖励 * 领取任务奖励支持同一任务多档位批量领取
*/ */
@Slf4j @Slf4j
@Component @Component
@ -38,68 +40,77 @@ public class RoomDailyTaskClaimExe {
public RoomDailyTaskClaimCO execute(RoomDailyTaskClaimCmd cmd) { public RoomDailyTaskClaimCO execute(RoomDailyTaskClaimCmd cmd) {
Long userId = cmd.getReqUserId(); Long userId = cmd.getReqUserId();
String taskCode = cmd.getTaskCode(); String taskCode = cmd.getTaskCode();
Integer tierIndex = cmd.getTierIndex();
LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate(); LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
String bizNo = userId + ":" + taskCode + ":" + today + ":" + tierIndex;
if (taskDatabaseService.existsClaimRecord(bizNo)) {
ResponseAssert.failure(UserErrorCode.AWARD_RECEIVED);
}
RoomDailyTaskConfig config = taskDatabaseService.getConfigByCode(taskCode); RoomDailyTaskConfig config = taskDatabaseService.getConfigByCode(taskCode);
if (config == null) { ResponseAssert.notNull(UserErrorCode.TASK_NOT_FOUND, config);
ResponseAssert.failure(UserErrorCode.TASK_NOT_FOUND);
}
RoomDailyTaskTier tier = taskDatabaseService.getTier(taskCode, tierIndex); List<RoomDailyTaskTier> tiers = taskDatabaseService.listTiersByTaskCodes(Collections.singletonList(taskCode));
if (tier == null) { ResponseAssert.isTrue(UserErrorCode.TASK_TIER_NOT_FOUND, !tiers.isEmpty());
ResponseAssert.failure(UserErrorCode.TASK_TIER_NOT_FOUND);
}
RoomDailyTaskProgress progress = taskDatabaseService.getProgress(userId, taskCode, today); RoomDailyTaskProgress progress = taskDatabaseService.getProgress(userId, taskCode, today);
if (progress == null || progress.getMaxTierCompleted() < tierIndex) { ResponseAssert.notNull(UserErrorCode.INCOMPLETE_TASK, progress);
ResponseAssert.failure(UserErrorCode.INCOMPLETE_TASK);
} // 找出所有已完成但未领取的档位
if (progress.getMaxTierClaimed() >= tierIndex) { int maxTierCompleted = progress.getMaxTierCompleted();
int maxTierClaimed = progress.getMaxTierClaimed();
if (maxTierCompleted <= maxTierClaimed) {
ResponseAssert.failure(UserErrorCode.AWARD_RECEIVED); ResponseAssert.failure(UserErrorCode.AWARD_RECEIVED);
} }
// 更新领取状态 List<RoomDailyTaskTier> claimableTiers = tiers.stream()
progress.setMaxTierClaimed(tierIndex); .filter(t -> t.getTierIndex() > maxTierClaimed && t.getTierIndex() <= maxTierCompleted)
.toList();
long totalReward = 0;
List<RoomDailyTaskClaimRecord> records = new ArrayList<>();
for (RoomDailyTaskTier tier : claimableTiers) {
String bizNo = userId + ":" + taskCode + ":" + today + ":" + tier.getTierIndex();
if (taskDatabaseService.existsClaimRecord(bizNo)) {
continue;
}
totalReward += tier.getRewardValue();
RoomDailyTaskClaimRecord record = new RoomDailyTaskClaimRecord();
record.setUserId(userId);
record.setTaskId(config.getId());
record.setTaskCode(taskCode);
record.setTierIndex(tier.getTierIndex());
record.setRewardType(tier.getRewardType());
record.setRewardValue(tier.getRewardValue());
record.setCycleDate(today);
record.setBizNo(bizNo);
record.setClaimTime(LocalDateTime.now());
record.setCreateTime(LocalDateTime.now());
records.add(record);
}
if (records.isEmpty()) {
ResponseAssert.failure(UserErrorCode.AWARD_RECEIVED);
}
// 更新最高已领取档位
progress.setMaxTierClaimed(maxTierCompleted);
progress.setUpdateTime(LocalDateTime.now()); progress.setUpdateTime(LocalDateTime.now());
taskDatabaseService.saveOrUpdateProgress(progress); taskDatabaseService.saveOrUpdateProgress(progress);
taskDatabaseService.saveClaimRecords(records);
// 保存领取记录 // 发放奖励
RoomDailyTaskClaimRecord record = new RoomDailyTaskClaimRecord(); String bizNo = userId + ":" + taskCode + ":" + today + ":batch:" + maxTierClaimed + "-" + maxTierCompleted;
record.setUserId(userId);
record.setTaskId(config.getId());
record.setTaskCode(taskCode);
record.setTierIndex(tierIndex);
record.setRewardType(tier.getRewardType());
record.setRewardValue(tier.getRewardValue());
record.setCycleDate(today);
record.setBizNo(bizNo);
record.setClaimTime(LocalDateTime.now());
record.setCreateTime(LocalDateTime.now());
taskDatabaseService.saveClaimRecord(record);
walletGoldClient.changeBalance(GoldReceiptCmd.builder() walletGoldClient.changeBalance(GoldReceiptCmd.builder()
.appIncome() .appIncome()
.userId(userId) .userId(userId)
.amount(PennyAmount.ofDollar(tier.getRewardValue().longValue())) .amount(PennyAmount.ofDollar(totalReward))
.eventId(bizNo) .eventId(bizNo)
.sysOrigin(cmd.requireReqSysOrigin()) .sysOrigin(cmd.requireReqSysOrigin())
.origin(GoldOrigin.ROOM_DAILY_TASK) .origin(GoldOrigin.ROOM_DAILY_TASK)
.build()); .build());
log.info("任务奖励领取成功, userId={}, taskCode={}, tierIndex={}, rewardValue={}", userId, taskCode, tierIndex, tier.getRewardValue());
RoomDailyTaskClaimCO co = new RoomDailyTaskClaimCO(); RoomDailyTaskClaimCO co = new RoomDailyTaskClaimCO();
co.setTaskCode(taskCode); co.setTaskCode(taskCode);
co.setTaskName(config.getTaskName()); co.setTaskName(config.getTaskName());
co.setTierIndex(tierIndex); co.setClaimedCount(records.size());
co.setRewardValue(tier.getRewardValue()); co.setTotalRewardValue(totalReward);
co.setClaimTime(LocalDateTime.now()); co.setClaimTime(LocalDateTime.now());
return co; return co;
} }

View File

@ -20,6 +20,8 @@ import com.red.circle.other.app.command.activity.GetValidInviteUsersExe;
import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd; import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd;
import com.red.circle.other.app.dto.cmd.activity.InviteUserActivityLimitCmd; import com.red.circle.other.app.dto.cmd.activity.InviteUserActivityLimitCmd;
import java.util.List; import java.util.List;
import com.red.circle.other.app.util.DistributedLockUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -48,6 +50,7 @@ public class InviteUserActivityServiceImpl implements InviteUserActivityService
private final GetIncomeStatisticsExe getIncomeStatisticsExe; private final GetIncomeStatisticsExe getIncomeStatisticsExe;
private final GetValidInviteUsersExe getValidInviteUsersExe; private final GetValidInviteUsersExe getValidInviteUsersExe;
private final MyInviterInfoQryExe myInviterInfoQryExe; private final MyInviterInfoQryExe myInviterInfoQryExe;
private final DistributedLockUtil distributedLockUtil;
@Override @Override
public InviteUserActivitySummaryCO getSummary(AppExtCommand cmd) { public InviteUserActivitySummaryCO getSummary(AppExtCommand cmd) {
@ -97,7 +100,10 @@ public class InviteUserActivityServiceImpl implements InviteUserActivityService
@Override @Override
public void bindInviteCode(BindInviteCodeCmd cmd) { public void bindInviteCode(BindInviteCodeCmd cmd) {
bindInviteCodeExe.execute(cmd); String key = "bind:inviteCode:" + cmd.getReqUserId();
distributedLockUtil.executeWithLock(key, () -> {
bindInviteCodeExe.execute(cmd);
});
} }
@Override @Override

View File

@ -16,11 +16,11 @@ public class RoomDailyTaskClaimCO {
/** 任务名称 */ /** 任务名称 */
private String taskName; private String taskName;
/** 领取的档位序号 */ /** 本次领取的档位数量 */
private Integer tierIndex; private Integer claimedCount;
/** 奖励金币数 */ /** 本次领取的总奖励金币数 */
private Integer rewardValue; private Long totalRewardValue;
/** 领取时间 */ /** 领取时间 */
private LocalDateTime claimTime; private LocalDateTime claimTime;

View File

@ -2,7 +2,6 @@ package com.red.circle.other.app.dto.cmd.task;
import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -15,7 +14,4 @@ public class RoomDailyTaskClaimCmd extends AppExtCommand {
@NotBlank(message = "任务编码不能为空") @NotBlank(message = "任务编码不能为空")
private String taskCode; private String taskCode;
@NotNull(message = "档位序号不能为空")
private Integer tierIndex;
} }

View File

@ -78,6 +78,10 @@ public class RoomDailyTaskDatabaseService {
claimRecordDAO.insert(record); claimRecordDAO.insert(record);
} }
public void saveClaimRecords(List<RoomDailyTaskClaimRecord> records) {
claimRecordDAO.insertBatchSomeColumn(records);
}
public RoomDailyTaskConfig getConfigByCode(String taskCode) { public RoomDailyTaskConfig getConfigByCode(String taskCode) {
return configDAO.selectList( return configDAO.selectList(
new LambdaQueryWrapper<RoomDailyTaskConfig>() new LambdaQueryWrapper<RoomDailyTaskConfig>()