first commit
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
package com.ruoyi.reward.contract.admin.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class AdjustRewardPoolRequest {
|
||||
// tighten(抽水: bet→profit) | loosen(放水: profit→bet)
|
||||
private String direction;
|
||||
private BigDecimal amount;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.reward.contract.admin.response;
|
||||
|
||||
import com.ruoyi.reward.model.GloalRewardConfig;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class QueryGlobalRewardConfig {
|
||||
private GloalRewardConfig config;
|
||||
|
||||
// 全局奖池数据
|
||||
private BigDecimal totalWin;
|
||||
private BigDecimal totalBet;
|
||||
private BigDecimal netProfit;
|
||||
private BigDecimal availableQuota;
|
||||
private BigDecimal originalTotalBet;
|
||||
private double rtp;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.ruoyi.reward.controller;
|
||||
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.reward.contract.admin.request.AdjustRewardPoolRequest;
|
||||
import com.ruoyi.reward.contract.admin.response.QueryGlobalRewardConfig;
|
||||
import com.ruoyi.reward.model.GloalRewardConfig;
|
||||
import com.ruoyi.reward.service.GlobalRewardPoolService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Api(tags = "全局奖池配置")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/admin/globalrewardpool")
|
||||
public class AdminGlobalRewardPoolController {
|
||||
@Autowired
|
||||
private GlobalRewardPoolService globalRewardPoolService;
|
||||
|
||||
@ApiOperation("获取奖池配置和状态")
|
||||
@GetMapping("/config")
|
||||
public R<QueryGlobalRewardConfig> getGameConfig() {
|
||||
var config = globalRewardPoolService.getGameConfig();
|
||||
var cache = globalRewardPoolService.getCache();
|
||||
QueryGlobalRewardConfig result = new QueryGlobalRewardConfig();
|
||||
result.setConfig(config);
|
||||
result.setTotalWin(cache.getTotalWin());
|
||||
result.setTotalBet(cache.getTotalBet());
|
||||
result.setNetProfit(cache.getNetProfit());
|
||||
result.setAvailableQuota(globalRewardPoolService.availableQuota());
|
||||
result.setOriginalTotalBet(cache.getTotalBet().add(cache.getNetProfit()));
|
||||
result.setRtp(globalRewardPoolService.rtp());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
@ApiOperation("更新奖池配置")
|
||||
@PostMapping("/config")
|
||||
public R<Void> updateGameConfig(@RequestBody GloalRewardConfig params) {
|
||||
String msg = globalRewardPoolService.updateGameConfig(params);
|
||||
if (msg != null && !msg.isEmpty())
|
||||
return R.fail(msg);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@ApiOperation("重置奖池缓存")
|
||||
@PostMapping("/reset")
|
||||
public R<?> resetRewardPool() {
|
||||
globalRewardPoolService.resetCache();
|
||||
return R.ok(null, "奖池缓存已清空");
|
||||
}
|
||||
|
||||
@ApiOperation("调整奖池(抽水/放水)")
|
||||
@PostMapping("/adjust")
|
||||
public R<?> adjustRewardPool(@RequestBody AdjustRewardPoolRequest req) {
|
||||
if (req.getAmount() == null || req.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return R.fail("金额必须大于0");
|
||||
}
|
||||
if (!"tighten".equals(req.getDirection()) && !"loosen".equals(req.getDirection())) {
|
||||
return R.fail("方向必须为 tighten 或 loosen");
|
||||
}
|
||||
globalRewardPoolService.adjust(req.getDirection(), req.getAmount());
|
||||
return R.ok(null, "调整成功");
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.ruoyi.reward.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GloalRewardConfig {
|
||||
// 利润率.抽水比例。 如0.3表示下注额的0.3倍将会存入网站,只有下注额的0.7倍才会放入奖池中
|
||||
private double profitRate;
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
package com.ruoyi.reward.model.cache;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class GlobalRewardPoolCache {
|
||||
private BigDecimal totalBet;
|
||||
private BigDecimal totalWin;
|
||||
private BigDecimal netProfit;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.ruoyi.reward.repository;
|
||||
|
||||
import com.ruoyi.framework.manager.AsyncManager;
|
||||
import com.ruoyi.reward.model.cache.GlobalRewardPoolCache;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Component
|
||||
public class GlobalRewardPoolCacheRepository {
|
||||
|
||||
@Autowired
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
private final static String GLOBAL_REWARD_POOL_CACHE = "ruoyi:global:reward:pool";
|
||||
|
||||
public void incrementalProfit(BigDecimal profit) {
|
||||
AsyncManager.me().run(()->{
|
||||
redisTemplate.opsForValue().increment(GLOBAL_REWARD_POOL_CACHE + ":profit", profit.doubleValue());
|
||||
});
|
||||
}
|
||||
|
||||
public void incrementalBet(BigDecimal totalBet) {
|
||||
redisTemplate.opsForValue().increment(GLOBAL_REWARD_POOL_CACHE + ":bet", totalBet.doubleValue());
|
||||
}
|
||||
|
||||
public void incrementalWin(BigDecimal totalWin) {
|
||||
redisTemplate.opsForValue().increment(GLOBAL_REWARD_POOL_CACHE + ":win", totalWin.doubleValue());
|
||||
}
|
||||
|
||||
public GlobalRewardPoolCache getCache() {
|
||||
var totalBetS = redisTemplate.opsForValue().get(GLOBAL_REWARD_POOL_CACHE + ":bet");
|
||||
var totalWinS = redisTemplate.opsForValue().get(GLOBAL_REWARD_POOL_CACHE + ":win");
|
||||
var totalProfitS = redisTemplate.opsForValue().get(GLOBAL_REWARD_POOL_CACHE + ":profit");
|
||||
var cache = new GlobalRewardPoolCache();
|
||||
cache.setTotalBet(totalBetS == null ? BigDecimal.ZERO : new BigDecimal(totalBetS.toString()));
|
||||
cache.setTotalWin(totalWinS == null ? BigDecimal.ZERO : new BigDecimal(totalWinS.toString()));
|
||||
cache.setNetProfit(totalProfitS == null ? BigDecimal.ZERO : new BigDecimal(totalProfitS.toString()));
|
||||
return cache;
|
||||
}
|
||||
|
||||
// 同步调整 bet 和 profit(允许变负)
|
||||
public void adjustPool(BigDecimal betDelta, BigDecimal profitDelta) {
|
||||
redisTemplate.opsForValue().increment(GLOBAL_REWARD_POOL_CACHE + ":bet", betDelta.doubleValue());
|
||||
redisTemplate.opsForValue().increment(GLOBAL_REWARD_POOL_CACHE + ":profit", profitDelta.doubleValue());
|
||||
}
|
||||
|
||||
// 清空奖池缓存(总下注、总返奖、累计抽水归零)
|
||||
public void resetCache() {
|
||||
redisTemplate.delete(GLOBAL_REWARD_POOL_CACHE + ":bet");
|
||||
redisTemplate.delete(GLOBAL_REWARD_POOL_CACHE + ":win");
|
||||
redisTemplate.delete(GLOBAL_REWARD_POOL_CACHE + ":profit");
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.ruoyi.reward.service;
|
||||
|
||||
import com.ruoyi.common.utils.json.JsonUtils;
|
||||
import com.ruoyi.reward.model.GloalRewardConfig;
|
||||
import com.ruoyi.reward.model.cache.GlobalRewardPoolCache;
|
||||
import com.ruoyi.reward.repository.GlobalRewardPoolCacheRepository;
|
||||
import com.ruoyi.system.domain.SysConfig;
|
||||
import com.ruoyi.system.mapper.SysConfigMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
@Service
|
||||
public class GlobalRewardPoolService {
|
||||
|
||||
private static final String CONFIG_KEY = "global.reward.setting";
|
||||
|
||||
@Autowired
|
||||
private SysConfigMapper sysConfigMapper;
|
||||
@Autowired
|
||||
private GlobalRewardPoolCacheRepository poolCacheRepository;
|
||||
|
||||
public void incrementalBet(BigDecimal totalBet) {
|
||||
BigDecimal profit = totalBet.abs().multiply(BigDecimal.valueOf(getGameConfig().getProfitRate()));
|
||||
poolCacheRepository.incrementalProfit(profit);
|
||||
poolCacheRepository.incrementalBet(totalBet.abs().subtract(profit));
|
||||
}
|
||||
|
||||
public void incrementalWin(BigDecimal totalWin) {
|
||||
poolCacheRepository.incrementalWin(totalWin.abs());
|
||||
}
|
||||
|
||||
public GlobalRewardPoolCache getCache() {
|
||||
return poolCacheRepository.getCache();
|
||||
}
|
||||
|
||||
// 清空奖池缓存(总下注、总返奖归零)
|
||||
public void resetCache() {
|
||||
poolCacheRepository.resetCache();
|
||||
}
|
||||
|
||||
// 手动调整奖池:tighten(抽水 bet→profit) | loosen(放水 profit→bet),允许变负
|
||||
public void adjust(String direction, BigDecimal amount) {
|
||||
if ("tighten".equals(direction)) {
|
||||
poolCacheRepository.adjustPool(amount.negate(), amount);
|
||||
} else {
|
||||
poolCacheRepository.adjustPool(amount, amount.negate());
|
||||
}
|
||||
}
|
||||
|
||||
// 奖池净利润
|
||||
public BigDecimal netProfits() {
|
||||
var cache = poolCacheRepository.getCache();
|
||||
return cache.getNetProfit();
|
||||
}
|
||||
|
||||
// 奖池可用额度 totalBet - totalWin
|
||||
public BigDecimal availableQuota() {
|
||||
var cache = poolCacheRepository.getCache();
|
||||
return cache.getTotalBet().subtract(cache.getTotalWin());
|
||||
}
|
||||
|
||||
// 奖池rtp totalWin/totalBet
|
||||
public double rtp() {
|
||||
var cache = poolCacheRepository.getCache();
|
||||
BigDecimal divisor = cache.getTotalBet().add(cache.getNetProfit());
|
||||
if (divisor.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return cache.getTotalWin().divide(divisor, 4, RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
}
|
||||
|
||||
public GloalRewardConfig getGameConfig() {
|
||||
SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique(CONFIG_KEY);
|
||||
if (sysConfig == null) {
|
||||
GloalRewardConfig config = new GloalRewardConfig();
|
||||
config.setProfitRate(0.1);
|
||||
return config;
|
||||
}
|
||||
return JsonUtils.fromSnakeCaseJson(sysConfig.getConfigValue(), GloalRewardConfig.class);
|
||||
}
|
||||
|
||||
|
||||
public String updateGameConfig(GloalRewardConfig params) {
|
||||
if (params.getProfitRate() < 0 || params.getProfitRate() > 1) {
|
||||
return "profitRate必须在[0,1]之间";
|
||||
}
|
||||
|
||||
SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique(CONFIG_KEY);
|
||||
if (sysConfig == null) {
|
||||
sysConfig = new SysConfig() {{
|
||||
setConfigName("全局奖池配置");
|
||||
setConfigKey(CONFIG_KEY);
|
||||
setConfigValue(JsonUtils.toSnakeCaseJson(params));
|
||||
}};
|
||||
sysConfigMapper.insertConfig(sysConfig);
|
||||
} else {
|
||||
sysConfig.setConfigValue(JsonUtils.toSnakeCaseJson(params));
|
||||
sysConfigMapper.updateConfig(sysConfig);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user