feat: 为赔率项增加 dimension 字段并支持按维度配置佣金,调整后台配置导航权限

This commit is contained in:
2026-05-21 17:54:31 +08:00
parent 7a6048de10
commit c1c25e3143
7 changed files with 150 additions and 31 deletions

View File

@@ -62,6 +62,7 @@ final class OddsStreamService
'version_id' => $draft->id,
'play_code' => $row->play_code,
'prize_scope' => $row->prize_scope,
'dimension' => $row->dimension,
'odds_value' => $row->odds_value,
'rebate_rate' => $row->rebate_rate,
'commission_rate' => $row->commission_rate,
@@ -77,6 +78,7 @@ final class OddsStreamService
'version_id' => $draft->id,
'play_code' => $pt->play_code,
'prize_scope' => $scope,
'dimension' => $pt->dimension,
'odds_value' => $oddsValue,
'rebate_rate' => 0,
'commission_rate' => 0,
@@ -107,6 +109,7 @@ final class OddsStreamService
'version_id' => $draft->id,
'play_code' => (string) $row['play_code'],
'prize_scope' => (string) $row['prize_scope'],
'dimension' => isset($row['dimension']) ? (int) $row['dimension'] : null,
'odds_value' => (int) $row['odds_value'],
'rebate_rate' => (float) ($row['rebate_rate'] ?? 0),
'commission_rate' => (float) ($row['commission_rate'] ?? 0),
@@ -221,6 +224,7 @@ final class OddsStreamService
foreach ($items as $index => $row) {
$playCode = (string) $row->play_code;
$scope = (string) $row->prize_scope;
$dimension = $row->dimension;
$currencyCode = strtoupper((string) $row->currency_code);
$oddsValue = (int) $row->odds_value;
$rebateRate = (float) $row->rebate_rate;
@@ -239,6 +243,10 @@ final class OddsStreamService
$errors["items.$index.currency_code"][] = '币种不可下注';
}
if ($dimension !== null && ! in_array($dimension, [2, 3, 4], true)) {
$errors["items.$index.dimension"][] = '维度必须是 2、3 或 4';
}
if (isset($seenKeys[$key])) {
$errors["items.$index"][] = '同一玩法、档位、币种存在重复赔率项';
}

View File

@@ -48,9 +48,11 @@ final class PlayRuleEngine
$unitBetAmount = $this->resolveUnitBetAmount($playCode, $amount, $combinationCount);
$totalBetAmount = $this->resolveTotalBetAmount($playCode, $amount, $unitBetAmount, $combinationCount);
$dimensionInt = $this->toDimensionInt(is_string($dimension) ? $dimension : null, $playConfig);
$primaryOdds = $this->pickPrimaryOdds($oddsItems);
$rebateRate = (float) $primaryOdds->rebate_rate;
$commissionRate = (float) $primaryOdds->commission_rate;
// 佣金按维度2D/3D/4D配置从 odds_items 中查找匹配维度的佣金率
$commissionRate = $this->pickCommissionByDimension($oddsItems, $dimensionInt);
$actualDeductAmount = max(0, (int) floor($totalBetAmount * (1 - $rebateRate)));
$maxOdds = $oddsItems->max(fn (OddsItem $row) => (int) $row->odds_value) ?? 0;
$estimatedPayoutPerCombo = (int) floor($unitBetAmount * ($maxOdds / 10000));
@@ -302,6 +304,28 @@ final class PlayRuleEngine
return $oddsItems->firstOrFail();
}
/**
* 按维度2D/3D/4D获取佣金率
*
* @param Collection<int, OddsItem> $oddsItems
*/
private function pickCommissionByDimension(Collection $oddsItems, ?int $dimension): float
{
if ($dimension === null) {
// 如果维度为空,返回第一个 odds item 的佣金率(向后兼容)
return (float) ($oddsItems->first()?->commission_rate ?? 0);
}
// 查找匹配维度的 odds item
$dimensionItem = $oddsItems->firstWhere('dimension', $dimension);
if ($dimensionItem !== null) {
return (float) $dimensionItem->commission_rate;
}
// 如果没有找到匹配维度的,返回第一个的佣金率(向后兼容)
return (float) ($oddsItems->first()?->commission_rate ?? 0);
}
private function toDimensionInt(?string $dimension, PlayConfigItem $playConfig): ?int
{
return match ($dimension) {