Sfoglia il codice sorgente

update:游戏记录列表

aiden 3 mesi fa
parent
commit
ed9db24acd

+ 2 - 0
app/common.php

@@ -1,5 +1,7 @@
 <?php
 
+require_once "common/GameGameConfig.php";
+
 use Firebase\JWT\JWT;
 use Firebase\JWT\Key;
 

+ 216 - 0
app/common/CommonUtils.php

@@ -0,0 +1,216 @@
+<?php
+
+namespace app\common;
+
+use Ramsey\Uuid\Uuid;
+use think\facade\Cache;
+use think\helper\Str;
+
+class CommonUtils
+{
+
+
+    /// 读取游戏类型
+    public static function getGameTypeConfig($type = '2') {
+        return $GLOBALS['gameGameTypeConfig'][$type];
+    }
+
+    /// 默认游戏图标
+    public static function getGameDefaultImage($item = []) {
+        $staticDomain = $GLOBALS['gameGameStaticDomain'];
+        // 中文图标
+        if(empty($item['image'])) {
+            $item['image_url'] = "//{$staticDomain}/{$item['game_id']}/zh.png";
+        }else {
+            $item['image_url'] = $item['image'];
+        }
+        // 英文图标
+        if(empty($item['image_en'])) {
+            $item['image_en_url'] = "//{$staticDomain}/{$item['game_id']}/en.png";
+        }else {
+            $item['image_en_url'] = $item['image_en'];
+        }
+        return $item;
+    }
+
+    // 转换 分数 * 10000 or / 10000
+    public static function convertBalance($balance = 0, $isTenThousandfold = true) {
+        $balance = (float)$balance;
+        // 分数小数点 * 10000;
+        // $GLOBALS['balanceTenThousandfold'] = 10000;
+        $balanceTenThousandfold = 10000;
+        if ($isTenThousandfold) {
+            $balance = bcmul($balance, $balanceTenThousandfold);
+        } else {
+            $balance = bcdiv($balance, $balanceTenThousandfold, 4);
+        }
+        return (float)$balance;
+    }
+
+    // 生成转账流水ID
+    public static function generateUuidSn($key = 'OD')
+    {
+        $uuid = Uuid::uuid4()->toString(); // 生成 UUID v4
+        $uuid = str_replace('-', '', $uuid); // 移除连字符
+        return 'OD' . $uuid; // 示例:OD550e8400e29b41d4a71644665544000
+    }
+    // 生成订单 单号
+    public static function generateThirdOrderId($key = 'ega'): string
+    {
+        // 时间戳
+        $timestamp = date('YmdHis'); // e.g., "20250319073600"
+        // 前缀:ega + 第4位基于时间递增
+        $currentTime = time();
+        $startTime = strtotime(date('Y-m-d 00:00:00', $currentTime)); // 假设起始时间
+        // 计算 15 分钟间隔
+        $fifteenMinuteIntervals = floor(($currentTime - $startTime) / (15 * 60)); // 82
+        // 限制在 'e' 到 'z' (101 到 122),共 22 个字符
+        $increment = $fifteenMinuteIntervals % 22; // 82 % 22 = 16
+        $fourthChar = chr(101 + $increment); // 101 + 16 = 117,'u'
+        $prefix = $key . $fourthChar; // e.g., "egae", "egaf"
+        // 8位随机字符串
+        $random = Str::random(8,3,'0123456789'); // 生成 8 位小写字母和数字混合的随机字符串        // 组合
+        return $timestamp . $prefix . $random;
+    }
+    // 生成局ID $prefix = '19'; // 服务器标识 $ext // 备用
+    public static function generateFlowId($prefix = '19', $ext = '000'): string
+    {
+        $prefix = $prefix ?? '19';
+
+        // 获取微秒级时间戳
+        $microtime = microtime(true); // e.g., 1743088050.123456
+        $timestamp = date('YmdHis', (int)$microtime) . sprintf('%06d', floor(($microtime - floor($microtime)) * 1000000));
+        $time_part = substr($timestamp, 2, 14); // 14 位时间,例如 "25032516073012"
+
+        // Redis 键名:基于毫秒时间戳(精确到毫秒)
+        $redisKey = 'order:counter:' . substr($timestamp, 0, 14); // e.g., "order:counter:20250325160730"
+        // 使用 Redis INCR 获取计数器值,并在首次设置时设置过期时间
+        $redis = Cache::store('redis')->handler(); // 获取 Redis 实例
+        $counter = $redis->incr($redisKey); // 计数器从 1 开始递增
+
+        // 如果是第一次递增,设置过期时间(1 秒)
+        if ($counter == 1) {
+            $redis->expire($redisKey, 1); // 1 秒后过期
+        }
+
+        // 转换为 3 位字符串,减 1 使其从 000 开始
+        $suffix = sprintf('%03d', $counter - 1); // e.g., "000", "001", "002"
+
+        // 拼接 19 位流水 ID
+        $flow_id =  $time_part . $prefix . $suffix . $ext;
+
+        return $flow_id;
+    }
+
+    /**
+     * 获取游戏玩法名称
+     * @param $type
+     * @return string
+     */
+    public static function getGamePlayType($type = 0) {
+        $config = [
+            '1' => '连消',
+            '2' => '免费旋转',
+            '3' => '重转',
+            '4' => '高倍',
+        ];
+        return $config[$type] ?? "";
+    }
+
+    /**
+     * 统一游戏成功返回字段
+     * @param $data
+     * @return \think\response\Json
+     */
+    public static function gameJsonSuccess($data = []) {
+        return json([
+            'dt' => $data,
+            'err' => null,
+        ]);
+    }
+
+    /**
+     * 统一游戏失败字段
+     * @param $code
+     * @param $msg
+     * @param $data
+     */
+    public static function gameJsonError($code = "1004", $msg = "", $data =[], $is_json = true) {
+        /**
+         * cd: '1201',
+         * msg: 'GameStateNotFoundException',
+         * tid: 'HQIIMN11',
+         *
+         * { cd: '1200', msg: 'Internal server error.', tid: 'LAAUWY01', at: 1 }
+         * * * cd: '1403',
+         * * msg: 'We are undergoing maintenance, please try again later.',
+         * * tid: 'SH8Q14K6'
+        * }
+         * cd: '50038',
+         * msg: '游戏不存在:%!d(string=cocktail-nite)',
+         * tid: 'S2VAFQQ9'
+         * { cd: '500', msg: 'protobuf data too short', tid: '4UOFS6OA' }
+         * err: { cd: '2', msg: 'is small game ont fb', tid: 'AFJGTF6B' }
+         *
+         * {cd: "1302", msg: "Invalid player session", tid: "PGTVSW16", at: null}
+         *
+         * {"cd":"1308","msg":"Player session is expired","tid":"PBSMUF18","at":null}
+         * Access denied.
+         * err: {
+         * cd: '3202',
+         * msg: 'OERR:Not enough cash.',
+         * tid: 'JSXSWO82',
+         * at: null
+         * }
+         */
+
+        $temp = [
+            'dt' => null,
+            'err' => array_merge([
+                "cd" => $code,
+                "msg" => $msg
+            ]),
+            'td' => time(),
+        ];
+        if(!empty($data)) {
+            $temp = array_merge($temp, $data);
+        }
+        if(!$is_json) {
+            return $temp;
+        }
+        return json($temp);
+    }
+
+    /**
+     * 格式化数据
+     * @param $item
+     * @param $change
+     * @return mixed
+     */
+    public static function formatResultData($item, $change) {
+        // $item['tb'] = CommonUtils::convertBalance($item['tb'], $change);
+        // $item['tbb'] = CommonUtils::convertBalance($item['tbb'],$change);
+        // $item['np'] = CommonUtils::convertBalance($item['np'],$change);
+        // $item['ctw'] = CommonUtils::convertBalance($item['ctw'],$change);
+        $keysList = ['cptw','atw', 'tb', 'tbb','np', 'ctw'];
+        foreach ($keysList as $key) {
+            if(isset($item[$key])) {
+                $item[$key] = CommonUtils::convertBalance($item[$key],$change);
+            }
+        }
+        $item['aw'] = CommonUtils::convertBalance($item['aw'],$change);
+        if(!empty($item['lw'])) {
+            foreach ($item['lw'] as $key => $lw) {
+                if(is_array($lw)) {
+                    foreach ($lw as $k => $templw) {
+                        $lw[$k] = CommonUtils::convertBalance($templw,$change);
+                    }
+                    $item['lw'][$key] = $lw;
+                }else {
+                    $item['lw'][$key] = CommonUtils::convertBalance($lw,$change);
+                }
+            }
+        }
+        return $item;
+    }
+}

