Browse Source

对接拼团数据1

master
wangfukang 2 months ago
parent
commit
24003857e7
  1. 16
      hiver-admin/test-output/test-report.html
  2. 2
      hiver-core/src/main/java/cc/hiver/core/common/constant/DealingsRecordConstant.java
  3. 51
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/controller/PlanetController.java
  4. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetDailyLoopVo.java
  5. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetHomeVo.java
  6. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetRankItemVo.java
  7. 7
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetAdventurePkService.java
  8. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetDrawService.java
  9. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetService.java
  10. 44
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetAdminServiceImpl.java
  11. 193
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetAdventurePkServiceImpl.java
  12. 12
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetBoxServiceImpl.java
  13. 149
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetDrawServiceImpl.java
  14. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetOperateServiceImpl.java
  15. 55
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetRankServiceImpl.java
  16. 142
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetServiceImpl.java
  17. 28
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetTicketServiceImpl.java
  18. 37
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java
  19. 98
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetAdventureSettleTask.java
  20. 22
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetDailyResetTask.java
  21. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetDrawTask.java
  22. 134
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetOperateSettleTask.java

16
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a> <a href="#"><span class="badge badge-primary">Hiver</span></a>
</li> </li>
<li class="m-r-10"> <li class="m-r-10">
<a href="#"><span class="badge badge-primary">六月 05, 2026 16:39:30</span></a> <a href="#"><span class="badge badge-primary">六月 09, 2026 18:01:00</span></a>
</li> </li>
</ul> </ul>
</div> </div>
@ -84,7 +84,7 @@
<div class="test-detail"> <div class="test-detail">
<span class="meta text-white badge badge-sm"></span> <span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p> <p class="name">passTest</p>
<p class="text-sm"><span>16:39:31 下午</span> / <span>0.017 secs</span></p> <p class="text-sm"><span>18:01:01 下午</span> / <span>0.021 secs</span></p>
</div> </div>
<div class="test-contents d-none"> <div class="test-contents d-none">
<div class="detail-head"> <div class="detail-head">
@ -92,9 +92,9 @@
<div class="info"> <div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div> <div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5> <h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>06.05.2026 16:39:31</span> <span class='badge badge-success'>06.09.2026 18:01:01</span>
<span class='badge badge-danger'>06.05.2026 16:39:31</span> <span class='badge badge-danger'>06.09.2026 18:01:01</span>
<span class='badge badge-default'>0.017 secs</span> <span class='badge badge-default'>0.021 secs</span>
</div> </div>
<div class="m-t-10 m-l-5"></div> <div class="m-t-10 m-l-5"></div>
</div> </div>
@ -104,7 +104,7 @@
<tbody> <tbody>
<tr class="event-row"> <tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td> <td><span class="badge log pass-bg">Pass</span></td>
<td>16:39:31</td> <td>18:01:01</td>
<td> <td>
Test passed Test passed
</td> </td>
@ -128,13 +128,13 @@
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Started</p> <p class="m-b-0">Started</p>
<h3>六月 05, 2026 16:39:30</h3> <h3>六月 09, 2026 18:01:00</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Ended</p> <p class="m-b-0">Ended</p>
<h3>六月 05, 2026 16:39:31</h3> <h3>六月 09, 2026 18:01:01</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">

2
hiver-core/src/main/java/cc/hiver/core/common/constant/DealingsRecordConstant.java

@ -15,7 +15,7 @@ public interface DealingsRecordConstant {
/** /**
* *
*/ */
String[] TYPE_REMARK = {"配送订单佣金","售后退款","配送排名奖励","商家提现","配送员提现","免单奖励","商家结算","用户提现","白嫖中奖"}; String[] TYPE_REMARK = {"配送订单佣金","售后退款","配送排名奖励","商家提现","配送员提现","免单奖励","商家结算","用户提现","白嫖中奖","学院排位赛排名奖励"};
/** /**
*交易类型0:增加 1 提现 2消费 3售后 *交易类型0:增加 1 提现 2消费 3售后

51
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/controller/PlanetController.java

@ -4,10 +4,7 @@ import cc.hiver.core.common.exception.HiverException;
import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.core.common.vo.Result; import cc.hiver.core.common.vo.Result;
import cc.hiver.mall.planet.entity.PlanetDrawRecord; import cc.hiver.mall.planet.entity.PlanetDrawRecord;
import cc.hiver.mall.planet.pojo.PlanetBoxResultVo; import cc.hiver.mall.planet.pojo.*;
import cc.hiver.mall.planet.pojo.PlanetHomeVo;
import cc.hiver.mall.planet.pojo.PlanetHuntResultVo;
import cc.hiver.mall.planet.pojo.PlanetQuery;
import cc.hiver.mall.planet.service.*; import cc.hiver.mall.planet.service.*;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -91,6 +88,23 @@ public class PlanetController {
} }
} }
@ApiOperation(value = "星球补给地图聚合数据")
@RequestMapping(value = "/supply", method = RequestMethod.POST)
public Result supply(@RequestBody PlanetQuery query) {
if (StringUtils.isEmpty(query.getUserId())) {
return ResultUtil.error("用户id不能为空");
}
if (StringUtils.isEmpty(query.getRegionId())) {
return ResultUtil.error(REGION_REQUIRED);
}
try {
final PlanetHomeVo vo = planetService.supply(query);
return new ResultUtil<PlanetHomeVo>().setData(vo);
} catch (HiverException e) {
return ResultUtil.error(e.getMessage());
}
}
@ApiOperation(value = "通缉榜TOP10") @ApiOperation(value = "通缉榜TOP10")
@RequestMapping(value = "/rank", method = RequestMethod.POST) @RequestMapping(value = "/rank", method = RequestMethod.POST)
public Result rank(@RequestBody PlanetQuery query) { public Result rank(@RequestBody PlanetQuery query) {
@ -100,6 +114,23 @@ public class PlanetController {
return new ResultUtil<>().setData(rankService.rankTop(query.getRegionId(), 10, query.getUserId())); return new ResultUtil<>().setData(rankService.rankTop(query.getRegionId(), 10, query.getUserId()));
} }
@ApiOperation(value = "通缉榜分页")
@RequestMapping(value = "/rank/page", method = RequestMethod.POST)
public Result rankPage(@RequestBody PlanetQuery query) {
if (StringUtils.isEmpty(query.getRegionId())) {
return ResultUtil.error(REGION_REQUIRED);
}
final Map<String, Object> data = new HashMap<>(8);
final com.baomidou.mybatisplus.extension.plugins.pagination.Page<PlanetRankItemVo> page =
rankService.rankPage(query.getRegionId(), query.getPageNumber(), query.getPageSize(), query.getUserId());
data.put("rankList", page.getRecords());
data.put("rankTotal", page.getTotal());
data.put("rankTotalPages", page.getPages());
data.put("rankPageNumber", page.getCurrent());
data.put("remainHunt", huntService.remainHunt(query.getUserId()));
return new ResultUtil<>().setData(data);
}
@ApiOperation(value = "发起追捕") @ApiOperation(value = "发起追捕")
@RequestMapping(value = "/hunt", method = RequestMethod.POST) @RequestMapping(value = "/hunt", method = RequestMethod.POST)
public Result hunt(@RequestBody PlanetQuery query) { public Result hunt(@RequestBody PlanetQuery query) {
@ -211,6 +242,7 @@ public class PlanetController {
final Map<String, Object> data = new HashMap<>(4); final Map<String, Object> data = new HashMap<>(4);
data.put("record", record); data.put("record", record);
data.put("winners", record == null ? null : drawService.winnersOfDraw(record.getId())); data.put("winners", record == null ? null : drawService.winnersOfDraw(record.getId()));
data.put("history", drawService.recentDrawResults(query.getRegionId(), 10));
return new ResultUtil<>().setData(data); return new ResultUtil<>().setData(data);
} catch (HiverException e) { } catch (HiverException e) {
return ResultUtil.error(e.getMessage()); return ResultUtil.error(e.getMessage());
@ -619,6 +651,17 @@ public class PlanetController {
} }
} }
@ApiOperation(value = "星球擂台-房间实时信息")
@RequestMapping(value = "/adventure/pk/roomInfo", method = RequestMethod.POST)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public Result adventurePkRoomInfo(@RequestBody PlanetQuery query) {
try {
return new ResultUtil<>().setData(adventurePkService.roomInfo(query.getUserId(), query.getRegionId(), query.getRoomId()));
} catch (HiverException e) {
return ResultUtil.error(e.getMessage());
}
}
@ApiOperation(value = "加入星球擂台房间") @ApiOperation(value = "加入星球擂台房间")
@RequestMapping(value = "/adventure/pk/join", method = RequestMethod.POST) @RequestMapping(value = "/adventure/pk/join", method = RequestMethod.POST)
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetDailyLoopVo.java

@ -15,7 +15,9 @@ public class PlanetDailyLoopVo implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Integer todayCollectedTickets; private Integer todayCollectedTickets;
private Integer myPoolTickets; private Integer myPoolTickets;
private Integer myWeightTickets;
private Integer poolTicketTotal; private Integer poolTicketTotal;
private Integer poolWeightTotal;
private Integer poolJoinCount; private Integer poolJoinCount;
private BigDecimal myProbability; private BigDecimal myProbability;
private Integer suggestedAddTickets; private Integer suggestedAddTickets;

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetHomeVo.java

@ -2,6 +2,7 @@ package cc.hiver.mall.planet.pojo;
import cc.hiver.mall.planet.entity.PlanetDrawWinner; import cc.hiver.mall.planet.entity.PlanetDrawWinner;
import cc.hiver.mall.planet.entity.PlanetNews; import cc.hiver.mall.planet.entity.PlanetNews;
import cc.hiver.mall.planet.entity.PlanetReward;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -38,6 +39,9 @@ public class PlanetHomeVo implements Serializable {
@ApiModelProperty(value = "期号") @ApiModelProperty(value = "期号")
private String periodNo; private String periodNo;
@ApiModelProperty(value = "本期奖项配置")
private List<PlanetReward> rewardList;
// ---------- 我的星球中心 ---------- // ---------- 我的星球中心 ----------
@ApiModelProperty(value = "我的券数量") @ApiModelProperty(value = "我的券数量")
private Integer myTicketCount; private Integer myTicketCount;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetRankItemVo.java

@ -50,6 +50,9 @@ public class PlanetRankItemVo implements Serializable {
@ApiModelProperty(value = "是否开启防护罩") @ApiModelProperty(value = "是否开启防护罩")
private Boolean shielded; private Boolean shielded;
@ApiModelProperty(value = "是否拥有防御塔")
private Boolean hasTower;
@ApiModelProperty(value = "是否隐身") @ApiModelProperty(value = "是否隐身")
private Boolean stealth; private Boolean stealth;

7
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetAdventurePkService.java

@ -3,6 +3,7 @@ package cc.hiver.mall.planet.service;
import cc.hiver.mall.planet.entity.PlanetAdventureChallenge; import cc.hiver.mall.planet.entity.PlanetAdventureChallenge;
import cc.hiver.mall.planet.entity.PlanetAdventurePkPlayer; import cc.hiver.mall.planet.entity.PlanetAdventurePkPlayer;
import cc.hiver.mall.planet.entity.PlanetAdventurePkRoom; import cc.hiver.mall.planet.entity.PlanetAdventurePkRoom;
import cc.hiver.mall.planet.entity.PlanetAdventureSession;
import cc.hiver.mall.planet.pojo.PlanetAdventureChallengeResultVo; import cc.hiver.mall.planet.pojo.PlanetAdventureChallengeResultVo;
import cc.hiver.mall.planet.pojo.PlanetAdventurePkHallVo; import cc.hiver.mall.planet.pojo.PlanetAdventurePkHallVo;
import cc.hiver.mall.planet.pojo.PlanetAdventurePkPlayVo; import cc.hiver.mall.planet.pojo.PlanetAdventurePkPlayVo;
@ -20,6 +21,8 @@ public interface PlanetAdventurePkService {
Page<PlanetAdventurePkRoom> hotRooms(String userId, String regionId, Integer pageNumber, Integer pageSize); Page<PlanetAdventurePkRoom> hotRooms(String userId, String regionId, Integer pageNumber, Integer pageSize);
PlanetAdventurePkPlayVo roomInfo(String userId, String regionId, String roomId);
PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar, PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar,
String college, String roomName, Integer maxPlayers, String college, String roomName, Integer maxPlayers,
Integer publicFlag, String password, Integer entryTickets); Integer publicFlag, String password, Integer entryTickets);
@ -32,6 +35,8 @@ public interface PlanetAdventurePkService {
PlanetAdventurePkPlayVo leaveRoom(String userId, String regionId, String roomId, Integer remainingCards); PlanetAdventurePkPlayVo leaveRoom(String userId, String regionId, String roomId, Integer remainingCards);
int autoSettleOverdueRooms();
PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar, PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar,
String college, Integer durationSeconds); String college, Integer durationSeconds);
@ -41,5 +46,5 @@ public interface PlanetAdventurePkService {
String college, String challengeId, Integer cleared, String college, String challengeId, Integer cleared,
Integer durationSeconds, Integer remainingCards); Integer durationSeconds, Integer remainingCards);
List<?> gloryTop(String regionId); List<PlanetAdventureSession> gloryTop(String regionId);
} }

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetDrawService.java

@ -7,6 +7,7 @@ import cc.hiver.mall.planet.entity.PlanetPoolTicket;
import cc.hiver.mall.planet.pojo.PlanetDailyLoopVo; import cc.hiver.mall.planet.pojo.PlanetDailyLoopVo;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 白嫖星球-开奖服务 * 白嫖星球-开奖服务
@ -52,6 +53,11 @@ public interface PlanetDrawService {
*/ */
List<PlanetDrawWinner> winnersOfDraw(String drawId); List<PlanetDrawWinner> winnersOfDraw(String drawId);
/**
* 最近若干期开奖及中奖名单按商圈隔离
*/
List<Map<String, Object>> recentDrawResults(String regionId, int limit);
/** /**
* 我的中奖记录(仅限本商圈) * 我的中奖记录(仅限本商圈)
*/ */

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/PlanetService.java

@ -14,4 +14,9 @@ public interface PlanetService {
* 首页聚合数据 * 首页聚合数据
*/ */
PlanetHomeVo home(PlanetQuery query); PlanetHomeVo home(PlanetQuery query);
/**
* 星球补给地图聚合数据
*/
PlanetHomeVo supply(PlanetQuery query);
} }

