Преглед изворни кода

提交足球结算和docker文件

lip пре 2 дана
родитељ
комит
1f9be2fbaf

+ 38 - 0
.dockerignore

@@ -0,0 +1,38 @@
+# 排除版本控制目录
+.git/
+.gitignore
+
+# 排除依赖目录
+vendor/
+node_modules/
+
+# 排除环境文件
+.env
+.env.local
+.env.*.local
+
+# 排除日志文件
+storage/logs/
+
+# 排除缓存文件
+bootstrap/cache/
+
+# 排除编译后的文件
+public/js/
+public/css/
+public/mix-manifest.json
+
+# 排除测试文件
+tests/
+phpunit.xml
+
+# 排除IDE配置文件
+.idea/
+.vscode/
+*.swp
+*.swo
+
+# 排除大型文件和目录
+storage/app/public/lottery/
+storage/app/public/avatars/
+storage/app/public/images/

+ 1 - 0
.gitignore

@@ -27,3 +27,4 @@ yarn-error.log
 /package-lock.json
 /src/
 /doc/
+DOCKER_README.md

+ 51 - 0
Dockerfile

@@ -0,0 +1,51 @@
+FROM php:8.4-fpm-alpine
+
+# 安装系统依赖
+RUN apk add --no-cache \
+    libpng-dev \
+    libjpeg-turbo-dev \
+    freetype-dev \
+    libzip-dev \
+    gmp-dev \
+    curl \
+    fontconfig \
+    tzdata \
+    && docker-php-ext-configure gd --with-freetype --with-jpeg \
+    && docker-php-ext-install -j$(nproc) \
+    gd \
+    gmp \
+    bcmath \
+    fileinfo \
+    zip \
+    pdo_mysql \
+    && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
+    && echo "Asia/Shanghai" > /etc/timezone
+
+# 注意:openssl和curl是PHP内置扩展,不需要单独安装
+
+# 设置工作目录
+WORKDIR /var/www/html
+
+# 复制项目文件
+COPY . .
+
+# 创建bootstrap/cache目录并设置权限
+RUN mkdir -p bootstrap/cache && chmod -R 755 bootstrap/cache
+
+# 安装Composer
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+
+# 安装项目依赖
+RUN composer install --no-dev
+
+# 创建存储软链接
+RUN php artisan storage:link
+
+# 创建队列表
+RUN php artisan queue:table
+
+# 暴露端口
+EXPOSE 9000
+
+# 启动PHP-FPM
+CMD ["php-fpm"]

+ 4 - 8
README.md

@@ -101,6 +101,9 @@ APP_NAME=lovingtalk
 APP_DEBUG=false
 APP_URL=http://localhost:8080
 
+#足球app接口域名
+FOOTBALL_APP_URL=http://sportapi.sp2509.cc
+
 # 数据库
 DB_CONNECTION=mysql
 DB_HOST=127.0.0.1
@@ -156,11 +159,4 @@ MAIL_EXP=600  # 邮件验证码有效期(秒)
 
 ## 七、支付配置
 
-    
-
-
-
-
-
-
-
+    

+ 86 - 0
app/Console/Commands/FootballSettlement.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Models\Order;
+
+class FootballSettlement extends Command
+{
+    /**
+     * 命令名称和签名
+     *
+     * @var string
+     */
+    protected $signature = 'football:settlement';
+    
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = '足球结算方法';
+    /**
+     * 执行命令
+     *
+     * @return int
+     */
+    public function handle()
+    {
+
+        $this->sportOrderSettlement();
+        $function = 'MatchWinner';
+        $params = [
+            'amount' => 10,
+            'score' => '1-1',
+            'detail' => [
+                'odds' => [
+                    [
+                        "id" => 1,
+                        "name" => "Match Winner",
+                        "values" => [
+                            [
+                                "value" => "Draw",
+                                "odd" => "3.30"
+                            ]
+                        ]
+                    ]
+                ]
+            ],
+        ];
+        $result = $this->doFunction($function, $params);
+        print_r($result);die;
+        return $result;
+    }
+
+    public function sportOrderSettlement(){
+        $where = [
+            'status' => 1,
+            'pay_status' => 1,
+            'return_status' => 0,
+            'settlement_status' => 0,
+        ];
+        $list = Order::alias('o')
+                ->join('sport s', 'o.data_id', '=', 's.data_id')
+                ->where('s.state', 2)
+                ->where($where)
+                ->select('o.*', 's.score','s.half_score')
+                ->get()->toArray();
+        foreach($list as $item) {
+            $detail = json_decode($item['detail'], true);
+            $odd_id = $detail['odds'][0]['id'];
+            $function = SportOdds::where('id',$odd_id)->value('function_name');
+            $params = [
+                'score' => $item['score'], 
+                'half_score' => $item['half_score'],
+                'data_id' => $item['data_id'],
+                'home_team_id' => $item['home_team_id'],
+                'guest_team_id' => $item['guest_team_id'],
+            ];
+            $result = $function($item['amount'], $detail, $params);
+            print_r($result);die;
+        }
+    }
+
+
+}

+ 199 - 134
app/Console/Commands/Sport.php

@@ -6,6 +6,8 @@ use Illuminate\Console\Command;
 use App\Models\Sport as SportModel;
 use App\Services\SportClientService;
 use Carbon\Carbon;
