model = new DiceLotteryPoolConfig(); } /** * 按渠道隔离更新(主键 id 全局唯一,仍校验 dept_id 防止越权) */ public function edit($id, array $data, ?array $adminInfo = null, $requestDeptId = null): mixed { $pickedDeptId = AdminScopeHelper::pickRequestDeptId($requestDeptId, $data); $deptId = AdminScopeHelper::resolveConfigDeptId($adminInfo, $pickedDeptId); $result = ConfigScopeEditHelper::updateByPkAndDept( $this->model, $id, $deptId, $data, ['id', 'dept_id', 'create_time', 'update_time', 'delete_time', 'row_id'], $adminInfo, $pickedDeptId ); if ($result) { $pool = DiceLotteryPoolConfig::where('id', $id)->find(); if ($pool && $pool->isPlayerDefaultTemplate()) { $this->syncPlayersBoundToPlayerDefaultPool($pool); } } return $result; } /** * 修改 playerDefault 后:同步同渠道所有绑定该池(及应跟随 playerDefault 的玩家)T1–T5 权重,并刷新 Redis * * @return int 已同步玩家数量 */ public function syncPlayersBoundToPlayerDefaultPool(DiceLotteryPoolConfig $pool): int { $poolId = (int) ($pool->id ?? 0); if ($poolId <= 0) { return 0; } $fresh = DiceLotteryPoolConfig::where('id', $poolId)->find(); if (!$fresh || !$fresh->isPlayerDefaultTemplate()) { return 0; } $pool = $fresh; $weights = $this->extractPoolTierWeights($pool); $poolDeptId = AdminScopeHelper::normalizeRecordDeptId($pool->dept_id ?? null); $legacyDefaultPoolId = $this->findDefaultPoolIdForDept($poolDeptId); $idsMap = []; $boundPlayers = DicePlayer::where('lottery_config_id', $poolId)->select(); foreach ($boundPlayers as $player) { $idsMap[(int) $player->id] = true; } if ($legacyDefaultPoolId > 0 && $legacyDefaultPoolId !== $poolId) { $legacyPlayers = DicePlayer::where('lottery_config_id', $legacyDefaultPoolId)->select(); foreach ($legacyPlayers as $player) { if (AdminScopeHelper::resolvePlayerConfigDeptId($player) === $poolDeptId) { $idsMap[(int) $player->id] = true; } } } $unboundPlayers = DicePlayer::where(function ($q) { $q->where('lottery_config_id', 0)->whereOr('lottery_config_id', null); })->select(); foreach ($unboundPlayers as $player) { if (AdminScopeHelper::resolvePlayerConfigDeptId($player) === $poolDeptId) { $idsMap[(int) $player->id] = true; } } if ($idsMap === []) { return 0; } $ids = array_keys($idsMap); $update = array_merge($weights, ['lottery_config_id' => $poolId]); Db::table('dice_player')->whereIn('id', $ids)->update($update); foreach ($ids as $playerId) { LotteryService::patchPlayerWeightsCache($playerId, $weights); LotteryService::invalidatePlayerLotteryCache($playerId); UserCache::deleteUser($playerId); } return count($ids); } /** * @return array{t1_weight:float,t2_weight:float,t3_weight:float,t4_weight:float,t5_weight:float} */ private function extractPoolTierWeights(DiceLotteryPoolConfig $pool): array { $data = $pool->getData(); return [ 't1_weight' => (float) ($data['t1_weight'] ?? 0), 't2_weight' => (float) ($data['t2_weight'] ?? 0), 't3_weight' => (float) ($data['t3_weight'] ?? 0), 't4_weight' => (float) ($data['t4_weight'] ?? 0), 't5_weight' => (float) ($data['t5_weight'] ?? 0), ]; } private function findDefaultPoolIdForDept(int $deptId): int { $query = DiceLotteryPoolConfig::where('name', 'default'); if (AdminScopeHelper::isTemplateDeptId($deptId)) { $query->where(function ($q) { $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT) ->whereOr('dept_id', null); }); } else { $query->where('dept_id', $deptId); } $row = $query->find(); return $row ? (int) $row->id : 0; } /** * 获取当前彩金池(type=0)+ 杀分权重为 type=1 的只读展示 * profit_amount 每次从 DB 实时读取;t1_weight~t5_weight 来自 type=1(杀分权重,不可在弹窗内修改) * * @return array{id:int,name:string,safety_line:int,kill_enabled:int,t1_weight:int,...,t5_weight:int,profit_amount:float} */ public function getCurrentPool(int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): array { $query0 = DiceLotteryPoolConfig::where('name', 'default'); if (AdminScopeHelper::isTemplateDeptId($deptId)) { $query0->where(function ($q) { $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT) ->whereOr('dept_id', null); }); } else { $query0->where('dept_id', $deptId); } $configType0 = $query0->find(); if (!$configType0) { throw new ApiException('No name=default pool config found, please create one first'); } $query1 = DiceLotteryPoolConfig::where('name', 'killScore'); if (AdminScopeHelper::isTemplateDeptId($deptId)) { $query1->where(function ($q) { $q->where('dept_id', AdminScopeHelper::DEFAULT_TEMPLATE_DEPT) ->whereOr('dept_id', null); }); } else { $query1->where('dept_id', $deptId); } $configType1 = $query1->find(); $row0 = $configType0->toArray(); $profitAmount = isset($row0['profit_amount']) ? (float) $row0['profit_amount'] : (isset($row0['ev']) ? (float) $row0['ev'] : 0.0); $pool = [ 'id' => (int) $row0['id'], 'name' => (string) ($row0['name'] ?? ''), 'safety_line' => (int) ($row0['safety_line'] ?? 0), 'kill_enabled' => (int) ($row0['kill_enabled'] ?? 1), 'profit_amount' => $profitAmount, ]; $row1 = $configType1 ? $configType1->toArray() : []; $pool['t1_weight'] = (int) ($row1['t1_weight'] ?? 0); $pool['t2_weight'] = (int) ($row1['t2_weight'] ?? 0); $pool['t3_weight'] = (int) ($row1['t3_weight'] ?? 0); $pool['t4_weight'] = (int) ($row1['t4_weight'] ?? 0); $pool['t5_weight'] = (int) ($row1['t5_weight'] ?? 0); return $pool; } /** * 更新当前彩金池:仅允许修改 type=0 的 safety_line、kill_enabled(杀分权重来自 type=1,不可在此接口修改) * * @param array{safety_line?:int,kill_enabled?:int} $data */ public function updateCurrentPool(array $data, int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): void { $pool = $this->getCurrentPool($deptId); $id = (int) $pool['id']; if (!array_key_exists('safety_line', $data) && !array_key_exists('kill_enabled', $data)) { return; } $update = []; if (array_key_exists('safety_line', $data)) { $update['safety_line'] = (int) $data['safety_line']; } if (array_key_exists('kill_enabled', $data)) { $update['kill_enabled'] = ((int) $data['kill_enabled']) === 1 ? 1 : 0; } if ($update === []) { return; } $query = DiceLotteryPoolConfig::where('id', $id); ConfigScopeEditHelper::applyDeptIdWhere($query, $deptId); $query->update($update); } /** * 重置当前彩金池的玩家累计盈利:将 profit_amount 置为 0,并刷新 Redis 缓存 */ public function resetProfitAmount(int $deptId = AdminScopeHelper::DEFAULT_TEMPLATE_DEPT): void { $pool = $this->getCurrentPool($deptId); $id = (int) $pool['id']; $query = DiceLotteryPoolConfig::where('id', $id); ConfigScopeEditHelper::applyDeptIdWhere($query, $deptId); $query->update(['profit_amount' => 0]); $pool['profit_amount'] = 0.0; Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE); } }