Sfoglia il codice sorgente

feat(business): 添加排期配置相关功能

- 新增排期配置异步保存服务
- 实现排期配置创建和更新接口
- 添加未来一周和三天的比赛生成任务
- 优化奖励领取流程
- 更新用户消息状态相关接口
fugui001 4 mesi fa
parent
commit
f28a4e03b2
15 ha cambiato i file con 360 aggiunte e 97 eliminazioni
  1. 52 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/ScheduleConfigController.java
  2. 6 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/ScheduleTournamentsReletion.java
  3. 3 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/MessageReceiversMapper.java
  4. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/ScheduleTournamentsReletionMapper.java
  5. 2 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/UserMessageStatusMapper.java
  6. 96 84
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/RewardClaimsServiceImpl.java
  7. 45 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/ScheduleConfigAsyncService.java
  8. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/ScheduleConfigServiceImpl.java
  9. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/TournamentsTemplateServiceImpl.java
  10. 0 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/UserServiceImpl.java
  11. 119 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/business/ScheduleTask.java
  12. 19 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/MessageReceiversMapper.xml
  13. 3 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/ScheduleConfigMapper.xml
  14. 3 1
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/ScheduleTournamentsReletionMapper.xml
  15. 9 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/UserMessageStatusMapper.xml

+ 52 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/controller/ScheduleConfigController.java

@@ -1,6 +1,8 @@
 package org.dromara.business.controller;
 
 import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
@@ -12,7 +14,10 @@ import org.dromara.business.domain.bo.ScheduleConfigRequestBo;
 import org.dromara.business.domain.vo.ScheduleConfigVo;
 import org.dromara.business.domain.vo.TournamentsVo;
 import org.dromara.business.service.IScheduleConfigService;
