优化中奖权重计算方式

This commit is contained in:
2026-03-12 17:17:00 +08:00
parent 064ce06393
commit 7e4ba86afa
25 changed files with 2344 additions and 403 deletions

View File

@@ -12,7 +12,7 @@ use app\api\util\ReturnCode;
use app\dice\model\config\DiceConfig;
use app\dice\model\play_record\DicePlayRecord;
use app\dice\model\player\DicePlayer;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward\DiceRewardConfig;
use app\api\controller\BaseController;
use app\api\util\ApiLang;
use plugin\saiadmin\exception\ApiException;

View File

@@ -10,7 +10,8 @@ use app\dice\model\play_record\DicePlayRecord;
use app\dice\model\player\DicePlayer;
use app\dice\model\player_ticket_record\DicePlayerTicketRecord;
use app\dice\model\player_wallet_record\DicePlayerWalletRecord;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward\DiceReward;
use app\dice\model\reward\DiceRewardConfig;
use plugin\saiadmin\exception\ApiException;
use support\Log;
use support\think\Cache;
@@ -85,7 +86,9 @@ class PlayStartLogic
$safetyLine = (int) ($config->safety_line ?? 0);
$usePoolWeights = $poolProfit >= $safetyLine;
// 按档位 T1-T5 抽取后,直接按该档位内 weight 抽取一条 DiceRewardConfig得到 grid_number
// 按档位 T1-T5 抽取后,从 DiceReward 表按当前方向取该档位数据,再按 weight 抽取一条得到 grid_number
$rewardInstance = DiceReward::getCachedInstance();
$byTierDirection = $rewardInstance['by_tier_direction'] ?? [];
$maxTierRetry = 10;
$chosen = null;
$tier = null;
@@ -93,9 +96,9 @@ class PlayStartLogic
$tier = $usePoolWeights
? LotteryService::drawTierByWeights($config)
: LotteryService::drawTierByPlayerWeights($player);
$tierRewards = DiceRewardConfig::getCachedByTier($tier);
$tierRewards = $byTierDirection[$tier][$direction] ?? [];
if (empty($tierRewards)) {
Log::warning("档位 {$tier} 无任何奖励配置,重新摇取档位");
Log::warning("档位 {$tier} 方向 {$direction} 无任何 DiceReward,重新摇取档位");
continue;
}
try {
@@ -110,23 +113,18 @@ class PlayStartLogic
break;
}
if ($chosen === null) {
Log::error("多次摇取档位后仍无有效权重配置");
Log::error("多次摇取档位后仍无有效 DiceReward");
throw new ApiException('暂无可用奖励配置');
}
$chosenId = (int) ($chosen['id'] ?? 0);
// 起始索引:根据 direction 取 s_start_index(顺时针)或 n_start_index逆时针结束索引当前中奖配置 id
$startIndex = $direction === 0
? (int) ($chosen['s_start_index'] ?? 0)
: (int) ($chosen['n_start_index'] ?? 0);
$targetIndex = $chosenId;
$startIndex = (int) ($chosen['start_index'] ?? 0);
$targetIndex = (int) ($chosen['end_index'] ?? 0);
$rollNumber = (int) ($chosen['grid_number'] ?? 0);
$realEv = (float) ($chosen['real_ev'] ?? 0);
$isTierT5 = (string) ($chosen['tier'] ?? '') === 'T5';
// T5再来一次摇色子中奖平台币 = 配置的 real_ev其他档位 = 100 + real_ev
$rewardWinCoin = $isTierT5 ? $realEv : (100 + $realEv);
// 流程:先抽档位 T1-T5再按档位内权重抽色子点数5 和 30 抽到即豹子10/15/20/25 按 BIGWIN weight 判定是否中大奖(豹子如 [4,4,4,4,4]
// 豹子判定5/30 必豹子10/15/20/25 按 DiceRewardConfig 中 BIGWIN 该点数的 weight 判定0-1000010000=100%
$superWinCoin = 0;
$isWin = 0;
$bigWinRealEv = 0.0;
@@ -135,21 +133,26 @@ class PlayStartLogic
$alwaysSuperWin = in_array($rollNumber, self::SUPER_WIN_ALWAYS_GRID_NUMBERS, true);
$doSuperWin = $alwaysSuperWin;
if (!$doSuperWin) {
$weight = $bigWinConfig !== null
? max(1, min(10000, (int) ($bigWinConfig['weight'] ?? 1)))
: 10000;
$bigWinWeight = 10000;
if ($bigWinConfig !== null && isset($bigWinConfig['weight'])) {
$bigWinWeight = min(10000, max(0, (int) $bigWinConfig['weight']));
$bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0);
}
$roll = (random_int(0, PHP_INT_MAX - 1) / (float) PHP_INT_MAX);
$doSuperWin = $roll < ($weight / 10000.0);
$doSuperWin = $bigWinWeight > 0 && $roll < ($bigWinWeight / 10000.0);
} else {
if ($bigWinConfig !== null) {
$bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0);
}
}
if ($doSuperWin) {
$rollArray = $this->getSuperWinRollArray($rollNumber);
$isWin = 1;
if ($bigWinConfig !== null) {
$bigWinRealEv = (float) ($bigWinConfig['real_ev'] ?? 0);
$superWinCoin = $bigWinRealEv;
} else {
$superWinCoin = self::SUPER_WIN_BONUS;
}
$superWinCoin = $bigWinRealEv > 0 ? $bigWinRealEv : self::SUPER_WIN_BONUS;
// 中 BIGWIN 豹子:不走原奖励流程,不记录原奖励,不触发 T5 再来一次,仅发放豹子奖金
$rewardWinCoin = 0;
$realEv = 0;
$isTierT5 = false;
} else {
$rollArray = $this->generateNonSuperWinRollArrayWithSum($rollNumber);
}
@@ -164,11 +167,11 @@ class PlayStartLogic
$startIndex,
$targetIndex
));
$winCoin = $superWinCoin + $rewardWinCoin; // 赢取平台币 = 中大奖 + 摇色子中奖
$winCoin = $superWinCoin + $rewardWinCoin; // 赢取平台币 = 中大奖 + 摇色子中奖(豹子时 rewardWinCoin 已为 0
$record = null;
$configId = (int) $config->id;
$rewardId = $chosenId;
$rewardId = ($isWin === 1 && $superWinCoin > 0) ? 0 : $targetIndex; // 中豹子不记录原奖励配置 id
$configName = (string) ($config->name ?? '');
$adminId = ($player->admin_id ?? null) ? (int) $player->admin_id : null;
try {

View File

@@ -12,7 +12,7 @@ use app\dice\logic\play_record\DicePlayRecordLogic;
use app\dice\validate\play_record\DicePlayRecordValidate;
use app\dice\model\player\DicePlayer;
use app\dice\model\lottery_pool_config\DiceLotteryPoolConfig;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward\DiceRewardConfig;
use plugin\saiadmin\service\Permission;
use support\Request;
use support\Response;

View File

@@ -0,0 +1,120 @@
<?php
// +----------------------------------------------------------------------
// | saiadmin [ saiadmin快速开发框架 ]
// +----------------------------------------------------------------------
namespace app\dice\controller\reward;
use app\dice\logic\reward\DiceRewardLogic;
use app\dice\model\reward\DiceReward;
use plugin\saiadmin\basic\BaseController;
use plugin\saiadmin\service\Permission;
use support\Request;
use support\Response;
/**
* 奖励对照控制器dice_reward按方向分页列表 + 权重编辑)
*/
class DiceRewardController extends BaseController
{
/**
* 分页列表,按 direction 区分顺时针(0)/逆时针(1)
* 参数direction(必), tier(选), page, limit, orderField, orderType
*/
#[Permission('奖励对照列表', 'dice:reward:index:index')]
public function index(Request $request): Response
{
$direction = $request->input('direction', null);
if ($direction === null || $direction === '') {
return $this->fail('请传入 direction0=顺时针 1=逆时针)');
}
$direction = (int) $direction;
if (!in_array($direction, [DiceReward::DIRECTION_CLOCKWISE, DiceReward::DIRECTION_COUNTERCLOCKWISE], true)) {
return $this->fail('direction 必须为 0顺时针或 1逆时针');
}
$tier = $request->input('tier', '');
$page = (int) $request->input('page', 1);
$limit = (int) $request->input('limit', 10);
$orderField = $request->input('orderField', 'r.tier');
$orderType = $request->input('orderType', 'asc');
$logic = new DiceRewardLogic();
$data = $logic->getListWithConfig($direction, [
'tier' => $tier,
'orderField' => $orderField,
'orderType' => $orderType,
], $page, $limit);
return $this->success($data);
}
/**
* 权重编辑弹窗:按档位分组获取当前方向的配置+权重(单方向,用于兼容)
* 参数direction 0=顺时针 1=逆时针
*/
#[Permission('奖励对照列表', 'dice:reward:index:index')]
public function weightRatioList(Request $request): Response
{
$direction = (int) $request->input('direction', 0);
if (!in_array($direction, [DiceReward::DIRECTION_CLOCKWISE, DiceReward::DIRECTION_COUNTERCLOCKWISE], true)) {
$direction = DiceReward::DIRECTION_CLOCKWISE;
}
$logic = new DiceRewardLogic();
$data = $logic->getListGroupedByTierForDirection($direction);
return $this->success($data);
}
/**
* 权重编辑弹窗:按档位分组获取配置+顺时针/逆时针权重dice_reward 双方向)
* 返回与 reward_config 权重配比一致结构,供奖励对照页弹窗同时编辑 direction=0/1
*/
#[Permission('奖励对照列表', 'dice:reward:index:index')]
public function weightRatioListWithDirection(Request $request): Response
{
$logic = new DiceRewardLogic();
$data = $logic->getListGroupedByTierWithDirection();
return $this->success($data);
}
/**
* 权重编辑弹窗:按方向+点数批量更新权重(写入 dice_reward
* 参数items: [{ grid_number, weight_clockwise, weight_counterclockwise }, ...]
*/
#[Permission('奖励对照修改', 'dice:reward:index:update')]
public function batchUpdateWeights(Request $request): Response
{
$items = $request->post('items', []);
if (!is_array($items)) {
return $this->fail('参数 items 必须为数组');
}
try {
$logic = new DiceRewardLogic();
$logic->batchUpdateWeights($items);
return $this->success('保存成功');
} catch (\plugin\saiadmin\exception\ApiException $e) {
return $this->fail($e->getMessage());
}
}
/**
* 权重编辑弹窗:批量更新当前方向的权重(单方向,用于兼容)
* 参数direction(必), items: [{ id, weight }, ...]
*/
#[Permission('奖励对照修改', 'dice:reward:index:update')]
public function batchUpdateWeightsByDirection(Request $request): Response
{
$direction = (int) $request->post('direction', 0);
if (!in_array($direction, [DiceReward::DIRECTION_CLOCKWISE, DiceReward::DIRECTION_COUNTERCLOCKWISE], true)) {
return $this->fail('direction 必须为 0顺时针或 1逆时针');
}
$items = $request->post('items', []);
if (!is_array($items)) {
return $this->fail('参数 items 必须为数组');
}
try {
$logic = new DiceRewardLogic();
$logic->batchUpdateWeightsByDirection($direction, $items);
return $this->success('保存成功');
} catch (\plugin\saiadmin\exception\ApiException $e) {
return $this->fail($e->getMessage());
}
}
}

View File

@@ -8,6 +8,7 @@ namespace app\dice\controller\reward_config;
use plugin\saiadmin\basic\BaseController;
use app\dice\logic\reward_config\DiceRewardConfigLogic;
use app\dice\logic\reward\DiceRewardLogic;
use app\dice\validate\reward_config\DiceRewardConfigValidate;
use plugin\saiadmin\service\Permission;
use support\Request;
@@ -124,20 +125,21 @@ class DiceRewardConfigController extends BaseController
}
/**
* T1-T5、BIGWIN 权重配比:按档位分组返回配置列表
* T1-T5、BIGWIN 权重配比:按档位分组返回配置列表(含顺时针/逆时针权重,来自 dice_reward
* @param Request $request
* @return Response
*/
#[Permission('奖励配置列表', 'dice:reward_config:index:index')]
public function weightRatioList(Request $request): Response
{
$data = $this->logic->getListGroupedByTier();
$rewardLogic = new DiceRewardLogic();
$data = $rewardLogic->getListGroupedByTierWithDirection();
return $this->success($data);
}
/**
* T1-T5、BIGWIN 权重配比:批量更新权重(单条 weight 1-10000各档位权重和不限制
* 保存后 Logic 会重新实例化奖励配置表缓存DiceRewardConfig::refreshCache
* T1-T5、BIGWIN 权重配比:按 DiceReward 主键 id 批量更新 weight写入 dice_reward修改后刷新缓存
* items: [ { id: DiceReward.id, weight: 1-10000 }, ... ]
* @param Request $request
* @return Response
*/
@@ -149,13 +151,32 @@ class DiceRewardConfigController extends BaseController
return $this->fail('参数 items 必须为数组');
}
try {
$this->logic->batchUpdateWeights($items);
$rewardLogic = new DiceRewardLogic();
$rewardLogic->batchUpdateWeights($items);
return $this->success('保存成功');
} catch (\plugin\saiadmin\exception\ApiException $e) {
return $this->fail($e->getMessage());
}
}
/**
* 创建奖励对照:按当前 dice_reward_config 为两种方向顺时针0、逆时针1生成所有色子可能对应的 dice_reward 记录
* 权重默认 1可在「奖励对照」页的权重编辑弹窗中调整
* @param Request $request
* @return Response
*/
#[Permission('奖励配置修改', 'dice:reward_config:index:update')]
public function createRewardReference(Request $request): Response
{
try {
$rewardLogic = new DiceRewardLogic();
$result = $rewardLogic->createRewardReferenceFromConfig();
return $this->success($result, '创建奖励对照成功');
} catch (\plugin\saiadmin\exception\ApiException $e) {
return $this->fail($e->getMessage());
}
}
/**
* 权重配比测试:仅模拟落点统计,不创建游玩记录。按当前配置在内存中模拟 N 次抽奖,返回各 grid_number 落点次数,可选保存到 dice_reward_config_record。
* @param Request $request test_count: 100|500|1000, save_record: bool, lottery_config_id: int|null 奖池配置ID用于设定 T1-T5 概率

View File

@@ -0,0 +1,427 @@
<?php
// +----------------------------------------------------------------------
// | saiadmin [ saiadmin快速开发框架 ]
// +----------------------------------------------------------------------
namespace app\dice\logic\reward;
use app\dice\model\reward\DiceReward;
use app\dice\model\reward_config\DiceRewardConfig;
use plugin\saiadmin\exception\ApiException;
use support\think\Db;
/**
* 奖励对照逻辑层DiceReward
* 权重 1-10000区分顺时针/逆时针,修改后刷新 DiceReward 缓存
*/
class DiceRewardLogic
{
private const WEIGHT_MIN = 1;
private const WEIGHT_MAX = 10000;
/** 档位键 */
private const TIER_KEYS = ['T1', 'T2', 'T3', 'T4', 'T5', 'BIGWIN'];
/**
* 分页列表(按方向筛选,关联 dice_reward_config 展示 grid_number、ui_text、real_ev、remark
* @param int $direction 0=顺时针 1=逆时针
* @param array{tier?: string, orderField?: string, orderType?: string} $where tier 档位筛选
* @param int $page
* @param int $limit
* @return array{total: int, per_page: int, current_page: int, data: array}
*/
public function getListWithConfig(int $direction, array $where, int $page = 1, int $limit = 10): array
{
$tier = isset($where['tier']) ? trim((string) $where['tier']) : '';
$orderField = isset($where['orderField']) && $where['orderField'] !== '' ? (string) $where['orderField'] : 'r.tier';
$orderType = isset($where['orderType']) && strtoupper((string) $where['orderType']) === 'DESC' ? 'desc' : 'asc';
$query = DiceReward::alias('r')
->where('r.direction', $direction)
->field('r.id,r.tier,r.direction,r.end_index,r.weight,r.grid_number,r.start_index,r.ui_text,r.real_ev,r.remark,r.type,r.create_time,r.update_time')
->order($orderField, $orderType)
->order('r.end_index', 'asc');
if ($tier !== '') {
$query->where('r.tier', $tier);
}
$paginator = $query->paginate($limit, false, ['page' => $page]);
$arr = $paginator->toArray();
$data = isset($arr['data']) ? $arr['data'] : $arr['records'] ?? [];
$total = (int) ($arr['total'] ?? 0);
$perPage = (int) ($arr['per_page'] ?? $limit);
$currentPage = (int) ($arr['current_page'] ?? $page);
foreach ($data as $i => $row) {
if (isset($row['id']) && $row['id'] !== '' && $row['id'] !== null) {
$data[$i]['id'] = (int) $row['id'];
} else {
$data[$i]['id'] = isset($row['end_index']) ? (int) $row['end_index'] : 0;
}
$data[$i]['start_index'] = isset($row['start_index']) && $row['start_index'] !== '' && $row['start_index'] !== null
? (int) $row['start_index']
: 0;
}
return [
'total' => $total,
'per_page' => $perPage,
'current_page' => $currentPage,
'data' => $data,
];
}
/**
* 按单方向批量更新权重(仅更新当前方向的 weight并刷新缓存
* @param int $direction 0=顺时针 1=逆时针
* @param array<int, array{id: int, weight: int}> $items id 为 end_indexDiceRewardConfig.id
*/
public function batchUpdateWeightsByDirection(int $direction, array $items): void
{
if (empty($items)) {
return;
}
foreach ($items as $item) {
if (!is_array($item)) {
continue;
}
$id = isset($item['id']) ? (int) $item['id'] : 0;
$weight = isset($item['weight']) ? (int) $item['weight'] : self::WEIGHT_MIN;
if ($id <= 0) {
throw new ApiException('存在无效的配置ID');
}
$weight = max(self::WEIGHT_MIN, min(self::WEIGHT_MAX, $weight));
$tier = DiceRewardConfig::where('id', $id)->value('tier');
if ($tier === null || $tier === '') {
throw new ApiException('配置ID ' . $id . ' 不存在或档位为空');
}
$tier = (string) $tier;
$affected = DiceReward::where('tier', $tier)->where('direction', $direction)->where('end_index', $id)->update(['weight' => $weight]);
if ($affected === 0) {
$m = new DiceReward();
$m->tier = $tier;
$m->direction = $direction;
$m->end_index = $id;
$m->weight = $weight;
$m->save();
}
}
DiceReward::refreshCache();
}
/**
* 按档位+单方向返回列表(用于权重编辑弹窗:当前方向下按档位分组的配置+权重)
* @param int $direction 0=顺时针 1=逆时针
* @return array<string, array> 键 T1|T2|...|BIGWIN值为该档位下带 weight 的行数组
*/
public function getListGroupedByTierForDirection(int $direction): array
{
$configInstance = DiceRewardConfig::getCachedInstance();
$byTier = $configInstance['by_tier'] ?? [];
$rewardInstance = DiceReward::getCachedInstance();
$byTierDirection = $rewardInstance['by_tier_direction'] ?? [];
$result = [];
foreach (self::TIER_KEYS as $tier) {
$result[$tier] = [];
$rows = $byTier[$tier] ?? [];
$dirRows = $byTierDirection[$tier][$direction] ?? [];
$weightMap = [];
foreach ($dirRows as $r) {
$eid = isset($r['end_index']) ? (int) $r['end_index'] : 0;
$weightMap[$eid] = isset($r['weight']) ? max(self::WEIGHT_MIN, min(self::WEIGHT_MAX, (int) $r['weight'])) : 1;
}
foreach ($rows as $row) {
$id = isset($row['id']) ? (int) $row['id'] : 0;
$result[$tier][] = [
'id' => $id,
'grid_number' => $row['grid_number'] ?? 0,
'ui_text' => $row['ui_text'] ?? '',
'real_ev' => $row['real_ev'] ?? 0,
'remark' => $row['remark'] ?? '',
'tier' => $tier,
'weight' => $weightMap[$id] ?? 1,
];
}
}
return $result;
}
/**
* 按档位+方向返回 DiceReward 列表(用于权重配比弹窗),直接读 dice_reward 表,不依赖 config
* 每行含 reward_id(DiceReward 主键,用于按 id 更新权重)、id(end_index 展示用)、grid_number、ui_text、real_ev、remark、weight
*
* @return array<string, array{0: array, 1: array}>
*/
public function getListGroupedByTierWithDirection(): array
{
$rewardInstance = DiceReward::getCachedInstance();
$byTierDirection = $rewardInstance['by_tier_direction'] ?? [];
$result = [];
foreach (self::TIER_KEYS as $tier) {
$result[$tier] = [0 => [], 1 => []];
foreach ([0, 1] as $direction) {
$rows = $byTierDirection[$tier][$direction] ?? [];
foreach ($rows as $r) {
$result[$tier][$direction][] = [
'reward_id' => isset($r['id']) ? (int) $r['id'] : 0,
'id' => isset($r['end_index']) ? (int) $r['end_index'] : 0,
'grid_number' => isset($r['grid_number']) ? (int) $r['grid_number'] : 0,
'ui_text' => (string) ($r['ui_text'] ?? ''),
'real_ev' => $r['real_ev'] ?? 0,
'remark' => (string) ($r['remark'] ?? ''),
'weight' => isset($r['weight']) ? max(self::WEIGHT_MIN, min(self::WEIGHT_MAX, (int) $r['weight'])) : self::WEIGHT_MIN,
];
}
}
}
return $result;
}
/**
* 批量更新权重:直接按 DiceReward 主键 id 更新 weight不依赖 direction/grid_number
*
* @param array<int, array{id: int, weight: int}> $items 每项 id 为 dice_reward 表主键weight 为 1-10000
* @throws ApiException
*/
public function batchUpdateWeights(array $items): void
{
if (empty($items)) {
return;
}
foreach ($items as $item) {
if (!is_array($item)) {
continue;
}
$id = isset($item['id']) ? (int) $item['id'] : 0;
$weight = isset($item['weight']) ? (int) $item['weight'] : self::WEIGHT_MIN;
if ($id <= 0) {
throw new ApiException('存在无效的 DiceReward id');
}
$weight = max(self::WEIGHT_MIN, min(self::WEIGHT_MAX, $weight));
DiceReward::where('id', $id)->update(['weight' => $weight]);
}
DiceReward::refreshCache();
}
/** BIGWIN 权重范围0=0% 中奖10000=100% 中奖grid_number=5/30 固定 100% 不可改 */
private const BIGWIN_WEIGHT_MAX = 10000;
/**
* 按 grid_number 获取 BIGWIN 档位权重(取顺时针方向,用于编辑展示)
* 若 DiceReward 无该点数则 5/30 返回 10000其余返回 0
*/
public function getBigwinWeightByGridNumber(int $gridNumber): int
{
$inst = DiceReward::getCachedInstance();
$rows = $inst['by_tier_direction']['BIGWIN'][DiceReward::DIRECTION_CLOCKWISE] ?? [];
foreach ($rows as $row) {
if ((int) ($row['grid_number'] ?? 0) === $gridNumber) {
return min(self::BIGWIN_WEIGHT_MAX, (int) ($row['weight'] ?? self::BIGWIN_WEIGHT_MAX));
}
}
return in_array($gridNumber, [5, 30], true) ? self::BIGWIN_WEIGHT_MAX : 0;
}
/**
* 更新 BIGWIN 档位某点数的权重(顺/逆时针同时更新0=0% 中奖10000=100% 中奖
*/
public function updateBigwinWeight(int $gridNumber, int $weight): void
{
$weight = min(self::BIGWIN_WEIGHT_MAX, max(0, $weight));
foreach ([DiceReward::DIRECTION_CLOCKWISE, DiceReward::DIRECTION_COUNTERCLOCKWISE] as $direction) {
// 优先更新已存在记录
$affected = DiceReward::where('tier', 'BIGWIN')
->where('direction', $direction)
->where('grid_number', $gridNumber)
->update(['weight' => $weight]);
// 若不存在 BIGWIN 记录,则按当前 BIGWIN 配置懒加载创建一条 dice_reward 记录
if ($affected === 0) {
$config = DiceRewardConfig::where('tier', 'BIGWIN')
->where('grid_number', $gridNumber)
->find();
if ($config) {
$m = new DiceReward();
$m->tier = 'BIGWIN';
$m->direction = $direction;
$m->grid_number = (int) $gridNumber;
// 对于 BIGWIN仅需保证 real_ev、weight、grid_numberstart_index/end_index 取当前配置 id 即可
$m->start_index = (int) $config->id;
$m->end_index = (int) $config->id;
$m->ui_text = (string) ($config->ui_text ?? '');
$m->real_ev = (float) ($config->real_ev ?? 0);
$m->remark = (string) ($config->remark ?? '');
$m->type = $config->type ?? null;
$m->weight = $weight > 0 ? $weight : self::WEIGHT_MIN;
$m->save();
}
}
}
DiceReward::refreshCache();
}
/** 盘面格数(用于顺时针/逆时针计算 end_index */
private const BOARD_SIZE = 26;
/** 点数摇取范围5-30顺时针与逆时针均需创建 */
private const GRID_NUMBER_MIN = 5;
private const GRID_NUMBER_MAX = 30;
/**
* 创建奖励对照:先清空 dice_reward 表,再按两种方向为点数 5-30 生成记录。
*
* DiceReward 记录数据规则(与 config 通过 end_index 关联):
* - 方向direction = 0顺时针/ 1逆时针
* - 摇取点数grid_number
* - 起始索引start_index = DiceRewardConfig::where('grid_number', $grid_number)->first()->id
* - 结束索引顺时针end_index = ($start_index + $grid_number) % 26对 26 取余)
* - 结束索引逆时针end_index = ($start_index - $grid_number >= 0) ? ($start_index - $grid_number) : (26 + $start_index - $grid_number)
* - 奖励档位tier = DiceRewardConfig::where('id', $end_index)->first()->tier
* - 显示uiui_text = DiceRewardConfig::where('id', $end_index)->first()->ui_text
* - 实际中奖real_ev = DiceRewardConfig::where('id', $end_index)->first()->real_ev
* - 备注remark = DiceRewardConfig::where('id', $end_index)->first()->remark
* - 类型type = DiceRewardConfig::where('id', $end_index)->first()->type-2=唯一惩罚,-1=抽水,0=回本,1=再来一次,2=小赚,3=大奖格)
* - weight 默认 1后续在权重编辑弹窗设置
*
* 例如顺时针摇取点数为 5 时start_index = 配置中 grid_number=5 对应格位的 id
* 结束位置 = (起始位置 + grid_number) % 26再取该位置的 config 的 id 作为 end_index。
* 使用「按 id 排序后的盘面位置 0-25」做环形计算避免 config.id 非连续时取模结果找不到;
* 唯一键为 (direction, grid_number),保证每个点数、每个方向各一条记录,不因 end_index 相同而覆盖。
*
* @return array{created_clockwise: int, created_counterclockwise: int, updated_clockwise: int, updated_counterclockwise: int, skipped: int}
* @throws ApiException
*/
public function createRewardReferenceFromConfig(): array
{
$list = DiceRewardConfig::order('id', 'asc')->select()->toArray();
if (empty($list)) {
throw new ApiException('奖励配置为空,请先维护 dice_reward_config');
}
$configCount = count($list);
if ($configCount < self::BOARD_SIZE) {
throw new ApiException(
'奖励配置需覆盖 26 个格位id 0-25 或 1-26当前仅 ' . $configCount . ' 条,无法完整生成 5-30 共26个点数、顺时针与逆时针的奖励对照'
);
}
$table = (new DiceReward())->getTable();
Db::execute('DELETE FROM `' . $table . '`');
DiceReward::refreshCache();
// 按 id 排序后,盘面位置 0..25 对应 $list[$pos],避免 config.id 非 0-25/1-26 时取模结果找不到
$gridToPosition = [];
foreach ($list as $pos => $row) {
$gn = isset($row['grid_number']) ? (int) $row['grid_number'] : 0;
if ($gn >= self::GRID_NUMBER_MIN && $gn <= self::GRID_NUMBER_MAX && !isset($gridToPosition[$gn])) {
$gridToPosition[$gn] = $pos;
}
}
$createdCw = 0;
$createdCcw = 0;
$updatedCw = 0;
$updatedCcw = 0;
$skipped = 0;
for ($gridNumber = self::GRID_NUMBER_MIN; $gridNumber <= self::GRID_NUMBER_MAX; $gridNumber++) {
if (!isset($gridToPosition[$gridNumber])) {
$skipped++;
continue;
}
$startPos = $gridToPosition[$gridNumber];
$startRow = $list[$startPos];
$startId = isset($startRow['id']) ? (int) $startRow['id'] : 0;
$endPosCw = ($startPos + $gridNumber) % self::BOARD_SIZE;
$endPosCcw = $startPos - $gridNumber >= 0 ? $startPos - $gridNumber : self::BOARD_SIZE + $startPos - $gridNumber;
$configCw = $list[$endPosCw] ?? null;
$configCcw = $list[$endPosCcw] ?? null;
$endIdCw = $configCw !== null && isset($configCw['id']) ? (int) $configCw['id'] : 0;
$endIdCcw = $configCcw !== null && isset($configCcw['id']) ? (int) $configCcw['id'] : 0;
if ($configCw !== null) {
$tier = isset($configCw['tier']) ? trim((string) $configCw['tier']) : '';
if ($tier !== '') {
$payloadCw = [
'tier' => $tier,
'weight' => self::WEIGHT_MIN,
'grid_number' => $gridNumber,
'start_index' => $startId,
'end_index' => $endIdCw,
'ui_text' => $configCw['ui_text'] ?? '',
'real_ev' => $configCw['real_ev'] ?? null,
'remark' => $configCw['remark'] ?? '',
'type' => isset($configCw['type']) ? (int) $configCw['type'] : 0,
];
$existing = DiceReward::where('direction', DiceReward::DIRECTION_CLOCKWISE)->where('grid_number', $gridNumber)->find();
if ($existing) {
DiceReward::where('id', $existing->id)->update($payloadCw);
$updatedCw++;
} else {
$m = new DiceReward();
$m->tier = $tier;
$m->direction = DiceReward::DIRECTION_CLOCKWISE;
$m->end_index = $endIdCw;
$m->weight = self::WEIGHT_MIN;
$m->grid_number = $gridNumber;
$m->start_index = $startId;
$m->ui_text = $configCw['ui_text'] ?? '';
$m->real_ev = $configCw['real_ev'] ?? null;
$m->remark = $configCw['remark'] ?? '';
$m->type = isset($configCw['type']) ? (int) $configCw['type'] : 0;
$m->save();
$createdCw++;
}
}
}
if ($configCcw !== null) {
$tier = isset($configCcw['tier']) ? trim((string) $configCcw['tier']) : '';
if ($tier !== '') {
$payloadCcw = [
'tier' => $tier,
'weight' => self::WEIGHT_MIN,
'grid_number' => $gridNumber,
'start_index' => $startId,
'end_index' => $endIdCcw,
'ui_text' => $configCcw['ui_text'] ?? '',
'real_ev' => $configCcw['real_ev'] ?? null,
'remark' => $configCcw['remark'] ?? '',
'type' => isset($configCcw['type']) ? (int) $configCcw['type'] : 0,
];
$existing = DiceReward::where('direction', DiceReward::DIRECTION_COUNTERCLOCKWISE)->where('grid_number', $gridNumber)->find();
if ($existing) {
DiceReward::where('id', $existing->id)->update($payloadCcw);
$updatedCcw++;
} else {
$m = new DiceReward();
$m->tier = $tier;
$m->direction = DiceReward::DIRECTION_COUNTERCLOCKWISE;
$m->end_index = $endIdCcw;
$m->weight = self::WEIGHT_MIN;
$m->grid_number = $gridNumber;
$m->start_index = $startId;
$m->ui_text = $configCcw['ui_text'] ?? '';
$m->real_ev = $configCcw['real_ev'] ?? null;
$m->remark = $configCcw['remark'] ?? '';
$m->type = isset($configCcw['type']) ? (int) $configCcw['type'] : 0;
$m->save();
$createdCcw++;
}
}
}
}
DiceReward::refreshCache();
return [
'created_clockwise' => $createdCw,
'created_counterclockwise' => $createdCcw,
'updated_clockwise' => $updatedCw,
'updated_counterclockwise' => $updatedCcw,
'skipped' => $skipped,
];
}
}

