| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- <?php
- namespace App\Console\Commands;
- use Illuminate\Console\Command;
- use App\Models\Sport as SportModel;
- use App\Models\SportOdds as SportOddsModel;
- use App\Services\SportClientService;
- use Illuminate\Support\Facades\Log;
- use App\Models\Config;
- use Illuminate\Support\Facades\Cache;
- use Throwable; // 使用 Throwable 可以捕获所有 PHP 7+ 的异常和错误
- class SportOdds extends Command
- {
- /**
- * 命令名称和签名
- *
- * @var string
- */
- protected $signature = 'sport:odds {is_live=0}';
- protected $is_live = 0;
-
- protected $long_status = [
- 'Time To Be Defined' => 0,
- 'Not Started' => 0,
- 'First Half' => 1,
- 'First Half, Kick Off' => 1,
- 'Halftime' => 1,
- 'Second Half' => 1,
- 'Second Half, 2nd Half Started' => 1,
- 'Extra Time' => 1,
- 'Break Time' => 1,
- 'Penalty In Progress' => 1,
- 'Match Suspended' => 1,
- 'Match Interrupted' => 1,
- 'Match Finished' => 2,
- 'Match Finished' => 2,
- 'Match Finished' => 2,
- 'Match Postponed' => 3,
- 'Match Cancelled' => 4,
- 'Match Abandoned' => 4,
- 'Technical Loss' => 4,
- 'WalkOver' => 4,
- 'In Progress' => 1,
- ];
-
- protected $fixture_status = [
- 'First Half' => 1,
- 'First Half, Kick Off' => 1,
- 'Halftime' => 1,
- 'Second Half' => 1,
- 'Second Half, 2nd Half Started' => 1,
- 'Extra Time' => 1,
- 'Break Time' => 1,
- 'Penalty In Progress' => 1,
- ];
- /**
- * 命令描述
- *
- * @var string
- */
- protected $description = '赔率(直播赔率5秒更新一次,塞前赔率3小时更新一次)';
- /**
- * 执行命令
- *
- * @return int
- */
- public function handle()
- {
- $this->is_live = $this->argument('is_live');
- $this->sportOddsData($this->is_live);
- }
- public function sportOddsData($is_live)
- {
- if ($is_live == 1) {
- // 直播赔率通常是一次获取全量,但也需要对整体更新逻辑做保护
- $data = SportClientService::oddsLive([]);
- if ($data) {
- // file_put_contents("oddsLive.json",json_encode($data));
- $this->updateOddsLive($data);
- }
- } else {
- $limit = 3000;
- //普通球赛是开赛前购买,更新数据
- $where['state'] = 0; //比赛状态:0未开始1进行中2已完场3延期4取消
- $list = SportModel::where($where)->where('odds',null)->limit($limit)->get()->toArray();
- foreach ($list as $item) {
- // --- 关键优化:在循环内部嵌套 try-catch ---
- try {
- $data = SportClientService::odds([
- 'fixture' => $item->data_id,
- ]);
- $this->updateOdds($item->data_id, $data);
- } catch (Throwable $e) {
- // 记录具体哪条赛事出错了,但不抛出,让循环继续
- Log::error("赛前赔率更新失败 [Fixture: {$item->data_id}]: " . $e->getMessage());
- continue;
- }
- }
- }
-
- return true;
- }
- public function updateOddsLive($data)
- {
- if (empty($data['response'])) return;
- //体育赛事结束前几(分钟)锁盘,90分钟结束
- $sport_locked = Config::where('field', 'sport_locked')->first()->val ?? 1;
- $responses = $data['response'];
- foreach ($responses as $item) {
- // --- 关键优化:直播赔率逐条更新也要包裹,防止单条数据格式问题挂掉全盘 ---
- try {
- $data_id = $item['fixture']['id'];
- $sport_info = SportModel::where('data_id',$data_id)->select('odds','odd_ids_locked')->first();
-
- if (!$sport_info) continue;
- $old_odd_ids_locked = $sport_info['odd_ids_locked'];
- $odds_data = $this->doOdds($item['odds'], $sport_info['odds']);
- $odds = $odds_data['odds'];
- $odds = !empty($odds) ? json_encode($odds) : null;
- $odd_ids_locked = array_merge($old_odd_ids_locked, $odds_data['odd_ids_locked']);
-
- $update_data = [
- 'is_send' => 0,
- 'is_roll' => 1,
- 'is_locked' => 0,
- 'odd_ids_locked' => array_unique($odd_ids_locked),
- 'odds' => $odds,
- 'error' => 0, //异常类型:0正常;1直播赔率的赛事时异常
- ];
- $odd_fixture_status = null;//直播赔率中的赛事时间和状态(与直播赛事信息中的赛事时间和状态存在较大差异)
- if (isset($item['fixture']['status']['long']) ) {
- // $long = $item['fixture']['status']['long'];
- // if (isset($this->fixture_status[$long])) {
- $sport_info = SportModel::where('data_id',$data_id)->first();
- $fixture_status = $sport_info['fixture_status'] ? json_decode($sport_info['fixture_status'],true) : [];
-
- $odd_fixture_status = $item['fixture']['status'];
- $update_data['odd_fixture_status'] = json_encode($odd_fixture_status);
-
- //如果时间差距超过3分钟,则锁盘
- if (isset($fixture_status['elapsed']) && isset($odd_fixture_status['elapsed'])) {
- if ( $fixture_status['elapsed'] - $odd_fixture_status['elapsed'] >= 3) {
-
- $update_data['error'] = 1; //异常
- $update_data['is_locked'] = 1; //锁盘
- unset($update_data['odds']);//不更新赔率
- } else {
- $update_data['error'] = 0;
- }
- }
- // }
- }
-
- //锁盘
- if (isset($item['fixture']['status']['blocked']) && $item['fixture']['status']['blocked']) {
- $update_data['is_locked'] = 1;
- }
- //提前锁盘(比赛进行时长,分钟)
- if (isset($item['fixture']['status']['elapsed'])) {
- $elapsed = $item['fixture']['status']['elapsed'];
- if ((int)$elapsed >= 90 - $sport_locked ) {
- $update_data['is_locked'] = 1;
- }
- }
- //已结束
- if (isset($item['fixture']['status']['finished']) && $item['fixture']['status']['finished']) {
- $update_data['state'] = 2;
- }
- //如果赛事取消、延期等,标记需要退款
- if (isset($update_data['state']) && $update_data['state'] > 2) {
- $update_data['refund_status'] = 1;
- }
- SportModel::where('data_id', $data_id)->update($update_data);
- } catch (Throwable $e) {
- Log::error("直播赔率单条更新失败 [ID: {$data_id}]: " . $e->getMessage());
- continue;
- }
- }
- }
- public function updateOdds($data_id, $data)
- {
- if (!empty($data['response'][0]['bookmakers'][0]['bets'])) {
- $odds = $data['response'][0]['bookmakers'][0]['bets'];
- SportModel::where('data_id',$data_id)->update(['odds' => json_encode($odds), 'is_send' => 0]);
- }
- }
- //去掉无效的赔率
- private function doOdds($odds, $old_odds) {
- // 1. 获取赔率,缓存数据
- $sport_odds = cache('sport_odds');
- if (!$sport_odds) {
- $sport_odds = SportOddsModel::where('function_name', '<>', null)->get()->toArray();
- Cache::set('sport_odds', $sport_odds, 300); //有效期5分钟
- }
- $old_odds = $old_odds ? json_decode($old_odds, true) : [];
- $odds_ids = []; //新的玩法id集合
- $sport_odds = array_column($sport_odds, null,'odd_name_en');
- $new_odds = [];
- foreach($odds as $item) {
- if (!isset($sport_odds[$item['name']])) {
- continue;
- }
- $new_odds[] = $item;
- $odds_ids[] = $item['id'];
- }
- $odd_ids_locked = [];
- foreach($old_odds as $item) {
- if (!in_array($item['id'], $odds_ids)) {
- $new_odds[] = $item;
- //历史玩法如果没有了,数据保存,加锁
- $odd_ids_locked[] = $item['id'];
- }
- }
- return [
- 'odds' => $new_odds,
- 'odd_ids_locked' => $odd_ids_locked,
- ];
- }
- }
|