-import org.springframework.http.ResponseEntity;
+import org.dromara.business.service.impl.ScheduleConfigAsyncService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -38,8 +43,14 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 @RequestMapping("/business/config")
 public class ScheduleConfigController extends BaseController {
 
+    private static final Logger log = LoggerFactory.getLogger(ScheduleConfigController.class);
+
     private final IScheduleConfigService scheduleConfigService;
 
+    private final ScheduleConfigAsyncService scheduleConfigAsyncService;
+
+
+
     /**
      * 查询排期配置:用于保存具体的排期实例配置列表
      */
@@ -111,12 +122,50 @@ public class ScheduleConfigController extends BaseController {
 
     @PostMapping("/createSchedule")
     public R<String> createSchedule(@Valid @RequestBody ScheduleConfigRequestBo request) {
-        return scheduleConfigService.saveScheduleConfig(request);
+        // 🌟 1. 记录请求进入(建议用 MDC 添加 traceId)
+        String traceId = UUID.randomUUID().toString().substring(0, 8);
+        MDC.put("traceId", traceId); // 用于链路追踪
+
+        log.info("【排期创建请求createSchedule】收到创建排期请求, traceId={}, 请求参数: {}", traceId, request);
+
+        try {
+            // 🌟 2. 提交异步任务
+            CompletableFuture<R<String>> future = scheduleConfigAsyncService.saveScheduleConfigAsync(request);
+
+            log.info("【排期创建请求createSchedule】异步任务已提交, traceId={}, configId={}", traceId, request.getTemplateId());
+
+            return R.ok("已提交,正在后台处理...");
+
+        } catch (Exception e) {
+            log.error("【排期创建请求createSchedule】提交异步任务失败, traceId={}, 请求参数: {}", traceId, request, e);
+            return R.fail("系统内部错误,提交失败");
+        } finally {
+            MDC.remove("traceId"); // 清理 MDC
+        }
      }
 
     @PostMapping("/updateScheduleConfig")
     public R<String> updateScheduleConfig(@Valid @RequestBody ScheduleConfigRequestBo request) {
-        return scheduleConfigService.updateScheduleConfig(request.getConfigId(), request);
+        // 🌟 1. 记录请求进入(建议用 MDC 添加 traceId)
+        String traceId = UUID.randomUUID().toString().substring(0, 8);
+        MDC.put("traceId", traceId); // 用于链路追踪
+
+        log.info("【排期创建请求updateScheduleConfig】收到创建排期请求, traceId={}, 请求参数: {}", traceId, request);
+
+        try {
+            // 🌟 2. 提交异步任务
+            CompletableFuture<R<String>> future = scheduleConfigAsyncService.updateScheduleConfigAsync(request.getConfigId(),request);
+
+            log.info("【排期创建请求updateScheduleConfig】异步任务已提交, traceId={}, configId={}", traceId, request.getTemplateId());
+
+            return R.ok("已提交,正在后台处理...");
+
+        } catch (Exception e) {
+            log.error("【排期创建请求updateScheduleConfig】提交异步任务失败, traceId={}, 请求参数: {}", traceId, request, e);
+            return R.fail("系统内部错误,提交失败");
+        } finally {
+            MDC.remove("traceId"); // 清理 MDC
+        }
     }
 
     @DeleteMapping("/deleteScheduleConfig/{id}")

+ 6 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/ScheduleTournamentsReletion.java

@@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.*;
 import lombok.Data;
 
 import java.io.Serial;
-import java.time.LocalDateTime;
+
 
 /**
  * 赛事分配的模版关系对象 schedule_tournaments_reletion
@@ -40,5 +40,10 @@ public class ScheduleTournamentsReletion {
      */
     private String scBeginTime;
 
+    /**
+     * 模版配置ID
+     */
+    private Long configId;
+
 
 }

+ 3 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/MessageReceiversMapper.java

@@ -42,4 +42,7 @@ public interface MessageReceiversMapper extends BaseMapperPlus<MessageReceivers,
     @InterceptorIgnore(tenantLine = "true")
     int batchInsertMessageReceiver(@Param("list") List<MessageReceivers> list);
 
+    @InterceptorIgnore(tenantLine = "true")
+    MessageReceiversVo selectVoRewardIdById(@Param("rewardId") Long rewardId);
+
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/ScheduleTournamentsReletionMapper.java

@@ -23,7 +23,7 @@ public interface ScheduleTournamentsReletionMapper extends BaseMapperPlus<Schedu
     int insertScheduleRelation(ScheduleTournamentsReletion scheduleTournamentsReletion);
 
     @InterceptorIgnore(tenantLine = "true")
-    int selectByScheduleRelation(@Param("templateId") Long templateId, @Param("beginTime") LocalDateTime beginTime);
+    int selectByScheduleRelation(@Param("templateId") Long templateId, @Param("beginTime") LocalDateTime beginTime,@Param("configId") Long configId);
 
     @InterceptorIgnore(tenantLine = "true")
     int selectByScheduleRelationExit(@Param("templateId") Long templateId);

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/UserMessageStatusMapper.java

@@ -21,5 +21,7 @@ public interface UserMessageStatusMapper extends BaseMapperPlus<UserMessageStatu
     @InterceptorIgnore(tenantLine = "true")
     int updateUserMessageClaimed(@Param("rewardId") Long rewardId);
 
+    @InterceptorIgnore(tenantLine = "true")
+    int updateUserMessageRewardId(@Param("rewardId") Long rewardId,@Param("messageId") Long messageId);
 
 }

+ 96 - 84
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/RewardClaimsServiceImpl.java

@@ -7,17 +7,12 @@ import org.dromara.business.domain.PlayerItems;
 import org.dromara.business.domain.PlayersItemsLog;
 import org.dromara.business.domain.RewardClaims;
 import org.dromara.business.domain.bo.RewardClaimsBo;
-import org.dromara.business.domain.enums.ItermTypeLogEnum;
 import org.dromara.business.domain.enums.RewardStatusEnum;
-import org.dromara.business.domain.vo.ItemsVo;
-import org.dromara.business.domain.vo.PlayerItemsVo;
-import org.dromara.business.domain.vo.RewardClaimsVo;
-import org.dromara.business.domain.vo.RewardVo;
+import org.dromara.business.domain.vo.*;
 import org.dromara.business.mapper.*;
 import org.dromara.business.service.IItemsService;
 import org.dromara.business.service.IRewardClaimsService;
 import org.dromara.business.utils.ItemOperationLock;
-import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -65,6 +60,8 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
     private final ItemsMapper itemsMapper;
 
 