View File

@@ -6,9 +6,10 @@
// +----------------------------------------------------------------------
namespace app\dice\logic\reward_config;
use app\dice\logic\reward\DiceRewardLogic;
use app\dice\model\lottery_pool_config\DiceLotteryPoolConfig;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward_config\DiceRewardConfigRecord;
use app\dice\model\reward\DiceRewardConfig;
use app\dice\model\reward_config_record\DiceRewardConfigRecord;
use plugin\saiadmin\basic\think\BaseLogic;
use plugin\saiadmin\exception\ApiException;
use plugin\saiadmin\utils\Helper;
@@ -30,27 +31,43 @@ class DiceRewardConfigLogic extends BaseLogic
}
/**
* 新增:weight 限制 1-10000保存后刷新缓存
* 新增:保存后刷新缓存(权重已迁移至 dice_reward 表)
*/
public function add(array $data): mixed
{
$data = $this->normalizeWeight($data);
$result = parent::add($data);
DiceRewardConfig::refreshCache();
return $result;
}
/**
* 修改:weight 限制 1-10000保存后刷新缓存
* 修改:保存后刷新缓存BIGWIN 的 weight 直接写入 dice_reward_config 表,抽奖时从 Config 读取
*/
public function edit($id, array $data): mixed
{
$data = $this->normalizeWeight($data);
$result = parent::edit($id, $data);
DiceRewardConfig::refreshCache();
return $result;
}
/**
* 为列表/分页数据中的 BIGWIN 行附加 weight来自 DiceReward 缓存)
*/
public function enrichBigwinWeight(array $listResult): array
{
$key = isset($listResult['data']) ? 'data' : (isset($listResult['records']) ? 'records' : null);
if ($key === null || empty($listResult[$key])) {
return $listResult;
}
$rewardLogic = new DiceRewardLogic();
foreach ($listResult[$key] as $i => $row) {
if (isset($row['tier']) && $row['tier'] === 'BIGWIN' && isset($row['grid_number'])) {
$listResult[$key][$i]['weight'] = $rewardLogic->getBigwinWeightByGridNumber((int) $row['grid_number']);
}
}
return $listResult;
}
/**
* 删除后刷新缓存
*/
@@ -64,18 +81,7 @@ class DiceRewardConfigLogic extends BaseLogic
}
/**
* weight 限制 1-10000
*/
private function normalizeWeight(array $data): array
{
$w = isset($data['weight']) ? (int) $data['weight'] : self::WEIGHT_MIN;
$data['weight'] = max(self::WEIGHT_MIN, min(self::WEIGHT_MAX, $w));
return $data;
}
/**
* 按档位分组返回奖励配置列表(用于 T1-T5、BIGWIN 权重配比)
* @return array<string, array> 键为 T1|T2|T3|T4|T5|BIGWIN值为该档位下的配置行数组
* 按档位分组返回奖励配置列表(仅配置,权重在 dice_reward 表;权重配比请用 DiceRewardLogic::getListGroupedByTierWithDirection
*/
public function getListGroupedByTier(): array
{
@@ -94,50 +100,6 @@ class DiceRewardConfigLogic extends BaseLogic
return $grouped;
}
/**
* 批量更新权重:单条 weight 1-10000各档位权重和不限制
* @param array<int, array{id: int, weight: int}> $items 元素为 [ id => 配置ID, weight => 1-10000 ]
* @throws ApiException 当单条 weight 非法时
*/
public function batchUpdateWeights(array $items): void
{
if (empty($items)) {
return;
}
$items = array_values($items);
$ids = [];
$weightById = [];
foreach ($items as $item) {
if (!is_array($item)) {
continue;
}
$id = isset($item['id']) ? (int) $item['id'] : 0;
$w = isset($item['weight']) ? (int) $item['weight'] : self::WEIGHT_MIN;
if ($id < 0) {
throw new ApiException('存在无效的配置ID');
}
if ($w < self::WEIGHT_MIN || $w > self::WEIGHT_MAX) {
throw new ApiException('权重必须在 ' . self::WEIGHT_MIN . '-' . self::WEIGHT_MAX . ' 之间');
}
$ids[] = $id;
$weightById[$id] = $w;
}
$list = $this->model->whereIn('id', array_unique($ids))->field('id,tier,grid_number')->select()->toArray();
$idToTier = [];
foreach ($list as $r) {
$id = isset($r['id']) ? (int) $r['id'] : 0;
$idToTier[$id] = isset($r['tier']) ? (string) $r['tier'] : '';
}
foreach ($weightById as $id => $w) {
$tier = $idToTier[$id] ?? '';
if ($tier === '') {
throw new ApiException('配置ID ' . $id . ' 不存在或档位为空');
}
DiceRewardConfig::where('id', $id)->update(['weight' => $w]);
}
DiceRewardConfig::refreshCache();
}
/** 测试时档位权重均为 0 的异常标识 */
private const EXCEPTION_WEIGHT_ALL_ZERO = 'REWARD_WEIGHT_ALL_ZERO';
@@ -208,7 +170,10 @@ class DiceRewardConfigLogic extends BaseLogic
throw new ApiException('测试次数仅支持 100、500、1000、5000、10000');
}
$grouped = $this->getListGroupedByTier();
$grouped = [];
foreach (['T1', 'T2', 'T3', 'T4', 'T5', 'BIGWIN'] as $t) {
$grouped[$t] = $this->model::getCachedByTierForDirection($t, 0);
}
$tiers = ['T1', 'T2', 'T3', 'T4', 'T5'];
$tierWeights = [1, 1, 1, 1, 1];
$config = null;

