Selaa lähdekoodia

feat(business): 新增奖励申领日志功能并优化删除逻辑

- 新增 RewardClaimsLog相关实体类和 Mapper
- 实现奖励申领日志的记录功能
- 优化奖励申领删除逻辑,支持替补选手自动填充
- 更新相关 XML 文件,修正 SQL 语句
fugui001 4 kuukautta sitten
vanhempi
commit
20fdef3d41

+ 78 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/RewardClaimsLog.java

@@ -0,0 +1,78 @@
+package org.dromara.business.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import java.util.Date;
+import java.io.Serial;
+
+/**
+ * 被移除排名用户参赛获奖日志对象 reward_claims_log
+ *
+ * @author Lion Li
+ * @date 2025-08-26
+ */
+@Data
+@TableName("reward_claims_log")
+public class RewardClaimsLog{
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 赛事id
+     */
+    private Long tournamentId;
+
+    /**
+     * 用户id
+     */
+    private Long playerId;
+
+    /**
+     * 排名
+     */
+    private Long rank;
+
+    /**
+     * 实名
+     */
+    private String playerName;
+
+    /**
+     *
+     */
+    private String phone;
+
+    /**
+     * 奖励
+     */
+    private String rewardJson;
+
+    /**
+     * 是否审核  0未领取  1已领取 2 已提交待审核
+     */
+    private Long claimed;
+
+    /**
+     *
+     */
+    private Date createdAt;
+
+    /**
+     *
+     */
+    private Date updatedAt;
+
+    /**
+     * 是否删除
+     */
+    private Long isDelete;
+
+
+}

+ 88 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/bo/RewardClaimsLogBo.java