+    private final MessageReceiversMapper messageReceiversMapper;
+
     /**
      * 查询用户参赛
      *
@@ -269,101 +266,116 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
         try {
             // 1. 校验领取状态,防止重复领取
             RewardClaimsVo rewardClaimsVo = baseMapper.selectInfoById(bo.getId());
-            if (rewardClaimsVo.getClaimed()!=0L) {
-                throw new RuntimeException("该奖励已处理,请勿重复操作");
-            }
-            String rewardKey="reward:"+bo.getId();
-            if(RedisUtils.isExistsObject(rewardKey)){
-                throw new RuntimeException("该奖励已处理,请勿重复操作");
-            }
+            // 是否已领取奖励  0未领取  1已领取 2 已提交待审核
+            if (rewardClaimsVo.getClaimed()==2L) {
+                String rewardKey="reward:"+bo.getId();
+                if(RedisUtils.isExistsObject(rewardKey)){
+                    throw new RuntimeException("该奖励已处理,请勿重复操作");
+                }
 
-            // TODO 验证 在校验领取记录里面是否存在  奖励发放之后放入redis中 表示已经发放 SYSTEM
-            RedisUtils.setCacheObject(rewardKey, bo.getId(), Duration.ofMinutes(60*24));
+                // TODO 验证 在校验领取记录里面是否存在  奖励发放之后放入redis中 表示已经发放 SYSTEM
+                RedisUtils.setCacheObject(rewardKey, bo.getId(), Duration.ofMinutes(60*24));
 
-            // 2. 解析 JSON 奖励数据(保留原始 Map 方式)
-            String rewardJson = bo.getRewardJson();
-            List<Map<String, Object>> list = objectMapper.readValue(
-                rewardJson,
-                new TypeReference<List<Map<String, Object>>>() {}
-            );
+                // 2. 解析 JSON 奖励数据(保留原始 Map 方式)
+                String rewardJson = bo.getRewardJson();
+                List<Map<String, Object>> list = objectMapper.readValue(
+                    rewardJson,
+                    new TypeReference<List<Map<String, Object>>>() {}
+                );
 
-            List<PlayerItems> items = new ArrayList<>();
-            List<PlayersItemsLog> playersItemsLogs = new ArrayList<>();
+                List<PlayerItems> items = new ArrayList<>();
+                List<PlayersItemsLog> playersItemsLogs = new ArrayList<>();
 
-            for (Map<String, Object> item : list) {
-                Integer itemId = (Integer) item.get("itemId");
-                Integer quantity = (Integer) item.get("quantity");
+                for (Map<String, Object> item : list) {
+                    Integer itemId = (Integer) item.get("itemId");
+                    Integer quantity = (Integer) item.get("quantity");
 
-                if (itemId == null || quantity == null) {
-                    throw new IllegalArgumentException("道具ID或数量不能为空");
-                }
+                    if (itemId == null || quantity == null) {
+                        throw new IllegalArgumentException("道具ID或数量不能为空");
+                    }
 
-                Long playerId = bo.getPlayerId();
-
-                PlayerItems playerItem = new PlayerItems();
-                playerItem.setPlayerId(playerId);
-                playerItem.setItemId(itemId.longValue());
-                playerItem.setQuantity(quantity.longValue());
-
-                items.add(playerItem);
-
-                ItemsVo itemsVo = itemsMapper.selectVoByIdInfo(itemId.longValue());
-
-                // 查询玩家当前道具信息
-                PlayerItemsVo playerItemsVos = playerItemsMapper.selectPlayerItems(playerItem);
-                Integer beforeNum = playerItemsVos != null ? Integer.valueOf(playerItemsVos.getQuantity().toString()) : 0;
-                Integer afterNum = beforeNum + quantity;
-
-                PlayersItemsLog logEntry = new PlayersItemsLog();
-                logEntry.setItemId(itemId.longValue());
-                logEntry.setScoreNum(quantity.longValue());
-                logEntry.setAfterNum(afterNum.longValue());
-                logEntry.setUserId(playerId);
-                logEntry.setType(1L);
-                logEntry.setBeforeNum(beforeNum.longValue());
-            /*    logEntry.setItemType(ItermTypeLogEnum.COMPETITION.getCode());*/
-                logEntry.setItemTypeText(itemsVo.getName());
-                logEntry.setRemark(itemsVo.getItemDesc());
-                playersItemsLogs.add(logEntry);
-            }
+                    Long playerId = bo.getPlayerId();
 