View File

@@ -5,7 +5,8 @@
namespace app\dice\logic\reward_config_record;
use app\dice\model\lottery_pool_config\DiceLotteryPoolConfig;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward\DiceReward;
use app\dice\model\reward\DiceRewardConfig;
use app\dice\model\reward_config_record\DiceRewardConfigRecord;
use plugin\saiadmin\basic\think\BaseLogic;
use plugin\saiadmin\exception\ApiException;
@@ -70,7 +71,7 @@ class DiceRewardConfigRecordLogic extends BaseLogic
}
/**
* 将测试记录的权重导入到正式配置weight_config_snapshot → DiceRewardConfigtier_weights_snapshot → DiceLotteryPoolConfig并刷新缓存
* 将测试记录的权重导入weight_config_snapshot → dice_reward(顺时针/逆时针同值)tier_weights_snapshot → DiceLotteryPoolConfig并刷新缓存
* @param int $recordId 测试记录 ID
* @param int|null $lotteryConfigId 要导入档位权重的奖池配置 ID不传则使用记录中的 lottery_config_id若有
* @throws ApiException
@@ -91,10 +92,28 @@ class DiceRewardConfigRecordLogic extends BaseLogic
foreach ($snapshot as $item) {
$id = isset($item['id']) ? (int) $item['id'] : 0;
$weight = isset($item['weight']) ? (int) $item['weight'] : 1;
if ($id > 0) {
DiceRewardConfig::where('id', $id)->update(['weight' => $weight]);
$weight = max(1, min(10000, $weight));
if ($id <= 0) {
continue;
}
$tier = DiceRewardConfig::where('id', $id)->value('tier');
if ($tier === null || $tier === '') {
continue;
}
$tier = (string) $tier;
foreach ([DiceReward::DIRECTION_CLOCKWISE, DiceReward::DIRECTION_COUNTERCLOCKWISE] as $direction) {
$affected = DiceReward::where('tier', $tier)->where('direction', $direction)->where('end_index', $id)->update(['weight' => $weight]);
if ($affected === 0) {
$m = new DiceReward();
$m->tier = $tier;
$m->direction = $direction;
$m->end_index = $id;
$m->weight = $weight;
$m->save();
}
}
}
DiceReward::refreshCache();
}
$tierSnapshot = $record['tier_weights_snapshot'] ?? null;

View File

@@ -8,7 +8,7 @@ namespace app\dice\model\play_record;
use app\dice\model\lottery_pool_config\DiceLotteryPoolConfig;
use app\dice\model\player\DicePlayer;
use app\dice\model\reward_config\DiceRewardConfig;
use app\dice\model\reward\DiceRewardConfig;
use plugin\saiadmin\basic\think\BaseModel;
use think\model\relation\BelongsTo;

View File

@@ -0,0 +1,139 @@
<?php
// +----------------------------------------------------------------------
// | saiadmin [ saiadmin快速开发框架 ]
// +----------------------------------------------------------------------
namespace app\dice\model\reward;
use plugin\saiadmin\basic\think\BaseModel;
use support\think\Cache;
/**
* 奖励对照模型
*
* dice_reward 奖励对照表(主键 id 自增)
* 唯一约束 (direction, grid_number)保证每个点数、每个方向各一条end_index 关联 DiceRewardConfig.id
*
* @property $id 主键
* @property $tier 档位 T1-T5/BIGWIN
* @property $direction 方向:0=顺时针,1=逆时针
* @property $end_index 结束索引DiceRewardConfig.id
* @property $weight 权重 1-10000档位内按权重比抽取
* @property $grid_number 色子点数(摇取值)
* @property $start_index 起始索引(DiceRewardConfig.id)
* @property $ui_text 显示文本(来自config)
* @property $real_ev 实际中奖金额(来自config)
* @property $remark 备注(来自config)
* @property $type 奖励类型(来自config)
*/
class DiceReward extends BaseModel
{
/** 方向:顺时针 */
public const DIRECTION_CLOCKWISE = 0;
/** 方向:逆时针 */
public const DIRECTION_COUNTERCLOCKWISE = 1;
/** 缓存键:奖励对照实例 */
private const CACHE_KEY_INSTANCE = 'dice:reward:instance';
private const CACHE_TTL = 86400 * 30;
private static ?array $instance = null;
protected $table = 'dice_reward';
/** 主键 id 自增,唯一约束 (direction, grid_number) */
protected $pk = 'id';
/**
* 获取奖励对照实例(按档位+方向索引,用于抽奖与权重配比)
* @return array{list: array, by_tier_direction: array}
*/
public static function getCachedInstance(): array
{
if (self::$instance !== null) {
return self::$instance;
}
$instance = Cache::get(self::CACHE_KEY_INSTANCE);
if ($instance !== null && is_array($instance)) {
self::$instance = $instance;
return $instance;
}
self::refreshCache();
$instance = Cache::get(self::CACHE_KEY_INSTANCE);
self::$instance = is_array($instance) ? $instance : self::buildEmptyInstance();
return self::$instance;
}
/**
* 按档位+方向取权重列表(用于抽奖:该档位该方向下 end_index => weight
* @return array<int, int> end_index => weight
*/
public static function getCachedByTierAndDirection(string $tier, int $direction): array
{
$inst = self::getCachedInstance();
$byTierDirection = $inst['by_tier_direction'] ?? [];
$list = $byTierDirection[$tier][$direction] ?? [];
$result = [];
foreach ($list as $row) {
$endIndex = isset($row['end_index']) ? (int) $row['end_index'] : 0;
$weight = isset($row['weight']) ? (int) $row['weight'] : 1;
$result[$endIndex] = $weight;
}
return $result;
}
/**
* 重新从数据库加载并写入缓存;修改/新增/删除后需调用以实例化
*/
public static function refreshCache(): void
{
$list = (new self())->order('tier')->order('direction')->order('end_index')->select()->toArray();
$byTierDirection = [];
foreach ($list as $row) {
$tier = isset($row['tier']) ? (string) $row['tier'] : '';
$direction = isset($row['direction']) ? (int) $row['direction'] : 0;
if ($tier !== '') {
if (!isset($byTierDirection[$tier])) {
$byTierDirection[$tier] = [0 => [], 1 => []];
}
if (!isset($byTierDirection[$tier][$direction])) {
$byTierDirection[$tier][$direction] = [];
}
$byTierDirection[$tier][$direction][] = $row;
}
}
self::$instance = [
'list' => $list,
'by_tier_direction' => $byTierDirection,
];
Cache::set(self::CACHE_KEY_INSTANCE, self::$instance, self::CACHE_TTL);
}
private static function buildEmptyInstance(): array
{
return [
'list' => [],
'by_tier_direction' => [],
];
}
public static function clearRequestInstance(): void
{
self::$instance = null;
}
public static function onAfterInsert($model): void
{
self::refreshCache();
}
public static function onAfterUpdate($model): void
{
self::refreshCache();
}
public static function onAfterDelete($model): void
{
self::refreshCache();
}
}

