get(); $data = []; foreach ($rows as $row) { $group = $row->group ?? ''; if (!isset($data[$group])) { $data[$group] = []; } $data[$group][] = [ 'name' => $row->name, 'title' => $row->title, 'value' => $row->value, 'create_time' => $row->create_time, 'update_time' => $row->update_time, ]; } return $this->success($data); } /** * 购买抽奖券 * POST /api/game/buyLotteryTickets * header: token(由 TokenMiddleware 注入 request->player_id) * body: count = 1 | 5 | 10(1次/100coin, 5次/500coin, 10次/1000coin) */ public function buyLotteryTickets(Request $request): Response { $userId = (int) ($request->player_id ?? 0); $count = (int) $request->post('count', 0); if (!in_array($count, [1, 5, 10], true)) { return $this->fail('购买抽奖券错误', ReturnCode::PARAMS_ERROR); } try { $logic = new GameLogic(); $data = $logic->buyLotteryTickets($userId, $count); return $this->success($data); } catch (ApiException $e) { $msg = $e->getMessage(); if ($msg === '平台币不足') { $player = DicePlayer::find($userId); $coin = $player ? (float) $player->coin : 0; return $this->success(['coin' => $coin], $msg); } return $this->fail($msg, ReturnCode::BUSINESS_ERROR); } } /** * 获取彩金池(中奖配置表) * GET /api/game/lotteryPool * header: token * 返回 DiceRewardConfig 列表(彩金池/中奖配置) */ public function lotteryPool(Request $request): Response { $list = DiceRewardConfig::getCachedList(); return $this->success($list); } /** * 开始游戏(抽奖一局) * POST /api/game/playStart * header: token(由 TokenMiddleware 注入 request->player_id) * body: direction 必传,0=无 1=中奖 */ public function playStart(Request $request): Response { $userId = (int) ($request->player_id ?? 0); $direction = $request->post('direction'); if ($direction !== null) { $direction = (int) $direction; } if (!in_array($direction, [0, 1], true)) { return $this->fail('direction 必须为 0 或 1', ReturnCode::PARAMS_ERROR); } $player = DicePlayer::find($userId); if (!$player) { return $this->fail('用户不存在', ReturnCode::NOT_FOUND); } $minEv = DiceRewardConfig::getCachedMinRealEv(); $minCoin = abs($minEv + 100); $coin = (float) $player->coin; if ($coin < $minCoin) { return $this->success([], '当前玩家余额'.$coin.'小于'.$minCoin.'无法继续游戏'); } try { $logic = new PlayStartLogic(); $data = $logic->run($userId, (int)$direction); return $this->success($data); } catch (ApiException $e) { return $this->fail($e->getMessage(), ReturnCode::BUSINESS_ERROR); } catch (\Throwable $e) { // 记录抽奖逻辑抛出的真实异常,便于排查“服务超时,没有原因” Log::error('playStart 异常: ' . $e->getMessage(), [ 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'player_id' => $userId, 'direction' => $direction, ]); $timeoutRecord = null; $timeout_message = ''; try { $timeoutRecord = DicePlayRecord::create([ 'player_id' => $userId, 'lottery_config_id' => 0, 'lottery_type' => 0, 'is_win' => 0, 'win_coin' => 0, 'super_win_coin' => 0, 'reward_win_coin' => 0, 'use_coins' => 0, 'direction' => $direction, 'reward_config_id' => 0, 'start_index' => 0, 'target_index' => 0, 'roll_array' => '[]', 'status' => PlayStartLogic::RECORD_STATUS_TIMEOUT, ]); } catch (\Exception $inner) { $timeout_message = $inner->getMessage(); Log::error('游玩记录写入超时: ' . $inner->getMessage()); } $payload = $timeoutRecord ? ['record' => $timeoutRecord->toArray()] : []; $msg = $timeout_message !== '' ? $timeout_message : $e->getMessage(); if ($msg === '') { $msg = '没有原因'; } return $this->fail('服务超时,' . $msg); } } }