|
@@ -1,21 +1,40 @@
|
|
|
package com.zanxiang.game.module.manage.service.impl;
|
|
|
|
|
|
+import com.alibaba.nacos.common.utils.CollectionUtils;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.github.sd4324530.jtuple.Tuple2;
|
|
|
+import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
|
|
|
+import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
|
|
|
+import com.zanxiang.game.module.manage.pojo.dto.GameGiftPackConditionDTO;
|
|
|
+import com.zanxiang.game.module.manage.pojo.dto.UserDTO;
|
|
|
import com.zanxiang.game.module.manage.pojo.params.GameGiftPackCodeLogListParam;
|
|
|
import com.zanxiang.game.module.manage.pojo.vo.GameGiftPackCodeLogVO;
|
|
|
-import com.zanxiang.game.module.manage.service.IGameGiftPackCodeLogService;
|
|
|
-import com.zanxiang.game.module.manage.service.IGameUserRoleService;
|
|
|
-import com.zanxiang.game.module.mybatis.entity.GameGiftPackCodeLog;
|
|
|
+import com.zanxiang.game.module.manage.service.*;
|
|
|
+import com.zanxiang.game.module.manage.utils.RedisUtil;
|
|
|
+import com.zanxiang.game.module.mybatis.entity.*;
|
|
|
import com.zanxiang.game.module.mybatis.mapper.GameGiftPackCodeLogMapper;
|
|
|
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
|
|
|
+import com.zanxiang.module.util.JsonUtil;
|
|
|
import com.zanxiang.module.util.bean.BeanUtil;
|
|
|
+import com.zanxiang.module.util.exception.BaseException;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.logging.log4j.util.Strings;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
-import reactor.util.function.Tuple2;
|
|
|
+import org.springframework.transaction.support.TransactionTemplate;
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.LocalTime;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @author : lingfeng
|
|
@@ -26,19 +45,271 @@ import java.time.LocalTime;
|
|
|
public class GameGiftPackCodeLogServiceImpl extends ServiceImpl<GameGiftPackCodeLogMapper, GameGiftPackCodeLog> implements IGameGiftPackCodeLogService {
|
|
|
|
|
|
@Autowired
|
|
|
- private IGameUserRoleService gameUserRoleService;
|
|
|
+ private ISmsService smsService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IUserService userService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IOrderService orderService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisUtil<String> redisUtil;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameServerService gameServerService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IRoleOperateService roleOperateService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TransactionTemplate transactionTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IUserLoginLogService userLoginLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameGiftPackCodeService gameGiftPackCodeService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameGiftPackLinkService gameGiftPackLinkService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDistributedLockComponent distributedLockComponent;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameGiftPackLinkLogService gameGiftPackLinkLogService;
|
|
|
|
|
|
@Override
|
|
|
public IPage<GameGiftPackCodeLogVO> list(GameGiftPackCodeLogListParam param) {
|
|
|
- return page(param.toPage(), new QueryWrapper<GameGiftPackCodeLog>().lambda()
|
|
|
+ IPage<GameGiftPackCodeLog> codeLogIPage = page(param.toPage(), new QueryWrapper<GameGiftPackCodeLog>().lambda()
|
|
|
.eq(GameGiftPackCodeLog::getLinkId, param.getLinkId())
|
|
|
.ge(param.getCreateBeginTime() != null, GameGiftPackCodeLog::getCreateTime, param.getCreateBeginTime() == null ? null : LocalDateTime.of(param.getCreateBeginTime(), LocalTime.MIN))
|
|
|
.le(param.getCreateEndTime() != null, GameGiftPackCodeLog::getCreateTime, param.getCreateEndTime() == null ? null : LocalDateTime.of(param.getCreateEndTime(), LocalTime.MAX))
|
|
|
- .orderByDesc(GameGiftPackCodeLog::getCreateTime)
|
|
|
- ).convert(log -> BeanUtil.copy(log, GameGiftPackCodeLogVO.class));
|
|
|
+ .orderByDesc(GameGiftPackCodeLog::getCreateTime));
|
|
|
+ IPage<GameGiftPackCodeLogVO> result = new Page<>(codeLogIPage.getCurrent(), codeLogIPage.getSize(), codeLogIPage.getTotal());
|
|
|
+ if (CollectionUtils.isNotEmpty(codeLogIPage.getRecords())) {
|
|
|
+ List<GameGiftPackCodeLog> records = codeLogIPage.getRecords();
|
|
|
+ List<String> serverIds = records.stream().map(GameGiftPackCodeLog::getServerId).collect(Collectors.toList());
|
|
|
+ Map<String, String> gameServerMap = gameServerService.list(new LambdaQueryWrapper<GameServer>()
|
|
|
+ .eq(GameServer::getIsSourceServer, Boolean.TRUE)
|
|
|
+ .in(GameServer::getServerId, serverIds)
|
|
|
+ ).stream().collect(Collectors.toMap(GameServer::getServerId, GameServer::getServerName));
|
|
|
+ result.setRecords(this.toVOBatch(records, gameServerMap));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<GameGiftPackCodeLogVO> toVOBatch(List<GameGiftPackCodeLog> codeLogList, Map<String, String> gameServerMap) {
|
|
|
+ return codeLogList.stream().map(codeLog -> {
|
|
|
+ GameGiftPackCodeLogVO gameGiftPackCodeLogVO = BeanUtil.copy(codeLog, GameGiftPackCodeLogVO.class);
|
|
|
+ String userPhone = codeLog.getUserPhone();
|
|
|
+ String phoneNum = userPhone.substring(0, 3) + " **** " + userPhone.substring(userPhone.length() - 4);
|
|
|
+ gameGiftPackCodeLogVO.setUserPhone(phoneNum);
|
|
|
+ gameGiftPackCodeLogVO.setServerName(gameServerMap.get(codeLog.getServerId()));
|
|
|
+ return gameGiftPackCodeLogVO;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Tuple2<Boolean, String> getGiftPackCode(Long linkId, String userPhone, String randomCode) {
|
|
|
+ //线程锁key
|
|
|
+ String lockKey = RedisKeyConstant.GAME_GIFT_PACK_LOCK + userPhone;
|
|
|
+ //线程锁 5 分钟, 防止同一用户重复请求
|
|
|
+ if (!distributedLockComponent.doLock(lockKey, 0L, 5L, TimeUnit.MINUTES)) {
|
|
|
+ throw new BaseException("操作频繁, 请稍后重试");
|
|
|
+ }
|
|
|
+ GameGiftPackLinkLog gameGiftPackLinkLog = gameGiftPackLinkLogService.getById(linkId);
|
|
|
+ assert gameGiftPackLinkLog != null : "参数错误, 链接访问日志信息不存在";
|
|
|
+ //判断验证是通过的
|
|
|
+ Long userId = gameGiftPackLinkLog.getUserId();
|
|
|
+ assert StringUtils.isNoneBlank(userId == null ? null : userId.toString(), gameGiftPackLinkLog.getServerId(),
|
|
|
+ gameGiftPackLinkLog.getRoleId(), gameGiftPackLinkLog.getRoleName()) : "参数错误, 链接访问记录信息缺失";
|
|
|
+ //获取礼包码, 且执行释放锁动作
|
|
|
+ try {
|
|
|
+ return this.getRandomCode(randomCode, userPhone, gameGiftPackLinkLog);
|
|
|
+ } finally {
|
|
|
+ distributedLockComponent.unlock(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple2<Boolean, String> getRandomCode(String randomCode, String userPhone, GameGiftPackLinkLog linkLog) {
|
|
|
+ //手机验证码校验
|
|
|
+ smsService.randomCodeCheck(userPhone, randomCode);
|
|
|
+ //查询记录, 判断是否重复领取, 重复领取直接返回之前领取的礼包码
|
|
|
+ Tuple2<Boolean, String> repeatCheck = this.repeatCheck(linkLog);
|
|
|
+ if (repeatCheck.first) {
|
|
|
+ return Tuple2.with(Boolean.TRUE, repeatCheck.second);
|
|
|
+ }
|
|
|
+ //异步更新角色操作表
|
|
|
+ roleOperateService.roleOperateUpdate(linkLog);
|
|
|
+ //构造记录
|
|
|
+ GameGiftPackCodeLog gameGiftPackCodeLog = this.transform(linkLog, userPhone);
|
|
|
+ //从缓存中获取一个礼包码id, 如果缓存中不存在则是领完了
|
|
|
+ String codeId = redisUtil.popOfSet(RedisKeyConstant.GAME_GIFT_PACK_CODE + linkLog.getLinkId());
|
|
|
+ if (Strings.isBlank(codeId)) {
|
|
|
+ String msg = "该礼包已被领取完, 请联系客服小姐姐领取其他礼包";
|
|
|
+ gameGiftPackCodeLog.setMsg(msg);
|
|
|
+ super.save(gameGiftPackCodeLog);
|
|
|
+ return Tuple2.with(Boolean.FALSE, msg);
|
|
|
+ }
|
|
|
+ //查询礼包码具体信息, 礼包码必须存在, 且未被领取, 否则数据错误
|
|
|
+ GameGiftPackCode gameGiftPackCode = gameGiftPackCodeService.getById(Long.valueOf(codeId));
|
|
|
+ assert gameGiftPackCode != null && !gameGiftPackCode.getIsSend() : "礼包码数据错误, 请联系客服小姐姐处理";
|
|
|
+ //判断是否满足领取条件
|
|
|
+ Tuple2<Boolean, String> conditionCheck = this.conditionCheck(linkLog);
|
|
|
+ //设置判定消息
|
|
|
+ gameGiftPackCodeLog.setMsg(conditionCheck.second);
|
|
|
+ //判定不通过, 返回错误消息提示
|
|
|
+ if (!conditionCheck.first) {
|
|
|
+ super.save(gameGiftPackCodeLog);
|
|
|
+ return Tuple2.with(Boolean.FALSE, "角色不满足该礼包领取条件, 请联系客服领取其他礼包");
|
|
|
+ }
|
|
|
+ //成功领取礼包码记录数据更新
|
|
|
+ this.codeSendUpdate(gameGiftPackCode, linkLog, gameGiftPackCodeLog);
|
|
|
+ //返回礼包码
|
|
|
+ return Tuple2.with(Boolean.TRUE, gameGiftPackCode.getCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple2<Boolean, String> repeatCheck(GameGiftPackLinkLog gameGiftPackLinkLog) {
|
|
|
+ GameGiftPackCodeLog giftPackCodeLog = super.getOne(new LambdaQueryWrapper<GameGiftPackCodeLog>()
|
|
|
+ .eq(GameGiftPackCodeLog::getLinkId, gameGiftPackLinkLog.getLinkId())
|
|
|
+ .eq(GameGiftPackCodeLog::getGameId, gameGiftPackLinkLog.getGameId())
|
|
|
+ .eq(GameGiftPackCodeLog::getRoleId, gameGiftPackLinkLog.getRoleId())
|
|
|
+ .isNotNull(GameGiftPackCodeLog::getCode));
|
|
|
+ return Tuple2.with(giftPackCodeLog != null, giftPackCodeLog != null ? giftPackCodeLog.getCode() : null);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void codeSendUpdate(GameGiftPackCode gameGiftPackCode, GameGiftPackLinkLog gameGiftPackLinkLog,
|
|
|
+ GameGiftPackCodeLog gameGiftPackCodeLog) {
|
|
|
+ //在同一个事物中进行表更新
|
|
|
+ transactionTemplate.execute(status -> {
|
|
|
+ //礼包码领取状态修改保存
|
|
|
+ gameGiftPackCode.setIsSend(Boolean.TRUE);
|
|
|
+ gameGiftPackCodeService.updateById(gameGiftPackCode);
|
|
|
+ //领取记录修改保存
|
|
|
+ gameGiftPackCodeLog.setCode(gameGiftPackCode.getCode());
|
|
|
+ super.save(gameGiftPackCodeLog);
|
|
|
+ //更新链接访问日志关联id
|
|
|
+ gameGiftPackLinkLog.setCodeLogId(gameGiftPackCodeLog.getId());
|
|
|
+ gameGiftPackLinkLog.setUpdateTime(LocalDateTime.now());
|
|
|
+ gameGiftPackLinkLogService.updateById(gameGiftPackLinkLog);
|
|
|
+ return Boolean.TRUE;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private GameGiftPackCodeLog transform(GameGiftPackLinkLog gameGiftPackLinkLog, String userPhone) {
|
|
|
+ return GameGiftPackCodeLog.builder()
|
|
|
+ .linkId(gameGiftPackLinkLog.getLinkId())
|
|
|
+ .userPhone(userPhone)
|
|
|
+ .gameId(gameGiftPackLinkLog.getGameId())
|
|
|
+ .userId(gameGiftPackLinkLog.getUserId())
|
|
|
+ .serverId(gameGiftPackLinkLog.getServerId())
|
|
|
+ .roleId(gameGiftPackLinkLog.getRoleId())
|
|
|
+ .roleName(gameGiftPackLinkLog.getRoleName())
|
|
|
+ .corpId(gameGiftPackLinkLog.getCorpId())
|
|
|
+ .corpUserId(gameGiftPackLinkLog.getCorpUserId())
|
|
|
+ .externalUserId(gameGiftPackLinkLog.getExternalUserId())
|
|
|
+ .linkLogId(gameGiftPackLinkLog.getId())
|
|
|
+ .createTime(LocalDateTime.now())
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple2<Boolean, String> conditionCheck(GameGiftPackLinkLog gameGiftPackLinkLog) {
|
|
|
+ GameGiftPackLink giftPackLink = gameGiftPackLinkService.getById(gameGiftPackLinkLog.getLinkId());
|
|
|
+ assert giftPackLink != null : "参数错误, 礼包链接信息不存在";
|
|
|
+ String codeCheck = giftPackLink.getCodeCheck();
|
|
|
+ if (Strings.isBlank(codeCheck)) {
|
|
|
+ return Tuple2.with(Boolean.TRUE, "领取成功, 礼包码领取条件 - 不存在");
|
|
|
+ }
|
|
|
+ GameGiftPackConditionDTO conditionDTO = JsonUtil.toObj(codeCheck, GameGiftPackConditionDTO.class);
|
|
|
+ //当前时间
|
|
|
+ LocalDateTime nowTime = LocalDateTime.now();
|
|
|
+ //注册时间区间判断
|
|
|
+ if (!this.regTimeCheck(nowTime, gameGiftPackLinkLog, conditionDTO.getRegTime())) {
|
|
|
+ return Tuple2.with(Boolean.FALSE, "注册时间区间 - 判定不通过");
|
|
|
+ }
|
|
|
+ //未登录时间区间判断
|
|
|
+ if (!this.unLoginCheck(nowTime, gameGiftPackLinkLog, conditionDTO.getUnLogin())) {
|
|
|
+ return Tuple2.with(Boolean.FALSE, "未登录时间区间 - 判定不通过");
|
|
|
+ }
|
|
|
+ //付费区间判断
|
|
|
+ if (!this.payCheck(gameGiftPackLinkLog, conditionDTO.getPay())) {
|
|
|
+ return Tuple2.with(Boolean.FALSE, "付费区间判断 - 判定不通过");
|
|
|
+ }
|
|
|
+ //判定通过
|
|
|
+ return Tuple2.with(Boolean.TRUE, "领取成功, 礼包码领取条件 - 全部判定通过");
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean regTimeCheck(LocalDateTime nowTime, GameGiftPackLinkLog gameGiftPackLinkLog,
|
|
|
+ GameGiftPackConditionDTO.RangeBean regTimeBean) {
|
|
|
+ //缺少条件参数, 无法判定, 直接返回通过
|
|
|
+ if (regTimeBean == null || regTimeBean.getMin() == null || regTimeBean.getMax() == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //查询玩家信息注册时间
|
|
|
+ UserDTO userDTO = userService.getById(gameGiftPackLinkLog.getUserId());
|
|
|
+ //玩家信息为空, 无法判定是否满足条件, 返回不通过
|
|
|
+ if (userDTO == null || userDTO.getCreateTime() == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //玩家注册时间
|
|
|
+ LocalDateTime userRegTime = userDTO.getCreateTime();
|
|
|
+ //计算时间区间
|
|
|
+ LocalDateTime startTime = nowTime.minusMinutes(regTimeBean.getMin());
|
|
|
+ LocalDateTime endTime = nowTime.plusMinutes(regTimeBean.getMax());
|
|
|
+ //返回判定
|
|
|
+ return userRegTime.isAfter(startTime) && userRegTime.isBefore(endTime);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean unLoginCheck(LocalDateTime nowTime, GameGiftPackLinkLog gameGiftPackLinkLog,
|
|
|
+ GameGiftPackConditionDTO.RangeBean unLoginBean) {
|
|
|
+ //缺少条件参数, 直接返回通过
|
|
|
+ if (unLoginBean == null || unLoginBean.getMin() == null || unLoginBean.getMax() == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //查询玩家最后登录时间
|
|
|
+ UserLoginLog userLoginLog = userLoginLogService.getOne(new LambdaQueryWrapper<UserLoginLog>()
|
|
|
+ .eq(UserLoginLog::getUserId, gameGiftPackLinkLog.getUserId())
|
|
|
+ .eq(UserLoginLog::getGameId, gameGiftPackLinkLog.getGameId())
|
|
|
+ .eq(UserLoginLog::getRoleId, gameGiftPackLinkLog.getRoleId())
|
|
|
+ .orderByDesc(UserLoginLog::getCreateTime)
|
|
|
+ .last("limit 1"));
|
|
|
+ //登录记录为空, 无法判定是否满足条件, 返回不通过
|
|
|
+ if (userLoginLog == null || userLoginLog.getCreateTime() == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //最后登录时间
|
|
|
+ LocalDateTime lastLoginTime = userLoginLog.getCreateTime();
|
|
|
+ //计算时间区间
|
|
|
+ LocalDateTime startTime = nowTime.minusMinutes(unLoginBean.getMin());
|
|
|
+ LocalDateTime endTime = nowTime.plusMinutes(unLoginBean.getMax());
|
|
|
+ //返回判定
|
|
|
+ return lastLoginTime.isBefore(startTime) || lastLoginTime.isAfter(endTime);
|
|
|
}
|
|
|
|
|
|
- public Tuple2<Boolean, String> gameRoleCheck(String gameServerId, String roleName) {
|
|
|
- return null;
|
|
|
+ private boolean payCheck(GameGiftPackLinkLog gameGiftPackLinkLog, GameGiftPackConditionDTO.RangeBean payBean) {
|
|
|
+ //缺少条件参数, 无法判定, 直接返回通过
|
|
|
+ if (payBean == null || payBean.getMin() == null || payBean.getMax() == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //查询玩家支付成功的订单信息
|
|
|
+ List<Order> userOrderList = orderService.list(new LambdaQueryWrapper<Order>()
|
|
|
+ .select(Order::getRealAmount)
|
|
|
+ .eq(Order::getUserId, gameGiftPackLinkLog.getUserId())
|
|
|
+ .eq(Order::getGameId, gameGiftPackLinkLog.getGameId())
|
|
|
+ .eq(Order::getRoleId, gameGiftPackLinkLog.getRoleId())
|
|
|
+ .eq(Order::getStatus, OrderStatusEnum.SUCCESS_PAY.getValue()));
|
|
|
+ //充值订单为空, 返回不通过
|
|
|
+ if (CollectionUtils.isEmpty(userOrderList)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //玩家充值总金额
|
|
|
+ BigDecimal userPaySum = userOrderList.stream().map(Order::getRealAmount)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ //返回判定
|
|
|
+ return userPaySum.compareTo(BigDecimal.valueOf(payBean.getMin())) >= 0
|
|
|
+ && userPaySum.compareTo(BigDecimal.valueOf(payBean.getMax())) <= 0;
|
|
|
}
|
|
|
}
|