Pārlūkot izejas kodu

Merge branch 'mp-server-test' into 'master'

Mp server test

See merge request quanshu/mp-server!645
zhong chunping 2 gadi atpakaļ
vecāks
revīzija
486c10abe5
20 mainītis faili ar 470 papildinājumiem un 43 dzēšanām
  1. 7 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsMgrController.java
  2. 45 5
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/MarketingMgrController.java
  3. 77 3
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/MarketingController.java
  4. 37 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java
  5. 2 2
      mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java
  6. 36 0
      mp-common/src/main/java/com/qs/mp/common/enums/MarketingCodeTypeEnum.java
  7. 2 1
      mp-framework/src/main/java/com/qs/mp/framework/config/SecurityConfig.java
  8. 4 0
      mp-service/src/main/java/com/qs/mp/admin/domain/Marketing.java
  9. 6 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsQueryParam.java
  10. 3 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/MarketingCreateParam.java
  11. 4 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/MarketingUpdateParam.java
  12. 28 0
      mp-service/src/main/java/com/qs/mp/admin/domain/vo/MarketingDataVO.java
  13. 13 0
      mp-service/src/main/java/com/qs/mp/admin/service/IMarketingService.java
  14. 157 20
      mp-service/src/main/java/com/qs/mp/admin/service/impl/MarketingServiceImpl.java
  15. 1 0
      mp-service/src/main/java/com/qs/mp/framework/redis/RedisLockKey.java
  16. 16 0
      mp-service/src/main/java/com/qs/mp/user/domain/UserCoupon.java
  17. 14 0
      mp-service/src/main/java/com/qs/mp/user/domain/vo/UserCouponVO.java
  18. 3 0
      mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingDetailVO.java
  19. 3 0
      mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingListVO.java
  20. 12 12
      mp-service/src/main/java/com/qs/mp/user/service/impl/UserDeliverOrderServiceImpl.java

+ 7 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsMgrController.java

@@ -112,6 +112,13 @@ public class GoodsMgrController extends BaseApiController {
         .ge(null != queryParam.getMinValue(), Goods::getValue, queryParam.getMinValue());
     queryWrapper.lambda()
         .le(null != queryParam.getMaxValue(), Goods::getValue, queryParam.getMaxValue());
+
+    // 盲豆兑换价格
+    queryWrapper.lambda()
+            .ge(null != queryParam.getMinExchange(), Goods::getExchangePrice, queryParam.getMinExchange());
+    queryWrapper.lambda()
+            .le(null != queryParam.getMaxExchange(), Goods::getExchangePrice, queryParam.getMaxExchange());
+
     // 状态
     queryWrapper.lambda()
         .eq(null != queryParam.getStatus(), Goods::getStatus, queryParam.getStatus());

+ 45 - 5
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/MarketingMgrController.java

@@ -12,10 +12,7 @@ import com.qs.mp.admin.domain.param.MarketingCreateParam;
 import com.qs.mp.admin.domain.param.MarketingHitPrizeExportParam;
 import com.qs.mp.admin.domain.param.MarketingQueryParam;
 import com.qs.mp.admin.domain.param.MarketingUpdateParam;
-import com.qs.mp.admin.domain.vo.MarketingAwardsVO;
-import com.qs.mp.admin.domain.vo.MarketingListVO;
-import com.qs.mp.admin.domain.vo.MarketingUserCodeListVO;
-import com.qs.mp.admin.domain.vo.MarketingVO;
+import com.qs.mp.admin.domain.vo.*;
 import com.qs.mp.admin.service.IMarketingAwardsPrizeService;
 import com.qs.mp.admin.service.IMarketingAwardsService;
 import com.qs.mp.admin.service.IMarketingService;
@@ -73,6 +70,17 @@ public class MarketingMgrController extends BaseApiController {
     @Autowired
     private IMarketingHitPrizeService marketingHitPrizeService;
 
+    @PreAuthorize("@ss.hasPermi('business:marketing:copy')")
+    @PostMapping("/copy/{marketingId}")
+    @ApiOperation("拷贝营销活动")
+    public AjaxResult copy(@PathVariable("marketingId") Long marketingId) {
+
+        marketingService.copyById(marketingId);
+
+        return AjaxResult.success();
+    }
+
+
     @Log(title = "营销活动新增", businessType = BusinessType.INSERT)
     @ApiOperation(value = "营销活动新增")
     @PostMapping("/create")
@@ -210,10 +218,42 @@ public class MarketingMgrController extends BaseApiController {
     @PostMapping("/data/{id}")
     @PreAuthorize("@ss.hasPermi('business:marketing:queryData')")
     @ApiOperation("活动数据")
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "success", response = MarketingDataVO.class)
+    )
+    public AjaxResult dataInfo(@PathVariable("id") Long id) {
+        MarketingDataVO marketingDataVO = new MarketingDataVO();
+        Marketing marketing = marketingService.getById(id);
+        if (Objects.isNull(marketing)) {
+            return AjaxResult.error("活动信息不存在");
+        }
+        marketingDataVO.setTitle(marketing.getTitle());
+        marketingDataVO.setRealNum(marketing.getRealNum());
+
+
+        int codeCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                .eq(MarketingUserCode::getMarketingId, id)
+                .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue()));
+        marketingDataVO.setCodeCount(codeCount);
+
+
+        int newUserCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                .eq(MarketingUserCode::getMarketingId, id)
+                .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue())
+                .ne(MarketingUserCode::getHelpUserId, -1));
+
+        marketingDataVO.setNewUserCount(newUserCount);
+
+        return AjaxResult.success(marketingDataVO);
+    }
+
+    @PostMapping("/data/codeList/{id}")
+    @PreAuthorize("@ss.hasPermi('business:marketing:queryData')")
+    @ApiOperation("活动抽奖码数据")
     @ApiResponses(
             @ApiResponse(code = 200, message = "success", response = MarketingUserCodeListVO.class)
     )
