Browse Source

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

活动开奖

See merge request quanshu/mp-server!528
zhong chunping 3 years ago
parent
commit
814c1b3093
31 changed files with 744 additions and 51 deletions
  1. 83 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/MarketingHitPrizeController.java
  2. 22 0
      mp-common/src/main/java/com/qs/mp/common/core/redis/RedisCache.java
  3. 5 1
      mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java
  4. 3 1
      mp-framework/src/main/java/com/qs/mp/framework/config/SecurityConfig.java
  5. 103 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/MarketingTask.java
  6. 6 0
      mp-service/src/main/java/com/qs/mp/admin/service/ICouponPkgService.java
  7. 7 0
      mp-service/src/main/java/com/qs/mp/admin/service/ICouponService.java
  8. 6 0
      mp-service/src/main/java/com/qs/mp/admin/service/IMarketingService.java
  9. 16 0
      mp-service/src/main/java/com/qs/mp/admin/service/impl/CouponPkgServiceImpl.java
  10. 34 16
      mp-service/src/main/java/com/qs/mp/admin/service/impl/CouponServiceImpl.java
  11. 241 12
      mp-service/src/main/java/com/qs/mp/admin/service/impl/MarketingServiceImpl.java
  12. 21 0
      mp-service/src/main/java/com/qs/mp/framework/domain/WxSubscribeMessage.java
  13. 12 0
      mp-service/src/main/java/com/qs/mp/framework/service/IWxSubscribeMessage.java
  14. 14 1
      mp-service/src/main/java/com/qs/mp/framework/service/impl/WxSubscribeMessageImpl.java
  15. 7 0
      mp-service/src/main/java/com/qs/mp/system/mapper/SysUserMapper.java
  16. 8 0
      mp-service/src/main/java/com/qs/mp/system/service/ISysUserService.java
  17. 5 0
      mp-service/src/main/java/com/qs/mp/system/service/impl/SysUserServiceImpl.java
  18. 2 2
      mp-service/src/main/java/com/qs/mp/user/domain/MarketingHitPrize.java
  19. 22 0
      mp-service/src/main/java/com/qs/mp/user/domain/param/UserMarketingHitPrizeQueryParam.java
  20. 27 0
      mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingHitPrizeDetailVO.java
  21. 34 0
      mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingHitPrizeListVO.java
  22. 12 0
      mp-service/src/main/java/com/qs/mp/user/mapper/MarketingHitPrizeMapper.java
  23. 10 0
      mp-service/src/main/java/com/qs/mp/user/service/IMarketingHitPrizeService.java
  24. 2 1
      mp-service/src/main/java/com/qs/mp/user/service/IUserCoinService.java
  25. 1 1
      mp-service/src/main/java/com/qs/mp/user/service/IUserPrizeStorageService.java
  26. 9 0
      mp-service/src/main/java/com/qs/mp/user/service/impl/MarketingHitPrizeServiceImpl.java
  27. 4 4
      mp-service/src/main/java/com/qs/mp/user/service/impl/UserCoinServiceImpl.java
  28. 3 8
      mp-service/src/main/java/com/qs/mp/user/service/impl/UserHitPrizeServiceImpl.java
  29. 4 4
      mp-service/src/main/java/com/qs/mp/user/service/impl/UserPrizeStorageServiceImpl.java
  30. 7 0
      mp-service/src/main/resources/mapper/system/SysUserMapper.xml
  31. 14 0
      mp-service/src/main/resources/mapper/user/MarketingHitPrizeMapper.xml

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

@@ -0,0 +1,83 @@
+package com.qs.mp.web.controller.api.user;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.framework.security.handle.HostHolder;
+import com.qs.mp.user.domain.MarketingHitPrize;
+import com.qs.mp.user.domain.param.UserMarketingHitPrizeQueryParam;
+import com.qs.mp.user.domain.vo.UserMarketingHitPrizeDetailVO;
+import com.qs.mp.user.domain.vo.UserMarketingHitPrizeListVO;
+import com.qs.mp.user.service.IMarketingHitPrizeService;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 营销活动中奖信息相关接口
+ * @author Cup
+ * @date 2022/5/19
+ */
+@RestController
+@RequestMapping("/api/v1/mp/user/marketing/hit/prize")
+@Api(tags = "营销活动中奖信息相关接口")
+public class MarketingHitPrizeController extends BaseApiController {
+
+    @Autowired
+    private IMarketingHitPrizeService marketingHitPrizeService;
+
+    @Autowired
+    private HostHolder hostHolder;
+
+    @PostMapping("/list")
+    @ApiOperation("获取中奖信息列表")
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = UserMarketingHitPrizeListVO.class)
+    )
+    public TableDataInfo list(@Validated @RequestBody UserMarketingHitPrizeQueryParam userMarketingHitPrizeQueryParam) {
+        startPage();
+        QueryWrapper<MarketingHitPrize> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("t1.marketing_id",userMarketingHitPrizeQueryParam.getMarketingId());
+        queryWrapper.orderByAsc("t2.sort");
+        List<UserMarketingHitPrizeListVO> marketingHitPrizeListVOList = marketingHitPrizeService.listHitPrizeByQueryWrapper(queryWrapper);
+        return getDataTable(marketingHitPrizeListVOList);
+    }
+
+    @PostMapping("/isHit/{marketingId}")
+    @ApiOperation("判断当前用户是否中奖")
+    public AjaxResult isHit(@PathVariable("marketingId") Long marketingId) {
+
+        Long userId = 0L;
+        if (hostHolder.getUser() != null) {
+            userId = hostHolder.getUser().getUserId();
+        }
+
+        UserMarketingHitPrizeDetailVO userMarketingHitPrizeDetailVO = new UserMarketingHitPrizeDetailVO();
+        userMarketingHitPrizeDetailVO.setIsHit(0);
+        if (Objects.nonNull(userId) && userId != 0) {
+            QueryWrapper<MarketingHitPrize> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("t1.marketing_id",marketingId);
+            queryWrapper.eq("t1.user_id", userId);
+            List<UserMarketingHitPrizeListVO> list = marketingHitPrizeService.listHitPrizeByQueryWrapper(queryWrapper);
+            if (CollectionUtils.isNotEmpty(list)) {
+                UserMarketingHitPrizeListVO userMarketingHitPrizeListVO = list.get(0);
+                userMarketingHitPrizeDetailVO.setPrizeTitle(userMarketingHitPrizeListVO.getPrizeTitle());
+                userMarketingHitPrizeDetailVO.setIsHit(1);
+                userMarketingHitPrizeDetailVO.setAwardName(userMarketingHitPrizeListVO.getAwardName());
+                userMarketingHitPrizeDetailVO.setPrizePicUrl(userMarketingHitPrizeListVO.getPrizePicUrl());
+            }
+        }
+        return AjaxResult.success(userMarketingHitPrizeDetailVO);
+    }
+
+}

