chunping 3 lat temu
rodzic
commit
e5c18ef7d1

+ 12 - 38
mp-admin/src/test/java/com/qs/mp/service/ServiceImplTest.java

@@ -3,6 +3,7 @@ package com.qs.mp.service;
 import com.qs.mp.MpApplication;
 import com.qs.mp.framework.service.IWxUrlLinkService;
 import java.util.Date;
+import java.util.Random;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,43 +36,16 @@ public class ServiceImplTest {
 
 
   public static void main(String[] args) {
-//    SignerVO signerVO = JSON.parseObject("{\"address\":\"西溪壹号\",\"corpName\":\"杭州全数时代科技有限公司\",\"corporate\":false,\"email\":\"\",\"idNo\":\"\",\"individual\":true,\"legalName\":\"戴小丹\",\"mobile\":\"18888888888\",\"name\":\"钟春平\",\"type\":\"INDIVIDUAL\"}", SignerVO.class);
-
-    /*String str = "abcd01234";
-
-    String[] part = str.split("(?<=\\D)(?=\\d)");
-
-    System.out.println(part[0]);
-
-    System.out.println(part[1]);
-
-    System.out.println("a1b2c3".replaceAll("[^(0-9)]", ""));*/
-
-    /*System.out.println((int)(new BigDecimal(80).divide(new BigDecimal(100)).setScale(0,
-        RoundingMode.HALF_UP).intValue()));
-    System.out.println((int)40/100);*/
-//    System.out.println((new GsonBuilder()).excludeFieldsWithoutExposeAnnotation().create().fromJson("{\"is_valid\":TRUE}", ValidSMSResult.class));
-    /*DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
-    Date start = DateUtils.parseStrToDate("2020-09-10", "yyyy-MM-dd");
-    Date end = DateUtils.parseStrToDate("2020-12-31", "yyyy-MM-dd");
-    Date calEndDay = DateUtils.addMonths(start, 1);
-    if (calEndDay.compareTo(end) == 0) {
-      System.out.println(true);
-    }*/
-
-    System.out.println(new Date().getMonth());
-//    int months = DateUtils.diffMonth(start, end);
-//    System.out.println(months);
-//    System.out.println(new Date(1648310400000L));
-//    System.out.println(DateUtils.addDays(DateUtils.getToday(), 2).getTime());
-//    System.out.println(DateUtils.diff(new Date(1635004800000L), DateUtils.getToday()));
-//    System.out.println(DateUtils.addDays(DateUtils.parseDate("2022-11-03"), -60));
-//    BigDecimal x = BigDecimal.valueOf(0.5);
-//    System.out.println(x.divide(BigDecimal.valueOf(100)));
-//    System.out.println(BigDecimal.valueOf(1).add(x.divide(BigDecimal.valueOf(100))).doubleValue());
-//
-//    System.out.println(BigDecimal.valueOf(1).add(x.divide(BigDecimal.valueOf(100))).pow(2));
-//    System.out.println(BigDecimal.valueOf(4000000).multiply(BigDecimal.valueOf(1).add(x.divide(BigDecimal.valueOf(100))).pow(2)));
-//    System.out.println(BigDecimal.valueOf(4000000).multiply(BigDecimal.valueOf(Math.pow( BigDecimal.valueOf(1).add(x.divide(BigDecimal.valueOf(100))).doubleValue(), Double.valueOf(String.valueOf(2))))).intValue());
+    int n = 500;
+    Random rand = new Random();
+    boolean[] bool = new boolean[n];
+    int randInt = 0;
+    for(int i = 0; i < 50 ; i++) {
+      do {
+        randInt = rand.nextInt(n);
+      }while(bool[randInt]);
+      bool[randInt] = true;
+      System.out.println(randInt);
+    }
   }
 }

+ 40 - 0
mp-common/src/main/java/com/qs/mp/common/enums/TicketPkgStatusEnum.java