+ 29 - 0
app/common/GameGameConfig.php

@@ -0,0 +1,29 @@
+<?php
+// 游戏配置
+use think\facade\Env;
+
+$GLOBALS['gamePgGameConfig'] = [
+    //RTP档位
+    'rtp_config' => [70,75,80,85,90,93,95,97,99,102],
+    // 押注等级
+    'deposit_level' => [1,2,3,4,5,6,7,8,9,10],
+    // 默认押注等级
+    'default_deposit_level' => 10,
+    // 线数
+    'line_numbers' => 30,
+    // 返还类型
+    'rtp_type_config' => [
+        '1' => ['name' => '心跳型', 'desc' => '玩家中奖倍数大,中奖率相对较低,短时间赢取大奖的几率较高,在玩家戏局数不是非常少时,游戏总体RTP和玩家个人RTP均较稳定'],
+        '2' => ['name' => '平缓型', 'desc' => '玩家中奖倍数较小,中奖半相对较高,短时间赢取大奖的几率较低,在玩家游戏局数不是非常少时,游戏总体RTP和玩家个人RTP均较稳逆'],
+        '3' => ['name' => '混合型', 'desc' => '中奖倍致,中奖率,短时间赢取大奖的几率介于心跳型和平缓型之间,在玩家游戏局数不是非常少时,游戏总体RTP和玩家个人RTP均较稳定'],
+        '4' => ['name' => '仿正版', 'desc' => '短时间内游戏RTP波动较大,长期来看游戏RTP超于稳定,玩家个人RTP可能会出现爆输爆赢的情况,能出非常大的倍数,平台玩家不多时请谨慎使用'],
+    ]
+];
+// 游戏大类
+$GLOBALS['gameGameTypeConfig'] = [
+    "1" => 'Spribe',
+    '2' => 'PG'
+];
+// 静态DOMAIN
+// $GLOBALS['gameGameStaticDomain'] = "game.w115.net";
+$GLOBALS['gameGameStaticDomain'] = Env::get('GAME_STATIC_DOMAIN', 'game.w115.net');

+ 89 - 5
app/controller/GameOrder.php

@@ -6,6 +6,10 @@ namespace app\controller;
 use app\BaseController;
 use think\facade\Request;
 use app\model\GameOrderModel;