+ 22 - 0
mp-common/src/main/java/com/qs/mp/common/core/redis/RedisCache.java

@@ -160,6 +160,28 @@ public class RedisCache
         return redisTemplate.opsForSet().members(key);
     }
 
+    /**
+     * 随机获取N个缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> List<T> popCacheSet(final String key, final long count)
+    {
+        return redisTemplate.opsForSet().pop(key,count);
+    }
+
+    /**
+     * 删除缓存的set中指定的值
+     *
+     * @param key 缓存键值
+     */
+    public void removeSetValueByKey(final String key, final List<Object> values)
+    {
+        redisTemplate.opsForSet().remove(key, values.toArray());
+    }
+
+
     /**
      * 缓存Map
      *

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

@@ -11,7 +11,8 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 public enum CoinLogTypeEnum implements IEnum<Integer> {
 
   PRIZE(1, "盲票奖品"),
-  EXCHANGE(2, "商品兑换");
+  EXCHANGE(2, "商品兑换"),
+  MARKETING(3,"营销活动");
 
 
   private final int value;
@@ -38,6 +39,9 @@ public enum CoinLogTypeEnum implements IEnum<Integer> {
     return value;
   }
 
+  public String getDesc() {
+    return desc;
+  }
 
   @Override
   public String toString() {

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

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

+ 103 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/MarketingTask.java

@@ -0,0 +1,103 @@
+package com.qs.mp.quartz.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.qs.mp.admin.domain.Marketing;
+import com.qs.mp.admin.service.IMarketingAwardsService;
+import com.qs.mp.admin.service.IMarketingService;
+import com.qs.mp.common.core.redis.DistributedLocker;
+import com.qs.mp.common.core.redis.RedisCache;
+import com.qs.mp.common.enums.MarketingStatusEnum;
+import com.qs.mp.common.enums.UserTypeEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.framework.domain.WxSubscribeMessage;
+import com.qs.mp.framework.service.IWxSubscribeMessage;
+import com.qs.mp.user.domain.MarketingUserCode;
+import com.qs.mp.user.service.IMarketingUserCodeService;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 营销活动相关任务
+ *
+ * @author Cup
+ * @date 2022/5/18
+ */
+@Component("marketingTask")
+public class MarketingTask {
+
+    public static final String MARKETING_LOTTERY_KEY = "MARKETING_LOTTERY_KEY:%s";
+
+
+    @Autowired
+    private DistributedLocker distributedLocker;
+
+    @Autowired
+    private IMarketingService marketingService;
+
+    @Autowired
+    private IWxSubscribeMessage wxSubscribeMessage;
+
+    @Autowired
+    private IMarketingUserCodeService marketingUserCodeService;
+
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+
+    /**
+     * 开奖任务方法
+     */
+    public void lottery() {
+        // 获取结束时间小于等于当前时间且未开奖的活动
+        Date now = DateUtils.getNowDate();
+        List<Marketing> marketingList = marketingService.list(new LambdaQueryWrapper<Marketing>()
+                .eq(Marketing::getTriggerStatus, 0)
+                .eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue())
+                .le(Marketing::getEndTime, now));
+        if (CollectionUtils.isEmpty(marketingList)) {
+            return;
+        }
+
+        for (Marketing marketing : marketingList) {
+            String lockKey = String.format(MARKETING_LOTTERY_KEY, marketing.getId());
+            // 加锁
+            if (!distributedLocker.tryLock(lockKey)) {
+                continue;
+            }
+            try {
+                // 开奖
+                marketingService.lottery(marketing);
+
+                // 获取所有的参与用户
+                List<MarketingUserCode> userCodeList = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
+                        .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                        .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue()));
+                for (MarketingUserCode marketingUserCode : userCodeList) {
+                    // 发送开奖订阅通知
+                    wxSubscribeMessage.sendMarketingLottery(marketingUserCode.getUserId(), marketing);
+                }
+            } catch (Exception e) {
+                LogUtil.error(logger, e, "活动开奖异常。marketingId:{0}", marketing.getId());
+            } finally {
+                // 释放锁
+                distributedLocker.unlock(lockKey);
+            }
+        }
+
+
+
+    }
+
+
+}

+ 6 - 0
mp-service/src/main/java/com/qs/mp/admin/service/ICouponPkgService.java

@@ -57,4 +57,10 @@ public interface ICouponPkgService extends IService<CouponPkg> {
      */
     void distribute(Ticket ticket, Long userId, String couponPkgId);
 
+    /**
+     * 营销活动券包发券
+     * @param userId
+     * @param couponPkgId
+     */
+    void distributeByMarketing(Long userId, String couponPkgId);
 }

+ 7 - 0
mp-service/src/main/java/com/qs/mp/admin/service/ICouponService.java

@@ -41,4 +41,11 @@ public interface ICouponService extends IService<Coupon> {
 	 * @param couponId
 	 */
 	void distribute(Ticket ticket, Long userId, String couponId);
+
+	/**
+	 * 营销活动优惠券发放
+	 * @param userId
+	 * @param couponId
+	 */
+    void distributeByMarketing(Long userId, String couponId);
 }

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

@@ -51,4 +51,10 @@ public interface IMarketingService extends IService<Marketing> {
      * @param userId
      */
     void help(MarketingHelpParam marketingHelpParam, Long userId);
+
+    /**
+     * 开奖
+     * @param marketing
+     */
+    void lottery(Marketing marketing);
 }

