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. 177
      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. 140
      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. 23
      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>
</li>
<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>
</ul>
</div>
@ -84,7 +84,7 @@
<div class="test-detail">
<span class="meta text-white badge badge-sm"></span>
<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 class="test-contents d-none">
<div class="detail-head">
@ -92,9 +92,9 @@
<div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>06.05.2026 16:39:31</span>
<span class='badge badge-danger'>06.05.2026 16:39:31</span>
<span class='badge badge-default'>0.017 secs</span>
<span class='badge badge-success'>06.09.2026 18:01:01</span>
<span class='badge badge-danger'>06.09.2026 18:01:01</span>
<span class='badge badge-default'>0.021 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
</div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>16:39:31</td>
<td>18:01:01</td>
<td>
Test passed
</td>
@ -128,13 +128,13 @@
<div class="col-md-3">
<div class="card"><div class="card-body">
<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 class="col-md-3">
<div class="card"><div class="card-body">
<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 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售后

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.vo.Result;
import cc.hiver.mall.planet.entity.PlanetDrawRecord;
import cc.hiver.mall.planet.pojo.PlanetBoxResultVo;
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.pojo.*;
import cc.hiver.mall.planet.service.*;
import io.swagger.annotations.Api;
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")
@RequestMapping(value = "/rank", method = RequestMethod.POST)
public Result rank(@RequestBody PlanetQuery query) {
@ -100,6 +114,23 @@ public class PlanetController {
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 = "发起追捕")
@RequestMapping(value = "/hunt", method = RequestMethod.POST)
public Result hunt(@RequestBody PlanetQuery query) {
@ -211,6 +242,7 @@ public class PlanetController {
final Map<String, Object> data = new HashMap<>(4);
data.put("record", record);
data.put("winners", record == null ? null : drawService.winnersOfDraw(record.getId()));
data.put("history", drawService.recentDrawResults(query.getRegionId(), 10));
return new ResultUtil<>().setData(data);
} catch (HiverException e) {
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 = "加入星球擂台房间")
@RequestMapping(value = "/adventure/pk/join", method = RequestMethod.POST)
@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 Integer todayCollectedTickets;
private Integer myPoolTickets;
private Integer myWeightTickets;
private Integer poolTicketTotal;
private Integer poolWeightTotal;
private Integer poolJoinCount;
private BigDecimal myProbability;
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.PlanetNews;
import cc.hiver.mall.planet.entity.PlanetReward;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -38,6 +39,9 @@ public class PlanetHomeVo implements Serializable {
@ApiModelProperty(value = "期号")
private String periodNo;
@ApiModelProperty(value = "本期奖项配置")
private List<PlanetReward> rewardList;
// ---------- 我的星球中心 ----------
@ApiModelProperty(value = "我的券数量")
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 = "是否开启防护罩")
private Boolean shielded;
@ApiModelProperty(value = "是否拥有防御塔")
private Boolean hasTower;
@ApiModelProperty(value = "是否隐身")
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.PlanetAdventurePkPlayer;
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.PlanetAdventurePkHallVo;
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);
PlanetAdventurePkPlayVo roomInfo(String userId, String regionId, String roomId);
PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar,
String college, String roomName, Integer maxPlayers,
Integer publicFlag, String password, Integer entryTickets);
@ -32,6 +35,8 @@ public interface PlanetAdventurePkService {
PlanetAdventurePkPlayVo leaveRoom(String userId, String regionId, String roomId, Integer remainingCards);
int autoSettleOverdueRooms();
PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar,
String college, Integer durationSeconds);
@ -41,5 +46,5 @@ public interface PlanetAdventurePkService {
String college, String challengeId, Integer cleared,
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 java.util.List;
import java.util.Map;
/**
* 白嫖星球-开奖服务
@ -52,6 +53,11 @@ public interface PlanetDrawService {
*/
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 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.stereotype.Service;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@ -75,6 +77,40 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
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) {
final int num = pageVo == null || pageVo.getPageNumber() <= 0 ? 1 : pageVo.getPageNumber();
final int size = pageVo == null || pageVo.getPageSize() <= 0 ? 10 : pageVo.getPageSize();
@ -110,6 +146,9 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
if (pool.getWinnerCount() == null) {
pool.setWinnerCount(0);
}
if (pool.getDrawTime() == null) {
pool.setDrawTime(nextDrawTime(new Date()));
}
pool.setCreateTime(new Date());
pool.setUpdateTime(new Date());
poolMapper.insert(pool);
@ -144,12 +183,17 @@ public class PlanetAdminServiceImpl implements PlanetAdminService {
} else {
rewardMapper.updateById(reward);
}
refreshPoolRewardAmount(reward.getPoolId());
return reward;
}
@Override
public void deleteReward(String id) {
final PlanetReward reward = rewardMapper.selectById(id);
rewardMapper.deleteById(id);
if (reward != null) {
refreshPoolRewardAmount(reward.getPoolId());
}
}
@Override

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