View File

@@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | 别名reward 命名空间下引用 reward_config\DiceRewardConfig
// +----------------------------------------------------------------------
namespace app\dice\model\reward;
class DiceRewardConfig extends \app\dice\model\reward_config\DiceRewardConfig
{
}

View File

@@ -6,24 +6,23 @@
// +----------------------------------------------------------------------
namespace app\dice\model\reward_config;
use app\dice\model\reward\DiceReward;
use plugin\saiadmin\basic\think\BaseModel;
use support\think\Cache;
/**
* 奖励配置模型
*
* dice_reward_config 奖励配置
* 按档位 T1-T5 直接权重抽取 grid_numberweight 1-10000起始索引 s_start_index / n_start_index
* dice_reward_config 奖励配置BIGWIN 档位使用本表 weight0-1000010000=100% 中大奖)
*
* @property $id ID
* @property $grid_number 色子点数
* @property $ui_text 前端显示文本
* @property $real_ev 真实资金结算
* @property $tier 所属档位
* @property $weight 权重 1-10000档位内按权重比抽取
* @property $n_start_index 逆时针起始索引
* @property $s_start_index 顺时针起始索引
* @property $weight 权重(仅 BIGWIN 使用0-10000
* @property $remark 备注
* @property $type 奖励类型 -2=唯一惩罚,-1=抽水,0=回本,1=再来一次,2=小赚,3=大奖格
* @property $create_time 创建时间
* @property $update_time 修改时间
*/
@@ -129,7 +128,7 @@ class DiceRewardConfig extends BaseModel
}
/**
* 从缓存按档位取奖励列表(含 weight用于按权重抽 grid_number
* 从缓存按档位取奖励列表(不含权重,仅配置
*/
public static function getCachedByTier(string $tier): array
{
@@ -138,6 +137,22 @@ class DiceRewardConfig extends BaseModel
return $byTier[$tier] ?? [];
}
/**
* 按档位+方向取奖励列表(合并 dice_reward 权重,用于抽奖)
* @param int $direction 0=顺时针, 1=逆时针
* @return array 每行含 id, grid_number, real_ev, tier, weight 等
*/
public static function getCachedByTierForDirection(string $tier, int $direction): array
{
$list = self::getCachedByTier($tier);
$weightMap = DiceReward::getCachedByTierAndDirection($tier, $direction);
foreach ($list as $i => $row) {
$id = isset($row['id']) ? (int) $row['id'] : 0;
$list[$i]['weight'] = $weightMap[$id] ?? 1;
}
return $list;
}
public static function clearRequestInstance(): void
{
self::$instance = null;
@@ -199,18 +214,4 @@ class DiceRewardConfig extends BaseModel
$query->where('tier', '=', $value);
}
}
public function searchWeightMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('weight', '>=', $value);
}
}
public function searchWeightMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('weight', '<=', $value);
}
}
}

