From 83f79ce3d817b866db591abc1811aebc9e42d2d1 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Tue, 21 Oct 2025 12:20:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Espins=20task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/api/LotteryTicketClientApi.java | 2 +- .../app/task/SpinsTaskRestController.java | 55 +++++++ .../SpinsTaskProgressIncrementExe.java | 153 +++++++++++++++++ .../app/command/SpinsTaskProgressInitExe.java | 111 +++++++++++++ .../command/SpinsTaskProgressResetExe.java | 54 ++++++ .../command/SpinsTaskProgressUpdateExe.java | 155 ++++++++++++++++++ .../other/app/command/SpinsTaskQueryExe.java | 121 ++++++++++++++ .../command/SpinsTaskReceiveRewardExe.java | 145 ++++++++++++++++ .../other/app/listener/task/TaskListener.java | 4 - .../service/task/SpinsTaskServiceImpl.java | 42 +++++ .../SpinsUserTaskProgressServiceImpl.java | 56 +++++++ .../app/dto/clientobject/SpinsTaskCO.java | 94 +++++++++++ .../dto/clientobject/SpinsTaskRewardCO.java | 49 ++++++ .../dto/cmd/SpinsTaskProgressUpdateCmd.java | 38 +++++ .../dto/cmd/SpinsTaskReceiveRewardCmd.java | 25 +++ .../other/app/service/SpinsTaskService.java | 32 ++++ .../service/SpinsUserTaskProgressService.java | 43 +++++ .../rds/dao/task/SpinsTaskConfigDAO.java | 13 ++ .../dao/task/SpinsUserTaskProgressDAO.java | 13 ++ .../rds/dao/task/SpinsUserTaskRecordDAO.java | 13 ++ .../rds/entity/task/SpinsTaskConfig.java | 140 ++++++++++++++++ .../entity/task/SpinsUserTaskProgress.java | 117 +++++++++++++ .../rds/entity/task/SpinsUserTaskRecord.java | 100 +++++++++++ .../activity/LotteryTicketClientEndpoint.java | 4 +- .../activity/LotteryTicketClientService.java | 2 +- .../impl/LotteryTicketClientServiceImpl.java | 4 +- 26 files changed, 1575 insertions(+), 10 deletions(-) create mode 100644 rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/task/SpinsTaskRestController.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressIncrementExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressInitExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressResetExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressUpdateExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskQueryExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskReceiveRewardExe.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsTaskServiceImpl.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsUserTaskProgressServiceImpl.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskCO.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskRewardCO.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskProgressUpdateCmd.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskReceiveRewardCmd.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsTaskService.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsUserTaskProgressService.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsTaskConfigDAO.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskProgressDAO.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskRecordDAO.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsTaskConfig.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskProgress.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskRecord.java diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java index 5002c022..7da8826f 100644 --- a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java @@ -34,7 +34,7 @@ public interface LotteryTicketClientApi { * 增加用户抽奖券. */ @PostMapping("/addTicket") - ResultResponse addTicket( + ResultResponse addTicket( @RequestParam("userId") Long userId, @RequestParam("count") Integer count, @RequestParam(value = "source", required = false) String source, diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/task/SpinsTaskRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/task/SpinsTaskRestController.java new file mode 100644 index 00000000..754b7b44 --- /dev/null +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/task/SpinsTaskRestController.java @@ -0,0 +1,55 @@ +package com.red.circle.other.adapter.app.task; + +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import com.red.circle.other.app.dto.clientobject.SpinsTaskCO; +import com.red.circle.other.app.dto.clientobject.SpinsTaskRewardCO; +import com.red.circle.other.app.dto.cmd.SpinsTaskReceiveRewardCmd; +import com.red.circle.other.app.service.SpinsTaskService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Spins任务接口 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@RestController +@RequestMapping("/spins/task") +@RequiredArgsConstructor +public class SpinsTaskRestController { + + private final SpinsTaskService spinsTaskService; + + /** + * 获取用户任务列表 + * + * @param cmd 用户ID + * @return 任务列表 + */ + @GetMapping("/list") + public List getTaskList(AppExtCommand cmd) { + Long userId = cmd.getReqUserId(); + log.info("获取用户任务列表, userId={}", userId); + List taskList = spinsTaskService.getUserTaskList(userId); + return taskList; + } + + /** + * 领取任务奖励 + * + * @param cmd 领取奖励命令 + * @return 奖励信息 + */ + @PostMapping("/receive/reward") + public SpinsTaskRewardCO receiveReward(@Validated @RequestBody SpinsTaskReceiveRewardCmd cmd) { + log.info("领取任务奖励, userId={}, taskCode={}", cmd.getUserId(), cmd.getTaskCode()); + SpinsTaskRewardCO reward = spinsTaskService.receiveTaskReward(cmd); + return reward; + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressIncrementExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressIncrementExe.java new file mode 100644 index 00000000..ca75e4bd --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressIncrementExe.java @@ -0,0 +1,153 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.infra.database.rds.dao.task.SpinsTaskConfigDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 增加任务进度执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskProgressIncrementExe { + + private final SpinsTaskConfigDAO spinsTaskConfigDAO; + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + + /** + * 执行增加任务进度 + * + * @param userId 用户ID + * @param taskCode 任务编码 + * @param incrementValue 增加值 + */ + @Transactional(rollbackFor = Exception.class) + public void execute(Long userId, String taskCode, Integer incrementValue) { + // 1. 查询任务配置 + List taskConfigs = spinsTaskConfigDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsTaskConfig::getTaskCode, taskCode) + .eq(SpinsTaskConfig::getStatus, 1) + ); + + if (taskConfigs.isEmpty()) { + log.warn("任务配置不存在或已下线, taskCode={}", taskCode); + return; + } + + SpinsTaskConfig taskConfig = taskConfigs.get(0); + + // 2. 获取或创建用户任务进度 + String cycleKey = getCurrentCycleKey(taskConfig.getCycleType()); + SpinsUserTaskProgress progress = getOrCreateProgress(userId, taskConfig, cycleKey); + + // 3. 增加进度值 + int newValue = progress.getCurrentValue() + incrementValue; + progress.setCurrentValue(newValue); + + // 4. 计算进度百分比 + BigDecimal progressRate = calculateProgressRate(newValue, taskConfig.getTargetValue()); + progress.setProgressRate(progressRate); + + // 5. 检查是否完成 + if (newValue >= taskConfig.getTargetValue() && progress.getTaskStatus() == 0) { + progress.setTaskStatus(1); + progress.setCompleteTime(new Timestamp(System.currentTimeMillis())); + progress.setCompleteTimes(progress.getCompleteTimes() + 1); + log.info("任务完成, userId={}, taskCode={}, newValue={}", userId, taskCode, newValue); + } + + progress.setUpdateTime(new Timestamp(System.currentTimeMillis())); + spinsUserTaskProgressDAO.updateById(progress); + + log.info("任务进度增加成功, userId={}, taskCode={}, incrementValue={}, newValue={}", + userId, taskCode, incrementValue, newValue); + } + + /** + * 获取或创建用户任务进度 + */ + private SpinsUserTaskProgress getOrCreateProgress(Long userId, SpinsTaskConfig taskConfig, String cycleKey) { + List progressList = spinsUserTaskProgressDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .eq(SpinsUserTaskProgress::getTaskCode, taskConfig.getTaskCode()) + .eq(SpinsUserTaskProgress::getCycleKey, cycleKey) + ); + SpinsUserTaskProgress progress = null; + if (!progressList.isEmpty()) { + progress = progressList.get(0); + } + + if (progress == null) { + progress = new SpinsUserTaskProgress(); + progress.setUserId(userId); + progress.setTaskId(taskConfig.getId()); + progress.setTaskCode(taskConfig.getTaskCode()); + progress.setCurrentValue(0); + progress.setTargetValue(taskConfig.getTargetValue()); + progress.setProgressRate(BigDecimal.ZERO); + progress.setTaskStatus(0); + progress.setCycleType(taskConfig.getCycleType()); + progress.setCycleDate(LocalDate.now()); + progress.setCycleKey(cycleKey); + progress.setCompleteTimes(0); + progress.setRewardType(taskConfig.getRewardType()); + progress.setRewardValue(taskConfig.getRewardValue()); + progress.setCreateTime(new Timestamp(System.currentTimeMillis())); + progress.setUpdateTime(new Timestamp(System.currentTimeMillis())); + spinsUserTaskProgressDAO.insert(progress); + } + + return progress; + } + + /** + * 计算进度百分比 + */ + private BigDecimal calculateProgressRate(Integer currentValue, Integer targetValue) { + if (targetValue == null || targetValue == 0) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(currentValue) + .divide(BigDecimal.valueOf(targetValue), 4, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)) + .setScale(2, RoundingMode.HALF_UP); + } + + /** + * 获取当前周期key + */ + private String getCurrentCycleKey(Integer cycleType) { + LocalDate now = LocalDate.now(); + if (cycleType == 1) { + // 每日任务:格式 yyyyMMdd + return now.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } else if (cycleType == 2) { + // 每周任务:格式 yyyyWw(例如:2025W03) + int weekOfYear = now.getDayOfYear() / 7 + 1; + return now.getYear() + "W" + String.format("%02d", weekOfYear); + } else { + // 一次性任务:固定标识 + return "ONCE"; + } + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressInitExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressInitExe.java new file mode 100644 index 00000000..52033bda --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressInitExe.java @@ -0,0 +1,111 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.infra.database.rds.dao.task.SpinsTaskConfigDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 初始化任务进度执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskProgressInitExe { + + private final SpinsTaskConfigDAO spinsTaskConfigDAO; + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + + /** + * 执行初始化用户任务进度 + * + * @param userId 用户ID + * @param taskCode 任务编码 + */ + @Transactional(rollbackFor = Exception.class) + public void execute(Long userId, String taskCode) { + // 1. 查询任务配置 + List taskConfigs = spinsTaskConfigDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsTaskConfig::getTaskCode, taskCode) + .eq(SpinsTaskConfig::getStatus, 1) + ); + + if (taskConfigs.isEmpty()) { + log.warn("任务配置不存在或已下线, taskCode={}", taskCode); + return; + } + SpinsTaskConfig taskConfig = taskConfigs.get(0); + + // 2. 获取当前周期key + String cycleKey = getCurrentCycleKey(taskConfig.getCycleType()); + + // 3. 检查是否已存在 + List existProgressList = spinsUserTaskProgressDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .eq(SpinsUserTaskProgress::getTaskCode, taskCode) + .eq(SpinsUserTaskProgress::getCycleKey, cycleKey) + ); + + if (!existProgressList.isEmpty()) { + log.info("任务进度已存在, userId={}, taskCode={}", userId, taskCode); + return; + } + + // 4. 创建新的任务进度 + SpinsUserTaskProgress progress = new SpinsUserTaskProgress(); + progress.setUserId(userId); + progress.setTaskId(taskConfig.getId()); + progress.setTaskCode(taskConfig.getTaskCode()); + progress.setCurrentValue(0); + progress.setTargetValue(taskConfig.getTargetValue()); + progress.setProgressRate(BigDecimal.ZERO); + progress.setTaskStatus(0); + progress.setCycleType(taskConfig.getCycleType()); + progress.setCycleDate(LocalDate.now()); + progress.setCycleKey(cycleKey); + progress.setCompleteTimes(0); + progress.setRewardType(taskConfig.getRewardType()); + progress.setRewardValue(taskConfig.getRewardValue()); + progress.setCreateTime(new Timestamp(System.currentTimeMillis())); + progress.setUpdateTime(new Timestamp(System.currentTimeMillis())); + + spinsUserTaskProgressDAO.insert(progress); + + log.info("初始化用户任务进度成功, userId={}, taskCode={}", userId, taskCode); + } + + /** + * 获取当前周期key + */ + private String getCurrentCycleKey(Integer cycleType) { + LocalDate now = LocalDate.now(); + if (cycleType == 1) { + // 每日任务:格式 yyyyMMdd + return now.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } else if (cycleType == 2) { + // 每周任务:格式 yyyyWw(例如:2025W03) + int weekOfYear = now.getDayOfYear() / 7 + 1; + return now.getYear() + "W" + String.format("%02d", weekOfYear); + } else { + // 一次性任务:固定标识 + return "ONCE"; + } + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressResetExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressResetExe.java new file mode 100644 index 00000000..6910fbfd --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressResetExe.java @@ -0,0 +1,54 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 重置任务进度执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskProgressResetExe { + + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + + /** + * 执行重置用户每日任务 + * + * @param userId 用户ID + */ + @Transactional(rollbackFor = Exception.class) + public void execute(Long userId) { + // 获取昨天的周期key + String yesterdayCycleKey = LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMdd")); + + // 查询昨天的每日任务进度 + List progressList = spinsUserTaskProgressDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .eq(SpinsUserTaskProgress::getCycleType, 1) // 每日任务 + .eq(SpinsUserTaskProgress::getCycleKey, yesterdayCycleKey) + ); + + if (progressList.isEmpty()) { + log.info("没有需要重置的每日任务, userId={}", userId); + return; + } + + log.info("重置用户每日任务成功, userId={}, 重置任务数={}", userId, progressList.size()); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressUpdateExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressUpdateExe.java new file mode 100644 index 00000000..7a103e64 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskProgressUpdateExe.java @@ -0,0 +1,155 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.app.dto.cmd.SpinsTaskProgressUpdateCmd; +import com.red.circle.other.infra.database.rds.dao.task.SpinsTaskConfigDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 更新任务进度执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskProgressUpdateExe { + + private final SpinsTaskConfigDAO spinsTaskConfigDAO; + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + + /** + * 执行更新任务进度 + * + * @param cmd 更新命令 + */ + @Transactional(rollbackFor = Exception.class) + public void execute(SpinsTaskProgressUpdateCmd cmd) { + Long userId = cmd.getUserId(); + String taskCode = cmd.getTaskCode(); + Integer progressValue = cmd.getProgressValue(); + + // 1. 查询任务配置 + List taskConfigs = spinsTaskConfigDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsTaskConfig::getTaskCode, taskCode) + .eq(SpinsTaskConfig::getStatus, 1) + ); + + if (taskConfigs.isEmpty()) { + log.warn("任务配置不存在或已下线, taskCode={}", taskCode); + return; + } + SpinsTaskConfig taskConfig = taskConfigs.get(0); + + // 2. 获取或创建用户任务进度 + String cycleKey = getCurrentCycleKey(taskConfig.getCycleType()); + SpinsUserTaskProgress progress = getOrCreateProgress(userId, taskConfig, cycleKey); + + // 3. 更新进度值 + progress.setCurrentValue(progressValue); + + // 4. 计算进度百分比 + BigDecimal progressRate = calculateProgressRate(progressValue, taskConfig.getTargetValue()); + progress.setProgressRate(progressRate); + + // 5. 检查是否完成 + if (progressValue >= taskConfig.getTargetValue() && progress.getTaskStatus() == 0) { + progress.setTaskStatus(1); + progress.setCompleteTime(new Timestamp(System.currentTimeMillis())); + progress.setCompleteTimes(progress.getCompleteTimes() + 1); + log.info("任务完成, userId={}, taskCode={}, progressValue={}", userId, taskCode, progressValue); + } + + progress.setUpdateTime(new Timestamp(System.currentTimeMillis())); + spinsUserTaskProgressDAO.updateById(progress); + + log.info("任务进度更新成功, userId={}, taskCode={}, progressValue={}, progressRate={}", + userId, taskCode, progressValue, progressRate); + } + + /** + * 获取或创建用户任务进度 + */ + private SpinsUserTaskProgress getOrCreateProgress(Long userId, SpinsTaskConfig taskConfig, String cycleKey) { + List progressList = spinsUserTaskProgressDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .eq(SpinsUserTaskProgress::getTaskCode, taskConfig.getTaskCode()) + .eq(SpinsUserTaskProgress::getCycleKey, cycleKey) + ); + + SpinsUserTaskProgress progress = null; + if (!progressList.isEmpty()) { + progress = progressList.get(0); + } + + if (progress == null) { + progress = new SpinsUserTaskProgress(); + progress.setUserId(userId); + progress.setTaskId(taskConfig.getId()); + progress.setTaskCode(taskConfig.getTaskCode()); + progress.setCurrentValue(0); + progress.setTargetValue(taskConfig.getTargetValue()); + progress.setProgressRate(BigDecimal.ZERO); + progress.setTaskStatus(0); + progress.setCycleType(taskConfig.getCycleType()); + progress.setCycleDate(LocalDate.now()); + progress.setCycleKey(cycleKey); + progress.setCompleteTimes(0); + progress.setRewardType(taskConfig.getRewardType()); + progress.setRewardValue(taskConfig.getRewardValue()); + progress.setCreateTime(new Timestamp(System.currentTimeMillis())); + progress.setUpdateTime(new Timestamp(System.currentTimeMillis())); + spinsUserTaskProgressDAO.insert(progress); + } + + return progress; + } + + /** + * 计算进度百分比 + */ + private BigDecimal calculateProgressRate(Integer currentValue, Integer targetValue) { + if (targetValue == null || targetValue == 0) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(currentValue) + .divide(BigDecimal.valueOf(targetValue), 4, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)) + .setScale(2, RoundingMode.HALF_UP); + } + + /** + * 获取当前周期key + */ + private String getCurrentCycleKey(Integer cycleType) { + LocalDate now = LocalDate.now(); + if (cycleType == 1) { + // 每日任务:格式 yyyyMMdd + return now.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } else if (cycleType == 2) { + // 每周任务:格式 yyyyWw(例如:2025W03) + int weekOfYear = now.getDayOfYear() / 7 + 1; + return now.getYear() + "W" + String.format("%02d", weekOfYear); + } else { + // 一次性任务:固定标识 + return "ONCE"; + } + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskQueryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskQueryExe.java new file mode 100644 index 00000000..28cdb8c0 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskQueryExe.java @@ -0,0 +1,121 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.app.dto.clientobject.SpinsTaskCO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import com.red.circle.other.infra.database.rds.dao.task.SpinsTaskConfigDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 查询用户任务列表执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskQueryExe { + + private final SpinsTaskConfigDAO spinsTaskConfigDAO; + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + + /** + * 执行查询用户任务列表 + * + * @param userId 用户ID + * @return 任务列表 + */ + public List execute(Long userId) { + // 1. 查询所有启用的任务配置 + List taskConfigs = spinsTaskConfigDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsTaskConfig::getStatus, 1) + .orderByAsc(SpinsTaskConfig::getSortOrder) + ); + + if (CollectionUtils.isEmpty(taskConfigs)) { + log.warn("未查询到启用的任务配置"); + return new ArrayList<>(); + } + + // 2. 获取当前周期key + String cycleKey = getCurrentCycleKey(); + + // 3. 查询用户任务进度 + List taskCodes = taskConfigs.stream() + .map(SpinsTaskConfig::getTaskCode) + .collect(Collectors.toList()); + + List progressList = spinsUserTaskProgressDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .in(SpinsUserTaskProgress::getTaskCode, taskCodes) + .eq(SpinsUserTaskProgress::getCycleKey, cycleKey) + ); + + Map progressMap = progressList.stream() + .collect(Collectors.toMap(SpinsUserTaskProgress::getTaskCode, p -> p, (p1, p2) -> p1)); + + // 4. 组装返回数据 + List result = new ArrayList<>(); + for (SpinsTaskConfig config : taskConfigs) { + SpinsTaskCO taskCO = buildTaskCO(config, progressMap.get(config.getTaskCode())); + result.add(taskCO); + } + + return result; + } + + /** + * 构建任务CO对象 + */ + private SpinsTaskCO buildTaskCO(SpinsTaskConfig config, SpinsUserTaskProgress progress) { + SpinsTaskCO taskCO = new SpinsTaskCO(); + taskCO.setTaskId(config.getId()); + taskCO.setTaskCode(config.getTaskCode()); + taskCO.setTaskName(config.getTaskName()); + taskCO.setTaskType(config.getTaskType()); + taskCO.setTaskDesc(config.getTaskDesc()); + taskCO.setIconUrl(config.getIconUrl()); + taskCO.setTargetType(config.getTargetType()); + taskCO.setTargetValue(config.getTargetValue()); + taskCO.setTargetUnit(config.getTargetUnit()); + taskCO.setRewardType(config.getRewardType()); + taskCO.setRewardValue(config.getRewardValue()); + + if (progress != null) { + taskCO.setCurrentValue(progress.getCurrentValue()); + taskCO.setTaskStatus(progress.getTaskStatus()); + taskCO.setProgressRate(progress.getProgressRate()); + taskCO.setCompleteTime(progress.getCompleteTime()); + } else { + // 未开始的任务 + taskCO.setCurrentValue(0); + taskCO.setTaskStatus(0); + taskCO.setProgressRate(BigDecimal.ZERO); + } + + return taskCO; + } + + /** + * 获取当前周期key(每日任务格式:yyyyMMdd) + */ + private String getCurrentCycleKey() { + return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskReceiveRewardExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskReceiveRewardExe.java new file mode 100644 index 00000000..3404cad6 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/SpinsTaskReceiveRewardExe.java @@ -0,0 +1,145 @@ +package com.red.circle.other.app.command; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.other.app.dto.clientobject.SpinsTaskRewardCO; +import com.red.circle.other.app.dto.cmd.SpinsTaskReceiveRewardCmd; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskRecord; +import com.red.circle.other.infra.database.rds.dao.task.SpinsTaskConfigDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskProgressDAO; +import com.red.circle.other.infra.database.rds.dao.task.SpinsUserTaskRecordDAO; +import com.red.circle.other.inner.endpoint.activity.LotteryTicketClient; +import com.red.circle.tool.core.date.TimestampUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +/** + * 领取任务奖励执行器 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SpinsTaskReceiveRewardExe { + + private final SpinsTaskConfigDAO spinsTaskConfigDAO; + private final SpinsUserTaskProgressDAO spinsUserTaskProgressDAO; + private final SpinsUserTaskRecordDAO spinsUserTaskRecordDAO; + private final LotteryTicketClient lotteryTicketClient; + + /** + * 执行领取任务奖励 + * + * @param cmd 领取奖励命令 + * @return 奖励信息 + */ + @Transactional(rollbackFor = Exception.class) + public SpinsTaskRewardCO execute(SpinsTaskReceiveRewardCmd cmd) { + Long userId = cmd.getUserId(); + String taskCode = cmd.getTaskCode(); + + // 1. 查询任务配置 + List spinsTaskConfigs = spinsTaskConfigDAO.selectList( + new LambdaQueryWrapper() + .eq(SpinsTaskConfig::getTaskCode, taskCode) + .eq(SpinsTaskConfig::getStatus, 1) + ); + + if (spinsTaskConfigs.isEmpty()) { + throw new RuntimeException("任务不存在或已下线"); + } + SpinsTaskConfig taskConfig = spinsTaskConfigs.get(0); + + // 2. 查询用户任务进度 + String cycleKey = getCurrentCycleKey(); + SpinsUserTaskProgress progress = spinsUserTaskProgressDAO.selectById( + new LambdaQueryWrapper() + .eq(SpinsUserTaskProgress::getUserId, userId) + .eq(SpinsUserTaskProgress::getTaskCode, taskCode) + .eq(SpinsUserTaskProgress::getCycleKey, cycleKey) + ); + + if (progress == null) { + throw new RuntimeException("任务未开始"); + } + + // 3. 校验任务状态 + if (progress.getTaskStatus() == 0) { + throw new RuntimeException("任务未完成,无法领取奖励"); + } + + if (progress.getTaskStatus() == 2) { + throw new RuntimeException("奖励已领取,请勿重复领取"); + } + + // 4. 发放抽奖券 + List ticketIds = new ArrayList<>(); + try { + for (int i = 0; i < taskConfig.getRewardValue(); i++) { + Long ticketId = lotteryTicketClient.addTicket( + userId, + 1, + "SPINS_TASK", + taskCode + ).getBody(); + ticketIds.add(ticketId); + } + } catch (Exception e) { + log.error("发放抽奖券失败, userId={}, taskCode={}", userId, taskCode, e); + throw new RuntimeException("发放奖励失败,请稍后重试"); + } + + // 5. 更新任务进度状态 + progress.setTaskStatus(2); + progress.setReceiveTime(TimestampUtils.now()); + progress.setLotteryTicketIds(String.join(",", ticketIds.stream().map(String::valueOf).toArray(String[]::new))); + progress.setUpdateTime(TimestampUtils.now()); + spinsUserTaskProgressDAO.updateById(progress); + + // 6. 记录任务完成记录 + SpinsUserTaskRecord record = new SpinsUserTaskRecord(); + record.setUserId(userId); + record.setTaskId(taskConfig.getId()); + record.setTaskCode(taskCode); + record.setTaskName(taskConfig.getTaskName()); + record.setCompleteValue(progress.getCurrentValue()); + record.setCompleteTime(progress.getCompleteTime()); + record.setCycleKey(cycleKey); + record.setRewardType(taskConfig.getRewardType()); + record.setRewardValue(taskConfig.getRewardValue()); + record.setLotteryActivityId(taskConfig.getLotteryActivityId()); + record.setLotteryTicketIds(progress.getLotteryTicketIds()); + record.setReceiveStatus(1); + record.setCreateTime(TimestampUtils.now()); + spinsUserTaskRecordDAO.insert(record); + + // 7. 组装返回结果 + SpinsTaskRewardCO rewardCO = new SpinsTaskRewardCO(); + rewardCO.setTaskCode(taskCode); + rewardCO.setTaskName(taskConfig.getTaskName()); + rewardCO.setRewardType(taskConfig.getRewardType()); + rewardCO.setRewardValue(taskConfig.getRewardValue()); + rewardCO.setLotteryTicketIds(ticketIds); + rewardCO.setReceiveTime(TimestampUtils.now()); + + log.info("任务奖励领取成功, userId={}, taskCode={}, ticketIds={}", userId, taskCode, ticketIds); + return rewardCO; + } + + /** + * 获取当前周期key(每日任务格式:yyyyMMdd) + */ + private String getCurrentCycleKey() { + return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/task/TaskListener.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/task/TaskListener.java index 7267f7e1..e36af160 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/task/TaskListener.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/task/TaskListener.java @@ -184,15 +184,11 @@ public class TaskListener implements MessageListener { if ("10".equals(inc) || Integer.parseInt(inc) >= 10) { // 更新任务状态的逻辑 直接更新 updateTaskStatus(eventBody); - //判断一下是否有工会裂变任务 -// checkMemberActive(eventBody.getUserId(), MemberActiveEnum.TASK_2); } else { redisService.increment(redisKey, 1); } } -// System.out.println("处理任务-1上麦10分钟: " + eventBody); - // task list 接口单独处理 } private void handleTask99(TaskApprovalEvent eventBody) { diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsTaskServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsTaskServiceImpl.java new file mode 100644 index 00000000..635621da --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsTaskServiceImpl.java @@ -0,0 +1,42 @@ +package com.red.circle.other.app.service.task; + +import com.red.circle.other.app.command.SpinsTaskQueryExe; +import com.red.circle.other.app.command.SpinsTaskReceiveRewardExe; +import com.red.circle.other.app.dto.clientobject.SpinsTaskCO; +import com.red.circle.other.app.dto.clientobject.SpinsTaskRewardCO; +import com.red.circle.other.app.dto.cmd.SpinsTaskReceiveRewardCmd; +import com.red.circle.other.app.service.SpinsTaskService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * Spins任务服务实现 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SpinsTaskServiceImpl implements SpinsTaskService { + + private final SpinsTaskQueryExe spinsTaskQueryExe; + + private final SpinsTaskReceiveRewardExe spinsTaskReceiveRewardExe; + + @Override + public List getUserTaskList(Long userId) { + log.info("执行获取用户任务列表, userId={}", userId); + return spinsTaskQueryExe.execute(userId); + } + + @Override + public SpinsTaskRewardCO receiveTaskReward(SpinsTaskReceiveRewardCmd cmd) { + log.info("执行领取任务奖励, userId={}, taskCode={}", cmd.getUserId(), cmd.getTaskCode()); + return spinsTaskReceiveRewardExe.execute(cmd); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsUserTaskProgressServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsUserTaskProgressServiceImpl.java new file mode 100644 index 00000000..413d65a2 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/task/SpinsUserTaskProgressServiceImpl.java @@ -0,0 +1,56 @@ +package com.red.circle.other.app.service.task; + +import com.red.circle.other.app.command.SpinsTaskProgressInitExe; +import com.red.circle.other.app.command.SpinsTaskProgressIncrementExe; +import com.red.circle.other.app.command.SpinsTaskProgressResetExe; +import com.red.circle.other.app.command.SpinsTaskProgressUpdateExe; +import com.red.circle.other.app.dto.cmd.SpinsTaskProgressUpdateCmd; +import com.red.circle.other.app.service.SpinsUserTaskProgressService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * Spins用户任务进度服务实现 + * + * @author system + * @date 2025-01-21 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SpinsUserTaskProgressServiceImpl implements SpinsUserTaskProgressService { + + private final SpinsTaskProgressUpdateExe spinsTaskProgressUpdateExe; + private final SpinsTaskProgressIncrementExe spinsTaskProgressIncrementExe; + private final SpinsTaskProgressResetExe spinsTaskProgressResetExe; + private final SpinsTaskProgressInitExe spinsTaskProgressInitExe; + + @Override + public void updateTaskProgress(SpinsTaskProgressUpdateCmd cmd) { + log.info("更新用户任务进度, userId={}, taskCode={}, progressValue={}", + cmd.getUserId(), cmd.getTaskCode(), cmd.getProgressValue()); + spinsTaskProgressUpdateExe.execute(cmd); + } + + @Override + public void incrementTaskProgress(Long userId, String taskCode, Integer incrementValue) { + log.info("增加用户任务进度, userId={}, taskCode={}, incrementValue={}", + userId, taskCode, incrementValue); + spinsTaskProgressIncrementExe.execute(userId, taskCode, incrementValue); + } + + @Override + public void resetDailyTasks(Long userId) { + log.info("重置用户每日任务, userId={}", userId); + spinsTaskProgressResetExe.execute(userId); + } + + @Override + public void initUserTaskProgress(Long userId, String taskCode) { + log.info("初始化用户任务进度, userId={}, taskCode={}", userId, taskCode); + spinsTaskProgressInitExe.execute(userId, taskCode); + } +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskCO.java new file mode 100644 index 00000000..88de77ca --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskCO.java @@ -0,0 +1,94 @@ +package com.red.circle.other.app.dto.clientobject; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * Spins任务客户端对象 + * + * @author system + * @date 2025-01-21 + */ +@Data +public class SpinsTaskCO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + private Long taskId; + + /** + * 任务编码 + */ + private String taskCode; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 任务类型:1-开麦任务,2-送礼任务,3-邀请任务 + */ + private Integer taskType; + + /** + * 任务描述 + */ + private String taskDesc; + + /** + * 任务图标 + */ + private String iconUrl; + + /** + * 目标类型:MIC_TIME-开麦时长,SEND_GIFT-送礼,INVITE_USER-邀请用户 + */ + private String targetType; + + /** + * 目标值 + */ + private Integer targetValue; + + /** + * 目标单位:MINUTES-分钟,COUNT-次数,HOURS-小时 + */ + private String targetUnit; + + /** + * 当前进度值 + */ + private Integer currentValue; + + /** + * 进度百分比 + */ + private BigDecimal progressRate; + + /** + * 任务状态:0-进行中,1-已完成,2-已领取奖励 + */ + private Integer taskStatus; + + /** + * 奖励类型:1-抽奖券 + */ + private Integer rewardType; + + /** + * 奖励数量 + */ + private Integer rewardValue; + + /** + * 完成时间 + */ + private Timestamp completeTime; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskRewardCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskRewardCO.java new file mode 100644 index 00000000..960a00e8 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/SpinsTaskRewardCO.java @@ -0,0 +1,49 @@ +package com.red.circle.other.app.dto.clientobject; + +import lombok.Data; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.List; + +/** + * Spins任务奖励客户端对象 + * + * @author system + * @date 2025-01-21 + */ +@Data +public class SpinsTaskRewardCO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 任务编码 + */ + private String taskCode; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 奖励类型:1-抽奖券 + */ + private Integer rewardType; + + /** + * 奖励数量 + */ + private Integer rewardValue; + + /** + * 抽奖券ID列表 + */ + private List lotteryTicketIds; + + /** + * 领取时间 + */ + private Timestamp receiveTime; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskProgressUpdateCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskProgressUpdateCmd.java new file mode 100644 index 00000000..5dcb8e70 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskProgressUpdateCmd.java @@ -0,0 +1,38 @@ +package com.red.circle.other.app.dto.cmd; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serializable; + +/** + * 更新任务进度命令 + * + * @author system + * @date 2025-01-21 + */ +@Data +public class SpinsTaskProgressUpdateCmd implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull(message = "用户ID不能为空") + private Long userId; + + @NotBlank(message = "任务编码不能为空") + private String taskCode; + + @NotNull(message = "进度值不能为空") + private Integer progressValue; + + /** + * 业务类型 + */ + private String bizType; + + /** + * 业务ID + */ + private String bizId; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskReceiveRewardCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskReceiveRewardCmd.java new file mode 100644 index 00000000..6f6d10b3 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/SpinsTaskReceiveRewardCmd.java @@ -0,0 +1,25 @@ +package com.red.circle.other.app.dto.cmd; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serializable; + +/** + * 领取任务奖励命令 + * + * @author system + * @date 2025-01-21 + */ +@Data +public class SpinsTaskReceiveRewardCmd implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull(message = "用户ID不能为空") + private Long userId; + + @NotBlank(message = "任务编码不能为空") + private String taskCode; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsTaskService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsTaskService.java new file mode 100644 index 00000000..0d18a37c --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsTaskService.java @@ -0,0 +1,32 @@ +package com.red.circle.other.app.service; + +import com.red.circle.other.app.dto.clientobject.SpinsTaskCO; +import com.red.circle.other.app.dto.clientobject.SpinsTaskRewardCO; +import com.red.circle.other.app.dto.cmd.SpinsTaskReceiveRewardCmd; + +import java.util.List; + +/** + * Spins任务服务接口 + * + * @author system + * @date 2025-01-21 + */ +public interface SpinsTaskService { + + /** + * 获取用户任务列表 + * + * @param userId 用户ID + * @return 任务列表 + */ + List getUserTaskList(Long userId); + + /** + * 领取任务奖励 + * + * @param cmd 领取奖励命令 + * @return 奖励信息 + */ + SpinsTaskRewardCO receiveTaskReward(SpinsTaskReceiveRewardCmd cmd); +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsUserTaskProgressService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsUserTaskProgressService.java new file mode 100644 index 00000000..d0118907 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/SpinsUserTaskProgressService.java @@ -0,0 +1,43 @@ +package com.red.circle.other.app.service; + +import com.red.circle.other.app.dto.cmd.SpinsTaskProgressUpdateCmd; + +/** + * Spins用户任务进度服务接口 + * + * @author system + * @date 2025-01-21 + */ +public interface SpinsUserTaskProgressService { + + /** + * 更新用户任务进度 + * + * @param cmd 更新进度命令 + */ + void updateTaskProgress(SpinsTaskProgressUpdateCmd cmd); + + /** + * 增加用户任务进度 + * + * @param userId 用户ID + * @param taskCode 任务编码 + * @param incrementValue 增加值 + */ + void incrementTaskProgress(Long userId, String taskCode, Integer incrementValue); + + /** + * 重置用户每日任务 + * + * @param userId 用户ID + */ + void resetDailyTasks(Long userId); + + /** + * 初始化用户任务进度 + * + * @param userId 用户ID + * @param taskCode 任务编码 + */ + void initUserTaskProgress(Long userId, String taskCode); +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsTaskConfigDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsTaskConfigDAO.java new file mode 100644 index 00000000..7b92da65 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsTaskConfigDAO.java @@ -0,0 +1,13 @@ +package com.red.circle.other.infra.database.rds.dao.task; + +import com.red.circle.framework.mybatis.dao.BaseDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsTaskConfig; + +/** + * Spins任务配置DAO + * + * @author system + * @date 2025-01-21 + */ +public interface SpinsTaskConfigDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskProgressDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskProgressDAO.java new file mode 100644 index 00000000..01d3daa3 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskProgressDAO.java @@ -0,0 +1,13 @@ +package com.red.circle.other.infra.database.rds.dao.task; + +import com.red.circle.framework.mybatis.dao.BaseDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskProgress; + +/** + * Spins用户任务进度DAO + * + * @author system + * @date 2025-01-21 + */ +public interface SpinsUserTaskProgressDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskRecordDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskRecordDAO.java new file mode 100644 index 00000000..25b26c9a --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/task/SpinsUserTaskRecordDAO.java @@ -0,0 +1,13 @@ +package com.red.circle.other.infra.database.rds.dao.task; + +import com.red.circle.framework.mybatis.dao.BaseDAO; +import com.red.circle.other.infra.database.rds.entity.task.SpinsUserTaskRecord; + +/** + * Spins用户任务完成记录DAO + * + * @author system + * @date 2025-01-21 + */ +public interface SpinsUserTaskRecordDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsTaskConfig.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsTaskConfig.java new file mode 100644 index 00000000..eff25ff6 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsTaskConfig.java @@ -0,0 +1,140 @@ +package com.red.circle.other.infra.database.rds.entity.task; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.sql.Timestamp; + +/** + * Spins任务配置实体 + * + * @author system + * @date 2025-01-21 + */ +@Data +@TableName("spins_task_config") +public class SpinsTaskConfig { + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 任务编码(唯一标识) + */ + private String taskCode; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 任务类型:1-开麦任务,2-送礼任务,3-邀请任务 + */ + private Integer taskType; + + /** + * 任务描述 + */ + private String taskDesc; + + /** + * 任务图标 + */ + private String iconUrl; + + /** + * 目标类型:MIC_TIME-开麦时长,SEND_GIFT-送礼,INVITE_USER-邀请用户 + */ + private String targetType; + + /** + * 目标值(如:15分钟=15,送3个礼物=3) + */ + private Integer targetValue; + + /** + * 目标单位:MINUTES-分钟,COUNT-次数,HOURS-小时 + */ + private String targetUnit; + + /** + * 奖励类型:1-抽奖券 + */ + private Integer rewardType; + + /** + * 奖励数量 + */ + private Integer rewardValue; + + /** + * 关联的抽奖活动ID + */ + private Long lotteryActivityId; + + /** + * 周期类型:1-每日,2-每周,3-一次性 + */ + private Integer cycleType; + + /** + * 重置时间(每日任务) + */ + private String resetTime; + + /** + * 每周期最大完成次数 + */ + private Integer maxTimes; + + /** + * 状态:0-禁用,1-启用 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sortOrder; + + /** + * 任务开始时间 + */ + private Timestamp startTime; + + /** + * 任务结束时间 + */ + private Timestamp endTime; + + /** + * 扩展配置(JSON格式) + */ + private String extraConfig; + + /** + * 创建时间 + */ + private Timestamp createTime; + + /** + * 更新时间 + */ + private Timestamp updateTime; + + /** + * 创建人 + */ + private String createdBy; + + /** + * 更新人 + */ + private String updatedBy; +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskProgress.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskProgress.java new file mode 100644 index 00000000..83739e50 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskProgress.java @@ -0,0 +1,117 @@ +package com.red.circle.other.infra.database.rds.entity.task; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.LocalDate; + +/** + * Spins用户任务进度实体 + * + * @author system + * @date 2025-01-21 + */ +@Data +@TableName("spins_user_task_progress") +public class SpinsUserTaskProgress { + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 任务配置ID + */ + private Long taskId; + + /** + * 任务编码 + */ + private String taskCode; + + /** + * 当前进度值 + */ + private Integer currentValue; + + /** + * 目标值(冗余,方便查询) + */ + private Integer targetValue; + + /** + * 进度百分比 + */ + private BigDecimal progressRate; + + /** + * 任务状态:0-进行中,1-已完成,2-已领取奖励 + */ + private Integer taskStatus; + + /** + * 完成时间 + */ + private Timestamp completeTime; + + /** + * 领取奖励时间 + */ + private Timestamp receiveTime; + + /** + * 周期类型:1-每日,2-每周,3-一次性 + */ + private Integer cycleType; + + /** + * 周期日期(用于每日任务) + */ + private LocalDate cycleDate; + + /** + * 周期标识:如20250121,202503W1 + */ + private String cycleKey; + + /** + * 当前周期完成次数 + */ + private Integer completeTimes; + + /** + * 奖励类型 + */ + private Integer rewardType; + + /** + * 奖励数量 + */ + private Integer rewardValue; + + /** + * 已发放的抽奖券ID列表(逗号分隔) + */ + private String lotteryTicketIds; + + /** + * 创建时间 + */ + private Timestamp createTime; + + /** + * 更新时间 + */ + private Timestamp updateTime; +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskRecord.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskRecord.java new file mode 100644 index 00000000..5511f811 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/task/SpinsUserTaskRecord.java @@ -0,0 +1,100 @@ +package com.red.circle.other.infra.database.rds.entity.task; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.sql.Timestamp; + +/** + * Spins用户任务完成记录实体 + * + * @author system + * @date 2025-01-21 + */ +@Data +@TableName("spins_user_task_record") +public class SpinsUserTaskRecord { + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 任务配置ID + */ + private Long taskId; + + /** + * 任务编码 + */ + private String taskCode; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 完成值 + */ + private Integer completeValue; + + /** + * 完成时间 + */ + private Timestamp completeTime; + + /** + * 周期标识 + */ + private String cycleKey; + + /** + * 奖励类型 + */ + private Integer rewardType; + + /** + * 奖励数量 + */ + private Integer rewardValue; + + /** + * 抽奖活动ID + */ + private Long lotteryActivityId; + + /** + * 抽奖券ID列表 + */ + private String lotteryTicketIds; + + /** + * 领取状态:1-已发放,2-发放失败 + */ + private Integer receiveStatus; + + /** + * 业务类型 + */ + private String bizType; + + /** + * 业务ID + */ + private String bizId; + + /** + * 创建时间 + */ + private Timestamp createTime; +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java index 4b6235a7..eac0958e 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java @@ -36,8 +36,8 @@ public class LotteryTicketClientEndpoint implements LotteryTicketClientApi { } @Override - public ResultResponse addTicket(Long userId, Integer count, String source, String sourceId) { - Boolean result = lotteryTicketClientService.addTicket(userId, count, source, sourceId); + public ResultResponse addTicket(Long userId, Integer count, String source, String sourceId) { + Long result = lotteryTicketClientService.addTicket(userId, count, source, sourceId); return ResultResponse.success(result); } diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/LotteryTicketClientService.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/LotteryTicketClientService.java index 9250ef93..823ab80b 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/LotteryTicketClientService.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/LotteryTicketClientService.java @@ -34,6 +34,6 @@ public interface LotteryTicketClientService { * @param sourceId 来源ID * @return 是否成功 */ - Boolean addTicket(Long userId, Integer count, String source, String sourceId); + Long addTicket(Long userId, Integer count, String source, String sourceId); } diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/impl/LotteryTicketClientServiceImpl.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/impl/LotteryTicketClientServiceImpl.java index d5c0371a..b1570e6d 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/impl/LotteryTicketClientServiceImpl.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/activity/impl/LotteryTicketClientServiceImpl.java @@ -86,7 +86,7 @@ public class LotteryTicketClientServiceImpl implements LotteryTicketClientServic @Override @Transactional(rollbackFor = Exception.class) - public Boolean addTicket(Long userId, Integer count, String source, String sourceId) { + public Long addTicket(Long userId, Integer count, String source, String sourceId) { LotteryTicket ticket = new LotteryTicket(); ticket.setUserId(userId); ticket.setTicketSource(source != null ? source : "SYSTEM"); @@ -107,7 +107,7 @@ public class LotteryTicketClientServiceImpl implements LotteryTicketClientServic ticketRecord.setRemark("系统发放"); lotteryTicketRecordService.save(ticketRecord); - return true; + return ticket.getId(); } }