|
|
@@ -0,0 +1,302 @@
|
|
|
+package com.citu.module.promotion.service.luck;
|
|
|
+
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
|
|
+import com.citu.framework.common.pojo.PageResult;
|
|
|
+import com.citu.framework.common.util.object.BeanUtils;
|
|
|
+import com.citu.module.menduner.system.api.area.MendunerAreaApi;
|
|
|
+import com.citu.module.product.api.spu.ProductSpuApi;
|
|
|
+import com.citu.module.product.api.spu.dto.ProductSpuRespDTO;
|
|
|
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeDetailRespVO;
|
|
|
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeImportExcelVO;
|
|
|
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizePageReqVO;
|
|
|
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeSaveReqVO;
|
|
|
+import com.citu.module.promotion.convert.luck.LuckPrizeConvert;
|
|
|
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
|
|
|
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
|
|
|
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtend;
|
|
|
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtendDO;
|
|
|
+import com.citu.module.promotion.dal.mysql.luck.LuckPrizeExtendMapper;
|
|
|
+import com.citu.module.promotion.dal.mysql.luck.LuckPrizeMapper;
|
|
|
+import com.citu.module.promotion.enums.luck.LuckPrizeTypeEnum;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+import org.springframework.validation.annotation.Validated;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
+import static com.citu.module.promotion.enums.ErrorCodeConstants.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 幸运抽奖-奖品 Service 实现类
|
|
|
+ *
|
|
|
+ * @author Rayson
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Validated
|
|
|
+public class LuckPrizeServiceImpl implements LuckPrizeService {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 奖品数量
|
|
|
+ */
|
|
|
+ private static final Integer num = 8;
|
|
|
+ @Resource
|
|
|
+ private LuckLotteryService luckLotteryService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private LuckPrizeMapper luckPrizeMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private LuckPrizeExtendMapper prizeExtendMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ProductSpuApi productSpuApi;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MendunerAreaApi mendunerAreaApi;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @DSTransactional
|
|
|
+ public Long createLuckPrize(LuckPrizeSaveReqVO createReqVO) {
|
|
|
+ // 插入
|
|
|
+// List<LuckPrizeDO> list = luckPrizeMapper.getListByLotteryId(createReqVO.getLotteryId());
|
|
|
+// if (list.size() >= num) {
|
|
|
+// throw exception(LUCK_LOTTERY_PRIZE_COUNT_EXCEED);
|
|
|
+// }
|
|
|
+ LuckPrizeDO luckPrize = BeanUtils.toBean(createReqVO, LuckPrizeDO.class);
|
|
|
+ luckPrizeMapper.insert(luckPrize);
|
|
|
+
|
|
|
+ if (LuckPrizeTypeEnum.CUSTOM.getType().equals(luckPrize.getType())) {
|
|
|
+ // 自定义奖品
|
|
|
+ LuckPrizeExtend extend = luckPrize.getExtend();
|
|
|
+ // 保存扩展信息
|
|
|
+ LuckPrizeExtendDO prizeExtend = BeanUtils.toBean(extend, LuckPrizeExtendDO.class);
|
|
|
+ prizeExtend.setLotteryId(luckPrize.getLotteryId());
|
|
|
+ prizeExtend.setLuckPrizeId(luckPrize.getId());
|
|
|
+ prizeExtendMapper.insert(prizeExtend);
|
|
|
+ }
|
|
|
+ // 返回
|
|
|
+ return luckPrize.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @DSTransactional
|
|
|
+ public void updateLuckPrize(LuckPrizeSaveReqVO updateReqVO) {
|
|
|
+ // 校验存在
|
|
|
+ LuckPrizeDO oldLuckPrize = validateLuckPrizeExists(updateReqVO.getId());
|
|
|
+ // 更新
|
|
|
+ LuckPrizeDO updateObj = BeanUtils.toBean(updateReqVO, LuckPrizeDO.class);
|
|
|
+ // 判断是否自定义
|
|
|
+ if (LuckPrizeTypeEnum.CUSTOM.getType().equals(updateObj.getType())) {
|
|
|
+ // 自定义奖品
|
|
|
+ if (null == updateObj.getExtend()) {
|
|
|
+ throw exception(LUCK_LOTTERY_PRIZE_EXTEND_NOT_COMPLETE);
|
|
|
+ }
|
|
|
+ // 查询扩展信息
|
|
|
+ LuckPrizeExtendDO prizeExtend = prizeExtendMapper.selectByLuckPrizeId(updateObj.getId());
|
|
|
+ // 解析对象
|
|
|
+ LuckPrizeExtend extend = updateObj.getExtend();
|
|
|
+ // 转换
|
|
|
+ LuckPrizeExtendDO newObj = BeanUtils.toBean(extend, LuckPrizeExtendDO.class);
|
|
|
+ newObj.setLotteryId(updateObj.getLotteryId());
|
|
|
+ newObj.setLuckPrizeId(updateObj.getId());
|
|
|
+ if (null == prizeExtend) {
|
|
|
+ // 新增扩展
|
|
|
+ prizeExtendMapper.insert(newObj);
|
|
|
+ } else {
|
|
|
+ // 修改扩展
|
|
|
+ newObj.setId(prizeExtend.getId());
|
|
|
+ prizeExtendMapper.updateById(newObj);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 判断之前是不是自定义奖品
|
|
|
+ if (LuckPrizeTypeEnum.CUSTOM.getType().equals(oldLuckPrize.getType())) {
|
|
|
+ // 删除
|
|
|
+ prizeExtendMapper.deleteByLuckPrizeId(oldLuckPrize.getId());
|
|
|
+ }
|
|
|
+ // 清空
|
|
|
+ updateObj.setExtend(null);
|
|
|
+ }
|
|
|
+ luckPrizeMapper.updateById(updateObj);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @DSTransactional
|
|
|
+ public void deleteLuckPrize(Long id) {
|
|
|
+ // 校验存在
|
|
|
+ validateLuckPrizeExists(id);
|
|
|
+ // 删除
|
|
|
+ luckPrizeMapper.deleteById(id);
|
|
|
+ prizeExtendMapper.deleteByLuckPrizeId(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ private LuckPrizeDO validateLuckPrizeExists(Long id) {
|
|
|
+ LuckPrizeDO luckPrize = getLuckPrize(id);
|
|
|
+ if (null == luckPrize) {
|
|
|
+ throw exception(LUCK_PRIZE_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ return luckPrize;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public LuckPrizeDO getLuckPrize(Long id) {
|
|
|
+ return luckPrizeMapper.selectById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public LuckPrizeDetailRespVO detail(Long id) {
|
|
|
+ LuckPrizeDetailRespVO respVO =
|
|
|
+ LuckPrizeConvert.INSTANCE.convert2(luckPrizeMapper.selectById(id));
|
|
|
+ if (LuckPrizeTypeEnum.PRODUCT.getType().equals(respVO.getType())
|
|
|
+ || null != respVO.getProductId()) {
|
|
|
+ // 站内商品
|
|
|
+ ProductSpuRespDTO spuResp =
|
|
|
+ productSpuApi.getSpu(respVO.getProductId()).getCheckedData();
|
|
|
+ respVO.setSpu(spuResp);
|
|
|
+ }
|
|
|
+ return respVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public PageResult<LuckPrizeDO> getLuckPrizePage(LuckPrizePageReqVO pageReqVO) {
|
|
|
+ return luckPrizeMapper.selectPage(pageReqVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<LuckPrizeDO> getListByLotteryId(Long lotteryId) {
|
|
|
+ List<LuckPrizeDO> list = luckPrizeMapper.getListByLotteryId(lotteryId);
|
|
|
+ if (null == list) {
|
|
|
+ throw exception(LUCK_LOTTERY_NOT_ADD_PRIZE);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @DSTransactional
|
|
|
+ public void importData(List<LuckPrizeImportExcelVO> list) {
|
|
|
+ list.forEach(vo -> {
|
|
|
+ LuckLotteryDO lottery = luckLotteryService.getByName(vo.getLotteryName());
|
|
|
+
|
|
|
+ LuckPrizeExtend extend = new LuckPrizeExtend();
|
|
|
+ extend.setBloc(vo.getBloc());
|
|
|
+ extend.setBrand(vo.getBrand());
|
|
|
+
|
|
|
+ if (StringUtils.hasText(vo.getProvinceName())) {
|
|
|
+ Long provinceId = mendunerAreaApi.getAreaByNameAndType(vo.getProvinceName(), MendunerAreaApi.PROVIDER)
|
|
|
+ .getCheckedData();
|
|
|
+ if (null == provinceId) {
|
|
|
+ throw exception(LUCK_PRIZE_EXTEND_PROVINCE_INCORRECT);
|
|
|
+ }
|
|
|
+ extend.setProvinceId(provinceId);
|
|
|
+ extend.setProvinceName(vo.getProvinceName());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.hasText(vo.getCityName())) {
|
|
|
+ Long cityId = mendunerAreaApi.getAreaByNameAndType(vo.getCityName(), MendunerAreaApi.CITY)
|
|
|
+ .getCheckedData();
|
|
|
+ if (null == cityId) {
|
|
|
+ throw exception(LUCK_PRIZE_EXTEND_CITY_INCORRECT);
|
|
|
+ }
|
|
|
+ extend.setCityId(cityId);
|
|
|
+ extend.setCityName(vo.getCityName());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.hasText(vo.getDistrictName())) {
|
|
|
+ Long districtId = mendunerAreaApi.getAreaByNameAndType(vo.getDistrictName(), MendunerAreaApi.DISTRICT)
|
|
|
+ .getCheckedData();
|
|
|
+ if (null == districtId) {
|
|
|
+ throw exception(LUCK_PRIZE_EXTEND_COUNTY_INCORRECT);
|
|
|
+ }
|
|
|
+ extend.setDistrictId(districtId);
|
|
|
+ extend.setDistrictName(vo.getDistrictName());
|
|
|
+ }
|
|
|
+
|
|
|
+ createLuckPrize(LuckPrizeSaveReqVO.builder()
|
|
|
+ .lotteryId(lottery.getId())
|
|
|
+ .name(vo.getName())
|
|
|
+ .type(vo.getType())
|
|
|
+ .image(vo.getImage())
|
|
|
+ .prompt(vo.getPrompt())
|
|
|
+ .total(vo.getTotal())
|
|
|
+ .chance(vo.getChance())
|
|
|
+ .extend(extend)
|
|
|
+ .sort(1)
|
|
|
+ .status(vo.getStatus())
|
|
|
+ .build());
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void updateById(LuckPrizeDO luckPrizeDO) {
|
|
|
+ luckPrizeMapper.updateById(luckPrizeDO);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据权重随机选择奖品
|
|
|
+ *
|
|
|
+ * @param randomNumber 随机数
|
|
|
+ * @param luckPrizeList 奖品列表
|
|
|
+ * @return 随机选择的奖品
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public LuckPrizeDO selectPrizeByWeight(int randomNumber, List<LuckPrizeDO> luckPrizeList) {
|
|
|
+ int cumulativeWeight = 0;
|
|
|
+
|
|
|
+ for (LuckPrizeDO prize : luckPrizeList) {
|
|
|
+ // 获取奖品的总数
|
|
|
+ Integer total = prize.getTotal();
|
|
|
+
|
|
|
+ // 检查total是否为空或无效(奖品是不是无限量?)
|
|
|
+ if (total == null || total <= 0) {
|
|
|
+ // 跳过总数无效的奖品
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算当前奖品的权重
|
|
|
+ int prizeWeight = prize.getChance() * total;
|
|
|
+
|
|
|
+ // 如果随机数落在当前奖品的权重范围内,则选择该奖品
|
|
|
+ if (randomNumber < cumulativeWeight + prizeWeight) {
|
|
|
+ return prize;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 累加权重
|
|
|
+ cumulativeWeight += prizeWeight;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有符合条件的奖品返回null,理论上不应该发生,除非所有奖品的总数都是无效的
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public PageResult<LuckPrizeDetailRespVO> page(LuckPrizePageReqVO pageReqVO) {
|
|
|
+ PageResult<LuckPrizeDetailRespVO> pageResult =
|
|
|
+ LuckPrizeConvert.INSTANCE.convertPage(luckPrizeMapper.selectPage(pageReqVO));
|
|
|
+ if (CollUtil.isEmpty(pageResult.getList())) {
|
|
|
+ return pageResult;
|
|
|
+ }
|
|
|
+ // 计算总权重 商品权重n*总数n
|
|
|
+ int totalWeight = pageResult.getList().stream().mapToInt(prize -> prize.getChance() * prize.getTotal()).sum();
|
|
|
+ for (LuckPrizeDetailRespVO resp : pageResult.getList()) {
|
|
|
+ // 计算概率赋值
|
|
|
+ if (resp.getChance() != null && resp.getTotal() != null && totalWeight > 0) {
|
|
|
+ double probability = (double) (resp.getChance() * resp.getTotal()) / totalWeight;
|
|
|
+ // 使用BigDecimal进行精确计算,设置小数位数和舍入模式
|
|
|
+ BigDecimal bd = new BigDecimal(probability * 100);
|
|
|
+ bd = bd.setScale(2, RoundingMode.HALF_UP);
|
|
|
+ resp.setProbability(bd.doubleValue());
|
|
|
+ } else {
|
|
|
+ resp.setProbability(0.00);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return pageResult;
|
|
|
+ }
|
|
|
+}
|