View File

@@ -9,51 +9,29 @@ namespace app\dice\validate\reward_config;
use plugin\saiadmin\basic\BaseValidate;
/**
* 奖励配置验证器DiceRewardConfig
* weight 1-10000各档位权重和不限制
* 奖励配置验证器DiceRewardConfigBIGWIN 的 weight 存本表0-10000
*/
class DiceRewardConfigValidate extends BaseValidate
{
private const WEIGHT_MIN = 1;
private const WEIGHT_MAX = 10000;
protected $rule = [
'grid_number' => 'require',
'ui_text' => 'require',
'real_ev' => 'require',
'tier' => 'require',
'weight' => 'checkWeight',
'n_start_index' => 'number',
's_start_index' => 'number',
'grid_number' => 'require',
'ui_text' => 'require',
'real_ev' => 'require',
'tier' => 'require',
'type' => 'number',
'weight' => 'number|between:0,10000', // BIGWIN 大奖权重,仅档位为 BIGWIN 时使用
];
protected $message = [
'grid_number' => '色子点数必须填写',
'ui_text' => '前端显示文本必须填写',
'real_ev' => '真实资金结算必须填写',
'tier' => '所属档位必须填写',
'weight' => '权重必须为 1-10000',
'n_start_index' => '逆时针起始索引须为数字',
's_start_index' => '顺时针起始索引须为数字',
'ui_text' => '前端显示文本必须填写',
'real_ev' => '真实资金结算必须填写',
'tier' => '所属档位必须填写',
'type' => '奖励类型须为数字',
];
protected $scene = [
'save' => ['grid_number', 'ui_text', 'real_ev', 'tier', 'weight', 'n_start_index', 's_start_index'],
'update' => ['grid_number', 'ui_text', 'real_ev', 'tier', 'weight', 'n_start_index', 's_start_index'],
'save' => ['grid_number', 'ui_text', 'real_ev', 'tier', 'type'],
'update' => ['grid_number', 'ui_text', 'real_ev', 'tier', 'type', 'weight'],
];
/**
* weight1-10000
*/
protected function checkWeight($value, $rule = '', $data = []): bool
{
$num = is_numeric($value) ? (int) $value : null;
if ($num === null) {
return false;
}
if ($num < self::WEIGHT_MIN || $num > self::WEIGHT_MAX) {
return false;
}
return true;
}
}