44
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetAdminServiceImpl.java

@ -12,6 +12,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -75,6 +77,40 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
return UUID.randomUUID().toString().replace("-", ""); return UUID.randomUUID().toString().replace("-", "");
} }
private Date nextDrawTime(Date from) {
final Calendar c = Calendar.getInstance();
c.setTime(from);
c.set(Calendar.HOUR_OF_DAY, 22);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
if (!c.getTime().after(from)) {
c.add(Calendar.DAY_OF_MONTH, 1);
}
return c.getTime();
}
private void refreshPoolRewardAmount(String poolId) {
if (StringUtils.isEmpty(poolId)) {
return;
}
final PlanetPool pool = poolMapper.selectById(poolId);
if (pool == null) {
return;
}
final List<PlanetReward> rewards = rewardMapper.selectList(new LambdaQueryWrapper<PlanetReward>()
.eq(PlanetReward::getPoolId, poolId));
BigDecimal total = BigDecimal.ZERO;
for (PlanetReward reward : rewards) {
final BigDecimal amount = reward.getAmount() == null ? BigDecimal.ZERO : reward.getAmount();
final int quota = reward.getQuota() == null ? 0 : reward.getQuota();
total = total.add(amount.multiply(BigDecimal.valueOf(quota)));
}
pool.setPoolAmount(total);
pool.setUpdateTime(new Date());
poolMapper.updateById(pool);
}
private <T> Page<T> page(PageVo pageVo) { private <T> Page<T> page(PageVo pageVo) {
final int num = pageVo == null || pageVo.getPageNumber() <= 0 ? 1 : pageVo.getPageNumber(); final int num = pageVo == null || pageVo.getPageNumber() <= 0 ? 1 : pageVo.getPageNumber();
final int size = pageVo == null || pageVo.getPageSize() <= 0 ? 10 : pageVo.getPageSize(); final int size = pageVo == null || pageVo.getPageSize() <= 0 ? 10 : pageVo.getPageSize();
@ -110,6 +146,9 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
if (pool.getWinnerCount() == null) { if (pool.getWinnerCount() == null) {
pool.setWinnerCount(0); pool.setWinnerCount(0);
} }
if (pool.getDrawTime() == null) {
pool.setDrawTime(nextDrawTime(new Date()));
}
pool.setCreateTime(new Date()); pool.setCreateTime(new Date());
pool.setUpdateTime(new Date()); pool.setUpdateTime(new Date());
poolMapper.insert(pool); poolMapper.insert(pool);
@ -144,12 +183,17 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
} else { } else {
rewardMapper.updateById(reward); rewardMapper.updateById(reward);
} }
refreshPoolRewardAmount(reward.getPoolId());
return reward; return reward;
} }
@Override @Override
public void deleteReward(String id) { public void deleteReward(String id) {
final PlanetReward reward = rewardMapper.selectById(id);
rewardMapper.deleteById(id); rewardMapper.deleteById(id);
if (reward != null) {
refreshPoolRewardAmount(reward.getPoolId());
}
} }
@Override @Override

193
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetAdventurePkServiceImpl.java

@ -25,6 +25,8 @@ import java.util.UUID;
@Service @Service
public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService { public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
private static final int AUTO_FAIL_REMAINING_CARDS = 999999;
@Autowired @Autowired
private PlanetAdventurePkRoomMapper roomMapper; private PlanetAdventurePkRoomMapper roomMapper;
@Autowired @Autowired
@ -85,6 +87,23 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
.orderByDesc(PlanetAdventurePkRoom::getCreateTime)); .orderByDesc(PlanetAdventurePkRoom::getCreateTime));
} }
@Override
public PlanetAdventurePkPlayVo roomInfo(String userId, String regionId, String roomId) {
if (StringUtils.isEmpty(userId)) throw new HiverException("用户id不能为空");
PlanetAdventurePkRoom room = mustRoom(roomId, regionId);
PlanetAdventurePkPlayer player = playerMapper.selectOne(new LambdaQueryWrapper<PlanetAdventurePkPlayer>()
.eq(PlanetAdventurePkPlayer::getRoomId, roomId)
.eq(PlanetAdventurePkPlayer::getUserId, userId)
.last("limit 1"));
PlanetAdventurePkPlayVo vo = new PlanetAdventurePkPlayVo();
vo.setMode("pk");
vo.setRoomId(room.getId());
vo.setSeed(room.getRoomSeed());
vo.setRoom(room);
vo.setPlayer(player);
return vo;
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar, public PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar,
@ -93,8 +112,11 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
require(userId, regionId); require(userId, regionId);
int players = maxPlayers == null ? 2 : Math.max(2, Math.min(5, maxPlayers)); int players = maxPlayers == null ? 2 : Math.max(2, Math.min(5, maxPlayers));
int tickets = entryTickets == null ? 1 : Math.max(1, entryTickets); int tickets = entryTickets == null ? 1 : Math.max(1, entryTickets);
String roomId = genId();
ticketService.deductTickets(userId, regionId, tickets,
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_ENTRY, roomId + "_" + userId, "星球擂台开房入场券");
PlanetAdventurePkRoom room = new PlanetAdventurePkRoom(); PlanetAdventurePkRoom room = new PlanetAdventurePkRoom();
room.setId(genId()); room.setId(roomId);
room.setRoomName(StringUtils.isEmpty(roomName) ? "星球擂台房间" : roomName.trim()); room.setRoomName(StringUtils.isEmpty(roomName) ? "星球擂台房间" : roomName.trim());
room.setRegionId(regionId); room.setRegionId(regionId);
room.setOwnerUserId(userId); room.setOwnerUserId(userId);
@ -106,11 +128,13 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
room.setPassword(password); room.setPassword(password);
room.setEntryTickets(tickets); room.setEntryTickets(tickets);
room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_WAITING); room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_WAITING);
room.setPoolTickets(0); room.setPoolTickets(tickets);
room.setPlayerCount(0); room.setPlayerCount(1);
room.setCreateTime(new Date()); room.setCreateTime(new Date());
room.setUpdateTime(new Date()); room.setUpdateTime(new Date());
roomMapper.insert(room); roomMapper.insert(room);
PlanetAdventurePkPlayer owner = newPkPlayer(roomId, regionId, userId, nickname, avatar, college, tickets);
playerMapper.insert(owner);
return room; return room;
} }
@ -141,22 +165,7 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
if (count >= room.getMaxPlayers()) throw new HiverException("房间人数已满"); if (count >= room.getMaxPlayers()) throw new HiverException("房间人数已满");
ticketService.deductTickets(userId, regionId, room.getEntryTickets(), ticketService.deductTickets(userId, regionId, room.getEntryTickets(),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_ENTRY, roomId + "_" + userId, "星球擂台入场券"); PlanetConstant.TICKET_TYPE_ADVENTURE_PK_ENTRY, roomId + "_" + userId, "星球擂台入场券");
PlanetAdventurePkPlayer player = new PlanetAdventurePkPlayer(); PlanetAdventurePkPlayer player = newPkPlayer(roomId, regionId, userId, nickname, avatar, college, room.getEntryTickets());
player.setId(genId());
player.setRoomId(roomId);
player.setRegionId(regionId);
player.setUserId(userId);
player.setNickname(nickname);
player.setAvatar(avatar);
player.setCollege(college);
player.setEntryTickets(room.getEntryTickets());
player.setStatus(PlanetConstant.ADVENTURE_PK_PLAYER_PLAYING);
player.setCleared(0);
player.setRankNo(0);
player.setRewardTickets(0);
player.setStartTime(new Date());
player.setCreateTime(new Date());
player.setUpdateTime(new Date());
playerMapper.insert(player); playerMapper.insert(player);
room.setPlayerCount(count + 1); room.setPlayerCount(count + 1);
room.setPoolTickets(nz(room.getPoolTickets()) + room.getEntryTickets()); room.setPoolTickets(nz(room.getPoolTickets()) + room.getEntryTickets());
@ -172,6 +181,9 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
Integer durationSeconds, Integer remainingSeconds, Integer remainingCards) { Integer durationSeconds, Integer remainingSeconds, Integer remainingCards) {
if (StringUtils.isEmpty(userId)) throw new HiverException("用户id不能为空"); if (StringUtils.isEmpty(userId)) throw new HiverException("用户id不能为空");
PlanetAdventurePkRoom room = mustRoom(roomId, regionId); PlanetAdventurePkRoom room = mustRoom(roomId, regionId);
if (room.getStatus() == PlanetConstant.ADVENTURE_PK_ROOM_SETTLED) {
throw new HiverException("房间已结算,无法提交成绩");
}
PlanetAdventurePkPlayer player = mustPlayer(roomId, userId); PlanetAdventurePkPlayer player = mustPlayer(roomId, userId);
if (terminal(player)) throw new HiverException("本房间成绩已提交"); if (terminal(player)) throw new HiverException("本房间成绩已提交");
player.setCleared(cleared != null && cleared == 1 ? 1 : 0); player.setCleared(cleared != null && cleared == 1 ? 1 : 0);
@ -192,6 +204,26 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
return submitRoom(userId, regionId, roomId, 0, 0, 0, remainingCards); return submitRoom(userId, regionId, roomId, 0, 0, 0, remainingCards);
} }
@Override
@Transactional(rollbackFor = Exception.class)
public int autoSettleOverdueRooms() {
Date deadline = new Date(System.currentTimeMillis() - 30L * 60 * 1000);
List<PlanetAdventurePkRoom> rooms = roomMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkRoom>()
.in(PlanetAdventurePkRoom::getStatus, PlanetConstant.ADVENTURE_PK_ROOM_WAITING, PlanetConstant.ADVENTURE_PK_ROOM_PLAYING)
.lt(PlanetAdventurePkRoom::getCreateTime, deadline));
int settled = 0;
for (PlanetAdventurePkRoom room : rooms) {
try {
if (settleOverdue(room)) {
settled++;
}
} catch (Exception ignored) {
// 单个房间异常不影响后续房间,外层任务会记录总量。
}
}
return settled;
}
@Override @Override
public PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar, public PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar,
String college, Integer durationSeconds) { String college, Integer durationSeconds) {
@ -262,16 +294,71 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
.eq(PlanetAdventureSession::getStatus, PlanetConstant.ADVENTURE_SESSION_SUBMITTED) .eq(PlanetAdventureSession::getStatus, PlanetConstant.ADVENTURE_SESSION_SUBMITTED)
.eq(PlanetAdventureSession::getCheatFlag, "N") .eq(PlanetAdventureSession::getCheatFlag, "N")
.orderByAsc(PlanetAdventureSession::getDurationSeconds) .orderByAsc(PlanetAdventureSession::getDurationSeconds)
.last("limit 3")); .last("limit 5"));
} }
private void settleIfReady(PlanetAdventurePkRoom room) { private void settleIfReady(PlanetAdventurePkRoom room) {
List<PlanetAdventurePkPlayer> players = playerMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkPlayer>() List<PlanetAdventurePkPlayer> players = playerMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkPlayer>()
.eq(PlanetAdventurePkPlayer::getRoomId, room.getId())); .eq(PlanetAdventurePkPlayer::getRoomId, room.getId()));
if (players.size() < room.getMaxPlayers()) return;
for (PlanetAdventurePkPlayer p : players) { for (PlanetAdventurePkPlayer p : players) {
if (!terminal(p)) return; if (!terminal(p)) return;
} }
settleRoom(room, players, false);
}
private boolean settleOverdue(PlanetAdventurePkRoom room) {
List<PlanetAdventurePkPlayer> players = playerMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkPlayer>()
.eq(PlanetAdventurePkPlayer::getRoomId, room.getId()));
if (players.isEmpty()) {
room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_SETTLED);
room.setSettleTime(new Date());
room.setUpdateTime(new Date());
roomMapper.updateById(room);
return true;
}
boolean noSubmitted = players.stream().noneMatch(this::terminal);
for (PlanetAdventurePkPlayer p : players) {
if (!terminal(p)) {
p.setStatus(PlanetConstant.ADVENTURE_PK_PLAYER_FAILED);
p.setCleared(0);
p.setDurationSeconds(0);
p.setRemainingSeconds(0);
p.setRemainingCards(AUTO_FAIL_REMAINING_CARDS);
p.setFinishTime(new Date());
p.setUpdateTime(new Date());
playerMapper.updateById(p);
}
}
List<PlanetAdventurePkPlayer> latestPlayers = playerMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkPlayer>()
.eq(PlanetAdventurePkPlayer::getRoomId, room.getId()));
settleRoom(room, latestPlayers, noSubmitted);
return true;
}
private void settleRoom(PlanetAdventurePkRoom room, List<PlanetAdventurePkPlayer> players, boolean refundAll) {
if (players.size() == 1 && Objects.equals(players.get(0).getUserId(), room.getOwnerUserId())) {
PlanetAdventurePkPlayer owner = players.get(0);
ticketService.addTicketsWithoutBuff(owner.getUserId(), owner.getRegionId(), nz(owner.getEntryTickets()),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REFUND, room.getId() + "_" + owner.getUserId(), "星球擂台无人参加退回");
owner.setRewardTickets(nz(owner.getEntryTickets()));
owner.setRankNo(0);
owner.setUpdateTime(new Date());
playerMapper.updateById(owner);
finishRoom(room, null);
return;
}
if (refundAll) {
for (PlanetAdventurePkPlayer p : players) {
ticketService.addTicketsWithoutBuff(p.getUserId(), p.getRegionId(), nz(p.getEntryTickets()),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REFUND, room.getId() + "_" + p.getUserId(), "星球擂台无人提交退回");
p.setRewardTickets(nz(p.getEntryTickets()));
p.setRankNo(0);
p.setUpdateTime(new Date());
playerMapper.updateById(p);
}
finishRoom(room, null);
return;
}
players.sort((a, b) -> { players.sort((a, b) -> {
boolean ac = nz(a.getCleared()) == 1; boolean ac = nz(a.getCleared()) == 1;
boolean bc = nz(b.getCleared()) == 1; boolean bc = nz(b.getCleared()) == 1;
@ -281,35 +368,59 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
if (d != 0) return d; if (d != 0) return d;
return Integer.compare(nz(b.getRemainingSeconds()), nz(a.getRemainingSeconds())); return Integer.compare(nz(b.getRemainingSeconds()), nz(a.getRemainingSeconds()));
} }
return Integer.compare(nz(a.getRemainingCards()), nz(b.getRemainingCards())); int remain = Integer.compare(nz(a.getRemainingCards()), nz(b.getRemainingCards()));
if (remain != 0) return remain;
return Integer.compare(durationForRank(a), durationForRank(b));
}); });
boolean hasClear = players.stream().anyMatch(p -> nz(p.getCleared()) == 1); boolean hasClear = players.stream().anyMatch(p -> nz(p.getCleared()) == 1);
if (!hasClear) { PlanetAdventurePkPlayer winner = players.get(0);
for (PlanetAdventurePkPlayer p : players) { ticketService.addTicketsWithoutBuff(winner.getUserId(), winner.getRegionId(), nz(room.getPoolTickets()),
ticketService.addTicketsWithoutBuff(p.getUserId(), p.getRegionId(), nz(p.getEntryTickets()), PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REWARD, room.getId(), hasClear ? "星球擂台第一名通吃奖池" : "星球擂台消除最多通吃奖池");
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REFUND, room.getId() + "_" + p.getUserId(), "星球擂台无人通关退回"); for (int i = 0; i < players.size(); i++) {
p.setRewardTickets(nz(p.getEntryTickets())); PlanetAdventurePkPlayer p = players.get(i);
p.setRankNo(0); p.setRankNo(i + 1);
playerMapper.updateById(p); p.setRewardTickets(p.getUserId().equals(winner.getUserId()) ? nz(room.getPoolTickets()) : 0);
} p.setUpdateTime(new Date());
} else { playerMapper.updateById(p);
PlanetAdventurePkPlayer winner = players.get(0);
ticketService.addTicketsWithoutBuff(winner.getUserId(), winner.getRegionId(), nz(room.getPoolTickets()),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REWARD, room.getId(), "星球擂台第一名通吃奖池");
for (int i = 0; i < players.size(); i++) {
PlanetAdventurePkPlayer p = players.get(i);
p.setRankNo(i + 1);
p.setRewardTickets(p.getUserId().equals(winner.getUserId()) ? nz(room.getPoolTickets()) : 0);
playerMapper.updateById(p);
}
room.setWinnerUserId(winner.getUserId());
} }
finishRoom(room, winner.getUserId());
}
private void finishRoom(PlanetAdventurePkRoom room, String winnerUserId) {
room.setWinnerUserId(winnerUserId);
room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_SETTLED); room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_SETTLED);
room.setSettleTime(new Date()); room.setSettleTime(new Date());
room.setUpdateTime(new Date()); room.setUpdateTime(new Date());
roomMapper.updateById(room); roomMapper.updateById(room);
} }
private PlanetAdventurePkPlayer newPkPlayer(String roomId, String regionId, String userId, String nickname,
String avatar, String college, Integer entryTickets) {
PlanetAdventurePkPlayer player = new PlanetAdventurePkPlayer();
player.setId(genId());
player.setRoomId(roomId);
player.setRegionId(regionId);
player.setUserId(userId);
player.setNickname(nickname);
player.setAvatar(avatar);
player.setCollege(college);
player.setEntryTickets(entryTickets);
player.setStatus(PlanetConstant.ADVENTURE_PK_PLAYER_PLAYING);
player.setCleared(0);
player.setRankNo(0);
player.setRewardTickets(0);
player.setStartTime(new Date());
player.setCreateTime(new Date());
player.setUpdateTime(new Date());
return player;
}
private int durationForRank(PlanetAdventurePkPlayer player) {
if (nz(player.getDurationSeconds()) > 0) return nz(player.getDurationSeconds());
if (nz(player.getRemainingSeconds()) > 0) return Math.max(0, 180 - nz(player.getRemainingSeconds()));
return Integer.MAX_VALUE;
}
private PlanetAdventurePkPlayVo playVo(PlanetAdventurePkRoom room, PlanetAdventurePkPlayer player) { private PlanetAdventurePkPlayVo playVo(PlanetAdventurePkRoom room, PlanetAdventurePkPlayer player) {
PlanetAdventurePkPlayVo vo = new PlanetAdventurePkPlayVo(); PlanetAdventurePkPlayVo vo = new PlanetAdventurePkPlayVo();
vo.setMode("pk"); vo.setMode("pk");

12
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetBoxServiceImpl.java

@ -6,7 +6,6 @@ import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper; import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import cc.hiver.mall.planet.pojo.PlanetBoxResultVo; import cc.hiver.mall.planet.pojo.PlanetBoxResultVo;
import cc.hiver.mall.planet.service.PlanetBoxService; import cc.hiver.mall.planet.service.PlanetBoxService;
import cc.hiver.mall.planet.service.PlanetBuffService;
import cc.hiver.mall.planet.service.PlanetNewsService; import cc.hiver.mall.planet.service.PlanetNewsService;
import cc.hiver.mall.planet.service.PlanetTicketService; import cc.hiver.mall.planet.service.PlanetTicketService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -31,9 +30,6 @@ public class PlanetBoxServiceImpl implements PlanetBoxService {
@Autowired @Autowired
private PlanetTicketMapper ticketMapper; private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetBuffService buffService;
@Autowired @Autowired
private PlanetNewsService newsService; private PlanetNewsService newsService;
@ -83,14 +79,6 @@ public class PlanetBoxServiceImpl implements PlanetBoxService {
vo.setMessage(name); vo.setMessage(name);
} }
private void grantBuff(String userId, String regionId, String type, String name, PlanetBoxResultVo vo) {
buffService.grantBuff(userId, regionId, type, "box");
vo.setRewardType("buff");
vo.setBuffType(type);
vo.setRewardName("获得「" + name + "」增益");
vo.setMessage("幸运宝箱开出「" + name + "」增益");
}
private String safeName(String name) { private String safeName(String name) {
return name == null || name.isEmpty() ? "神秘同学" : name; return name == null || name.isEmpty() ? "神秘同学" : name;
} }

149
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetDrawServiceImpl.java

@ -9,7 +9,10 @@ import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.*; import cc.hiver.mall.planet.entity.*;
import cc.hiver.mall.planet.mapper.*; import cc.hiver.mall.planet.mapper.*;
import cc.hiver.mall.planet.pojo.PlanetDailyLoopVo; import cc.hiver.mall.planet.pojo.PlanetDailyLoopVo;
import cc.hiver.mall.planet.service.*; import cc.hiver.mall.planet.service.PlanetDrawService;
import cc.hiver.mall.planet.service.PlanetNewsService;
import cc.hiver.mall.planet.service.PlanetTaskService;
import cc.hiver.mall.planet.service.PlanetTicketService;
import cc.hiver.mall.service.mybatis.DealingsRecordService; import cc.hiver.mall.service.mybatis.DealingsRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -35,6 +38,8 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
/** 每日开奖时刻(24小时制),到点由定时任务自动开奖,每日一抽 */ /** 每日开奖时刻(24小时制),到点由定时任务自动开奖,每日一抽 */
private static final int DAILY_DRAW_HOUR = 22; private static final int DAILY_DRAW_HOUR = 22;
/** 同一用户中奖冷却天数,让更多同学有机会中奖 */
private static final int WIN_COOLDOWN_DAYS = 7;
@Autowired @Autowired
private PlanetPoolMapper poolMapper; private PlanetPoolMapper poolMapper;
@ -60,9 +65,6 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
@Autowired @Autowired
private PlanetDrawWinnerMapper drawWinnerMapper; private PlanetDrawWinnerMapper drawWinnerMapper;
@Autowired
private PlanetBuffService buffService;
@Autowired @Autowired
private PlanetNewsService newsService; private PlanetNewsService newsService;
@ -132,7 +134,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
join.setCreateTime(new Date()); join.setCreateTime(new Date());
} }
join.setTickets((join.getTickets() == null ? 0 : join.getTickets()) + tickets); join.setTickets((join.getTickets() == null ? 0 : join.getTickets()) + tickets);
join.setWeightTickets(join.getTickets()); join.setWeightTickets(calcWeightTickets(join.getTickets()));
join.setUpdateTime(new Date()); join.setUpdateTime(new Date());
if (poolTicketMapper.selectById(join.getId()) == null) { if (poolTicketMapper.selectById(join.getId()) == null) {
poolTicketMapper.insert(join); poolTicketMapper.insert(join);
@ -155,10 +157,12 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
vo.setMyPoolTickets(myTickets); vo.setMyPoolTickets(myTickets);
vo.setPoolTicketTotal(total); vo.setPoolTicketTotal(total);
vo.setPoolJoinCount(countPoolJoin(pool.getId())); vo.setPoolJoinCount(countPoolJoin(pool.getId()));
vo.setMyProbability(probability(myTickets, total)); final Integer totalWeight = sumPoolWeightTickets(pool.getId());
final int myWeight = myJoin == null || myJoin.getWeightTickets() == null ? calcWeightTickets(myTickets) : myJoin.getWeightTickets();
vo.setMyProbability(probability(myWeight, totalWeight));
final int suggested = myTickets <= 0 ? 3 : Math.min(10, Math.max(1, total / 20)); final int suggested = myTickets <= 0 ? 3 : Math.min(10, Math.max(1, total / 20));
vo.setSuggestedAddTickets(suggested); vo.setSuggestedAddTickets(suggested);
vo.setSuggestedProbability(probability(myTickets + suggested, total + suggested)); vo.setSuggestedProbability(probability(calcWeightTickets(myTickets + suggested), totalWeight - myWeight + calcWeightTickets(myTickets + suggested)));
vo.setMinutesToDraw(pool.getDrawTime() == null ? 0 : Math.max(0, (int) ((pool.getDrawTime().getTime() - System.currentTimeMillis()) / 60000L))); vo.setMinutesToDraw(pool.getDrawTime() == null ? 0 : Math.max(0, (int) ((pool.getDrawTime().getTime() - System.currentTimeMillis()) / 60000L)));
vo.setSignedToday(taskService.signedToday(userId, regionId)); vo.setSignedToday(taskService.signedToday(userId, regionId));
vo.setBoxAvailable(boxAvailableQuick(userId, regionId)); vo.setBoxAvailable(boxAvailableQuick(userId, regionId));
@ -178,7 +182,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
pool.setRegionId(regionId); pool.setRegionId(regionId);
pool.setPeriodNo(genPeriodNo()); pool.setPeriodNo(genPeriodNo());
pool.setTitle("白嫖星球·本期瓜分"); pool.setTitle("白嫖星球·本期瓜分");
pool.setPoolAmount(new BigDecimal("88.88")); pool.setPoolAmount(BigDecimal.ZERO);
pool.setDrawTime(nextDrawTime(now)); pool.setDrawTime(nextDrawTime(now));
pool.setJoinCount(0); pool.setJoinCount(0);
pool.setTicketTotal(0); pool.setTicketTotal(0);
@ -190,6 +194,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
poolMapper.insert(pool); poolMapper.insert(pool);
// 默认奖项 // 默认奖项
createDefaultRewards(pool); createDefaultRewards(pool);
refreshPoolRewardAmount(pool);
return pool; return pool;
} }
@ -237,19 +242,17 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
final LambdaQueryWrapper<PlanetReward> rq = new LambdaQueryWrapper<>(); final LambdaQueryWrapper<PlanetReward> rq = new LambdaQueryWrapper<>();
rq.eq(PlanetReward::getPoolId, poolId).orderByAsc(PlanetReward::getSort); rq.eq(PlanetReward::getPoolId, poolId).orderByAsc(PlanetReward::getSort);
final List<PlanetReward> rewards = rewardMapper.selectList(rq); final List<PlanetReward> rewards = rewardMapper.selectList(rq);
final BigDecimal poolAmount = sumRewardAmount(rewards);
// 批量查询所有参与者的幸运系数,一次查库,避免循环逐个查询 // 构建加权候选:投入券先按递减规则折算权重,防止大户无限堆券垄断。
final Set<String> userIds = joins.stream().map(PlanetPoolTicket::getUserId).collect(Collectors.toCollection(LinkedHashSet::new)); final List<Candidate> poolCandidates = new ArrayList<>();
final Map<String, Double> luckyMap = buffService.luckyWeightFactors(userIds);
// 构建加权候选(权重= 券数量 * 幸运系数)
final List<Candidate> poutPool = new ArrayList<>();
int ticketTotal = 0; int ticketTotal = 0;
for (PlanetPoolTicket t : joins) { for (PlanetPoolTicket t : joins) {
final double factor = luckyMap.getOrDefault(t.getUserId(), 1.0); final int tickets = t.getTickets() == null ? 0 : t.getTickets();
final double weight = t.getTickets() * factor; final int weightTickets = t.getWeightTickets() == null ? calcWeightTickets(tickets) : t.getWeightTickets();
poutPool.add(new Candidate(t, weight)); t.setWeightTickets(weightTickets);
ticketTotal += t.getTickets(); poolCandidates.add(new Candidate(t, weightTickets));
ticketTotal += tickets;
} }
final Date now = new Date(); final Date now = new Date();
@ -259,21 +262,24 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
record.setPoolId(pool.getId()); record.setPoolId(pool.getId());
record.setRegionId(pool.getRegionId()); record.setRegionId(pool.getRegionId());
record.setPeriodNo(pool.getPeriodNo()); record.setPeriodNo(pool.getPeriodNo());
record.setPoolAmount(pool.getPoolAmount()); record.setPoolAmount(poolAmount);
record.setJoinCount(joins.size()); record.setJoinCount(joins.size());
record.setTicketTotal(ticketTotal); record.setTicketTotal(ticketTotal);
record.setStatus(1); record.setStatus(1);
record.setDrawTime(now); record.setDrawTime(now);
record.setCreateTime(now); record.setCreateTime(now);
final Set<String> cooldownUsers = recentWinnerUserIds(pool.getRegionId(), now);
boolean useCooldown = hasCandidate(poolCandidates, cooldownUsers);
int winnerCount = 0; int winnerCount = 0;
for (PlanetReward reward : rewards) { for (PlanetReward reward : rewards) {
final int quota = reward.getQuota() == null ? 0 : reward.getQuota(); final int quota = reward.getQuota() == null ? 0 : reward.getQuota();
for (int i = 0; i < quota; i++) { for (int i = 0; i < quota; i++) {
if (poutPoolEmpty(poutPool)) { List<Candidate> usable = usableCandidates(poolCandidates, useCooldown ? cooldownUsers : Collections.emptySet());
if (usable.isEmpty()) {
break; break;
} }
final Candidate winner = pickWeighted(poutPoolUsable(poutPool)); final Candidate winner = pickWeighted(usable);
if (winner == null) { if (winner == null) {
break; break;
} }
@ -290,6 +296,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
pool.setJoinCount(joins.size()); pool.setJoinCount(joins.size());
pool.setTicketTotal(ticketTotal); pool.setTicketTotal(ticketTotal);
pool.setWinnerCount(winnerCount); pool.setWinnerCount(winnerCount);
pool.setPoolAmount(poolAmount);
pool.setUpdateTime(now); pool.setUpdateTime(now);
poolMapper.updateById(pool); poolMapper.updateById(pool);
@ -327,6 +334,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
for (PlanetReward r : rewardMapper.selectList(rq)) { for (PlanetReward r : rewardMapper.selectList(rq)) {
addReward(pool, r.getLevel(), r.getLevelName(), r.getAmount(), r.getQuota() == null ? 0 : r.getQuota(), r.getSort() == null ? 0 : r.getSort()); addReward(pool, r.getLevel(), r.getLevelName(), r.getAmount(), r.getQuota() == null ? 0 : r.getQuota(), r.getSort() == null ? 0 : r.getSort());
} }
refreshPoolRewardAmount(pool);
} }
@Override @Override
@ -371,6 +379,24 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
return drawWinnerMapper.selectList(qw); return drawWinnerMapper.selectList(qw);
} }
@Override
public List<Map<String, Object>> recentDrawResults(String regionId, int limit) {
requireRegion(regionId);
final int size = limit <= 0 ? 10 : Math.min(limit, 20);
final List<PlanetDrawRecord> records = drawRecordMapper.selectList(new LambdaQueryWrapper<PlanetDrawRecord>()
.eq(PlanetDrawRecord::getRegionId, regionId)
.orderByDesc(PlanetDrawRecord::getDrawTime)
.last("limit " + size));
final List<Map<String, Object>> result = new ArrayList<>();
for (PlanetDrawRecord record : records) {
final Map<String, Object> item = new HashMap<>(4);
item.put("record", record);
item.put("winners", winnersOfDraw(record.getId()));
result.add(item);
}
return result;
}
@Override @Override
public List<PlanetDrawWinner> myWinning(String userId, String regionId) { public List<PlanetDrawWinner> myWinning(String userId, String regionId) {
requireRegion(regionId); requireRegion(regionId);
@ -482,25 +508,20 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
drawWinnerMapper.insert(winner); drawWinnerMapper.insert(winner);
} }
private boolean poutPoolEmpty(List<Candidate> pool) { private List<Candidate> usableCandidates(List<Candidate> pool, Set<String> cooldownUsers) {
for (Candidate c : pool) {
if (!c.win) {
return false;
}
}
return true;
}
private List<Candidate> poutPoolUsable(List<Candidate> pool) {
final List<Candidate> usable = new ArrayList<>(); final List<Candidate> usable = new ArrayList<>();
for (Candidate c : pool) { for (Candidate c : pool) {
if (!c.win) { if (!c.win && (cooldownUsers == null || !cooldownUsers.contains(c.ticket.getUserId()))) {
usable.add(c); usable.add(c);
} }
} }
return usable; return usable;
} }
private boolean hasCandidate(List<Candidate> pool, Set<String> cooldownUsers) {
return !usableCandidates(pool, cooldownUsers).isEmpty();
}
private Candidate pickWeighted(List<Candidate> usable) { private Candidate pickWeighted(List<Candidate> usable) {
if (usable.isEmpty()) { if (usable.isEmpty()) {
return null; return null;
@ -572,6 +593,16 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
return total; return total;
} }
private int sumPoolWeightTickets(String poolId) {
final List<PlanetPoolTicket> joins = poolTicketMapper.selectList(new LambdaQueryWrapper<PlanetPoolTicket>()
.eq(PlanetPoolTicket::getPoolId, poolId));
int total = 0;
for (PlanetPoolTicket join : joins) {
total += join.getWeightTickets() == null ? calcWeightTickets(join.getTickets() == null ? 0 : join.getTickets()) : join.getWeightTickets();
}
return total;
}
private int countPoolJoin(String poolId) { private int countPoolJoin(String poolId) {
return poolTicketMapper.selectCount(new LambdaQueryWrapper<PlanetPoolTicket>() return poolTicketMapper.selectCount(new LambdaQueryWrapper<PlanetPoolTicket>()
.eq(PlanetPoolTicket::getPoolId, poolId) .eq(PlanetPoolTicket::getPoolId, poolId)
@ -586,6 +617,60 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
.divide(BigDecimal.valueOf(total), 2, BigDecimal.ROUND_HALF_UP); .divide(BigDecimal.valueOf(total), 2, BigDecimal.ROUND_HALF_UP);
} }
public static int calcWeightTickets(int tickets) {
if (tickets <= 0) {
return 0;
}
BigDecimal weight = BigDecimal.ZERO;
int remain = tickets;
int first = Math.min(remain, 3);
weight = weight.add(BigDecimal.valueOf(first));
remain -= first;
if (remain > 0) {
int second = Math.min(remain, 7);
weight = weight.add(BigDecimal.valueOf(second).multiply(new BigDecimal("0.8")));
remain -= second;
}
if (remain > 0) {
int third = Math.min(remain, 10);
weight = weight.add(BigDecimal.valueOf(third).multiply(new BigDecimal("0.6")));
remain -= third;
}
if (remain > 0) {
weight = weight.add(BigDecimal.valueOf(remain).multiply(new BigDecimal("0.4")));
}
return weight.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
}
private Set<String> recentWinnerUserIds(String regionId, Date now) {
final Calendar c = Calendar.getInstance();
c.setTime(now);
c.add(Calendar.DAY_OF_MONTH, -WIN_COOLDOWN_DAYS);
final List<PlanetDrawWinner> winners = drawWinnerMapper.selectList(new LambdaQueryWrapper<PlanetDrawWinner>()
.select(PlanetDrawWinner::getUserId)
.eq(PlanetDrawWinner::getRegionId, regionId)
.ge(PlanetDrawWinner::getCreateTime, c.getTime()));
return winners.stream().map(PlanetDrawWinner::getUserId).filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
}
private BigDecimal sumRewardAmount(List<PlanetReward> rewards) {
BigDecimal total = BigDecimal.ZERO;
for (PlanetReward reward : rewards) {
final BigDecimal amount = reward.getAmount() == null ? BigDecimal.ZERO : reward.getAmount();
final int quota = reward.getQuota() == null ? 0 : reward.getQuota();
total = total.add(amount.multiply(BigDecimal.valueOf(quota)));
}
return total;
}
private void refreshPoolRewardAmount(PlanetPool pool) {
final List<PlanetReward> rewards = rewardMapper.selectList(new LambdaQueryWrapper<PlanetReward>()
.eq(PlanetReward::getPoolId, pool.getId()));
pool.setPoolAmount(sumRewardAmount(rewards));
pool.setUpdateTime(new Date());
poolMapper.updateById(pool);
}
private int todayCollectedTickets(String userId, String regionId) { private int todayCollectedTickets(String userId, String regionId) {
final Calendar c = Calendar.getInstance(); final Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetOperateServiceImpl.java

@ -103,6 +103,7 @@ public class PlanetOperateServiceImpl implements PlanetOperateService {
data.put("state", state); data.put("state", state);
data.put("treeConfigs", treeConfigs(regionId)); data.put("treeConfigs", treeConfigs(regionId));
data.put("treeOrders", treeOrders(userId, regionId)); data.put("treeOrders", treeOrders(userId, regionId));
data.put("nextTowerConfig", getTowerLevel(regionId, nullToZero(state.getTowerLevel()) + 1));
data.put("landmarks", landmarkList(regionId)); data.put("landmarks", landmarkList(regionId));
data.put("staminaItems", staminaItems(regionId)); data.put("staminaItems", staminaItems(regionId));
return data; return data;

55
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetRankServiceImpl.java

@ -3,9 +3,10 @@ package cc.hiver.mall.planet.service.impl;
import cc.hiver.core.common.redis.RedisTemplateHelper; import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.mall.planet.constant.PlanetConstant; import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetTicket; import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.entity.PlanetUserState;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper; import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import cc.hiver.mall.planet.mapper.PlanetUserStateMapper;
import cc.hiver.mall.planet.pojo.PlanetRankItemVo; import cc.hiver.mall.planet.pojo.PlanetRankItemVo;
import cc.hiver.mall.planet.service.PlanetBuffService;
import cc.hiver.mall.planet.service.PlanetRankService; import cc.hiver.mall.planet.service.PlanetRankService;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -37,7 +38,7 @@ public class PlanetRankServiceImpl implements PlanetRankService {
private PlanetTicketMapper ticketMapper; private PlanetTicketMapper ticketMapper;
@Autowired @Autowired
private PlanetBuffService buffService; private PlanetUserStateMapper userStateMapper;
@Autowired @Autowired
private RedisTemplateHelper redisTemplateHelper; private RedisTemplateHelper redisTemplateHelper;
@ -77,28 +78,27 @@ public class PlanetRankServiceImpl implements PlanetRankService {
return page; return page;
} }
final Set<String> userIds = tickets.stream().map(PlanetTicket::getUserId).collect(Collectors.toCollection(LinkedHashSet::new)); final Set<String> userIds = tickets.stream().map(PlanetTicket::getUserId).collect(Collectors.toCollection(LinkedHashSet::new));
final Map<String, Set<String>> buffMap = buffService.activeBuffTypes(userIds); final Set<String> towerUserIds = towerUserIds(regionId, userIds);
final List<PlanetRankItemVo> result = new ArrayList<>(); final List<PlanetRankItemVo> result = new ArrayList<>();
int offset = (current - 1) * size; int offset = (current - 1) * size;
for (int i = 0; i < tickets.size(); i++) { for (int i = 0; i < tickets.size(); i++) {
PlanetTicket t = tickets.get(i); PlanetTicket t = tickets.get(i);
final Set<String> buffs = buffMap.get(t.getUserId());
final boolean stealth = buffs != null && buffs.contains(PlanetConstant.BUFF_STEALTH);
int rankNo = offset + i + 1; int rankNo = offset + i + 1;
final PlanetRankItemVo vo = new PlanetRankItemVo(); final PlanetRankItemVo vo = new PlanetRankItemVo();
vo.setRankNo(rankNo); vo.setRankNo(rankNo);
vo.setUserId(t.getUserId()); vo.setUserId(t.getUserId());
vo.setNickname(stealth ? "隐身侠" : t.getNickname()); vo.setNickname(t.getNickname());
vo.setAvatar(stealth ? null : t.getAvatar()); vo.setAvatar(t.getAvatar());
vo.setCollege(stealth ? null : t.getCollege()); vo.setCollege(t.getCollege());
vo.setTicketCount(t.getTicketCount()); vo.setTicketCount(t.getTicketCount());
vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount())); vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount()));
vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount())); vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount()));
vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays()); vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays());
vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo)); vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo));
vo.setShielded(buffs != null && buffs.contains(PlanetConstant.BUFF_SHIELD)); vo.setShielded(false);
vo.setStealth(stealth); vo.setHasTower(towerUserIds.contains(t.getUserId()));
vo.setStealth(false);
vo.setSelf(t.getUserId() != null && t.getUserId().equals(currentUserId)); vo.setSelf(t.getUserId() != null && t.getUserId().equals(currentUserId));
result.add(vo); result.add(vo);
} }
@ -107,10 +107,9 @@ public class PlanetRankServiceImpl implements PlanetRankService {
} }
/** /**
* 从数据库构建基础榜单先批量取候选券记录再一次性批量查 BUFF内存组装避免循环查库 * 从数据库构建基础榜单批量取券记录后一次性补防御塔状态避免循环查库
*/ */
private List<PlanetRankItemVo> buildRankFromDb(String regionId, int topN) { private List<PlanetRankItemVo> buildRankFromDb(String regionId, int topN) {
// 多取一些以便过滤隐身用户后仍能凑满topN
final LambdaQueryWrapper<PlanetTicket> qw = new LambdaQueryWrapper<>(); final LambdaQueryWrapper<PlanetTicket> qw = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(regionId)) { if (StringUtils.isNotEmpty(regionId)) {
qw.eq(PlanetTicket::getRegionId, regionId); qw.eq(PlanetTicket::getRegionId, regionId);
@ -123,15 +122,12 @@ public class PlanetRankServiceImpl implements PlanetRankService {
if (tickets.isEmpty()) { if (tickets.isEmpty()) {
return new ArrayList<>(); return new ArrayList<>();
} }
// 批量查询候选用户的生效 BUFF 类型,一次查库
final Set<String> userIds = tickets.stream().map(PlanetTicket::getUserId).collect(Collectors.toCollection(LinkedHashSet::new)); final Set<String> userIds = tickets.stream().map(PlanetTicket::getUserId).collect(Collectors.toCollection(LinkedHashSet::new));
final Map<String, Set<String>> buffMap = buffService.activeBuffTypes(userIds); final Set<String> towerUserIds = towerUserIds(regionId, userIds);
final List<PlanetRankItemVo> result = new ArrayList<>(); final List<PlanetRankItemVo> result = new ArrayList<>();
int rankNo = 0; int rankNo = 0;
for (PlanetTicket t : tickets) { for (PlanetTicket t : tickets) {
final Set<String> buffs = buffMap.get(t.getUserId());
final boolean stealth = buffs != null && buffs.contains(PlanetConstant.BUFF_STEALTH);
rankNo++; rankNo++;
if (rankNo > topN) { if (rankNo > topN) {
break; break;
@ -139,22 +135,39 @@ public class PlanetRankServiceImpl implements PlanetRankService {
final PlanetRankItemVo vo = new PlanetRankItemVo(); final PlanetRankItemVo vo = new PlanetRankItemVo();
vo.setRankNo(rankNo); vo.setRankNo(rankNo);
vo.setUserId(t.getUserId()); vo.setUserId(t.getUserId());
vo.setNickname(stealth ? "隐身侠" : t.getNickname()); vo.setNickname(t.getNickname());
vo.setAvatar(stealth ? null : t.getAvatar()); vo.setAvatar(t.getAvatar());
vo.setCollege(stealth ? null : t.getCollege()); vo.setCollege(t.getCollege());
vo.setTicketCount(t.getTicketCount()); vo.setTicketCount(t.getTicketCount());
vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount())); vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount()));
vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount())); vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount()));
vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays()); vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays());
vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo)); vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo));
vo.setShielded(buffs != null && buffs.contains(PlanetConstant.BUFF_SHIELD)); vo.setShielded(false);
vo.setStealth(stealth); vo.setHasTower(towerUserIds.contains(t.getUserId()));
vo.setStealth(false);
vo.setSelf(false); vo.setSelf(false);
result.add(vo); result.add(vo);
} }
return result; return result;
} }
private Set<String> towerUserIds(String regionId, Set<String> userIds) {
if (userIds == null || userIds.isEmpty()) {
return Collections.emptySet();
}
final LambdaQueryWrapper<PlanetUserState> qw = new LambdaQueryWrapper<>();
qw.select(PlanetUserState::getUserId)
.in(PlanetUserState::getUserId, userIds)
.gt(PlanetUserState::getTowerLevel, 0);
if (StringUtils.isNotEmpty(regionId)) {
qw.eq(PlanetUserState::getRegionId, regionId);
}
return userStateMapper.selectList(qw).stream()
.map(PlanetUserState::getUserId)
.collect(Collectors.toSet());
}
private List<PlanetRankItemVo> readCache(String regionId, int topN) { private List<PlanetRankItemVo> readCache(String regionId, int topN) {
try { try {
final String json = redisTemplateHelper.get(cacheKey(regionId, topN)); final String json = redisTemplateHelper.get(cacheKey(regionId, topN));

142
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetServiceImpl.java

@ -1,18 +1,23 @@
package cc.hiver.mall.planet.service.impl; package cc.hiver.mall.planet.service.impl;
import cc.hiver.mall.planet.constant.PlanetConstant; import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetPool; import cc.hiver.mall.planet.entity.*;
import cc.hiver.mall.planet.entity.PlanetTicket; import cc.hiver.mall.planet.mapper.PlanetPoolTicketMapper;
import cc.hiver.mall.planet.mapper.PlanetRewardMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketLogMapper;
import cc.hiver.mall.planet.pojo.PlanetDailyLoopVo;
import cc.hiver.mall.planet.pojo.PlanetHomeVo; import cc.hiver.mall.planet.pojo.PlanetHomeVo;
import cc.hiver.mall.planet.pojo.PlanetQuery; import cc.hiver.mall.planet.pojo.PlanetQuery;
import cc.hiver.mall.planet.pojo.PlanetRankItemVo;
import cc.hiver.mall.planet.service.*; import cc.hiver.mall.planet.service.*;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List;
/** /**
* 白嫖星球-首页聚合服务实现 * 白嫖星球-首页聚合服务实现
@ -31,9 +36,6 @@ public class PlanetServiceImpl implements PlanetService {
@Autowired @Autowired
private PlanetTaskService taskService; private PlanetTaskService taskService;
@Autowired
private PlanetBuffService buffService;
@Autowired @Autowired
private PlanetBoxService boxService; private PlanetBoxService boxService;
@ -49,6 +51,15 @@ public class PlanetServiceImpl implements PlanetService {
@Autowired @Autowired
private PlanetOperateService operateService; private PlanetOperateService operateService;
@Autowired
private PlanetPoolTicketMapper poolTicketMapper;
@Autowired
private PlanetTicketLogMapper ticketLogMapper;
@Autowired
private PlanetRewardMapper rewardMapper;
@Override @Override
public PlanetHomeVo home(PlanetQuery query) { public PlanetHomeVo home(PlanetQuery query) {
final String userId = query.getUserId(); final String userId = query.getUserId();
@ -70,6 +81,7 @@ public class PlanetServiceImpl implements PlanetService {
vo.setCountdownMillis(0L); vo.setCountdownMillis(0L);
} }
vo.setJoinCount(pool.getJoinCount() == null ? 0 : pool.getJoinCount()); vo.setJoinCount(pool.getJoinCount() == null ? 0 : pool.getJoinCount());
vo.setRewardList(rewardsOfPool(pool.getId()));
// 我的星球中心 // 我的星球中心
vo.setMyTicketCount(ticket.getTicketCount() == null ? 0 : ticket.getTicketCount()); vo.setMyTicketCount(ticket.getTicketCount() == null ? 0 : ticket.getTicketCount());
@ -81,32 +93,104 @@ public class PlanetServiceImpl implements PlanetService {
vo.setRemainHunt(huntService.remainHunt(userId)); vo.setRemainHunt(huntService.remainHunt(userId));
vo.setLevel(PlanetConstant.dangerLevel(vo.getMyTicketCount())); vo.setLevel(PlanetConstant.dangerLevel(vo.getMyTicketCount()));
vo.setMyRankNo(rankService.userRankNo(regionId, userId)); vo.setMyRankNo(rankService.userRankNo(regionId, userId));
vo.setDailyLoop(lightDailyLoop(userId, regionId, pool));
vo.setUnreadWinning(drawService.unreadWinning(userId, regionId));
return vo;
}
// 我生效的BUFF @Override
/*final List<PlanetBuffVo> myBuffs = new ArrayList<>(); public PlanetHomeVo supply(PlanetQuery query) {
for (PlanetBuffRecord r : buffService.activeBuffs(userId)) { final String userId = query.getUserId();
final PlanetBuffVo bv = new PlanetBuffVo(); final String regionId = query.getRegionId();
bv.setId(r.getBuffId()); final PlanetHomeVo vo = new PlanetHomeVo();
bv.setType(r.getType()); final PlanetTicket ticket = ticketService.getOrCreate(userId, regionId,
bv.setEffectValue(r.getEffectValue()); query.getNickname(), query.getAvatar(), query.getCollege());
bv.setActive(true); vo.setMyTicketCount(ticket.getTicketCount() == null ? 0 : ticket.getTicketCount());
bv.setActiveEndTime(r.getEndTime());
myBuffs.add(bv);
}
vo.setMyBuffs(myBuffs);*/
// 各板块
vo.setTasks(taskService.listTasks(userId, regionId)); vo.setTasks(taskService.listTasks(userId, regionId));
final Page<PlanetRankItemVo> rankPage = rankService.rankPage(regionId, query.getPageNumber(), query.getPageSize(), userId);
vo.setRankList(rankPage.getRecords());
vo.setRankTotal(rankPage.getTotal());
vo.setRankTotalPages(rankPage.getPages());
vo.setRankPageNumber(rankPage.getCurrent());
vo.setBuffShop(buffService.shopList(userId, regionId));
vo.setNewsList(newsService.latest(regionId, 10)); vo.setNewsList(newsService.latest(regionId, 10));
vo.setOperate(operateService.overview(userId, regionId)); vo.setOperate(operateService.overview(userId, regionId));
vo.setDailyLoop(drawService.dailyLoop(userId, regionId));
vo.setUnreadWinning(drawService.unreadWinning(userId, regionId));
return vo; return vo;
} }
private PlanetDailyLoopVo lightDailyLoop(String userId, String regionId, PlanetPool pool) {
final PlanetDailyLoopVo vo = new PlanetDailyLoopVo();
final PlanetPoolTicket myJoin = poolTicketMapper.selectOne(new LambdaQueryWrapper<PlanetPoolTicket>()
.eq(PlanetPoolTicket::getPoolId, pool.getId())
.eq(PlanetPoolTicket::getUserId, userId)
.last("limit 1"));
final Integer total = sumPoolTickets(pool.getId());
final Integer weightTotal = sumPoolWeightTickets(pool.getId());
final int myTickets = myJoin == null || myJoin.getTickets() == null ? 0 : myJoin.getTickets();
final int myWeight = myJoin == null || myJoin.getWeightTickets() == null ? calcWeightTickets(myTickets) : myJoin.getWeightTickets();
vo.setMyPoolTickets(myTickets);
vo.setMyWeightTickets(myWeight);
vo.setPoolTicketTotal(total);
vo.setPoolWeightTotal(weightTotal);
vo.setMyProbability(probability(myWeight, weightTotal));
final int suggested = myTickets <= 0 ? 3 : Math.min(10, Math.max(1, total / 20));
vo.setSuggestedAddTickets(suggested);
vo.setSuggestedProbability(probability(calcWeightTickets(myTickets + suggested), weightTotal - myWeight + calcWeightTickets(myTickets + suggested)));
vo.setTodayCollectedTickets(todayCollectedTickets(userId, regionId));
return vo;
}
private Integer sumPoolTickets(String poolId) {
List<PlanetPoolTicket> joins = poolTicketMapper.selectList(new LambdaQueryWrapper<PlanetPoolTicket>()
.select(PlanetPoolTicket::getTickets)
.eq(PlanetPoolTicket::getPoolId, poolId));
int total = 0;
for (PlanetPoolTicket join : joins) {
total += join.getTickets() == null ? 0 : join.getTickets();
}
return total;
}
private Integer sumPoolWeightTickets(String poolId) {
List<PlanetPoolTicket> joins = poolTicketMapper.selectList(new LambdaQueryWrapper<PlanetPoolTicket>()
.select(PlanetPoolTicket::getTickets, PlanetPoolTicket::getWeightTickets)
.eq(PlanetPoolTicket::getPoolId, poolId));
int total = 0;
for (PlanetPoolTicket join : joins) {
total += join.getWeightTickets() == null ? calcWeightTickets(join.getTickets() == null ? 0 : join.getTickets()) : join.getWeightTickets();
}
return total;
}
private Integer todayCollectedTickets(String userId, String regionId) {
final Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
final List<PlanetTicketLog> logs = ticketLogMapper.selectList(new LambdaQueryWrapper<PlanetTicketLog>()
.select(PlanetTicketLog::getChangeCount)
.eq(PlanetTicketLog::getUserId, userId)
.eq(PlanetTicketLog::getRegionId, regionId)
.gt(PlanetTicketLog::getChangeCount, 0)
.ge(PlanetTicketLog::getCreateTime, c.getTime()));
int total = 0;
for (PlanetTicketLog log : logs) {
total += log.getChangeCount() == null ? 0 : log.getChangeCount();
}
return total;
}
private BigDecimal probability(int mine, int total) {
if (mine <= 0 || total <= 0) {
return BigDecimal.ZERO;
}
return BigDecimal.valueOf(mine)
.multiply(BigDecimal.valueOf(100))
.divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP);
}
private Integer calcWeightTickets(int tickets) {
return PlanetDrawServiceImpl.calcWeightTickets(tickets);
}
private List<PlanetReward> rewardsOfPool(String poolId) {
return rewardMapper.selectList(new LambdaQueryWrapper<PlanetReward>()
.eq(PlanetReward::getPoolId, poolId)
.orderByAsc(PlanetReward::getSort));
}
} }

