framework/src/main/java/cn/lili/modules/lmk/domain/entity/AddNumCheek.java
New file @@ -0,0 +1,34 @@ package cn.lili.modules.lmk.domain.entity; import cn.lili.mybatis.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import lombok.Data; /** * 用户增加次数校验 * * @author peng * @since 2025-09-29 */ @Data @TableName("lmk_add_num_cheek") public class AddNumCheek extends BaseEntity { private static final long serialVersionUID = 1L; @TableField("user_id") /** 用户id */ private String userId; @TableField("type") /** 类型 */ private String type; @TableField("check_no") /** 校验编号 */ private String checkNo; } framework/src/main/java/cn/lili/modules/lmk/domain/form/AddNumCheekForm.java
New file @@ -0,0 +1,46 @@ package cn.lili.modules.lmk.domain.form; import cn.lili.group.Update; import cn.lili.group.Add; import cn.lili.base.AbsForm; import cn.lili.modules.lmk.domain.entity.AddNumCheek; import org.springframework.beans.BeanUtils; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import org.springframework.lang.NonNull; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; /** * 用户增加次数校验表单 * * @author peng * @since 2025-09-29 */ @Data @ApiModel(value = "AddNumCheek表单", description = "用户增加次数校验表单") public class AddNumCheekForm extends AbsForm { @NotNull(message = "用户id不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("用户id") private Long userId; @NotBlank(message = "类型不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("类型") private String type; @NotBlank(message = "校验编号不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("校验编号") private String checkNo; public static AddNumCheek getEntityByForm(@NonNull AddNumCheekForm form, AddNumCheek entity) { if(entity == null) { entity = new AddNumCheek(); } BeanUtils.copyProperties(form, entity); return entity; } } framework/src/main/java/cn/lili/modules/lmk/domain/form/AddPrizeNumForm.java
@@ -1,5 +1,6 @@ package cn.lili.modules.lmk.domain.form; import cn.lili.modules.lmk.enums.general.PrizeUserActionEnum; import lombok.Data; @Data @@ -14,6 +15,7 @@ private String addType; /** *抽奖活动id * @see PrizeUserActionEnum */ private String prizeActivityId; /** framework/src/main/java/cn/lili/modules/lmk/domain/query/AddNumCheekQuery.java
New file @@ -0,0 +1,22 @@ package cn.lili.modules.lmk.domain.query; import cn.lili.base.AbsQuery; import java.util.List; import org.springframework.lang.NonNull; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 用户增加次数校验查询 * * @author peng * @since 2025-09-29 */ @Data @ApiModel(value = "AddNumCheek查询参数", description = "用户增加次数校验查询参数") public class AddNumCheekQuery extends AbsQuery { } framework/src/main/java/cn/lili/modules/lmk/domain/vo/AddNumCheekVO.java
New file @@ -0,0 +1,43 @@ package cn.lili.modules.lmk.domain.vo; import cn.lili.base.AbsVo; import cn.lili.modules.lmk.domain.entity.AddNumCheek; import java.util.List; import org.springframework.lang.NonNull; import org.springframework.beans.BeanUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; /** * 用户增加次数校验展示 * * @author peng * @since 2025-09-29 */ @Data @ApiModel(value = "用户增加次数校验响应数据", description = "用户增加次数校验响应数据") public class AddNumCheekVO extends AbsVo { /** 用户id */ @ApiModelProperty("用户id") private Long userId; /** 类型 */ @ApiModelProperty("类型") private String type; /** 校验编号 */ @ApiModelProperty("校验编号") private String checkNo; public static AddNumCheekVO getVoByEntity(@NonNull AddNumCheek entity, AddNumCheekVO vo) { if(vo == null) { vo = new AddNumCheekVO(); } BeanUtils.copyProperties(entity, vo); return vo; } } framework/src/main/java/cn/lili/modules/lmk/enums/general/PrizeUserActionEnum.java
@@ -10,13 +10,17 @@ /** * 获取优惠卷的方式 */ SYSTEM("系统赠送",1), BUY("购买",1), SHARE("分享",1), SEE_SHOP("看商城",1), SEE_VIDEO("看视频",1); SYSTEM("系统赠送"), SHARE_GOODS_VIDEO("分享商品或视频内容(当日)"), SHARE_USER_REGISTRY("分享后带来的新用户的注册(当日)"), SHARE_USER_SHOPPING("分享后带来的用户的消费(当日)"), USER_STAY_TIME("用户在平台停留的时长(当日)"), USER_PUBLISH_EXAMINE("用户在平台上发布内容并经审核通过(当日)"), USER_BUY_SUM_PRICE("用户在平台上的购买金额(当日)"), USER_SCAN_STORE("用户商户码添加次数"), USER_BUY_ORDER_NUM("用户在平台上的订单数量(当日)"); private final String description; private final Integer sendNumber; public static PrizeUserActionEnum select(String name) { for (PrizeUserActionEnum prizeUserActionEnum : values()) { framework/src/main/java/cn/lili/modules/lmk/mapper/AddNumCheekMapper.java
New file @@ -0,0 +1,34 @@ package cn.lili.modules.lmk.mapper; import cn.lili.modules.lmk.domain.entity.AddNumCheek; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import cn.lili.modules.lmk.domain.vo.AddNumCheekVO; import cn.lili.modules.lmk.domain.form.AddNumCheekForm; import cn.lili.modules.lmk.domain.query.AddNumCheekQuery; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * 用户增加次数校验 Mapper 接口 * * @author peng * @since 2025-09-29 */ @Mapper public interface AddNumCheekMapper extends BaseMapper<AddNumCheek> { /** * id查找用户增加次数校验 * @param id * @return */ AddNumCheekVO getById(String id); /** * 分页 */ IPage getPage(IPage page, @Param("query") AddNumCheekQuery query); } framework/src/main/java/cn/lili/modules/lmk/service/AddNumCheekService.java
New file @@ -0,0 +1,65 @@ package cn.lili.modules.lmk.service; import cn.lili.modules.lmk.domain.entity.AddNumCheek; import com.baomidou.mybatisplus.extension.service.IService; import cn.lili.base.Result; import cn.lili.modules.lmk.domain.form.AddNumCheekForm; import cn.lili.modules.lmk.domain.query.AddNumCheekQuery; import java.util.List; /** * 用户增加次数校验 服务类 * * @author peng * @since 2025-09-29 */ public interface AddNumCheekService extends IService<AddNumCheek> { /** * 添加 * @param form * @return */ Result add(AddNumCheekForm form); /** * 修改 * @param form * @return */ Result update(AddNumCheekForm form); /** * 批量删除 * @param ids * @return */ Result remove(List<String> ids); /** * id删除 * @param id * @return */ Result removeById(String id); /** * 分页查询 * @param query * @return */ Result page(AddNumCheekQuery query); /** * 根据id查找 * @param id * @return */ Result detail(String id); /** * 列表 * @return */ Result all(); } framework/src/main/java/cn/lili/modules/lmk/service/impl/AddNumCheekServiceImpl.java
New file @@ -0,0 +1,119 @@ package cn.lili.modules.lmk.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.AddNumCheek; import cn.lili.modules.lmk.mapper.AddNumCheekMapper; import cn.lili.modules.lmk.service.AddNumCheekService; import cn.lili.base.Result; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.lili.modules.lmk.domain.form.AddNumCheekForm; import cn.lili.modules.lmk.domain.vo.AddNumCheekVO; import cn.lili.modules.lmk.domain.query.AddNumCheekQuery; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; import org.springframework.beans.BeanUtils; import org.springframework.util.Assert; import java.util.List; import java.util.stream.Collectors; /** * 用户增加次数校验 服务实现类 * * @author peng * @since 2025-09-29 */ @Service @RequiredArgsConstructor public class AddNumCheekServiceImpl extends ServiceImpl<AddNumCheekMapper, AddNumCheek> implements AddNumCheekService { private final AddNumCheekMapper addNumCheekMapper; /** * 添加 * @param form * @return */ @Override public Result add(AddNumCheekForm form) { AddNumCheek entity = AddNumCheekForm.getEntityByForm(form, null); baseMapper.insert(entity); return Result.ok("添加成功"); } /** * 修改 * @param form * @return */ @Override public Result update(AddNumCheekForm form) { AddNumCheek entity = baseMapper.selectById(form.getId()); // 为空抛IllegalArgumentException,做全局异常处理 Assert.notNull(entity, "记录不存在"); BeanUtils.copyProperties(form, entity); baseMapper.updateById(entity); return Result.ok("修改成功"); } /** * 批量删除 * @param ids * @return */ @Override public Result remove(List<String> ids) { baseMapper.deleteBatchIds(ids); return Result.ok("删除成功"); } /** * id删除 * @param id * @return */ @Override public Result removeById(String id) { baseMapper.deleteById(id); return Result.ok("删除成功"); } /** * 分页查询 * @param query * @return */ @Override public Result page(AddNumCheekQuery query) { IPage<AddNumCheekVO> page = PageUtil.getPage(query, AddNumCheekVO.class); baseMapper.getPage(page, query); return Result.ok().data(page.getRecords()).total(page.getTotal()); } /** * 根据id查找 * @param id * @return */ @Override public Result detail(String id) { AddNumCheekVO vo = baseMapper.getById(id); Assert.notNull(vo, "记录不存在"); return Result.ok().data(vo); } /** * 列表 * @return */ @Override public Result all() { List<AddNumCheek> entities = baseMapper.selectList(null); List<AddNumCheekVO> vos = entities.stream() .map(entity -> AddNumCheekVO.getVoByEntity(entity, null)) .collect(Collectors.toList()); return Result.ok().data(vos); } } framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java
@@ -16,6 +16,8 @@ import cn.lili.modules.lmk.domain.vo.PrizeResultVO; import cn.lili.modules.lmk.enums.general.*; import cn.lili.modules.lmk.service.*; import cn.lili.modules.order.order.entity.dos.Order; import cn.lili.modules.order.order.service.OrderService; import cn.lili.modules.promotion.entity.dos.Coupon; import cn.lili.modules.promotion.service.CouponService; import cn.lili.mybatis.BaseEntity; @@ -60,12 +62,18 @@ private final PrizeRecordService prizeRecordService; private static final String PRIZE_PREFIX = "prize_draw:"; private static final String PRIZE_NUMBER = "prize_number:"; private static final String PRIZE_ADD_NUM = "prize_add_num:"; private final RedisTemplate<String, String> redisTemplate; private final RedissonClient redissonClient; private final RocketmqCustomProperties rocketmqCustomProperties; private final RocketMQTemplate rocketMQTemplate; private final COSUtil cosUtil; private final CouponService couponService; private final AddPrizeRuleService addPrizeRuleService; private final ActionRecordService actionRecordService; private final ShareActionService shareActionService; private final AddNumCheekService addNumCheekService; private final OrderService orderService; @Override @Transactional(rollbackFor = Exception.class) @@ -390,13 +398,26 @@ try { lock.lock(); prizeNumberList = getPrizeNumberList(prizeId, userId); //默认生成 boolean needGenerate = true; for (PrizeNumber prizeNumber : prizeNumberList) { String userAction = prizeNumber.getUserAction(); if (PrizeUserActionEnum.SYSTEM.name().equals(userAction)) { needGenerate = false; break; } } // 当前用户没有初始化抽奖数据需要初始化当天抽奖数据 if (prizeNumberList == null || prizeNumberList.isEmpty()) { //没有默认抽奖次数直接返回0次 if (prizeNumberList.isEmpty() || needGenerate) { //没有默认抽奖次数不生成抽奖次数 int size = prizeNumberList.size(); if (prizeNum == null || prizeNum <= 0) { return Result.ok().data(0); return Result.ok().data(size); } prizeNumberList = new ArrayList<>(); if (size+prizeNum>activity.getMaxPrize()){ prizeNum = activity.getMaxPrize()-size; } //设置默认抽奖次数并返回默认抽奖次数 for (int i = 0; i < prizeNum; i++) { PrizeNumber prizeNumber = new PrizeNumber(); @@ -408,13 +429,9 @@ } //添加抽奖次数并返回 prizeNumberService.saveBatch(prizeNumberList); return Result.ok().data(prizeNumberList.size()); return Result.ok().data(prizeNumberList.size()+size); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } Integer maxPrize = activity.getMaxPrize(); //其他情况 int useNum = 0; @@ -431,6 +448,24 @@ return Result.ok().data(0); } else { return Result.ok().data(userPrizeNum > maxPrize ? maxPrize - useNum : notUseNum); } } finally { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } @Override public void afterCompletion(int status) { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }); } } @@ -490,6 +525,28 @@ @Override public Result addPrizeNum(AddPrizeNumForm addPrizeNumForm) { //指定活动给指定活动添加没指定活动给默认活动添加 String prizeActivityId = addPrizeNumForm.getPrizeActivityId(); if (StringUtils.isBlank(prizeActivityId)) { LambdaQueryWrapper<PrizeActivity> pop = Wrappers.<PrizeActivity>lambdaQuery() .eq(PrizeActivity::getEnableStatus, PrizeActivityStatusEnum.ON.name()) .eq(PrizeActivity::getPopup, true); PrizeActivity one = prizeActivityService.getOne(pop); if (one == null) { return Result.ok().data(0); } addPrizeNumForm.setPrizeActivityId(one.getId()); } AuthUser currentUser = UserContext.getCurrentUser(); if (currentUser == null) { return Result.ok().data(0); } //指定用户给指定用户添加没指定活动给当前登录用户添加 if (StringUtils.isBlank(addPrizeNumForm.getUserId())) { addPrizeNumForm.setUserId(currentUser.getId()); } PrizeActivity activity = prizeActivityService.getById(addPrizeNumForm.getPrizeActivityId()); if (activity == null) { throw new ServiceException("当前活动不存在"); @@ -512,25 +569,158 @@ if (actionEnum == null) { throw new ServiceException("当前类型不存在"); } //todo 进行数据校验 AddPrizeRule addPrizeRule = getAddPrizeRule(actionEnum.name()); if (addPrizeRule == null) { return Result.ok().data(0); } List<PrizeNumber> needAdd = new ArrayList<>(); Integer addNum = addPrizeRule.getAddNum(); if (addNum == null) { return Result.ok().data(0); } //判读添加后是否大于最大次数 if (prizeNumberList.size()+addNum >= maxPrize){ addNum = maxPrize-prizeNumberList.size(); } boolean addFlag = false; //判断该类型当天是否添加过了 for (PrizeNumber prizeNumber : prizeNumberList) { if (actionEnum.name().equals(prizeNumber.getUserAction())) { addFlag = true; break; } } String extend = addPrizeNumForm.getExtend(); JSONObject jsonObject = JSONObject.parseObject(extend); LambdaQueryWrapper<AddNumCheek> query = Wrappers.lambdaQuery(); AddNumCheek addNumCheek = null; String orderSn = null; Order order = null; String ruleValue= null; switch (actionEnum) { case BUY: System.err.println("BUY"); case SHARE_GOODS_VIDEO: String shareId = jsonObject.getString("shareId"); ShareAction shareAction = shareActionService.getById(shareId); if (shareAction == null) { return Result.ok().data(0); } if (addFlag){ log.info("当前用户当天已经添加过了分享添加次数了-------->{}",userId); return Result.ok().data(0); } break; case SHARE: //直接获得抽奖次数 System.err.println("SHARE"); case SHARE_USER_REGISTRY: String memberId = jsonObject.getString("memberId"); query.eq(AddNumCheek::getType,PrizeUserActionEnum.SHARE_USER_REGISTRY.name()) .eq(AddNumCheek::getCheckNo, memberId); if (addNumCheekService.getOne(query) != null) { log.info("当前用户已经被邀请过了----------------->{}",memberId); return Result.ok().data(0); } addNumCheek = new AddNumCheek(); addNumCheek.setType(PrizeUserActionEnum.SHARE_USER_REGISTRY.name()); addNumCheek.setUserId(userId); addNumCheek.setCheckNo(memberId); addNumCheekService.save(addNumCheek); break; case SEE_SHOP: System.err.println("SEE_SHOP"); case SHARE_USER_SHOPPING: orderSn = jsonObject.getString("orderSn"); //校验订单是否存在 order = orderService.getBySn(orderSn); if (order == null) { log.info("分享用户购物订单不存在{}",orderSn); return Result.ok().data(0); } query.eq(AddNumCheek::getType,PrizeUserActionEnum.SHARE_USER_SHOPPING.name()) .eq(AddNumCheek::getCheckNo, orderSn); if (addNumCheekService.getOne(query) != null) { log.info("当前邀请订单已经被领取过了----------------->{}",orderSn); return Result.ok().data(0); } addNumCheek = new AddNumCheek(); addNumCheek.setType(PrizeUserActionEnum.SHARE_USER_SHOPPING.name()); addNumCheek.setUserId(userId); addNumCheek.setCheckNo(orderSn); addNumCheekService.save(addNumCheek); break; case SEE_VIDEO: System.err.println("SEE_VIDEO"); case USER_STAY_TIME: //todo 通过用户行为分析获取数据进行判断 ruleValue = addPrizeRule.getRuleValue(); if (addFlag){ log.info("当前用户当天已经添加过了停留时间添加次数了-------->{}",userId); return Result.ok().data(0); } break; default: case USER_BUY_SUM_PRICE: orderSn = jsonObject.getString("orderSn"); //校验订单是否存在 order = orderService.getBySn(orderSn); if (order == null) { log.info("用户购物订单不存在{}",orderSn); return Result.ok().data(0); } ruleValue = addPrizeRule.getRuleValue(); double price = Double.parseDouble(ruleValue); Double flowPrice = order.getFlowPrice(); if (flowPrice < price) { log.info("当前购物订单金额小于添加要求----------------->{}",orderSn); return Result.ok().data(0); } query.eq(AddNumCheek::getType,PrizeUserActionEnum.USER_BUY_SUM_PRICE.name()) .eq(AddNumCheek::getCheckNo, orderSn); if (addNumCheekService.getOne(query) != null) { log.info("当前购物订单已经被领取过了----------------->{}",orderSn); return Result.ok().data(0); } addNumCheek = new AddNumCheek(); addNumCheek.setType(PrizeUserActionEnum.USER_BUY_SUM_PRICE.name()); addNumCheek.setUserId(userId); addNumCheek.setCheckNo(orderSn); addNumCheekService.save(addNumCheek); break; case USER_BUY_ORDER_NUM: orderSn = jsonObject.getString("orderSn"); //校验订单是否存在 order = orderService.getBySn(orderSn); if (order == null) { log.info("用户购物数量订单不存在{}",orderSn); return Result.ok().data(0); } query.eq(AddNumCheek::getType,PrizeUserActionEnum.USER_BUY_ORDER_NUM.name()) .eq(AddNumCheek::getCheckNo, orderSn); if (addNumCheekService.getOne(query) != null) { log.info("当前购物订单数量已经被领取过了----------------->{}",orderSn); return Result.ok().data(0); } addNumCheek = new AddNumCheek(); addNumCheek.setType(PrizeUserActionEnum.USER_BUY_ORDER_NUM.name()); addNumCheek.setUserId(userId); addNumCheek.setCheckNo(orderSn); addNumCheekService.save(addNumCheek); break; case USER_SCAN_STORE: break; case USER_PUBLISH_EXAMINE: break; default: return Result.ok().data(0); } return null; //设置默认抽奖次数并返回默认抽奖次数 for (int i = 0; i < addNum; i++) { PrizeNumber prizeNumber = new PrizeNumber(); prizeNumber.setActivityPrizeId(Long.parseLong(addPrizeNumForm.getPrizeActivityId())); prizeNumber.setUserId(Long.parseLong(userId)); prizeNumber.setUserAction(actionEnum.name()); prizeNumber.setUseStatus(PrizeNumberUseEnum.WAIT.name()); needAdd.add(prizeNumber); } prizeNumberService.saveBatch(needAdd); return Result.ok().data(0); } public AddPrizeRule getAddPrizeRule(String ruleCode) { LambdaQueryWrapper<AddPrizeRule> one = Wrappers.<AddPrizeRule>lambdaQuery().eq(AddPrizeRule::getRuleCode, ruleCode); return addPrizeRuleService.getOne(one); } } framework/src/main/resources/mapper/lmk/AddNumCheekMapper.xml
New file @@ -0,0 +1,44 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.lili.modules.lmk.mapper.AddNumCheekMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.AddNumCheekVO"> <id column="id" property="id"/> <result column="user_id" property="userId" /> <result column="type" property="type" /> <result column="check_no" property="checkNo" /> </resultMap> <select id="getById" resultMap="BaseResultMap"> SELECT LANC.user_id, LANC.type, LANC.check_no, LANC.id FROM lmk_add_num_cheek LANC WHERE LANC.id = #{id} AND LANC.delete_flag = 0 </select> <select id="getPage" resultMap="BaseResultMap"> SELECT LANC.user_id, LANC.type, LANC.check_no, LANC.id FROM lmk_add_num_cheek LANC WHERE LANC.delete_flag = 0 </select> </mapper>