+use Illuminate\Support\Facades\DB;
+use App\Models\SportEvent;
 
 class Sport extends Command
 {
@@ -16,6 +18,29 @@ class Sport extends Command
      */
     protected $signature = 'sport';
 
+    protected  $short_status = [
+            'TBD' => 0,
+            'NS' => 0,
+            '1H' => 1,
+            'HT' => 1,
+            '2H' => 1,
+            'ET' => 1,
+            'BT' => 1,
+            'P' => 1,
+            'SUSP' => 1,
+            'INT' => 1,
+            'FT' => 2,
+            'AET' => 2,
+            'PEN' => 2,
+            'PST' => 3,
+            'CANC' => 4,
+            'ABD' => 4,
+            'AWD' => 4,
+            'WO' => 4,
+            'LIVE' => 1,
+        ];
+   
+
     /**
      * 命令描述
      *
@@ -29,73 +54,160 @@ class Sport extends Command
      */
     public function handle()
     {
+        
         $this->info('开始执行统计比赛数据任务...');
 
+        // $data = SportClientService::fixtures(['id' => '1506018']);
+        // file_put_contents('fixtures-1506018.json', json_encode($data));
+        // die;
+
         $this->fixtures();
         
         $this->info('结束执行统计比赛数据任务');
     }
 
-    public function sportData()
-    {
-        try {
-            $today = date('Y-m-d');
-            $host = env('SPORT_HOST');
-            $url = "{$host}/api/sport";
-            $url .= "?date={$today}";
-            $result = file_get_contents($url);
-            $result = $result ? json_decode($result, true) : [];
-            foreach ($result as $item) {
-                $info = SportModel::where('data_id',$item['data_id'])->first();
-                $data = [
-                    'home_team_id' => $item['home_team_id'] ?? '',
-                    'home_team_en' => $item['home_team_en'] ?? '',
-                    'home_team' => $item['home_team'] ?? '',
-                    'home_team_logo' => $item['home_team_logo'] ?? '',
-                    'guest_team_id' => $item['guest_team_id'] ?? '',
-                    'guest_team_en' => $item['guest_team_en'] ?? '',
-                    'guest_team' => $item['guest_team'] ?? '',
-                    'guest_team_logo' => $item['guest_team_logo'] ?? '',
-                    'half_score' => $item['half_score'] ?? '',
-                    'rbt' => $item['rbt'] ?? '',
-                    'is_roll' => $item['is_roll'] ?? 0,
-                    'score' => $item['score'] ?? '',
-                    'league_en' => $item['league_en'] ?? '',
-                    'league' => $item['league'] ?? '',
-                    'odds' => $item['odds'] ?? '',
-                    'state' => $item['state'] ?? 0,
-                    'game_time' => $item['game_time'] ?? 0,
-                    'status' => $item['status'] ?? 0,
-                    'handicap_limit' => $item['handicap_limit'] ?? '',
-                    'over_under_limit' => $item['over_under_limit'] ?? '',
-                    'duying_limit' => $item['duying_limit'] ?? '',
-                    'correct_core_limit' => $item['correct_core_limit'] ?? '',
-                    'odd_even_limit' => $item['odd_even_limit'] ?? '',
-                    'total_goal_limit' => $item['total_goal_limit'] ?? '',
-                    'is_handicap' => $item['is_handicap'] ?? 0,
-                    'is_over_under' => $item['is_over_under'] ?? 0,
-                    'is_duying' => $item['is_duying'] ?? 0,
-                    'is_correct_core' => $item['is_correct_core'] ?? 0,
-                    'is_odd_even' => $item['is_odd_even'] ?? 0,
-                    'is_total_goal' => $item['is_total_goal'] ?? 0,
-                    'is_locked' => $item['is_locked'] ?? 0,
-                ];
-                if ($info) {
-                    //更新数据
-                    SportModel::where('data_id',$item['data_id'])->update($data);
-                } else {
-                    $data['data_id'] = $item['data_id'];
-                    SportModel::create($data);
+    public function initOdds(){
+        $page = 1;
+        $limit = 10;
+        while (true) { 
+            $list = SportModel::where('odds','<>', null)->forPage($page, $limit)->get()->toArray();
+            if (empty($list)) {
+                break;
+            }
+            echo $page.PHP_EOL;
+            foreach($list as $item) {
+                $odds = json_decode($item['odds'], true);
+                foreach($odds as $odd) {
+                    $odd_id = $odd['id'];
+                    $odd_name = $odd['name'];
+                    $info = DB::table('sport_odds')->where('odd_id',$odd_id)->where('odd_name_en',$odd_name)->first();
+                    if ($info && (!$info->odd_name || $odd_name != $info->odd_name_en)) {
+                        DB::table('sport_odds')->where('id', $info->id)->update([
+                            'odd_name_en' => $odd_name,
+                            'odd_name' => $this->getZhName($odd_name),
+                        ]);
+                        echo '更新数据:'.$odd_id.'-'.$odd_name.PHP_EOL;
+                    } elseif (!$info) {
+                        DB::table('sport_odds')->insert([
+                            'odd_id' => $odd_id,
+                            'odd_name_en' => $odd_name,
+                            'odd_name' => $this->getZhName($odd_name),
+                            'created_at' => date('Y-m-d H:i:s'),
+                            'updated_at' => date('Y-m-d H:i:s'),
+                        ]);
+                        echo '插入数据:'.$odd_id.'-'.$odd_name.PHP_EOL;
+                    }
                 }
             }
-        } catch (\Exception $e) {
-            $this->error($e->getMessage());
+
+            $page++;
         }
+    }
 
-        
-        
-       
-        return true;
+    public function getZhName ($name) {
+        $betting_terms = [
+            "Match Winner" => "全场胜负",
+            "Home/Away" => "主胜/客胜",
+            "Second Half Winner" => "下半场胜负",
+            "Asian Handicap" => "亚洲让球盘",
+            "Goals Over/Under" => "全场大小球",
+            "Goals Over/Under First Half" => "上半场大小球",
+            "Goals Over/Under - Second Half" => "下半场大小球",
+            "HT/FT Double" => "半场+全场双猜",
+            "Both Teams Score" => "双方均进球",
+            "Handicap Result" => "让球结果",
+            "Exact Score" => "精确比分",
+            "Correct Score - First Half" => "上半场精确比分",
+            "Correct Score - Second Half" => "下半场精确比分",
+            "Double Chance" => "双选胜平负",
+            "First Half Winner" => "上半场胜负",
+            "Team To Score First" => "首支进球球队",
+            "Team To Score Last" => "最后进球球队",
+            "Win Both Halves" => "上下半场均获胜",
+            "Total - Home" => "主队总进球数",
+            "Total - Away" => "客队总进球数",
+            "Both Teams Score - First Half" => "上半场双方均进球",
+            "Both Teams To Score - Second Half" => "下半场双方均进球",
+            "Odd/Even" => "总进球数奇偶",
+            "Odd/Even - First Half" => "上半场进球奇偶",
+            "Home Team Exact Goals Number" => "主队精确进球数",
+            "Away Team Exact Goals Number" => "客队精确进球数",
+            "Results/Both Teams Score" => "赛果+双方进球",
+            "Odd/Even - Second Half" => "下半场进球奇偶",
+            "Clean Sheet - Home" => "主队零封",
+            "Clean Sheet - Away" => "客队零封",
+            "Win to Nil - Home" => "主队零封获胜",
+            "Win to Nil - Away" => "客队零封获胜",
+            "Highest Scoring Half" => "进球更多的半场",
+            "Handicap Result - First Half" => "上半场让球结果",
+            "Asian Handicap First Half" => "上半场亚洲让球盘",
+            "Double Chance - First Half" => "上半场双选胜平负",
+            "Win To Nil" => "零封获胜",
+            "Home Odd/Even" => "主队进球奇偶",
+            "Away Odd/Even" => "客队进球奇偶",
+            "To Win Either Half" => "赢得任意半场",
+            "Result/Total Goals" => "赛果+总进球数",
+            "First 10 min Winner" => "前10分钟胜负",
+            "Corners Over Under" => "角球大小",
+            "Home Team Total Goals(1st Half)" => "主队上半场总进球",
+            "Away Team Total Goals(1st Half)" => "客队上半场总进球",
+            "Home Team Total Goals(2nd Half)" => "主队下半场总进球",
+            "Away Team Total Goals(2nd Half)" => "客队下半场总进球",
+            "Draw No Bet (1st Half)" => "上半场让球平注",
+            "European Handicap (2nd Half)" => "下半场欧洲让球",
+            "Draw No Bet (2nd Half)" => "下半场让球平注",
+            "Total Goals/Both Teams To Score" => "总进球+双方进球",
+            "Home Corners Over/Under" => "主队角球大小",
+            "Away Corners Over/Under" => "客队角球大小",
+            "Total Corners (3 way)" => "总角球三路",
+            "1x2 - 60 minutes" => "60分钟胜平负",
+            "1x2 - 30 minutes" => "30分钟胜平负",
+            "First Team to Score (3 way) 1st Half" => "上半场首支进球球队(三路)",
+            "Total Corners (1st Half)" => "上半场总角球",
+            "Corners. Odd/Even" => "角球奇偶",
+            "RTG_H1" => "上半场进球数(简写)",
+            "Cards Over/Under" => "黄牌大小",
+            "To Qualify" => "晋级球队",
+            "Goal Line" => "进球线",
+            "Goal Line (1st Half)" => "上半场进球线",
+            "Home team will score in both halves" => "主队上下半场均进球",
+            "Away team will score in both halves" => "客队上下半场均进球",
+            "Last Corner" => "最后角球",
+            "How many goals will Away Team score?" => "客队进球数",
+            "Asian Corners" => "亚洲让角球",
+            "Match Corners" => "全场角球",
+            "Final Score" => "最终比分",
+            "Match Goals" => "全场进球",
+            "Home Team Score a Goal (2nd Half)" => "主队下半场进球",
+            "Result / Both Teams To Score" => "赛果/双方进球",
+            "To Win 2nd Half" => "赢下半场",
+            "Over/Under Line" => "大小球盘口",
+            "3-Way Handicap" => "三路让球",
+            "Away Team Goals" => "客队进球",
+            "Both Teams To Score (2nd Half)" => "下半场双方进球",
+            "Which team will score the 5th corner? (2 Way)" => "第5个角球归属(二路)",
+            "Race to the 9th corner?" => "先得9个角球",
+            "Race to the 7th corner?" => "先得7个角球",
+            "Draw No Bet" => "让球平注",
+            "Home Team Goals" => "主队进球",
+            "Total Corners" => "总角球",
+            "Fulltime Result" => "全场赛果",
+            "Race to the 5th corner?" => "先得5个角球",
+            "Last Team to Score (3 way)" => "最后进球球队(三路)",
+            "Which team will score the 2nd goal?" => "第二球归属球队",
+            "Home Team Clean Sheet" => "主队零封",
+            "How many goals will Home Team score?" => "主队进球数",
+            "Goals Odd/Even" => "进球奇偶",
+            "Both Teams to Score" => "双方均进球",
+            "Away Team Score a Goal (2nd Half)" => "客队下半场进球",
+            "Which team will score the 4th goal?" => "第四球归属球队",
+            "Which team will score the 7th corner? (2 Way)" => "第7个角球归属(二路)",
+        ];
+
+        if (isset($betting_terms[$name])) {
+            return $betting_terms[$name];
+        }
+        return '';
     }
 
     /**
@@ -106,11 +218,17 @@ class Sport extends Command
     public function fixtures()
     {
         $date = Carbon::tomorrow()->toDateString();
+        // $date = '2026-03-07';
         $data = SportClientService::fixtures(['date' => $date]);
+        // $data = SportClientService::fixtures(['live' => 'all']);
+
         $data = $data['response'];
         $tableData = [];
-        $status = ['NS' => 0, '1H' => 1, 'HT' => 1, '2H' => 1, 'ET' => 1, 'BT' => 1, 'P' => 1, 'SUSP' => 1, 'INT' => 1, 'LIVE' => 1, 'FT' => 2, 'AET' => 2, 'PEN' => 2, 'PST' => 3, 'CANC' => 4, 'ABD' => 4,];
+        $status = $this->short_status;
         foreach ($data as $item) {
+            $home_statistics = !empty($item['statistics']) ? $item['statistics'][0]['statistics'] : '';
+            $away_statistics = !empty($item['statistics']) ? $item['statistics'][1]['statistics'] : '';
+
             $sport_data = [
                 'data_id' => $item['fixture']['id'],
                 'home_team_id' => $item['teams']['home']['id'],
@@ -123,19 +241,42 @@ class Sport extends Command
                 'guest_team_logo' => $item['teams']['away']['logo'],
                 'half_score' => "{$item['score']['halftime']['home']}-{$item['score']['halftime']['away']}",
                 'rbt' => $item['fixture']['timestamp'],
-                'score' => "{$item['score']['fulltime']['home']}-{$item['goals']['fulltime']['away']}",
+                'score' => isset($item['score']['fulltime']) ? "{$item['score']['fulltime']['home']}-{$item['score']['fulltime']['away']}":'-',
                 'league' => lang($item['league']['name']),
                 'league_en' => $item['league']['name'],
                 'state' => $status[$item['fixture']['status']['short']],//比赛状态:0未开始1进行中2已完场3延期4取消
                 'game_time' => $item['fixture']['timestamp'],
+                'status' => 1,
                 'updated_at' => now(),
+                'home_statistics' => $home_statistics,
+                'away_statistics' => $away_statistics,
             ];
+            $sport_data['score'] = $sport_data['score'] == '-' ? '' : $sport_data['score'];
+            $sport_data['half_score'] = $sport_data['half_score'] == '-' ? '' : $sport_data['half_score'];
+
             if (!SportModel::where('data_id', $item['fixture']['id'])->exists()) {
                 $sport_data['created_at'] = now();
                 $tableData[] = $sport_data;
             } else {
                 SportModel::where('data_id', $item['fixture']['id'])->update($sport_data);
             }
+            //比赛结束,插入比赛事件
+            if ($sport_data['state'] == 2 && !empty($item['events'])) {
+                foreach($item['events'] as $event) {
+                    SportEvent::create([
+                        'data_id' => $item['fixture']['id'],
+                        'type' => $event['type'],
+                        'time_elapsed' => $event['time']['elapsed'],
+                        'time' => json_encode($event['time']),
+                        'detail' => $event['detail'],
+                        'player' => $event['player'] ? json_encode($event['player']) : $event['player'],
+                        'team_id' => $event['team']['id'],
+                        'comments' => $event['comments'],
+                        'assist' => $event['assist'] ? json_encode($event['assist']) : $event['assist'],
+                    ]);
+                }
+
+            }
         }
         if ($tableData) {
             SportModel::insert($tableData);
@@ -143,80 +284,4 @@ class Sport extends Command
         return $tableData;
     }
 
-      // 核心响应数据:赛事列表(数组形式,每个元素对应一场赛事)
-//   "response": [
-//     {
-//       // 赛事基础信息
-//       "fixture": {
-//         "id": 239625,                // 赛事唯一ID
-//         "referee": null,             // 主裁判姓名(null表示暂无数据)
-//         "timezone": "UTC",           // 赛事时间所属时区
-//         "date": "2020-02-06T14:00:00+00:00", // 赛事开始时间(ISO 8601格式)
-//         "timestamp": 1580997600,     // 赛事开始时间戳(秒级)
-//         "periods": {                 // 赛事时段时间戳
-//           "first": 1580997600,       // 上半场开始时间戳
-//           "second": null             // 下半场开始时间戳(null表示尚未开始)
-//         },
-//         "venue": {                   // 赛事场馆信息
-//           "id": 1887,                // 场馆唯一ID
-//           "name": "Stade Municipal", // 场馆名称
-//           "city": "Oued Zem"         // 场馆所在城市
-//         },
-//         "status": {                  // 赛事当前状态
-//           "long": "Halftime",        // 状态描述(长文本):半场休息
-//           "short": "HT",             // 状态缩写:HT=Halftime(半场)
-//           "elapsed": 45,             // 已进行时长(分钟):45分钟(半场结束)
-//           "extra": null              // 补时/加时时长(null表示无)
-//         }
-//       },
-//       // 联赛信息
-//       "league": {
-//         "id": 200,                           // 联赛唯一ID
-//         "name": "Botola Pro",                // 联赛名称:摩洛哥职业足球甲级联赛
-//         "country": "Morocco",                // 联赛所属国家
-//         "logo": "https://media.api-sports.io/football/leagues/115.png", // 联赛logo地址
-//         "flag": "https://media.api-sports.io/flags/ma.svg",             // 国家旗帜地址
-//         "season": 2019,                      // 赛事赛季:2019/2020赛季(通常取首年)
-//         "round": "Regular Season - 14"       // 联赛轮次:常规赛第14轮
-//       },
-//       // 参赛球队信息
-//       "teams": {
-//         "home": {                           // 主队信息
-//           "id": 967,                        // 主队ID
-//           "name": "Rapide Oued ZEM",        // 主队名称
-//           "logo": "https://media.api-sports.io/football/teams/967.png", // 主队logo地址
-//           "winner": false                   // 是否获胜:false(半场暂时落后)
-//         },
-//         "away": {                           // 客队信息
-//           "id": 968,                        // 客队ID
-//           "name": "Wydad AC",               // 客队名称
-//           "logo": "https://media.api-sports.io/football/teams/968.png", // 客队logo地址
-//           "winner": true                    // 是否获胜:true(半场暂时领先)
-//         }
-//       },
-//       // 进球数(当前已产生的总进球数)
-//       "goals": {
-//         "home": 0,  // 主队进球数
-//         "away": 1   // 客队进球数
-//       },
-//       // 比分详情(不同时段的比分)
-//       "score": {
-//         "halftime": {       // 半场比分
-//           "home": 0,        // 主队半场进球
-//           "away": 1         // 客队半场进球
-//         },
-//         "fulltime": {       // 全场比分(null表示赛事未结束)
-//           "home": null,
-//           "away": null
-//         },
-//         "extratime": {      // 加时赛比分(null表示无加时/未进行)
-//           "home": null,
-//           "away": null
-//         },
-//         "penalty": {        // 点球大战比分(null表示无点球/未进行)
-//           "home": null,
-//           "away": null
-//         }
-//       }
-
 }

+ 97 - 31
app/Console/Commands/SportOdds.php

@@ -4,6 +4,7 @@ namespace App\Console\Commands;
 
 use Illuminate\Console\Command;
 use App\Models\Sport as SportModel;
+use App\Services\SportClientService;
 
 class SportOdds extends Command
 {
@@ -12,16 +13,40 @@ class SportOdds extends Command
      *
      * @var string
      */
-    protected $signature = 'sport:odds {is_roll=0}';
+    protected $signature = 'sport:odds {is_live=0}';
 
-    protected $is_roll = 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,
+    ];        
 
     /**
      * 命令描述
      *
      * @var string
      */
-    protected $description = '赔率(滚球5秒更新一次,普通的3小时更新一次)';
+    protected $description = '赔率(直播赔率5秒更新一次,塞前赔率3小时更新一次)';
     /**
      * 执行命令
      *
@@ -29,50 +54,91 @@ class SportOdds extends Command
      */
     public function handle()
     {
-        $this->is_roll = $this->argument('is_roll');
 
-        if ($this->is_roll == 1) {
-            $this->info('滚球开始执行赔率任务...');
-            $this->sportOddsData($this->is_roll);
+    $data = SportClientService::odds([
+                'fixture' => '1526463',
+            ]);
+        file_put_contents('odds-1526463.json', json_encode($data, JSON_UNESCAPED_UNICODE));
+        die;
+
+        $this->is_live = $this->argument('is_live');
+        if ($this->is_live == 1) {
+            $this->info('直播赔率开始执行任务...');
+            $this->sportOddsData($this->is_live);
         } else {
-            $this->info('普通开始执行赔率任务...');
-            $this->sportOddsData($this->is_roll);
+            $this->info('开赛前赔率开始执行任务...');
+            $this->sportOddsData($this->is_live);
         }
         
         $this->info('结束执行赔率任务');
     }
 
-    public function sportOddsData($is_roll)
+    public function sportOddsData($is_live)
     {
         try {
-            $host = env('SPORT_HOST');
-            $where['status'] = 1;
-            $where['is_roll'] = $is_roll;
-            //滚球(滚球是开赛后随时可以买,更新数据)
-            if ($is_roll == 1) {
-                $where['state'] = 1; //比赛状态:0未开始1进行中2已完场3延期4取消
-                $url = "{$host}/api/sport/oddsLive";
+            $limit = 100;
+            //直播赔率(获取正在直播的所有赛事的赔率)
+            if ($is_live == 1) {
+                $data = SportClientService::oddsLive([]);
+                $this->updateOddsLive($data);
             } else {
-                //普通球赛是开赛前购买,更新数据
-                $where['state'] = 0;
-                $url = "{$host}/api/sport/odds";
-            }
+                //按照日期获取赔率
+                // $data = SportClientService::odds([
+                //     'date' => date('Y-m-d'),
+                // ]);
 
-            $list = SportModel::where($where)->get()->toArray();
-            foreach ($list as $item) { 
-                $url .= "?data_id={$item['data_id']}";
-                $result = file_get_contents($url);
-                $result = $result ? json_decode($result, true) : [];
+
+                //普通球赛是开赛前购买,更新数据
+                $where['state'] = 0;  //比赛状态:0未开始1进行中2已完场3延期4取消
+                $list = SportModel::where($where)->where('odds',null)->limit($limit)->get()->toArray();
+                foreach($list as $item) {
+                    $data = SportClientService::odds([
+                        'fixture' => $item['data_id'],
+                    ]);
+                    $this->updateOdds($item['data_id'],$data);
+                }
             }
-           
         } catch (\Exception $e) {
             $this->error($e->getMessage());
         }
-
-        
-        
-       
         return true;
     }
 
+    public function updateOddsLive($data)
+    {
+        if(!empty($data['response'])) {
+            $data = $data['response'];
+            foreach($data as $item) {
+                $data_id = $item['fixture']['id'];
+                $long_status = $item['fixture']['status']['long']; 
+                $state = isset($this->long_status[$long_status]) ? $this->long_status[$long_status] : null;
+                $odds = $item['odds'];
+                $update_data = [
+                    'odds' => $odds,
+                ];
+                if ($state) {
+                    $update_data = [
+                        'state' => $state,
+                        'odds' => $odds,
+                    ];
+                }
+                SportModel::where('data_id',$data_id)->update($update_data);
+                echo $data_id.": 更新成功\r\n";
+            }
+        } 
+    }
+
+    public function updateOdds($data_id,$data)
+    {
+        echo $data_id;
+        if (!empty($data['response'][0]['bookmakers'][0]['bets'])) {
+            $odds = $data['response'][0]['bookmakers'][0]['bets'];
+            echo "更新成功\r\n";
+            SportModel::where('data_id',$data_id)->update(['odds' => json_encode($odds)]);
+        } else {
+            echo "更新失败\r\n";
+            file_put_contents('odds-error.log', json_encode($data)."\r\n\r\n", FILE_APPEND);
+        }
+    }
+
 }

+ 1135 - 0
app/Helpers/FootballSettlement.php

@@ -0,0 +1,1135 @@
+<?php
+use app\models\SportEvent;
+
+/***************胜相关的玩法***************** */
+/**
+ * 全场胜负(Match Winner) 玩法
+ * 主胜(Home)、平局(Draw)、客胜(Away)
+ * $amount:下注金额
+ * $params['score']:主队-客对   
+ * $detail:下注时的详情
+ */
+function MatchWinner($amount, $detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $value == 'Home') {
+        $is_win = 1;
+    } elseif ($away > $home && $value == 'Away') {
+        $is_win = 1;
+    } elseif ($home == $away && $value == 'Draw') {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Home/Away(主胜/客胜) 玩法(平局不输不赢)
+ * 主胜(Home)、平局(Draw)、客胜(Away)
+ * $amount:下注金额
+ * $params['score']:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeAwayWinner($amount, $detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $value == 'Home') {
+        $is_win = 1;
+    } elseif ($away > $home && $value == 'Away') {
+        $is_win = 1;
+    } elseif ($home == $away && $value == 'Draw') {
+        $is_win = 2;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+
+/**
+ * Second Half Winner(下半场胜负) 玩法
+ * 主胜(Home)、平局(Draw)、客胜(Away)
+ * $amount:下注金额
+ * $half_score:上半场比分
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function SecondHalfWinner($amount, $detail, $params)
+{
+    $score = getHalfScore($params['score'], $params['half_score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $value == 'Home') {
+        $is_win = 1;
+    } elseif ($away > $home && $value == 'Away') {
+        $is_win = 1;
+    } elseif ($home == $away && $value == 'Draw') {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Win to Nil - Home(主队零封获胜:主队赢,客队的进球数为 0) 玩法
+ * -yes: 主队零封获胜就中奖
+ * -no: 非主队零封获胜就中奖
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function WinToNilHomeWinner($amount, $detail, $params)
+{
+}
+
+/**
+ * First Half Winner(上半场胜负) 玩法
+ * 主胜(Home)、平局(Draw)、客胜(Away)
+ * $amount:下注金额
+ * $half_score:上半场比分
+ * $detail:下注时的详情
+ */
+function FirstHalfWinner($amount, $detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $value == 'Home') {
+        $is_win = 1;
+    } elseif ($away > $home && $value == 'Away') {
+        $is_win = 1;
+    } elseif ($home == $away && $value == 'Draw') {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+
+/**
+ * Win Both Halves(上下半场均获胜) 玩法
+ * -Home: 主队上下半场都赢就中奖
+ * -Away: 客队上下半场都赢就中奖
+ * $amount:下注金额
+ * $params['half_score']:上半场比分
+ * $params['score']:主队-客对   
+ * $detail:下注时的详情
+ */
+function WinBothHalvesWinner($amount, $detail, $params)
+{
+    //上半场得分
+    $score = getScore($params['half_score']);
+    $home_first_half = $score['home'];
+    $away_first_half = $score['away'];
+    //下半场得分
+    $score = getHalfScore($params['score'], $params['half_score']);
+    $home_second_half = $score['home'];
+    $away_second_half = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home_first_half > $away_first_half && $home_second_half > $away_second_half && $value == 'Home') {
+        $is_win = 1;  //主胜
+    } elseif ($home_first_half < $away_first_half && $home_second_half < $away_second_half && $value == 'Away') {
+        $is_win = 1;  //客胜
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Double Chance(双选胜平负) 玩法
+ * -Home or Draw:主队赢或打平就中奖
+ * -Away or Draw:客队赢或打平就中奖
+ * -Home or Away:只要分出胜负你就中奖
+ * $amount:下注金额
+ * $params['score']:主队-客对   
+ * $detail:下注时的详情
+ */
+function DoubleChance($amount, $detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home >= $away && ($value == 'Home or Draw' || $value == 'Home/Draw')) {
+        $is_win = 1;
+    } elseif ($away >= $home && ($value == 'Away or Draw' || $value == 'Away/Draw')) {
+        $is_win = 1;
+    } elseif ($home != $away && ($value == 'Home or Away' || $value == 'Home/Away')) {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Double Chance - First Half(上半场双选胜平负) 玩法
+ * -Home or Draw:主队赢或打平就中奖
+ * -Away or Draw:客队赢或打平就中奖
+ * -Home or Away:只要分出胜负你就中奖
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function DoubleChanceFirstHalf($amount, $detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home >= $away && ($value == 'Home or Draw' || $value == 'Home/Draw')) {
+        $is_win = 1;
+    } elseif ($away >= $home && ($value == 'Away or Draw' || $value == 'Away/Draw')) {
+        $is_win = 1;
+    } elseif ($home != $away && ($value == 'Home or Away' || $value == 'Home/Away')) {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+
+
+/***************进球相关的玩法***************** */
+/**
+ * Both Teams Score(双方均有进球) 玩法
+ * -Yes: 预测两支球队在比赛中都能至少攻入 1 球
+ * -No: 预测至少有一支球队进球数为 0(或者两队都没有进球)
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function BothTeamsScore($amount, $detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    return getBothTeamsScore($amount, $home, $away,$detail);
+}
+
+/**
+ * Team To Score First(首支进球球队) 玩法
+ * -Home: 预测主队打入全场第一个进球
+ * -Away: 预测客队打入全场第一个进球
+ * -Draw: 预测两队打平
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function TeamToScoreFirst($amount, $detail, $params)
+{
+    return teamToScore($amount, $detail, $params['data_id'], $params['home_team_id'], $params['guest_team_id'], 'first');
+}
+
+/**
+ * Team To Score Last(首支进球球队) 玩法
+ * -Home: 预测主队打入全场第一个进球
+ * -Away: 预测客队打入全场第一个进球
+ * -Draw: 预测两队打平
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function TeamToScoreLast($amount, $detail, $params)
+{
+    return teamToScore($amount, $detail, $params['data_id'], $params['home_team_id'], $params['guest_team_id'], 'last');
+}
+
+function teamToScore($amount, $detail, $data_id, $home_team_id, $away_team_id, $type = 'first')
+{
+    $order = $type == 'first' ? 'asc' : 'desc';
+    $team_id = SportEvent::where('data_id', $data_id)->where('type', 'Goal')->order('time_elapsed', $order)->value('team_id');
+    $value_and_odd = getValueAndOdd($detail);
+    $value = $value_and_odd['value'];
+    $odd = $value_and_odd['odd'];
+    
+    $is_win = 0;
+    if ($home_team_id == $team_id && strtolower($value) == 'home' ) {
+        $is_win = 1;
+    } elseif ($away_team_id == $team_id && strtolower($value) == 'away' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Total - Home(主队总进球数) 玩法
+ * -Over 1.5: 预测主队至少打进 2 个 或更多球
+ * -Under 1.5: 预测主队进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function TotalHome($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    return totalHomeOrAway($amount, $home,$detail);
+}
+
+/**
+ * Total - Away(客队总进球数) 玩法
+ * -Over 1.5: 预测客队至少打进 2 个 或更多球
+ * -Under 1.5: 预测客队进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function TotalAway($amount, $detail, $params)
+{
+    $score = getScore($params['score']);
+    $away = $score['away'];
+    return totalHomeOrAway($amount, $away,$detail);
+}
+
+/**
+ * Both Teams Score - First Half(上半场双方均进球) 玩法
+ * -Yes: 预测上半场结束时,两队都至少各进一球
+ * -No: 预测上半场结束时,至少有一支球队没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function BothTeamsScoreFirstHalf($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    return getBothTeamsScore($amount, $home, $away, $detail);
+}
+
+/**
+ * Both Teams To Score - Second Half(下半场双方均进球) 玩法
+ * -Yes: 预测下半场结束时,两队都至少各进一球
+ * -No: 预测下半场结束时,至少有一支球队没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function BothTeamsScoreSecondHalf($amount,$detail, $params)
+{
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $half_home = $half_score['home'];
+    $half_away = $half_score['away'];
+    return getBothTeamsScore($amount, $half_home, $half_away, $detail);
+}
+
+//双方均进球的处理方法
+function getBothTeamsScore($amount, $home, $away,$detail)
+{
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home > 0 && $away > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif (($away == 0 || $home == 0) && strtolower($value) == 'no' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Odd/Even(总进球数奇偶) 玩法
+ * -Yes: 预测上半场结束时,两队都至少各进一球
+ * -No: 预测上半场结束时,至少有一支球队没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function OddEven($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $goals = $score['home'] + $score['away'];
+    return getOddEven($amount, $goals, $detail);
+}
+
+/**
+ * Odd/Even - First Half(上半场进球奇偶) 玩法
+ * -Odd: 进球数除以 2 余 1
+ * -Even: 进球数除以 2 余 0
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function OddEvenFirstHalf($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $half_goals = $score['home'] + $score['away'];
+    return getOddEven($amount, $half_goals, $detail);
+}
+
+/**
+ * Odd/Even - Second Half(下半场进球奇偶) 玩法
+ * -Odd: 进球数除以 2 余 1
+ * -Even: 进球数除以 2 余 0
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function OddEvenSecondHalf($amount,$detail, $params)
+{
+    $score = getHalfScore($params['score'], $params['half_score']);
+    $half_goals = $score['home'] + $score['away'];
+    return getOddEven($amount, $half_goals, $detail);
+}
+
+/**
+ * Home Odd/Even(主队进球奇偶) 玩法
+ * -Odd: 进球数除以 2 余 1
+ * -Even: 进球数除以 2 余 0
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeOddEven($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    return getOddEven($amount, $home, $detail);
+}
+
+/**
+ * Away Odd/Even(客队进球奇偶) 玩法
+ * -Odd: 进球数除以 2 余 1
+ * -Even: 进球数除以 2 余 0
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayOddEven($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $away = $score['away'];
+    return getOddEven($amount, $away, $detail);
+}
+
+//进球数奇偶的处理方法
+function getOddEven($amount, $goals,$detail)
+{
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($goals % 2 == 1 && strtolower($value) == 'odd' ) {
+        $is_win = 1;
+    } elseif ($goals % 2 == 0 && strtolower($value) == 'even' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Home Team Total Goals(1st Half)(主队上半场总进球) 玩法
+ * -Over 1.5: 预测主队上半场至少打进 2 个 或更多球
+ * -Under 1.5: 预测主队上半场进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamTotalGoals($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    return totalHomeOrAway($amount, $home,$detail);
+}
+
+/**
+ * Away Team Total Goals(1st Half)(客队上半场总进球) 玩法
+ * -Over 1.5: 预测客队上半场至少打进 2 个 或更多球
+ * -Under 1.5: 预测客队上半场进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamTotalGoals($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $away = $score['away'];
+    return totalHomeOrAway($amount, $away,$detail);
+}
+
+/**
+ * Home Team Total Goals(2nd Half)(主队下半场总进球) 玩法
+ * -Over 1.5: 预测主队下半场至少打进 2 个 或更多球
+ * -Under 1.5: 预测主队下半场进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamTotalGoals2($amount,$detail, $params)
+{
+    $score = getHalfScore($params['score'], $params['half_score']);
+    $home_half = $score['home'];
+    return totalHomeOrAway($amount, $home_half,$detail);
+}
+
+/**
+ * Away Team Total Goals(2nd Half)(客队下半场总进球) 玩法
+ * -Over 1.5: 预测客队下半场至少打进 2 个 或更多球
+ * -Under 1.5: 预测客队下半场进球数为 0 个 或 1 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamTotalGoals2($amount,$detail, $params)
+{
+    $score = getHalfScore($params['score'], $params['half_score']);
+    $away_half = $score['away'];
+    return totalHomeOrAway($amount, $away_half,$detail);
+}
+
+//$score:主队/客队的进球数
+function totalHomeOrAway($amount, $score,$detail)
+{
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $value = explode(' ', $value);
+    $type = $value[0];
+    $goal = $value[1];
+    $is_win = 0;
+    if ($score > $goal && strtolower($type) == 'over' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && strtolower($type) == 'under' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Total Goals/Both Teams To Score(总进球+双方进球) 玩法
+ * -o/yes 2.5: 大于 2.5 且 双方进球
+ * -o/no 2.5: 大于 2.5 且 双方不同时进球(有一方为0)
+ * -u/yes 2.5: 小于 2.5 且 双方进球
+ * -u/no 2.5: 小于 2.5 且 双方不同时进球(且至少有一队没进球)
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function TotalGoalsBothTeamsToScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    $score = $home + $away;
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $value = explode(' ', $value);
+    $type = $value[0];
+    $goal = $value[1];
+    $is_win = 0;
+    if ($score > $goal && $home > 0 && $away > 0 && strtolower($type) == 'o/yes' ) {
+        $is_win = 1;
+    } elseif ($score > $goal && ($home == 0 || $away == 0) && strtolower($type) == 'o/no' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home > 0 && $away > 0 && strtolower($type) == 'u/yes' ) {
+        $is_win = 1;
+    }  elseif ($score < $goal && ($home == 0 || $away == 0) && strtolower($type) == 'u/no' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * RTG_H1(上半场进球数(简写)) 玩法
+ * -Draw/Over 1.5: 平局 + 大 1.5    上半场打平 且 总进球≥2
+ * -Away/Over 1.5: 客胜 + 大 1.5	上半场客队赢 且 总进球≥2
+ * -Home/Over 1.5	主胜 + 大 1.5	上半场主队赢 且 总进球≥2
+ * -Home/Under 1.5	主胜 + 小 1.5	上半场主队赢 且 总进球≤1
+ * -Draw/Under 1.5	平局 + 小 1.5	上半场打平 且 总进球≤1
+ * -Away/Under 1.5	客胜 + 小 1.5	上半场客队赢 且 总进球≤1
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function RTGH1($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    $score = $home + $away;
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $value = explode(' ', $value);
+    $type = $value[0];
+    $goal = $value[1];
+    $is_win = 0;
+    if ($score > $goal && $home == $away && strtolower($type) == 'draw/over' ) {
+        $is_win = 1;
+    } elseif ($score > $goal && $home < $away && strtolower($type) == 'away/over' ) {
+        $is_win = 1;
+    } elseif ($score > $goal && $home > $away && strtolower($type) == 'home/over' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home > $away && strtolower($type) == 'home/under' ) {  
+        $is_win = 1;
+    } elseif ($score < $goal && $home == $away && strtolower($type) == 'draw/under' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home < $away && strtolower($type) == 'away/under' ) {  
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+
+/**
+ * Home team will score in both halves(主队上下半场均进球) 玩法
+ * -yes: 主队在上半场至少进一球,且在下半场也至少进一球。
+ * -no: 主队在其中一个半场没进球,或者两个半场都没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamWillScoreInBothHalves($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $home = $score['home'];
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $home_half = $half_score['home'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home > 0 && $home_half > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif (($home == 0 || $home_half == 0) && strtolower($value) == 'no' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Away team will score in both halves(客队上下半场均进球) 玩法
+ * -yes: 客队在上半场至少进一球,且在下半场也至少进一球。
+ * -no: 客队在其中一个半场没进球,或者两个半场都没进球。
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamWillScoreInBothHalves($amount,$detail, $params)
+{
+    $score = getScore($params['half_score']);
+    $away = $score['away'];
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $away_half = $half_score['away'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($away > 0 && $away_half > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif (($away == 0 || $away_half == 0) && strtolower($value) == 'no' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * How many goals will Home Team score?(主队进球数) 玩法
+ * -No goal: 主队全场 0 进球
+ * -1: 主队恰好进 1 个球
+ * -2: 主队恰好进 2 个球
+ * -3 or more: 主队射门 3 个或更多球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HowManyGoalsWillHomeTeamScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home == 0 && strtolower($value) == 'no goal' ) {
+        $is_win = 1;
+    } elseif (is_numeric($value) && $home == $value ) { 
+        $is_win = 1;
+    } elseif (strpos($value, 'or more') !== false && $home >= intval($value)) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * How many goals will Away Team score?(客队进球数) 玩法
+ * -No goal: 客队全场 0 进球
+ * -1: 客队恰好进 1 个球
+ * -2: 客队恰好进 2 个球
+ * -3 or more: 客队打进 3 个或更多球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HowManyGoalsWillAwayTeamScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $away = $score['away'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($away == 0 && strtolower($value) == 'no goal' ) {
+        $is_win = 1;
+    } elseif (is_numeric($value) && $away == $value ) {
+        $is_win = 1;
+    } elseif (strpos($value, 'or more') !== false && $away >= intval($value)) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Match Goals(全场进球,按盘口分类) 玩法
+ * -value: over/under
+ * -handicap: 1.5 2.5 ..
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function MatchGoals($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $score = $score['home'] + $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $handicap = $value_and_odd['handicap'];
+    $is_win = 0;
+    if ($score > $handicap && strtolower($value) == 'over' ) {
+        $is_win = 1;
+    } elseif ($score < $handicap && strtolower($value) == 'under'  ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Home Team Goals(主队进球,按盘口分类) 玩法
+ * -value: over/under
+ * -handicap: 1.5 2.5 ..
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamGoals($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $handicap = $value_and_odd['handicap'];
+    $is_win = 0;
+    if ($home > $handicap && strtolower($value) == 'over' ) {
+        $is_win = 1;
+    } elseif ($home < $handicap && strtolower($value) == 'under'  ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Away Team Goals(客队进球,按盘口分类) 玩法
+ * -value: over/under
+ * -handicap: 1.5 2.5 ..
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamGoals($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $handicap = $value_and_odd['handicap'];
+    $is_win = 0;
+    if ($away > $handicap && strtolower($value) == 'over' ) {
+        $is_win = 1;
+    } elseif ($away < $handicap && strtolower($value) == 'under'  ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Home Team Score a Goal (2nd Half)(主队下半场进球) 玩法
+ * -Yes: 主队在下半场至少打进一球
+ * -No: 主队在下半场一个球都不进
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamScoreAGoal2($amount,$detail, $params)
+{
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $home_half = $half_score['home'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home_half > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif ($home_half == 0 && strtolower($value) == 'no'  ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Away Team Score a Goal (2nd Half)(客队下半场进球) 玩法
+ * -Yes: 客队在下半场至少打进一球
+ * -No: 客队在下半场一个球都不进
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamScoreAGoal2($amount,$detail, $params)
+{
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $away_half = $half_score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($away_half > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif ($away_half == 0 && strtolower($value) == 'no'  ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Both Teams to Score(双方进球) 玩法
+ * -yes: 主队有进球,且客队也有进球
+ * -no: 至少有一支球队没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function BothTeamsToScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home > 0 && $away > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif (($home == 0 || $away == 0) && strtolower($value) == 'no' ) {      
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Both Teams To Score (2nd Half)(下半场双方进球) 玩法
+ * -yes: 下半场主队有进球,且下半场客队也有进球
+ * -no: 下半场至少有一支球队没进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function BothTeamsToScore2($amount,$detail, $params)
+{
+    $half_score = getHalfScore($params['score'], $params['half_score']);
+    $home_half = $half_score['home'];
+    $away_half = $half_score['away'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if ($home_half > 0 && $away_half > 0 && strtolower($value) == 'yes' ) {
+        $is_win = 1;
+    } elseif (($home_half == 0 || $away_half == 0) && strtolower($value) == 'no' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Goals Odd/Even (进球数奇偶) 玩法
+ */
+function GoalsOddEven($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $goals = $score['home'] + $score['away'];
+    return getOddEven($amount, $goals, $detail);
+}
+
+/**
+ * Home Team Exact Goals Number(主队精确进球数) 玩法
+ * -0: 预测主队全场比赛一个球都进不了
+ * -1: 预测主队刚好只进 1 个球。
+ * -more 2: 预测主队进球数达到或超过 2 个
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function HomeTeamExactGoalsNumber($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if (is_numeric($value) && $home == $value ) {
+        $is_win = 1;
+    } elseif (strpos($value, 'more') !== false && $home >= intval($value)) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Away Team Exact Goals Number(客队精确进球数) 玩法
+ * -0: 预测客队全场比赛一个球都进不了
+ * -1: 预测客队刚好只进 1 个球。
+ * -more 2: 预测客队进球数达到或超过 2 个。
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function AwayTeamExactGoalsNumber($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $away = $score['away'];
+
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $is_win = 0;
+    if (is_numeric($value) && $away == $value ) {
+        $is_win = 1;
+    } elseif (strpos($value, 'more') !== false && $away >= intval($value)) {    
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Results/Both Teams Score(赛果+双方进球) 玩法
+ * -Home/Yes: 主队赢球,且客队也进了球
+ * -Away/Yes: 客队赢球,且主队也进了球
+ * -Draw/Yes: 双方打平,且都有进球
+ * -Home/No: 主队赢球,且零封了客队
+ * -Away/No: 客队赢球,且零封了主队
+ * -Draw/No: 双方打平,且都没有进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function ResultsBothTeamsScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = strtolower($value_and_odd['value']);
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $away > 0 && ($value == 'home or yes' || $value == 'home/yes')) {
+        $is_win = 1;
+    } elseif ($away > $home && $home > 0 && ($value == 'away or yes' || $value == 'away/yes')) {
+        $is_win = 1;
+    } elseif ($home == $away && $home > 0 && $away >0 && ($value == 'draw or yes' || $value == 'draw/yes')) {
+        $is_win = 1;
+    } elseif ($home > $away && $away == 0 && ($value == 'home or no' || $value == 'home/no')) {
+        $is_win = 1;
+    } elseif ($away > $home && $home == 0 && ($value == 'away or no' || $value == 'away/no')) {
+        $is_win = 1;
+    } elseif ($home == $away && $home == 0 && $away == 0 && ($value == 'draw or no' || $value == 'draw/no')) {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Result/Total Goals(赛果+总进球数) 玩法
+ * -Draw/Over 1.5: 平局 + 大 1.5    总进球数打平 且 总进球≥2
+ * -Away/Over 1.5: 客胜 + 大 1.5	总进球数赢 且 总进球≥2
+ * -Home/Over 1.5	主胜 + 大 1.5	总进球数赢 且 总进球≥2
+ * -Home/Under 1.5	主胜 + 小 1.5	总进球数赢 且 总进球≤1
+ * -Draw/Under 1.5	平局 + 小 1.5	总进球数打平 且 总进球≤1
+ * -Away/Under 1.5	客胜 + 小 1.5	总进球数赢 且 总进球≤1
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function ResultTotalGoals($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    $score = $home + $away;
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $odd = $value_and_odd['odd'];
+    $value = $value_and_odd['value'];
+    $value = explode(' ', $value);
+    $type = $value[0];
+    $goal = $value[1];
+    $is_win = 0;
+    if ($score > $goal && $home == $away && strtolower($type) == 'draw/over' ) {
+        $is_win = 1;
+    } elseif ($score > $goal && $home < $away && strtolower($type) == 'away/over' ) {
+        $is_win = 1;
+    } elseif ($score > $goal && $home > $away && strtolower($type) == 'home/over' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home > $away && strtolower($type) == 'home/under' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home == $away && strtolower($type) == 'draw/under' ) {
+        $is_win = 1;
+    } elseif ($score < $goal && $home < $away && strtolower($type) == 'away/under' ) {
+        $is_win = 1;
+    } 
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * Result / Both Teams To Score(赛果+双方进球) 玩法
+ * -Home/Yes: 主队赢球,且客队也进了球
+ * -Away/Yes: 客队赢球,且主队也进了球
+ * -Draw/Yes: 双方打平,且都有进球
+ * -Home/No: 主队赢球,且零封了客队
+ * -Away/No: 客队赢球,且零封了主队
+ * -Draw/No: 双方打平,且都没有进球
+ * $amount:下注金额
+ * $score:主队-客对   
+ * $detail:下注时的详情
+ */
+function ResultBothTeamsToScore($amount,$detail, $params)
+{
+    $score = getScore($params['score']);
+    $home = $score['home'];
+    $away = $score['away'];
+    
+    $value_and_odd = getValueAndOdd($detail);
+    $value = strtolower($value_and_odd['value']);
+    $odd = $value_and_odd['odd'];
+    $is_win = 0;
+    if ($home > $away && $away > 0 && ($value == 'home or yes' || $value == 'home/yes')) {
+        $is_win = 1;
+    } elseif ($away > $home && $home > 0 && ($value == 'away or yes' || $value == 'away/yes')) {
+        $is_win = 1;
+    } elseif ($home == $away && $home > 0 && $away >0 && ($value == 'draw or yes' || $value == 'draw/yes')) {
+        $is_win = 1;
+    } elseif ($home > $away && $away == 0 && ($value == 'home or no' || $value == 'home/no')) {
+        $is_win = 1;
+    } elseif ($away > $home && $home == 0 && ($value == 'away or no' || $value == 'away/no')) {
+        $is_win = 1;
+    } elseif ($home == $away && $home == 0 && $away == 0 && ($value == 'draw or no' || $value == 'draw/no')) {
+        $is_win = 1;
+    }
+    return getResult($is_win, $amount, $odd);
+}
+
+/**
+ * 获取主客队得分
+ */
+function getScore($score) { 
+    $score = explode('-', $score);
+    return [
+        'home' => (int)$score[0],
+        'away' => (int)$score[1],
+    ];
+}
+
+/**
+ * 获取下半场主客队得分
+ */
+function getHalfScore($score, $half_score) { 
+    $score = explode('-', $score);
+    $half_score = explode('-', $half_score);
+    return [
+        'home' => (int)$score[0] - (int)$half_score[0],
+        'away' => (int)$score[1] - (int)$half_score[1],
+    ];
+}
+
+/**
+ * 获取比分
+ * $type : 1 主队总进球数,2 客队总进球数, 3
+ */
+function getValueAndOdd($detail) {
+    $odds = $detail['odds'][0];
+    $values = $odds['values'][0];
+    return [
+        'value' => $values['value'],
+        'odd' => $values['odd'],
+        'handicap' => isset($values['handicap']) ? $values['handicap'] : 0,
+    ];
+}
+
+function getResult($is_win, $amount, $odds) {
+    //is_win:是否中奖:0没中奖1中奖2和局3平手半
+    $result = [
+        'is_win' => 0, //是否中奖:0没中奖1中奖2和局3平手半
+        'win_amount' => 0, //中奖金额
+        'profit_and_loss' => -$amount, //盈亏金额
+        'settlement_status' => 1, //结算状态:1未结算2已结算3已取消
+    ];
+    if ($is_win == 1) {
+        $result['is_win'] = 1;
+        $result['win_amount'] = bcmul($amount, $odds, 2);
+        $result['profit_and_loss'] = $result['win_amount'] - $amount;
+    }
+    if ($is_win == 2) {
+        $result['is_win'] = 2;
+        $result['win_amount'] = 0;
+        $result['profit_and_loss'] = 0;
+    }
+    $result['settlement_status'] = 2;
+    return $result;
+}

+ 9 - 0
app/Models/SportEvent.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace App\Models;
+
+class SportEvent extends BaseModel
+{
+    protected $table = 'sport_event';
+    protected $fillable = ['data_id', 'type', 'time_elapsed', 'team_id', 'time', 'player', 'detail', 'comments', 'assist'];
+}

+ 2 - 1
composer.json

@@ -48,7 +48,8 @@
       "TronTool\\": "tron.php/src/"
     },
     "files": [
-      "app/Helpers/helpers.php"
+      "app/Helpers/helpers.php",
+      "app/Helpers/FootballSettlement.php"
     ]
   },
   "autoload-dev": {

+ 36 - 0
docker-compose.yml

@@ -0,0 +1,36 @@
+services:
+  app:
+    build: .
+    container_name: bot-28-app
+    volumes:
+      - .:/var/www/html
+      - /path/to/wkhtmltoimage:/usr/bin/wkhtmltoimage
+    networks:
+      - bot-28-network
+
+  web:
+    image: nginx:alpine
+    container_name: bot-28-web
+    volumes:
+      - .:/var/www/html
+      - ./nginx.conf:/etc/nginx/conf.d/default.conf
+    depends_on:
+      - app
+    networks:
+      - bot-28-network
+
+  queue:
+    build: .
+    container_name: bot-28-queue
+    command: php artisan queue:work --queue
+    volumes:
+      - .:/var/www/html
+      - /path/to/wkhtmltoimage:/usr/bin/wkhtmltoimage
+    depends_on:
+      - app
+    networks:
+      - bot-28-network
+
+networks:
+  bot-28-network:
+    driver: bridge

+ 3 - 0
example.env

@@ -5,6 +5,9 @@ APP_NAME=Bot
 APP_DEBUG=true
 APP_URL=
 
+#足球app接口域名
+FOOTBALL_APP_URL=
+
 # 短信宝
 SMS_USERNAME=
 SMS_PASSWORD=

+ 56 - 0
nginx.conf

@@ -0,0 +1,56 @@
+server {
+    listen 80;
+    server_name bot28api.sp2509.cc;
+    root /var/www/html/public; # 必须指向 public 目录
+    index index.php index.html;
+
+
+
+    location / {
+        add_header 'Access-Control-Allow-Origin' '*';
+        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
+        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
+        add_header 'Access-Control-Allow-Credentials' 'true';
+        add_header 'Access-Control-Max-Age' 3600;
+
+        if ($request_method = 'OPTIONS') {
+            # OPTIONS 请求直接返回 200
+            return 204;
+        }
+
+        #try_files $uri $uri/ /index.php?$query_string;        
+        if (!-e $request_filename) {
+            rewrite ^/index.php(.*)$ /index.php?s=$1 last;
+            rewrite ^(.*)$ /index.php?s=$1 last;
+            break;
+        }
+}
+
+    # ===== PHP 解析配置(强制指向 8.4,避免版本问题)=====
+    location ~ \.php$ {
+        fastcgi_pass app:9000; # 确认是 8.4 的 sock 文件
+        fastcgi_index index.php;
+        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
+        fastcgi_param DOCUMENT_ROOT $realpath_root;
+        include fastcgi_params;
+    }
+
+    # ===== 禁止访问敏感文件/目录(保留)=====
+    location ~ /\.(?!well-known).* {
+        deny all;
+    }
+    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env) {
+        return 404;
+    }
+
+    # ===== 静态文件缓存(保留,不影响接口)=====
+    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
+        expires 30d;
+        add_header Cache-Control "public, max-age=2592000";
+        access_log off;
+    }
+
+    # ===== 日志配置(保留)=====
+    access_log /var/log/nginx/bot28api.sp2509.cc.log;
+    error_log /var/log/nginx/bot28api.sp2509.cc.error.log;
+}