View File

@@ -102,9 +102,15 @@ Route::group('/core', function () {
Route::post('/dice/player_wallet_record/DicePlayerWalletRecord/adminOperate', [\app\dice\controller\player_wallet_record\DicePlayerWalletRecordController::class, 'adminOperate']);
fastRoute('dice/player_ticket_record/DicePlayerTicketRecord', \app\dice\controller\player_ticket_record\DicePlayerTicketRecordController::class);
Route::get('/dice/player_ticket_record/DicePlayerTicketRecord/getPlayerOptions', [\app\dice\controller\player_ticket_record\DicePlayerTicketRecordController::class, 'getPlayerOptions']);
fastRoute('dice/reward/DiceReward', \app\dice\controller\reward\DiceRewardController::class);
Route::get('/dice/reward/DiceReward/weightRatioList', [\app\dice\controller\reward\DiceRewardController::class, 'weightRatioList']);
Route::get('/dice/reward/DiceReward/weightRatioListWithDirection', [\app\dice\controller\reward\DiceRewardController::class, 'weightRatioListWithDirection']);
Route::post('/dice/reward/DiceReward/batchUpdateWeights', [\app\dice\controller\reward\DiceRewardController::class, 'batchUpdateWeights']);
Route::post('/dice/reward/DiceReward/batchUpdateWeightsByDirection', [\app\dice\controller\reward\DiceRewardController::class, 'batchUpdateWeightsByDirection']);
fastRoute('dice/reward_config/DiceRewardConfig', \app\dice\controller\reward_config\DiceRewardConfigController::class);
Route::get('/dice/reward_config/DiceRewardConfig/weightRatioList', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'weightRatioList']);
Route::post('/dice/reward_config/DiceRewardConfig/batchUpdateWeights', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'batchUpdateWeights']);
Route::post('/dice/reward_config/DiceRewardConfig/createRewardReference', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'createRewardReference']);
Route::post('/dice/reward_config/DiceRewardConfig/runWeightTest', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'runWeightTest']);
fastRoute('dice/lottery_pool_config/DiceLotteryPoolConfig', \app\dice\controller\lottery_pool_config\DiceLotteryPoolConfigController::class);
Route::get('/dice/lottery_pool_config/DiceLotteryPoolConfig/getOptions', [\app\dice\controller\lottery_pool_config\DiceLotteryPoolConfigController::class, 'getOptions']);