+ 16 - 0
mp-service/src/main/java/com/qs/mp/admin/service/impl/CouponPkgServiceImpl.java

@@ -66,6 +66,22 @@ public class CouponPkgServiceImpl extends ServiceImpl<CouponPkgMapper, CouponPkg
     @Autowired
     private ICouponService couponService;
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+
+    public void distributeByMarketing(Long userId, String couponPkgId) {
+        List<CouponPkgItem> couponPkgItems = couponPkgItemService.list(new LambdaQueryWrapper<CouponPkgItem>().eq(CouponPkgItem::getCouponPkgId, couponPkgId));
+
+        if (CollectionUtils.isEmpty(couponPkgItems)) {
+            throw new ServiceException("券包下优惠券不存在");
+        }
+        for (CouponPkgItem couponPkgItem : couponPkgItems) {
+            for (int i = 0; i < couponPkgItem.getCouponNum(); i++) {
+                couponService.distributeByMarketing(userId, couponPkgItem.getCouponId().toString());
+            }
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void distribute(Ticket ticket, Long userId, String couponPkgId) {

+ 34 - 16
mp-service/src/main/java/com/qs/mp/admin/service/impl/CouponServiceImpl.java

@@ -75,26 +75,27 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
 	@Autowired
 	private IChannelService channelService;
 
-  @Override
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void distributeByMarketing(Long userId, String couponId) {
+		Coupon coupon = getById(couponId);
+		UserCoupon userCoupon = getUserCoupon(userId, coupon);
+		userCoupon.setUseAreaDesc(coupon.getUseArea().getDesc());
+		userCouponService.save(userCoupon);
+		boolean rtn = update(new LambdaUpdateWrapper<Coupon>().set(Coupon::getDistributeQty, coupon.getDistributeQty() + 1)
+				.eq(Coupon::getCouponId, coupon.getCouponId()).eq(Coupon::getDistributeQty, coupon.getDistributeQty()));
+		Assert.isTrue(rtn, "发放优惠券奖品,更新优惠券发放量失败。couponId:" + coupon.getCouponId());
+	}
+
+
+	@Override
   @Transactional(rollbackFor = Exception.class)
   public void distribute(Ticket ticket, Long userId, String couponId) {
     Coupon coupon = getById(couponId);
-    UserCoupon userCoupon = new UserCoupon();
-    userCoupon.setId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-    userCoupon.setUserId(userId);
-    userCoupon.setVerifyCode(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-    userCoupon.setCouponId(coupon.getCouponId());
-    if (coupon.getDueDays() > 0) {
-      userCoupon.setValidStart(DateUtils.getToday());
-      userCoupon.setValidEnd(DateUtils.addDays(userCoupon.getValidStart(), coupon.getDueDays() - 1));
-    } else {
-      userCoupon.setValidStart(coupon.getValidStart());
-      userCoupon.setValidEnd(coupon.getValidEnd());
-    }
-    userCoupon.setStatus(UserCouponStatusEnum.UNUSED);
+	UserCoupon userCoupon = getUserCoupon(userId, coupon);
 
 
-    // 确定限定范围
+		// 确定限定范围
     if (coupon.getUseArea() == CouponUseAreaEnum.POST_SCOPE) {
       UserTicketOrderItem orderItem = userTicketOrderItemService.queryFinishedOrderItem(userId, ticket.getTicketId());
 			UserTicketOrder ticketOrder = userTicketOrderService.getById(orderItem.getOrderId());
@@ -119,7 +120,24 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
 		Assert.isTrue(rtn, "领取优惠券奖品,更新优惠券发放量失败。couponId:" + coupon.getCouponId());
   }
 
-  @Override
+	private UserCoupon getUserCoupon(Long userId, Coupon coupon) {
+		UserCoupon userCoupon = new UserCoupon();
+		userCoupon.setId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
+		userCoupon.setUserId(userId);
+		userCoupon.setVerifyCode(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
+		userCoupon.setCouponId(coupon.getCouponId());
+		if (coupon.getDueDays() > 0) {
+			userCoupon.setValidStart(DateUtils.getToday());
+			userCoupon.setValidEnd(DateUtils.addDays(userCoupon.getValidStart(), coupon.getDueDays() - 1));
+		} else {
+			userCoupon.setValidStart(coupon.getValidStart());
+			userCoupon.setValidEnd(coupon.getValidEnd());
+		}
+		userCoupon.setStatus(UserCouponStatusEnum.UNUSED);
+		return userCoupon;
+	}
+
+	@Override
 	@Transactional
 	public void saveCoupon(Coupon coupon, List<CouponTicket> ticketList) {
 		boolean res = couponService.save(coupon);

+ 241 - 12
mp-service/src/main/java/com/qs/mp/admin/service/impl/MarketingServiceImpl.java

@@ -1,6 +1,7 @@
 package com.qs.mp.admin.service.impl;
 
-import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
@@ -11,26 +12,30 @@ import com.qs.mp.admin.mapper.MarketingMapper;
 import com.qs.mp.admin.service.*;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qs.mp.common.core.domain.AjaxResult;
-import com.qs.mp.common.enums.MarketingStatusEnum;
-import com.qs.mp.common.enums.TicketPrizeTypeEnum;
-import com.qs.mp.common.enums.UserTypeEnum;
+import com.qs.mp.common.core.redis.RedisCache;
+import com.qs.mp.common.enums.*;
 import com.qs.mp.common.exception.ServiceException;
 import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.common.utils.bean.BeanUtils;
+import com.qs.mp.system.domain.SysUser;
+import com.qs.mp.system.service.ISysUserService;
+import com.qs.mp.system.service.id.BizIdGenerator;
+import com.qs.mp.user.domain.MarketingHitPrize;
 import com.qs.mp.user.domain.MarketingUserCode;
 import com.qs.mp.user.domain.param.MarketingHelpParam;
+import com.qs.mp.user.service.IMarketingHitPrizeService;
 import com.qs.mp.user.service.IMarketingUserCodeService;
+import com.qs.mp.user.service.IUserCoinService;
+import com.qs.mp.user.service.IUserPrizeStorageService;
 import com.qs.mp.utils.MarketingUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
 
 import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -44,6 +49,13 @@ import java.util.stream.Collectors;
 @Service
 public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing> implements IMarketingService {
 
+    // 内部奖池
+    public static final String MARKETING_LOTTERY_INSIDE_POOL = "MARKETING_LOTTERY_INSIDE_POOL:%s";
+
+    // 普通奖池
+    public static final String MARKETING_LOTTERY_ORDINARY_POOL = "MARKETING_LOTTERY_ORDINARY_POOL:%s";
+
+
     @Autowired
     private IGoodsService goodsService;
 
@@ -62,6 +74,222 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
     @Autowired
     private IMarketingUserCodeService marketingUserCodeService;
 
+    @Autowired
+    private ISysUserService sysUserService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private IMarketingHitPrizeService marketingHitPrizeService;
+
+    @Autowired
+    private IUserCoinService userCoinService;
+
+    @Autowired
+    private IUserPrizeStorageService userPrizeStorageService;
+
+    @Autowired
+    private BizIdGenerator bizIdGenerator;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void lottery(Marketing marketing) {
+
+        // 用户抽奖池
+        String userLotteryPool = String.format(MARKETING_LOTTERY_ORDINARY_POOL, marketing.getId());
+        // 内部抽奖池
+        String insideLotteryPool = String.format(MARKETING_LOTTERY_INSIDE_POOL, marketing.getId());
+
+        // 获取奖级信息
+        List<MarketingAwards> marketingAwardsList = marketingAwardsService.list(new LambdaQueryWrapper<MarketingAwards>()
+                .eq(MarketingAwards::getMarketingId, marketing.getId()));
+
+        // 奖品总数
+        int prizeQuantity = marketingAwardsList.stream().mapToInt(MarketingAwards::getQuantity).sum();
+
+        // 校准并获取真实参与人数
+        int realNum = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue())
+                .groupBy(MarketingUserCode::getMarketingId));
+
+        // 设置需要的内定人数
+        int insideNum = 0;
+
+        boolean isInside = false;
+
+        // 参与人数不足,全部采用内定人员开奖
+        if (prizeQuantity >= realNum) {
+            insideNum = prizeQuantity;
+            isInside = true;
+        } else {
+            insideNum = marketingAwardsList.stream().mapToInt(MarketingAwards::getInsideNum).sum();
+        }
+
+        // 获取一定数量的内定人员设置抽奖码加入抽奖关系表和抽奖池
+        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();
+            while (true) {
+                // 判断抽奖码是否已经存在
+                int codeCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
+                        .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                        .eq(MarketingUserCode::getCode, code));
+                if (codeCount > 0) {
+                    code = MarketingUtils.generatePrizeCode();
+                    continue;
+                }
+                break;
+            }
+            insideCodes.add(code);
+            MarketingUserCode marketingUserCode = new MarketingUserCode();
+            marketingUserCode.setMarketingId(marketing.getId());
+            marketingUserCode.setUserId(sysUser.getUserId());
+            marketingUserCode.setUserType(UserTypeEnum.INSIDE.getValue());
+            marketingUserCode.setCode(code);
+            marketingUserCode.setHelpUserId(0L);
+            // 设置中奖
+            marketingUserCode.setIsHit(1);
+            marketingUserCodeService.save(marketingUserCode);
+        }
+        // 将抽奖码放入内部抽奖池
+        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());
+        }
+        // 将抽奖码放入普通抽奖池
+        redisCache.setCacheSet(userLotteryPool, userCodes);
+
+        // 所有中奖名单
+        List<MarketingHitPrize> allHitPrizeList = new ArrayList<>();
+
+        // 普通用户中奖名单
+        List<MarketingHitPrize> userHitPrizeList = new ArrayList<>();
+
+        // 抽奖码中奖状态更新列表
+        List<MarketingUserCode> userCodeUpdateList = new ArrayList<>();
+
+        // 遍历奖级进行抽奖
+        for (MarketingAwards marketingAwards : marketingAwardsList) {
+            // 获取内部人数
+            if (isInside) {
+                insideNum = marketingAwards.getQuantity();
+            } else {
+                insideNum = marketingAwards.getInsideNum();
+            }
+
+            List<MarketingAwardsPrize> marketingAwardsPrizeList = marketingAwardsPrizeService.list(new LambdaQueryWrapper<MarketingAwardsPrize>()
+                    .eq(MarketingAwardsPrize::getMarketingId, marketing.getId())
+                    .eq(MarketingAwardsPrize::getAwardsId, marketingAwards.getId()));
+
+            if (insideNum != 0) {
+                // 设置内部用户抽奖信息
+                List<String> insideCodeList = redisCache.popCacheSet(insideLotteryPool, insideNum);
+                for (String code : insideCodeList) {
+                    MarketingUserCode marketingUserCode = marketingUserCodeService.getOne(new LambdaQueryWrapper<MarketingUserCode>()
+                            .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                            .eq(MarketingUserCode::getCode, code));
+
+                    // 设置中奖信息
+                    exchangeMarketingHitPrize(marketing, allHitPrizeList, marketingAwards, marketingAwardsPrizeList, marketingUserCode);
+                }
+            }
+
+            // 用户中奖数量为 名额 - 内定人数
+            int userNum = marketingAwards.getQuantity() - insideNum;
+            if (userNum > 0) {
+                // 设置普通用户抽奖信息
+                for (int i = 0; i < userNum; i++) {
+                    List<String> insideCodeList = redisCache.popCacheSet(userLotteryPool, 1);
+                    MarketingUserCode marketingUserCode = marketingUserCodeService.getOne(new LambdaQueryWrapper<MarketingUserCode>()
+                            .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                            .eq(MarketingUserCode::getCode, insideCodeList.get(0)));
+
+                    // 删除redis中该用户所有的抽奖码
+                    List<MarketingUserCode> list = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
+                            .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                            .eq(MarketingUserCode::getUserId, marketingUserCode.getUserId()));
+                    List<Object> delUserCodeList = list.stream().map(MarketingUserCode::getCode).collect(Collectors.toList());
+                    redisCache.removeSetValueByKey(userLotteryPool, delUserCodeList);
+                    MarketingHitPrize marketingHitPrize = exchangeMarketingHitPrize(marketing, allHitPrizeList, marketingAwards, marketingAwardsPrizeList, marketingUserCode);
+
+                    userHitPrizeList.add(marketingHitPrize);
+
+                    // 更新用户中奖状态
+                    marketingUserCode.setIsHit(1);
+                    userCodeUpdateList.add(marketingUserCode);
+                }
+            }
+        }
+        // 保存中奖信息
+        marketingHitPrizeService.saveBatch(allHitPrizeList);
+
+        // 更新抽奖码中奖状态
+        if (CollectionUtils.isNotEmpty(userCodeUpdateList)) {
+            marketingUserCodeService.updateBatchById(userCodeUpdateList);
+        }
+
+        // 发奖品
+        if (CollectionUtils.isNotEmpty(userHitPrizeList)) {
+            for (MarketingHitPrize marketingHitPrize : userHitPrizeList) {
+                MarketingAwardsPrize marketingAwardsPrize = marketingAwardsPrizeService.getById(marketingHitPrize.getPrizeId());
+
+                // 放入仓库
+                if (marketingAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COIN) {
+                    userCoinService.produce(marketingHitPrize.getUserId(), marketingAwardsPrize.getValue(), String.valueOf(marketingHitPrize.getId()), CoinLogTypeEnum.MARKETING);
+                } else if (marketingAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COUPON) {
+                    couponService.distributeByMarketing(marketingHitPrize.getUserId(), marketingAwardsPrize.getRefId());
+                } else if (marketingAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COUPON_PKG) {
+                    couponPkgService.distributeByMarketing(marketingHitPrize.getUserId(), marketingAwardsPrize.getRefId());
+                } else {
+                    // 实物奖品
+                    userPrizeStorageService.takeInStorage(marketingHitPrize.getUserId(), marketingAwardsPrize.getTitle(), marketingAwardsPrize.getPicUrl(), marketingAwardsPrize.getRefId(), PrizeStorageInTypeEnum.MARKETING, marketingHitPrize.getId());
+                }
+            }
+        }
+
+        // 更新活动状态
+        boolean rtn = this.update(new LambdaUpdateWrapper<Marketing>().set(Marketing::getTriggerStatus, 1)
+                .eq(Marketing::getId, marketing.getId())
+                .eq(Marketing::getTriggerStatus, 0));
+        Assert.isTrue(rtn, "更新活动开奖状态失败。marketingId:" + marketing.getId());
+
+        // 删除抽奖池
+        redisCache.deleteObject(userLotteryPool);
+        redisCache.deleteObject(insideLotteryPool);
+
+    }
+
+    private MarketingHitPrize exchangeMarketingHitPrize(Marketing marketing, List<MarketingHitPrize> allHitPrizeList, MarketingAwards marketingAwards, List<MarketingAwardsPrize> marketingAwardsPrizeList, MarketingUserCode marketingUserCode) {
+        // 设置中奖信息
+        MarketingHitPrize marketingHitPrize = new MarketingHitPrize();
+        marketingHitPrize.setId(bizIdGenerator.newId());
+        marketingHitPrize.setMarketingId(marketing.getId());
+        marketingHitPrize.setAwardsId(marketingAwards.getId());
+        marketingHitPrize.setMarketingUserCodeId(marketingUserCode.getId());
+        marketingHitPrize.setUserId(marketingUserCode.getUserId());
+        marketingHitPrize.setUserType(marketingUserCode.getUserType());
+
+        // 随机抽取奖品,[0, list.size)  左闭右开
+        int randomIndex = RandomUtil.randomInt(0, marketingAwardsPrizeList.size());
+        marketingHitPrize.setPrizeId(marketingAwardsPrizeList.get(randomIndex).getId());
+
+        allHitPrizeList.add(marketingHitPrize);
+        return marketingHitPrize;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void help(MarketingHelpParam marketingHelpParam, Long userId) {
@@ -106,7 +334,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
             code = MarketingUtils.generatePrizeCode();
             // 判断抽奖码是否已经存在
             int codeCount = marketingUserCodeService.count(new LambdaQueryWrapper<MarketingUserCode>()
-                    .eq(MarketingUserCode::getMarketingId,marketing.getId())
+                    .eq(MarketingUserCode::getMarketingId, marketing.getId())
                     .eq(MarketingUserCode::getCode, code));
             if (codeCount > 0) {
                 continue;
@@ -169,14 +397,14 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
                     MarketingStatusEnum.OFF.getValue().equals(marketingQueryParam.getStatus()) ||
                     MarketingStatusEnum.ON.getValue().equals(marketingQueryParam.getStatus())) {
                 queryWrapper.eq(Marketing::getIsOn, marketingQueryParam.getStatus());
-            }else if (MarketingStatusEnum.UNSTART.getValue().equals(marketingQueryParam.getStatus())){
+            } else if (MarketingStatusEnum.UNSTART.getValue().equals(marketingQueryParam.getStatus())) {
                 queryWrapper.gt(Marketing::getStartTime, new Date());
                 queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
-            }else if (MarketingStatusEnum.START.getValue().equals(marketingQueryParam.getStatus())){
+            } else if (MarketingStatusEnum.START.getValue().equals(marketingQueryParam.getStatus())) {
                 queryWrapper.le(Marketing::getStartTime, new Date());
                 queryWrapper.ge(Marketing::getEndTime, new Date());
                 queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
-            }else if (MarketingStatusEnum.END.getValue().equals(marketingQueryParam.getStatus())){
+            } else if (MarketingStatusEnum.END.getValue().equals(marketingQueryParam.getStatus())) {
                 queryWrapper.lt(Marketing::getEndTime, new Date());
                 queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
             }
@@ -254,6 +482,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
 
     /**
      * 创建奖级和奖品信息
+     *
      * @param awardsList
      * @param marketing
      */

+ 21 - 0
mp-service/src/main/java/com/qs/mp/framework/domain/WxSubscribeMessage.java

@@ -4,6 +4,7 @@
  */
 package com.qs.mp.framework.domain;
 
+import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.common.utils.DateUtils;
 import java.util.HashMap;
 
@@ -74,6 +75,26 @@ public class WxSubscribeMessage {
 //        page = page + actId ;
         miniprogram_state = state;
     }
+
+
+    /**
+     * 活动开奖消息
+     */
+    public void buildMarketingLotterySuccessMessage(Marketing marketing){
+        template_id = "3y_My-yRmqmGd3-f-vAwNaK4LQeehzXBSNDi_5wcnFI";
+//        page = "/pages/bills/detail?id=" + merchantBill.getBillId() + "&custId=" + merchantBill.getCustId();
+        /**
+         * 活动名称
+         * {{thing1.DATA}}
+         *
+         * 温馨提示
+         * {{thing5.DATA}}
+         */
+        data.put("thing1", new WeappDataValue(marketing.getTitle()));
+        data.put("thing5", new WeappDataValue("看看你中奖了吗?"));
+    }
+
+
 /*
     public void buildBillPaySuccessMessage(MerchantBill merchantBill){
         template_id = "1F2Hrqfr8fS--3CWeUOkDCjP83U6WTcfnBfqG7CYdKM";

+ 12 - 0
mp-service/src/main/java/com/qs/mp/framework/service/IWxSubscribeMessage.java

@@ -1,9 +1,21 @@
 package com.qs.mp.framework.service;
 
 
+import com.qs.mp.admin.domain.Marketing;
+
 /**
  * @author zhongcp
  * @Date 2021/9/22
  */
 public interface IWxSubscribeMessage {
+
+    /**
+     * 发送开奖消息
+     * @param userId
+     * @param marketing
+     * @return
+     */
+    public boolean sendMarketingLottery(Long userId, Marketing marketing);
+
+
 }

+ 14 - 1
mp-service/src/main/java/com/qs/mp/framework/service/impl/WxSubscribeMessageImpl.java

@@ -1,6 +1,7 @@
 package com.qs.mp.framework.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.http.HttpUtils;
 import com.qs.mp.framework.domain.WxSubscribeMessage;
@@ -40,10 +41,22 @@ public class WxSubscribeMessageImpl implements IWxSubscribeMessage {
   @Value("${miniprogram.state}")
   private String state;
 
+  @Override
+  public boolean sendMarketingLottery(Long userId, Marketing marketing) {
+    String openId = getOpenIdByUserId(userId);
+    WxSubscribeMessage wxSubscribeMessage = new WxSubscribeMessage(userAppId, openId, state);
+    wxSubscribeMessage.buildMarketingLotterySuccessMessage(marketing);
+    return this.sendNotify(userId, marketing.getId().toString(), wxSubscribeMessage);
+  }
+
+  private String getOpenIdByUserId(Long userId) {
+    return sysUserService.selectUserById(userId).getOpenId();
+  }
+
 
   private boolean sendNotify(Long userId, String bizId, WxSubscribeMessage message) {
     // 获取access_token
-    String accessToken = appTokenService.getAccessToken(channelAppId);
+    String accessToken = appTokenService.getAccessToken(userAppId);
     String res = HttpUtils.sendPost(
         "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken,
         JSON.toJSONString(message));

+ 7 - 0
mp-service/src/main/java/com/qs/mp/system/mapper/SysUserMapper.java

@@ -145,4 +145,11 @@ public interface SysUserMapper  extends BaseMapper<SysUser>
      */
     int updateUserGzhOpenId(@Param("unionId") String unionId, @Param("gzhOpenId") String gzhOpenId);
 
+    /**
+     * 获取一定数量用户
+     * @param userType
+     * @param insideNum
+     * @return
+     */
+    List<SysUser> selectUserListByRand(@Param("userType") String userType,@Param("num") int num);
 }

+ 8 - 0
mp-service/src/main/java/com/qs/mp/system/service/ISysUserService.java

@@ -221,4 +221,12 @@ public interface ISysUserService  extends IService<SysUser>
      * @return 结果
      */
     public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
+
+    /**
+     * 随机获取一定数量的用户
+     * @param userType
+     * @param insideNum
+     * @return
+     */
+    List<SysUser> selectUserListByRand(String userType, int num);
 }

+ 5 - 0
mp-service/src/main/java/com/qs/mp/system/service/impl/SysUserServiceImpl.java

@@ -572,4 +572,9 @@ public class SysUserServiceImpl  extends ServiceImpl<SysUserMapper, SysUser> imp
         }
         return successMsg.toString();
     }
+
+    @Override
+    public List<SysUser> selectUserListByRand(String userType, int num) {
+        return userMapper.selectUserListByRand(userType, num);
+    }
 }

