优化中奖,后台新增彩金池实时显示
This commit is contained in:
@@ -14,10 +14,22 @@
|
||||
<span class="text-gray-500">池子名称:</span>
|
||||
<span>{{ pool.name }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-gray-500">池子盈利:</span>
|
||||
<span class="font-mono text-lg" :class="profitAmountClass">{{ displayProfitAmount }}</span>
|
||||
<span class="text-gray-400 text-sm">(实时,不可修改)</span>
|
||||
<div class="profit-row mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-gray-500">彩金池盈利(profit_amount):</span>
|
||||
<span class="font-mono text-lg" :class="profitAmountClass">{{ displayProfitAmount }}</span>
|
||||
<span class="realtime-badge">实时</span>
|
||||
</div>
|
||||
<div class="profit-calc-hint">
|
||||
计算方式:每局抽奖累加 (100 − 该局中奖档位 real_ev),弹窗打开期间每 2 秒自动刷新
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-block">
|
||||
<div class="tip-title">抽奖档位规则</div>
|
||||
<div class="tip-content">
|
||||
当彩金池盈利 <strong>低于安全线</strong> 时,按<strong>玩家</strong>的 T*_weight 权重抽取抽奖档位;
|
||||
当彩金池盈利 <strong>高于或等于安全线</strong> 时,按<strong>当前彩金池</strong>的 T*_weight 权重抽取档位。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
|
||||
@@ -233,4 +245,48 @@
|
||||
.pool-info {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.profit-row {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.profit-calc-hint {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.realtime-badge {
|
||||
font-size: 11px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
background: var(--el-color-success-light-9);
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.tip-block {
|
||||
margin-top: 12px;
|
||||
padding: 10px 12px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid var(--el-color-primary);
|
||||
}
|
||||
|
||||
.tip-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.tip-content {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tip-content strong {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -72,17 +72,28 @@ class PlayStartLogic
|
||||
$config = $ticketType === self::LOTTERY_TYPE_PAID
|
||||
? ($lotteryService->getConfigType0Id() ? DiceLotteryPoolConfig::find($lotteryService->getConfigType0Id()) : null)
|
||||
: ($lotteryService->getConfigType1Id() ? DiceLotteryPoolConfig::find($lotteryService->getConfigType1Id()) : null);
|
||||
// 未找到付费/免费对应配置时,统一回退到 type=0 的彩金池,保证所有玩家累加同一彩金池
|
||||
if (!$config) {
|
||||
$config = DiceLotteryPoolConfig::where('type', 0)->find();
|
||||
}
|
||||
if (!$config) {
|
||||
throw new ApiException('奖池配置不存在');
|
||||
}
|
||||
|
||||
// 按玩家权重抽取档位;若该档位无奖励或该方向下均无可用路径则重新摇取档位
|
||||
// 彩金池盈利低于安全线时按玩家权重抽档,高于或等于安全线时按奖池权重抽档
|
||||
$poolProfit = (float) ($config->profit_amount ?? $config->ev ?? 0);
|
||||
$safetyLine = (int) ($config->safety_line ?? 0);
|
||||
$usePoolWeights = $poolProfit >= $safetyLine;
|
||||
|
||||
// 按上述规则抽取档位;若该档位无奖励或该方向下均无可用路径则重新摇取档位
|
||||
$maxTierRetry = 10;
|
||||
$chosen = null;
|
||||
$startCandidates = [];
|
||||
$tier = null;
|
||||
for ($tierAttempt = 0; $tierAttempt < $maxTierRetry; $tierAttempt++) {
|
||||
$tier = LotteryService::drawTierByPlayerWeights($player);
|
||||
$tier = $usePoolWeights
|
||||
? LotteryService::drawTierByWeights($config)
|
||||
: LotteryService::drawTierByPlayerWeights($player);
|
||||
$tierRewards = DiceRewardConfig::getCachedByTier($tier);
|
||||
if (empty($tierRewards)) {
|
||||
Log::warning("档位 {$tier} 无任何奖励配置,重新摇取档位");
|
||||
@@ -122,6 +133,7 @@ class PlayStartLogic
|
||||
// 当抽到的 grid_number 为 5/10/15/20/25/30 时,可出豹子;其中 grid_number=5 与 30 固定 100% 豹子(BIGWIN 约定)
|
||||
$superWinCoin = 0;
|
||||
$isWin = 0;
|
||||
$bigWinRealEv = 0.0; // BIGWIN 档位的真实资金结算,用于从彩金池盈利中一并扣除
|
||||
if (in_array($rollNumber, self::SUPER_WIN_GRID_NUMBERS, true)) {
|
||||
$bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber);
|
||||
$alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true);
|
||||
@@ -136,9 +148,12 @@ class PlayStartLogic
|
||||
if ($doSuperWin) {
|
||||
$rollArray = $this->getSuperWinRollArray($rollNumber);
|
||||
$isWin = 1;
|
||||
$superWinCoin = $bigWinConfig !== null
|
||||
? 100 + (float) ($bigWinConfig['real_ev'] ?? 0)
|
||||
: self::SUPER_WIN_BONUS;
|
||||
if ($bigWinConfig !== null) {
|
||||
$bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0);
|
||||
$superWinCoin = 100 + $bigWinRealEv;
|
||||
} else {
|
||||
$superWinCoin = self::SUPER_WIN_BONUS;
|
||||
}
|
||||
} else {
|
||||
$rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber);
|
||||
}
|
||||
@@ -174,6 +189,7 @@ class PlayStartLogic
|
||||
$rewardWinCoin,
|
||||
$isWin,
|
||||
$realEv,
|
||||
$bigWinRealEv,
|
||||
$direction,
|
||||
$startIndex,
|
||||
$targetIndex,
|
||||
@@ -230,12 +246,22 @@ class PlayStartLogic
|
||||
|
||||
$p->save();
|
||||
|
||||
// 累加彩金池盈利额度(累加值为 -real_ev)。若 dice_lottery_config 表有 ev 字段则执行
|
||||
// 彩金池盈利累加:每局累加 (100 - 本局总 real_ev),其中本局总 real_ev = 普通档位 real_ev + BIGWIN.real_ev(如触发)
|
||||
// 需确保表有 profit_amount 字段(见 db/dice_lottery_config_add_profit_amount.sql)
|
||||
$totalRealEv = $realEv + $bigWinRealEv;
|
||||
$addProfit = 100 - $totalRealEv;
|
||||
try {
|
||||
DiceLotteryPoolConfig::where('id', $configId)->update([
|
||||
'ev' => Db::raw('IFNULL(ev,0) - ' . (float) $realEv),
|
||||
'profit_amount' => Db::raw('IFNULL(profit_amount,0) + ' . (float) $addProfit),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('彩金池盈利累加失败,请确认表 dice_lottery_config 已存在 profit_amount 字段并执行 db/dice_lottery_config_add_profit_amount.sql', [
|
||||
'config_id' => $configId,
|
||||
'add_profit' => $addProfit,
|
||||
'real_ev' => $realEv,
|
||||
'bigwin_ev' => $bigWinRealEv,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
} catch (\Throwable $_) {
|
||||
}
|
||||
|
||||
DicePlayerWalletRecord::create([
|
||||
|
||||
@@ -31,7 +31,7 @@ class DiceLotteryPoolConfigLogic extends BaseLogic
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前彩金池:从 Redis 读取,若无则按 type=0 配置创建并写入 Redis,返回含 profit_amount(ev) 的完整数据
|
||||
* 获取当前彩金池:从 Redis 读取实例,profit_amount 每次从 DB 实时读取以保证与抽奖累加一致
|
||||
*
|
||||
* @return array{id:int,name:string,safety_line:int,t1_weight:int,t2_weight:int,t3_weight:int,t4_weight:int,t5_weight:int,profit_amount:float}
|
||||
*/
|
||||
@@ -42,8 +42,13 @@ class DiceLotteryPoolConfigLogic extends BaseLogic
|
||||
$data = json_decode($cached, true);
|
||||
if (is_array($data)) {
|
||||
$config = DiceLotteryPoolConfig::find($data['id'] ?? 0);
|
||||
$ev = $config && isset($config->ev) ? (float) $config->ev : (float) ($data['profit_amount'] ?? 0);
|
||||
$data['profit_amount'] = $ev;
|
||||
$profit = 0.0;
|
||||
if ($config) {
|
||||
$profit = isset($config->profit_amount) ? (float) $config->profit_amount : (isset($config->ev) ? (float) $config->ev : 0.0);
|
||||
} else {
|
||||
$profit = (float) ($data['profit_amount'] ?? 0);
|
||||
}
|
||||
$data['profit_amount'] = $profit;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -52,23 +57,24 @@ class DiceLotteryPoolConfigLogic extends BaseLogic
|
||||
throw new ApiException('未找到 type=0 的奖池配置,请先创建');
|
||||
}
|
||||
$row = $config->toArray();
|
||||
$profitAmount = isset($row['profit_amount']) ? (float) $row['profit_amount'] : (isset($row['ev']) ? (float) $row['ev'] : 0.0);
|
||||
$pool = [
|
||||
'id' => (int) $row['id'],
|
||||
'name' => (string) ($row['name'] ?? ''),
|
||||
'safety_line' => (int) ($row['safety_line'] ?? 0),
|
||||
't1_weight' => (int) ($row['t1_weight'] ?? 0),
|
||||
't2_weight' => (int) ($row['t2_weight'] ?? 0),
|
||||
't3_weight' => (int) ($row['t3_weight'] ?? 0),
|
||||
't4_weight' => (int) ($row['t4_weight'] ?? 0),
|
||||
't5_weight' => (int) ($row['t5_weight'] ?? 0),
|
||||
'profit_amount' => isset($row['ev']) ? (float) $row['ev'] : 0.0,
|
||||
'id' => (int) $row['id'],
|
||||
'name' => (string) ($row['name'] ?? ''),
|
||||
'safety_line' => (int) ($row['safety_line'] ?? 0),
|
||||
't1_weight' => (int) ($row['t1_weight'] ?? 0),
|
||||
't2_weight' => (int) ($row['t2_weight'] ?? 0),
|
||||
't3_weight' => (int) ($row['t3_weight'] ?? 0),
|
||||
't4_weight' => (int) ($row['t4_weight'] ?? 0),
|
||||
't5_weight' => (int) ($row['t5_weight'] ?? 0),
|
||||
'profit_amount' => $profitAmount,
|
||||
];
|
||||
Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE);
|
||||
return $pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前彩金池:仅允许修改 safety_line、t1_weight~t5_weight,不同步 profit_amount(ev)
|
||||
* 更新当前彩金池:仅允许修改 safety_line、t1_weight~t5_weight,不修改 profit_amount
|
||||
* 同时更新 Redis 与 DB 中 type=0 的记录
|
||||
*
|
||||
* @param array{safety_line?:int,t1_weight?:int,t2_weight?:int,t3_weight?:int,t4_weight?:int,t5_weight?:int} $data
|
||||
@@ -98,7 +104,9 @@ class DiceLotteryPoolConfigLogic extends BaseLogic
|
||||
DiceLotteryPoolConfig::where('id', $id)->update($update);
|
||||
$pool = array_merge($pool, $update);
|
||||
$refreshed = DiceLotteryPoolConfig::find($id);
|
||||
$pool['profit_amount'] = $refreshed && isset($refreshed->ev) ? (float) $refreshed->ev : (float) ($pool['profit_amount'] ?? 0);
|
||||
$pool['profit_amount'] = $refreshed && (isset($refreshed->profit_amount) || isset($refreshed->ev))
|
||||
? (float) ($refreshed->profit_amount ?? $refreshed->ev)
|
||||
: (float) ($pool['profit_amount'] ?? 0);
|
||||
Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use plugin\saiadmin\basic\think\BaseModel;
|
||||
* @property $t3_weight T3池权重
|
||||
* @property $t4_weight T4池权重
|
||||
* @property $t5_weight T5池权重
|
||||
* @property $ev 池子累计盈利(游戏结算时累加,仅展示不可编辑)
|
||||
* @property $profit_amount 池子累计盈利(每局抽奖累加 100-real_ev,仅展示不可编辑)
|
||||
*/
|
||||
class DiceLotteryPoolConfig extends BaseModel
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user