|
@@ -1,6 +1,8 @@
|
|
|
package com.qs.mp.admin.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.qs.mp.admin.domain.Coupon;
|
|
|
import com.qs.mp.admin.domain.Goods;
|
|
@@ -22,11 +24,13 @@ import com.qs.mp.admin.service.ITicketBoxSerialService;
|
|
|
import com.qs.mp.admin.service.ITicketBoxService;
|
|
|
import com.qs.mp.admin.service.ITicketPackageService;
|
|
|
import com.qs.mp.admin.service.ITicketService;
|
|
|
+import com.qs.mp.common.enums.MqTopicType;
|
|
|
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.pulsar.PulsarClientService;
|
|
|
import com.qs.mp.common.utils.LogUtil;
|
|
|
import com.qs.mp.system.service.id.BizIdGenerator;
|
|
|
import java.math.BigDecimal;
|
|
@@ -40,6 +44,7 @@ import java.util.Map;
|
|
|
import java.util.Random;
|
|
|
import lombok.Data;
|
|
|
import ma.glasnost.orika.MapperFacade;
|
|
|
+import org.apache.pulsar.client.api.PulsarClientException;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
@@ -88,6 +93,9 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
@Autowired
|
|
|
private ITicketPackageService ticketPackageService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private PulsarClientService pulsarClientService;
|
|
|
+
|
|
|
@Override
|
|
|
@Transactional
|
|
|
public boolean createTicketBox(TicketBoxCreateParam param) {
|
|
@@ -96,7 +104,7 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
if (ticketBox.getType() == TicketTypeEnum.OFFLINE) {
|
|
|
ticketBox.setPkgQty(ticketBox.getQuantity() / ticketBox.getPkgUnit());
|
|
|
}
|
|
|
- ticketBox.setStatus(TicketBoxStatusEnum.PUT_OFF);
|
|
|
+ ticketBox.setStatus(TicketBoxStatusEnum.WAIT);
|
|
|
ticketBox.setBoxNo(ticketBoxSerialService.generateSerial(ticketBox.getType()));
|
|
|
ticketBox.setBoxId(bizIdGenerator.newId());
|
|
|
save(ticketBox);
|
|
@@ -140,118 +148,155 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
ticketAwardsService.saveBatch(ticketAwardsList);
|
|
|
ticketAwardsPrizeService.saveBatch(awardsPrizeList);
|
|
|
|
|
|
- // 线下票要分包
|
|
|
- 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()));
|
|
|
+ try {
|
|
|
+ pulsarClientService.producer(MqTopicType.ticket_generate, ticketBox.getBoxId());
|
|
|
+ } catch (PulsarClientException e) {
|
|
|
+ LogUtil.error(logger, e, "盲票组保存成功,发送异步消息失败. {0}", JSONObject.toJSONString(ticketBox));
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void generateTicket(String boxId) {
|
|
|
+ TicketBox ticketBox = getById(boxId);
|
|
|
+ Assert.isTrue(ticketBox.getStatus() == TicketBoxStatusEnum.DOING,
|
|
|
+ "盲票生成时,票组状态不是出票中,boxId=" + boxId);
|
|
|
+ List<TicketAwards> ticketAwardsList = ticketAwardsService.list(
|
|
|
+ new LambdaQueryWrapper<TicketAwards>()
|
|
|
+ .eq(TicketAwards::getBoxId, ticketBox.getBoxId()));
|
|
|
+ // 分包
|
|
|
+ int pkgNum = ticketBox.getPkgQty();
|
|
|
+ int pkgUnit = ticketBox.getPkgUnit();
|
|
|
+
|
|
|
+ Map<Integer, List<PkgAwards>> pkgAwardsMap = generatePkgAwards(
|
|
|
+ ticketBox, ticketAwardsList, pkgNum, pkgUnit);
|
|
|
+
|
|
|
+ // 生成票包记录和盲票记录
|
|
|
+ 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);
|
|
|
+ LogUtil.debug(logger, "第{0}包盲票奖项数量为{1}", pkgCnt, pkgAwardsList);
|
|
|
+ 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();
|
|
|
}
|
|
|
- } 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));
|
|
|
+ }
|
|
|
+ LogUtil.debug(logger, "开始生成第{0}包、第{1}盲票", pkgCnt, j);
|
|
|
+ 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) + 1;
|
|
|
+ ticket.setCipherLuckyNum(String.valueOf(luckyNum));
|
|
|
+ List<TicketDrawNumDTO> drawNumDTOList = new ArrayList<>();
|
|
|
+ List<Integer> randomNumList = getRandomList(new ArrayList<Integer>(), 18, 18);
|
|
|
+ for (Integer drawNum : randomNumList) {
|
|
|
+ if (drawNum == luckyNum) {
|
|
|
+ drawNumDTOList.add(new TicketDrawNumDTO(pkgAwards.getName(), drawNum));
|
|
|
+ continue;
|
|
|
}
|
|
|
+ int awardsNum = new Random().nextInt(ticketAwardsList.size());
|
|
|
+ drawNumDTOList.add(
|
|
|
+ new TicketDrawNumDTO(ticketAwardsList.get(awardsNum).getName(), drawNum));
|
|
|
}
|
|
|
+ ticket.setDrawNum(JSONObject.toJSONString(drawNumDTOList));
|
|
|
+ ticket.setIsPhysical(1);
|
|
|
+ ticket.setStatus(TicketStatusEnum.NOT_PAY);
|
|
|
+ ticketList.add(ticket);
|
|
|
}
|
|
|
+ ticketService.saveBatch(ticketList);
|
|
|
+ }
|
|
|
+ ticketPackageService.saveBatch(ticketPackageList);
|
|
|
|
|
|
- // 生成票包记录和盲票记录
|
|
|
- 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);
|
|
|
- LogUtil.debug(logger, "第{0}包盲票奖项数量为{1}", new Object[]{pkgCnt, pkgAwardsList});
|
|
|
- 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();
|
|
|
- }
|
|
|
+ boolean rst = update(new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getStatus, TicketBoxStatusEnum.DONE)
|
|
|
+ .eq(TicketBox::getBoxId, boxId).eq(TicketBox::getStatus, TicketBoxStatusEnum.DOING));
|
|
|
+ Assert.isTrue(rst, "盲票生成完,更新盲票组状态失败。boxId:{0}" + ticketBox.getBoxId());
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<Integer, List<PkgAwards>> generatePkgAwards(TicketBox ticketBox,
|
|
|
+ List<TicketAwards> ticketAwardsList, int pkgNum, int pkgUnit) {
|
|
|
+ // 1.把各奖级的中奖数量分摊到每包上
|
|
|
+ Map<Integer, List<PkgAwards>> pkgAwardsMap = new HashMap<>();
|
|
|
+ for (int m = 1; m <= pkgNum; m++) {
|
|
|
+ pkgAwardsMap.put(m, new ArrayList<PkgAwards>());
|
|
|
+ }
|
|
|
+ List<Integer> excludePkgList = new ArrayList<>();
|
|
|
+ for (int k = 0; k < ticketAwardsList.size(); k++) {
|
|
|
+ TicketAwards ticketAwards = ticketAwardsList.get(k);
|
|
|
+ if (ticketAwards.getQuantity() < pkgNum) {
|
|
|
+ // 奖级数量少于包数的,随机不重复分配,随机数从1开始
|
|
|
+ int totalNone = pkgNum - ticketAwards.getQuantity(); // 轮空数
|
|
|
+ int moreExInt = excludePkgList.size() - totalNone; // 本轮要排除的数 - 轮空数
|
|
|
+ if (moreExInt > 0) {
|
|
|
+ // 多出来的数,从末尾开始删除
|
|
|
+ for (int l = 0; l < moreExInt; l++) {
|
|
|
+ excludePkgList.remove(excludePkgList.size() - 1);
|
|
|
}
|
|
|
- LogUtil.debug(logger, "开始生成第{0}包、第{1}盲票", new Object[]{pkgCnt, j});
|
|
|
- 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;
|
|
|
+ }
|
|
|
+ List<Integer> randomList = getRandomList(excludePkgList, ticketAwards.getQuantity(),
|
|
|
+ pkgNum);
|
|
|
+ excludePkgList.addAll(randomList);
|
|
|
+ LogUtil.debug(logger, "随机分配到的包序号为:{0}", JSONObject.toJSONString(randomList));
|
|
|
+ for (Integer pkgId : randomList) {
|
|
|
+ pkgAwardsMap.get(pkgId).add(
|
|
|
+ new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
|
|
|
+ ticketAwards.getSort(), 1));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 奖级数量大于包数的,平均分配,四舍五入
|
|
|
+ int remainQty = ticketAwards.getQuantity();
|
|
|
+ for (int i = 1; i <= pkgNum; i++) {
|
|
|
+ int quantity;
|
|
|
+ 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();
|
|
|
}
|
|
|
- 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);
|
|
|
+ remainQty -= quantity;
|
|
|
+ Assert.isTrue(remainQty >= 0, "剩余奖级数量不足分配。boxId:" + ticketBox.getBoxId());
|
|
|
+ pkgAwardsMap.get(i).add(
|
|
|
+ new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
|
|
|
+ ticketAwards.getSort(), quantity));
|
|
|
}
|
|
|
- ticketService.saveBatch(ticketList);
|
|
|
}
|
|
|
- ticketPackageService.saveBatch(ticketPackageList);
|
|
|
- } else {
|
|
|
- // TODO 线上票,不用分包
|
|
|
-
|
|
|
+ LogUtil.debug(logger, "奖级{0}分包结果:{1}",
|
|
|
+ k, JSONObject.toJSONString(pkgAwardsMap));
|
|
|
}
|
|
|
- return true;
|
|
|
+ return pkgAwardsMap;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -284,34 +329,38 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
} else {
|
|
|
d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getQuantity())) / sumWeight;
|
|
|
}
|
|
|
- LogUtil.debug(logger, "prize:{0},区间 d1:{1}, d2:{2}", new Object[]{JSONObject.toJSONString(prizes.get(i)), d1, d2} );
|
|
|
+ LogUtil.debug(logger, "prize:{0},区间 d1:{1}, d2:{2}",
|
|
|
+ JSONObject.toJSONString(prizes.get(i)), d1, d2);
|
|
|
if (randomNumber > d1 && randomNumber <= d2) {
|
|
|
random = i;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- LogUtil.debug(logger, "抽中序号:{0}", new Object[]{random});
|
|
|
+ LogUtil.debug(logger, "抽中序号:{0}", random);
|
|
|
return random;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 从total中随机取n个不重复的数
|
|
|
+ * 从total中随机取n个不重复的数,范围[1, total]
|
|
|
*
|
|
|
* @param n
|
|
|
* @param total
|
|
|
* @return
|
|
|
*/
|
|
|
- private List<Integer> getRandomList(int n, int total) {
|
|
|
+ private List<Integer> getRandomList(List<Integer> excludeList, int n, int total) {
|
|
|
List<Integer> randomList = new ArrayList<>();
|
|
|
Random rand = new Random();
|
|
|
boolean[] bool = new boolean[total];
|
|
|
+ for (Integer exInt : excludeList) {
|
|
|
+ bool[exInt - 1] = true;
|
|
|
+ }
|
|
|
int randInt = 0;
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
do {
|
|
|
randInt = rand.nextInt(total);
|
|
|
} while (bool[randInt]);
|
|
|
bool[randInt] = true;
|
|
|
- randomList.add(randInt);
|
|
|
+ randomList.add(randInt + 1);
|
|
|
}
|
|
|
return randomList;
|
|
|
}
|
|
@@ -351,9 +400,10 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
prizes.add(new PkgAwards("3", "三等奖", 3, 3));
|
|
|
prizes.add(new PkgAwards("4", "四等奖", 4, 4));
|
|
|
TicketBoxServiceImpl boxService = new TicketBoxServiceImpl();
|
|
|
- for (int i = 0 ; i < 10; i ++ ) {
|
|
|
+ System.out.println(boxService.getRandomList(new ArrayList<>(), 10, 10));
|
|
|
+ /*for (int i = 0 ; i < 10; i ++ ) {
|
|
|
int random = boxService.getPrizeIndex(prizes);
|
|
|
System.out.println(random);
|
|
|
- }
|
|
|
+ }*/
|
|
|
}
|
|
|
}
|