+use app\model\GameModel;
+use app\model\GameCheckBetOrder;
+use app\model\GameResultBetOrder;
+use app\common\CommonUtils;
 
 /**
  * 游戏订单控制器
@@ -33,21 +37,89 @@ class GameOrder extends BaseController
             // 订单原因筛选
             'order_reason' => Request::get('order_reason', '', 'trim'),
             // 平台ID筛选
-            'platform_id' => Request::get('platform_id', '', 'trim'),
+            'uname' => Request::get('uname', '', 'trim'),
+            // 玩家ID筛选
+            'player_id' => Request::get('user_id', '', 'trim'), 
+            // 平台昵称
+            'nickname' => Request::get('nickname', '', 'trim'),
             // 订单状态筛选
             'order_status' => Request::get('order_status', ''),
             // 订单编号筛选
-            'order_number' => Request::get('order_number', '', 'trim'),
+            'third_order_id' => Request::get('third_order_id', '', 'trim'),
             // 母单号筛选
-            'parent_order' => Request::get('parent_order', '', 'trim'),
+            'third_gid' => Request::get('third_gid', '', 'trim'),
             // 牌局编号筛选
-            'round_number' => Request::get('round_number', '', 'trim'),
+            'third_round_id' => Request::get('third_round_id', '', 'trim'),
         ];
         
         try {
-            $result = GameOrderModel::getOrderRecords($userInfo['merchant_id'], $page, $limit, $filters);
+            // 获取主订单列表
+            $result = GameOrderModel::getBetOrderList($userInfo['merchant_id'], $page, $limit, $filters);
+            
+            if (empty($result['list'])) {
+                return json_success($result, '获取成功');
+            }
+
+            // 获取游戏信息信息
+            $game_ids = array_unique(array_column($result['list'], 'game_id'));
+            $tempGameList = GameModel::where([['merchant_id', '=', $userInfo['merchant_id']], ['game_id', 'in', $game_ids]])->field(['game_id','title','image'])->select()->toArray();
+            $gameList = [];
+            foreach ($tempGameList as $item) {
+                $game_id = $item['game_id'];
+                $gameList[$game_id] = $item;
+            }
+            
+            // 获取母单号列表
+            $thirdGids = array_unique(array_column($result['list'], 'third_gid'));
+            
+            // 获取子订单列表
+            $childOrderList = [];
+            if (count($thirdGids) > 0) {
+                $tempCheckList = GameCheckBetOrder::where([ ['third_gid', 'in', $thirdGids] ])->select()->toArray();
+                $tempResultList = GameResultBetOrder::where([['third_gid', 'in', $thirdGids] ])->select()->toArray();
+                $tempList = array_merge($tempCheckList, $tempResultList);
+                foreach ($tempList as $item) {
+                    if(!isset($childOrderList[$item['third_gid']])) {
+                        $childOrderList[$item['third_gid']] = [];
+                    }
+                    $item = $this->formatItemDataText($item);
+                    $item['id'] = 'm_' . $item['id'];
+                    $childOrderList[$item['third_gid']][] = $item;
+                }
+            }
+
+            // 格式化数据并添加子订单
+            $newDataList = [];
+            foreach ($result['list'] as $item) {
+                $item = $this->formatItemDataText($item);
+                $thirdGid = $item['third_gid'];
+                $game_id = $item['game_id'];
+                $gameInfo = $gameList[$game_id] ?? [];
+                if (!empty($gameInfo))
+                {
+                    $gameImages = CommonUtils::getGameDefaultImage($gameInfo);
+                }
+                $item['game_image_url'] = $gameImages['image_url'] ?? '';
+                $item['game_title'] = $gameInfo['title'] ?? '';
+                $item['game_type_text'] = CommonUtils::getGameTypeConfig($item['game_type']);
+
+                if(isset($childOrderList[$thirdGid])) {
+                    $item['children'] = [];
+                    $childList = $childOrderList[$thirdGid];
+                    foreach ($childList as $citem) {
+                        $citem['game_type_text'] = $item['game_type_text'];
+                        $citem['game_image_url'] = $item['game_image_url'];
+                        $citem['game_title'] = $item['game_title'];
+                        $item['children'][] = $citem;
+                    }
+                }
+                $newDataList[] = $item;
+            }
+            
+            $result['list'] = $newDataList;
             return json_success($result, '获取成功');
         } catch (\Exception $e) {
+            print_r($e->getTraceAsString());
             return json_error([], '获取订单记录失败:' . $e->getMessage());
         }
     }
@@ -235,4 +307,16 @@ class GameOrder extends BaseController
         
         return $gameNames[$gameId] ?? $gameId;
     }
+
+   // 格式化信息
+    private function formatItemDataText($item = [])
+    {
+        $item['amount'] = CommonUtils::convertBalance($item['amount'], false);
+        $item['bet'] = CommonUtils::convertBalance($item['bet'], false);
+        $item['prev_amount'] = CommonUtils::convertBalance($item['prev_amount'], false);
+        $item['next_amount'] = CommonUtils::convertBalance($item['next_amount'], false);
+        $item['total_win_amount'] = CommonUtils::convertBalance($item['total_win_amount'], false);
+        $item['total_amount'] = CommonUtils::convertBalance($item['total_amount'], false);
+        return $item;
+    }    
 }

+ 84 - 20
app/controller/GameRecord.php

@@ -7,6 +7,7 @@ use app\BaseController;
 use think\facade\Request;
 use app\model\GameRecordModel;
 use app\model\GameModel;
+use app\common\CommonUtils;
 
 /**
  * 游戏记录控制器
@@ -29,38 +30,87 @@ class GameRecord extends BaseController
             // 时间筛选
             'start_time' => Request::get('start_time', '', 'trim'),
             'end_time' => Request::get('end_time', '', 'trim'),
-            // 游戏品牌筛选(这里使用user_id作为平台ID)
-            'platform_id' => Request::get('platform_id', '', 'trim'),
             // 游戏筛选
             'game_id' => Request::get('game_id', '', 'trim'),
-            // 玩家状态筛选
-            'play_status' => Request::get('play_status', ''),
-            // 玩法筛选
-            'play_method' => Request::get('play_method', '', 'trim'),
-            // 触发方式筛选
-            'trigger_method' => Request::get('trigger_method', '', 'trim'),
             // 牌局编号筛选
-            'round_number' => Request::get('round_number', '', 'trim'),
+            'third_round_id' => Request::get('third_round_id', '', 'trim'),
+            // 平台ID筛选
+            'uname' => Request::get('uname', '', 'trim'),
+            // 玩家ID筛选
+            'player_id' => Request::get('user_id', '', 'trim'), 
+            // 平台昵称
+            'nickname' => Request::get('nickname', '', 'trim'),
+            // 游戏玩法类型筛选
+            'bet_game_play_type' => Request::get('bet_game_play_type', '', 'trim'),
         ];
         
         try {
-            $result = GameRecordModel::getGameRecords($userInfo['merchant_id'], $page, $limit, $filters);
+            // 获取游戏记录列表
+            $result = GameRecordModel::getBetGameList($userInfo['merchant_id'], $page, $limit, $filters);
             
-            // 获取游戏信息映射
-            $gameIds = array_unique(array_column($result['list'], 'game_id'));
-            $gameInfoMap = $this->getGameInfoMap($gameIds, $userInfo['merchant_id']);
+            if (empty($result['list'])) {
+                return json_success($result, '获取成功');
+            }
             
-            // 添加游戏名称和图标到结果中
-            foreach ($result['list'] as &$item) {
-                $gameInfo = $gameInfoMap[$item['game_id']] ?? null;
-                $item['game_name'] = $gameInfo ? $gameInfo['title'] : $item['game_id'];
-                $item['game_name_en'] = $gameInfo ? $gameInfo['title_en'] : '';
-                $item['game_icon'] = $gameInfo ? $gameInfo['image'] : '';
-                $item['game_icon_en'] = $gameInfo ? $gameInfo['image_en'] : '';
+            
+            // 获取游戏信息信息
+            $game_ids = array_unique(array_column($result['list'], 'game_id'));
+            $tempGameList = GameModel::where([['merchant_id', '=', $userInfo['merchant_id']], ['game_id', 'in', $game_ids]])->field(['game_id','title','image'])->select()->toArray();
+            $gameList = [];
+            foreach ($tempGameList as $item) {
+                $game_id = $item['game_id'];
+                $gameList[$game_id] = $item;
             }
             
+            // 获取母单号列表
+            $thirdGids = array_unique(array_column($result['list'], 'third_gid'));
+
+            $childOrderList = [];
+            if(count($thirdGids) > 0) {
+                $tempCheckList = GameRecordModel::where([ ['third_gid', 'in', $thirdGids], ['action_type','=',2] ])->withoutField('result')->select()->toArray();
+                foreach ($tempCheckList as $item) {
+                    if(!isset($childOrderList[$item['third_gid']])) {
+                        $childOrderList[$item['third_gid']] = [];
+                    }
+                    $item = $this->formatItemDataText($item);
+                    $item['id'] = 'm_' . $item['id'];
+                    $childOrderList[$item['third_gid']][] = $item;
+                }
+            }
+            
+            // 格式化数据并添加子订单
+            $newDataList = [];
+            foreach ($result['list'] as $item) {
+                $thirdGid = $item['third_gid'];
+                $game_id = $item['game_id'];
+                $gameInfo = $gameInfoMap[$item['game_id']] ?? [];
+                if (!empty($gameInfo))
+                {
+                    $gameImages = CommonUtils::getGameDefaultImage($gameInfo);
+                }
+                $item['game_image_url'] = $gameImages['image_url'] ?? '';
+                $item['game_title'] = $gameInfo['title'] ?? '';
+                $item['game_type_text'] = CommonUtils::getGameTypeConfig($item['game_type']);
+                
+                if(isset($childOrderList[$thirdGid])) {
+                    $item['children'] = [];
+                    $childList = $childOrderList[$thirdGid];
+                    foreach ($childList as $citem) {
+                        $citem['game_type_text'] = $item['game_type_text'];
+                        $citem['game_image_url'] = $item['game_image_url'];
+                        $citem['game_title'] = $item['game_title'];
+                        $item['children'][] = $citem;
+                    }
+                }
+                $item['c_count'] = count($childOrderList[$thirdGid] ?? []);
+                $item['view_layout_url'] = "/history/{$game_id}.html?sid={$thirdGid}&pf=1&lang=zh&api=".Request::host()."%2Fweb-api%2Fgame-proxy%2Fv2%2FBetDetails%2FGet";
+                $newDataList[] = $item;
+            }
+            
+            $result['list'] = $newDataList;
             return json_success($result, '获取成功');
         } catch (\Exception $e) {
+            echo $e->getTraceAsString();
             return json_error([], '获取游戏记录失败:' . $e->getMessage());
         }
     }
@@ -346,4 +396,18 @@ class GameRecord extends BaseController
         
         return $map;
     }
+
+   // 格式化信息
+    private function formatItemDataText($item = [])
+    {
+        $item['bet'] = CommonUtils::convertBalance($item['bet'], false);
+        $item['prev_amount'] = CommonUtils::convertBalance($item['prev_amount'], false);
+        $item['next_amount'] = CommonUtils::convertBalance($item['next_amount'], false);
+        $item['total_amount']  = COmmonUtils::convertBalance($item['total_amount'], false);
+        $item['win_amount']  = COmmonUtils::convertBalance($item['win_amount'], false);
+        $item['total_win_amount']  = COmmonUtils::convertBalance($item['total_win_amount'], false);
+        $item['res_multiple'] = $item['res_multiple'] / 100;
+        $item['bet_game_play_type'] = CommonUtils::getGamePlayType($item['bet_game_play_type']);
+        return $item;
+    }    
 }

+ 16 - 0
app/model/GameCheckBetOrder.php

@@ -0,0 +1,16 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+
+/**
+ * 商户游戏模型
+ */
+class GameCheckBetOrder extends Model
+{
+    protected $name = 'game_check_bet_order';
+    protected $connection = 'fortue_tiger';
+
+}

