peng
2025-08-21 b2a68b1eaa6db1c1456534e084d66fe98e4443f0
抽奖活动
16个文件已修改
15个文件已添加
1168 ■■■■■ 已修改文件
buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java 413 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java
New file
@@ -0,0 +1,52 @@
package cn.lili.controller.lmk;
import cn.lili.base.Result;
import cn.lili.modules.lmk.domain.entity.PrizeRecord;
import cn.lili.modules.lmk.service.PrizeService;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Validated
@RequiredArgsConstructor
@Api(value = "小程序抽奖活动接口", tags = "小程序抽奖活动接口")
@RestController
@RequestMapping("/buyer/lmk/prize")
public class PrizeController {
    private final PrizeService prizeService;
    /**
     * 抽奖
     *
     * @param prizeActivityId
     * @return
     */
    @PostMapping("/{prizeActivityId}")
    public Result prize(@PathVariable String prizeActivityId) {
        return prizeService.prize(prizeActivityId);
    }
    /**
     * 获取抽奖次数
     *
     * @param prizeActivityId
     * @return
     */
    @PostMapping("/prizeNum/{prizeActivityId}")
    public Result prizeNum(@PathVariable String prizeActivityId) {
        return prizeService.prizeNum(prizeActivityId);
    }
    /**
     * 获取获取抽奖页面信息
     *
     * @param prizeActivityId
     * @return
     */
    @PostMapping("/prizeInfo/{prizeActivityId}")
    public Result prizeInfo(@PathVariable String prizeActivityId) {
        return prizeService.prizeInfo(prizeActivityId);
    }
}
framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java
@@ -57,7 +57,7 @@
            }
            //如果有扩展消息,则输出异常中,跟随补充异常
            if (!serviceException.getMsg().equals(ServiceException.DEFAULT_MESSAGE)) {
                message += ":" + serviceException.getMsg();
                message = serviceException.getMsg();
            }
            // 对一些特殊异常处理,不再打印error级别的日志
framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java
@@ -27,6 +27,13 @@
    private String commentGroup;
    /**
     * 抽奖活动
     */
    private String prizeTopic;
    private String prizeGroup;
    /**
     * 视频
     */
    private String videoTopic;
framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java
@@ -164,11 +164,13 @@
    @ApiModelProperty(value = "预售结束时间")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private Date preSaleEndDate;
    @ApiModelProperty(value = "预售开始时间")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private Date preSaleBeginDate;
    @ApiModelProperty(value = "抽成比例")
    private BigDecimal commission;
@@ -192,6 +194,11 @@
        this.mobileIntro = goodsOperationDTO.getMobileIntro();
        this.goodsVideo = goodsOperationDTO.getGoodsVideo();
        this.price = goodsOperationDTO.getPrice();
        //不是预售商品预售时间置空
        if (!GoodsSalesModeEnum.PRESALE.name().equals(goodsOperationDTO.getSalesModel())) {
            goodsOperationDTO.setPreSaleBeginDate(null);
            goodsOperationDTO.setPreSaleEndDate(null);
        }
        this.preSaleEndDate = goodsOperationDTO.getPreSaleEndDate();
        this.preSaleBeginDate = goodsOperationDTO.getPreSaleBeginDate();
        this.commission =  goodsOperationDTO.getCommission();
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java
@@ -3,9 +3,14 @@
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.ibatis.type.LocalDateTimeTypeHandler;
/**
 * 抽奖活动
@@ -27,13 +32,15 @@
    /** 活动描述 */
    private String activityDes;
    @TableField("begin_time")
    @TableField(value = "begin_time", typeHandler = LocalDateTimeTypeHandler.class)
    /** 活动开始时间 */
    private LocalDateTime beginTime;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date beginTime;
    @TableField("end_time")
    @TableField(value = "end_time", typeHandler = LocalDateTimeTypeHandler.class)
    /** 活动结束时间 */
    private LocalDateTime endTime;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;
    @TableField("max_prize")
    /** 每日最大抽奖上限 */
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java
New file
@@ -0,0 +1,62 @@
package cn.lili.modules.lmk.domain.entity;
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
 * 奖品发放记录
 *
 * @author peng
 * @since 2025-08-20
 */
@Data
@TableName("lmk_prize_grant_record")
public class PrizeGrantRecord extends BaseEntity {
    private static final long serialVersionUID = 1L;
    @TableField("user_id")
    /** 用户id */
    private Long userId;
    @TableField("nick_name")
    /** 用户昵称 */
    private String nickName;
    @TableField("activity_id")
    /** 抽奖活动id */
    private Long activityId;
    @TableField("activity_name")
    /** 活动名称 */
    private String activityName;
    @TableField("prize_id")
    /** 奖品id */
    private Long prizeId;
    @TableField("prize_name")
    /** 奖品名称 */
    private String prizeName;
    @TableField("prize_content")
    /** 奖品内容 */
    private String prizeContent;
    @TableField("grant_status")
    /** 发放状态 */
    private String grantStatus;
    @TableField("prize_num_id")
    /** 抽奖机会id */
    private Long prizeNumId;
    @TableField("des")
    /** 描述 */
    private String des;
}
framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java
@@ -54,6 +54,11 @@
    /** 奖品id */
    private Long prizeId;
    @TableField("prize_name")
    /** 奖品名称 */
    private String prizeName;
    @TableField("prize_img")
    /** 奖品封面 */
    private String prizeImg;
framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java
New file
@@ -0,0 +1,74 @@
package cn.lili.modules.lmk.domain.form;
import cn.lili.group.Update;
import cn.lili.group.Add;
import cn.lili.base.AbsForm;
import cn.lili.modules.lmk.domain.entity.PrizeGrantRecord;
import org.springframework.beans.BeanUtils;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.springframework.lang.NonNull;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * 奖品发放记录表单
 *
 * @author peng
 * @since 2025-08-20
 */
@Data
@ApiModel(value = "PrizeGrantRecord表单", description = "奖品发放记录表单")
public class PrizeGrantRecordForm extends AbsForm {
    @NotNull(message = "用户id不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("用户id")
    private Long userId;
    @NotBlank(message = "用户昵称不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("用户昵称")
    private String nickName;
    @NotNull(message = "抽奖活动id不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("抽奖活动id")
    private Long activityId;
    @NotBlank(message = "活动名称不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("活动名称")
    private String activityName;
    @NotNull(message = "奖品id不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("奖品id")
    private Long prizeId;
    @NotBlank(message = "奖品名称不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("奖品名称")
    private String prizeName;
    @NotBlank(message = "奖品内容不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("奖品内容")
    private String prizeContent;
    @NotBlank(message = "发放状态不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("发放状态")
    private String grantStatus;
    @NotNull(message = "抽奖机会id不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("抽奖机会id")
    private Long prizeNumId;
    @NotBlank(message = "描述不能为空", groups = {Add.class, Update.class})
    @ApiModelProperty("描述")
    private String des;
    public static PrizeGrantRecord getEntityByForm(@NonNull PrizeGrantRecordForm form, PrizeGrantRecord entity) {
        if(entity == null) {
          entity = new PrizeGrantRecord();
        }
        BeanUtils.copyProperties(form, entity);
        return entity;
    }
}
framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java
New file
@@ -0,0 +1,22 @@
package cn.lili.modules.lmk.domain.query;
import cn.lili.base.AbsQuery;
import java.util.List;
import org.springframework.lang.NonNull;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * 奖品发放记录查询
 *
 * @author peng
 * @since 2025-08-20
 */
@Data
@ApiModel(value = "PrizeGrantRecord查询参数", description = "奖品发放记录查询参数")
public class PrizeGrantRecordQuery extends AbsQuery {
}
framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java
New file
@@ -0,0 +1,21 @@
package cn.lili.modules.lmk.domain.query;
import lombok.Data;
import java.util.Date;
@Data
public class PrizeRecordTimeQuery {
    /**
     * 开始时间
     */
    private Date startTime;
    /**
     * 结束时间
     */
    private Date endTime;
    /**
     * 活动id
     */
    private String recordActivityId;
}
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java
New file
@@ -0,0 +1,71 @@
package cn.lili.modules.lmk.domain.vo;
import cn.lili.base.AbsVo;
import cn.lili.modules.lmk.domain.entity.PrizeGrantRecord;
import java.util.List;
import org.springframework.lang.NonNull;
import org.springframework.beans.BeanUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * 奖品发放记录展示
 *
 * @author peng
 * @since 2025-08-20
 */
@Data
@ApiModel(value = "奖品发放记录响应数据", description = "奖品发放记录响应数据")
public class PrizeGrantRecordVO extends AbsVo {
    /** 用户id */
    @ApiModelProperty("用户id")
    private Long userId;
    /** 用户昵称 */
    @ApiModelProperty("用户昵称")
    private String nickName;
    /** 抽奖活动id */
    @ApiModelProperty("抽奖活动id")
    private Long activityId;
    /** 活动名称 */
    @ApiModelProperty("活动名称")
    private String activityName;
    /** 奖品id */
    @ApiModelProperty("奖品id")
    private Long prizeId;
    /** 奖品名称 */
    @ApiModelProperty("奖品名称")
    private String prizeName;
    /** 奖品内容 */
    @ApiModelProperty("奖品内容")
    private String prizeContent;
    /** 发放状态 */
    @ApiModelProperty("发放状态")
    private String grantStatus;
    /** 抽奖机会id */
    @ApiModelProperty("抽奖机会id")
    private Long prizeNumId;
    /** 描述 */
    @ApiModelProperty("描述")
    private String des;
    public static PrizeGrantRecordVO getVoByEntity(@NonNull PrizeGrantRecord entity, PrizeGrantRecordVO vo) {
        if(vo == null) {
            vo = new PrizeGrantRecordVO();
        }
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }
}
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java
New file
@@ -0,0 +1,11 @@
package cn.lili.modules.lmk.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class PrizeProbabilityVO {
    private Long prizeId;
    private BigDecimal[][] probability;
}
framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java
New file
@@ -0,0 +1,24 @@
package cn.lili.modules.lmk.domain.vo;
import lombok.Data;
import java.util.Date;
@Data
public class PrizeRecordTimeVO {
    /**
     * 奖品id
     */
    private String prizeId;
    /**
     * 活动id
     */
    private String prizeActivityId;
    /**
     * 被抽中数量
     */
    private Integer total;
}
framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java
@@ -10,9 +10,9 @@
@AllArgsConstructor
public enum EnableStatusEnums {
    /**
     * 中奖状态
     * 启用状态
     */
    ENABLE("中奖"),
    DISABLE("未中奖");
    ENABLE("启用"),
    DISABLE("禁用");
    private final String description;
}
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java
@@ -11,6 +11,7 @@
     */
    NOT_WAIT("未中奖"),
    WAIT("待发放"),
    FAILED("发放失败"),
    SUCCESS("已发放");
    private final String description;
}
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java
New file
@@ -0,0 +1,15 @@
package cn.lili.modules.lmk.enums.general;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum PrizeGrantStatusEnums {
    /**
     * 奖品发放记录
     */
    FAILED("发放失败"),
    SUCCESS("发放成功");
    private final String description;
}
framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java
@@ -9,7 +9,7 @@
    /**
     * 中奖状态
     */
    WIN("未中奖"),
    NOT_WIN("中奖");
    WIN("中奖"),
    NOT_WIN("未中奖");
    private final String description;
}
framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java
@@ -31,4 +31,6 @@
    */
    IPage getPage(IPage page, @Param("query") ActivityRefPrizeQuery query);
    String lockPrizeRef(@Param("refId") String refId);;
}
framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java
New file
@@ -0,0 +1,34 @@
package cn.lili.modules.lmk.mapper;
import cn.lili.modules.lmk.domain.entity.PrizeGrantRecord;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.lili.modules.lmk.domain.vo.PrizeGrantRecordVO;
import cn.lili.modules.lmk.domain.form.PrizeGrantRecordForm;
import cn.lili.modules.lmk.domain.query.PrizeGrantRecordQuery;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * 奖品发放记录 Mapper 接口
 *
 * @author peng
 * @since 2025-08-20
 */
@Mapper
public interface PrizeGrantRecordMapper extends BaseMapper<PrizeGrantRecord> {
    /**
     * id查找奖品发放记录
     * @param id
     * @return
     */
    PrizeGrantRecordVO getById(String id);
    /**
    *  分页
    */
    IPage getPage(IPage page, @Param("query") PrizeGrantRecordQuery query);
}
framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java
@@ -1,6 +1,8 @@
package cn.lili.modules.lmk.mapper;
import cn.lili.modules.lmk.domain.entity.PrizeRecord;
import cn.lili.modules.lmk.domain.query.PrizeRecordTimeQuery;
import cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.lili.modules.lmk.domain.vo.PrizeRecordVO;
@@ -31,4 +33,5 @@
    */
    IPage getPage(IPage page, @Param("query") PrizeRecordQuery query);
    List<PrizeRecordTimeVO> getPrizeRecordListByTime(@Param("query") PrizeRecordTimeQuery query);
}
framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java
@@ -5,6 +5,8 @@
import cn.lili.base.Result;
import cn.lili.modules.lmk.domain.form.ActivityRefPrizeForm;
import cn.lili.modules.lmk.domain.query.ActivityRefPrizeQuery;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
@@ -62,4 +64,6 @@
     * @return
     */
    Result all();
    String lockPrizeRef(String refId);
}
framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java
New file
@@ -0,0 +1,65 @@
package cn.lili.modules.lmk.service;
import cn.lili.modules.lmk.domain.entity.PrizeGrantRecord;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.lili.base.Result;
import cn.lili.modules.lmk.domain.form.PrizeGrantRecordForm;
import cn.lili.modules.lmk.domain.query.PrizeGrantRecordQuery;
import java.util.List;
/**
 * 奖品发放记录 服务类
 *
 * @author peng
 * @since 2025-08-20
 */
public interface PrizeGrantRecordService extends IService<PrizeGrantRecord> {
    /**
     * 添加
     * @param form
     * @return
     */
    Result add(PrizeGrantRecordForm form);
    /**
     * 修改
     * @param form
     * @return
     */
    Result update(PrizeGrantRecordForm form);
    /**
     * 批量删除
     * @param ids
     * @return
     */
    Result remove(List<String> ids);
    /**
     * id删除
     * @param id
     * @return
     */
    Result removeById(String id);
    /**
     * 分页查询
     * @param query
     * @return
     */
    Result page(PrizeGrantRecordQuery query);
    /**
     * 根据id查找
     * @param id
     * @return
     */
    Result detail(String id);
    /**
     * 列表
     * @return
     */
    Result all();
}
framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java
@@ -1,6 +1,8 @@
package cn.lili.modules.lmk.service;
import cn.lili.modules.lmk.domain.entity.PrizeRecord;
import cn.lili.modules.lmk.domain.query.PrizeRecordTimeQuery;
import cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.lili.base.Result;
import cn.lili.modules.lmk.domain.form.PrizeRecordForm;
@@ -62,4 +64,6 @@
     * @return
     */
    Result all();
    List<PrizeRecordTimeVO> getPrizeRecordListByTime(PrizeRecordTimeQuery query);
}
framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java
New file
@@ -0,0 +1,15 @@
package cn.lili.modules.lmk.service;
import cn.lili.base.Result;
import org.springframework.web.bind.annotation.PathVariable;
public interface PrizeService {
    Result prize(String prizeId);
    Result prizeNum(String prizeId);
    Result prizeInfo(String prizeActivityId);
}
framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java
@@ -116,4 +116,9 @@
                .collect(Collectors.toList());
        return Result.ok().data(vos);
    }
    @Override
    public String lockPrizeRef(String refId) {
       return baseMapper.lockPrizeRef(refId);
    }
}
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java
New file
@@ -0,0 +1,119 @@
package cn.lili.modules.lmk.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.lili.modules.lmk.domain.entity.PrizeGrantRecord;
import cn.lili.modules.lmk.mapper.PrizeGrantRecordMapper;
import cn.lili.modules.lmk.service.PrizeGrantRecordService;
import cn.lili.base.Result;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.lili.modules.lmk.domain.form.PrizeGrantRecordForm;
import cn.lili.modules.lmk.domain.vo.PrizeGrantRecordVO;
import cn.lili.modules.lmk.domain.query.PrizeGrantRecordQuery;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import cn.lili.utils.PageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 奖品发放记录 服务实现类
 *
 * @author peng
 * @since 2025-08-20
 */
@Service
@RequiredArgsConstructor
public class PrizeGrantRecordServiceImpl extends ServiceImpl<PrizeGrantRecordMapper, PrizeGrantRecord> implements PrizeGrantRecordService {
    private final PrizeGrantRecordMapper prizeGrantRecordMapper;
    /**
     * 添加
     * @param form
     * @return
     */
    @Override
    public Result add(PrizeGrantRecordForm form) {
        PrizeGrantRecord entity = PrizeGrantRecordForm.getEntityByForm(form, null);
        baseMapper.insert(entity);
        return Result.ok("添加成功");
    }
    /**
     * 修改
     * @param form
     * @return
     */
    @Override
    public Result update(PrizeGrantRecordForm form) {
        PrizeGrantRecord entity = baseMapper.selectById(form.getId());
        // 为空抛IllegalArgumentException,做全局异常处理
        Assert.notNull(entity, "记录不存在");
        BeanUtils.copyProperties(form, entity);
        baseMapper.updateById(entity);
        return Result.ok("修改成功");
    }
    /**
     * 批量删除
     * @param ids
     * @return
     */
    @Override
    public Result remove(List<String> ids) {
        baseMapper.deleteBatchIds(ids);
        return Result.ok("删除成功");
    }
    /**
     * id删除
     * @param id
     * @return
     */
    @Override
    public Result removeById(String id) {
        baseMapper.deleteById(id);
        return Result.ok("删除成功");
    }
    /**
     * 分页查询
     * @param query
     * @return
     */
    @Override
    public Result page(PrizeGrantRecordQuery query) {
        IPage<PrizeGrantRecordVO> page = PageUtil.getPage(query, PrizeGrantRecordVO.class);
        baseMapper.getPage(page, query);
        return Result.ok().data(page.getRecords()).total(page.getTotal());
    }
    /**
     * 根据id查找
     * @param id
     * @return
     */
    @Override
    public Result detail(String id) {
        PrizeGrantRecordVO vo = baseMapper.getById(id);
        Assert.notNull(vo, "记录不存在");
        return Result.ok().data(vo);
    }
    /**
     * 列表
     * @return
     */
    @Override
    public Result all() {
        List<PrizeGrantRecord> entities = baseMapper.selectList(null);
        List<PrizeGrantRecordVO> vos = entities.stream()
                .map(entity -> PrizeGrantRecordVO.getVoByEntity(entity, null))
                .collect(Collectors.toList());
        return Result.ok().data(vos);
    }
}
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java
@@ -1,5 +1,7 @@
package cn.lili.modules.lmk.service.impl;
import cn.lili.modules.lmk.domain.query.PrizeRecordTimeQuery;
import cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.lili.modules.lmk.domain.entity.PrizeRecord;
import cn.lili.modules.lmk.mapper.PrizeRecordMapper;
@@ -116,4 +118,9 @@
                .collect(Collectors.toList());
        return Result.ok().data(vos);
    }
    @Override
    public List<PrizeRecordTimeVO> getPrizeRecordListByTime(PrizeRecordTimeQuery query) {
        return baseMapper.getPrizeRecordListByTime(query);
    }
}
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java
New file
@@ -0,0 +1,413 @@
package cn.lili.modules.lmk.service.impl;
import cn.lili.base.Result;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.lmk.domain.entity.*;
import cn.lili.modules.lmk.domain.query.PrizeRecordTimeQuery;
import cn.lili.modules.lmk.domain.vo.PrizeProbabilityVO;
import cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO;
import cn.lili.modules.lmk.enums.general.*;
import cn.lili.modules.lmk.service.*;
import cn.lili.mybatis.BaseEntity;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.CommentTagsEnum;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class PrizeServiceImpl implements PrizeService {
    private final PrizeActivityService prizeActivityService;
    private final PrizeNumberService prizeNumberService;
    private final PrizeDrawService prizeDrawService;
    private final ActivityRefPrizeService activityRefPrizeService;
    private final PrizeRecordService prizeRecordService;
    private static final String PRIZE_PREFIX = "prize_draw:";
    private static final String PRIZE_NUMBER = "prize_number:";
    private final RedisTemplate<String, String> redisTemplate;
    private final RedissonClient redissonClient;
    private final RocketmqCustomProperties rocketmqCustomProperties;
    private final RocketMQTemplate rocketMQTemplate;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result prize(String prizeId) {
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            throw new RuntimeException("当前用户没有登录无法抽奖");
        }
        String userId = currentUser.getId();
        if (StringUtils.isBlank(userId)) {
            throw new RuntimeException("当前用户没有登录无法抽奖");
        }
        Result result;
        String lock = IdWorker.get32UUID();
        RLock redissonLock = redissonClient.getLock(PRIZE_PREFIX + prizeId);
        try {
//            Boolean lockResult = redisTemplate.opsForValue().setIfAbsent(PRIZE_PREFIX + prizeId, lock, 60, TimeUnit.SECONDS);
//            if (Boolean.FALSE.equals(lockResult)) {
//                throw new ServiceException("当前活动太火爆了请稍后再试");
//            }
            redissonLock.lock();
            result = prizeDraw(prizeId, userId, lock);
        } finally {
            if (redissonLock.isHeldByCurrentThread()) {
                redissonLock.unlock();
            }
//            //释放锁
//            String newLock = redisTemplate.opsForValue().get(PRIZE_PREFIX + prizeId);
//            if (lock.equals(newLock))
//                redisTemplate.delete(PRIZE_PREFIX + prizeId);
        }
        return result;
    }
    @Transactional(rollbackFor = Exception.class)
    public Result prizeDraw(String prizeId, String userId, String lock) {
        //活动
        PrizeActivity prizeActivity;
        //待使用的抽奖机会
        PrizeNumber waitUserPrize;
        //当天开始时间
        Date beginTime;
        //当天结束时间
        Date endTime;
        //使用了的抽奖机会
        List<PrizeNumber> usedPrize;
        //没被使用的抽奖机会
        List<PrizeNumber> canUsedPrize;
        //抽奖商品集合
        List<ActivityRefPrize> refPrizes;
        //查询当天抽奖记录入参
        PrizeRecordTimeQuery prizeRecordTimeQuery;
        //当天抽奖记录汇总
        List<PrizeRecordTimeVO> prizeRecordListByTime;
        //还能抽奖商品map集合
        Map<Long, ActivityRefPrize> canPrizeMap;
        //待构建抽奖概率商品集合
        List<ActivityRefPrize> refPrizeList;
        //概率集合
        List<PrizeProbabilityVO> prizeProbabilityList;
        //中奖商品id
        Long prizeWon = null;
        prizeActivity = prizeActivityService.getById(prizeId);
        if (prizeActivity == null) {
            throw new ServiceException("当前活动不存在");
        }
        Date activityEndtime = prizeActivity.getEndTime();
        if (new Date().after(activityEndtime)) {
            throw new ServiceException("当前活动已经结束");
        }
        if (!EnableStatusEnums.ENABLE.name().equals(prizeActivity.getEnableStatus())) {
            throw new ServiceException("活动还没有开始");
        }
        //查询当天的抽奖卷
        LocalDate now = LocalDate.now();
        LocalDateTime maxTime = LocalDateTime.of(now, LocalTime.MAX);
        LocalDateTime minTime = LocalDateTime.of(now, LocalTime.MIN);
        beginTime = Date.from(
                minTime.atZone(ZoneId.systemDefault()).toInstant()
        );
        endTime = Date.from(
                maxTime.atZone(ZoneId.systemDefault()).toInstant()
        );
        LambdaQueryWrapper<PrizeNumber> queryNumber = Wrappers.<PrizeNumber>lambdaQuery();
        queryNumber.eq(PrizeNumber::getUserId, userId).eq(PrizeNumber::getActivityPrizeId, prizeId);
        queryNumber.between(BaseEntity::getCreateTime, beginTime, endTime);
        //判断用户是否有抽奖机会有取出一条未抽奖的数据待使用
        List<PrizeNumber> list = prizeNumberService.list(queryNumber);
        if (list == null || list.isEmpty()) {
            throw new ServiceException("抽奖次数用完了");
        }
        usedPrize = list.stream().filter(item -> {
            return PrizeNumberUseEnum.USED.name().equals(item.getUseStatus());
        }).collect(Collectors.toList());
        canUsedPrize = list.stream().filter(item -> {
            return PrizeNumberUseEnum.WAIT.name().equals(item.getUseStatus());
        }).collect(Collectors.toList());
        if (usedPrize.size() > prizeActivity.getMaxPrize()) {
            throw new ServiceException("抽奖已达到上限");
        }
        if (canUsedPrize.isEmpty()) {
            throw new ServiceException("抽奖次数用完了");
        }
        waitUserPrize = canUsedPrize.get(0);
        //判断奖品是否还有以及当天是否还有奖品
        LambdaQueryWrapper<ActivityRefPrize> prizeRefQuery = Wrappers.<ActivityRefPrize>lambdaQuery();
        prizeRefQuery.eq(ActivityRefPrize::getPrizeActivityId, prizeId);
        refPrizes = activityRefPrizeService.list(prizeRefQuery);
        canPrizeMap = refPrizes.stream().filter(item -> {
            return item.getRemainNum() > 0;
        }).collect(Collectors.toMap(ActivityRefPrize::getPrizeId, Function.identity()));
        prizeRecordTimeQuery = new PrizeRecordTimeQuery();
        prizeRecordTimeQuery.setStartTime(beginTime);
        prizeRecordTimeQuery.setEndTime(endTime);
        prizeRecordTimeQuery.setRecordActivityId(prizeId);
        prizeRecordListByTime = prizeRecordService.getPrizeRecordListByTime(prizeRecordTimeQuery);
        prizeRecordListByTime.stream().filter(item->{
            return item.getPrizeId() != null;
        }).forEach(item -> {
            ActivityRefPrize activityRefPrize = canPrizeMap.get(Long.parseLong(item.getPrizeId()));
            if (activityRefPrize != null) {
                //移除当日上限的奖品并且添加到不能抽奖商品中去
                if (activityRefPrize.getMaxPreDay() <= item.getTotal()) {
                    canPrizeMap.remove(Long.parseLong(item.getPrizeId()));
                }
            }
        });
        //准备构建范围集合
        refPrizeList = new ArrayList<>(canPrizeMap.values());
        //当前中奖比例
        BigDecimal currentProbability = refPrizeList.stream().map(ActivityRefPrize::getPrizeProbability).reduce(BigDecimal.ZERO, BigDecimal::add);
        //用不能中奖的商品补齐
        BigDecimal subtract = new BigDecimal(100).subtract(currentProbability);
        if (subtract.compareTo(BigDecimal.ZERO) > 0) {
            ActivityRefPrize activityRefPrize = new ActivityRefPrize();
            activityRefPrize.setPrizeId(null);
            activityRefPrize.setPrizeProbability(subtract);
            refPrizeList.add(activityRefPrize);
            currentProbability = new BigDecimal(100);
        }
        //打乱排序
        Collections.shuffle(refPrizeList);
        //构建抽奖范围集合
        prizeProbabilityList = new ArrayList<>();
        BigDecimal probabilityBegin = BigDecimal.ZERO;
        for (ActivityRefPrize item : refPrizeList) {
            PrizeProbabilityVO prizeProbabilityVO = new PrizeProbabilityVO();
            prizeProbabilityVO.setPrizeId(item.getPrizeId());
            BigDecimal multiply = item.getPrizeProbability().multiply(BigDecimal.valueOf(100));
            BigDecimal[][] position = {{probabilityBegin, multiply.add(probabilityBegin)}};
            prizeProbabilityVO.setProbability(position);
            probabilityBegin = multiply.add(probabilityBegin);
            prizeProbabilityList.add(prizeProbabilityVO);
        }
        BigDecimal max = currentProbability.multiply(BigDecimal.valueOf(100));
        BigDecimal bigDecimal = generateRandom(BigDecimal.ONE, max);
        for (PrizeProbabilityVO prizeProbabilityVO : prizeProbabilityList) {
            BigDecimal minP = prizeProbabilityVO.getProbability()[0][0];
            BigDecimal maxP = prizeProbabilityVO.getProbability()[0][1];
            if (bigDecimal.compareTo(minP) > 0 && bigDecimal.compareTo(maxP) <= 0) {
                prizeWon = prizeProbabilityVO.getPrizeId();
                break;
            }
        }
        //未中奖的情况
        if (prizeWon == null) {
            //写入抽奖记录返回没有中奖信息
            //写入抽奖记录
            PrizeRecord prizeRecord = new PrizeRecord();
            prizeRecord.setUserId(Long.parseLong(userId));
            prizeRecord.setNickName(Objects.requireNonNull(UserContext.getCurrentUser()).getNickName());
            prizeRecord.setPrizeActivityId(Long.parseLong(prizeId));
            prizeRecord.setPrizeActivityName(prizeActivity.getActivityName());
            prizeRecord.setPrizeActivityCover(prizeActivity.getActivityCover());
            prizeRecord.setPrizeStatus(PrizeStatusEnum.NOT_WIN.name());
            prizeRecord.setPrizeContent(null);
            prizeRecord.setPrizeId(null);
            prizeRecord.setPrizeNumId(Long.parseLong(waitUserPrize.getId()));
            prizeRecord.setActivityPrizeRefId(null);
            prizeRecord.setDistributeStatus(PrizeDistributeStatusEnum.NOT_WAIT.name());
            prizeRecordService.save(prizeRecord);
            waitUserPrize.setUseStatus(PrizeNumberUseEnum.USED.name());
            prizeNumberService.updateById(waitUserPrize);
            return Result.error("未中奖");
        }
        ActivityRefPrize activityRefPrize;
        String nowLock;
        activityRefPrize = canPrizeMap.get(prizeWon);
        //将活动当前活动奖品库存使用排他锁锁住
        activityRefPrizeService.lockPrizeRef(activityRefPrize.getId());
        //修改抽奖机会状态
        waitUserPrize.setUseStatus(PrizeNumberUseEnum.USED.name());
        prizeNumberService.updateById(waitUserPrize);
        //扣库存
        LambdaUpdateWrapper<ActivityRefPrize> set = Wrappers.lambdaUpdate(ActivityRefPrize.class)
                .eq(ActivityRefPrize::getId, activityRefPrize.getId())
                .eq(ActivityRefPrize::getRemainNum, activityRefPrize.getRemainNum())
                .eq(ActivityRefPrize::getVersion, activityRefPrize.getVersion())
                .gt(ActivityRefPrize::getRemainNum, 0)
                .set(ActivityRefPrize::getRemainNum, activityRefPrize.getRemainNum() - 1)
                .set(ActivityRefPrize::getVersion, activityRefPrize.getVersion() + 1);
        boolean update = activityRefPrizeService.update(set);
        if (!update) {
            throw new ServiceException("当前活动太火爆了请稍后再试");
        }
        PrizeDraw prizeDraw = prizeDrawService.getById(prizeWon);
        //写入抽奖记录
        PrizeRecord prizeRecord = new PrizeRecord();
        prizeRecord.setUserId(Long.parseLong(userId));
        prizeRecord.setNickName(Objects.requireNonNull(UserContext.getCurrentUser()).getNickName());
        prizeRecord.setPrizeActivityId(Long.parseLong(prizeId));
        prizeRecord.setPrizeActivityName(prizeActivity.getActivityName());
        prizeRecord.setPrizeActivityCover(prizeActivity.getActivityCover());
        prizeRecord.setPrizeStatus(PrizeStatusEnum.WIN.name());
        prizeRecord.setPrizeContent(prizeDraw.getPrizeContent());
        prizeRecord.setPrizeImg(prizeActivity.getActivityImg());
        prizeRecord.setPrizeNumId(Long.parseLong(waitUserPrize.getId()));
        prizeRecord.setActivityPrizeRefId(Long.parseLong(activityRefPrize.getId()));
        prizeRecord.setDistributeStatus(PrizeDistributeStatusEnum.WAIT.name());
        prizeRecord.setPrizeId(prizeWon);
        prizeRecord.setPrizeName(prizeDraw.getPrizeName());
        prizeRecord.setPrizeActivityCover(prizeActivity.getActivityCover());
        prizeRecord.setPrizeImg(prizeDraw.getPrizeImg());
        prizeRecordService.save(prizeRecord);
        //判断当前锁还是不是当前的锁如果不是直接抛出异常回滚
//        nowLock = redisTemplate.opsForValue().get(PRIZE_PREFIX + prizeId);
//        if (!lock.equals(nowLock)) {
//            throw new RuntimeException("当前活动太火爆了请稍后再试");
//        }
        // 走mq异步处理
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                String destination = rocketmqCustomProperties.getPrizeTopic() + ":" + PrizeStatusEnum.WIN.name();
                rocketMQTemplate.asyncSend(destination, JSON.toJSONString(prizeRecord), RocketmqSendCallbackBuilder.commonCallback());
            }
        });
        return Result.ok().data(activityRefPrize);
    }
    public static BigDecimal generateRandom(BigDecimal min, BigDecimal max) {
        if (min.compareTo(max) >= 0) {
            throw new IllegalArgumentException("最小值必须小于最大值");
        }
        // 计算范围差值
        BigDecimal range = max.subtract(min);
        // 生成0-1之间的随机double数
        double randomDouble = new Random().nextDouble();
        // 计算随机数并设置精度
        return min.add(range.multiply(new BigDecimal(randomDouble)))
                .setScale(0, RoundingMode.HALF_UP);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result prizeNum(String prizeId) {
        String userId;
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            throw new RuntimeException("当前用户没有登录");
        }
        userId = currentUser.getId();
        //获取redis锁
        RLock lock = redissonClient.getLock(PRIZE_NUMBER + userId);
        PrizeActivity activity = prizeActivityService.getById(prizeId);
        if (activity == null) {
            throw new RuntimeException("当前活动不存在");
        }
        //获取用户抽奖次数
        Integer prizeNum = activity.getPrizeNum();
        //加锁判断添加系统赠送次数
        List<PrizeNumber> prizeNumberList;
        try {
            lock.lock();
            prizeNumberList = getPrizeNumberList(prizeId, userId);
            // 当前用户没有初始化抽奖数据需要初始化当天抽奖数据
            if (prizeNumberList == null || prizeNumberList.isEmpty()) {
                //没有默认抽奖次数直接返回0次
                if (prizeNum == null || prizeNum <= 0) {
                    return Result.ok().data(0);
                }
                prizeNumberList = new ArrayList<>();
                //设置默认抽奖次数并返回默认抽奖次数
                for (int i = 0; i < prizeNum; i++) {
                    PrizeNumber prizeNumber = new PrizeNumber();
                    prizeNumber.setActivityPrizeId(Long.parseLong(prizeId));
                    prizeNumber.setUserId(Long.parseLong(userId));
                    prizeNumber.setUserAction(PrizeUserActionEnum.SYSTEM.name());
                    prizeNumber.setUseStatus(PrizeNumberUseEnum.WAIT.name());
                    prizeNumberList.add(prizeNumber);
                }
                //添加抽奖次数并返回
                prizeNumberService.saveBatch(prizeNumberList);
                return Result.ok().data(prizeNumberList.size());
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        Integer maxPrize = activity.getMaxPrize();
        //其他情况
        int useNum = 0;
        int notUseNum = 0;
        for (PrizeNumber prizeNumber : prizeNumberList) {
            if (PrizeNumberUseEnum.WAIT.name().equals(prizeNumber.getUseStatus())) {
                notUseNum++;
            } else if (PrizeNumberUseEnum.USED.name().equals(prizeNumber.getUseStatus())) {
                useNum++;
            }
        }
        int userPrizeNum = prizeNumberList.size();
        if (useNum >= maxPrize) {
            return Result.ok().data(0);
        } else {
            return Result.ok().data(userPrizeNum>maxPrize?maxPrize-useNum:notUseNum);
        }
    }
    /**
     * 获取当天某个用户的所有的优惠卷
     *
     * @param prizeId 活动id
     * @param userId  用户id
     * @return 抽奖次数集合
     */
    public List<PrizeNumber> getPrizeNumberList(String prizeId, String userId) {
        Date beginTime;
        Date endTime;
        //查询当天的优惠卷
        LocalDate now = LocalDate.now();
        LocalDateTime maxTime = LocalDateTime.of(now, LocalTime.MAX);
        LocalDateTime minTime = LocalDateTime.of(now, LocalTime.MIN);
        beginTime = Date.from(
                minTime.atZone(ZoneId.systemDefault()).toInstant()
        );
        endTime = Date.from(
                maxTime.atZone(ZoneId.systemDefault()).toInstant()
        );
        LambdaQueryWrapper<PrizeNumber> queryNumber = Wrappers.<PrizeNumber>lambdaQuery();
        queryNumber.eq(PrizeNumber::getUserId, userId).eq(PrizeNumber::getActivityPrizeId, prizeId);
        queryNumber.between(BaseEntity::getCreateTime, beginTime, endTime);
        return prizeNumberService.list(queryNumber);
    }
    @Override
    public Result prizeInfo(String prizeActivityId) {
        return null;
    }
}
framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml
@@ -52,5 +52,12 @@
        WHERE
            LARP.delete_flag = 0
    </select>
    <select id="lockPrizeRef" resultType="string">
        SELECT
            *
        FROM
            lmk_activity_ref_prize
        WHERE id = #{refId} FOR UPDATE;
    </select>
</mapper>
framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml
New file
@@ -0,0 +1,65 @@
<?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="cn.lili.modules.lmk.mapper.PrizeGrantRecordMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.PrizeGrantRecordVO">
        <id column="id" property="id"/>
        <result column="user_id" property="userId" />
        <result column="nick_name" property="nickName" />
        <result column="activity_id" property="activityId" />
        <result column="activity_name" property="activityName" />
        <result column="prize_id" property="prizeId" />
        <result column="prize_name" property="prizeName" />
        <result column="prize_content" property="prizeContent" />
        <result column="grant_status" property="grantStatus" />
        <result column="prize_num_id" property="prizeNumId" />
        <result column="des" property="des" />
    </resultMap>
    <select id="getById" resultMap="BaseResultMap">
        SELECT
            LPGR.user_id,
            LPGR.nick_name,
            LPGR.activity_id,
            LPGR.activity_name,
            LPGR.prize_id,
            LPGR.prize_name,
            LPGR.prize_content,
            LPGR.grant_status,
            LPGR.prize_num_id,
            LPGR.des,
            LPGR.id
        FROM
            lmk_prize_grant_record LPGR
        WHERE
            LPGR.id = #{id} AND LPGR.delete_flag = 0
    </select>
    <select id="getPage" resultMap="BaseResultMap">
        SELECT
            LPGR.user_id,
            LPGR.nick_name,
            LPGR.activity_id,
            LPGR.activity_name,
            LPGR.prize_id,
            LPGR.prize_name,
            LPGR.prize_content,
            LPGR.grant_status,
            LPGR.prize_num_id,
            LPGR.des,
            LPGR.id
        FROM
            lmk_prize_grant_record LPGR
        WHERE
            LPGR.delete_flag = 0
    </select>
</mapper>
framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml
@@ -16,6 +16,7 @@
        <result column="prize_img" property="prizeImg" />
        <result column="prize_num_id" property="prizeNumId" />
        <result column="activity_prize_ref_id" property="activityPrizeRefId" />
        <result column="distribute_status" property="distributeStatus" />
    </resultMap>
@@ -37,7 +38,8 @@
            LPR.prize_img,
            LPR.prize_num_id,
            LPR.activity_prize_ref_id,
            LPR.id
            LPR.id,
            LPR.distribute_status
        FROM
            lmk_prize_record LPR
        WHERE
@@ -64,5 +66,25 @@
        WHERE
            LPR.delete_flag = 0
    </select>
    <resultMap id="getPrizeRecordListByTimeMap" type="cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO">
        <result property="prizeId" column="prize_id"/>
        <result property="prizeActivityId" column="prize_activity_id"/>
        <result property="total" column="total"/>
    </resultMap>
    <select id="getPrizeRecordListByTime" resultMap="getPrizeRecordListByTimeMap">
        SELECT
            prize_id,
            prize_activity_id,
            count(*) total
        FROM
            lmk_prize_record
        WHERE
            prize_activity_id = #{query.recordActivityId}
          AND delete_flag = 0
          AND create_time BETWEEN #{query.startTime}
            AND #{query.endTime}
        GROUP BY
            prize_id,
            prize_activity_id;
    </select>
</mapper>