星级厨房重构-预警机器人

This commit is contained in:
2023-03-08 14:31:20 +08:00
parent 260f2947d4
commit b8f2068ade
14 changed files with 182 additions and 99 deletions

View File

@@ -97,4 +97,5 @@ public interface LuckySeaActAdminService {
void delLuckySeaItemGroup(Long id);
void saveLuckySeaItemGroup(Long id, String name, String itemIds, Byte status);
}

View File

@@ -17,6 +17,7 @@ import com.accompany.admin.service.activity.LuckySeaActAdminService;
import com.accompany.admin.vo.luckysea.*;
import com.accompany.business.model.activity.luckysea.LuckySeaItem;
import com.accompany.business.model.activity.luckysea.LuckySeaItemGroup;
import com.accompany.business.service.activities.luckySea.LuckySeaActInfoService;
import com.accompany.business.service.activities.luckySea.LuckySeaItemGroupService;
import com.accompany.business.service.activities.luckySea.LuckySeaItemService;
import com.accompany.common.constant.Constant;
@@ -64,6 +65,8 @@ public class LuckySeaActAdminServiceImpl implements LuckySeaActAdminService {
@Autowired
private LuckySeaActAdminMapper luckySeaActAdminMapper;
@Autowired
private LuckySeaActInfoService luckySeaActInfoService;
@Autowired
private SysConfService sysConfService;
@Override
@@ -155,7 +158,7 @@ public class LuckySeaActAdminServiceImpl implements LuckySeaActAdminService {
});
if (CollectionUtil.isNotEmpty(newItems)) {
if (oldIds.size() + newItems.size() > 8){
if (oldItems.size() + newItems.size() > 8){
throw new ServiceException(BusiStatus.SERVERERROR, "最多只能存在 8 个档位");
}
@@ -300,7 +303,7 @@ public class LuckySeaActAdminServiceImpl implements LuckySeaActAdminService {
db.setStatus(status);
db.setCreateTime(now);
db.setUpdateTime(now);
//luckySeaItemGroupService.saveOrUpdate(db);
luckySeaItemGroupService.saveOrUpdate(db);
}
/**

View File

@@ -1,13 +1,3 @@
/*
* 文 件 名: LuckySeaActAdminController
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/1/11
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.admin.controller.activity;
import com.accompany.admin.controller.BaseController;
@@ -20,12 +10,9 @@ import com.accompany.admin.vo.luckysea.LuckySeaActPlatformStatVo;
import com.accompany.admin.vo.luckysea.LuckySeaItemGroupAdminVo;
import com.accompany.business.model.activity.luckysea.LuckySeaActInfo;
import com.accompany.business.model.activity.luckysea.LuckySeaItem;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.LuckySeaActInfoService;
import com.accompany.business.service.activities.luckySea.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.api.QinniuService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.result.BusiResult;
import com.accompany.common.result.PageResult;
import com.accompany.common.status.BusiStatus;
@@ -33,7 +20,6 @@ import com.accompany.common.utils.BlankUtil;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.enumeration.BusinessStatusCodeEnum;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.common.JedisService;
import com.accompany.core.vo.BaseResponseVO;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
@@ -47,7 +33,6 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
@@ -69,10 +54,6 @@ public class LuckySeaActAdminController extends BaseController {
@Autowired
private QinniuService qinniuService;
@Autowired
private ActivitiesLuckySeaService activitiesLuckySeaService;
@Autowired
private JedisService jedisService;
@Autowired
private LuckySeaActInfoService luckySeaActInfoService;
@RequestMapping(value = "/addOrUpdateItem", method = RequestMethod.POST)
@@ -235,8 +216,7 @@ public class LuckySeaActAdminController extends BaseController {
@RequestMapping(value = "/getStock", method = RequestMethod.GET)
public BaseResponseVO<String> getStock() {
Long stock = activitiesLuckySeaService.getStock();
String stockStr = new BigDecimal(stock).divide(new BigDecimal(ActivitiesLuckySeaServiceImpl.HANDLE_STOCK_MULTIPLE)).toString();
String stockStr = luckySeaActInfoService.getStockStr();
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, stockStr);
}
@@ -246,9 +226,7 @@ public class LuckySeaActAdminController extends BaseController {
if (null != currRound && Constant.LuckySeaActStatus.DRAWING.equals(currRound.getStatus())) {
throw new ServiceException("当前正在开奖,请等待开奖结束再修改库存");
}
Double stockValue = Double.valueOf(stock.trim());
Long stockLongValue = stockValue.longValue() * ActivitiesLuckySeaServiceImpl.HANDLE_STOCK_MULTIPLE;
jedisService.set(RedisKey.LUCKY_SEA_ACT_STOCK.getKey(), String.valueOf(stockLongValue));
luckySeaActInfoService.setStock(stock.trim());
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS);
}

View File

@@ -31,14 +31,47 @@ public class LuckySeaPreWarningConfig {
* 活动名称
*/
private String actName;
/**
* 金币预警
*/
private GoldPreWarning goldPreWarning;
/**
* 定时轮播
*/
private Broadcast broadcast;
/**
* 金币预警
*/
private InputOutputPreWarning inputOutputPreWarning;
/**
* 金币预警
*/
private GoldPreWarning goldPreWarning;
/**
* 定时轮播
*/
@Data
public static class Broadcast {
/**
* 开关
*/
private Boolean open;
/**
* 广播开启时间段
*/
private String openTime;
}
/**
* 金币预警
*/
@Data
public static class InputOutputPreWarning {
/**
* 开关
*/
private Boolean open;
private Long input;
private Long output;
}
/**
* 金币预警
@@ -68,20 +101,6 @@ public class LuckySeaPreWarningConfig {
* 预警比例 = out/in
*/
private Double warnRate;
}
/**
* 定时轮播
*/
@Data
public static class Broadcast {
/**
* 开关
*/
private Boolean open;
/**
* 广播开启时间段
*/
private String openTime;
private Long warnStock;
}
}

