From b2a68b1eaa6db1c1456534e084d66fe98e4443f0 Mon Sep 17 00:00:00 2001
From: peng <peng.com>
Date: 星期四, 21 八月 2025 15:26:59 +0800
Subject: [PATCH] 抽奖活动

---
 framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java            |   34 +
 framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java              |   24 +
 framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java |  119 +++++
 framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java            |  413 ++++++++++++++++++++
 framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java            |    4 
 framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java             |   11 
 framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java |    5 
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java                |    5 
 framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java      |   15 
 framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java           |    7 
 buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java                       |   52 ++
 framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java          |    4 
 framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml                             |   26 +
 framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml                        |    7 
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java           |   62 +++
 framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java              |   15 
 framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java      |    7 
 framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java       |   22 +
 framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java          |    6 
 framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml                        |   65 +++
 framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java  |    1 
 framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java            |    2 
 framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java          |   65 +++
 framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java        |   21 +
 framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java             |   71 +++
 framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java         |   74 +++
 framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java                       |    7 
 framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java               |    4 
 framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java                     |   15 
 framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java    |    2 
 framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java                 |    3 
 31 files changed, 1,156 insertions(+), 12 deletions(-)

diff --git a/buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java b/buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java
new file mode 100644
index 0000000..d09c64a
--- /dev/null
+++ b/buyer-api/src/main/java/cn/lili/controller/lmk/PrizeController.java
@@ -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);
+    }
+}
diff --git a/framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java b/framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java
index 118c836..f79d291 100644
--- a/framework/src/main/java/cn/lili/common/exception/GlobalControllerExceptionHandler.java
+++ b/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绾у埆鐨勬棩蹇�
diff --git a/framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java b/framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java
index 965c1ce..8cb9ede 100644
--- a/framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java
+++ b/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;
diff --git a/framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java b/framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java
index 2cda83b..43d2e79 100644
--- a/framework/src/main/java/cn/lili/modules/goods/entity/dos/Goods.java
+++ b/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();
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java
index 4476df2..f28dcfc 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeActivity.java
+++ b/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")
     /** 姣忔棩鏈�澶ф娊濂栦笂闄� */
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java
new file mode 100644
index 0000000..7effdda
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeGrantRecord.java
@@ -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;
+
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java
index c7f52b6..b100e42 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeRecord.java
+++ b/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;
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java b/framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java
new file mode 100644
index 0000000..3750237
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/form/PrizeGrantRecordForm.java
@@ -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;
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java b/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java
new file mode 100644
index 0000000..4c4b3d3
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeGrantRecordQuery.java
@@ -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 {
+}
+
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java b/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java
new file mode 100644
index 0000000..6aa564f
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/query/PrizeRecordTimeQuery.java
@@ -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;
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java
new file mode 100644
index 0000000..fc0edc4
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeGrantRecordVO.java
@@ -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;
+    }
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java
new file mode 100644
index 0000000..39a0401
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeProbabilityVO.java
@@ -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;
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java
new file mode 100644
index 0000000..b3896be
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/PrizeRecordTimeVO.java
@@ -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;
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java
index 389eba2..adbc760 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/enums/general/EnableStatusEnums.java
+++ b/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;
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java
index 008fb6b..1ba1d96 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeDistributeStatusEnum.java
+++ b/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;
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java
new file mode 100644
index 0000000..985f872
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeGrantStatusEnums.java
@@ -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;
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java b/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java
index c07cb8e..c7ca869 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeStatusEnum.java
+++ b/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;
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java
index 153f5fd..a7bde6e 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/mapper/ActivityRefPrizeMapper.java
+++ b/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);;
+
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java
new file mode 100644
index 0000000..5c491e2
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeGrantRecordMapper.java
@@ -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);
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java
index ece74a1..4a894f2 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/mapper/PrizeRecordMapper.java
+++ b/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);
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java b/framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java
index 1516fed..6a0d684 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/ActivityRefPrizeService.java
+++ b/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);
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java
new file mode 100644
index 0000000..a1760c6
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeGrantRecordService.java
@@ -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();
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java
index a57d4b0..34c9027 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeRecordService.java
+++ b/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);
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java
new file mode 100644
index 0000000..7b2cbdb
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java
@@ -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);
+
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java
index 27abbd0..2f3658e 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/ActivityRefPrizeServiceImpl.java
+++ b/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);
+    }
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java
new file mode 100644
index 0000000..78f34d3
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeGrantRecordServiceImpl.java
@@ -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());
+
+        // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊
+        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);
+    }
+}
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java
index 6fed40e..dedeb91 100644
--- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeRecordServiceImpl.java
+++ b/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);
+    }
 }
diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java
new file mode 100644
index 0000000..c41225c
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java
@@ -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);
+        //鎵e簱瀛�
+        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("褰撳墠娲诲姩澶伀鐖嗕簡璇风◢鍚庡啀璇�");
+//        }
+        // 璧癿q寮傛澶勭悊
+        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涔嬮棿鐨勯殢鏈篸ouble鏁�
+        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;
+    }
+}
diff --git a/framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml b/framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml
index 28aa0c4..f06dad1 100644
--- a/framework/src/main/resources/mapper/lmk/ActivityRefPrizeMapper.xml
+++ b/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>
diff --git a/framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml b/framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml
new file mode 100644
index 0000000..b1a97a7
--- /dev/null
+++ b/framework/src/main/resources/mapper/lmk/PrizeGrantRecordMapper.xml
@@ -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>
diff --git a/framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml b/framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml
index 31aed99..a0fc583 100644
--- a/framework/src/main/resources/mapper/lmk/PrizeRecordMapper.xml
+++ b/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>

--
Gitblit v1.8.0