浏览代码

feat: 声明事务领取活动领域开发

seamew 2 年之前
父节点
当前提交
895c4a10f3
共有 20 个文件被更改,包括 701 次插入27 次删除
  1. 2 2
      lottery-common/src/main/java/com/seamew/lottery/common/Constants.java
  2. 8 1
      lottery-common/src/main/java/com/seamew/lottery/common/Result.java
  3. 6 0
      lottery-domain/pom.xml
  4. 33 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/req/PartakeReq.java
  5. 29 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/res/PartakeResult.java
  6. 63 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/vo/ActivityBillVO.java
  7. 16 4
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/repository/IActivityRepository.java
  8. 40 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/repository/IUserTakeActivityRepository.java
  9. 23 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/ActivityPartakeSupport.java
  10. 73 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/BaseActivityPartake.java
  11. 20 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/IActivityPartake.java
  12. 108 0
      lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/impl/ActivityPartakeImpl.java
  13. 7 0
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/dao/IActivityDao.java
  14. 40 0
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/dao/IUserTakeActivityCountDao.java
  15. 46 12
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/po/Activity.java
  16. 48 0
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/po/UserTakeActivityCount.java
  17. 39 8
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/repository/ActivityRepository.java
  18. 67 0
      lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/repository/UserTakeActivityRepository.java
  19. 5 0
      lottery-interfaces/src/main/resources/mybatis/mapper/Activity_Mapper.xml
  20. 28 0
      lottery-interfaces/src/main/resources/mybatis/mapper/UserTakeActivityCount_Mapper.xml

+ 2 - 2
lottery-common/src/main/java/com/seamew/lottery/common/Constants.java

@@ -12,7 +12,8 @@ public class Constants {
         SUCCESS("0000", "成功"),
         UN_ERROR("0001", "未知失败"),
         ILLEGAL_PARAMETER("0002", "非法参数"),
-        INDEX_DUP("0003", "主键冲突");
+        INDEX_DUP("0003", "主键冲突"),
+        NO_UPDATE("0004","SQL操作无更新");
 
         private final String code;
         private final String info;
@@ -31,7 +32,6 @@ public class Constants {
         }
 
     }
-
     /**
      * 活动状态:1编辑、2提审、3撤审、4通过、5运行(审核通过后worker扫描状态)、6拒绝、7关闭、8开启
      */

+ 8 - 1
lottery-common/src/main/java/com/seamew/lottery/common/Result.java