+ 2 - 2
mp-service/src/main/java/com/qs/mp/user/domain/MarketingHitPrize.java

@@ -31,8 +31,8 @@ public class MarketingHitPrize implements Serializable {
      * 主键
      */
     @ApiModelProperty("中奖记录id")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
+    @TableId(value = "id", type = IdType.INPUT)
+    private String id;
 
     /**
      * 营销活动id

+ 22 - 0
mp-service/src/main/java/com/qs/mp/user/domain/param/UserMarketingHitPrizeQueryParam.java

@@ -0,0 +1,22 @@
+package com.qs.mp.user.domain.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 用户中奖信息列表查询入参类
+ * @author Cup
+ * @date 2022/5/19
+ */
+@ApiModel("用户中奖信息列表查询入参类")
+@Data
+public class UserMarketingHitPrizeQueryParam {
+
+    @NotNull(message = "活动id不能为空")
+    @ApiModelProperty("活动id")
+    private Long marketingId;
+
+}

+ 27 - 0
mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingHitPrizeDetailVO.java

@@ -0,0 +1,27 @@
+package com.qs.mp.user.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户活动中奖详情出参类
+ * @author Cup
+ * @date 2022/5/19
+ */
+@ApiModel("用户活动中奖详情出参类")
+@Data
+public class UserMarketingHitPrizeDetailVO {
+
+    @ApiModelProperty("是否中奖,0未中奖,1中奖")
+    private Integer isHit;
+
+    @ApiModelProperty("奖级")
+    private String awardName;
+
+    @ApiModelProperty("奖品")
+    private String prizeTitle;
+
+    @ApiModelProperty("奖品图片")
+    private String prizePicUrl;
+}

+ 34 - 0
mp-service/src/main/java/com/qs/mp/user/domain/vo/UserMarketingHitPrizeListVO.java

@@ -0,0 +1,34 @@
+package com.qs.mp.user.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户营销活动中奖列表出参类
+ * @author Cup
+ * @date 2022/5/19
+ */
+@ApiModel("用户营销活动中奖列表出参类")
+@Data
+public class UserMarketingHitPrizeListVO {
+
+    @ApiModelProperty("用户昵称")
+    private String nickName;
+
+    @ApiModelProperty("用户头像")
+    private String avatar;
+
+    @ApiModelProperty("中奖码")
+    private String code;
+
+    @ApiModelProperty("奖品图片")
+    private String prizePicUrl;
+
+    @ApiModelProperty("奖级")
+    private String awardName;
+
+    @ApiModelProperty("奖品")
+    private String prizeTitle;
+
+}

+ 12 - 0
mp-service/src/main/java/com/qs/mp/user/mapper/MarketingHitPrizeMapper.java

@@ -1,7 +1,13 @@
 package com.qs.mp.user.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
 import com.qs.mp.user.domain.MarketingHitPrize;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qs.mp.user.domain.vo.UserMarketingHitPrizeListVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * @auther quanshu
@@ -10,4 +16,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  */
 public interface MarketingHitPrizeMapper extends BaseMapper<MarketingHitPrize> {
 
+    /**
+     * 根据条件获取中奖信息列表
+     * @param queryWrapper
+     * @return
+     */
+    List<UserMarketingHitPrizeListVO> listHitPrizeByQueryWrapper(@Param(Constants.WRAPPER) QueryWrapper<MarketingHitPrize> queryWrapper);
 }

+ 10 - 0
mp-service/src/main/java/com/qs/mp/user/service/IMarketingHitPrizeService.java

@@ -1,7 +1,11 @@
 package com.qs.mp.user.service;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qs.mp.user.domain.MarketingHitPrize;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qs.mp.user.domain.vo.UserMarketingHitPrizeListVO;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +17,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IMarketingHitPrizeService extends IService<MarketingHitPrize> {
 
+    /**
+     * 根据条件获取中奖信息列表
+     * @param queryWrapper
+     * @return
+     */
+    List<UserMarketingHitPrizeListVO> listHitPrizeByQueryWrapper(QueryWrapper<MarketingHitPrize> queryWrapper);
 }

+ 2 - 1
mp-service/src/main/java/com/qs/mp/user/service/IUserCoinService.java

@@ -1,5 +1,6 @@
 package com.qs.mp.user.service;
 
+import com.qs.mp.common.enums.CoinLogTypeEnum;
 import com.qs.mp.user.domain.UserCoin;
 import com.baomidou.mybatisplus.extension.service.IService;
 
@@ -19,7 +20,7 @@ public interface IUserCoinService extends IService<UserCoin> {
    * @param logCoin
    * @param bizId
    */
-  void produce(Long userId, Integer logCoin, String bizId);
+  void produce(Long userId, Integer logCoin, String bizId, CoinLogTypeEnum coinLogTypeEnum);
 
   /**
    * 消耗代币

+ 1 - 1
mp-service/src/main/java/com/qs/mp/user/service/IUserPrizeStorageService.java

@@ -22,5 +22,5 @@ public interface IUserPrizeStorageService extends IService<UserPrizeStorage> {
    * @param inTypeEnum
    * @param refId
    */
-  void takeInStorage(Long userId, TicketAwardsPrize ticketAwardsPrize, PrizeStorageInTypeEnum inTypeEnum, String refId);
+  void takeInStorage(Long userId, String title, String picUrl, String goodsId, PrizeStorageInTypeEnum inTypeEnum, String refId);
 }

+ 9 - 0
mp-service/src/main/java/com/qs/mp/user/service/impl/MarketingHitPrizeServiceImpl.java

@@ -1,11 +1,15 @@
 package com.qs.mp.user.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qs.mp.user.domain.MarketingHitPrize;
+import com.qs.mp.user.domain.vo.UserMarketingHitPrizeListVO;
 import com.qs.mp.user.mapper.MarketingHitPrizeMapper;
 import com.qs.mp.user.service.IMarketingHitPrizeService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * <p>
  * 营销活动中奖信息表 服务实现类
@@ -17,4 +21,9 @@ import org.springframework.stereotype.Service;
 @Service
 public class MarketingHitPrizeServiceImpl extends ServiceImpl<MarketingHitPrizeMapper, MarketingHitPrize> implements IMarketingHitPrizeService {
 
+
+    @Override
+    public List<UserMarketingHitPrizeListVO> listHitPrizeByQueryWrapper(QueryWrapper<MarketingHitPrize> queryWrapper) {
+        return getBaseMapper().listHitPrizeByQueryWrapper(queryWrapper);
+    }
 }

+ 4 - 4
mp-service/src/main/java/com/qs/mp/user/service/impl/UserCoinServiceImpl.java

@@ -29,8 +29,8 @@ public class UserCoinServiceImpl extends ServiceImpl<UserCoinMapper, UserCoin> i
   private IUserCoinLogService userCoinLogService;
 
   @Override
-  @Transactional
-  public void produce(Long userId, Integer logCoin, String bizId) {
+  @Transactional(rollbackFor = Exception.class)
+  public void produce(Long userId, Integer logCoin, String bizId, CoinLogTypeEnum coinLogTypeEnum) {
     UserCoin userCoin = getById(userId);
     if (null == userCoin) {
       userCoin = new UserCoin();
@@ -46,11 +46,11 @@ public class UserCoinServiceImpl extends ServiceImpl<UserCoinMapper, UserCoin> i
 
     UserCoinLog userCoinLog = new UserCoinLog();
     userCoinLog.setUserId(userId);
-    userCoinLog.setType(CoinLogTypeEnum.PRIZE);
+    userCoinLog.setType(coinLogTypeEnum);
     userCoinLog.setMoney(userCoin.getCoin());
     userCoinLog.setLogMoney(logCoin);
     userCoinLog.setIncomeExpense(CoinLogTypeEnum.INCOME);
-    userCoinLog.setLogText("盲票奖品");
+    userCoinLog.setLogText(coinLogTypeEnum.getDesc());
     userCoinLog.setBizTime(new Date());
     userCoinLog.setRefId(bizId);
     userCoinLogService.save(userCoinLog);

+ 3 - 8
mp-service/src/main/java/com/qs/mp/user/service/impl/UserHitPrizeServiceImpl.java

@@ -9,12 +9,7 @@ import com.qs.mp.admin.domain.TicketAwards;
 import com.qs.mp.admin.domain.TicketAwardsPrize;
 import com.qs.mp.admin.domain.dto.TicketDrawNumDTO;
 import com.qs.mp.admin.service.*;
-import com.qs.mp.common.enums.CouponUseAreaEnum;
-import com.qs.mp.common.enums.PrizeStorageInTypeEnum;
-import com.qs.mp.common.enums.PrizeStorageStatusEnum;
-import com.qs.mp.common.enums.TicketPrizeTypeEnum;
-import com.qs.mp.common.enums.TicketStatusEnum;
-import com.qs.mp.common.enums.UserCouponStatusEnum;
+import com.qs.mp.common.enums.*;
 import com.qs.mp.common.exception.ServiceException;
 import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.common.utils.LogUtil;
@@ -147,13 +142,13 @@ public class UserHitPrizeServiceImpl extends ServiceImpl<UserHitPrizeMapper, Use
 
         // 放入仓库
         if (ticketAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COIN) {
-            userCoinService.produce(userId, ticketAwardsPrize.getValue(), userHitPrize.getId());
+            userCoinService.produce(userId, ticketAwardsPrize.getValue(), userHitPrize.getId(),CoinLogTypeEnum.PRIZE);
         } else if (ticketAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COUPON) {
             couponService.distribute(ticket, userId, ticketAwardsPrize.getRefId());
         } else if (ticketAwardsPrize.getPrizeType() == TicketPrizeTypeEnum.COUPON_PKG) {
             couponPkgService.distribute(ticket, userId, ticketAwardsPrize.getRefId());
         }else {
-            userPrizeStorageService.takeInStorage(userId, ticketAwardsPrize, PrizeStorageInTypeEnum.TICKET_CASHED, userHitPrize.getId());
+            userPrizeStorageService.takeInStorage(userId, ticketAwardsPrize.getTitle(),ticketAwardsPrize.getPicUrl(),ticketAwardsPrize.getRefId(), PrizeStorageInTypeEnum.TICKET_CASHED, userHitPrize.getId());
         }
 
         boolean rtn = ticketService.update(new LambdaUpdateWrapper<Ticket>().set(Ticket::getStatus, TicketStatusEnum.CASHED)

+ 4 - 4
mp-service/src/main/java/com/qs/mp/user/service/impl/UserPrizeStorageServiceImpl.java

@@ -27,15 +27,15 @@ public class UserPrizeStorageServiceImpl extends ServiceImpl<UserPrizeStorageMap
   private BizIdGenerator bizIdGenerator;
 
   @Override
-  public void takeInStorage(Long userId, TicketAwardsPrize ticketAwardsPrize, PrizeStorageInTypeEnum inTypeEnum, String refId) {
+  public void takeInStorage(Long userId, String title, String picUrl, String goodsId, PrizeStorageInTypeEnum inTypeEnum, String refId) {
       UserPrizeStorage userPrizeStorage = new UserPrizeStorage();
       userPrizeStorage.setStorageId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
       userPrizeStorage.setUserId(userId);
-      userPrizeStorage.setGoodsId(Long.valueOf(ticketAwardsPrize.getRefId()));
+      userPrizeStorage.setGoodsId(Long.valueOf(goodsId));
       userPrizeStorage.setSkuId(null);
       userPrizeStorage.setProperties(null);
-      userPrizeStorage.setTitle(ticketAwardsPrize.getTitle());
-      userPrizeStorage.setPicUrl(ticketAwardsPrize.getPicUrl());
+      userPrizeStorage.setTitle(title);
+      userPrizeStorage.setPicUrl(picUrl);
       userPrizeStorage.setGoodsNum(1);
       userPrizeStorage.setInType(inTypeEnum);
       userPrizeStorage.setRefId(refId);

+ 7 - 0
mp-service/src/main/resources/mapper/system/SysUserMapper.xml

@@ -236,4 +236,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
  	</delete>
 
+	<select id="selectUserListByRand" resultMap="SysUserResult">
+		SELECT user_id
+		FROM sys_user
+		WHERE user_type = #{userType}
+			order by rand()
+			LIMIT #{num};
+    </select>
 </mapper>

+ 14 - 0
mp-service/src/main/resources/mapper/user/MarketingHitPrizeMapper.xml

@@ -20,4 +20,18 @@
         id, marketing_id, user_id, user_type, awards_id, prize_id, created_time, updated_time, is_deleted
     </sql>
 
+    <select id="listHitPrizeByQueryWrapper" resultType="com.qs.mp.user.domain.vo.UserMarketingHitPrizeListVO">
+        select t4.nick_name,
+               t4.avatar,
+               t5.code,
+               t2.name awardName,
+               t3.title prizeTitle,
+               t3.pic_url prizePicUrl
+        from mp_marketing_hit_prize t1
+             left join mp_marketing_awards t2 on t1.awards_id = t2.id
+             left join mp_marketing_awards_prize t3 on t1.prize_id = t3.id
+             left join sys_user t4 on t1.user_id = t4.user_id
+             left join mp_marketing_user_code t5 on t1.marketing_user_code_id = t5.id
+        ${ew.customSqlSegment}
+    </select>
 </mapper>