28
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetTicketServiceImpl.java

@ -4,10 +4,8 @@ import cc.hiver.core.common.exception.HiverException;
import cc.hiver.core.entity.User; import cc.hiver.core.entity.User;
import cc.hiver.core.service.UserService; import cc.hiver.core.service.UserService;
import cc.hiver.mall.planet.constant.PlanetConstant; import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetBuffRecord;
import cc.hiver.mall.planet.entity.PlanetTicket; import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.entity.PlanetTicketLog; import cc.hiver.mall.planet.entity.PlanetTicketLog;
import cc.hiver.mall.planet.mapper.PlanetBuffRecordMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketLogMapper; import cc.hiver.mall.planet.mapper.PlanetTicketLogMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper; import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import cc.hiver.mall.planet.service.PlanetTicketService; import cc.hiver.mall.planet.service.PlanetTicketService;
@ -18,9 +16,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
@ -38,9 +34,6 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
@Autowired @Autowired
private PlanetTicketLogMapper ticketLogMapper; private PlanetTicketLogMapper ticketLogMapper;
@Autowired
private PlanetBuffRecordMapper buffRecordMapper;
@Autowired @Autowired
private UserService userService; private UserService userService;
@ -140,12 +133,7 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
} }
} }
final PlanetTicket ticket = getOrCreate(userId, regionId, null, null, null); final PlanetTicket ticket = getOrCreate(userId, regionId, null, null, null);
// 双倍BUFF加成
int finalCount = baseCount; int finalCount = baseCount;
final BigDecimal multiplier = getActiveDoubleMultiplier(userId);
if (multiplier != null && multiplier.compareTo(BigDecimal.ONE) > 0) {
finalCount = multiplier.multiply(BigDecimal.valueOf(baseCount)).intValue();
}
ticket.setTicketCount(ticket.getTicketCount() + finalCount); ticket.setTicketCount(ticket.getTicketCount() + finalCount);
ticket.setTotalTicket(ticket.getTotalTicket() + finalCount); ticket.setTotalTicket(ticket.getTotalTicket() + finalCount);
ticket.setUpdateTime(new Date()); ticket.setUpdateTime(new Date());
@ -223,22 +211,6 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
return ticketLogMapper.selectPage(page, qw); return ticketLogMapper.selectPage(page, qw);
} }
private BigDecimal getActiveDoubleMultiplier(String userId) {
final LambdaQueryWrapper<PlanetBuffRecord> qw = new LambdaQueryWrapper<>();
qw.eq(PlanetBuffRecord::getUserId, userId)
.eq(PlanetBuffRecord::getType, PlanetConstant.BUFF_DOUBLE)
.eq(PlanetBuffRecord::getStatus, PlanetConstant.BUFF_STATUS_ACTIVE)
.gt(PlanetBuffRecord::getEndTime, new Date())
.orderByDesc(PlanetBuffRecord::getEffectValue)
.last("limit 1");
final List<PlanetBuffRecord> list = buffRecordMapper.selectList(qw);
if (list != null && !list.isEmpty()) {
final BigDecimal v = list.get(0).getEffectValue();
return v == null ? BigDecimal.valueOf(2) : v;
}
return BigDecimal.ONE;
}
private void saveLog(String userId, String regionId, int change, int balance, String type, String sourceId, String remark) { private void saveLog(String userId, String regionId, int change, int balance, String type, String sourceId, String remark) {
final PlanetTicketLog logEntity = new PlanetTicketLog(); final PlanetTicketLog logEntity = new PlanetTicketLog();
logEntity.setId(UUID.randomUUID().toString().replace("-", "")); logEntity.setId(UUID.randomUUID().toString().replace("-", ""));

37
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java

@ -1,6 +1,7 @@
package cc.hiver.mall.quartz; package cc.hiver.mall.quartz;
import cc.hiver.mall.entity.MallOrderGroup; import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.planet.service.PlanetAdventurePkService;
import cc.hiver.mall.service.mybatis.MallOrderGroupService; import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -13,7 +14,7 @@ import java.util.List;
/** /**
* 拼团超时自动失败定时任务 * 拼团超时自动失败定时任务
* 30分钟扫描一次拼团中status=0/3且已超过 expireTime 的拼团 * 5分钟扫描一次拼团中status=0/3且已超过 expireTime 的拼团
*/ */
@Slf4j @Slf4j
@Component @Component
@ -22,10 +23,13 @@ public class GroupBuyExpireTask {
@Autowired @Autowired
private MallOrderGroupService mallOrderGroupService; private MallOrderGroupService mallOrderGroupService;
@Autowired
private PlanetAdventurePkService planetAdventurePkService;
/** /**
* 每5分钟执行一次 * 每5分钟执行一次
*/ */
@Scheduled(cron = "0 0/30 * * * ?") @Scheduled(cron = "0 0/5 * * * ?")
public void expireOverdueGroups() { public void expireOverdueGroups() {
log.info("[拼团过期任务] 开始扫描超时拼团..."); log.info("[拼团过期任务] 开始扫描超时拼团...");
try { try {
@ -38,20 +42,29 @@ public class GroupBuyExpireTask {
if (overdueGroups.isEmpty()) { if (overdueGroups.isEmpty()) {
log.info("[拼团过期任务] 无超时拼团"); log.info("[拼团过期任务] 无超时拼团");
return; } else {
} log.info("[拼团过期任务] 发现 {} 个超时拼团,开始处理...", overdueGroups.size());
for (MallOrderGroup group : overdueGroups) {
log.info("[拼团过期任务] 发现 {} 个超时拼团,开始处理...", overdueGroups.size()); try {
for (MallOrderGroup group : overdueGroups) { mallOrderGroupService.expireGroup(group.getId());
try { log.info("[拼团过期任务] 拼团 {} 处理完成", group.getId());
mallOrderGroupService.expireGroup(group.getId()); } catch (Exception e) {
log.info("[拼团过期任务] 拼团 {} 处理完成", group.getId()); log.error("[拼团过期任务] 处理拼团 {} 失败: {}", group.getId(), e.getMessage(), e);
} catch (Exception e) { }
log.error("[拼团过期任务] 处理拼团 {} 失败: {}", group.getId(), e.getMessage(), e);
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("[拼团过期任务] 任务执行异常: {}", e.getMessage(), e); log.error("[拼团过期任务] 任务执行异常: {}", e.getMessage(), e);
} }
expireOverduePkRooms();
}
private void expireOverduePkRooms() {
try {
int settled = planetAdventurePkService.autoSettleOverdueRooms();
log.info("[拼团过期任务] 星球擂台超时房间自动结算完成,处理 {} 个", settled);
} catch (Exception e) {
log.error("[拼团过期任务] 星球擂台超时结算异常: {}", e.getMessage(), e);
}
} }
} }

98
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetAdventureSettleTask.java

@ -1,17 +1,26 @@
package cc.hiver.mall.quartz; package cc.hiver.mall.quartz;
import cc.hiver.core.common.constant.DealingsRecordConstant;
import cc.hiver.core.entity.User;
import cc.hiver.core.service.UserService;
import cc.hiver.mall.entity.DealingsRecord;
import cc.hiver.mall.planet.constant.PlanetConstant; import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetAdventureSession;
import cc.hiver.mall.planet.entity.PlanetTicket; import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.mapper.PlanetAdventureSessionMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper; import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import cc.hiver.mall.planet.service.PlanetAdventureService; import cc.hiver.mall.planet.service.PlanetAdventureService;
import cc.hiver.mall.planet.service.PlanetTicketService; import cc.hiver.mall.planet.service.PlanetTicketService;
import cc.hiver.mall.service.mybatis.DealingsRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -19,6 +28,14 @@ import java.util.stream.Collectors;
@Component @Component
public class PlanetAdventureSettleTask { public class PlanetAdventureSettleTask {
private static final BigDecimal[] GLORY_REWARD_AMOUNTS = {
new BigDecimal("5.00"),
new BigDecimal("4.00"),
new BigDecimal("3.00"),
new BigDecimal("2.00"),
new BigDecimal("1.00")
};
@Autowired @Autowired
private PlanetAdventureService adventureService; private PlanetAdventureService adventureService;
@ -28,12 +45,22 @@ public class PlanetAdventureSettleTask {
@Autowired @Autowired
private PlanetTicketService ticketService; private PlanetTicketService ticketService;
@Autowired
private PlanetAdventureSessionMapper sessionMapper;
@Autowired
private UserService userService;
@Autowired
private DealingsRecordService dealingsRecordService;
@Scheduled(cron = "0 30 21 * * ?") @Scheduled(cron = "0 30 21 * * ?")
public void settleAdventureRanks() { public void settleAdventureRanks() {
try { try {
int count = adventureService.settleDueRanks(); int count = adventureService.settleDueRanks();
int rewardCount = rewardRegionTopTickets(); int rewardCount = rewardRegionTopTickets();
log.info("[白嫖星球] 学院助推赛结算完成 count={}, rankRewardCount={}", count, rewardCount); int cashRewardCount = rewardRegionGloryCash();
log.info("[白嫖星球] 学院助推赛结算完成 count={}, rankRewardCount={}, cashRewardCount={}", count, rewardCount, cashRewardCount);
} catch (Exception e) { } catch (Exception e) {
log.error("[白嫖星球] 学院助推赛结算异常: {}", e.getMessage(), e); log.error("[白嫖星球] 学院助推赛结算异常: {}", e.getMessage(), e);
} }
@ -71,4 +98,73 @@ public class PlanetAdventureSettleTask {
} }
return rewarded; return rewarded;
} }
private int rewardRegionGloryCash() {
LocalDate today = LocalDate.now();
List<String> regionIds = sessionMapper.selectList(new LambdaQueryWrapper<PlanetAdventureSession>()
.select(PlanetAdventureSession::getRegionId)
.isNotNull(PlanetAdventureSession::getRegionId)
.eq(PlanetAdventureSession::getPlayDate, today)
.eq(PlanetAdventureSession::getStatus, PlanetConstant.ADVENTURE_SESSION_SUBMITTED)
.eq(PlanetAdventureSession::getCheatFlag, "N")
.groupBy(PlanetAdventureSession::getRegionId)).stream()
.map(PlanetAdventureSession::getRegionId)
.collect(Collectors.toList());
int rewarded = 0;
String rewardDate = today.toString();
for (String regionId : regionIds) {
List<PlanetAdventureSession> topList = sessionMapper.selectList(new LambdaQueryWrapper<PlanetAdventureSession>()
.eq(PlanetAdventureSession::getRegionId, regionId)
.eq(PlanetAdventureSession::getPlayDate, today)
.eq(PlanetAdventureSession::getStatus, PlanetConstant.ADVENTURE_SESSION_SUBMITTED)
.eq(PlanetAdventureSession::getCheatFlag, "N")
.orderByAsc(PlanetAdventureSession::getDurationSeconds)
.last("limit 5"));
if (topList == null || topList.isEmpty()) {
continue;
}
for (int i = 0; i < topList.size() && i < GLORY_REWARD_AMOUNTS.length; i++) {
if (rewardGloryCash(topList.get(i), i + 1, GLORY_REWARD_AMOUNTS[i], rewardDate)) {
rewarded++;
}
}
}
return rewarded;
}
private boolean rewardGloryCash(PlanetAdventureSession session, int rankNo, BigDecimal amount, String rewardDate) {
if (session == null || session.getUserId() == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
return false;
}
String linkId = "planet_adventure_glory_" + rewardDate + "_" + session.getRegionId() + "_" + rankNo + "_" + session.getUserId();
long exists = dealingsRecordService.count(new LambdaQueryWrapper<DealingsRecord>()
.eq(DealingsRecord::getLinkId, linkId)
.eq(DealingsRecord::getLinkUserId, session.getUserId())
.eq(DealingsRecord::getRegionId, session.getRegionId()));
if (exists > 0) {
return false;
}
User user = userService.findById(session.getUserId());
if (user == null) {
log.warn("[白嫖星球] 学院助推赛荣耀榜现金奖励跳过,用户不存在 userId={}, regionId={}, rankNo={}",
session.getUserId(), session.getRegionId(), rankNo);
return false;
}
user.setDepoBal((user.getDepoBal() == null ? BigDecimal.ZERO : user.getDepoBal()).add(amount));
userService.update(user);
DealingsRecord dealingsRecord = new DealingsRecord();
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[9]);
dealingsRecord.setAmount(amount);
dealingsRecord.setDealingsTime(new Date());
dealingsRecord.setLinkId(linkId);
dealingsRecord.setLinkUserId(session.getUserId());
dealingsRecord.setRegionId(session.getRegionId());
dealingsRecord.setLinkType(DealingsRecordConstant.TYPE[0]);
dealingsRecord.setDealingsType(DealingsRecordConstant.DEALINGS_TYPE[0]);
dealingsRecord.setCreateBy(session.getUserId());
dealingsRecord.setRemark("学院助推赛荣耀榜第" + rankNo + "名现金奖励");
dealingsRecordService.save(dealingsRecord);
return true;
}
} }

22
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetDailyResetTask.java

@ -1,9 +1,6 @@
package cc.hiver.mall.quartz; package cc.hiver.mall.quartz;
import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetBuffRecord;
import cc.hiver.mall.planet.entity.PlanetTicket; import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.mapper.PlanetBuffRecordMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper; import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -19,9 +16,8 @@ import java.util.List;
* 白嫖星球-每日重置定时任务 * 白嫖星球-每日重置定时任务
* <p> * <p>
* 每日 00:05 执行 * 每日 00:05 执行
* 1. 过期BUFF置为失效状态 * 1. 重置今日追捕/被追计数(展示用)
* 2. 重置今日追捕/被追计数(展示用) * 2. 更新连续霸榜天数
* 3. 更新连续霸榜天数
* *
* @author hiver * @author hiver
*/ */
@ -32,26 +28,16 @@ public class PlanetDailyResetTask {
@Autowired @Autowired
private PlanetTicketMapper ticketMapper; private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetBuffRecordMapper buffRecordMapper;
@Scheduled(cron = "0 5 0 * * ?") @Scheduled(cron = "0 5 0 * * ?")
public void dailyReset() { public void dailyReset() {
try { try {
// 1. 过期BUFF // 1. 重置每日计数(展示字段)
final LambdaUpdateWrapper<PlanetBuffRecord> bw = new LambdaUpdateWrapper<>();
bw.eq(PlanetBuffRecord::getStatus, PlanetConstant.BUFF_STATUS_ACTIVE)
.lt(PlanetBuffRecord::getEndTime, new Date())
.set(PlanetBuffRecord::getStatus, PlanetConstant.BUFF_STATUS_EXPIRED);
buffRecordMapper.update(null, bw);
// 2. 重置每日计数(展示字段)
final LambdaUpdateWrapper<PlanetTicket> tw = new LambdaUpdateWrapper<>(); final LambdaUpdateWrapper<PlanetTicket> tw = new LambdaUpdateWrapper<>();
tw.set(PlanetTicket::getHuntCountToday, 0) tw.set(PlanetTicket::getHuntCountToday, 0)
.set(PlanetTicket::getHuntedSuccessToday, 0); .set(PlanetTicket::getHuntedSuccessToday, 0);
ticketMapper.update(null, tw); ticketMapper.update(null, tw);
// 3. 更新连续霸榜天数:仍在TOP10的用户 keepDays+1,否则清零 // 2. 更新连续霸榜天数:仍在TOP10的用户 keepDays+1,否则清零
updateRankKeepDays(); updateRankKeepDays();
log.info("[白嫖星球] 每日重置任务完成"); log.info("[白嫖星球] 每日重置任务完成");
} catch (Exception e) { } catch (Exception e) {

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetDrawTask.java

@ -7,8 +7,8 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* 白嫖星球-到点开奖定时任务 * 白嫖星球-每日现金开奖定时任务
* 分钟扫描到达开奖时间且未开奖的奖池并执行加权开奖 * 22:00 按校区扫描到达开奖时间且未开奖的奖池并执行加权开奖
* *
* @author hiver * @author hiver
*/ */
@ -19,7 +19,7 @@ public class PlanetDrawTask {
@Autowired @Autowired
private PlanetDrawService drawService; private PlanetDrawService drawService;
@Scheduled(cron = "0 * * * * ?") @Scheduled(cron = "0 0 22 * * ?")
public void drawDuePools() { public void drawDuePools() {
try { try {
final int count = drawService.drawDuePools(); final int count = drawService.drawDuePools();

134
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/PlanetOperateSettleTask.java

@ -1,9 +1,12 @@
package cc.hiver.mall.quartz; package cc.hiver.mall.quartz;
import cc.hiver.mall.planet.constant.PlanetConstant; import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.*; import cc.hiver.mall.planet.entity.PlanetEconomyAudit;
import cc.hiver.mall.planet.mapper.*; import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.service.PlanetTicketService; import cc.hiver.mall.planet.entity.PlanetTicketLog;
import cc.hiver.mall.planet.mapper.PlanetEconomyAuditMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketLogMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -19,136 +22,19 @@ import java.util.stream.Collectors;
@Component @Component
public class PlanetOperateSettleTask { public class PlanetOperateSettleTask {
@Autowired
private PlanetLandmarkRoundMapper landmarkRoundMapper;
@Autowired
private PlanetLandmarkBidMapper landmarkBidMapper;
@Autowired
private PlanetLandmarkConfigMapper landmarkConfigMapper;
@Autowired
private PlanetLandmarkRewardLogMapper landmarkRewardLogMapper;
@Autowired @Autowired
private PlanetEconomyAuditMapper economyAuditMapper; private PlanetEconomyAuditMapper economyAuditMapper;
@Autowired @Autowired
private PlanetTicketLogMapper ticketLogMapper; private PlanetTicketLogMapper ticketLogMapper;
@Autowired @Autowired
private PlanetTicketMapper ticketMapper; private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetTicketService ticketService;
private static String genId() { private static String genId() {
return UUID.randomUUID().toString().replace("-", ""); return UUID.randomUUID().toString().replace("-", "");
} }
/** /**
* 每晚22点后结算校园地标失败只记录日志避免影响开奖主流程 * 每日经济审计保留当前仍在使用的券树防御塔奖池等券流水统计
*/
@Scheduled(cron = "0 3 22 * * ?")
@Transactional(rollbackFor = Exception.class)
public void settleLandmarks() {
final LambdaQueryWrapper<PlanetLandmarkRound> qw = new LambdaQueryWrapper<>();
qw.eq(PlanetLandmarkRound::getStatus, PlanetConstant.LANDMARK_ROUND_RUNNING)
.le(PlanetLandmarkRound::getRoundDate, LocalDate.now());
final List<PlanetLandmarkRound> rounds = landmarkRoundMapper.selectList(qw);
for (PlanetLandmarkRound round : rounds) {
try {
settleRound(round);
} catch (Exception e) {
log.error("[白嫖星球] 地标结算失败 roundId={}, {}", round.getId(), e.getMessage(), e);
}
}
if (!rounds.isEmpty()) {
log.info("[白嫖星球] 地标结算完成 roundCount={}", rounds.size());
}
}
private void settleRound(PlanetLandmarkRound round) {
final PlanetLandmarkConfig landmark = landmarkConfigMapper.selectById(round.getLandmarkId());
if (landmark == null) {
round.setStatus(PlanetConstant.LANDMARK_ROUND_SETTLED);
round.setSettleTime(new Date());
round.setUpdateTime(new Date());
landmarkRoundMapper.updateById(round);
return;
}
final LambdaQueryWrapper<PlanetLandmarkBid> bq = new LambdaQueryWrapper<>();
bq.eq(PlanetLandmarkBid::getRoundId, round.getId()).eq(PlanetLandmarkBid::getStatus, 0);
final List<PlanetLandmarkBid> bids = landmarkBidMapper.selectList(bq);
if (bids == null || bids.isEmpty()) {
round.setStatus(PlanetConstant.LANDMARK_ROUND_SETTLED);
round.setSettleTime(new Date());
round.setUpdateTime(new Date());
landmarkRoundMapper.updateById(round);
return;
}
final Map<String, Integer> userInvest = bids.stream().collect(Collectors.groupingBy(
PlanetLandmarkBid::getUserId, Collectors.summingInt(b -> b.getInvestTickets() == null ? 0 : b.getInvestTickets())));
final String winnerUserId = userInvest.entrySet().stream()
.max(Comparator.comparingInt(Map.Entry::getValue))
.map(Map.Entry::getKey).orElse(null);
final int winnerContribution = winnerUserId == null ? 0 : userInvest.get(winnerUserId);
int totalBurn = 0;
for (PlanetLandmarkBid bid : bids) {
final boolean winner = winnerUserId != null && winnerUserId.equals(bid.getUserId());
bid.setIsWinner(winner ? 1 : 0);
bid.setStatus(1);
if (winner) {
bid.setRefundTickets(0);
bid.setBurnTickets(bid.getInvestTickets());
} else {
final int invest = bid.getInvestTickets() == null ? 0 : bid.getInvestTickets();
final int burn = Math.min(1, invest);
final int refund = Math.max(0, invest - burn);
bid.setBurnTickets(burn);
bid.setRefundTickets(refund);
totalBurn += burn;
if (refund > 0) {
ticketService.addTicketsWithoutBuff(bid.getUserId(), bid.getRegionId(), refund,
PlanetConstant.TICKET_TYPE_LANDMARK_REFUND, bid.getId(), "校园地标未占领退回");
}
}
bid.setUpdateTime(new Date());
landmarkBidMapper.updateById(bid);
}
grantLandmarkReward(round, landmark, winnerUserId);
round.setOwnerUserId(winnerUserId);
round.setOwnerContribution(winnerContribution);
round.setTotalBurn(totalBurn);
round.setStatus(PlanetConstant.LANDMARK_ROUND_SETTLED);
round.setSettleTime(new Date());
round.setUpdateTime(new Date());
landmarkRoundMapper.updateById(round);
}
private void grantLandmarkReward(PlanetLandmarkRound round, PlanetLandmarkConfig landmark, String winnerUserId) {
if (winnerUserId == null || !"ticket".equals(landmark.getBenefitType())) {
return;
}
final int reward = landmark.getBenefitValue() == null ? 0 : landmark.getBenefitValue().intValue();
if (reward <= 0) {
return;
}
final String sourceId = round.getId() + "_reward";
final int added = ticketService.addTicketsWithoutBuff(winnerUserId, round.getRegionId(), reward,
PlanetConstant.TICKET_TYPE_LANDMARK_REWARD, sourceId, "占领校园地标收益:" + landmark.getName());
if (added > 0) {
final PlanetLandmarkRewardLog log = new PlanetLandmarkRewardLog();
log.setId(genId());
log.setRoundId(round.getId());
log.setLandmarkId(landmark.getId());
log.setRegionId(round.getRegionId());
log.setUserId(winnerUserId);
log.setBenefitType(landmark.getBenefitType());
log.setBenefitValue(landmark.getBenefitValue());
log.setTicketAmount(reward);
log.setSourceId(sourceId);
log.setCreateTime(new Date());
landmarkRewardLogMapper.insert(log);
}
}
/**
* 每日经济审计用券流水做区域净增/回收统计发现净增过高时标记预警
*/ */
@Scheduled(cron = "0 20 0 * * ?") @Scheduled(cron = "0 20 0 * * ?")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -175,7 +61,6 @@ public class PlanetOperateSettleTask {
int burnTickets = 0; int burnTickets = 0;
int plantOutput = 0; int plantOutput = 0;
int searchTransfer = 0; int searchTransfer = 0;
int landmarkBurn = 0;
int upgradeBurn = 0; int upgradeBurn = 0;
int poolBurn = 0; int poolBurn = 0;
for (PlanetTicketLog log : logs) { for (PlanetTicketLog log : logs) {
@ -188,8 +73,7 @@ public class PlanetOperateSettleTask {
final String type = log.getType(); final String type = log.getType();
if (PlanetConstant.TICKET_TYPE_TREE_HARVEST.equals(type)) plantOutput += Math.max(0, change); if (PlanetConstant.TICKET_TYPE_TREE_HARVEST.equals(type)) plantOutput += Math.max(0, change);
if (PlanetConstant.TICKET_TYPE_SEARCH.equals(type)) searchTransfer += Math.max(0, change); if (PlanetConstant.TICKET_TYPE_SEARCH.equals(type)) searchTransfer += Math.max(0, change);
if (PlanetConstant.TICKET_TYPE_LANDMARK_BID.equals(type)) landmarkBurn += Math.max(0, -change); if (PlanetConstant.TICKET_TYPE_TOWER_UPGRADE.equals(type)) upgradeBurn += Math.max(0, -change);
if (PlanetConstant.TICKET_TYPE_WAREHOUSE_UPGRADE.equals(type) || PlanetConstant.TICKET_TYPE_TOWER_UPGRADE.equals(type)) upgradeBurn += Math.max(0, -change);
if (PlanetConstant.TICKET_TYPE_DRAW.equals(type)) poolBurn += Math.max(0, -change); if (PlanetConstant.TICKET_TYPE_DRAW.equals(type)) poolBurn += Math.max(0, -change);
} }
final Long activeUsers = ticketMapper.selectCount(new LambdaQueryWrapper<PlanetTicket>() final Long activeUsers = ticketMapper.selectCount(new LambdaQueryWrapper<PlanetTicket>()
@ -207,7 +91,7 @@ public class PlanetOperateSettleTask {
audit.setNetTickets(newTickets - burnTickets); audit.setNetTickets(newTickets - burnTickets);
audit.setPlantOutput(plantOutput); audit.setPlantOutput(plantOutput);
audit.setSearchTransfer(searchTransfer); audit.setSearchTransfer(searchTransfer);
audit.setLandmarkBurn(landmarkBurn); audit.setLandmarkBurn(0);
audit.setUpgradeBurn(upgradeBurn); audit.setUpgradeBurn(upgradeBurn);
audit.setPoolBurn(poolBurn); audit.setPoolBurn(poolBurn);
audit.setActiveUserCount(activeUsers == null ? 0 : activeUsers.intValue()); audit.setActiveUserCount(activeUsers == null ? 0 : activeUsers.intValue());

Loading…
Cancel
Save