-    public TableDataInfo dataInfo(@PathVariable("id") Long id) {
+    public TableDataInfo dataCodeList(@PathVariable("id") Long id) {
         startPage();
         QueryWrapper<MarketingUserCode> queryWrapper = new QueryWrapper<>();
         queryWrapper.eq("t1.marketing_id", id);

+ 77 - 3
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/MarketingController.java

@@ -1,6 +1,7 @@
 package com.qs.mp.web.controller.api.user;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.admin.domain.MarketingAwards;
@@ -12,11 +13,13 @@ import com.qs.mp.admin.service.IMarketingService;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.core.redis.DistributedLocker;
+import com.qs.mp.common.enums.MarketingCodeTypeEnum;
 import com.qs.mp.common.enums.MarketingStatusEnum;
 import com.qs.mp.common.enums.UserTypeEnum;
 import com.qs.mp.common.exception.ServiceException;
 import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.framework.redis.RedisLockKey;
 import com.qs.mp.framework.security.handle.HostHolder;
 import com.qs.mp.system.domain.SysUser;
 import com.qs.mp.system.service.ISysUserService;
@@ -83,6 +86,76 @@ public class MarketingController extends BaseApiController {
     @Autowired
     private ISysUserService sysUserService;
 
+    @PostMapping("/generateCode/{marketingId}")
+    @ApiOperation("立即获取抽奖码")
+    public AjaxResult generateCode(@PathVariable("marketingId") Long marketingId) {
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        if (Objects.isNull(userId)) {
+            return AjaxResult.error("用户未登录");
+        }
+
+        Marketing marketing = marketingService.getById(marketingId);
+        if (Objects.isNull(marketing)) {
+            return AjaxResult.error("活动不存在");
+        }
+        // 未开启的活动不能获取抽奖码
+        if (!MarketingStatusEnum.ON.getValue().equals(marketing.getIsOn())) {
+            return AjaxResult.error("活动未开启~");
+        }
+        Date now = DateUtils.getNowDate();
+        // 结束的活动不支持获取抽奖码
+        if (marketing.getTriggerStatus() == 1 || marketing.getEndTime().before(now)) {
+            return AjaxResult.error("活动已过期~");
+        }
+        // 未开始的活动不能获取抽奖码
+        if (marketing.getStartTime().after(now)) {
+            return AjaxResult.error("活动未开始~");
+        }
+
+        if (!marketing.getCodeType().equals(MarketingCodeTypeEnum.INSTANT.getValue())) {
+            return AjaxResult.error("错误请求");
+        }
+
+        String lockKey = RedisLockKey.build(RedisLockKey.MARKETING_REAL_NUM_LOCK, marketingId);
+        if (!distributedLocker.tryLock(lockKey)) {
+            return AjaxResult.error("活动太火爆了,请稍后重试!");
+        }
+
+        try {
+            marketingService.generateCode(marketingId, userId);
+        }finally {
+            distributedLocker.unlock(lockKey);
+        }
+
+        return AjaxResult.success("获取成功");
+
+    }
+
+
+    @PostMapping("/recent")
+    @ApiOperation("获取已开始且最近要开奖的营销活动")
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "OK", response = UserMarketingListVO.class)
+    )
+    public AjaxResult getRecentMarketing() {
+        Date nowDate = DateUtils.getNowDate();
+        LambdaQueryWrapper<Marketing> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
+        queryWrapper.eq(Marketing::getTriggerStatus, 0);
+        queryWrapper.le(Marketing::getStartTime, nowDate);
+        queryWrapper.ge(Marketing::getEndTime, nowDate);
+        queryWrapper.orderByAsc(Marketing::getEndTime, Marketing::getStartTime);
+        List<Marketing> marketingList = marketingService.list(queryWrapper);
+        if (CollectionUtils.isNotEmpty(marketingList)) {
+            UserMarketingListVO userMarketingListVO = new UserMarketingListVO();
+            BeanUtils.copyProperties(marketingList.get(0), userMarketingListVO);
+            return success(userMarketingListVO);
+        }
+
+        return AjaxResult.success();
+    }
+
+
     @PostMapping("/userInfo/{inviteCode}")
     @ApiOperation("通过邀请码获取用户信息")
     @ApiResponses(
@@ -138,7 +211,7 @@ public class MarketingController extends BaseApiController {
             return AjaxResult.error("不能助力自己哦");
         }
 
-        String lockKey = String.format(MARKETING_REAL_NUM_LOCK, marketing.getId());
+        String lockKey = RedisLockKey.build(RedisLockKey.MARKETING_REAL_NUM_LOCK, marketingHelpParam.getMarketingId());
 
         if (!distributedLocker.tryLock(lockKey)) {
             return AjaxResult.error("活动太火爆了,请稍后重试!");
@@ -186,10 +259,11 @@ public class MarketingController extends BaseApiController {
         if (userMarketingQueryParam.getTriggerStatus() == 0) {
             // 已开启的列表
             Date now = DateUtils.getNowDate();
+            // 开始时间小于当前时间的
+            queryWrapper.le(Marketing::getStartTime, now);
             // 结束时间大于当前时间的
             queryWrapper.gt(Marketing::getEndTime, now);
-            queryWrapper.orderByAsc(Marketing::getStartTime);
-            queryWrapper.orderByAsc(Marketing::getEndTime);
+            queryWrapper.orderByAsc(Marketing::getEndTime, Marketing::getStartTime);
         }else if(userMarketingQueryParam.getTriggerStatus() == 1) {
             // 开奖的排序
             queryWrapper.orderByDesc(Marketing::getEndTime);

+ 37 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java

@@ -8,6 +8,7 @@ import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.channel.domain.ChannelOrder;
 import com.qs.mp.channel.domain.param.OrderPayParam;
 import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.BizTypeEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
@@ -35,6 +36,9 @@ import io.swagger.annotations.ApiOperation;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import javax.validation.Valid;
+
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
 import org.apache.pulsar.client.api.PulsarClientException;
@@ -209,6 +213,9 @@ public class UserTicketOrderController extends BaseApiController {
    */
   @PostMapping("/order/coupon/list")
   @ApiOperation(value = "查询可用优惠券" , notes = "在下单页面选择")
+  @ApiResponses(
+          @ApiResponse(code = 200, message = "成功", response = UserCouponVO.class)
+  )
   public AjaxResult listCoupon(@RequestBody TicketOrderParam param) {
     Long userId = SecurityUtils.getUserId();
     TicketOrderSettleVO orderSettleVO = redisCache.getCacheObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
@@ -232,4 +239,34 @@ public class UserTicketOrderController extends BaseApiController {
     return AjaxResult.success(userCouponVOList);
   }
 
+
+  @PostMapping("/order/coupon/listPage")
+  @ApiOperation(value = "查询可用优惠券,分页" , notes = "在下单页面选择")
+  @ApiResponses(
+          @ApiResponse(code = 200, message = "成功", response = UserCouponVO.class)
+  )
+  public TableDataInfo listPageCoupon(@RequestBody TicketOrderParam param) {
+    Long userId = SecurityUtils.getUserId();
+    TicketOrderSettleVO orderSettleVO = redisCache.getCacheObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
+    if (null == orderSettleVO) {
+      return getErrorDataTable("订单已过期,请重新下单");
+    }
+    TicketBox ticketBox = ticketBoxService.getById(orderSettleVO.getBoxId());
+    startPage();
+    List<UserCouponVO> userCouponVOList = userCouponService.queryUserCouponList(userId, orderSettleVO.getOrderAmt(), ticketBox);
+
+    // 设置选中状态
+    for (UserCouponVO userCouponVO : userCouponVOList) {
+      if (!CollectionUtils.isEmpty(orderSettleVO.getCouponList())) {
+        for (UserCoupon4OrderVO userCoupon4OrderVO : orderSettleVO.getCouponList()) {
+          if (userCoupon4OrderVO.getId().equals(userCouponVO.getId())) {
+            userCouponVO.setChecked(true);
+            break;
+          }
+        }
+      }
+    }
+    return getDataTable(userCouponVOList);
+  }
+
 }

+ 2 - 2
mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java

@@ -11,9 +11,9 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 public enum CoinLogTypeEnum implements IEnum<Integer> {
 
   PRIZE(1, "盲票奖品"),
-  EXCHANGE(2, "商品兑换"),
+  EXCHANGE(2, "兑换商品"),
   MARKETING(3,"营销活动"),
-  RECOVERY(4,"商品回收");
+  RECOVERY(4,"商品兑换");
 
 
   private final int value;

+ 36 - 0
mp-common/src/main/java/com/qs/mp/common/enums/MarketingCodeTypeEnum.java

@@ -0,0 +1,36 @@
+package com.qs.mp.common.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import io.swagger.annotations.ApiModel;
+
+/**
+ * 活动邀请码获取枚举类
+ *
+ * @author Cup
+ * @date 2022/5/30
+ */
+@ApiModel("活动邀请码获取枚举类")
+public enum MarketingCodeTypeEnum implements IEnum<Integer> {
+
+    INSTANT(1, "立即获取邀请码"),
+    HELP(2, "助力获取邀请码");
+
+
+    private Integer value;
+    private String desc;
+
+    MarketingCodeTypeEnum(Integer value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+
+    @Override
+    public Integer getValue() {
+        return this.value;
+    }
+}

+ 2 - 1
mp-framework/src/main/java/com/qs/mp/framework/config/SecurityConfig.java

@@ -144,7 +144,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                     "/api/v1/mp/user/marketing/list",
                     "/api/v1/mp/user/marketing/detail/*",
                     "/api/v1/mp/user/marketing/userInfo/*",
-                    "/api/v1/mp/user/exchange/category/listTree"
+                    "/api/v1/mp/user/exchange/category/listTree",
+                    "/api/v1/mp/user/marketing/recent"
                 ).permitAll()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()

+ 4 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/Marketing.java

@@ -83,6 +83,10 @@ public class Marketing implements Serializable {
     @TableField("description")
     private String description;
 
+    @ApiModelProperty("code获取类型,1可立即获得,2必须助力")
+    @TableField("code_type")
+    private Integer codeType;
+
     /**
      * 是否开启: -1关闭,0待开启, 1开启  默认0
      */

+ 6 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsQueryParam.java

@@ -67,6 +67,12 @@ public class GoodsQueryParam {
 	@ApiModelProperty(value = "最高价格", required = false)
 	private Integer maxValue;
 
+	@ApiModelProperty("最低兑换价格")
+	private Integer minExchange;
+
+	@ApiModelProperty("最高兑换价格")
+	private Integer maxExchange;
+
 	/**
 	 * 兑换大厅是否展示,0不展示,1展示
 	 */

+ 3 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/MarketingCreateParam.java

@@ -43,6 +43,9 @@ public class MarketingCreateParam {
     @ApiModelProperty(value = "活动描述",required = false)
     private String description;
 
+    @ApiModelProperty("code获取类型,1可立即获得,2必须助力")
+    private Integer codeType;
+
     @NotEmpty(message = "奖级列表不能为空")
     @ApiModelProperty(value = "奖级列表", required = true)
     List<MarketingAwardsParam> awardsList;

+ 4 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/MarketingUpdateParam.java

@@ -1,5 +1,6 @@
 package com.qs.mp.admin.domain.param;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -43,6 +44,9 @@ public class MarketingUpdateParam {
     @NotNull(message = "结束时间不能为空")
     private Date endTime;
 
+    @ApiModelProperty("code获取类型,1可立即获得,2必须助力")
+    private Integer codeType;
+
     @ApiModelProperty(value = "活动描述",required = false)
     private String description;
 

+ 28 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/vo/MarketingDataVO.java

@@ -0,0 +1,28 @@
+package com.qs.mp.admin.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 营销活动数据出参类
+ * @author Cup
+ * @date 2022/5/31
+ */
+@ApiModel("营销活动数据出参类")
+@Data
+public class MarketingDataVO {
+
+    @ApiModelProperty("活动名称")
+    private String title;
+
+    @ApiModelProperty("真实参与用户量")
+    private Integer realNum;
+
+    @ApiModelProperty("抽奖码数量")
+    private Integer codeCount;
+
+    @ApiModelProperty("新用户数")
+    private Integer newUserCount;
+
+}

+ 13 - 0
mp-service/src/main/java/com/qs/mp/admin/service/IMarketingService.java

@@ -57,4 +57,17 @@ public interface IMarketingService extends IService<Marketing> {
      * @param marketing
      */
     void lottery(Marketing marketing);
+
+    /**
+     * 立即获取抽奖码
+     * @param marketingId
+     * @param userId
+     */
+    void generateCode(Long marketingId, Long userId);
+
+    /**
+     * 拷贝营销活动
+     * @param marketingId
+     */
+    void copyById(Long marketingId);
 }

+ 157 - 20
mp-service/src/main/java/com/qs/mp/admin/service/impl/MarketingServiceImpl.java

@@ -62,6 +62,10 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
     // 普通奖池
     public static final String MARKETING_LOTTERY_ORDINARY_POOL = "MARKETING_LOTTERY_ORDINARY_POOL:%s";
 
+    // 普通用户低阶奖池
+    public static final String MARKETING_LOW_LOTTERY_ORDINARY_POOL = "MARKETING_LOW_LOTTERY_ORDINARY_POOL:%s";
+
+
     protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
 
     @Autowired
@@ -108,12 +112,100 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
     private DistributedLocker distributedLocker;
 
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void copyById(Long marketingId) {
+        Marketing marketing = this.getById(marketingId);
+        if (Objects.isNull(marketing)) {
+            throw new ServiceException("活动不存在");
+        }
+        // 初始化活动
+        marketing.setId(null);
+        marketing.setFakeNum(0);
+        marketing.setRealNum(0);
+        marketing.setIsOn(MarketingStatusEnum.OFF.getValue());
+        marketing.setIsSend(0);
+        marketing.setTriggerStatus(0);
+        marketing.setCreatedTime(null);
+        Assert.isTrue(this.save(marketing), "复制营销活动失败");
+
+        List<MarketingAwards> marketingAwardsList = marketingAwardsService.list(new LambdaQueryWrapper<MarketingAwards>().eq(MarketingAwards::getMarketingId, marketingId));
+        if (CollectionUtils.isEmpty(marketingAwardsList)) {
+            throw new ServiceException("活动奖级信息不存在");
+        }
+        for (MarketingAwards marketingAwards : marketingAwardsList) {
+            List<MarketingAwardsPrize> marketingAwardsPrizeList = marketingAwardsPrizeService.list(new LambdaQueryWrapper<MarketingAwardsPrize>()
+                    .eq(MarketingAwardsPrize::getMarketingId, marketingId)
+                    .eq(MarketingAwardsPrize::getAwardsId, marketingAwards.getId()));
+            marketingAwards.setId(null);
+            marketingAwards.setMarketingId(marketing.getId());
+            Assert.isTrue(marketingAwardsService.save(marketingAwards),"复制营销活动奖级失败");
+            for (MarketingAwardsPrize marketingAwardsPrize : marketingAwardsPrizeList) {
+                marketingAwardsPrize.setId(null);
+                marketingAwardsPrize.setAwardsId(marketingAwards.getId());
+                marketingAwardsPrize.setMarketingId(marketing.getId());
+            }
+            Assert.isTrue(marketingAwardsPrizeService.saveBatch(marketingAwardsPrizeList),"复制营销活动奖品失败");
+        }
+
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void generateCode(Long marketingId, Long userId) {
+
+        // 判断是否已经获取过
+        int count = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                .eq(MarketingUserCode::getUserId, userId)
+                .eq(MarketingUserCode::getMarketingId, marketingId)
+                .eq(MarketingUserCode::getHelpUserId, -1L));
+        if (count > 0) {
+            throw new ServiceException("您已经获取过抽奖码了");
+        }
+
+
+        // 生成唯一抽奖码
+        String code = getOnlyCode(marketingId);
+
+        MarketingUserCode marketingUserCode = new MarketingUserCode();
+        // 设置活动id
+        marketingUserCode.setMarketingId(marketingId);
+        // 设置抽奖码
+        marketingUserCode.setCode(code);
+        // 设置用户
+        marketingUserCode.setUserId(userId);
+        // -1为无人助力获取抽奖码
+        marketingUserCode.setHelpUserId(-1L);
+        // 设置用户类型
+        marketingUserCode.setUserType(UserTypeEnum.ORDINARY.getValue());
+
+        // 保存助力信息
+        marketingUserCodeService.save(marketingUserCode);
+
+        Marketing marketing = this.getById(marketingId);
+
+
+        // 真实用户
+        int realNum = marketingUserCodeService.countRealUserNumByMarketingId(marketing.getId());
+        // 获取最新活动信息
+        marketing.setRealNum(realNum);
+        int randomNum = (int) 1 + (int) (Math.random() * 10);
+        marketing.setFakeNum(marketing.getFakeNum() + randomNum);
+        // 更新活动参与人数
+        boolean rtn = this.updateById(marketing);
+        Assert.isTrue(rtn, "更新活动参与人数异常。marketingId:" + marketing.getId());
+
+    }
+
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void lottery(Marketing marketing) {
 
         // 用户抽奖池
         String userLotteryPool = String.format(MARKETING_LOTTERY_ORDINARY_POOL, marketing.getId());
+        // 用户低阶奖池
+        String userLowLotteryPool = String.format(MARKETING_LOW_LOTTERY_ORDINARY_POOL, marketing.getId());
         // 内部抽奖池
         String insideLotteryPool = String.format(MARKETING_LOTTERY_INSIDE_POOL, marketing.getId());
 
@@ -144,7 +236,6 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
         List<SysUser> insideUserList = sysUserService.selectUserListByRand(UserTypeEnum.INSIDE.getValue(), insideNum);
 
         Set<String> insideCodes = new HashSet<>();
-        Set<String> userCodes = new HashSet<>();
         for (SysUser sysUser : insideUserList) {
             // 生成抽奖码
             String code = MarketingUtils.generatePrizeCode();
@@ -174,15 +265,32 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
         redisCache.setCacheSet(insideLotteryPool, insideCodes);
 
 
-        // 获取普通用户所有的抽奖码
+        // 获取普通用户拉新所获得的所有的抽奖码
         List<MarketingUserCode> userCodeList = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
                 .eq(MarketingUserCode::getMarketingId, marketing.getId())
                 .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue()));
         if (CollectionUtils.isNotEmpty(userCodeList)) {
-            userCodes = userCodeList.stream().map(MarketingUserCode::getCode).collect(Collectors.toSet());
+            // 用户普通抽奖码
+            Set<String> userCodes = new HashSet<>();
+            // 用户低阶抽奖码
+            Set<String> userLowCodes = new HashSet<>();
+            for (MarketingUserCode marketingUserCode : userCodeList) {
+                if (marketingUserCode.getHelpUserId() == -1L) {
+                    userLowCodes.add(marketingUserCode.getCode());
+                } else {
+                    userCodes.add(marketingUserCode.getCode());
+                }
+            }
+            if (CollectionUtils.isNotEmpty(userCodes)) {
+                // 将抽奖码放入普通抽奖池
+                redisCache.setCacheSet(userLotteryPool, userCodes);
+            }
+            if (CollectionUtils.isNotEmpty(userLowCodes)) {
+                // 将抽奖码放入低阶抽奖池
+                redisCache.setCacheSet(userLowLotteryPool, userLowCodes);
+            }
         }
-        // 将抽奖码放入普通抽奖池
-        redisCache.setCacheSet(userLotteryPool, userCodes);
+
 
         // 所有中奖名单
         List<MarketingHitPrize> allHitPrizeList = new ArrayList<>();
@@ -224,10 +332,13 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
             if (userNum > 0) {
                 // 设置普通用户抽奖信息
                 for (int i = 0; i < userNum; i++) {
-                    List<String> insideCodeList = redisCache.popCacheSet(userLotteryPool, 1);
+                    List<String> hitCodeList = redisCache.popCacheSet(userLotteryPool, 1);
+                    if (CollectionUtils.isEmpty(hitCodeList)) {
+                        hitCodeList = redisCache.popCacheSet(userLowLotteryPool, 1);
+                    }
                     MarketingUserCode marketingUserCode = marketingUserCodeService.getOne(new LambdaQueryWrapper<MarketingUserCode>()
                             .eq(MarketingUserCode::getMarketingId, marketing.getId())
-                            .eq(MarketingUserCode::getCode, insideCodeList.get(0)));
+                            .eq(MarketingUserCode::getCode, hitCodeList.get(0)));
 
                     // 删除redis中该用户所有的抽奖码
                     List<MarketingUserCode> list = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
@@ -235,6 +346,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
                             .eq(MarketingUserCode::getUserId, marketingUserCode.getUserId()));
                     List<Object> delUserCodeList = list.stream().map(MarketingUserCode::getCode).collect(Collectors.toList());
                     redisCache.removeSetValueByKey(userLotteryPool, delUserCodeList);
+                    redisCache.removeSetValueByKey(userLowLotteryPool, delUserCodeList);
                     MarketingHitPrize marketingHitPrize = exchangeMarketingHitPrize(marketing, allHitPrizeList, marketingAwards, marketingAwardsPrizeList, marketingUserCode);
 
                     userHitPrizeList.add(marketingHitPrize);
@@ -281,6 +393,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
 
         // 删除抽奖池
         redisCache.deleteObject(userLotteryPool);
+        redisCache.deleteObject(userLowLotteryPool);
         redisCache.deleteObject(insideLotteryPool);
 
     }
@@ -319,19 +432,8 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
         if (count > 0) {
             throw new ServiceException("您已经助力过了");
         }
-        // 生成抽奖码
-        String code = "";
-        while (true) {
-            code = MarketingUtils.generatePrizeCode();
-            // 判断抽奖码是否已经存在
-            int codeCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
-                    .eq(MarketingUserCode::getMarketingId, marketing.getId())
-                    .eq(MarketingUserCode::getCode, code));
-            if (codeCount > 0) {
-                continue;
-            }
-            break;
-        }
+        // 生成唯一抽奖码
+        String code = getOnlyCode(marketing.getId());
 
         MarketingUserCode marketingUserCode = new MarketingUserCode();
         // 设置活动id
@@ -348,6 +450,20 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
         marketingUserCodeService.save(marketingUserCode);
 
 
+        // 自己获得一个普通抽奖码
+        MarketingUserCode myCode= new MarketingUserCode();
+        myCode.setMarketingId(marketing.getId());
+        // 设置抽奖码
+        myCode.setCode(getOnlyCode(marketing.getId()));
+        // 设置被助力人
+        myCode.setUserId(userId);
+        myCode.setHelpUserId(-1L);
+        myCode.setUserType(UserTypeEnum.ORDINARY.getValue());
+
+        // 保存抽奖码
+        marketingUserCodeService.save(myCode);
+
+
         // 真实用户
         int realNum = marketingUserCodeService.countRealUserNumByMarketingId(marketing.getId());
 
@@ -365,6 +481,27 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
 
     }
 
+    /**
+     * 获取当前活动用户唯一的抽奖码
+     * @param marketingId
+     * @return
+     */
+    private String getOnlyCode(Long marketingId) {
+        String code = "";
+        while (true) {
+            code = MarketingUtils.generatePrizeCode();
+            // 判断抽奖码是否已经存在
+            int codeCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                    .eq(MarketingUserCode::getMarketingId, marketingId)
+                    .eq(MarketingUserCode::getCode, code));
+            if (codeCount > 0) {
+                continue;
+            }
+            break;
+        }
+        return code;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void deleteById(Long id) {

+ 1 - 0
mp-service/src/main/java/com/qs/mp/framework/redis/RedisLockKey.java

@@ -10,6 +10,7 @@ import com.qs.mp.common.utils.MessageHelper;
  */
 public enum RedisLockKey {
 
+    MARKETING_REAL_NUM_LOCK("marketing_real_num_lock_{0}", "活动真实人数增加锁"),
     MARKETING_LOTTERY_KEY("marketing_lottery_key_{0}","免费抽奖活动开奖"),
     USER_TICKET_CASH_LOCK("user_ticket_cash_lock_{0}", "盲票兑奖锁");
 

+ 16 - 0
mp-service/src/main/java/com/qs/mp/user/domain/UserCoupon.java

@@ -10,6 +10,9 @@ import com.baomidou.mybatisplus.annotation.Version;
 import com.qs.mp.common.enums.UserCouponStatusEnum;
 import java.io.Serializable;
 import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 /**
@@ -19,6 +22,7 @@ import lombok.Data;
  */
 @TableName("mp_user_coupon")
 @Data
+@ApiModel("用户的优惠券实体类")
 public class UserCoupon implements Serializable {
 
   private static final long serialVersionUID = 1L;
@@ -26,60 +30,70 @@ public class UserCoupon implements Serializable {
   /**
    * 主键
    */
+  @ApiModelProperty("主键")
   @TableId(value = "id", type = IdType.INPUT)
   private String id;
 
   /**
    * 用户ID
    */
+  @ApiModelProperty("用户id")
   @TableField("user_id")
   private Long userId;
 
   /**
    * 核销码
    */
+  @ApiModelProperty("核销码")
   @TableField("verify_code")
   private String verifyCode;
 
   /**
    * 优惠券ID
    */
+  @ApiModelProperty("优惠券id")
   @TableField("coupon_id")
   private Long couponId;
 
   /**
    * 生效日
    */
+  @ApiModelProperty("生效日")
   @TableField("valid_start")
   private Date validStart;
 
   /**
    * 到期日
    */
+  @ApiModelProperty("到期日")
   @TableField("valid_end")
   private Date validEnd;
 
   /**
    * 适用范围说明
    */
+  @ApiModelProperty("适用范围说明")
   @TableField("use_area_desc")
   private String useAreaDesc;
 
   /**
    * 使用订单ID
    */
+  @ApiModelProperty("使用订单id")
   @TableField("order_id")
   private String orderId;
 
   /**
    * 核销时间
    */
+  @ApiModelProperty("核销时间")
   @TableField("verify_time")
   private Date verifyTime;
 
   /**
    * 状态;1未使用 2已使用 3已过期
    */
+  @ApiModelProperty("状态;1未使用 2已使用 3已过期")
   @TableField("status")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private UserCouponStatusEnum status;
@@ -87,12 +101,14 @@ public class UserCoupon implements Serializable {
   /**
    * 创建时间
    */
+  @ApiModelProperty("创建时间")
   @TableField("created_time")
   private Date createdTime;
 
   /**
    * 更新时间
    */
+  @ApiModelProperty("更新时间")
   @TableField("updated_time")
   @Version
   private Date updatedTime;

+ 14 - 0
mp-service/src/main/java/com/qs/mp/user/domain/vo/UserCouponVO.java

@@ -15,6 +15,9 @@ import com.qs.mp.common.enums.UserCouponStatusEnum;
 import com.qs.mp.user.domain.UserCoupon;
 import java.io.Serializable;
 import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 /**
@@ -23,58 +26,69 @@ import lombok.Data;
  * @create 2022-03-07 20:45:43
  */
 @Data
+@ApiModel("用户的优惠券出参类")
 public class UserCouponVO extends UserCoupon {
   /**
    * 标题
    */
+  @ApiModelProperty("标题")
   private String title;
 
   /**
    * 类型;1用户盲票购买优惠券、2用户门店消费优惠券、3经销商盲票采购优惠券
    */
+  @ApiModelProperty("类型;1用户盲票购买优惠券、2用户门店消费优惠券、3经销商盲票采购优惠券")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponTypeEnum type;
 
   /**
    * 图片
    */
+  @ApiModelProperty("图片")
   private String picUrl;
 
   /**
    * 使用说明
    */
+  @ApiModelProperty("使用说明")
   private String description;
 
   /**
    * 优惠类型;1代金券、2折扣券、3兑换券
    */
+  @ApiModelProperty("优惠类型;1代金券、2折扣券、3兑换券")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponDiscountTypeEnum discountType;
 
   /**
    * 优惠金额(比例)
    */
+  @ApiModelProperty("优惠金额(比例)")
   private Integer discount;
 
   /**
    * 最低消费金额
    */
+  @ApiModelProperty("最低消费金额")
   private Integer minOrderAmt;
 
   /**
    * 使用范围;0通用 1生成券时指定范围 2发放时动态指定范围
    */
+  @ApiModelProperty("使用范围;0通用 1生成券时指定范围 2发放时动态指定范围")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponUseAreaEnum useArea;
 
   /**
    * 叠加使用;0不允许 1允许
    */
+  @ApiModelProperty("叠加使用;0不允许 1允许")
   private Integer compositeUse;
 
   /**
    * 是否选中
    */
+  @ApiModelProperty("是否选中")
   private boolean checked = false;
 
 

+ 3 - 0
mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingDetailVO.java

@@ -44,6 +44,9 @@ public class UserMarketingDetailVO {
     @ApiModelProperty("活动描述")
     private String description;
 
+    @ApiModelProperty("code获取类型,1可立即获得,2必须助力")
+    private Integer codeType;
+
     @ApiModelProperty("抽奖码列表")
     private List<String> codeList;
 

+ 3 - 0
mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingListVO.java

@@ -26,6 +26,9 @@ public class UserMarketingListVO {
     @ApiModelProperty("活动主图")
     private String picUrl;
 
+    @ApiModelProperty("参与人数")
+    private Integer fakeNum;
+
     @ApiModelProperty("开始时间")
     private Date startTime;
 

+ 12 - 12
mp-service/src/main/java/com/qs/mp/user/service/impl/UserDeliverOrderServiceImpl.java

@@ -176,19 +176,19 @@ public class UserDeliverOrderServiceImpl extends ServiceImpl<UserDeliverOrderMap
     if (DeliverOrderResourceEnum.PAYMENT.equals(userDeliverOrder.getResource())) {
         // 恢复商品库存状态
         for (UserDeliverOrderItem orderItem : orderItemList) {
-            GoodsSku goodsSku = null;
             if (Objects.nonNull(orderItem.getSkuId()) && orderItem.getSkuId() != 0) {
-                goodsSku = goodsSkuService.getById(orderItem.getSkuId());
-            }
-            if (Objects.nonNull(goodsSku)) {
-                boolean updateSku = goodsSkuService.update(new LambdaUpdateWrapper<GoodsSku>()
-                        .set(GoodsSku::getQuantity, goodsSku.getQuantity() + orderItem.getGoodsNum())
-                        .set(GoodsSku::getSoldQty, goodsSku.getSoldQty() - orderItem.getGoodsNum())
-                        .eq(GoodsSku::getSkuId, goodsSku.getSkuId())
-                        .eq(GoodsSku::getQuantity, goodsSku.getGoodsId())
-                        .eq(GoodsSku::getProperties, orderItem.getProperties()));
-
-                Assert.isTrue(updateSku, "现金购买商品取消订单更新SKU库存失败。goodsId:" + goodsSku.getGoodsId() + ",skuId:" + goodsSku.getSkuId());
+                GoodsSku goodsSku = goodsSkuService.getById(orderItem.getSkuId());
+                if (Objects.nonNull(goodsSku)) {
+                    boolean updateSku = goodsSkuService.update(new LambdaUpdateWrapper<GoodsSku>()
+                            .set(GoodsSku::getQuantity, goodsSku.getQuantity() + orderItem.getGoodsNum())
+                            .set(GoodsSku::getSoldQty, goodsSku.getSoldQty() - orderItem.getGoodsNum())
+                            .eq(GoodsSku::getSkuId, goodsSku.getSkuId())
+                            .eq(GoodsSku::getGoodsId, goodsSku.getGoodsId())
+                            .eq(GoodsSku::getQuantity, goodsSku.getQuantity())
+                            .eq(GoodsSku::getSoldQty, goodsSku.getSoldQty()));
+
+                    Assert.isTrue(updateSku, "现金购买商品取消订单更新SKU库存失败。goodsId:" + goodsSku.getGoodsId() + ",skuId:" + goodsSku.getSkuId());
+                }
             } else {
                 Goods goods = goodsService.getById(orderItem.getGoodsId());
                 // 更新库存