+ 64 - 71
app/model/GameOrderModel.php

@@ -7,7 +7,7 @@ use think\Model;
 use think\facade\Db;
 
 /**
- * 游戏订单模型
+ * 游戏订单模型 - 基于tp_game_bet_order表
  */
 class GameOrderModel extends Model
 {
@@ -25,11 +25,18 @@ class GameOrderModel extends Model
     const ACTION_TYPE_BET = 1;      // 下注
     const ACTION_TYPE_SETTLE = 2;   // 结算
     const ACTION_TYPE_CANCEL = 3;   // 取消
+    const ACTION_TYPE_CHECK = 4;    // 检查
+    const ACTION_TYPE_RESULT = 5;   // 结果
+    
+    // 游戏类型常量
+    const GAME_TYPE_SLOT = 1;       // 老虎机
+    const GAME_TYPE_TABLE = 2;      // 桌面游戏
+    const GAME_TYPE_LIVE = 3;       // 真人游戏
     
     /**
-     * 获取订单记录列表
+     * 获取下注订单列表(参考apiAdminBetOrderList方法)
      */
-    public static function getOrderRecords($appId, $page = 1, $limit = 20, $filters = [])
+    public static function getBetOrderList($appId, $page = 1, $limit = 20, $filters = [])
     {
         $where = [
             ['app_id', '=', $appId]
@@ -51,34 +58,44 @@ class GameOrderModel extends Model
             $where[] = ['game_id', '=', $filters['game_id']];
         }
         
-        // 订单原因筛选
+        // 订单原因筛选(动作类型)
         if (!empty($filters['order_reason'])) {
             $where[] = ['action_type', '=', $filters['order_reason']];
         }
         
         // 平台ID筛选
-        if (!empty($filters['platform_id'])) {
-            $where[] = ['uname', '=', $filters['platform_id']];
+        if (!empty($filters['uname'])) {
+            $where[] = ['uname', '=', $filters['uname']];
+        }
+
+        // 平台昵称筛选
+        if (!empty($filters['nickname'])) {
+            $where[] = ['nickname', 'like', '%' . $filters['nickname'] . '%'];
+        }        
+        
+        // 玩家id筛选
+        if (!empty($filters['player_id'])) {
+            $where[] = ['user_id', 'like', '%' . $filters['player_id'] . '%'];
         }
         
         // 订单状态筛选
         if ($filters['order_status'] !== '') {
             $where[] = ['status', '=', $filters['order_status']];
         }
-        
-        // 订单编号筛选(支持母单号、子单号、牌局编号)
-        if (!empty($filters['order_number'])) {
-            $where[] = ['third_order_id', 'like', '%' . $filters['order_number'] . '%'];
+                
+        // 订单编号筛选
+        if (!empty($filters['third_order_id'])) {
+            $where[] = ['third_order_id', 'like', '%' . $filters['third_order_id'] . '%'];
         }
         
         // 母单号筛选
-        if (!empty($filters['parent_order'])) {
-            $where[] = ['third_gid', 'like', '%' . $filters['parent_order'] . '%'];
+        if (!empty($filters['third_gid'])) {
+            $where[] = ['third_gid', 'like', '%' . $filters['third_gid'] . '%'];
         }
         
         // 牌局编号筛选
-        if (!empty($filters['round_number'])) {
-            $where[] = ['third_round_id', 'like', '%' . $filters['round_number'] . '%'];
+        if (!empty($filters['third_round_id'])) {
+            $where[] = ['third_round_id', 'like', '%' . $filters['third_round_id'] . '%'];
         }
         
         $query = self::where($where);
@@ -88,36 +105,18 @@ class GameOrderModel extends Model
         
         // 获取列表数据
         $list = $query->field([
-                'id', 'user_id', 'uname', 'nickname', 'third_gid', 'third_order_id',
-                'third_round_id', 'parent_id', 'game_id', 'game_type', 'status',
-                'message', 'amount', 'bet', 'prev_amount', 'next_amount',
-                'action_type', 'ip', 'create_time', 'total_win_amount', 'total_amount'
+                'id', 'user_id', 'app_id', 'uname', 'nickname', 
+                'third_gid', 'third_order_id', 'third_round_id', 'parent_id',
+                'game_id', 'game_type', 'status', 'message',
+                'amount', 'bet', 'prev_amount', 'next_amount',
+                'action_type', 'ip', 'err_desc', 'create_time',
+                'total_win_amount', 'total_amount'
             ])
-            ->order('create_time', 'desc')
+            ->order('id', 'desc')
             ->page($page, $limit)
             ->select()
             ->toArray();
-        
-        // 格式化数据
-        foreach ($list as &$item) {            
-            // 格式化金额(分转元)
-            $item['amount'] = bcdiv((string)$item['amount'], '100', 2);
-            $item['bet'] = bcdiv((string)$item['bet'], '100', 2);
-            $item['prev_amount'] = bcdiv((string)$item['prev_amount'], '10000', 2);
-            $item['next_amount'] = bcdiv((string)$item['next_amount'], '10000', 2);
-            $item['total_win_amount'] = bcdiv((string)$item['total_win_amount'], '10000', 2);
-            $item['total_amount'] = bcdiv((string)$item['total_amount'], '10000', 2);
-            
-            // 状态文本
-            $item['status_text'] = self::getStatusText($item['status']);
-            
-            // 动作类型文本
-            $item['action_type_text'] = self::getActionTypeText($item['action_type']);
-            
-            // 游戏名称
-            $item['game_name'] = self::getGameName($item['game_id']);
-        }
-        
+                
         return [
             'list' => $list,
             'total' => $total,
@@ -125,7 +124,7 @@ class GameOrderModel extends Model
             'limit' => $limit
         ];
     }
-    
+       
     /**
      * 获取订单详情
      */
@@ -140,23 +139,13 @@ class GameOrderModel extends Model
         }
         
         $order = $order->toArray();
+        $order = self::formatItemData($order);
         
-        // 格式化数据
-        $order['create_time_text'] = date('Y-m-d H:i:s', $order['create_time']);
-        
-        // 格式化金额
-        $order['amount_yuan'] = bcdiv((string)$order['amount'], '100', 2);
-        $order['bet_yuan'] = bcdiv((string)$order['bet'], '100', 2);
-        $order['prev_amount_yuan'] = bcdiv((string)$order['prev_amount'], '10000', 2);
-        $order['next_amount_yuan'] = bcdiv((string)$order['next_amount'], '10000', 2);
-        $order['total_win_amount_yuan'] = bcdiv((string)$order['total_win_amount'], '10000', 2);
-        $order['total_amount_yuan'] = bcdiv((string)$order['total_amount'], '10000', 2);
-        
-        // 状态文本
-        $order['status_text'] = self::getStatusText($order['status']);
-        
-        // 动作类型文本
-        $order['action_type_text'] = self::getActionTypeText($order['action_type']);
+        // 获取相关的子订单
+        if (!empty($order['third_gid'])) {
+            $childOrders = self::getChildOrders([$order['third_gid']], $appId);
+            $order['children'] = $childOrders;
+        }
         
         // 游戏名称
         $order['game_name'] = self::getGameName($order['game_id']);
@@ -170,7 +159,8 @@ class GameOrderModel extends Model
     public static function getOrderStatistics($appId, $filters = [])
     {
         $where = [
-            ['app_id', '=', $appId]
+            ['app_id', '=', $appId],
+            ['status', '=', 1]
         ];
         
         // 时间筛选
@@ -188,9 +178,10 @@ class GameOrderModel extends Model
             ->field([
                 'COUNT(*) as total_orders',
                 'COUNT(DISTINCT uname) as total_players',
-                'SUM(bet) as total_bet_amount',
-                'SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_win_amount',
-                'SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END) as total_loss_amount',
+                'SUM(CASE WHEN action_type = 1 THEN bet ELSE 0 END) as total_bet_amount',
+                'SUM(total_win_amount) as total_win_amount',
+                'SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_profit',
+                'SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END) as total_loss',
                 'SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as success_orders',
                 'SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as failed_orders',
                 'SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) as cancelled_orders'
@@ -199,18 +190,18 @@ class GameOrderModel extends Model
             ->toArray();
         
         // 格式化金额
-        $statistics['total_bet_amount_yuan'] = bcdiv((string)$statistics['total_bet_amount'], '100', 2);
-        $statistics['total_win_amount_yuan'] = bcdiv((string)$statistics['total_win_amount'], '100', 2);
-        $statistics['total_loss_amount_yuan'] = bcdiv((string)$statistics['total_loss_amount'], '100', 2);
-        $net_amount = bcsub((string)$statistics['total_loss_amount'], (string)$statistics['total_win_amount']);
-        $statistics['net_amount_yuan'] = bcdiv($net_amount, '100', 2);
+        $statistics['total_bet_amount_yuan'] = self::convertBalance($statistics['total_bet_amount']);
+        $statistics['total_win_amount_yuan'] = self::convertBalance($statistics['total_win_amount']);
+        $statistics['total_profit_yuan'] = self::convertBalance($statistics['total_profit']);
+        $statistics['total_loss_yuan'] = self::convertBalance($statistics['total_loss']);
+        $net_amount = $statistics['total_bet_amount'] - $statistics['total_win_amount'];
+        $statistics['net_amount_yuan'] = self::convertBalance($net_amount);
         
         // 计算成功率
         if ($statistics['total_orders'] > 0) {
-            $rate = bcdiv((string)$statistics['success_orders'], (string)$statistics['total_orders'], 4);
-            $statistics['success_rate'] = bcmul($rate, '100', 2);
+            $statistics['success_rate'] = round(($statistics['success_orders'] / $statistics['total_orders']) * 100, 2);
         } else {
-            $statistics['success_rate'] = '0.00';
+            $statistics['success_rate'] = 0;
         }
         
         return $statistics;
@@ -249,12 +240,14 @@ class GameOrderModel extends Model
         $actionTypeMap = [
             self::ACTION_TYPE_BET => '下注',
             self::ACTION_TYPE_SETTLE => '结算',
-            self::ACTION_TYPE_CANCEL => '取消'
+            self::ACTION_TYPE_CANCEL => '取消',
+            self::ACTION_TYPE_CHECK => '检查',
+            self::ACTION_TYPE_RESULT => '结果'
         ];
         
         return $actionTypeMap[$actionType] ?? '其他';
     }
-    
+        
     /**
      * 获取游戏名称
      */

+ 108 - 118
app/model/GameRecordModel.php

@@ -7,108 +7,93 @@ use think\Model;
 use think\facade\Db;
 
 /**
- * 游戏记录模型
+ * 游戏记录模型 - 基于tp_game_bet_game表
  */
 class GameRecordModel extends Model
 {
-    protected $name = 'game_lottery_prizes';
+    protected $name = 'game_bet_game';
     protected $connection = 'fortue_tiger';
     protected $pk = 'id';
     
     // 动作类型常量
     const ACTION_TYPE_BET = 1;      // 下注
-    const ACTION_TYPE_WIN = 2;      // 中奖
-    const ACTION_TYPE_RETURN = 3;   // 退还
+    const ACTION_TYPE_RESULT = 2;   // 结算
     
     // 状态常量
     const STATUS_PENDING = 0;       // 待处理
     const STATUS_SUCCESS = 1;       // 成功
     const STATUS_FAILED = 2;        // 失败
     
+    // 游戏类型常量
+    const GAME_TYPE_SLOT = 1;       // 老虎机
+    const GAME_TYPE_TABLE = 2;      // 桌面游戏
+    const GAME_TYPE_LIVE = 3;       // 真人游戏
+    
     /**
-     * 获取游戏记录列表
+     * 获取游戏记录列表(参考apiAdminBetGameList方法)
      */
-    public static function getGameRecords($appId, $page = 1, $limit = 20, $filters = [])
+    public static function getBetGameList($appId, $page = 1, $limit = 20, $filters = [])
     {
-        $where = [
-            ['app_id', '=', $appId],
-            ['action_type', '=', 1],
-        ];
+        $wheres = [];
+        $wheres[] = ['action_type', '=', 1]; // 只查询下注记录
+        $wheres[] = ['app_id', '=', $appId];
         
         // 时间筛选
         if (!empty($filters['start_time'])) {
             $startTime = strtotime($filters['start_time'] . ' 00:00:00');
-            $where[] = ['create_time', '>=', $startTime];
+            $wheres[] = ['create_time', '>=', $startTime];
         }
         
         if (!empty($filters['end_time'])) {
             $endTime = strtotime($filters['end_time'] . ' 23:59:59');
-            $where[] = ['create_time', '<=', $endTime];
-        }
-        
-        // 平台ID筛选
-        if (!empty($filters['platform_id'])) {
-            $where[] = ['user_id', '=', $filters['platform_id']];
+            $wheres[] = ['create_time', '<=', $endTime];
         }
         
-        // 游戏筛选
+        // 游戏ID筛选
         if (!empty($filters['game_id'])) {
-            $where[] = ['game_id', '=', $filters['game_id']];
+            $wheres[] = ['game_id', '=', $filters['game_id']];
         }
         
-        // 玩家状态筛选
-        if ($filters['play_status'] !== '') {
-            $where[] = ['status', '=', $filters['play_status']];
+        // 牌局编号筛选
+        if (!empty($filters['third_round_id'])) {
+            $wheres[] = ['third_round_id', '=', $filters['third_round_id']];
         }
         
-        // 玩法筛选
-        if (!empty($filters['play_method'])) {
-            $where[] = ['bet_game_play_type', '=', $filters['play_method']];
+        // 用户ID筛选
+        if (!empty($filters['user_id'])) {
+            $wheres[] = ['user_id', '=', $filters['user_id']];
         }
         
-        // 触发方式筛选
-        if (!empty($filters['trigger_method'])) {
-            $where[] = ['action_type', '=', $filters['trigger_method']];
+        // 游戏玩法类型筛选
+        if (!empty($filters['bet_game_play_type'])) {
+            if ($filters['bet_game_play_type'] == 2) {
+                $wheres[] = ['bet_game_play_type', 'in', [1, 2]];
+            } else {
+                $wheres[] = ['bet_game_play_type', '=', $filters['bet_game_play_type']];
+            }
         }
         
-        // 牌局编号筛选
-        if (!empty($filters['round_number'])) {
-            $where[] = ['third_round_id', 'like', '%' . $filters['round_number'] . '%'];
-        }
-        
-        $query = self::where($where);
+        $query = self::where($wheres);
         
         // 统计总数
         $total = $query->count();
         
-        // 获取列表数据
-        $list = $query->field([
-                'id', 'user_id', 'uname', 'nickname', 'third_gid', 'third_round_id',
-                'game_id', 'game_type', 'bet_game_play_type', 'amount', 'bet_amount',
-                'prev_amount', 'next_amount', 'balance_amount', 'action_type', 'status',
-                'ip', 'create_time'
-            ])
-            ->order('create_time', 'desc')
+        // 获取列表数据(不包含result字段)
+        $list = $query->withoutField('result')
+            ->order('id', 'desc')
             ->page($page, $limit)
             ->select()
             ->toArray();
         
-        // 格式化数据
-        foreach ($list as &$item) {
-            // 格式化金额(除以10000)
-            $item['amount'] = bcdiv((string)$item['amount'], '10000', 2);
-            $item['bet_amount'] = bcdiv((string)$item['bet_amount'], '10000', 2);
-            $item['prev_amount'] = bcdiv((string)$item['prev_amount'], '10000', 2);
-            $item['next_amount'] = bcdiv((string)$item['next_amount'], '10000', 2);
-            $item['balance_amount'] = bcdiv((string)$item['balance_amount'], '10000', 2);
-            
-            // 状态文本
-            $item['status_text'] = self::getStatusText($item['status']);
-            
-            // 动作类型文本
-            $item['action_type_text'] = self::getActionTypeText($item['action_type']);            
+        if (empty($list)) {
+            return [
+                'list' => [],
+                'total' => $total,
+                'page' => $page,
+                'limit' => $limit
+            ];
         }
-        
+                
         return [
             'list' => $list,
             'total' => $total,
@@ -117,6 +102,48 @@ class GameRecordModel extends Model
         ];
     }
     
+    /**
+     * 获取子订单列表(action_type = 2的记录)
+     */
+    public static function getChildBetGameOrders($thirdGids, $appId)
+    {
+        if (empty($thirdGids)) {
+            return [];
+        }
+        
+        $childOrders = self::where([
+                ['third_gid', 'in', $thirdGids],
+                ['action_type', '=', 2],
+                ['app_id', '=', $appId]
+            ])
+            ->withoutField('result')
+            ->select()
+            ->toArray();
+        
+        return $childOrders;
+    }
+    
+    /**
+     * 获取商户信息映射
+     */
+    private static function getMerchantsInfoMap($appIds)
+    {
+        if (empty($appIds)) {
+            return [];
+        }
+        
+        // 这里可以从商户表获取信息,暂时返回基本信息
+        $map = [];
+        foreach ($appIds as $appId) {
+            $map[$appId] = [
+                'app_id' => $appId,
+                'nickname' => '商户' . $appId
+            ];
+        }
+        
+        return $map;
+    }
+        
     /**
      * 获取游戏记录详情
      */
@@ -132,25 +159,15 @@ class GameRecordModel extends Model
         
         $record = $record->toArray();
         
-        // 格式化数据
-        $record['create_time_text'] = date('Y-m-d H:i:s', $record['create_time']);
-        $record['update_time_text'] = date('Y-m-d H:i:s', $record['update_time']);
-        
-        // 格式化金额
-        $record['amount_yuan'] = bcdiv((string)$record['amount'], '10000', 2);
-        $record['bet_amount_yuan'] = bcdiv((string)$record['bet_amount'], '10000', 2);
-        $record['prev_amount_yuan'] = bcdiv((string)$record['prev_amount'], '10000', 2);
-        $record['next_amount_yuan'] = bcdiv((string)$record['next_amount'], '10000', 2);
-        $record['balance_amount_yuan'] = bcdiv((string)$record['balance_amount'], '10000', 2);
-        
-        // 状态文本
-        $record['status_text'] = self::getStatusText($record['status']);
+        // 获取商户信息
+        $merchantsMap = self::getMerchantsInfoMap([$record['app_id']]);
+        $record = self::formatBetGameData($record, $merchantsMap);
         
-        // 动作类型文本
-        $record['action_type_text'] = self::getActionTypeText($record['action_type']);
-        
-        // 解析开奖结果
-        $record['result_data'] = !empty($record['result']) ? json_decode($record['result'], true) : [];
+        // 获取相关的子订单
+        if (!empty($record['third_gid'])) {
+            $childOrders = self::getChildBetGameOrders([$record['third_gid']], $appId);
+            $record['children'] = $childOrders;
+        }
         
         return $record;
     }
@@ -161,7 +178,8 @@ class GameRecordModel extends Model
     public static function getGameStatistics($appId, $filters = [])
     {
         $where = [
-            ['app_id', '=', $appId]
+            ['app_id', '=', $appId],
+            ['action_type', '=', 1]
         ];
         
         // 时间筛选
@@ -179,26 +197,24 @@ class GameRecordModel extends Model
             ->field([
                 'COUNT(*) as total_records',
                 'COUNT(DISTINCT uname) as total_players',
-                'SUM(CASE WHEN action_type = 1 THEN bet_amount ELSE 0 END) as total_bet_amount',
-                'SUM(CASE WHEN action_type = 2 THEN amount ELSE 0 END) as total_win_amount',
-                'SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as success_records',
-                'SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as failed_records'
+                'SUM(bet) as total_bet_amount',
+                'SUM(total_win_amount) as total_win_amount',
+                'COUNT(DISTINCT game_id) as total_games'
             ])
             ->find()
             ->toArray();
         
         // 格式化金额
-        $statistics['total_bet_amount_yuan'] = bcdiv((string)$statistics['total_bet_amount'], '10000', 2);
-        $statistics['total_win_amount_yuan'] = bcdiv((string)$statistics['total_win_amount'], '10000', 2);
-        $net_amount = bcsub((string)$statistics['total_bet_amount'], (string)$statistics['total_win_amount']);
-        $statistics['net_amount_yuan'] = bcdiv($net_amount, '10000', 2);
-        
-        // 计算成功率
-        if ($statistics['total_records'] > 0) {
-            $rate = bcdiv((string)$statistics['success_records'], (string)$statistics['total_records'], 4);
-            $statistics['success_rate'] = bcmul($rate, '100', 2);
+        $statistics['total_bet_amount_yuan'] = self::convertBalance($statistics['total_bet_amount']);
+        $statistics['total_win_amount_yuan'] = self::convertBalance($statistics['total_win_amount']);
+        $net_amount = $statistics['total_bet_amount'] - $statistics['total_win_amount'];
+        $statistics['net_amount_yuan'] = self::convertBalance($net_amount);
+        
+        // 计算RTP
+        if ($statistics['total_bet_amount'] > 0) {
+            $statistics['rtp'] = round(($statistics['total_win_amount'] / $statistics['total_bet_amount']) * 100, 2);
         } else {
-            $statistics['success_rate'] = '0.00';
+            $statistics['rtp'] = 0;
         }
         
         return $statistics;
@@ -210,6 +226,7 @@ class GameRecordModel extends Model
     public static function getAllGameIds($appId)
     {
         return self::where('app_id', $appId)
+            ->where('action_type', 1)
             ->distinct(true)
             ->column('game_id');
     }
@@ -220,35 +237,8 @@ class GameRecordModel extends Model
     public static function getAllPlayMethods($appId)
     {
         return self::where('app_id', $appId)
+            ->where('action_type', 1)
             ->distinct(true)
             ->column('bet_game_play_type');
     }
-    
-    /**
-     * 获取状态文本
-     */
-    public static function getStatusText($status)
-    {
-        $statusMap = [
-            self::STATUS_PENDING => '待处理',
-            self::STATUS_SUCCESS => '成功',
-            self::STATUS_FAILED => '失败'
-        ];
-        
-        return $statusMap[$status] ?? '未知';
-    }
-    
-    /**
-     * 获取动作类型文本
-     */
-    public static function getActionTypeText($actionType)
-    {
-        $actionTypeMap = [
-            self::ACTION_TYPE_BET => '下注',
-            self::ACTION_TYPE_WIN => '中奖',
-            self::ACTION_TYPE_RETURN => '退还'
-        ];
-        
-        return $actionTypeMap[$actionType] ?? '其他';
-    }
 }

+ 16 - 0
app/model/GameResultBetOrder.php

@@ -0,0 +1,16 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+
+/**
+ * 商户游戏模型
+ */
+class GameResultBetOrder extends Model
+{
+    protected $name = 'game_result_bet_order';
+    protected $connection = 'fortue_tiger';
+
+}