View File

@@ -1,17 +1,8 @@
/*
* 文 件 名: LuckySeaPreWarningMapper
* 版 权:
* 描 述: <描述>
* 创建人: H1
* 创建时间: 2021/9/22
* 修改人:
* 修改内容:
* 修改时间:
*/
package com.accompany.business.mybatismapper.activity;
import com.accompany.business.dto.activity.LuckySeaBroadCastDTO;
import com.accompany.business.dto.activity.LuckySeaGoldPreWarningDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
@@ -21,7 +12,11 @@ import org.apache.ibatis.annotations.Param;
* @author H1
* @date [2021/9/22]
*/
@Mapper
public interface LuckySeaPreWarningMapper {
LuckySeaBroadCastDTO getStatByRoundId(String roundId);
/**
* 统计前N轮的活动in和out
* @param roundNum 统计活动轮数

View File

@@ -13,9 +13,10 @@ package com.accompany.business.service;
import com.accompany.business.config.LuckySeaPreWarningConfig;
import com.accompany.business.dto.activity.LuckySeaBroadCastDTO;
import com.accompany.business.dto.activity.LuckySeaGoldPreWarningDTO;
import com.accompany.business.model.activity.luckysea.LuckySeaActInfo;
import com.accompany.business.model.activity.luckysea.LuckySeaDrawItem;
import com.accompany.business.mybatismapper.activity.LuckySeaPreWarningMapper;
import com.accompany.business.service.activities.luckySea.ActivitiesLuckySeaService;
import com.accompany.business.service.activities.luckySea.impl.ActivitiesLuckySeaServiceImpl;
import com.accompany.business.service.activities.luckySea.LuckySeaActInfoService;
import com.accompany.business.service.push.EnterpriseWechatPushService;
import com.accompany.common.config.WebSecurityConfig;
import com.accompany.common.constant.Constant;
@@ -37,6 +38,7 @@ import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <br>类描述:
@@ -56,7 +58,7 @@ public class LuckySeaPreWarningService {
@Autowired
private WebSecurityConfig webSecurityConfig;
@Autowired
private ActivitiesLuckySeaService activitiesLuckySeaService;
private LuckySeaActInfoService actInfoService;
@Autowired
private EnterpriseWechatPushService enterpriseWechatPushService;
@@ -64,25 +66,6 @@ public class LuckySeaPreWarningService {
private static final String START_TIME_KEY = "startTime";
private static final String END_TIME_KEY = "endTime";
/**
* 金币预警
*/
@Async
public void handleGoldPreWarning() {
log.info("[handleGoldPreWarning] =========== start ===========");
LuckySeaPreWarningConfig config = getConfig();
if (null == config) {
log.info("[handleGoldPreWarning] config is null");
return;
}
try {
handleGoldPreWarning(config);
log.info("[handleGoldPreWarning] =========== end ===========");
} catch (Exception e) {
log.error("[handleGoldPreWarning] error", e);
}
}
/**
* 获取预警配置
* @return
@@ -98,7 +81,7 @@ public class LuckySeaPreWarningService {
*/
private void handleGoldPreWarning(LuckySeaPreWarningConfig config) {
LuckySeaPreWarningConfig.GoldPreWarning goldPreWarning = config.getGoldPreWarning();
if (!goldPreWarning.getOpen()) {
if (null == goldPreWarning || !goldPreWarning.getOpen()) {
log.info("[handleGoldPreWarning] 开关未开启");
return;
}
@@ -109,10 +92,12 @@ public class LuckySeaPreWarningService {
}
for (LuckySeaPreWarningConfig.GoldPreWarningItem item : itemList) {
LuckySeaGoldPreWarningDTO stat = luckySeaPreWarningMapper.getPreRoundStat(item.getRoundNum());
if (stat.getGoldIn() != 0) {
double rate = new BigDecimal(stat.getGoldOut()).divide(BigDecimal.valueOf(stat.getGoldIn()), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
if (stat.getGoldIn() > 0) {
String stockStr = actInfoService.getStockStr();
Long stock = new BigDecimal(stockStr).longValue();
double rate = BigDecimal.valueOf(stat.getGoldOut()).divide(BigDecimal.valueOf(stat.getGoldIn()), 2, RoundingMode.HALF_UP).doubleValue();
log.info("[handleGoldPreWarning] 前{}轮 out{} in{} rate{}", item.getRoundNum(), stat.getGoldOut(), stat.getGoldIn(), rate);
if (rate >= item.getWarnRate()) {
if (rate >= item.getWarnRate() || stock <= item.getWarnStock()) {
sendGoldPreWarningEnterpriseWechatMsg(config, stat, item.getRoundNum(), rate);
}
}
@@ -121,23 +106,26 @@ public class LuckySeaPreWarningService {
/**
* 发送金币预警企业微信消息
*
* @param config
* @param stat
* @param roundNum
* @param rate
*/
private void sendGoldPreWarningEnterpriseWechatMsg(LuckySeaPreWarningConfig config, LuckySeaGoldPreWarningDTO stat, Integer roundNum, Double rate) {
String stockStr = actInfoService.getStockStr();
MarkdownMessage msg = new MarkdownMessage();
String appName = config.getAppName();
String actName = config.getActName();
msg.add(MarkdownMessage.getHeaderText(3, actName + "产出金币预警"));
msg.add(MarkdownMessage.getHeaderText(3, actName + "库存预警"));
msg.add(MarkdownMessage.getReferenceText("["+ appName + "]" + "[" + actName + "]在前" + roundNum + "轮的产出/投入=" + "[" + rate + "],具体:"));
msg.add(MarkdownMessage.getReferenceText(""+ roundNum + "轮投入:" + stat.getGoldIn()));
msg.add(MarkdownMessage.getReferenceText(""+ roundNum + "轮产出:" + stat.getGoldOut()));
msg.add(MarkdownMessage.getReferenceText("当前库存数:" + stockStr));
msg.add(MarkdownMessage.getReferenceText("请判断是否需要前往后台查看"));
String key = webSecurityConfig.getActivityEnterpriseWechatPushKey();
enterpriseWechatPushService.pushMessageByKey(key,msg);
}
/**
@@ -210,6 +198,8 @@ public class LuckySeaPreWarningService {
* @param endTime
*/
private void sendBroadcastEnterpriseWechatMsg(LuckySeaPreWarningConfig config, LuckySeaBroadCastDTO broadCastStat, String startTime, String endTime) {
String stockStr = actInfoService.getStockStr();
MarkdownMessage msg = new MarkdownMessage();
String appName = config.getAppName();
String actName = config.getActName();
@@ -219,11 +209,58 @@ public class LuckySeaPreWarningService {
msg.add(MarkdownMessage.getReferenceText("用户参与总值:" + broadCastStat.getGoldIn()));
msg.add(MarkdownMessage.getReferenceText("用户产出总值:" + broadCastStat.getGoldOut()));
msg.add(MarkdownMessage.getReferenceText("游戏执行轮数:" + broadCastStat.getRoundNum()));
Long stock = activitiesLuckySeaService.getStock();
String stockStr = new BigDecimal(stock).divide(new BigDecimal(ActivitiesLuckySeaServiceImpl.HANDLE_STOCK_MULTIPLE), 2, RoundingMode.HALF_DOWN).toString();
msg.add(MarkdownMessage.getReferenceText("当前库存数:" + stockStr));
String key = webSecurityConfig.getActivityEnterpriseWechatPushKey();
enterpriseWechatPushService.pushMessageByKey(key,msg);
}
@Async
public void handleWarning(String roundId) {
LuckySeaPreWarningConfig config = getConfig();
if (null == config) {
log.info("[handleGoldPreWarning] config is null");
return;
}
handleInputOutputPreWarning(roundId, config);
handleGoldPreWarning(config);
}
private void handleInputOutputPreWarning(String roundId, LuckySeaPreWarningConfig c) {
LuckySeaPreWarningConfig.InputOutputPreWarning config = c.getInputOutputPreWarning();
if (null == config || !config.getOpen()){
log.info("[handleInputOutputPreWarning] 开关未开启");
return;
}
LuckySeaBroadCastDTO statDto = luckySeaPreWarningMapper.getStatByRoundId(roundId);
if (null == statDto) {
return;
}
if (statDto.getGoldIn() > config.getInput() || statDto.getGoldOut() > config.getOutput()){
sendInputOutputWarningEnterpriseWechatMsg(c, statDto, roundId);
}
}
private void sendInputOutputWarningEnterpriseWechatMsg(LuckySeaPreWarningConfig config, LuckySeaBroadCastDTO broadCastStat, String roundId) {
String stockStr = actInfoService.getStockStr();
LuckySeaActInfo actInfo = actInfoService.getById(roundId);
String drawItemNames = actInfo.getDrawItemList().stream()
.map(LuckySeaDrawItem::getDrawName)
.collect(Collectors.joining(","));
MarkdownMessage msg = new MarkdownMessage();
String appName = config.getAppName();
String actName = config.getActName();
msg.add(MarkdownMessage.getHeaderText(3, actName + "高投产播报"));
msg.add(MarkdownMessage.getReferenceText("["+ appName + "]" + "[" + actName + "]"));
msg.add(MarkdownMessage.getReferenceText("轮次:" + roundId));
msg.add(MarkdownMessage.getReferenceText("开奖:" + actInfo.getDrawName()) + "("+ drawItemNames + ")");
msg.add(MarkdownMessage.getReferenceText("参与用户数:" + broadCastStat.getPeopleNum()));
msg.add(MarkdownMessage.getReferenceText("用户参与总值:" + broadCastStat.getGoldIn()));
msg.add(MarkdownMessage.getReferenceText("用户产出总值:" + broadCastStat.getGoldOut()));
msg.add(MarkdownMessage.getReferenceText("当前库存数:" + stockStr));
String key = webSecurityConfig.getActivityEnterpriseWechatPushKey();
enterpriseWechatPushService.pushMessageByKey(key,msg);
}
}

View File

@@ -93,7 +93,8 @@ public interface ActivitiesLuckySeaService {
/**
* 获取游戏库存
*
* @return
*/
Long getStock();
String getStock();
}

View File

@@ -25,6 +25,8 @@ public interface LuckySeaActInfoService extends IService<LuckySeaActInfo> {
Long getStock();
String getStockStr();
LuckySeaActInfo createNewRoundAct(Integer chooseStageTime);
boolean updateStatus(String roundId, Byte drawing);
@@ -36,8 +38,9 @@ public interface LuckySeaActInfoService extends IService<LuckySeaActInfo> {
long subStock(Long prizePiece);
void setStock(Long stoke);
void setStock(String stock);
boolean endRound(String roundId);
}

View File

@@ -84,11 +84,6 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
@Autowired
private Executor taskExecutor;
/**
* 处理库存时需要换算的倍数
*/
public final static Integer HANDLE_STOCK_MULTIPLE = 100000;
@Override
public void updateUserLuckySeaActPiece(Long uid, Integer packId, Integer packNum) {
@@ -344,11 +339,10 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
@Override
public void compensateUserPieceWhenGameAbnormal(String roundId, Long beforeStoke) {
// 将库存还原为发生异常之前的库存
luckySeaActInfoService.setStock(beforeStoke);
log.info("春日游园活动,开始处理发生异常的活动, roundId:{}, 还原库存:{}", roundId, beforeStoke);
// 将库存还原为发生异常之前的库存
jedisService.set(RedisKey.LUCKY_SEA_ACT_STOCK.getKey(), String.valueOf(beforeStoke));
// 获取此轮参加游戏的用户投入碎片情况
List<LuckySeaActUserRoundStatDTO> statList = luckySeaActMapper.listUserDrawStatDtoOneRound(roundId);
if (!CollectionUtils.isEmpty(statList)) {
@@ -361,11 +355,12 @@ public class ActivitiesLuckySeaServiceImpl implements ActivitiesLuckySeaService
/**
* 获取深海活动的库存
*
* @return
*/
@Override
public Long getStock() {
return luckySeaActInfoService.getStock();
public String getStock() {
return luckySeaActInfoService.getStockStr();
}
}

View File

@@ -18,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -67,6 +66,13 @@ public class LuckySeaActInfoServiceImpl extends ServiceImpl<LuckySeaActInfoMappe
return stock;
}
@Override
public String getStockStr() {
Long stockInCache = getStock();
BigDecimal stock = BigDecimal.valueOf(stockInCache).divide(STOCK_MULTIPLE, 5, RoundingMode.DOWN);
return stock.toPlainString();
}
@Override
public Long addUserStock(String roundId, Long userInput, Double ticket) {
Long stockInCache = getStock();
@@ -96,6 +102,12 @@ public class LuckySeaActInfoServiceImpl extends ServiceImpl<LuckySeaActInfoMappe
stockCache.set(stoke);
}
@Override
public void setStock(String stock) {
Long stockInCache = new BigDecimal(stock).multiply(STOCK_MULTIPLE).longValue();
setStock(stockInCache);
}
@Override
public LuckySeaActInfo createNewRoundAct(Integer chooseStageConfigTime) {
Date startTime = new Date();

View File

@@ -210,7 +210,7 @@ public class LuckySeaDrawServiceImpl implements LuckySeaDrawService {
log.info("春日游园活动此轮结束, roundId:{}", roundId);
// 进行预警数据统计
luckySeaPreWarningService.handleGoldPreWarning();
luckySeaPreWarningService.handleWarning(roundId);
} catch (Exception e) {
// 更新活动状态
log.error("春日游园活动更新用户抽奖记录与分发奖励时出现异常, roundId: " + roundId, e);

View File

@@ -1,6 +1,15 @@
<?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="com.accompany.business.mybatismapper.activity.LuckySeaPreWarningMapper">
<select id="getStatByRoundId" resultType="com.accompany.business.dto.activity.LuckySeaBroadCastDTO">
select ifnull(sum(r.cost_piece_num),0) as goldIn,
ifnull(sum(if(r.draw_status = 1, r.cost_piece_num * r.item_multiple, 0 )), 0) as goldOut,
count(distinct r.uid) peopleNum
from lucky_sea_user_draw_record r
where r.round_id = #{roundId};
</select>
<select id="getPreRoundStat" resultType="com.accompany.business.dto.activity.LuckySeaGoldPreWarningDTO">
select ifnull(sum(r.cost_piece_num),0) as goldIn,
ifnull(sum(if(r.draw_status = 1, r.cost_piece_num * r.item_multiple, 0 )), 0) as goldOut

View File

@@ -0,0 +1,30 @@
package com.accompany.scheduler.task.activity;
import com.accompany.business.service.LuckySeaPreWarningService;
import com.accompany.scheduler.base.BaseTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class LuckySeaPreWarningTask extends BaseTask {
@Autowired
private LuckySeaPreWarningService luckySeaPreWarningService;
/**
* 自动轮播寻找小精灵
*/
@Scheduled(cron = "0 0 */1 * * ?")
public void handleBroadcastTask() {
try {
log.info("开始自动轮播星级厨房");
luckySeaPreWarningService.handleBroadcast();
log.info("开始自动轮播星级厨房");
} catch (Exception e) {
log.error("开始自动轮播星级厨房失败...", e);
}
}
}

View File

@@ -1,4 +1,4 @@
package com.accompany.scheduler.task;
package com.accompany.scheduler.task.activity;
import com.accompany.business.service.seekelfin.SeekElfinPreWarningService;
import com.accompany.scheduler.base.BaseTask;