@ -25,6 +25,8 @@ import java.util.UUID;
@Service
public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
private static final int AUTO_FAIL_REMAINING_CARDS = 999999;
@Autowired
private PlanetAdventurePkRoomMapper roomMapper;
@Autowired
@ -85,6 +87,23 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
.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
@Transactional(rollbackFor = Exception.class)
public PlanetAdventurePkRoom createRoom(String userId, String regionId, String nickname, String avatar,
@ -93,8 +112,11 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
require(userId, regionId);
int players = maxPlayers == null ? 2 : Math.max(2, Math.min(5, maxPlayers));
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();
room.setId(genId());
room.setId(roomId);
room.setRoomName(StringUtils.isEmpty(roomName) ? "星球擂台房间" : roomName.trim());
room.setRegionId(regionId);
room.setOwnerUserId(userId);
@ -106,11 +128,13 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
room.setPassword(password);
room.setEntryTickets(tickets);
room.setStatus(PlanetConstant.ADVENTURE_PK_ROOM_WAITING);
room.setPoolTickets(0);
room.setPlayerCount(0);
room.setPoolTickets(tickets);
room.setPlayerCount(1);
room.setCreateTime(new Date());
room.setUpdateTime(new Date());
roomMapper.insert(room);
PlanetAdventurePkPlayer owner = newPkPlayer(roomId, regionId, userId, nickname, avatar, college, tickets);
playerMapper.insert(owner);
return room;
}
@ -141,22 +165,7 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
if (count >= room.getMaxPlayers()) throw new HiverException("房间人数已满");
ticketService.deductTickets(userId, regionId, room.getEntryTickets(),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_ENTRY, roomId + "_" + userId, "星球擂台入场券");
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(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());
PlanetAdventurePkPlayer player = newPkPlayer(roomId, regionId, userId, nickname, avatar, college, room.getEntryTickets());
playerMapper.insert(player);
room.setPlayerCount(count + 1);
room.setPoolTickets(nz(room.getPoolTickets()) + room.getEntryTickets());
@ -172,6 +181,9 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
Integer durationSeconds, Integer remainingSeconds, Integer remainingCards) {
if (StringUtils.isEmpty(userId)) throw new HiverException("用户id不能为空");
PlanetAdventurePkRoom room = mustRoom(roomId, regionId);
if (room.getStatus() == PlanetConstant.ADVENTURE_PK_ROOM_SETTLED) {
throw new HiverException("房间已结算,无法提交成绩");
}
PlanetAdventurePkPlayer player = mustPlayer(roomId, userId);
if (terminal(player)) throw new HiverException("本房间成绩已提交");
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);
}
@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
public PlanetAdventureChallenge createChallenge(String userId, String regionId, String nickname, String avatar,
String college, Integer durationSeconds) {
@ -262,16 +294,71 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
.eq(PlanetAdventureSession::getStatus, PlanetConstant.ADVENTURE_SESSION_SUBMITTED)
.eq(PlanetAdventureSession::getCheatFlag, "N")
.orderByAsc(PlanetAdventureSession::getDurationSeconds)
.last("limit 3"));
.last("limit 5"));
}
private void settleIfReady(PlanetAdventurePkRoom room) {
List<PlanetAdventurePkPlayer> players = playerMapper.selectList(new LambdaQueryWrapper<PlanetAdventurePkPlayer>()
.eq(PlanetAdventurePkPlayer::getRoomId, room.getId()));
if (players.size() < room.getMaxPlayers()) return;
for (PlanetAdventurePkPlayer p : players) {
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) -> {
boolean ac = nz(a.getCleared()) == 1;
boolean bc = nz(b.getCleared()) == 1;
@ -281,35 +368,59 @@ public class PlanetAdventurePkServiceImpl implements PlanetAdventurePkService {
if (d != 0) return d;
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);
if (!hasClear) {
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);
playerMapper.updateById(p);
}
} else {
PlanetAdventurePkPlayer winner = players.get(0);
ticketService.addTicketsWithoutBuff(winner.getUserId(), winner.getRegionId(), nz(room.getPoolTickets()),
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REWARD, room.getId(), "星球擂台第一名通吃奖池");
PlanetConstant.TICKET_TYPE_ADVENTURE_PK_REWARD, room.getId(), hasClear ? "星球擂台第一名通吃奖池" : "星球擂台消除最多通吃奖池");
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);
p.setUpdateTime(new Date());
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.setSettleTime(new Date());
room.setUpdateTime(new Date());
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) {
PlanetAdventurePkPlayVo vo = new PlanetAdventurePkPlayVo();
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.pojo.PlanetBoxResultVo;
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.PlanetTicketService;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,9 +30,6 @@ public class PlanetBoxServiceImpl implements PlanetBoxService {
@Autowired
private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetBuffService buffService;
@Autowired
private PlanetNewsService newsService;
@ -83,14 +79,6 @@ public class PlanetBoxServiceImpl implements PlanetBoxService {
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) {
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.mapper.*;
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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
@ -35,6 +38,8 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
/** 每日开奖时刻(24小时制),到点由定时任务自动开奖,每日一抽 */
private static final int DAILY_DRAW_HOUR = 22;
/** 同一用户中奖冷却天数,让更多同学有机会中奖 */
private static final int WIN_COOLDOWN_DAYS = 7;
@Autowired
private PlanetPoolMapper poolMapper;
@ -60,9 +65,6 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
@Autowired
private PlanetDrawWinnerMapper drawWinnerMapper;
@Autowired
private PlanetBuffService buffService;
@Autowired
private PlanetNewsService newsService;
@ -132,7 +134,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
join.setCreateTime(new Date());
}
join.setTickets((join.getTickets() == null ? 0 : join.getTickets()) + tickets);
join.setWeightTickets(join.getTickets());
join.setWeightTickets(calcWeightTickets(join.getTickets()));
join.setUpdateTime(new Date());
if (poolTicketMapper.selectById(join.getId()) == null) {
poolTicketMapper.insert(join);
@ -155,10 +157,12 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
vo.setMyPoolTickets(myTickets);
vo.setPoolTicketTotal(total);
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));
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.setSignedToday(taskService.signedToday(userId, regionId));
vo.setBoxAvailable(boxAvailableQuick(userId, regionId));
@ -178,7 +182,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
pool.setRegionId(regionId);
pool.setPeriodNo(genPeriodNo());
pool.setTitle("白嫖星球·本期瓜分");
pool.setPoolAmount(new BigDecimal("88.88"));
pool.setPoolAmount(BigDecimal.ZERO);
pool.setDrawTime(nextDrawTime(now));
pool.setJoinCount(0);
pool.setTicketTotal(0);
@ -190,6 +194,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
poolMapper.insert(pool);
// 默认奖项
createDefaultRewards(pool);
refreshPoolRewardAmount(pool);
return pool;
}
@ -237,19 +242,17 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
final LambdaQueryWrapper<PlanetReward> rq = new LambdaQueryWrapper<>();
rq.eq(PlanetReward::getPoolId, poolId).orderByAsc(PlanetReward::getSort);
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 Map<String, Double> luckyMap = buffService.luckyWeightFactors(userIds);
// 构建加权候选(权重= 券数量 * 幸运系数)
final List<Candidate> poutPool = new ArrayList<>();
// 构建加权候选:投入券先按递减规则折算权重,防止大户无限堆券垄断。
final List<Candidate> poolCandidates = new ArrayList<>();
int ticketTotal = 0;
for (PlanetPoolTicket t : joins) {
final double factor = luckyMap.getOrDefault(t.getUserId(), 1.0);
final double weight = t.getTickets() * factor;
poutPool.add(new Candidate(t, weight));
ticketTotal += t.getTickets();
final int tickets = t.getTickets() == null ? 0 : t.getTickets();
final int weightTickets = t.getWeightTickets() == null ? calcWeightTickets(tickets) : t.getWeightTickets();
t.setWeightTickets(weightTickets);
poolCandidates.add(new Candidate(t, weightTickets));
ticketTotal += tickets;
}
final Date now = new Date();
@ -259,21 +262,24 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
record.setPoolId(pool.getId());
record.setRegionId(pool.getRegionId());
record.setPeriodNo(pool.getPeriodNo());
record.setPoolAmount(pool.getPoolAmount());
record.setPoolAmount(poolAmount);
record.setJoinCount(joins.size());
record.setTicketTotal(ticketTotal);
record.setStatus(1);
record.setDrawTime(now);
record.setCreateTime(now);
final Set<String> cooldownUsers = recentWinnerUserIds(pool.getRegionId(), now);
boolean useCooldown = hasCandidate(poolCandidates, cooldownUsers);
int winnerCount = 0;
for (PlanetReward reward : rewards) {
final int quota = reward.getQuota() == null ? 0 : reward.getQuota();
for (int i = 0; i < quota; i++) {
if (poutPoolEmpty(poutPool)) {
List<Candidate> usable = usableCandidates(poolCandidates, useCooldown ? cooldownUsers : Collections.emptySet());
if (usable.isEmpty()) {
break;
}
final Candidate winner = pickWeighted(poutPoolUsable(poutPool));
final Candidate winner = pickWeighted(usable);
if (winner == null) {
break;
}
@ -290,6 +296,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
pool.setJoinCount(joins.size());
pool.setTicketTotal(ticketTotal);
pool.setWinnerCount(winnerCount);
pool.setPoolAmount(poolAmount);
pool.setUpdateTime(now);
poolMapper.updateById(pool);
@ -327,6 +334,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
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());
}
refreshPoolRewardAmount(pool);
}
@Override
@ -371,6 +379,24 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
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
public List<PlanetDrawWinner> myWinning(String userId, String regionId) {
requireRegion(regionId);
@ -482,25 +508,20 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
drawWinnerMapper.insert(winner);
}
private boolean poutPoolEmpty(List<Candidate> pool) {
for (Candidate c : pool) {
if (!c.win) {
return false;
}
}
return true;
}
private List<Candidate> poutPoolUsable(List<Candidate> pool) {
private List<Candidate> usableCandidates(List<Candidate> pool, Set<String> cooldownUsers) {
final List<Candidate> usable = new ArrayList<>();
for (Candidate c : pool) {
if (!c.win) {
if (!c.win && (cooldownUsers == null || !cooldownUsers.contains(c.ticket.getUserId()))) {
usable.add(c);
}
}
return usable;
}
private boolean hasCandidate(List<Candidate> pool, Set<String> cooldownUsers) {
return !usableCandidates(pool, cooldownUsers).isEmpty();
}
private Candidate pickWeighted(List<Candidate> usable) {
if (usable.isEmpty()) {
return null;
@ -572,6 +593,16 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
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) {
return poolTicketMapper.selectCount(new LambdaQueryWrapper<PlanetPoolTicket>()
.eq(PlanetPoolTicket::getPoolId, poolId)
@ -586,6 +617,60 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
.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) {
final Calendar c = Calendar.getInstance();
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("treeConfigs", treeConfigs(regionId));
data.put("treeOrders", treeOrders(userId, regionId));
data.put("nextTowerConfig", getTowerLevel(regionId, nullToZero(state.getTowerLevel()) + 1));
data.put("landmarks", landmarkList(regionId));
data.put("staminaItems", staminaItems(regionId));
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.mall.planet.constant.PlanetConstant;
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.PlanetUserStateMapper;
import cc.hiver.mall.planet.pojo.PlanetRankItemVo;
import cc.hiver.mall.planet.service.PlanetBuffService;
import cc.hiver.mall.planet.service.PlanetRankService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -37,7 +38,7 @@ public class PlanetRankServiceImpl implements PlanetRankService {
private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetBuffService buffService;
private PlanetUserStateMapper userStateMapper;
@Autowired
private RedisTemplateHelper redisTemplateHelper;
@ -77,28 +78,27 @@ public class PlanetRankServiceImpl implements PlanetRankService {
return page;
}
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<>();
int offset = (current - 1) * size;
for (int i = 0; i < tickets.size(); 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;
final PlanetRankItemVo vo = new PlanetRankItemVo();
vo.setRankNo(rankNo);
vo.setUserId(t.getUserId());
vo.setNickname(stealth ? "隐身侠" : t.getNickname());
vo.setAvatar(stealth ? null : t.getAvatar());
vo.setCollege(stealth ? null : t.getCollege());
vo.setNickname(t.getNickname());
vo.setAvatar(t.getAvatar());
vo.setCollege(t.getCollege());
vo.setTicketCount(t.getTicketCount());
vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount()));
vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount()));
vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays());
vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo));
vo.setShielded(buffs != null && buffs.contains(PlanetConstant.BUFF_SHIELD));
vo.setStealth(stealth);
vo.setShielded(false);
vo.setHasTower(towerUserIds.contains(t.getUserId()));
vo.setStealth(false);
vo.setSelf(t.getUserId() != null && t.getUserId().equals(currentUserId));
result.add(vo);
}
@ -107,10 +107,9 @@ public class PlanetRankServiceImpl implements PlanetRankService {
}
/**
* 从数据库构建基础榜单先批量取候选券记录再一次性批量查 BUFF内存组装避免循环查库
* 从数据库构建基础榜单批量取券记录后一次性补防御塔状态避免循环查库
*/
private List<PlanetRankItemVo> buildRankFromDb(String regionId, int topN) {
// 多取一些以便过滤隐身用户后仍能凑满topN
final LambdaQueryWrapper<PlanetTicket> qw = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(regionId)) {
qw.eq(PlanetTicket::getRegionId, regionId);
@ -123,15 +122,12 @@ public class PlanetRankServiceImpl implements PlanetRankService {
if (tickets.isEmpty()) {
return new ArrayList<>();
}
// 批量查询候选用户的生效 BUFF 类型,一次查库
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<>();
int rankNo = 0;
for (PlanetTicket t : tickets) {
final Set<String> buffs = buffMap.get(t.getUserId());
final boolean stealth = buffs != null && buffs.contains(PlanetConstant.BUFF_STEALTH);
rankNo++;
if (rankNo > topN) {
break;
@ -139,22 +135,39 @@ public class PlanetRankServiceImpl implements PlanetRankService {
final PlanetRankItemVo vo = new PlanetRankItemVo();
vo.setRankNo(rankNo);
vo.setUserId(t.getUserId());
vo.setNickname(stealth ? "隐身侠" : t.getNickname());
vo.setAvatar(stealth ? null : t.getAvatar());
vo.setCollege(stealth ? null : t.getCollege());
vo.setNickname(t.getNickname());
vo.setAvatar(t.getAvatar());
vo.setCollege(t.getCollege());
vo.setTicketCount(t.getTicketCount());
vo.setDangerLevel(PlanetConstant.dangerLevel(t.getTicketCount()));
vo.setDangerLevelName(PlanetConstant.dangerLevelName(t.getTicketCount()));
vo.setRankKeepDays(t.getRankKeepDays() == null ? 0 : t.getRankKeepDays());
vo.setBountyTickets(PlanetConstant.bountyByRank(rankNo));
vo.setShielded(buffs != null && buffs.contains(PlanetConstant.BUFF_SHIELD));
vo.setStealth(stealth);
vo.setShielded(false);
vo.setHasTower(towerUserIds.contains(t.getUserId()));
vo.setStealth(false);
vo.setSelf(false);
result.add(vo);
}
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) {
try {
final String json = redisTemplateHelper.get(cacheKey(regionId, topN));

140
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;
import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.PlanetPool;
import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.entity.*;
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.PlanetQuery;
import cc.hiver.mall.planet.pojo.PlanetRankItemVo;
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.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 白嫖星球-首页聚合服务实现
@ -31,9 +36,6 @@ public class PlanetServiceImpl implements PlanetService {
@Autowired
private PlanetTaskService taskService;
@Autowired
private PlanetBuffService buffService;
@Autowired
private PlanetBoxService boxService;
@ -49,6 +51,15 @@ public class PlanetServiceImpl implements PlanetService {
@Autowired
private PlanetOperateService operateService;
@Autowired
private PlanetPoolTicketMapper poolTicketMapper;
@Autowired
private PlanetTicketLogMapper ticketLogMapper;
@Autowired
private PlanetRewardMapper rewardMapper;
@Override
public PlanetHomeVo home(PlanetQuery query) {
final String userId = query.getUserId();
@ -70,6 +81,7 @@ public class PlanetServiceImpl implements PlanetService {
vo.setCountdownMillis(0L);
}
vo.setJoinCount(pool.getJoinCount() == null ? 0 : pool.getJoinCount());
vo.setRewardList(rewardsOfPool(pool.getId()));
// 我的星球中心
vo.setMyTicketCount(ticket.getTicketCount() == null ? 0 : ticket.getTicketCount());
@ -81,32 +93,104 @@ public class PlanetServiceImpl implements PlanetService {
vo.setRemainHunt(huntService.remainHunt(userId));
vo.setLevel(PlanetConstant.dangerLevel(vo.getMyTicketCount()));
vo.setMyRankNo(rankService.userRankNo(regionId, userId));
// 我生效的BUFF
/*final List<PlanetBuffVo> myBuffs = new ArrayList<>();
for (PlanetBuffRecord r : buffService.activeBuffs(userId)) {
final PlanetBuffVo bv = new PlanetBuffVo();
bv.setId(r.getBuffId());
bv.setType(r.getType());
bv.setEffectValue(r.getEffectValue());
bv.setActive(true);
bv.setActiveEndTime(r.getEndTime());
myBuffs.add(bv);
vo.setDailyLoop(lightDailyLoop(userId, regionId, pool));
vo.setUnreadWinning(drawService.unreadWinning(userId, regionId));
return vo;
}
vo.setMyBuffs(myBuffs);*/
// 各板块
@Override
public PlanetHomeVo supply(PlanetQuery query) {
final String userId = query.getUserId();
final String regionId = query.getRegionId();
final PlanetHomeVo vo = new PlanetHomeVo();
final PlanetTicket ticket = ticketService.getOrCreate(userId, regionId,
query.getNickname(), query.getAvatar(), query.getCollege());
vo.setMyTicketCount(ticket.getTicketCount() == null ? 0 : ticket.getTicketCount());
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.setOperate(operateService.overview(userId, regionId));
vo.setDailyLoop(drawService.dailyLoop(userId, regionId));
vo.setUnreadWinning(drawService.unreadWinning(userId, regionId));
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.service.UserService;
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.PlanetTicketLog;
import cc.hiver.mall.planet.mapper.PlanetBuffRecordMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketLogMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
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.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
@ -38,9 +34,6 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
@Autowired
private PlanetTicketLogMapper ticketLogMapper;
@Autowired
private PlanetBuffRecordMapper buffRecordMapper;
@Autowired
private UserService userService;
@ -140,12 +133,7 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
}
}
final PlanetTicket ticket = getOrCreate(userId, regionId, null, null, null);
// 双倍BUFF加成
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.setTotalTicket(ticket.getTotalTicket() + finalCount);
ticket.setUpdateTime(new Date());
@ -223,22 +211,6 @@ public class PlanetTicketServiceImpl implements PlanetTicketService {
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) {
final PlanetTicketLog logEntity = new PlanetTicketLog();
logEntity.setId(UUID.randomUUID().toString().replace("-", ""));

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

@ -1,6 +1,7 @@
package cc.hiver.mall.quartz;
import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.planet.service.PlanetAdventurePkService;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
@ -13,7 +14,7 @@ import java.util.List;
/**
* 拼团超时自动失败定时任务
* 30分钟扫描一次拼团中status=0/3且已超过 expireTime 的拼团
* 5分钟扫描一次拼团中status=0/3且已超过 expireTime 的拼团
*/
@Slf4j
@Component
@ -22,10 +23,13 @@ public class GroupBuyExpireTask {
@Autowired
private MallOrderGroupService mallOrderGroupService;
@Autowired
private PlanetAdventurePkService planetAdventurePkService;
/**
* 每5分钟执行一次
*/
@Scheduled(cron = "0 0/30 * * * ?")
@Scheduled(cron = "0 0/5 * * * ?")
public void expireOverdueGroups() {
log.info("[拼团过期任务] 开始扫描超时拼团...");
try {
@ -38,9 +42,7 @@ public class GroupBuyExpireTask {
if (overdueGroups.isEmpty()) {
log.info("[拼团过期任务] 无超时拼团");
return;
}
} else {
log.info("[拼团过期任务] 发现 {} 个超时拼团,开始处理...", overdueGroups.size());
for (MallOrderGroup group : overdueGroups) {
try {
@ -50,8 +52,19 @@ public class GroupBuyExpireTask {
log.error("[拼团过期任务] 处理拼团 {} 失败: {}", group.getId(), e.getMessage(), e);
}
}
}
} catch (Exception 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;
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.entity.PlanetAdventureSession;
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.service.PlanetAdventureService;
import cc.hiver.mall.planet.service.PlanetTicketService;
import cc.hiver.mall.service.mybatis.DealingsRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@ -19,6 +28,14 @@ import java.util.stream.Collectors;
@Component
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
private PlanetAdventureService adventureService;
@ -28,12 +45,22 @@ public class PlanetAdventureSettleTask {
@Autowired
private PlanetTicketService ticketService;
@Autowired
private PlanetAdventureSessionMapper sessionMapper;
@Autowired
private UserService userService;
@Autowired
private DealingsRecordService dealingsRecordService;
@Scheduled(cron = "0 30 21 * * ?")
public void settleAdventureRanks() {
try {
int count = adventureService.settleDueRanks();
int rewardCount = rewardRegionTopTickets();
log.info("[白嫖星球] 学院助推赛结算完成 count={}, rankRewardCount={}", count, rewardCount);
int cashRewardCount = rewardRegionGloryCash();
log.info("[白嫖星球] 学院助推赛结算完成 count={}, rankRewardCount={}, cashRewardCount={}", count, rewardCount, cashRewardCount);
} catch (Exception e) {
log.error("[白嫖星球] 学院助推赛结算异常: {}", e.getMessage(), e);
}
@ -71,4 +98,73 @@ public class PlanetAdventureSettleTask {
}
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;
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.mapper.PlanetBuffRecordMapper;
import cc.hiver.mall.planet.mapper.PlanetTicketMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -19,9 +16,8 @@ import java.util.List;
* 白嫖星球-每日重置定时任务
* <p>
* 每日 00:05 执行
* 1. 过期BUFF置为失效状态
* 2. 重置今日追捕/被追计数(展示用)
* 3. 更新连续霸榜天数
* 1. 重置今日追捕/被追计数(展示用)
* 2. 更新连续霸榜天数
*
* @author hiver
*/
@ -32,26 +28,16 @@ public class PlanetDailyResetTask {
@Autowired
private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetBuffRecordMapper buffRecordMapper;
@Scheduled(cron = "0 5 0 * * ?")
public void dailyReset() {
try {
// 1. 过期BUFF
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. 重置每日计数(展示字段)
// 1. 重置每日计数(展示字段)
final LambdaUpdateWrapper<PlanetTicket> tw = new LambdaUpdateWrapper<>();
tw.set(PlanetTicket::getHuntCountToday, 0)
.set(PlanetTicket::getHuntedSuccessToday, 0);
ticketMapper.update(null, tw);
// 3. 更新连续霸榜天数:仍在TOP10的用户 keepDays+1,否则清零
// 2. 更新连续霸榜天数:仍在TOP10的用户 keepDays+1,否则清零
updateRankKeepDays();
log.info("[白嫖星球] 每日重置任务完成");
} 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;
/**
* 白嫖星球-到点开奖定时任务
* 分钟扫描到达开奖时间且未开奖的奖池并执行加权开奖
* 白嫖星球-每日现金开奖定时任务
* 22:00 按校区扫描到达开奖时间且未开奖的奖池并执行加权开奖
*
* @author hiver
*/
@ -19,7 +19,7 @@ public class PlanetDrawTask {
@Autowired
private PlanetDrawService drawService;
@Scheduled(cron = "0 * * * * ?")
@Scheduled(cron = "0 0 22 * * ?")
public void drawDuePools() {
try {
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;
import cc.hiver.mall.planet.constant.PlanetConstant;
import cc.hiver.mall.planet.entity.*;
import cc.hiver.mall.planet.mapper.*;
import cc.hiver.mall.planet.service.PlanetTicketService;
import cc.hiver.mall.planet.entity.PlanetEconomyAudit;
import cc.hiver.mall.planet.entity.PlanetTicket;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -19,136 +22,19 @@ import java.util.stream.Collectors;
@Component
public class PlanetOperateSettleTask {
@Autowired
private PlanetLandmarkRoundMapper landmarkRoundMapper;
@Autowired
private PlanetLandmarkBidMapper landmarkBidMapper;
@Autowired
private PlanetLandmarkConfigMapper landmarkConfigMapper;
@Autowired
private PlanetLandmarkRewardLogMapper landmarkRewardLogMapper;
@Autowired
private PlanetEconomyAuditMapper economyAuditMapper;
@Autowired
private PlanetTicketLogMapper ticketLogMapper;
@Autowired
private PlanetTicketMapper ticketMapper;
@Autowired
private PlanetTicketService ticketService;
private static String genId() {
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 * * ?")
@Transactional(rollbackFor = Exception.class)
@ -175,7 +61,6 @@ public class PlanetOperateSettleTask {
int burnTickets = 0;
int plantOutput = 0;
int searchTransfer = 0;
int landmarkBurn = 0;
int upgradeBurn = 0;
int poolBurn = 0;
for (PlanetTicketLog log : logs) {
@ -188,8 +73,7 @@ public class PlanetOperateSettleTask {
final String type = log.getType();
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_LANDMARK_BID.equals(type)) landmarkBurn += 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_TOWER_UPGRADE.equals(type)) upgradeBurn += Math.max(0, -change);
if (PlanetConstant.TICKET_TYPE_DRAW.equals(type)) poolBurn += Math.max(0, -change);
}
final Long activeUsers = ticketMapper.selectCount(new LambdaQueryWrapper<PlanetTicket>()
@ -207,7 +91,7 @@ public class PlanetOperateSettleTask {
audit.setNetTickets(newTickets - burnTickets);
audit.setPlantOutput(plantOutput);
audit.setSearchTransfer(searchTransfer);
audit.setLandmarkBurn(landmarkBurn);
audit.setLandmarkBurn(0);
audit.setUpgradeBurn(upgradeBurn);
audit.setPoolBurn(poolBurn);
audit.setActiveUserCount(activeUsers == null ? 0 : activeUsers.intValue());

Loading…
Cancel
Save