Sport.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use App\Models\Sport as SportModel;
  5. use App\Services\SportClientService;
  6. use Carbon\Carbon;
  7. use Illuminate\Support\Facades\DB;
  8. use App\Models\SportEvent;
  9. class Sport extends Command
  10. {
  11. /**
  12. * 命令名称和签名
  13. *
  14. * @var string
  15. */
  16. protected $signature = 'sport {is_live=0}';
  17. protected $is_live = 0;
  18. protected $short_status = [
  19. 'TBD' => 0,
  20. 'NS' => 0,
  21. '1H' => 1,
  22. 'HT' => 1,
  23. '2H' => 1,
  24. 'ET' => 1,
  25. 'BT' => 1,
  26. 'P' => 1,
  27. 'SUSP' => 1,
  28. 'INT' => 1,
  29. 'FT' => 2,
  30. 'AET' => 2,
  31. 'PEN' => 2,
  32. 'PST' => 3,
  33. 'CANC' => 4,
  34. 'ABD' => 4,
  35. 'AWD' => 4,
  36. 'WO' => 4,
  37. 'LIVE' => 1,
  38. ];
  39. /**
  40. * 命令描述
  41. *
  42. * @var string
  43. */
  44. protected $description = '当天会去更新明天的赛事(23:59:00执行一次)';
  45. /**
  46. * 执行命令
  47. *
  48. * @return int
  49. */
  50. public function handle()
  51. {
  52. $this->info('开始执行统计比赛数据任务...');
  53. $this->is_live = $this->argument('is_live');
  54. if ($this->is_live == 1) {
  55. //进行中的赛事,定时更新
  56. $this->liveFixtures();
  57. } else {
  58. //未开始的赛事拉取
  59. $this->fixtures();
  60. }
  61. $this->info('结束执行统计比赛数据任务');
  62. }
  63. //更新进行中的赛事
  64. public function liveFixtures()
  65. {
  66. $data = SportClientService::fixtures(['live' => 'all']);
  67. $data = $data['response'];
  68. $tableData = [];
  69. $status = $this->short_status;
  70. foreach ($data as $item) {
  71. $home_statistics = !empty($item['statistics']) ? $item['statistics'][0]['statistics'] : '';
  72. $away_statistics = !empty($item['statistics']) ? $item['statistics'][1]['statistics'] : '';
  73. $sport_data = [
  74. 'data_id' => $item['fixture']['id'],
  75. 'home_team_id' => $item['teams']['home']['id'],
  76. 'home_team_en' => $item['teams']['home']['name'],
  77. 'home_team' => lang($item['teams']['home']['name']),
  78. 'home_team_logo' => $item['teams']['home']['logo'],
  79. 'guest_team_id' => $item['teams']['away']['id'],
  80. 'guest_team_en' => $item['teams']['away']['name'],
  81. 'guest_team' => lang($item['teams']['away']['name']),
  82. 'guest_team_logo' => $item['teams']['away']['logo'],
  83. 'half_score' => "{$item['score']['halftime']['home']}-{$item['score']['halftime']['away']}",
  84. 'rbt' => $item['fixture']['timestamp'],
  85. 'score' => isset($item['score']['fulltime']) ? "{$item['score']['fulltime']['home']}-{$item['score']['fulltime']['away']}":'-',
  86. 'league' => lang($item['league']['name']),
  87. 'league_en' => $item['league']['name'],
  88. 'state' => $status[$item['fixture']['status']['short']],//比赛状态:0未开始1进行中2已完场3延期4取消
  89. 'game_time' => $item['fixture']['timestamp'],
  90. 'status' => 1,
  91. 'updated_at' => now(),
  92. 'home_statistics' => $home_statistics,
  93. 'away_statistics' => $away_statistics,
  94. ];
  95. $sport_data['score'] = $sport_data['score'] == '-' ? '' : $sport_data['score'];
  96. $sport_data['half_score'] = $sport_data['half_score'] == '-' ? '' : $sport_data['half_score'];
  97. if (!SportModel::where('data_id', $item['fixture']['id'])->exists()) {
  98. $sport_data['created_at'] = now();
  99. $tableData[] = $sport_data;
  100. } else {
  101. SportModel::where('data_id', $item['fixture']['id'])->update($sport_data);
  102. }
  103. //比赛结束,插入比赛事件
  104. if ($sport_data['state'] == 2 && !empty($item['events'])) {
  105. foreach($item['events'] as $event) {
  106. SportEvent::create([
  107. 'data_id' => $item['fixture']['id'],
  108. 'type' => $event['type'],
  109. 'time_elapsed' => $event['time']['elapsed'],
  110. 'time' => json_encode($event['time']),
  111. 'detail' => $event['detail'],
  112. 'player' => $event['player'] ? json_encode($event['player']) : $event['player'],
  113. 'team_id' => $event['team']['id'],
  114. 'comments' => $event['comments'],
  115. 'assist' => $event['assist'] ? json_encode($event['assist']) : $event['assist'],
  116. ]);
  117. }
  118. }
  119. }
  120. if ($tableData) {
  121. SportModel::insert($tableData);
  122. }
  123. return $tableData;
  124. }
  125. /**
  126. * 获取指定日期的所有赛事
  127. *
  128. * @return array
  129. */
  130. public function fixtures()
  131. {
  132. $date = Carbon::tomorrow()->toDateString();
  133. // $date = '2026-03-28';
  134. // $data = SportClientService::odds([
  135. // 'fixture' => 1461571,
  136. // ]);
  137. // file_put_contents("1461571-fixtures.json",json_encode($data));
  138. // $data = SportClientService::fixtures(['live' => 'all']);
  139. $data = SportClientService::fixtures(['date' => $date]);
  140. $data = $data['response'];
  141. $tableData = [];
  142. $status = $this->short_status;
  143. foreach ($data as $item) {
  144. $home_statistics = !empty($item['statistics']) ? $item['statistics'][0]['statistics'] : '';
  145. $away_statistics = !empty($item['statistics']) ? $item['statistics'][1]['statistics'] : '';
  146. $sport_data = [
  147. 'data_id' => $item['fixture']['id'],
  148. 'home_team_id' => $item['teams']['home']['id'],
  149. 'home_team_en' => $item['teams']['home']['name'],
  150. 'home_team' => lang($item['teams']['home']['name']),
  151. 'home_team_logo' => $item['teams']['home']['logo'],
  152. 'guest_team_id' => $item['teams']['away']['id'],
  153. 'guest_team_en' => $item['teams']['away']['name'],
  154. 'guest_team' => lang($item['teams']['away']['name']),
  155. 'guest_team_logo' => $item['teams']['away']['logo'],
  156. 'half_score' => "{$item['score']['halftime']['home']}-{$item['score']['halftime']['away']}",
  157. 'rbt' => $item['fixture']['timestamp'],
  158. 'score' => isset($item['score']['fulltime']) ? "{$item['score']['fulltime']['home']}-{$item['score']['fulltime']['away']}":'-',
  159. 'league' => lang($item['league']['name']),
  160. 'league_en' => $item['league']['name'],
  161. 'state' => $status[$item['fixture']['status']['short']],//比赛状态:0未开始1进行中2已完场3延期4取消
  162. 'game_time' => $item['fixture']['timestamp'],
  163. 'status' => 1,
  164. 'updated_at' => now(),
  165. 'home_statistics' => $home_statistics,
  166. 'away_statistics' => $away_statistics,
  167. 'is_send' => 0,
  168. ];
  169. $sport_data['score'] = $sport_data['score'] == '-' ? '' : $sport_data['score'];
  170. $sport_data['half_score'] = $sport_data['half_score'] == '-' ? '' : $sport_data['half_score'];
  171. if (!SportModel::where('data_id', $item['fixture']['id'])->exists()) {
  172. $sport_data['created_at'] = now();
  173. $tableData[] = $sport_data;
  174. } else {
  175. SportModel::where('data_id', $item['fixture']['id'])->update($sport_data);
  176. }
  177. //比赛结束,插入比赛事件
  178. if ($sport_data['state'] == 2 && !empty($item['events'])) {
  179. foreach($item['events'] as $event) {
  180. SportEvent::create([
  181. 'data_id' => $item['fixture']['id'],
  182. 'type' => $event['type'],
  183. 'time_elapsed' => $event['time']['elapsed'],
  184. 'time' => json_encode($event['time']),
  185. 'detail' => $event['detail'],
  186. 'player' => $event['player'] ? json_encode($event['player']) : $event['player'],
  187. 'team_id' => $event['team']['id'],
  188. 'comments' => $event['comments'],
  189. 'assist' => $event['assist'] ? json_encode($event['assist']) : $event['assist'],
  190. ]);
  191. }
  192. }
  193. }
  194. if ($tableData) {
  195. SportModel::insert($tableData);
  196. }
  197. return $tableData;
  198. }
  199. public function initOdds(){
  200. $page = 1;
  201. $limit = 10;
  202. while (true) {
  203. $list = SportModel::where('odds','<>', null)->forPage($page, $limit)->get()->toArray();
  204. if (empty($list)) {
  205. break;
  206. }
  207. echo $page.PHP_EOL;
  208. foreach($list as $item) {
  209. $odds = json_decode($item['odds'], true);
  210. foreach($odds as $odd) {
  211. $odd_id = $odd['id'];
  212. $odd_name = $odd['name'];
  213. $info = DB::table('sport_odds')->where('odd_id',$odd_id)->where('odd_name_en',$odd_name)->first();
  214. if ($info && (!$info->odd_name || $odd_name != $info->odd_name_en)) {
  215. DB::table('sport_odds')->where('id', $info->id)->update([
  216. 'odd_name_en' => $odd_name,
  217. 'odd_name' => $this->getZhName($odd_name),
  218. ]);
  219. echo '更新数据:'.$odd_id.'-'.$odd_name.PHP_EOL;
  220. } elseif (!$info) {
  221. DB::table('sport_odds')->insert([
  222. 'odd_id' => $odd_id,
  223. 'odd_name_en' => $odd_name,
  224. 'odd_name' => $this->getZhName($odd_name),
  225. 'created_at' => date('Y-m-d H:i:s'),
  226. 'updated_at' => date('Y-m-d H:i:s'),
  227. ]);
  228. echo '插入数据:'.$odd_id.'-'.$odd_name.PHP_EOL;
  229. }
  230. }
  231. }
  232. $page++;
  233. }
  234. }
  235. public function getZhName ($name) {
  236. $betting_terms = [
  237. "Match Winner" => "全场胜负",
  238. "Home/Away" => "主胜/客胜",
  239. "Second Half Winner" => "下半场胜负",
  240. "Asian Handicap" => "亚洲让球盘",
  241. "Goals Over/Under" => "全场大小球",
  242. "Goals Over/Under First Half" => "上半场大小球",
  243. "Goals Over/Under - Second Half" => "下半场大小球",
  244. "HT/FT Double" => "半场+全场双猜",
  245. "Both Teams Score" => "双方均进球",
  246. "Handicap Result" => "让球结果",
  247. "Exact Score" => "精确比分",
  248. "Correct Score - First Half" => "上半场精确比分",
  249. "Correct Score - Second Half" => "下半场精确比分",
  250. "Double Chance" => "双选胜平负",
  251. "First Half Winner" => "上半场胜负",
  252. "Team To Score First" => "首支进球球队",
  253. "Team To Score Last" => "最后进球球队",
  254. "Win Both Halves" => "上下半场均获胜",
  255. "Total - Home" => "主队总进球数",
  256. "Total - Away" => "客队总进球数",
  257. "Both Teams Score - First Half" => "上半场双方均进球",
  258. "Both Teams To Score - Second Half" => "下半场双方均进球",
  259. "Odd/Even" => "总进球数奇偶",
  260. "Odd/Even - First Half" => "上半场进球奇偶",
  261. "Home Team Exact Goals Number" => "主队精确进球数",
  262. "Away Team Exact Goals Number" => "客队精确进球数",
  263. "Results/Both Teams Score" => "赛果+双方进球",
  264. "Odd/Even - Second Half" => "下半场进球奇偶",
  265. "Clean Sheet - Home" => "主队零封",
  266. "Clean Sheet - Away" => "客队零封",
  267. "Win to Nil - Home" => "主队零封获胜",
  268. "Win to Nil - Away" => "客队零封获胜",
  269. "Highest Scoring Half" => "进球更多的半场",
  270. "Handicap Result - First Half" => "上半场让球结果",
  271. "Asian Handicap First Half" => "上半场亚洲让球盘",
  272. "Double Chance - First Half" => "上半场双选胜平负",
  273. "Win To Nil" => "零封获胜",
  274. "Home Odd/Even" => "主队进球奇偶",
  275. "Away Odd/Even" => "客队进球奇偶",
  276. "To Win Either Half" => "赢得任意半场",
  277. "Result/Total Goals" => "赛果+总进球数",
  278. "First 10 min Winner" => "前10分钟胜负",
  279. "Corners Over Under" => "角球大小",
  280. "Home Team Total Goals(1st Half)" => "主队上半场总进球",
  281. "Away Team Total Goals(1st Half)" => "客队上半场总进球",
  282. "Home Team Total Goals(2nd Half)" => "主队下半场总进球",
  283. "Away Team Total Goals(2nd Half)" => "客队下半场总进球",
  284. "Draw No Bet (1st Half)" => "上半场让球平注",
  285. "European Handicap (2nd Half)" => "下半场欧洲让球",
  286. "Draw No Bet (2nd Half)" => "下半场让球平注",
  287. "Total Goals/Both Teams To Score" => "总进球+双方进球",
  288. "Home Corners Over/Under" => "主队角球大小",
  289. "Away Corners Over/Under" => "客队角球大小",
  290. "Total Corners (3 way)" => "总角球三路",
  291. "1x2 - 60 minutes" => "60分钟胜平负",
  292. "1x2 - 30 minutes" => "30分钟胜平负",
  293. "First Team to Score (3 way) 1st Half" => "上半场首支进球球队(三路)",
  294. "Total Corners (1st Half)" => "上半场总角球",
  295. "Corners. Odd/Even" => "角球奇偶",
  296. "RTG_H1" => "上半场进球数(简写)",
  297. "Cards Over/Under" => "黄牌大小",
  298. "To Qualify" => "晋级球队",
  299. "Goal Line" => "进球线",
  300. "Goal Line (1st Half)" => "上半场进球线",
  301. "Home team will score in both halves" => "主队上下半场均进球",
  302. "Away team will score in both halves" => "客队上下半场均进球",
  303. "Last Corner" => "最后角球",
  304. "How many goals will Away Team score?" => "客队进球数",
  305. "Asian Corners" => "亚洲让角球",
  306. "Match Corners" => "全场角球",
  307. "Final Score" => "最终比分",
  308. "Match Goals" => "全场进球",
  309. "Home Team Score a Goal (2nd Half)" => "主队下半场进球",
  310. "Result / Both Teams To Score" => "赛果/双方进球",
  311. "To Win 2nd Half" => "赢下半场",
  312. "Over/Under Line" => "大小球盘口",
  313. "3-Way Handicap" => "三路让球",
  314. "Away Team Goals" => "客队进球",
  315. "Both Teams To Score (2nd Half)" => "下半场双方进球",
  316. "Which team will score the 5th corner? (2 Way)" => "第5个角球归属(二路)",
  317. "Race to the 9th corner?" => "先得9个角球",
  318. "Race to the 7th corner?" => "先得7个角球",
  319. "Draw No Bet" => "让球平注",
  320. "Home Team Goals" => "主队进球",
  321. "Total Corners" => "总角球",
  322. "Fulltime Result" => "全场赛果",
  323. "Race to the 5th corner?" => "先得5个角球",
  324. "Last Team to Score (3 way)" => "最后进球球队(三路)",
  325. "Which team will score the 2nd goal?" => "第二球归属球队",
  326. "Home Team Clean Sheet" => "主队零封",
  327. "How many goals will Home Team score?" => "主队进球数",
  328. "Goals Odd/Even" => "进球奇偶",
  329. "Both Teams to Score" => "双方均进球",
  330. "Away Team Score a Goal (2nd Half)" => "客队下半场进球",
  331. "Which team will score the 4th goal?" => "第四球归属球队",
  332. "Which team will score the 7th corner? (2 Way)" => "第7个角球归属(二路)",
  333. ];
  334. if (isset($betting_terms[$name])) {
  335. return $betting_terms[$name];
  336. }
  337. return '';
  338. }
  339. }