@@ -0,0 +1,88 @@
+package org.dromara.business.domain.bo;
+
+import org.dromara.business.domain.RewardClaimsLog;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+
+/**
+ * 被移除排名用户参赛获奖日志业务对象 reward_claims_log
+ *
+ * @author Lion Li
+ * @date 2025-08-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = RewardClaimsLog.class, reverseConvertGenerate = false)
+public class RewardClaimsLogBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 赛事id
+     */
+    private Long tournamentId;
+
+    /**
+     * 用户id
+     */
+    @NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long playerId;
+
+    /**
+     * 排名
+     */
+    @NotNull(message = "排名不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long rank;
+
+    /**
+     * 实名
+     */
+    @NotBlank(message = "实名不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String playerName;
+
+    /**
+     *
+     */
+    @NotBlank(message = "不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String phone;
+
+    /**
+     * 奖励
+     */
+    private String rewardJson;
+
+    /**
+     * 是否审核  0未领取  1已领取 2 已提交待审核
+     */
+    @NotNull(message = "是否审核  0未领取  1已领取 2 已提交待审核 不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long claimed;
+
+    /**
+     *
+     */
+    @NotNull(message = "不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Date createdAt;
+
+    /**
+     *
+     */
+    @NotNull(message = "不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Date updatedAt;
+
+    /**
+     * 是否删除
+     */
+    private Long isDelete;
+
+
+}

+ 97 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/RewardClaimsLogVo.java

@@ -0,0 +1,97 @@
+package org.dromara.business.domain.vo;
+
+import java.util.Date;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.business.domain.RewardClaimsLog;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+
+
+/**
+ * 被移除排名用户参赛获奖日志视图对象 reward_claims_log
+ *
+ * @author Lion Li
+ * @date 2025-08-26
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = RewardClaimsLog.class)
+public class RewardClaimsLogVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 赛事id
+     */
+    @ExcelProperty(value = "赛事id")
+    private Long tournamentId;
+
+    /**
+     * 用户id
+     */
+    @ExcelProperty(value = "用户id")
+    private Long playerId;
+
+    /**
+     * 排名
+     */
+    @ExcelProperty(value = "排名")
+    private Long rank;
+
+    /**
+     * 实名
+     */
+    @ExcelProperty(value = "实名")
+    private String playerName;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private String phone;
+
+    /**
+     * 奖励
+     */
+    @ExcelProperty(value = "奖励")
+    private String rewardJson;
+
+    /**
+     * 是否审核  0未领取  1已领取 2 已提交待审核
+     */
+    @ExcelProperty(value = "是否审核  0未领取  1已领取 2 已提交待审核 ")
+    private Long claimed;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Date createdAt;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Date updatedAt;
+
+    /**
+     * 是否删除
+     */
+    @ExcelProperty(value = "是否删除")
+    private Long isDelete;
+
+
+}

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/domain/vo/RewardVo.java

@@ -22,4 +22,6 @@ public class RewardVo implements Serializable {
 
     private String itemName;
 
+    //[{"itemId": 1001, "ranking": 1, "quantity": 1, "itemsName": "三湘杯资格卡"}]
+
 }

+ 36 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/business/mapper/RewardClaimsLogMapper.java

@@ -0,0 +1,36 @@
+package org.dromara.business.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.business.domain.RewardClaimsLog;
+import org.dromara.business.domain.vo.RewardClaimsLogVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+/**
+ * 被移除排名用户参赛获奖日志Mapper接口
+ *
+ * @author Lion Li
+ * @date 2025-08-26
+ */
+@DS("mysql2")
+public interface RewardClaimsLogMapper extends BaseMapperPlus<RewardClaimsLog, RewardClaimsLogVo> {
+
+    @InterceptorIgnore(tenantLine = "true")
+    Page<RewardClaimsLogVo> selectRewardClaimsLogByCondition(@Param("page") Page<RewardClaimsLog> page, @Param("ew") Wrapper<RewardClaimsLog> wrapper);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int insertRewardClaimsLog(RewardClaimsLog rewardClaimsLog);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int updateRewardClaimsLogById(RewardClaimsLog rewardClaimsLog);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int deleteById(Long id);
+
+    @InterceptorIgnore(tenantLine = "true")
+    RewardClaimsLogVo selectRewardClaimsLogById(Long id);
+
+
+}

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

@@ -6,13 +6,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.dromara.business.domain.PlayerItems;
 import org.dromara.business.domain.PlayersItemsLog;
 import org.dromara.business.domain.RewardClaims;
+import org.dromara.business.domain.RewardClaimsLog;
 import org.dromara.business.domain.bo.RewardClaimsBo;
 import org.dromara.business.domain.enums.RewardStatusEnum;
 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.service.IUserService;
 import org.dromara.business.utils.ItemOperationLock;
+import org.dromara.business.utils.RedisKeys;
+import org.dromara.business.utils.RedisUtil;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -25,11 +29,13 @@ import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.time.Duration;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 用户参赛Service业务层处理
@@ -64,6 +70,17 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
 
     private final UserComplaintsMapper userComplaintsMapper;
 
+    private final RewardClaimsLogMapper rewardClaimsLogMapper;
+
+    private final PrizeDistributionsMapper prizeDistributionsMapper;
+
+    private final PrizeDistributionItemsMapper prizeDistributionItemsMapper;
+
+    private final IUserService iUserService;
+
+
+    @Autowired
+    RedisUtil redisUtil;
 
     /**
      * 查询用户参赛
@@ -192,17 +209,103 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
             RewardClaimsVo rewardClaimsVo = baseMapper.selectInfoById(bo.getId());
 
             // 检查是否存在并且已被认领
-            if (rewardClaimsVo == null || rewardClaimsVo.getClaimed() != 1) {
+            if (rewardClaimsVo == null) {
                 logger.warn("Attempt to delete unclaimed or non-existent reward claim. ID: {}", bo.getId());
                 return false;
             }
 
-            // 执行删除操作
+            //获奖名单信息  只要有认领了 审核通过后就不能删除了   都是未领取才能删除
+            List<RewardClaimsVo> rewardClaimsVosList = baseMapper.selectByCriteria(bo.getTournamentId());
+            boolean hasClaimed = rewardClaimsVosList.stream()
+                .anyMatch(vo -> vo.getClaimed() != null && vo.getClaimed() == 1);
+            if(hasClaimed){
+                return false;
+            }
+
+
+            // 执行删除操作 baseMapper.deleteByCriteria(bo.getId(), bo.getTournamentId())
             int rowsAffected = baseMapper.deleteByCriteria(bo.getId(), bo.getTournamentId());
 
             // 判断删除是否成功
             boolean isDeleted = rowsAffected > 0;
             if (isDeleted) {
+                //本次奖品信息
+                List<RewardVo> itemsPrizeList=new ArrayList<>();
+                //排名
+                List<PrizeDistributionsVo> prizeDistributionsVos = prizeDistributionsMapper.selectByTournamentId(bo.getTournamentId());
+                if(prizeDistributionsVos!=null){
+                    // 提取并按排名正序排序后,取出 id 列表
+                    List<Long> ids = prizeDistributionsVos.stream()
+                        .sorted(Comparator.comparing(PrizeDistributionsVo::getPaiming))
+                        .map(PrizeDistributionsVo::getId)
+                        .collect(Collectors.toList());
+                    for (Long id2 : ids) {
+                        //奖品
+                        PrizeDistributionItemsVo prizeDistributionItemsVos = prizeDistributionItemsMapper.selectByPrizeDistributionId(id2);
+                        RewardVo rewardVo = new RewardVo();
+                        rewardVo.setItemId(prizeDistributionItemsVos.getItemId());
+                        rewardVo.setItemName(prizeDistributionItemsVos.getItemsName());
+                        rewardVo.setQuantity(prizeDistributionItemsVos.getQuantity());
+                        itemsPrizeList.add(rewardVo);
+                    }
+                }
+                String itemsPrizeListString = "";
+                if(itemsPrizeList.size()>0){
+                    try {
+                        itemsPrizeListString = objectMapper.writeValueAsString(itemsPrizeList);
+                    } catch (JsonProcessingException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println(itemsPrizeListString);
+                }
+
+                //获奖名单信息
+                for (RewardClaimsVo claimsVo : rewardClaimsVosList) {
+                    //先把操作的记录赋值的到日志表
+                    RewardClaimsLog rewardClaimsLog = new RewardClaimsLog();
+
+                    // 复制同名同类型的属性(自动忽略不匹配的字段)
+                    BeanUtils.copyProperties(claimsVo, rewardClaimsLog);
+                    // 插入日志记录
+                    rewardClaimsLogMapper.insertRewardClaimsLog(rewardClaimsLog);
+                }
+                //删除原来的获奖信息列表
+                for (RewardClaimsVo claimsVo : rewardClaimsVosList) {
+                    baseMapper.deleteById(claimsVo.getId());
+                }
+
+                //排名列表信息
+                //todo 删除成功之后进行替补  1:后面的往前推送  增加记录表  记录源数据来源  2:修改列表排名数据
+                Long tournamentId=bo.getTournamentId();
+                String leaderboardJson = redisUtil.get(RedisKeys.tournamentLeaderboard(tournamentId));
+                ObjectMapper objectMapper = new ObjectMapper();
+
+                List<PlayerVo> players = null;
+                players = objectMapper.readValue(leaderboardJson,
+                    objectMapper.getTypeFactory().constructCollectionType(List.class, PlayerVo.class));
+
+                // 3. 从 players 中取出前 claimedCount 名选手(防止越界)
+                List<PlayerVo> topPlayers = new ArrayList<>();
+                if (players != null && !players.isEmpty()) {
+                    int endIndex = Math.min(rewardClaimsVosList.size(), players.size()); // 防止索引越界
+                    topPlayers = players.subList(0, endIndex);
+                }
+                for (PlayerVo topPlayer : topPlayers) {
+                    UserVo userVo = iUserService.queryById(topPlayer.getId());
+                    RewardClaims rewardClaims=new RewardClaims();
+                    rewardClaims.setTournamentId(tournamentId);
+                    rewardClaims.setPlayerId(topPlayer.getId());
+                    rewardClaims.setRank(topPlayer.getRank());
+                    rewardClaims.setPlayerName(userVo.getNickName());
+                    rewardClaims.setClaimed(0L);
+                    if(userVo!=null){
+                        rewardClaims.setPhone(userVo.getPhone());
+                    }
+                    rewardClaims.setIsDelete(false);
+                    rewardClaims.setRewardJson(itemsPrizeListString);
+                    baseMapper.insert(rewardClaims);
+                }
+
                 logger.info("Reward claim successfully deleted. ID: {}, Tournament ID: {}", bo.getId(), bo.getTournamentId());
             } else {
                 logger.warn("Failed to delete reward claim. ID: {}, Tournament ID: {}", bo.getId(), bo.getTournamentId());
@@ -210,6 +313,7 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
 
             return isDeleted;
         } catch (Exception e) {
+            e.printStackTrace();
             logger.error("Error occurred while trying to delete reward claim. ID: {}, Tournament ID: {}", bo.getId(), bo.getTournamentId(), e);
             return false;
         }
@@ -328,6 +432,7 @@ public class RewardClaimsServiceImpl implements IRewardClaimsService {
                     /*    logEntry.setItemType(ItermTypeLogEnum.COMPETITION.getCode());*/
                     logEntry.setItemTypeText(itemsVo.getName());
                     logEntry.setRemark(itemsVo.getItemDesc());
+                    logEntry.setCreatedAt(new Date());
                     playersItemsLogs.add(logEntry);
                 }
 

+ 78 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/RewardClaimsLogMapper.xml

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.business.mapper.RewardClaimsLogMapper">
+
+
+
+
+    <!-- 根据 ID 查询(非删除状态) -->
+    <select id="selectRewardClaimsLogById" resultType="org.dromara.business.domain.vo.RewardClaimsLogVo">
+        SELECT *
+        FROM reward_claims_log
+        WHERE id = #{id}
+          AND (is_delete IS NULL OR is_delete = 0)
+    </select>
+
+    <!-- 条件查询(支持字段为空判断) -->
+    <select id="selectRewardClaimsLogByCondition" resultType="org.dromara.business.domain.vo.RewardClaimsLogVo">
+        SELECT *
+        FROM reward_claims_log
+        ${ew.customSqlSegment}
+    </select>
+
+    <!-- 更新语句:只更新非空字段 -->
+    <update id="updateRewardClaimsLogById">
+        UPDATE reward_claims_log
+        <set>
+            <if test="tournamentId != null">tournament_id = #{tournamentId},</if>
+            <if test="playerId != null">player_id = #{playerId},</if>
+            <if test="rank != null">rank = #{rank},</if>
+            <if test="playerName != null and playerName != ''">player_name = #{playerName},</if>
+            <if test="phone != null and phone != ''">phone = #{phone},</if>
+            <if test="rewardJson != null and rewardJson != ''">reward_json = #{rewardJson},</if>
+            <if test="claimed != null">claimed = #{claimed},</if>
+            <if test="isDelete != null">is_delete = #{isDelete},</if>
+            updated_at = NOW()
+        </set>
+        WHERE id = #{id}
+        AND (is_delete IS NULL OR is_delete = 0)
+    </update>
+
+    <!-- 逻辑删除:is_delete = 1 -->
+    <update id="deleteLogicById">
+        UPDATE reward_claims_log
+        SET is_delete = 1, updated_at = NOW()
+        WHERE id = #{id}
+          AND (is_delete IS NULL OR is_delete = 0)
+    </update>
+
+    <!-- 插入语句:字段非空才插入 -->
+    <insert id="insertRewardClaimsLog" useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO reward_claims_log
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="tournamentId != null">tournament_id,</if>
+            <if test="playerId != null">player_id,</if>
+            <if test="rank != null">`rank`,</if>  <!-- ⚠️ 加上反引号 -->
+            <if test="playerName != null and playerName != ''">player_name,</if>
+            <if test="phone != null and phone != ''">phone,</if>
+            <if test="rewardJson != null and rewardJson != ''">reward_json,</if>
+            <if test="claimed != null">claimed,</if>
+            <if test="isDelete != null">is_delete,</if>
+            created_at,
+            updated_at
+        </trim>
+        <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
+            <if test="tournamentId != null">#{tournamentId},</if>
+            <if test="playerId != null">#{playerId},</if>
+            <if test="rank != null">#{rank},</if>
+            <if test="playerName != null and playerName != ''">#{playerName},</if>
+            <if test="phone != null and phone != ''">#{phone},</if>
+            <if test="rewardJson != null and rewardJson != ''">#{rewardJson},</if>
+            <if test="claimed != null">#{claimed},</if>
+            <if test="isDelete != null">#{isDelete},</if>
+            NOW(), NOW()
+        </trim>
+    </insert>
+</mapper>

+ 2 - 2
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/RewardClaimsMapper.xml

@@ -29,7 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="tournamentId != null">tournament_id,</if>
             <if test="playerId != null">player_id,</if>
-            <if test="rank != null">rank,</if>
+            <if test="rank != null">`rank`,</if>
             <if test="playerName != null and playerName != ''">player_name,</if>
             <if test="phone != null and phone != ''">phone,</if>
             <if test="rewardJson != null">reward_json,</if>
@@ -42,7 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="rank != null">#{rank},</if>
             <if test="playerName != null and playerName != ''">#{playerName},</if>
             <if test="phone != null and phone != ''">#{phone},</if>
-            <if test="rewardJson != null">#{rewardJson, typeHandler=org.apache.ibatis.type.JdbcType.VARCHAR},</if>
+            <if test="rewardJson != null">#{rewardJson},</if>
             <if test="claimed != null">#{claimed},</if>
         </trim>
     </insert>

+ 1 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/business/UserComplaintsMapper.xml

@@ -161,6 +161,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                               left join  tournaments c  on a.tournament_id=c.id
         WHERE a.tournament_id =  #{tournamentId}  and a.status not in (2,3)
         <if test="userId != null">and a.user_id = #{userId}</if>
+        limit 1
     </select>
 
 </mapper>