@@ -0,0 +1,40 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.IEnum;
+
+/**
+ *
+ * 盲票包销售状态
+ *
+ */
+public enum TicketPkgStatusEnum implements IEnum<String> {
+
+  FOR_SALE("forSale", "待售"),
+  SOLD("sold", "已售");
+
+  private final String value;
+  private final String desc;
+
+  TicketPkgStatusEnum(final String value, final String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  @Override
+  public String getValue() {
+    return value;
+  }
+
+  /**
+   * 重写toString,单个转化成json
+   * @return
+   */
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value",value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 11 - 1
mp-service/src/main/java/com/qs/mp/admin/domain/TicketPackage.java

@@ -1,9 +1,12 @@
 package com.qs.mp.admin.domain;
 
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.qs.mp.common.enums.TicketPkgStatusEnum;
 import java.io.Serializable;
 import java.util.Date;
 import lombok.Data;
@@ -31,6 +34,12 @@ public class TicketPackage implements Serializable {
   @TableField("box_id")
   private String boxId;
 
+  /**
+   * 盲票包编号
+   */
+  @TableField("pkg_no")
+  private String pkgNo;
+
   /**
    * 开始序号
    */
@@ -47,7 +56,8 @@ public class TicketPackage implements Serializable {
    * 状态(待销售、已销售)
    */
   @TableField("status")
-  private String status;
+  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  private TicketPkgStatusEnum status;
 
   /**
    * 创建时间

+ 5 - 2
mp-service/src/main/java/com/qs/mp/admin/domain/dto/TicketDrawNumDTO.java

@@ -9,11 +9,14 @@ import lombok.Data;
  */
 @Data
 public class TicketDrawNumDTO {
-  // 奖项ID
-  private String id;
   // 奖项名
   private String name;
   // 号码
   private int num;
 
+  public TicketDrawNumDTO(String name, int num) {
+    this.name = name;
+    this.num = num;
+  }
+
 }

+ 222 - 5
mp-service/src/main/java/com/qs/mp/admin/service/impl/TicketBoxServiceImpl.java

@@ -1,11 +1,15 @@
 package com.qs.mp.admin.service.impl;
 
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qs.mp.admin.domain.Coupon;
 import com.qs.mp.admin.domain.Goods;
+import com.qs.mp.admin.domain.Ticket;
 import com.qs.mp.admin.domain.TicketAwards;
 import com.qs.mp.admin.domain.TicketAwardsPrize;
 import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.domain.TicketPackage;
+import com.qs.mp.admin.domain.dto.TicketDrawNumDTO;
 import com.qs.mp.admin.domain.param.TicketAwardsParam;
 import com.qs.mp.admin.domain.param.TicketAwardsPrizeParam;
 import com.qs.mp.admin.domain.param.TicketBoxCreateParam;
@@ -16,22 +20,31 @@ import com.qs.mp.admin.service.ITicketAwardsPrizeService;
 import com.qs.mp.admin.service.ITicketAwardsService;
 import com.qs.mp.admin.service.ITicketBoxSerialService;
 import com.qs.mp.admin.service.ITicketBoxService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qs.mp.admin.service.ITicketPackageService;
+import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.common.enums.TicketBoxStatusEnum;
+import com.qs.mp.common.enums.TicketPkgStatusEnum;
 import com.qs.mp.common.enums.TicketPrizeTypeEnum;
+import com.qs.mp.common.enums.TicketStatusEnum;
 import com.qs.mp.common.enums.TicketTypeEnum;
-import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.system.service.id.BizIdGenerator;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.DecimalFormat;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import lombok.Data;
 import ma.glasnost.orika.MapperFacade;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
 
 /**
  * <p>
@@ -42,7 +55,8 @@ import org.springframework.transaction.annotation.Transactional;
  * @since 2022-03-02
  */
 @Service
-public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox> implements ITicketBoxService {
+public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox> implements
+    ITicketBoxService {
 
   protected final Logger logger = LoggerFactory.getLogger(this.getClass());
 
@@ -67,6 +81,12 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
   @Autowired
   private ITicketBoxSerialService ticketBoxSerialService;
 
+  @Autowired
+  private ITicketService ticketService;
+
+  @Autowired
+  private ITicketPackageService ticketPackageService;
+
   @Override
   @Transactional
   public boolean createTicketBox(TicketBoxCreateParam param) {
@@ -87,7 +107,8 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
       TicketAwards ticketAwards = mapperFacade.map(awardsParam, TicketAwards.class);
       ticketAwards.setAwardsId(bizIdGenerator.newId());
       ticketAwards.setBoxId(ticketBox.getBoxId());
-      BigDecimal hitRate = new BigDecimal(awardsParam.getQuantity()).divide(new BigDecimal(ticketBox.getQuantity()), 4, RoundingMode.DOWN);
+      BigDecimal hitRate = new BigDecimal(awardsParam.getQuantity()).divide(
+          new BigDecimal(ticketBox.getQuantity()), 4, RoundingMode.DOWN);
       ticketAwards.setHitRate(hitRate);
       ticketAwardsList.add(ticketAwards);
 
@@ -118,8 +139,204 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
     ticketAwardsService.saveBatch(ticketAwardsList);
     ticketAwardsPrizeService.saveBatch(awardsPrizeList);
 
-    // TODO 分包,生成券
+    // 线下票要分包
+    if (ticketBox.getType() == TicketTypeEnum.OFFLINE) {
+      int pkgNum = ticketBox.getPkgQty();
+      int pkgUnit = ticketBox.getPkgUnit();
+      // 1.把各奖级的中奖数量分摊到每包上
+      Map<Integer, List<PkgAwards>> pkgAwardsMap = new HashMap<>();
+      for (int k = 0; k < ticketAwardsList.size(); k++) {
+        TicketAwards ticketAwards = ticketAwardsList.get(k);
+        if (ticketAwards.getQuantity() < pkgNum) {
+          // 奖级数量少于包数的,随机不重复分配,随机数从1开始
+          List<Integer> randomList = getRandomList(ticketAwards.getQuantity(), pkgNum);
+          for (Integer pkgId : randomList) {
+            if (null == pkgAwardsMap.get(pkgId)) {
+              pkgAwardsMap.put(pkgId, new ArrayList<PkgAwards>());
+            }
+            pkgAwardsMap.get(pkgId).add(
+                new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
+                    ticketAwards.getSort(), ticketAwards.getQuantity()));
+          }
+        } else {
+          // 奖级数量大于包数的,平均分配,四舍五入
+          int remainQty = ticketAwards.getQuantity();
+          for (int i = 1; i <= pkgNum; i++) {
+            int quantity;
+            if (null == pkgAwardsMap.get(i)) {
+              pkgAwardsMap.put(i, new ArrayList<PkgAwards>());
+            }
+            if (k == ticketAwardsList.size() - 1) {
+              // 最后一个奖项直接分配奖级数量差额即可
+              int hasQty = pkgAwardsMap.get(i).stream().mapToInt(PkgAwards::getQuantity).sum();
+              quantity = pkgUnit - hasQty;
+            } else {
+              if (i == pkgNum) {
+                quantity = remainQty;
+              } else {
+                quantity = new BigDecimal(remainQty).divide(new BigDecimal(pkgNum - i + 1), 0,
+                    RoundingMode.HALF_UP).intValue();
+              }
+            }
+            remainQty -= quantity;
+            Assert.isTrue(remainQty >= 0, "剩余奖级数量不足分配。boxId:" + ticketBox.getBoxId());
+            pkgAwardsMap.get(i).add(
+                new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
+                    ticketAwards.getSort(), quantity));
+          }
+        }
+      }
 
+      // 生成票包记录和盲票记录
+      int pkgCnt = 0;
+      int ticketCnt = 0;
+      List<TicketPackage> ticketPackageList = new ArrayList<>();
+      for (Integer key : pkgAwardsMap.keySet()) {
+        pkgCnt += 1;
+        TicketPackage ticketPackage = new TicketPackage();
+        ticketPackage.setPkgId(bizIdGenerator.newId());
+        ticketPackage.setBoxId(ticketBox.getBoxId());
+        ticketPackage.setPkgNo(ticketBox.getBoxNo() + "-" + String.format("%1$04d", pkgCnt));
+        ticketPackage.setStartSn(
+            ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt + 1));
+        ticketPackage.setEndSn(
+            ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt + 200));
+        ticketPackage.setStatus(TicketPkgStatusEnum.FOR_SALE);
+        ticketPackageList.add(ticketPackage);
+
+        List<PkgAwards> pkgAwardsList = pkgAwardsMap.get(key);
+        List<Ticket> ticketList = new ArrayList<>();
+        for (int j = 1; j <= pkgUnit; j++) {
+          ticketCnt += 1;
+          Iterator<PkgAwards> iterator = pkgAwardsList.iterator();
+          while (iterator.hasNext()) {
+            PkgAwards next = iterator.next();
+            if (next.getQuantity() == 0) {
+              iterator.remove();
+            }
+          }
+          int random = getPrizeIndex(pkgAwardsList);
+          PkgAwards pkgAwards = pkgAwardsList.get(random);
+          pkgAwards.setQuantity(pkgAwards.getQuantity() - 1);
+
+          Ticket ticket = new Ticket();
+          ticket.setTicketId(bizIdGenerator.newId());
+          ticket.setBoxId(ticketBox.getBoxId());
+          ticket.setPkgId(ticketPackage.getPkgId());
+          ticket.setTitle(ticketBox.getTitle());
+          ticket.setSerialNo(ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt));
+          ticket.setFacePrice(ticketBox.getFacePrice());
+          int luckyNum = new Random().nextInt(18);
+          ticket.setCipherLuckyNum(String.valueOf(luckyNum));
+          List<TicketDrawNumDTO> drawNumDTOList = new ArrayList<>();
+          for (int i = 1; i <= 18; i++) {
+            if (i == luckyNum) {
+              continue;
+            }
+            TicketDrawNumDTO drawNumDTO = new TicketDrawNumDTO(pkgAwards.getName(), i);
+            drawNumDTOList.add(drawNumDTO);
+          }
+          ticket.setDrawNum(JSONObject.toJSONString(drawNumDTOList));
+          ticket.setIsPhysical(1);
+          ticket.setStatus(TicketStatusEnum.NOT_PAY);
+          ticketList.add(ticket);
+        }
+        ticketService.saveBatch(ticketList);
+      }
+      ticketPackageService.saveBatch(ticketPackageList);
+    } else {
+      // TODO 线上票,不用分包
+
+    }
     return true;
   }
+
+  /**
+   * 根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率
+   *
+   * @param prizes
+   * @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
+   */
+  public int getPrizeIndex(List<PkgAwards> prizes) {
+    DecimalFormat df = new DecimalFormat("######0.00");
+    int random = -1;
+
+    //计算总权重
+    double sumWeight = 0;
+    for (PkgAwards p : prizes) {
+      sumWeight += p.getQuantity();
+    }
+
+    //产生随机数
+    double randomNumber;
+    randomNumber = Math.random();
+
+    //根据随机数在所有奖品分布的区域并确定所抽奖品
+    double d1 = 0;
+    double d2 = 0;
+    for (int i = 0; i < prizes.size(); i++) {
+      d2 += Double.parseDouble(String.valueOf(prizes.get(i).getQuantity())) / sumWeight;
+      if (i == 0) {
+        d1 = 0;
+      } else {
+        d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getQuantity())) / sumWeight;
+      }
+      if (randomNumber > d1 && randomNumber <= d2) {
+        random = i;
+        break;
+      }
+    }
+
+    return random;
+  }
+
+  /**
+   * 从total中随机取n个不重复的数
+   *
+   * @param n
+   * @param total
+   * @return
+   */
+  private List<Integer> getRandomList(int n, int total) {
+    List<Integer> randomList = new ArrayList<>();
+    Random rand = new Random();
+    boolean[] bool = new boolean[total];
+    int randInt = 0;
+    for (int i = 0; i < n; i++) {
+      do {
+        randInt = rand.nextInt(total);
+      } while (bool[randInt]);
+      bool[randInt] = true;
+      randomList.add(randInt);
+    }
+    return randomList;
+  }
+
+  @Data
+  private class PkgAwards {
+
+    private String awardsId;
+
+    /**
+     * 奖项名
+     */
+    private String name;
+
+    /**
+     * 奖项顺序
+     */
+    private String sort;
+
+    /**
+     * 奖项数量
+     */
+    private Integer quantity;
+
+    PkgAwards(String awardsId, String name, String sort, Integer quantity) {
+      this.awardsId = awardsId;
+      this.name = name;
+      this.sort = sort;
+      this.quantity = quantity;
+    }
+  }
 }

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

