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