@@ -21,10 +21,18 @@ public class Result implements Serializable {
     private String code;
     private String info;
 
+    public static Result buildResult(Constants.ResponseCode code) {
+        return new Result(code.getCode(), code.getInfo());
+    }
+
     public static Result buildResult(Constants.ResponseCode code, String info) {
         return new Result(code.getCode(), info);
     }
 
+    public static Result buildResult(String code, String info) {
+        return new Result(code, info);
+    }
+
     public static Result buildResult(Constants.ResponseCode code, Constants.ResponseCode info) {
         return new Result(code.getCode(), info.getInfo());
     }
@@ -40,5 +48,4 @@ public class Result implements Serializable {
     public static Result buildErrorResult(String info) {
         return new Result(Constants.ResponseCode.UN_ERROR.getCode(), info);
     }
-
 }

+ 6 - 0
lottery-domain/pom.xml

@@ -28,6 +28,12 @@
             <artifactId>spring-tx</artifactId>
         </dependency>
 
+        <!-- 自研启动类 -->
+        <dependency>
+            <groupId>com.seamew</groupId>
+            <artifactId>db-router-spring-boot-starter</artifactId>
+        </dependency>
+
         <!-- 三方工具类 -->
         <dependency>
             <groupId>cn.hutool</groupId>

+ 33 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/req/PartakeReq.java

@@ -0,0 +1,33 @@
+package com.seamew.lottery.domain.activity.model.req;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * @Author: seamew
+ * @Title: PartakeReq
+ * @CreateTime: 2023年02月22日 16:47:00
+ * @Description: 参与活动请求
+ * @Version: 1.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class PartakeReq {
+
+    /**
+     * 用户ID
+     */
+    private String uId;
+    /**
+     * 活动ID
+     */
+    private Long activityId;
+    /**
+     * 活动领取时间
+     */
+    private Date partakeDate;
+}

+ 29 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/res/PartakeResult.java

@@ -0,0 +1,29 @@
+package com.seamew.lottery.domain.activity.model.res;
+
+import com.seamew.lottery.common.Result;
+
+/**
+ * @Author: seamew
+ * @Title: PartakeResult
+ * @CreateTime: 2023年02月22日 16:47:00
+ * @Description:
+ * @Version: 1.0
+ */
+public class PartakeResult extends Result {
+    /**
+     * 策略ID
+     */
+    private Long strategyId;
+
+    public PartakeResult(String code, String info) {
+        super(code, info);
+    }
+
+    public Long getStrategyId() {
+        return strategyId;
+    }
+
+    public void setStrategyId(Long strategyId) {
+        this.strategyId = strategyId;
+    }
+}

+ 63 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/model/vo/ActivityBillVO.java

@@ -0,0 +1,63 @@
+package com.seamew.lottery.domain.activity.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * @Author: seamew
+ * @Title: ActivityBillVO
+ * @CreateTime: 2023年02月22日 16:49:00
+ * @Description: 活动账单【库存、状态、日期、个人参与次数】
+ * @Version: 1.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ActivityBillVO {
+    /**
+     * 用户ID
+     */
+    private String uId;
+
+    /**
+     * 活动ID
+     */
+    private Long activityId;
+    /**
+     * 活动名称
+     */
+    private String activityName;
+    /**
+     * 开始时间
+     */
+    private Date beginDateTime;
+    /**
+     * 结束时间
+     */
+    private Date endDateTime;
+    /**
+     * 库存剩余
+     */
+    private Integer stockSurplusCount;
+    /**
+     * 活动状态:1编辑、2提审、3撤审、4通过、5运行(审核通过后worker扫描状态)、6拒绝、7关闭、8开启
+     * Constants.ActivityState
+     */
+    private Integer state;
+    /**
+     * 策略ID
+     */
+    private Long strategyId;
+
+    /**
+     * 每人可参与次数
+     */
+    private Integer takeCount;
+    /**
+     * 已领取次数
+     */
+    private Integer userTakeLeftCount;
+}

+ 16 - 4
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/repository/IActivityRepository.java

@@ -1,10 +1,8 @@
 package com.seamew.lottery.domain.activity.repository;
 
 import com.seamew.lottery.common.Constants;
-import com.seamew.lottery.domain.activity.model.vo.ActivityVO;
-import com.seamew.lottery.domain.activity.model.vo.AwardVO;
-import com.seamew.lottery.domain.activity.model.vo.StrategyDetailVO;
-import com.seamew.lottery.domain.activity.model.vo.StrategyVO;
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
+import com.seamew.lottery.domain.activity.model.vo.*;
 
 import java.util.List;
 
@@ -52,4 +50,18 @@ public interface IActivityRepository {
      * @return              更新结果
      */
     boolean alterStatus(Long activityId, Constants.ActivityState beforeState, Constants.ActivityState afterState);
+
+    /**
+     * 查询活动账单信息【库存、状态、日期、个人参与次数】
+     * @param req 参与活动请求
+     * @return    活动账单
+     */
+    ActivityBillVO queryActivityBill(PartakeReq req);
+
+    /**
+     * 扣减活动库存
+     * @param activityId   活动ID
+     * @return      扣减结果
+     */
+    int subtractionActivityStock(Long activityId);
 }

+ 40 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/repository/IUserTakeActivityRepository.java

@@ -0,0 +1,40 @@
+package com.seamew.lottery.domain.activity.repository;
+
+import java.util.Date;
+
+/**
+ * @Author: seamew
+ * @Title: IUserTakeActivityRepository
+ * @CreateTime: 2023年02月22日 16:51:00
+ * @Description: 用户参与活动仓储接口
+ * @Version: 1.0
+ */
+public interface IUserTakeActivityRepository {
+
+    /**
+     * 扣减个人活动参与次数
+     *
+     * @param activityId        活动ID
+     * @param activityName      活动名称
+     * @param takeCount         活动个人可领取次数
+     * @param userTakeLeftCount 活动个人剩余领取次数
+     * @param uId               用户ID
+     * @param partakeDate       领取时间
+     * @return 更新结果
+     */
+    int subtractionLeftCount(Long activityId, String activityName, Integer takeCount, Integer userTakeLeftCount, String uId, Date partakeDate);
+
+    /**
+     * 领取活动
+     *
+     * @param activityId        活动ID
+     * @param activityName      活动名称
+     * @param takeCount         活动个人可领取次数
+     * @param userTakeLeftCount 活动个人剩余领取次数
+     * @param uId               用户ID
+     * @param takeDate          领取时间
+     * @param takeId            领取ID
+     */
+    void takeActivity(Long activityId, String activityName, Integer takeCount, Integer userTakeLeftCount, String uId, Date takeDate, Long takeId);
+
+}

+ 23 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/ActivityPartakeSupport.java

@@ -0,0 +1,23 @@
+package com.seamew.lottery.domain.activity.service.partake;
+
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
+import com.seamew.lottery.domain.activity.model.vo.ActivityBillVO;
+import com.seamew.lottery.domain.activity.repository.IActivityRepository;
+
+import javax.annotation.Resource;
+
+/**
+ * @Author: seamew
+ * @Title: ActivityPartakeSupport
+ * @CreateTime: 2023年02月22日 16:48:00
+ * @Description: 活动领取模操作,一些通用的数据服务
+ * @Version: 1.0
+ */
+public class ActivityPartakeSupport {
+    @Resource
+    protected IActivityRepository activityRepository;
+
+    protected ActivityBillVO queryActivityBill(PartakeReq req) {
+        return activityRepository.queryActivityBill(req);
+    }
+}

+ 73 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/BaseActivityPartake.java

@@ -0,0 +1,73 @@
+package com.seamew.lottery.domain.activity.service.partake;
+
+import com.seamew.lottery.common.Constants;
+import com.seamew.lottery.common.Result;
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
+import com.seamew.lottery.domain.activity.model.res.PartakeResult;
+import com.seamew.lottery.domain.activity.model.vo.ActivityBillVO;
+
+/**
+ * @Author: seamew
+ * @Title: BaseActivityPartake
+ * @CreateTime: 2023年02月22日 17:08:00
+ * @Description: 活动领取模板抽象类
+ * @Version: 1.0
+ */
+public abstract class BaseActivityPartake extends ActivityPartakeSupport implements IActivityPartake {
+
+    @Override
+    public PartakeResult doPartake(PartakeReq req) {
+        // 查询活动账单
+        ActivityBillVO activityBillVO = super.queryActivityBill(req);
+
+        // 活动信息校验处理【活动库存、状态、日期、个人参与次数】
+        Result checkResult = this.checkActivityBill(req, activityBillVO);
+        if (!Constants.ResponseCode.SUCCESS.getCode().equals(checkResult.getCode())) {
+            return new PartakeResult(checkResult.getCode(), checkResult.getInfo());
+        }
+
+        // 扣减活动库存【目前为直接对配置库中的 lottery.activity 直接操作表扣减库存,后续优化为Redis扣减】
+        Result subtractionActivityResult = this.subtractionActivityStock(req);
+        if (!Constants.ResponseCode.SUCCESS.getCode().equals(subtractionActivityResult.getCode())) {
+            return new PartakeResult(subtractionActivityResult.getCode(), subtractionActivityResult.getInfo());
+        }
+
+        // 领取活动信息【个人用户把活动信息写入到用户表】
+        Result grabResult = this.grabActivity(req, activityBillVO);
+        if (!Constants.ResponseCode.SUCCESS.getCode().equals(grabResult.getCode())) {
+            return new PartakeResult(grabResult.getCode(), grabResult.getInfo());
+        }
+
+        // 封装结果【返回的策略ID,用于继续完成抽奖步骤】
+        PartakeResult partakeResult = new PartakeResult(Constants.ResponseCode.SUCCESS.getCode(), Constants.ResponseCode.SUCCESS.getInfo());
+        partakeResult.setStrategyId(activityBillVO.getStrategyId());
+        return partakeResult;
+    }
+
+    /**
+     * 活动信息校验处理,把活动库存、状态、日期、个人参与次数
+     *
+     * @param partake 参与活动请求
+     * @param bill    活动账单
+     * @return 校验结果
+     */
+    protected abstract Result checkActivityBill(PartakeReq partake, ActivityBillVO bill);
+
+    /**
+     * 扣减活动库存
+     *
+     * @param req 参与活动请求
+     * @return 扣减结果
+     */
+    protected abstract Result subtractionActivityStock(PartakeReq req);
+
+    /**
+     * 领取活动
+     *
+     * @param partake 参与活动请求
+     * @param bill    活动账单
+     * @return 领取结果
+     */
+    protected abstract Result grabActivity(PartakeReq partake, ActivityBillVO bill);
+
+}

+ 20 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/IActivityPartake.java

@@ -0,0 +1,20 @@
+package com.seamew.lottery.domain.activity.service.partake;
+
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
+import com.seamew.lottery.domain.activity.model.res.PartakeResult;
+
+/**
+ * @Author: seamew
+ * @Title: IActivityPartake
+ * @CreateTime: 2023年02月22日 16:46:00
+ * @Description: 抽奖活动参与接口
+ * @Version: 1.0
+ */
+public interface IActivityPartake {
+    /**
+     * 参与活动
+     * @param req 入参
+     * @return    领取结果
+     */
+    PartakeResult doPartake(PartakeReq req);
+}

+ 108 - 0
lottery-domain/src/main/java/com/seamew/lottery/domain/activity/service/partake/impl/ActivityPartakeImpl.java

@@ -0,0 +1,108 @@
+package com.seamew.lottery.domain.activity.service.partake.impl;
+
+import com.seamew.lottery.common.Constants;
+import com.seamew.lottery.common.Result;
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
+import com.seamew.lottery.domain.activity.model.vo.ActivityBillVO;
+import com.seamew.lottery.domain.activity.repository.IUserTakeActivityRepository;
+import com.seamew.lottery.domain.activity.service.partake.BaseActivityPartake;
+import com.seamew.lottery.domain.support.ids.IIdGenerator;
+import com.seamew.middleware.db.router.strategy.IDBRouterStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * @Author: seamew
+ * @Title: ActivityPartakeImpl
+ * @CreateTime: 2023年02月22日 17:10:00
+ * @Description: 活动参与功能实现
+ * @Version: 1.0
+ */
+@Service
+@Slf4j
+public class ActivityPartakeImpl extends BaseActivityPartake {
+    @Resource
+    private IUserTakeActivityRepository userTakeActivityRepository;
+
+    @Resource
+    private Map<Constants.Ids, IIdGenerator> idGeneratorMap;
+
+    @Resource
+    private TransactionTemplate transactionTemplate;
+
+    @Resource
+    private IDBRouterStrategy dbRouter;
+
+    @Override
+    protected Result checkActivityBill(PartakeReq partake, ActivityBillVO bill) {
+        // 校验:活动状态
+        if (!Constants.ActivityState.DOING.getCode().equals(bill.getState())) {
+            log.warn("活动当前状态非可用 state:{}", bill.getState());
+            return Result.buildResult(Constants.ResponseCode.UN_ERROR, "活动当前状态非可用");
+        }
+
+        // 校验:活动日期
+        if (bill.getBeginDateTime().after(partake.getPartakeDate()) || bill.getEndDateTime().before(partake.getPartakeDate())) {
+            log.warn("活动时间范围非可用 beginDateTime:{} endDateTime:{}", bill.getBeginDateTime(), bill.getEndDateTime());
+            return Result.buildResult(Constants.ResponseCode.UN_ERROR, "活动时间范围非可用");
+        }
+
+        // 校验:活动库存
+        if (bill.getStockSurplusCount() <= 0) {
+            log.warn("活动剩余库存非可用 stockSurplusCount:{}", bill.getStockSurplusCount());
+            return Result.buildResult(Constants.ResponseCode.UN_ERROR, "活动剩余库存非可用");
+        }
+
+        // 校验:个人库存 - 个人活动剩余可领取次数
+        if (bill.getUserTakeLeftCount() <= 0) {
+            log.warn("个人领取次数非可用 userTakeLeftCount:{}", bill.getUserTakeLeftCount());
+            return Result.buildResult(Constants.ResponseCode.UN_ERROR, "个人领取次数非可用");
+        }
+
+        return Result.buildSuccessResult();
+    }
+
+    @Override
+    protected Result subtractionActivityStock(PartakeReq req) {
+        int count = activityRepository.subtractionActivityStock(req.getActivityId());
+        if (0 == count) {
+            log.error("扣减活动库存失败 activityId:{}", req.getActivityId());
+            return Result.buildResult(Constants.ResponseCode.NO_UPDATE);
+        }
+        return Result.buildSuccessResult();
+    }
+
+    @Override
+    protected Result grabActivity(PartakeReq partake, ActivityBillVO bill) {
+        try {
+            dbRouter.doRouter(partake.getUId());
+            return transactionTemplate.execute(status -> {
+                try {
+                    // 扣减个人已参与次数
+                    int updateCount = userTakeActivityRepository.subtractionLeftCount(bill.getActivityId(), bill.getActivityName(), bill.getTakeCount(), bill.getUserTakeLeftCount(), partake.getUId(), partake.getPartakeDate());
+                    if (0 == updateCount) {
+                        status.setRollbackOnly();
+                        log.error("领取活动,扣减个人已参与次数失败 activityId:{} uId:{}", partake.getActivityId(), partake.getUId());
+                        return Result.buildResult(Constants.ResponseCode.NO_UPDATE);
+                    }
+
+                    // 插入领取活动信息
+                    Long takeId = idGeneratorMap.get(Constants.Ids.SnowFlake).nextId();
+                    userTakeActivityRepository.takeActivity(bill.getActivityId(), bill.getActivityName(), bill.getTakeCount(), bill.getUserTakeLeftCount(), partake.getUId(), partake.getPartakeDate(), takeId);
+                } catch (DuplicateKeyException e) {
+                    status.setRollbackOnly();
+                    log.error("领取活动,唯一索引冲突 activityId:{} uId:{}", partake.getActivityId(), partake.getUId(), e);
+                    return Result.buildResult(Constants.ResponseCode.INDEX_DUP);
+                }
+                return Result.buildSuccessResult();
+            });
+        } finally {
+            dbRouter.clear();
+        }
+    }
+}

+ 7 - 0
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/dao/IActivityDao.java

@@ -38,4 +38,11 @@ public interface IActivityDao {
      */
     int alterState(AlterStateVO alterStateVO);
 
+    /**
+     * 扣减活动库存
+     * @param activityId 活动ID
+     * @return 更新数量
+     */
+    int subtractionActivityStock(Long activityId);
+
 }

+ 40 - 0
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/dao/IUserTakeActivityCountDao.java

@@ -0,0 +1,40 @@
+package com.seamew.lottery.infrastructure.dao;
+
+import com.seamew.lottery.infrastructure.po.UserTakeActivityCount;
+import com.seamew.middleware.db.router.annotation.DBRouter;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Author: seamew
+ * @Title: IUserTakeActivityCountDao
+ * @CreateTime: 2023年02月22日 16:52:00
+ * @Description: 用户活动参与次数表Dao
+ * @Version: 1.0
+ */
+@Mapper
+public interface IUserTakeActivityCountDao {
+
+    /**
+     * 查询用户领取次数信息
+     * @param userTakeActivityCountReq 请求入参【活动号、用户ID】
+     * @return 领取结果
+     */
+    @DBRouter
+    UserTakeActivityCount queryUserTakeActivityCount(UserTakeActivityCount userTakeActivityCountReq);
+
+    /**
+     * 插入领取次数信息
+     * @param userTakeActivityCount 请求入参
+     */
+    @DBRouter
+    void insert(UserTakeActivityCount userTakeActivityCount);
+
+    /**
+     * 更新领取次数信息
+     * @param userTakeActivityCount 请求入参
+     * @return 更新数量
+     */
+    @DBRouter
+    int updateLeftCount(UserTakeActivityCount userTakeActivityCount);
+
+}

+ 46 - 12
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/po/Activity.java

@@ -17,40 +17,74 @@ import java.util.Date;
 @NoArgsConstructor
 @AllArgsConstructor
 public class Activity {
-    // 自增ID
+    /**
+     * 自增ID
+     */
     private Long id;
 
-    // 活动ID
+    /**
+     * 活动ID
+     */
     private Long activityId;
 
-    // 活动名称
+    /**
+     * 活动名称
+     */
     private String activityName;
 
-    // 活动描述
+    /**
+     * 活动描述
+     */
     private String activityDesc;
 
-    // 开始时间
+    /**
+     * 开始时间
+     */
     private Date beginDateTime;
 
-    // 结束时间
+    /**
+     * 结束时间
+     */
     private Date endDateTime;
 
-    // 库存
+    /**
+     * 库存
+     */
     private Integer stockCount;
 
-    // 每人可参与次数
+    /**
+     * 库存剩余
+     */
+    private Integer stockSurplusCount;
+
+    /**
+     * 每人可参与次数
+     */
     private Integer takeCount;
 
-    // 活动状态:编辑、提审、撤审、通过、运行、拒绝、关闭、开启
+    /**
+     * 策略ID
+     */
+    private Long strategyId;
+
+    /**
+     * 活动状态:1编辑、2提审、3撤审、4通过、5运行(审核通过后worker扫描状态)、6拒绝、7关闭、8开启
+     */
     private Integer state;
 
-    // 创建人
+    /**
+     * 创建人
+     */
     private String creator;
 
-    // 创建时间
+    /**
+     * 创建时间
+     */
     private Date createTime;
 
-    // 修改时间
+    /**
+     * 修改时间
+     */
     private Date updateTime;
 
 }

+ 48 - 0
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/po/UserTakeActivityCount.java

@@ -0,0 +1,48 @@
+package com.seamew.lottery.infrastructure.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * @Author: seamew
+ * @Title: UserTakeActivityCount
+ * @CreateTime: 2023年02月22日 16:52:00
+ * @Description: 用户活动参与次数表
+ * @Version: 1.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserTakeActivityCount {
+    /**
+     * 自增ID
+     */
+    private Long id;
+    /**
+     * 用户ID
+     */
+    private String uId;
+    /**
+     * 活动ID
+     */
+    private Long activityId;
+    /**
+     * 可领取次数
+     */
+    private Integer totalCount;
+    /**
+     * 已领取次数
+     */
+    private Integer leftCount;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}

+ 39 - 8
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/repository/ActivityRepository.java

@@ -1,16 +1,11 @@
 package com.seamew.lottery.infrastructure.repository;
 
 import com.seamew.lottery.common.Constants;
+import com.seamew.lottery.domain.activity.model.req.PartakeReq;
 import com.seamew.lottery.domain.activity.model.vo.*;
 import com.seamew.lottery.domain.activity.repository.IActivityRepository;
-import com.seamew.lottery.infrastructure.dao.IActivityDao;
-import com.seamew.lottery.infrastructure.dao.IAwardDao;
-import com.seamew.lottery.infrastructure.dao.IStrategyDao;
-import com.seamew.lottery.infrastructure.dao.IStrategyDetailDao;
-import com.seamew.lottery.infrastructure.po.Activity;
-import com.seamew.lottery.infrastructure.po.Award;
-import com.seamew.lottery.infrastructure.po.Strategy;
-import com.seamew.lottery.infrastructure.po.StrategyDetail;
+import com.seamew.lottery.infrastructure.dao.*;
+import com.seamew.lottery.infrastructure.po.*;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Component;
 
@@ -36,6 +31,9 @@ public class ActivityRepository implements IActivityRepository {
     private IStrategyDao strategyDao;
     @Resource
     private IStrategyDetailDao strategyDetailDao;
+    @Resource
+    private IUserTakeActivityCountDao userTakeActivityCountDao;
+
 
     @Override
     public void addActivity(ActivityVO activity) {
@@ -80,4 +78,37 @@ public class ActivityRepository implements IActivityRepository {
         return 1 == count;
     }
 
+    @Override
+    public ActivityBillVO queryActivityBill(PartakeReq req) {
+
+        // 查询活动信息
+        Activity activity = activityDao.queryActivityById(req.getActivityId());
+
+        // 查询领取次数
+        UserTakeActivityCount userTakeActivityCountReq = new UserTakeActivityCount();
+        userTakeActivityCountReq.setUId(req.getUId());
+        userTakeActivityCountReq.setActivityId(req.getActivityId());
+        UserTakeActivityCount userTakeActivityCount = userTakeActivityCountDao.queryUserTakeActivityCount(userTakeActivityCountReq);
+
+        // 封装结果信息
+        ActivityBillVO activityBillVO = new ActivityBillVO();
+        activityBillVO.setUId(req.getUId());
+        activityBillVO.setActivityId(req.getActivityId());
+        activityBillVO.setActivityName(activity.getActivityName());
+        activityBillVO.setBeginDateTime(activity.getBeginDateTime());
+        activityBillVO.setEndDateTime(activity.getEndDateTime());
+        activityBillVO.setTakeCount(activity.getTakeCount());
+        activityBillVO.setStockSurplusCount(activity.getStockSurplusCount());
+        activityBillVO.setStrategyId(activity.getStrategyId());
+        activityBillVO.setState(activity.getState());
+        activityBillVO.setUserTakeLeftCount(null == userTakeActivityCount ? null : userTakeActivityCount.getLeftCount());
+
+        return activityBillVO;
+    }
+
+    @Override
+    public int subtractionActivityStock(Long activityId) {
+        return activityDao.subtractionActivityStock(activityId);
+    }
+
 }

+ 67 - 0
lottery-infrastructure/src/main/java/com/seamew/lottery/infrastructure/repository/UserTakeActivityRepository.java

@@ -0,0 +1,67 @@
+package com.seamew.lottery.infrastructure.repository;
+
+import com.seamew.lottery.domain.activity.repository.IUserTakeActivityRepository;
+import com.seamew.lottery.infrastructure.dao.IUserTakeActivityCountDao;
+import com.seamew.lottery.infrastructure.dao.IUserTakeActivityDao;
+import com.seamew.lottery.infrastructure.po.UserTakeActivity;
+import com.seamew.lottery.infrastructure.po.UserTakeActivityCount;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * @Author: seamew
+ * @Title: UserTakeActivityRepository
+ * @CreateTime: 2023年02月22日 16:51:00
+ * @Description:
+ * @Version: 1.0
+ */
+@Component
+public class UserTakeActivityRepository implements IUserTakeActivityRepository {
+
+    @Resource
+    private IUserTakeActivityCountDao userTakeActivityCountDao;
+
+    @Resource
+    private IUserTakeActivityDao userTakeActivityDao;
+
+
+    @Override
+    public int subtractionLeftCount(Long activityId, String activityName, Integer takeCount, Integer userTakeLeftCount, String uId, Date partakeDate) {
+        if (null == userTakeLeftCount) {
+            UserTakeActivityCount userTakeActivityCount = new UserTakeActivityCount();
+            userTakeActivityCount.setUId(uId);
+            userTakeActivityCount.setActivityId(activityId);
+            userTakeActivityCount.setTotalCount(takeCount);
+            userTakeActivityCount.setLeftCount(takeCount - 1);
+            userTakeActivityCountDao.insert(userTakeActivityCount);
+            return 1;
+        } else {
+            UserTakeActivityCount userTakeActivityCount = new UserTakeActivityCount();
+            userTakeActivityCount.setUId(uId);
+            userTakeActivityCount.setActivityId(activityId);
+            return userTakeActivityCountDao.updateLeftCount(userTakeActivityCount);
+        }
+    }
+
+    @Override
+    public void takeActivity(Long activityId, String activityName, Integer takeCount, Integer userTakeLeftCount, String uId, Date takeDate, Long takeId) {
+        UserTakeActivity userTakeActivity = new UserTakeActivity();
+        userTakeActivity.setUId(uId);
+        userTakeActivity.setTakeId(takeId);
+        userTakeActivity.setActivityId(activityId);
+        userTakeActivity.setActivityName(activityName);
+        userTakeActivity.setTakeDate(takeDate);
+        if (null == userTakeLeftCount) {
+            userTakeActivity.setTakeCount(1);
+        } else {
+            userTakeActivity.setTakeCount(takeCount - userTakeLeftCount);
+        }
+        String uuid = uId + "_" + activityId + "_" + userTakeActivity.getTakeCount();
+        userTakeActivity.setUuid(uuid);
+
+        userTakeActivityDao.insert(userTakeActivity);
+    }
+
+}

+ 5 - 0
lottery-interfaces/src/main/resources/mybatis/mapper/Activity_Mapper.xml

@@ -25,5 +25,10 @@
           AND state = #{beforeState}
     </update>
 
+    <update id="subtractionActivityStock" parameterType="java.lang.Long">
+        UPDATE activity SET stock_surplus_count = stock_surplus_count - 1
+        WHERE activity_id = #{activityId} AND stock_surplus_count > 0
+    </update>
+
 
 </mapper>

+ 28 - 0
lottery-interfaces/src/main/resources/mybatis/mapper/UserTakeActivityCount_Mapper.xml

@@ -0,0 +1,28 @@
+<?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="com.seamew.lottery.infrastructure.dao.IUserTakeActivityCountDao">
+
+    <insert id="insert" parameterType="com.seamew.lottery.infrastructure.po.UserTakeActivityCount">
+        INSERT INTO user_take_activity_count
+            (u_id, activity_id, total_count, left_count, create_time, update_time)
+        VALUES (#{uId}, #{activityId}, #{totalCount}, #{leftCount}, now(), now())
+    </insert>
+
+    <select id="queryUserTakeActivityCount" parameterType="com.seamew.lottery.infrastructure.po.UserTakeActivityCount"
+            resultType="com.seamew.lottery.infrastructure.po.UserTakeActivityCount">
+        SELECT total_count, left_count
+        FROM user_take_activity_count
+        WHERE u_id = #{uId}
+          AND activity_id = #{activityId}
+    </select>
+
+    <update id="updateLeftCount" parameterType="com.seamew.lottery.infrastructure.po.UserTakeActivityCount">
+        UPDATE user_take_activity_count
+        SET left_count = left_count - 1
+        WHERE u_id = #{uId}
+          AND activity_id = #{activityId}
+          AND left_count > 0
+    </update>
+
+
+</mapper>