-            // 3. 获取分布式锁
-            boolean lockAcquired = ItemOperationLock.tryLock(bo.getPlayerId(), 3000);
-            if (!lockAcquired) {
-                throw new RuntimeException("获取道具操作锁失败,请稍后再试");
-            }
+                    PlayerItems playerItem = new PlayerItems();
+                    playerItem.setPlayerId(playerId);
+                    playerItem.setItemId(itemId.longValue());
+                    playerItem.setQuantity(quantity.longValue());
 
-            try {
+                    items.add(playerItem);
 
-                // 4. 插入道具日志
-                int logCount = playersItemsLogMapper.batchInsertPlayerItemLog(playersItemsLogs);
-                if (logCount <= 0) {
-                    throw new RuntimeException("道具日志记录失败");
-                }
+                    ItemsVo itemsVo = itemsMapper.selectVoByIdInfo(itemId.longValue());
 
-                // 5. 批量插入或更新道具
-                int insertCount = playerItemsMapper.batchInsertOrUpdatePlayerItems(items);
-                if (insertCount <= 0) {
-                    throw new RuntimeException("道具发放失败");
+                    // 查询玩家当前道具信息
+                    PlayerItemsVo playerItemsVos = playerItemsMapper.selectPlayerItems(playerItem);
+                    Integer beforeNum = playerItemsVos != null ? Integer.valueOf(playerItemsVos.getQuantity().toString()) : 0;
+                    Integer afterNum = beforeNum + quantity;
+
+                    PlayersItemsLog logEntry = new PlayersItemsLog();
+                    logEntry.setItemId(itemId.longValue());
+                    logEntry.setScoreNum(quantity.longValue());
+                    logEntry.setAfterNum(afterNum.longValue());
+                    logEntry.setUserId(playerId);
+                    logEntry.setType(1L);
+                    logEntry.setBeforeNum(beforeNum.longValue());
+                    /*    logEntry.setItemType(ItermTypeLogEnum.COMPETITION.getCode());*/
+                    logEntry.setItemTypeText(itemsVo.getName());
+                    logEntry.setRemark(itemsVo.getItemDesc());
+                    playersItemsLogs.add(logEntry);
                 }
-                // 7. 更新奖励记录状态
-                int rewardUpdateCount = baseMapper.updateUserRewardClaimed(bo.getId());
-                if (rewardUpdateCount <= 0) {
-                    throw new RuntimeException("更新奖励记录失败");
+
+                // 3. 获取分布式锁
+                boolean lockAcquired = ItemOperationLock.tryLock(bo.getPlayerId(), 3000);
+                if (!lockAcquired) {
+                    throw new RuntimeException("获取道具操作锁失败,请稍后再试");
                 }
 
-               // TODO app收到消息  用户提交领取状态   审核  发放
-                // 6. 更新用户消息状态
-                int messageUpdateCount = userMessageStatusMapper.updateUserMessageClaimed(bo.getId());
-                if (messageUpdateCount <= 0) {
-                    throw new RuntimeException("更新用户消息状态失败");
+                try {
+
+                    // 4. 插入道具日志
+                    int logCount = playersItemsLogMapper.batchInsertPlayerItemLog(playersItemsLogs);
+                    if (logCount <= 0) {
+                        throw new RuntimeException("道具日志记录失败");
+                    }
+
+                    // 5. 批量插入或更新道具
+                    int insertCount = playerItemsMapper.batchInsertOrUpdatePlayerItems(items);
+                    if (insertCount <= 0) {
+                        throw new RuntimeException("道具发放失败");
+                    }
+                    // 7. 更新奖励记录状态
+                    int rewardUpdateCount = baseMapper.updateUserRewardClaimed(bo.getId());
+                    if (rewardUpdateCount <= 0) {
+                        throw new RuntimeException("更新奖励记录失败");
+                    }
+
+                    //todo  查询用户是哪条消息 根据 reward_claims中的id  需要修改
+
+                    MessageReceiversVo receiversVo = messageReceiversMapper.selectVoRewardIdById(bo.getId());
+                    if(receiversVo!=null){
+
+                        // 更新状态表的 reward_claims中的id 进 user_message_status 中
+                        userMessageStatusMapper.updateUserMessageRewardId(receiversVo.getRewardId(), receiversVo.getId());
+
+                        // TODO app收到消息  用户提交领取状态   审核  发放      修改消息状态表的领取状态
+                        userMessageStatusMapper.updateUserMessageClaimed(bo.getId());
+
+                        // TODO app收到消息  用户提交领取状态   审核  发放
+                        // 6. 更新用户消息状态
+                    /*int messageUpdateCount = userMessageStatusMapper.updateUserMessageClaimed(bo.getId());
+                    if (messageUpdateCount <= 0) {
+                        throw new RuntimeException("更新用户消息状态失败");
+                    }*/
+                    }
+
+                } finally {
+                    ItemOperationLock.releaseLock(bo.getPlayerId()); // 确保释放锁
                 }
 
-            } finally {
-                ItemOperationLock.releaseLock(bo.getPlayerId()); // 确保释放锁
+                return Boolean.TRUE;
+            }else{
+                throw new RuntimeException("该奖励已处理,请勿重复操作");
             }
 
-            return Boolean.TRUE;
 
         } catch (Exception e) {
             log.error("审核并发放奖励过程中发生异常,rewardId={}", bo.getId(), e);

+ 45 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/ScheduleConfigAsyncService.java

@@ -0,0 +1,45 @@
+package org.dromara.business.service.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.business.domain.bo.ScheduleConfigRequestBo;
+import org.dromara.business.service.IScheduleConfigService;
+import org.dromara.common.core.domain.R;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.CompletableFuture;
+
+@Service
+@Slf4j
+public class ScheduleConfigAsyncService {
+
+    @Autowired
+    private IScheduleConfigService scheduleConfigService; // 假设你的业务逻辑在 Service 层
+
+    @Async
+    public CompletableFuture<R<String>> saveScheduleConfigAsync(ScheduleConfigRequestBo dto) {
+        try {
+            // 调用真正的业务逻辑(可提取到 Service)
+            R<String> result = scheduleConfigService.saveScheduleConfig(dto);
+            return CompletableFuture.completedFuture(result);
+        } catch (Exception e) {
+            log.error("异步保存排期配置失败", e);
+            return CompletableFuture.completedFuture(R.fail("内部错误:" + e.getMessage()));
+        }
+    }
+
+
+    @Async
+    public CompletableFuture<R<String>> updateScheduleConfigAsync(Long configId,ScheduleConfigRequestBo dto) {
+        try {
+            // 调用真正的业务逻辑(可提取到 Service)
+            R<String> result = scheduleConfigService.updateScheduleConfig(configId,dto);
+            return CompletableFuture.completedFuture(result);
+        } catch (Exception e) {
+            log.error("异步保存排期配置失败", e);
+            return CompletableFuture.completedFuture(R.fail("内部错误:" + e.getMessage()));
+        }
+    }
+}
+

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/ScheduleConfigServiceImpl.java

@@ -212,7 +212,7 @@ public class ScheduleConfigServiceImpl implements IScheduleConfigService {
         // 6. ✅ 预生成执行计划
         generateExecutionPlan(configId, dto.getCreationSchemeCode(), startDate, endDate, dto.getRepeatTypes(), dto.getExecTimes());
 
-        //7 模版变成已使用
+        //7 模版变成 投放中
         tournamentsTemplateMapper.updateUseTournamentTemplate(dto.getTemplateId());
 
         return R.ok();

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/TournamentsTemplateServiceImpl.java

@@ -140,7 +140,7 @@ public class TournamentsTemplateServiceImpl implements ITournamentsTemplateServi
             Long tournamentId = record.getId();
 
             if(record.getStatus()==1L){
-                record.setStatusText("使用中");
+                record.setStatusText("投放中");
             }else if(record.getStatus()==2L){
                 record.setStatusText("未使用");
             }

+ 0 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/service/impl/UserServiceImpl.java

@@ -344,7 +344,6 @@ public class UserServiceImpl implements IUserService {
         logEntry.setBeforeNum(beforeNum.longValue());
         logEntry.setItemTypeText(itemsVo.getName());
         logEntry.setRemark(itemsVo.getItemDesc());
-
         int insertResult = playersItemsLogMapper.insertPlayerItemLog(logEntry);
         if (insertResult <= 0) {
             throw new RuntimeException("道具日志记录失败");

+ 119 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/business/ScheduleTask.java

@@ -82,14 +82,13 @@ public class ScheduleTask {
                 LocalDateTime triggerTime = LocalDateTime.of(exec.getExecutionDate(), exec.getExecutionTime());
 
                 // 再次防重(可选)
-             /*   if (scheduleTournamentsReletionMapper.selectByScheduleRelation(config.getTemplateId(), triggerTime>0) {
+                if (scheduleTournamentsReletionMapper.selectByScheduleRelation(config.getTemplateId(), triggerTime, config.getId())>0) {
                     log.debug("比赛已存在,跳过: {}", triggerTime);
                     scheduleExecutionMapper.updateSelective(exec.getId(), "SKIPPED");
                     continue;
                 }
-*/
                 // ✅ 创建比赛
-                autowiredTournamentData(config.getTemplateId(), triggerTime);
+                autowiredTournamentData(config.getTemplateId(), triggerTime,config.getId());
 
 
                 scheduleExecutionMapper.updateSelective(exec.getId(), "SUCCESS");
@@ -104,12 +103,121 @@ public class ScheduleTask {
     }
 
 
+
+
+
+    /**
+     * 每周一 00:10 执行,生成未来一周的数据
+     */
+    @Scheduled(cron = "0 10 00 ? * MON")
+    public void generateMatchesForNextWeek() {
+        LocalDate today = LocalDate.now();
+        log.info("开始生成未来一周比赛: {}", today);
+
+        // 获取未来一周的日期列表
+        List<LocalDate> futureDates = getFutureDates(7);
+
+        for (LocalDate date : futureDates) {
+            List<ScheduleExecutionVo> executions = scheduleExecutionMapper.findTodayPendingExecutions(date);
+
+            for (ScheduleExecutionVo exec : executions) {
+                try {
+                    ScheduleConfigVo config = baseMapper.selectScheduleConfigById(exec.getConfigId());
+                    if (config == null) {
+                        log.warn("配置不存在: execId={}", exec.getId());
+                        scheduleExecutionMapper.updateSelective(exec.getId(), "FAILED");
+                        continue;
+                    }
+
+                    LocalDateTime triggerTime = LocalDateTime.of(date, exec.getExecutionTime());
+
+
+                    // 再次防重(可选)
+                    if (scheduleTournamentsReletionMapper.selectByScheduleRelation(config.getTemplateId(), triggerTime, config.getId())>0) {
+                        log.debug("比赛已存在,跳过: {}", triggerTime);
+                        scheduleExecutionMapper.updateSelective(exec.getId(), "SKIPPED");
+                        continue;
+                    }
+
+                    // 创建比赛
+                    autowiredTournamentData(config.getTemplateId(), triggerTime,config.getId());
+
+                    scheduleExecutionMapper.updateSelective(exec.getId(), "SUCCESS");
+
+                } catch (Exception e) {
+                    log.error("创建比赛失败: execId={}", exec.getId(), e);
+                    scheduleExecutionMapper.updateSelective(exec.getId(), "FAILED");
+                }
+            }
+            log.info("未来一周比赛生成完成,共处理 {} 条", executions.size());
+        }
+    }
+
+
+    /**
+     * 每天 00:10 执行,生成未来三天的数据
+     */
+    @Scheduled(cron = "0 10 00 * * ?")
+    public void generateMatchesForNextThreeDays() {
+        LocalDate today = LocalDate.now();
+        log.info("开始生成未来三天比赛: {}", today);
+
+        // 获取未来三天的日期列表
+        List<LocalDate> futureDates = getFutureDates(3);
+
+        for (LocalDate date : futureDates) {
+            List<ScheduleExecutionVo> executions = scheduleExecutionMapper.findTodayPendingExecutions(date);
+
+            for (ScheduleExecutionVo exec : executions) {
+                try {
+                    ScheduleConfigVo config = baseMapper.selectScheduleConfigById(exec.getConfigId());
+                    if (config == null) {
+                        log.warn("配置不存在: execId={}", exec.getId());
+                        scheduleExecutionMapper.updateSelective(exec.getId(), "FAILED");
+                        continue;
+                    }
+
+                    LocalDateTime triggerTime = LocalDateTime.of(date, exec.getExecutionTime());
+
+                    // 再次防重(可选)
+                    if (scheduleTournamentsReletionMapper.selectByScheduleRelation(config.getTemplateId(), triggerTime, config.getId())>0) {
+                        log.debug("比赛已存在,跳过: {}", triggerTime);
+                        scheduleExecutionMapper.updateSelective(exec.getId(), "SKIPPED");
+                        continue;
+                    }
+
+                    // 创建比赛
+                    autowiredTournamentData(config.getTemplateId(), triggerTime,config.getId());
+
+                    scheduleExecutionMapper.updateSelective(exec.getId(), "SUCCESS");
+
+                } catch (Exception e) {
+                    log.error("创建比赛失败: execId={}", exec.getId(), e);
+                    scheduleExecutionMapper.updateSelective(exec.getId(), "FAILED");
+                }
+            }
+            log.info("未来三天比赛生成完成,共处理 {} 条", executions.size());
+        }
+
+
+    }
+
+
+    private List<LocalDate> getFutureDates(int days) {
+        LocalDate today = LocalDate.now();
+        List<LocalDate> dates = new ArrayList<>();
+        for (int i = 0; i < days; i++) {
+            dates.add(today.plusDays(i));
+        }
+        return dates;
+    }
+
     /**
      * 自动组装赛事数据
      * @param templateId
      * @return
      */
-    public Boolean autowiredTournamentData(Long templateId,LocalDateTime triggerTime) {
+    public Boolean autowiredTournamentData(Long templateId,LocalDateTime triggerTime,Long configId) {
         try {
                 TournamentsVo tournamentsVo = tournamentsTemplateMapper.selectVoByIdInfoTemplate(templateId);
                 // 模拟构造 TournamentsDto 数据
@@ -184,8 +292,15 @@ public class ScheduleTask {
             scheduleTournamentsReletion.setTournamentsId(bo.getId());
             scheduleTournamentsReletion.setTournamentsTemplateId(templateId);
             scheduleTournamentsReletion.setScBeginTime(startTime);
+            scheduleTournamentsReletion.setConfigId(configId);
             scheduleTournamentsReletionMapper.insertScheduleRelation(scheduleTournamentsReletion);
 
+            //todo 生成完成之后  自动化模版状态变成 使用中
+            ScheduleConfig scheduleConfig = new ScheduleConfig();
+            scheduleConfig.setId(configId);
+            scheduleConfig.setEnabled(true);
+            baseMapper.updateScheduleConfig(scheduleConfig);
+
             return true;
         } catch (Exception e) {
             log.error("批量插入赛事过程中发生异常", e);

+ 19 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/MessageReceiversMapper.xml

@@ -152,4 +152,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
 
+    <select id="selectVoRewardIdById" resultType="org.dromara.business.domain.vo.MessageReceiversVo">
+        SELECT
+            id,
+            user_id,
+            title,
+            content,
+            target_type,
+            reward_id,
+            template_code,
+            message_type,
+            create_by,
+            send_time,
+            created_at,
+            updated_at,
+            send_name
+        FROM message_receivers
+        WHERE reward_id = #{rewardId} LIMIT 1
+    </select>
+
 </mapper>

+ 3 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/ScheduleConfigMapper.xml

@@ -152,5 +152,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         FROM schedule_config sc  where  template_id=#{templateId}
     </select>
 
+    <update id="updateConfigStatus">
+        update schedule_config set enabled=#{enabled} where id=#{id}
+    </update>
 
 </mapper>

+ 3 - 1
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/ScheduleTournamentsReletionMapper.xml

@@ -11,12 +11,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="tournamentsId != null">tournaments_id,</if>
             <if test="tournamentsTemplateId != null">tournaments_template_id,</if>
+            <if test="configId != null">config_id,</if>
             <if test="scBeginTime != null">sc_begin_time,</if>
             create_time
         </trim>
         <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
             <if test="tournamentsId != null">#{tournamentsId},</if>
             <if test="tournamentsTemplateId != null">#{tournamentsTemplateId},</if>
+            <if test="configId != null">#{configId},</if>
             <if test="scBeginTime != null">#{scBeginTime},</if>
             now()
         </trim>
@@ -37,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         SELECT
            count(1)
         FROM schedule_tournaments_reletion
-        WHERE tournaments_template_id = #{templateId} and sc_begin_time=#{beginTime}
+        WHERE tournaments_template_id = #{templateId} and sc_begin_time=#{beginTime} and config_id = #{configId}
     </select>
 
 

+ 9 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/UserMessageStatusMapper.xml

@@ -13,4 +13,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         WHERE  reward_id=#{rewardId}
     </update>
 
+    <update id="updateUserMessageRewardId">
+        UPDATE user_message_status
+        SET
+            reward_id = #{rewardId},audit_time=NOW()
+        WHERE  message_id=#{messageId}
+    </update>
+
+
+
 </mapper>