@@ -5,10 +5,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.qs.mp.admin.domain.Coupon;
 import com.qs.mp.admin.domain.Ticket;
+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.ICouponService;
 import com.qs.mp.admin.service.ITicketAwardsPrizeService;
+import com.qs.mp.admin.service.ITicketAwardsService;
 import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.common.enums.CouponUseAreaEnum;
 import com.qs.mp.common.enums.PrizeStorageInTypeEnum;
@@ -71,6 +73,9 @@ public class UserHitPrizeServiceImpl extends ServiceImpl<UserHitPrizeMapper, Use
   @Autowired
   private ICouponService couponService;
 
+  @Autowired
+  private ITicketAwardsService ticketAwardsService;
+
   @Override
   public List<TicketAwardsPrize> listPrize(Ticket ticket, Long userId) {
     UserHitPrize userHitPrize = getOne(new LambdaQueryWrapper<UserHitPrize>().eq(UserHitPrize::getTicketId, ticket.getTicketId()));
@@ -90,7 +95,9 @@ public class UserHitPrizeServiceImpl extends ServiceImpl<UserHitPrizeMapper, Use
           userHitPrize.setOrderId(orderItem.getOrderId());
           userHitPrize.setOrderItemId(orderItem.getItemId());
           userHitPrize.setTicketId(ticket.getTicketId());
-          userHitPrize.setAwardsId(ticketDrawNumDTO.getId());
+          TicketAwards ticketAwards = ticketAwardsService.getOne(new LambdaQueryWrapper<TicketAwards>()
+              .eq(TicketAwards::getBoxId, ticket.getBoxId()).eq(TicketAwards::getName, ticketDrawNumDTO.getName()));
+          userHitPrize.setAwardsId(ticketAwards.getAwardsId());
           // 奖品ID等用户选择后填入
 //          userHitPrize.setPrizeId();
           save(userHitPrize);

+ 3 - 2
mp-service/src/main/resources/mapper/admin/TicketPackageMapper.xml

@@ -6,6 +6,7 @@
     <resultMap id="BaseResultMap" type="com.qs.mp.admin.domain.TicketPackage">
         <id column="pkg_id" property="pkgId" />
         <result column="box_id" property="boxId" />
+        <result column="pkg_no" property="pkgNo" />
         <result column="start_sn" property="startSn" />
         <result column="end_sn" property="endSn" />
         <result column="status" property="status" />
@@ -15,7 +16,7 @@
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        pkg_id, box_id, start_sn, end_sn, status, created_time, updated_time
+        pkg_id, box_id, pkg_no, start_sn, end_sn, status, created_time, updated_time
     </sql>
 
-</mapper>
+</mapper>