Jelajahi Sumber

Merge remote-tracking branch 'origin/main'

# Conflicts:
#	app/middleware.php
ssvfdn 3 bulan lalu
induk
melakukan
8a7ff3d3b4

+ 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');

+ 376 - 0
app/controller/DailyStatistics.php

@@ -0,0 +1,376 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\controller;
+
+use app\BaseController;
+use app\model\MerchantDailyModel;
+use app\model\GameDailyModel;
+use app\model\MerchantHistoryModel;
+use think\facade\Request;
+
+class DailyStatistics extends BaseController
+{
+    /**
+     * 获取商户每日数据列表
+     */
+    public function merchantDailyList()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 10, 'intval');
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-7 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        try {
+            // 获取商户每日数据
+            $result = MerchantDailyModel::getMerchantDailyList(
+                $userInfo['merchant_id'],
+                $startDate,
+                $endDate,
+                $page,
+                $limit
+            );
+            
+            // 格式化数据
+            foreach ($result['list'] as &$item) {
+                $item['game_profit'] = round($item['game_profit'], 2);
+                $item['bet_amount'] = round($item['bet_amount'], 2);
+                $item['commission_amount'] = round($item['commission_amount'], 2);
+                $item['platform_fee'] = round($item['platform_fee'], 2);
+                $item['merchant_name'] = $userInfo['merchant_name'] ?? '商户' . $userInfo['merchant_id'];
+            }
+            
+            return json_success($result, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取商户每日数据失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取游戏每日数据列表
+     */
+    public function gameDailyList()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 10, 'intval');
+        $gameId = Request::get('game_id', 0, 'intval');
+        $gameName = Request::get('game_name', '', 'trim');
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-7 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        $filters = [
+            'merchant_id' => $userInfo['merchant_id'],
+            'game_id' => $gameId,
+            'game_name' => $gameName,
+            'start_date' => $startDate,
+            'end_date' => $endDate
+        ];
+        
+        try {
+            // 获取游戏每日数据
+            $result = GameDailyModel::getGameDailyList($filters, $page, $limit);
+            
+            // 格式化数据
+            foreach ($result['list'] as &$item) {
+                $item['game_profit'] = round($item['game_profit'], 2);
+                $item['bet_amount'] = round($item['bet_amount'], 2);
+                $item['commission_amount'] = round($item['commission_amount'], 2);
+            }
+            
+            return json_success($result, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取游戏每日数据失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取商户汇总统计
+     */
+    public function merchantSummary()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-30 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        try {
+            $summary = MerchantDailyModel::getMerchantSummary(
+                $userInfo['merchant_id'],
+                $startDate,
+                $endDate
+            );
+            
+            return json_success($summary, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取商户汇总统计失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取游戏列表
+     */
+    public function getGameList()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        try {
+            $games = GameDailyModel::getGameList($userInfo['merchant_id']);
+            
+            return json_success($games, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取游戏列表失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取商户历史数据统计
+     */
+    public function merchantHistory()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取过滤参数
+        $filters = [
+            'start_date' => Request::get('start_date', '', 'trim'),
+            'end_date' => Request::get('end_date', '', 'trim')
+        ];
+        
+        try {
+            $history = MerchantHistoryModel::getMerchantHistoryStatistics(
+                $userInfo['merchant_id'],
+                $filters
+            );
+            
+            return json_success($history, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取商户历史数据失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取商户历史数据列表(按月或按天)
+     */
+    public function merchantHistoryList()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 10, 'intval');
+        $groupBy = Request::get('group_by', 'month', 'trim'); // month 或 day
+        
+        $filters = [
+            'start_date' => Request::get('start_date', '', 'trim'),
+            'end_date' => Request::get('end_date', '', 'trim')
+        ];
+        
+        try {
+            $result = MerchantHistoryModel::getMerchantHistoryList(
+                $userInfo['merchant_id'],
+                $groupBy,
+                $page,
+                $limit,
+                $filters
+            );
+            
+            return json_success($result, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取商户历史数据列表失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 导出商户历史数据
+     */
+    public function exportMerchantHistory()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        $groupBy = Request::get('group_by', 'month', 'trim');
+        $filters = [
+            'start_date' => Request::get('start_date', '', 'trim'),
+            'end_date' => Request::get('end_date', '', 'trim')
+        ];
+        
+        try {
+            // 获取所有数据
+            $result = MerchantHistoryModel::getMerchantHistoryList(
+                $userInfo['merchant_id'],
+                $groupBy,
+                1,
+                100000,
+                $filters
+            );
+            
+            // 生成CSV数据
+            $csvData = "时间,RTP(%),注单数,注单金额(THB),游戏输赢(THB),注单金额(USDT),游戏输赢(USDT),登录用户,注册用户,投注用户,抽水额度(USDT),购买免费游戏次数\n";
+            
+            foreach ($result['list'] as $item) {
+                $csvData .= sprintf(
+                    "%s,%.2f,%d,%.2f,%.2f,%.4f,%.4f,%d,%d,%d,%.4f,%d\n",
+                    $item['period'],
+                    $item['rtp'],
+                    $item['total_orders'],
+                    $item['total_bet_thb'],
+                    $item['game_profit_thb'],
+                    $item['total_bet_usdt'],
+                    $item['game_profit_usdt'],
+                    $item['login_users'],
+                    $item['register_users'],
+                    $item['bet_users'],
+                    $item['commission_usdt'],
+                    $item['free_game_count']
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="merchant_history_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出商户历史数据失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取游戏汇总统计
+     */
+    public function gameSummary()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-30 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        try {
+            $summary = GameDailyModel::getGameSummary(
+                $userInfo['merchant_id'],
+                $startDate,
+                $endDate
+            );
+            
+            // 格式化数据
+            foreach ($summary as &$item) {
+                $item['total_profit'] = round($item['total_profit'], 2);
+                $item['avg_rtp'] = round($item['avg_rtp'], 2);
+                $item['total_bet_amount'] = round($item['total_bet_amount'], 2);
+                $item['total_commission'] = round($item['total_commission'], 2);
+            }
+            
+            return json_success($summary, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取游戏汇总统计失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 导出商户每日数据
+     */
+    public function exportMerchantDaily()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-30 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        try {
+            // 获取所有数据
+            $result = MerchantDailyModel::getMerchantDailyList(
+                $userInfo['merchant_id'],
+                $startDate,
+                $endDate,
+                1,
+                100000
+            );
+            
+            // 生成CSV数据
+            $csvData = "日期,商户,游戏输赢,游戏RTP(%),注单金额,注单数,投注用户,注册用户,登录用户,抽水额度,平台费用(USDT),购买免费游戏次数\n";
+            
+            foreach ($result['list'] as $item) {
+                $csvData .= sprintf(
+                    "%s,%s,%.2f,%.2f,%.2f,%d,%d,%d,%d,%.2f,%.2f,%d\n",
+                    $item['date'],
+                    $userInfo['merchant_name'] ?? '商户' . $userInfo['merchant_id'],
+                    $item['game_profit'],
+                    $item['game_rtp'],
+                    $item['bet_amount'],
+                    $item['bet_count'],
+                    $item['bet_users'],
+                    $item['register_users'],
+                    $item['login_users'],
+                    $item['commission_amount'],
+                    $item['platform_fee'],
+                    $item['free_game_count']
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="merchant_daily_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出商户每日数据失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 导出游戏每日数据
+     */
+    public function exportGameDaily()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        $startDate = Request::get('start_date', date('Y-m-d', strtotime('-30 days')), 'trim');
+        $endDate = Request::get('end_date', date('Y-m-d'), 'trim');
+        
+        $filters = [
+            'merchant_id' => $userInfo['merchant_id'],
+            'start_date' => $startDate,
+            'end_date' => $endDate
+        ];
+        
+        try {
+            // 获取所有数据
+            $result = GameDailyModel::getGameDailyList($filters, 1, 100000);
+            
+            // 生成CSV数据
+            $csvData = "日期,游戏名称,游戏输赢,游戏RTP(%),注单金额,注单数,投注用户,注册用户,登录用户,抽水额度,购买免费游戏次数\n";
+            
+            foreach ($result['list'] as $item) {
+                $csvData .= sprintf(
+                    "%s,%s,%.2f,%.2f,%.2f,%d,%d,%d,%d,%.2f,%d\n",
+                    $item['date'],
+                    $item['game_name'],
+                    $item['game_profit'],
+                    $item['game_rtp'],
+                    $item['bet_amount'],
+                    $item['bet_count'],
+                    $item['bet_users'],
+                    $item['register_users'],
+                    $item['login_users'],
+                    $item['commission_amount'],
+                    $item['free_game_count']
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="game_daily_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出游戏每日数据失败:' . $e->getMessage());
+        }
+    }
+}

+ 26 - 24
app/controller/Game.php

@@ -7,6 +7,7 @@ use app\BaseController;
 use app\model\GameModel;
 use app\validate\GameValidate;
 use think\facade\Request;
+use app\common\CommonUtils;
 
 class Game extends BaseController
 {
@@ -40,6 +41,12 @@ class Game extends BaseController
             foreach ($result['list'] as &$game) {
                 $game['status_text'] = GameModel::getStatusText($game['status']);
                 $game['rtp_type_text'] = GameModel::getRtpTypeText($game['rtp_type']);
+                $game['game_type_text'] = GameModel::getPlatFormText($game['game_platform']);                
+
+                $gameImages = CommonUtils::getGameDefaultImage($game);
+                $game['game_image_url'] = $gameImages['image_url'] ?? '';
+                $game['image_en_url'] = $gameImages['image_en_url'] ?? '';
+                $game['game_title'] = $game['title'] ?? '';
             }
             
             return json_success($result, '获取成功');
@@ -62,14 +69,15 @@ class Game extends BaseController
         }
         
         try {
-            $game = GameModel::getGameDetail($id, $userInfo['merchant_id']);
+            $game = GameModel::getGameDetail($userInfo['merchant_id'], ['id' => $id]);
             if (!$game) {
                 return json_error([], '游戏不存在');
             }
             
             $game['status_text'] = GameModel::getStatusText($game['status']);
             $game['rtp_type_text'] = GameModel::getRtpTypeText($game['rtp_type']);
-            
+            $game['game_type_text'] = GameModel::getPlatFormText($game['game_platform']);                
+
             return json_success($game, '获取成功');
         } catch (\Exception $e) {
             return json_error([], '获取游戏详情失败:' . $e->getMessage());
@@ -90,7 +98,7 @@ class Game extends BaseController
         }
         
         // 检查游戏是否存在且属于当前商户
-        $game = GameModel::getGameDetail($id, $userInfo['merchant_id']);
+        $game = GameModel::getGameDetail($userInfo['merchant_id'], ['id' => $id]);
         if (!$game) {
             return json_error([], '游戏不存在');
         }
@@ -130,7 +138,7 @@ class Game extends BaseController
         }
         
         try {
-            GameModel::updateGame($id, $updateData, $userInfo['merchant_id']);
+            GameModel::updateGame($userInfo['merchant_id'], $id, $updateData);
             return json_success([], '更新游戏成功');
         } catch (\Exception $e) {
             return json_error([], '更新游戏失败:' . $e->getMessage());
@@ -152,16 +160,12 @@ class Game extends BaseController
             return json_error([], '请选择要更新的游戏');
         }
         
-        if (!in_array($status, [
-            GameModel::STATUS_NORMAL,
-            GameModel::STATUS_MAINTAIN,
-            GameModel::STATUS_DISABLED
-        ])) {
+        if (!in_array($status, array_keys(GameModel::STATUS))) {
             return json_error([], '状态值无效');
         }
         
         try {
-            $result = GameModel::updateGameStatus($ids, $userInfo['merchant_id'], $status);
+            $result = GameModel::updateGameStatus($userInfo['merchant_id'], $ids, $status);
             if ($result) {
                 return json_success([], '状态更新成功');
             } else {
@@ -172,30 +176,28 @@ class Game extends BaseController
         }
     }
     
-    
     /**
-     * 获取游戏统计信息
+     * 获取游戏平台列表
      */
-    public function statistics()
+    public function getPlatforms()
     {
-        // 获取当前用户信息
-        $userInfo = $this->getUserInfo();
-        
         try {
-            $statistics = GameModel::getGameStatistics($userInfo['merchant_id']);
-            return json_success($statistics, '获取成功');
+            $platforms = GameModel::getAllPlatforms();
+            return json_success($platforms, '获取成功');
         } catch (\Exception $e) {
-            return json_error([], '获取游戏统计失败:' . $e->getMessage());
+            return json_error([], '获取游戏平台失败:' . $e->getMessage());
         }
     }
-    
+
     /**
-     * 获取游戏平台列表
+     * 获取所有游戏
      */
-    public function getPlatforms()
+    public function getGames()
     {
+        $userInfo = $this->getUserInfo();
+
         try {
-            $platforms = GameModel::getAllPlatforms();
+            $platforms = GameModel::getGames($userInfo['merchant_id']);
             return json_success($platforms, '获取成功');
         } catch (\Exception $e) {
             return json_error([], '获取游戏平台失败:' . $e->getMessage());
@@ -233,7 +235,7 @@ class Game extends BaseController
                     "%d,%d,%s,%s,%s,%.2f,%s,%s,%d,%d,%.2f,%.2f,%s,%s,%s\n",
                     $game['id'],
                     $game['game_id'],
-                    $game['game_platform'],
+                    GameModel::getPlatFormText($game['game_platform']),
                     $game['title'],
                     $game['title_en'],
                     $game['rtp'],

+ 86 - 121
app/controller/GameOrder.php

@@ -5,7 +5,11 @@ namespace app\controller;
 
 use app\BaseController;
 use think\facade\Request;
-use app\model\GameOrderModel;
+use app\model\GameBetOrderModel;
+use app\model\GameModel;
+use app\model\GameCheckBetOrder;
+use app\model\GameResultBetOrder;
+use app\common\CommonUtils;
 
 /**
  * 游戏订单控制器
@@ -33,127 +37,93 @@ 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);
-            return json_success($result, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取订单记录失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取订单详情
-     */
-    public function detail()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        $id = Request::get('id', 0, 'intval');
-        if (!$id) {
-            return json_error([], '订单ID不能为空');
-        }
-        
-        try {
-            $order = GameOrderModel::getOrderDetail($id, $userInfo['merchant_id']);
+            // 获取主订单列表
+            $result = GameBetOrderModel::getBetOrderList($userInfo['merchant_id'], $page, $limit, $filters);
             
-            if (!$order) {
-                return json_error([], '订单不存在');
+            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;
             }
             
-            return json_success($order, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取订单详情失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取订单统计信息
-     */
-    public function statistics()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        // 筛选条件
-        $filters = [
-            'start_time' => Request::get('start_time', '', 'trim'),
-            'end_time' => Request::get('end_time', '', 'trim'),
-        ];
-        
-        // 如果没有指定时间范围,默认获取今天
-        if (empty($filters['start_time']) && empty($filters['end_time'])) {
-            $filters['start_time'] = date('Y-m-d');
-            $filters['end_time'] = date('Y-m-d');
-        }
-        
-        try {
-            $statistics = GameOrderModel::getOrderStatistics($userInfo['merchant_id'], $filters);
-            
-            return json_success([
-                'statistics' => $statistics,
-                'date_range' => [
-                    'start_time' => $filters['start_time'],
-                    'end_time' => $filters['end_time']
-                ]
-            ], '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取统计信息失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取游戏列表(用于筛选下拉框)
-     */
-    public function getGames()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        try {
-            $gameIds = GameOrderModel::getAllGameIds($userInfo['merchant_id']);
+            // 获取母单号列表
+            $thirdGids = array_unique(array_column($result['list'], 'third_gid'));
             
-            // 构建游戏列表
-            $games = [];
-            foreach ($gameIds as $gameId) {
-                $games[] = [
-                    'game_id' => $gameId,
-                    'game_name' => $this->getGameName($gameId)
-                ];
+            // 获取子订单列表
+            $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;
             }
             
-            return json_success($games, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取游戏列表失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取订单原因列表(用于筛选下拉框)
-     */
-    public function getOrderReasons()
-    {
-        try {
-            $reasons = [
-                ['reason_id' => GameOrderModel::ACTION_TYPE_BET, 'reason_name' => '下注'],
-                ['reason_id' => GameOrderModel::ACTION_TYPE_SETTLE, 'reason_name' => '结算'],
-                ['reason_id' => GameOrderModel::ACTION_TYPE_CANCEL, 'reason_name' => '取消'],
-            ];
-            
-            return json_success($reasons, '获取成功');
+            $result['list'] = $newDataList;
+            return json_success($result, '获取成功');
         } catch (\Exception $e) {
-            return json_error([], '获取订单原因列表失败:' . $e->getMessage());
+            print_r($e->getTraceAsString());
+            return json_error([], '获取订单记录失败:' . $e->getMessage());
         }
     }
-    
+                
     /**
      * 导出订单记录
      */
@@ -176,7 +146,7 @@ class GameOrder extends BaseController
         
         try {
             // 获取所有符合条件的数据(不分页)
-            $result = GameOrderModel::getOrderRecords($userInfo['merchant_id'], 1, 100000, $filters);
+            $result = GameBetOrderModel::getOrderRecords($userInfo['merchant_id'], 1, 100000, $filters);
             
             // 生成CSV数据
             $csvData = "序号,母单号,子单号,牌局编号,平台昵称,玩家ID,所属商户,平台ID," .
@@ -219,20 +189,15 @@ class GameOrder extends BaseController
         }
     }
     
-    /**
-     * 获取游戏名称
-     */
-    private function getGameName($gameId)
+   // 格式化信息
+    private function formatItemDataText($item = [])
     {
-        // 这里可以根据实际情况配置游戏ID对应的名称
-        $gameNames = [
-            'tiger' => '老虎机',
-            'fortue_tiger' => '财富老虎',
-            'dragon_tiger' => '龙虎斗',
-            'baccarat' => '百家乐',
-            // 可以继续添加其他游戏
-        ];
-        
-        return $gameNames[$gameId] ?? $gameId;
-    }
+        $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;
+    }    
 }

+ 92 - 169
app/controller/GameRecord.php

@@ -5,8 +5,9 @@ namespace app\controller;
 
 use app\BaseController;
 use think\facade\Request;
-use app\model\GameRecordModel;
+use app\model\GameBetGameModel;
 use app\model\GameModel;
+use app\common\CommonUtils;
 
 /**
  * 游戏记录控制器
@@ -23,201 +24,109 @@ class GameRecord extends BaseController
         // 获取查询参数
         $page = Request::get('page', 1, 'intval');
         $limit = Request::get('limit', 20, 'intval');
-        
+        $compress = Request::get('compress', 1, 'intval');
+
         // 筛选条件
         $filters = [
             // 时间筛选
             '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);
-            
-            // 获取游戏信息映射
-            $gameIds = array_unique(array_column($result['list'], 'game_id'));
-            $gameInfoMap = $this->getGameInfoMap($gameIds, $userInfo['merchant_id']);
+            // 获取游戏记录列表
+            $result = GameBetGameModel::getBetGameList($userInfo['merchant_id'], $page, $limit, $filters);
             
-            // 添加游戏名称和图标到结果中
-            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'] : '';
+            if (empty($result['list'])) {
+                return json_success($result, '获取成功');
             }
             
-            return json_success($result, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取游戏记录失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取游戏记录详情
-     */
-    public function detail()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        $id = Request::get('id', 0, 'intval');
-        if (!$id) {
-            return json_error([], '记录ID不能为空');
-        }
-        
-        try {
-            $record = GameRecordModel::getGameRecordDetail($id, $userInfo['merchant_id']);
-            
-            if (!$record) {
-                return json_error([], '记录不存在');
-            }
-            
-            // 获取游戏信息
-            $gameInfo = GameModel::where('game_id', $record['game_id'])
-                ->where('merchant_id', $userInfo['merchant_id'])
-                ->field(['title', 'title_en', 'image', 'image_en'])
-                ->find();
             
-            if ($gameInfo) {
-                $record['game_name'] = $gameInfo['title'];
-                $record['game_name_en'] = $gameInfo['title_en'];
-                $record['game_icon'] = $gameInfo['image'];
-                $record['game_icon_en'] = $gameInfo['image_en'];
-            } else {
-                $record['game_name'] = $record['game_id'];
-                $record['game_name_en'] = '';
-                $record['game_icon'] = '';
-                $record['game_icon_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;
             }
             
-            return json_success($record, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取记录详情失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取游戏统计信息
-     */
-    public function statistics()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        // 筛选条件
-        $filters = [
-            'start_time' => Request::get('start_time', '', 'trim'),
-            'end_time' => Request::get('end_time', '', 'trim'),
-        ];
-        
-        // 如果没有指定时间范围,默认获取今天
-        if (empty($filters['start_time']) && empty($filters['end_time'])) {
-            $filters['start_time'] = date('Y-m-d');
-            $filters['end_time'] = date('Y-m-d');
-        }
-        
-        try {
-            $statistics = GameRecordModel::getGameStatistics($userInfo['merchant_id'], $filters);
-            
-            return json_success([
-                'statistics' => $statistics,
-                'date_range' => [
-                    'start_time' => $filters['start_time'],
-                    'end_time' => $filters['end_time']
-                ]
-            ], '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取统计信息失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取游戏列表(用于筛选下拉框)
-     */
-    public function getGames()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        try {
-            $gameIds = GameRecordModel::getAllGameIds($userInfo['merchant_id']);
-            
-            // 从GameModel获取游戏详细信息
-            $gameInfos = GameModel::whereIn('game_id', $gameIds)
-                ->where('merchant_id', $userInfo['merchant_id'])
-                ->field(['game_id', 'title', 'title_en', 'image', 'image_en'])
-                ->select()
-                ->toArray();
-            
-            // 创建游戏ID到游戏信息的映射
-            $gameMap = [];
-            foreach ($gameInfos as $gameInfo) {
-                $gameMap[$gameInfo['game_id']] = $gameInfo;
+            // 获取母单号列表
+            $thirdGids = array_unique(array_column($result['list'], 'third_gid'));
+
+            $childOrderList = [];
+            if(count($thirdGids) > 0) {
+                $tempCheckList = GameBetGameModel::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;
+                }
             }
             
-            // 构建游戏列表
-            $games = [];
-            foreach ($gameIds as $gameId) {
-                if (isset($gameMap[$gameId])) {
-                    $games[] = [
-                        'game_id' => $gameId,
-                        'game_name' => $gameMap[$gameId]['title'],
-                        'game_name_en' => $gameMap[$gameId]['title_en'],
-                        'game_icon' => $gameMap[$gameId]['image'],
-                        'game_icon_en' => $gameMap[$gameId]['image_en']
-                    ];
-                } else {
-                    $games[] = [
-                        'game_id' => $gameId,
-                        'game_name' => $this->getGameName($gameId),
-                        'game_name_en' => '',
-                        'game_icon' => '',
-                        'game_icon_en' => ''
-                    ];
+            // 格式化数据并添加子订单
+            $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;
             }
             
-            return json_success($games, '获取成功');
-        } catch (\Exception $e) {
-            return json_error([], '获取游戏列表失败:' . $e->getMessage());
-        }
-    }
-    
-    /**
-     * 获取玩法列表(用于筛选下拉框)
-     */
-    public function getPlayMethods()
-    {
-        $userInfo = $this->request->userInfo;
-        
-        try {
-            $playMethods = GameRecordModel::getAllPlayMethods($userInfo['merchant_id']);
-            
-            // 构建玩法列表
-            $methods = [];
-            foreach ($playMethods as $method) {
-                $methods[] = [
-                    'method_id' => $method,
-                    'method_name' => $this->getPlayMethodName($method)
+            $result['list'] = $newDataList;
+            if ($compress == 1)
+            {
+                $return = [
+                    'state' => 1,
+                    'code' => 0,
+                    'data' => $result,
+                    'message' => "获取成功"
                 ];
+                return base64_encode(gzcompress(json_encode($return)));
             }
-            
-            return json_success($methods, '获取成功');
+
+            return json_success($result, '获取成功');
         } catch (\Exception $e) {
-            return json_error([], '获取玩法列表失败:' . $e->getMessage());
+            return json_error([], '获取游戏记录失败:' . $e->getMessage());
         }
     }
     
+        
     /**
      * 导出游戏记录
      */
@@ -239,7 +148,7 @@ class GameRecord extends BaseController
         
         try {
             // 获取所有符合条件的数据(不分页)
-            $result = GameRecordModel::getGameRecords($userInfo['merchant_id'], 1, 100000, $filters);
+            $result = GameBetGameModel::getGameRecords($userInfo['merchant_id'], 1, 100000, $filters);
             
             // 获取游戏信息映射
             $gameIds = array_unique(array_column($result['list'], 'game_id'));
@@ -346,4 +255,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;
+    }    
 }

+ 6 - 6
app/controller/Player.php

@@ -24,7 +24,7 @@ class Player extends BaseController
         $filters = [
             'uname' => Request::get('uname', '', 'trim'),
             'nickname' => Request::get('nickname', '', 'trim'),
-            'user_id' => Request::get('user_id', 0, 'intval'),
+            'player_id' => Request::get('user_id', 0, 'intval'),
             'status' => Request::get('status', ''),
             'adjust_status' => Request::get('adjust_status', ''),
             'login_ip' => Request::get('login_ip', '', 'trim'),
@@ -59,7 +59,7 @@ class Player extends BaseController
     {
         $userInfo = $this->request->userInfo;
         
-        $playerId = Request::get('player_id', 0, 'intval');
+        $playerId = Request::get('user_id', 0, 'intval');
         if (!$playerId) {
             return json_error([], '玩家ID不能为空');
         }
@@ -90,7 +90,7 @@ class Player extends BaseController
 
         print_r($userInfo);
         
-        $playerIds = Request::post('player_ids', []);
+        $playerIds = Request::post('user_ids', []);
         $status = Request::post('status', 0, 'intval');
         
         if (empty($playerIds) || !is_array($playerIds)) {
@@ -120,7 +120,7 @@ class Player extends BaseController
     {
         $userInfo = $this->request->userInfo;
         
-        $playerIds = Request::post('player_ids', []);
+        $playerIds = Request::post('user_ids', []);
         $adjustStatus = Request::post('adjust_status', 0, 'intval');
         
         if (empty($playerIds) || !is_array($playerIds)) {
@@ -172,7 +172,7 @@ class Player extends BaseController
         // 获取所有过滤条件
         $filters = [
             'nickname' => Request::get('nickname', '', 'trim'),
-            'player_id' => Request::get('player_id', 0, 'intval'),
+            'player_id' => Request::get('user_id', 0, 'intval'),
             'status' => Request::get('status', ''),
             'adjust_status' => Request::get('adjust_status', ''),
             'login_ip' => Request::get('login_ip', '', 'trim'),
@@ -193,7 +193,7 @@ class Player extends BaseController
             foreach ($result['list'] as $player) {
                 $csvData .= sprintf(
                     "%d,%s,%s,%s,%.4f,%.4f,%.4f,%.4f,%d,%d,%s,%s,%s,%s\n",
-                    $player['player_id'],
+                    $player['user_id'],
                     $player['nickname'],
                     $player['reg_ip'],
                     $player['login_ip'],

+ 1 - 0
app/middleware.php

@@ -7,6 +7,7 @@ return [
     // \think\middleware\LoadLangPack::class,
     // Session初始化
     // \think\middleware\SessionInit::class
+    // 跨域
     \think\middleware\AllowCrossDomain::class
     // 注意:AuthMiddleware 不能配置在这里,因为这里的中间件在路由分发前执行
     // 需要在路由中配置中间件

+ 104 - 0
app/model/GameBetGameModel.php

@@ -0,0 +1,104 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+
+/**
+ * 游戏记录模型 - 基于tp_game_bet_game表
+ */
+class GameBetGameModel extends Model
+{
+    protected $name = 'game_bet_game';
+    protected $connection = 'fortue_tiger';
+    protected $pk = 'id';
+    
+    // 动作类型常量
+    const ACTION_TYPE_BET = 1;      // 下注
+    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 getBetGameList($appId, $page = 1, $limit = 20, $filters = [])
+    {
+        $wheres = [];
+        $wheres[] = ['action_type', '=', 1]; // 只查询下注记录
+        $wheres[] = ['app_id', '=', $appId];
+        
+        // 时间筛选
+        if (!empty($filters['start_time'])) {
+            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
+            $wheres[] = ['create_time', '>=', $startTime];
+        }
+        
+        if (!empty($filters['end_time'])) {
+            $endTime = strtotime($filters['end_time'] . ' 23:59:59');
+            $wheres[] = ['create_time', '<=', $endTime];
+        }
+        
+        // 游戏ID筛选
+        if (!empty($filters['game_id'])) {
+            $wheres[] = ['game_id', '=', $filters['game_id']];
+        }
+        
+        // 牌局编号筛选
+        if (!empty($filters['third_round_id'])) {
+            $wheres[] = ['third_round_id', '=', $filters['third_round_id']];
+        }
+        
+        // 用户ID筛选
+        if (!empty($filters['player_id'])) {
+            $wheres[] = ['user_id', '=', $filters['user_id']];
+        }
+        
+        // 游戏玩法类型筛选
+        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']];
+            }
+        }
+        
+        $query = self::where($wheres);
+        
+        // 统计总数
+        $total = $query->count();
+        
+        // 获取列表数据(不包含result字段)
+        $list = $query->withoutField('result')
+            ->order('id', 'desc')
+            ->page($page, $limit)
+            ->select()
+            ->toArray();
+        
+        if (empty($list)) {
+            return [
+                'list' => [],
+                'total' => $total,
+                'page' => $page,
+                'limit' => $limit
+            ];
+        }
+                
+        return [
+            'list' => $list,
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+}

+ 128 - 0
app/model/GameBetOrderModel.php

@@ -0,0 +1,128 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+use app\model\GameModel;
+
+/**
+ * 游戏订单模型 - 基于tp_game_bet_order表
+ */
+class GameBetOrderModel extends Model
+{
+    protected $name = 'game_bet_order';
+    protected $connection = 'fortue_tiger';
+    protected $pk = 'id';
+    
+    // 状态常量
+    const STATUS_PENDING = 0;       // 待处理
+    const STATUS_SUCCESS = 1;       // 成功
+    const STATUS_FAILED = 2;        // 失败
+    const STATUS_CANCELLED = 3;     // 已取消
+    
+    // 动作类型常量
+    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 getBetOrderList($appId, $page = 1, $limit = 20, $filters = [])
+    {
+        $where = [
+            ['app_id', '=', $appId]
+        ];
+        
+        // 时间筛选
+        if (!empty($filters['start_time'])) {
+            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
+            $where[] = ['create_time', '>=', $startTime];
+        }
+        
+        if (!empty($filters['end_time'])) {
+            $endTime = strtotime($filters['end_time'] . ' 23:59:59');
+            $where[] = ['create_time', '<=', $endTime];
+        }
+        
+        // 游戏筛选
+        if (!empty($filters['game_id'])) {
+            $where[] = ['game_id', '=', $filters['game_id']];
+        }
+        
+        // 订单原因筛选(动作类型)
+        if (!empty($filters['order_reason'])) {
+            $where[] = ['action_type', '=', $filters['order_reason']];
+        }
+        
+        // 平台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['third_order_id'])) {
+            $where[] = ['third_order_id', 'like', '%' . $filters['third_order_id'] . '%'];
+        }
+        
+        // 母单号筛选
+        if (!empty($filters['third_gid'])) {
+            $where[] = ['third_gid', 'like', '%' . $filters['third_gid'] . '%'];
+        }
+        
+        // 牌局编号筛选
+        if (!empty($filters['third_round_id'])) {
+            $where[] = ['third_round_id', 'like', '%' . $filters['third_round_id'] . '%'];
+        }
+        
+        $query = self::where($where);
+        
+        // 统计总数
+        $total = $query->count();
+        
+        // 获取列表数据
+        $list = $query->field([
+                '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('id', 'desc')
+            ->page($page, $limit)
+            ->select()
+            ->toArray();
+                
+        return [
+            'list' => $list,
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+}

+ 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';
+
+}

+ 245 - 0
app/model/GameDailyModel.php

@@ -0,0 +1,245 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+
+/**
+ * 游戏每日数据统计模型 - 基于tp_game_bet_order表实时统计
+ */
+class GameDailyModel extends Model
+{
+    // 连接到fortue_tiger数据库
+    protected $connection = 'fortue_tiger';
+    
+    /**
+     * 获取游戏每日数据列表
+     */
+    public static function getGameDailyList($filters = [], $page = 1, $limit = 10)
+    {
+        $query = Db::connect('fortue_tiger')->name('game_bet_order');
+        
+        // 应用过滤条件
+        if (!empty($filters['merchant_id'])) {
+            $query->where('app_id', $filters['merchant_id']);
+        }
+        
+        // 日期范围
+        $startDate = $filters['start_date'] ?? date('Y-m-d', strtotime('-7 days'));
+        $endDate = $filters['end_date'] ?? date('Y-m-d');
+        $startTime = strtotime($startDate . ' 00:00:00');
+        $endTime = strtotime($endDate . ' 23:59:59');
+        
+        $query->where('create_time', '>=', $startTime)
+              ->where('create_time', '<=', $endTime)
+              ->where('status', 1); // 只统计有效订单
+        
+        // 游戏ID或名称过滤
+        if (!empty($filters['game_id'])) {
+            $query->where('game_id', $filters['game_id']);
+        }
+        
+        if (!empty($filters['game_name'])) {
+            // 如果有游戏名称表,可以关联查询
+            $query->where('game_id', 'like', '%' . $filters['game_name'] . '%');
+        }
+        
+        // 按游戏和日期分组统计
+        $sql = "SELECT 
+                    DATE_FORMAT(FROM_UNIXTIME(create_time), '%Y-%m-%d') as date,
+                    game_id,
+                    COUNT(DISTINCT uname) as bet_users,
+                    COUNT(id) as bet_count,
+                    SUM(bet) as bet_amount,
+                    SUM(amount) as game_profit,
+                    SUM(total_win_amount) as total_win,
+                    COUNT(DISTINCT CASE WHEN action_type = 5 THEN id END) as free_game_count
+                FROM tp_game_bet_order
+                WHERE app_id = ? 
+                    AND create_time >= ? 
+                    AND create_time <= ?
+                    AND status = 1";
+        
+        $params = [$filters['merchant_id'] ?? 0, $startTime, $endTime];
+        
+        if (!empty($filters['game_id'])) {
+            $sql .= " AND game_id = ?";
+            $params[] = $filters['game_id'];
+        }
+        
+        $sql .= " GROUP BY date, game_id
+                  ORDER BY date DESC, game_id ASC";
+        
+        // 获取总数(用于分页)
+        $countSql = "SELECT COUNT(DISTINCT CONCAT(DATE_FORMAT(FROM_UNIXTIME(create_time), '%Y-%m-%d'), '-', game_id)) as total
+                     FROM tp_game_bet_order
+                     WHERE app_id = ? 
+                         AND create_time >= ? 
+                         AND create_time <= ?
+                         AND status = 1";
+        
+        $countParams = [$filters['merchant_id'] ?? 0, $startTime, $endTime];
+        if (!empty($filters['game_id'])) {
+            $countSql .= " AND game_id = ?";
+            $countParams[] = $filters['game_id'];
+        }
+        
+        $total = Db::connect('fortue_tiger')->query($countSql, $countParams)[0]['total'] ?? 0;
+        
+        // 添加分页
+        $sql .= " LIMIT " . (($page - 1) * $limit) . ", " . $limit;
+        
+        $list = Db::connect('fortue_tiger')->query($sql, $params);
+        
+        // 处理每条记录
+        foreach ($list as &$item) {
+            // 计算RTP
+            $item['game_rtp'] = 0;
+            if ($item['bet_amount'] > 0) {
+                $item['game_rtp'] = round(($item['total_win'] / $item['bet_amount']) * 100, 2);
+            }
+            
+            // 获取该游戏该天的注册用户(新用户首次玩该游戏)
+            $dayStart = strtotime($item['date'] . ' 00:00:00');
+            $dayEnd = strtotime($item['date'] . ' 23:59:59');
+            
+            $registerUsers = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->alias('gbo')
+                ->join('tp_merchants_user mu', 'gbo.uname = mu.uname', 'INNER')
+                ->where('gbo.app_id', $filters['merchant_id'] ?? 0)
+                ->where('gbo.game_id', $item['game_id'])
+                ->where('gbo.create_time', '>=', $dayStart)
+                ->where('gbo.create_time', '<=', $dayEnd)
+                ->where('mu.create_time', '>=', $dayStart)
+                ->where('mu.create_time', '<=', $dayEnd)
+                ->count('DISTINCT gbo.uname');
+            
+            // 获取登录用户数
+            $loginUsers = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->alias('gbo')
+                ->join('tp_merchants_user mu', 'gbo.uname = mu.uname', 'INNER')
+                ->where('gbo.app_id', $filters['merchant_id'] ?? 0)
+                ->where('gbo.game_id', $item['game_id'])
+                ->where('gbo.create_time', '>=', $dayStart)
+                ->where('gbo.create_time', '<=', $dayEnd)
+                ->where('mu.login_time', '>=', $dayStart)
+                ->where('mu.login_time', '<=', $dayEnd)
+                ->count('DISTINCT gbo.uname');
+            
+            // 计算抽水额度
+            $item['commission_amount'] = ($item['bet_amount'] - $item['total_win']) / 100;
+            
+            // 格式化金额字段(转换为元)
+            $item['game_profit'] = abs($item['game_profit']) / 100;
+            $item['bet_amount'] = $item['bet_amount'] / 100;
+            $item['total_win'] = $item['total_win'] / 100;
+            
+            // 添加其他字段
+            $item['game_name'] = '游戏' . $item['game_id']; // 如果有游戏名称表可以关联查询
+            $item['register_users'] = $registerUsers;
+            $item['login_users'] = $loginUsers;
+            
+            // 移除不需要的字段
+            unset($item['total_win']);
+        }
+        
+        return [
+            'list' => $list,
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+    
+    /**
+     * 获取游戏汇总统计
+     */
+    public static function getGameSummary($merchantId, $startDate, $endDate)
+    {
+        $startTime = strtotime($startDate . ' 00:00:00');
+        $endTime = strtotime($endDate . ' 23:59:59');
+        
+        $sql = "SELECT 
+                    game_id,
+                    COUNT(DISTINCT uname) as total_bet_users,
+                    COUNT(id) as total_bet_count,
+                    SUM(bet) as total_bet_amount,
+                    SUM(amount) as total_game_profit,
+                    SUM(total_win_amount) as total_win_amount,
+                    COUNT(DISTINCT CASE WHEN action_type = 5 THEN id END) as total_free_games,
+                    COUNT(DISTINCT DATE_FORMAT(FROM_UNIXTIME(create_time), '%Y-%m-%d')) as active_days
+                FROM tp_game_bet_order
+                WHERE app_id = ? 
+                    AND create_time >= ? 
+                    AND create_time <= ?
+                    AND status = 1
+                GROUP BY game_id
+                ORDER BY total_bet_amount DESC";
+        
+        $list = Db::connect('fortue_tiger')->query($sql, [$merchantId, $startTime, $endTime]);
+        
+        foreach ($list as &$item) {
+            // 计算平均RTP
+            $item['avg_rtp'] = 0;
+            if ($item['total_bet_amount'] > 0) {
+                $item['avg_rtp'] = round(($item['total_win_amount'] / $item['total_bet_amount']) * 100, 2);
+            }
+            
+            // 计算总抽水
+            $item['total_commission'] = ($item['total_bet_amount'] - $item['total_win_amount']) / 100;
+            
+            // 格式化金额字段
+            $item['total_game_profit'] = abs($item['total_game_profit']) / 100;
+            $item['total_bet_amount'] = $item['total_bet_amount'] / 100;
+            $item['total_win_amount'] = $item['total_win_amount'] / 100;
+            
+            // 添加游戏名称
+            $item['game_name'] = '游戏' . $item['game_id'];
+            
+            // 获取该游戏期间的注册和登录用户
+            $item['total_register_users'] = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->alias('gbo')
+                ->join('tp_merchants_user mu', 'gbo.uname = mu.uname', 'INNER')
+                ->where('gbo.app_id', $merchantId)
+                ->where('gbo.game_id', $item['game_id'])
+                ->where('gbo.create_time', '>=', $startTime)
+                ->where('gbo.create_time', '<=', $endTime)
+                ->where('mu.create_time', '>=', $startTime)
+                ->where('mu.create_time', '<=', $endTime)
+                ->count('DISTINCT gbo.uname');
+            
+            $item['total_login_users'] = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->alias('gbo')
+                ->join('tp_merchants_user mu', 'gbo.uname = mu.uname', 'INNER')
+                ->where('gbo.app_id', $merchantId)
+                ->where('gbo.game_id', $item['game_id'])
+                ->where('gbo.create_time', '>=', $startTime)
+                ->where('gbo.create_time', '<=', $endTime)
+                ->where('mu.login_time', '>=', $startTime)
+                ->where('mu.login_time', '<=', $endTime)
+                ->count('DISTINCT gbo.uname');
+        }
+        
+        return $list;
+    }
+    
+    /**
+     * 获取所有游戏列表
+     */
+    public static function getGameList($merchantId)
+    {
+        return Db::connect('fortue_tiger')
+            ->name('game_bet_order')
+            ->where('app_id', $merchantId)
+            ->group('game_id')
+            ->field('game_id, COUNT(id) as play_count')
+            ->order('play_count', 'desc')
+            ->select();
+    }
+}

+ 55 - 92
app/model/GameModel.php

@@ -46,33 +46,30 @@ class GameModel extends Model
     ];
 
     // 状态常量
-    const STATUS_NORMAL = 0;    // 正常
-    const STATUS_MAINTAIN = 1;  // 维护
-    const STATUS_DISABLED = 2;  // 停用
-
-    // RTP类型常量
-    const RTP_TYPE_AI = 1;       // AI数值
-    const RTP_TYPE_IMITATE = 2;     // 仿正版
+    const STATUS = [
+        0 => "初始",
+        1 => "正常",
+        2 => "维护",
+    ];
 
-    // 免费游戏状态
-    const FREE_GAME_DISABLED = 0;   // 不支持购买免费游戏
-    const FREE_GAME_ENABLED = 1;    // 支持购买免费游戏
+    // 止损止赢功能开关状态
+    const FREE_STATUS = [
+        0 => '关闭',
+        1 => '开启',
+    ];
 
-    // 止损止赢功能
-    const TERMINAL_SPIN_DISABLED = 0;   // 关闭止损止赢
-    const TERMINAL_SPIN_ENABLED = 1;    // 开启止损止赢
+    // 购买免费游戏功能开关状态
+    const TERMINAL_SPIN_STATUS = [
+        0 => '关闭',
+        1 => '开启',
+    ];
 
     /**
      * 获取状态文本
      */
     public static function getStatusText($status): string
     {
-        $statusMap = [
-            self::STATUS_NORMAL => '正常',
-            self::STATUS_MAINTAIN => '维护',
-            self::STATUS_DISABLED => '停用',
-        ];
-        return $statusMap[$status] ?? '未知';
+        return self::STATUS[$status] ?? '未知';
     }
 
     /**
@@ -80,11 +77,17 @@ class GameModel extends Model
      */
     public static function getRtpTypeText($rtpType): string
     {
-        $rtpTypeMap = [
-            self::RTP_TYPE_AI => 'AI数值',
-            self::RTP_TYPE_IMITATE => '仿正版',
-        ];
-        return $rtpTypeMap[$rtpType] ?? '未知';
+        $rtpTypeMap = $GLOBALS['gamePgGameConfig']['rtp_type_config'];
+        return $rtpTypeMap[$rtpType]['name'] ?? '未知';
+    }
+
+    /**
+     * 获取游戏平台文本
+     */
+    public static function getPlatFormText($platform): string
+    {
+        $platforms = self::getAllPlatforms();
+        return $platforms[$platform] ?? '未知';
     }
 
     /**
@@ -159,7 +162,7 @@ class GameModel extends Model
         $total = $query->count();
 
         // 获取列表
-        $list = $query->page($page, $limit)->select();
+        $list = $query->page($page, $limit)->select()->toArray();
 
         return [
             'list' => $list,
@@ -169,20 +172,38 @@ class GameModel extends Model
         ];
     }
 
+    public static function getGames($merchantId, $filters = [])
+    {
+        $query = self::where('merchant_id', $merchantId);
+        // 排序
+        $order = $filters['order'] ?? 'id';
+        $sort = $filters['sort'] ?? 'desc';
+        $query->order($order, $sort);
+
+        return $query->field(['id', 'game_id', 'title'])->select()->toArray();
+    }    
+
     /**
      * 获取游戏详情
      */
-    public static function getGameDetail($id, $merchantId)
+    public static function getGameDetail($merchantId, $filters = [])
     {
-        return self::where('id', $id)
-            ->where('merchant_id', $merchantId)
-            ->find();
+        $query = self::where('merchant_id', $merchantId);
+        if (!empty($filters['id'])) {
+            $query->where('id', $filters['id']);
+        }
+
+        if (!empty($filters['game_id'])) {
+            $query->where('game_id', $filters['game_id']);
+        }
+
+        return $query->find()->toArray();
     }
 
     /**
      * 创建游戏
      */
-    public static function createGame($data, $merchantId)
+    public static function createGame($merchantId, $data)
     {
         // 处理押注配置
         if (isset($data['deposit_list']) && is_array($data['deposit_list'])) {
@@ -198,7 +219,7 @@ class GameModel extends Model
     /**
      * 更新游戏
      */
-    public static function updateGame($id, $data, $merchantId)
+    public static function updateGame($merchantId, $id, $data)
     {
         // 处理押注配置
         if (isset($data['deposit_list']) && is_array($data['deposit_list'])) {
@@ -210,70 +231,12 @@ class GameModel extends Model
             ->update($data);
     }
 
-    /**
-     * 更新游戏状态
-     */
-    public static function updateGameStatus($ids, $merchantId, $status)
-    {
-        return self::whereIn('id', $ids)
-            ->where('merchant_id', $merchantId)
-            ->update(['status' => $status]);
-    }
-
-    /**
-     * 批量更新游戏状态
-     */
-    public static function batchUpdateStatus($ids, $status, $merchantId)
-    {
-        return self::whereIn('id', $ids)
-            ->where('merchant_id', $merchantId)
-            ->update(['status' => $status]);
-    }
-
-    /**
-     * 获取游戏统计信息
-     */
-    public static function getGameStatistics($merchantId)
-    {
-        $query = self::where('merchant_id', $merchantId);
-        
-        $totalGames = (clone $query)->count();
-        $normalGames = (clone $query)->where('status', self::STATUS_NORMAL)->count();
-        $maintainGames = (clone $query)->where('status', self::STATUS_MAINTAIN)->count();
-        $disabledGames = (clone $query)->where('status', self::STATUS_DISABLED)->count();
-        
-        // 按平台统计
-        $platformStats = [];
-        $platforms = self::getAllPlatforms();
-        
-        foreach ($platforms as $platform) {
-            $platformStats[$platform['platform_name']] = self::where('game_platform', $platform['id'])
-                ->where('merchant_id', $merchantId)
-                ->count();
-        }
-        
-        return [
-            'total_games' => $totalGames,
-            'normal_games' => $normalGames,
-            'maintain_games' => $maintainGames,
-            'disabled_games' => $disabledGames,
-            'platform_stats' => $platformStats,
-            'avg_rtp' => (clone $query)->avg('rtp'),
-            'free_game_enabled' => (clone $query)->where('free_game_status', self::FREE_GAME_ENABLED)->count(),
-            'terminal_spin_enabled' => (clone $query)->where('terminal_spin', self::TERMINAL_SPIN_ENABLED)->count(),
-        ];
-    }
-
     /**
      * 获取所有游戏平台
      */
     public static function getAllPlatforms(): array
     {
-        return self::table('merchant_game_platform')
-            ->field(['id', 'platform_name'])
-            ->order('id', 'asc')
-            ->select()
-            ->toArray();
+        return $GLOBALS['gameGameTypeConfig'];
     }
 
     /**
@@ -302,7 +265,7 @@ class GameModel extends Model
     /**
      * 检查游戏ID是否已存在
      */
-    public static function checkGameIdExists($gameId, $merchantId, $excludeId = null): bool
+    public static function checkGameIdExists($merchantId, $gameId, $excludeId = null): bool
     {
         $query = self::where('game_id', $gameId)
             ->where('merchant_id', $merchantId);
@@ -315,7 +278,7 @@ class GameModel extends Model
     /**
      * 删除游戏
      */
-    public static function deleteGame($id, $merchantId): bool
+    public static function deleteGame($merchantId, $id): bool
     {
         return self::where('id', $id)
             ->where('merchant_id', $merchantId)

+ 0 - 274
app/model/GameOrderModel.php

@@ -1,274 +0,0 @@
-<?php
-declare (strict_types = 1);
-
-namespace app\model;
-
-use think\Model;
-use think\facade\Db;
-
-/**
- * 游戏订单模型
- */
-class GameOrderModel extends Model
-{
-    protected $name = 'game_bet_order';
-    protected $connection = 'fortue_tiger';
-    protected $pk = 'id';
-    
-    // 状态常量
-    const STATUS_PENDING = 0;       // 待处理
-    const STATUS_SUCCESS = 1;       // 成功
-    const STATUS_FAILED = 2;        // 失败
-    const STATUS_CANCELLED = 3;     // 已取消
-    
-    // 动作类型常量
-    const ACTION_TYPE_BET = 1;      // 下注
-    const ACTION_TYPE_SETTLE = 2;   // 结算
-    const ACTION_TYPE_CANCEL = 3;   // 取消
-    
-    /**
-     * 获取订单记录列表
-     */
-    public static function getOrderRecords($appId, $page = 1, $limit = 20, $filters = [])
-    {
-        $where = [
-            ['app_id', '=', $appId]
-        ];
-        
-        // 时间筛选
-        if (!empty($filters['start_time'])) {
-            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
-            $where[] = ['create_time', '>=', $startTime];
-        }
-        
-        if (!empty($filters['end_time'])) {
-            $endTime = strtotime($filters['end_time'] . ' 23:59:59');
-            $where[] = ['create_time', '<=', $endTime];
-        }
-        
-        // 游戏筛选
-        if (!empty($filters['game_id'])) {
-            $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 ($filters['order_status'] !== '') {
-            $where[] = ['status', '=', $filters['order_status']];
-        }
-        
-        // 订单编号筛选(支持母单号、子单号、牌局编号)
-        if (!empty($filters['order_number'])) {
-            $where[] = ['third_order_id', 'like', '%' . $filters['order_number'] . '%'];
-        }
-        
-        // 母单号筛选
-        if (!empty($filters['parent_order'])) {
-            $where[] = ['third_gid', 'like', '%' . $filters['parent_order'] . '%'];
-        }
-        
-        // 牌局编号筛选
-        if (!empty($filters['round_number'])) {
-            $where[] = ['third_round_id', 'like', '%' . $filters['round_number'] . '%'];
-        }
-        
-        $query = self::where($where);
-        
-        // 统计总数
-        $total = $query->count();
-        
-        // 获取列表数据
-        $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'
-            ])
-            ->order('create_time', '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,
-            'page' => $page,
-            'limit' => $limit
-        ];
-    }
-    
-    /**
-     * 获取订单详情
-     */
-    public static function getOrderDetail($id, $appId)
-    {
-        $order = self::where('id', $id)
-            ->where('app_id', $appId)
-            ->find();
-            
-        if (!$order) {
-            return null;
-        }
-        
-        $order = $order->toArray();
-        
-        // 格式化数据
-        $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']);
-        
-        // 游戏名称
-        $order['game_name'] = self::getGameName($order['game_id']);
-        
-        return $order;
-    }
-    
-    /**
-     * 获取订单统计信息
-     */
-    public static function getOrderStatistics($appId, $filters = [])
-    {
-        $where = [
-            ['app_id', '=', $appId]
-        ];
-        
-        // 时间筛选
-        if (!empty($filters['start_time'])) {
-            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
-            $where[] = ['create_time', '>=', $startTime];
-        }
-        
-        if (!empty($filters['end_time'])) {
-            $endTime = strtotime($filters['end_time'] . ' 23:59:59');
-            $where[] = ['create_time', '<=', $endTime];
-        }
-        
-        $statistics = self::where($where)
-            ->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 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'
-            ])
-            ->find()
-            ->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);
-        
-        // 计算成功率
-        if ($statistics['total_orders'] > 0) {
-            $rate = bcdiv((string)$statistics['success_orders'], (string)$statistics['total_orders'], 4);
-            $statistics['success_rate'] = bcmul($rate, '100', 2);
-        } else {
-            $statistics['success_rate'] = '0.00';
-        }
-        
-        return $statistics;
-    }
-    
-    /**
-     * 获取所有游戏ID列表
-     */
-    public static function getAllGameIds($appId)
-    {
-        return self::where('app_id', $appId)
-            ->distinct(true)
-            ->column('game_id');
-    }
-    
-    /**
-     * 获取状态文本
-     */
-    public static function getStatusText($status)
-    {
-        $statusMap = [
-            self::STATUS_PENDING => '待处理',
-            self::STATUS_SUCCESS => '成功',
-            self::STATUS_FAILED => '失败',
-            self::STATUS_CANCELLED => '已取消'
-        ];
-        
-        return $statusMap[$status] ?? '未知';
-    }
-    
-    /**
-     * 获取动作类型文本
-     */
-    public static function getActionTypeText($actionType)
-    {
-        $actionTypeMap = [
-            self::ACTION_TYPE_BET => '下注',
-            self::ACTION_TYPE_SETTLE => '结算',
-            self::ACTION_TYPE_CANCEL => '取消'
-        ];
-        
-        return $actionTypeMap[$actionType] ?? '其他';
-    }
-    
-    /**
-     * 获取游戏名称
-     */
-    private static function getGameName($gameId)
-    {
-        // 这里可以根据实际情况配置游戏ID对应的名称
-        $gameNames = [
-            'tiger' => '老虎机',
-            'fortue_tiger' => '财富老虎',
-            'dragon_tiger' => '龙虎斗',
-            'baccarat' => '百家乐',
-            // 可以继续添加其他游戏
-        ];
-        
-        return $gameNames[$gameId] ?? $gameId;
-    }
-}

+ 0 - 254
app/model/GameRecordModel.php

@@ -1,254 +0,0 @@
-<?php
-declare (strict_types = 1);
-
-namespace app\model;
-
-use think\Model;
-use think\facade\Db;
-
-/**
- * 游戏记录模型
- */
-class GameRecordModel extends Model
-{
-    protected $name = 'game_lottery_prizes';
-    protected $connection = 'fortue_tiger';
-    protected $pk = 'id';
-    
-    // 动作类型常量
-    const ACTION_TYPE_BET = 1;      // 下注
-    const ACTION_TYPE_WIN = 2;      // 中奖
-    const ACTION_TYPE_RETURN = 3;   // 退还
-    
-    // 状态常量
-    const STATUS_PENDING = 0;       // 待处理
-    const STATUS_SUCCESS = 1;       // 成功
-    const STATUS_FAILED = 2;        // 失败
-    
-    /**
-     * 获取游戏记录列表
-     */
-    public static function getGameRecords($appId, $page = 1, $limit = 20, $filters = [])
-    {
-        $where = [
-            ['app_id', '=', $appId],
-            ['action_type', '=', 1],
-        ];
-        
-        // 时间筛选
-        if (!empty($filters['start_time'])) {
-            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
-            $where[] = ['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']];
-        }
-        
-        // 游戏筛选
-        if (!empty($filters['game_id'])) {
-            $where[] = ['game_id', '=', $filters['game_id']];
-        }
-        
-        // 玩家状态筛选
-        if ($filters['play_status'] !== '') {
-            $where[] = ['status', '=', $filters['play_status']];
-        }
-        
-        // 玩法筛选
-        if (!empty($filters['play_method'])) {
-            $where[] = ['bet_game_play_type', '=', $filters['play_method']];
-        }
-        
-        // 触发方式筛选
-        if (!empty($filters['trigger_method'])) {
-            $where[] = ['action_type', '=', $filters['trigger_method']];
-        }
-        
-        // 牌局编号筛选
-        if (!empty($filters['round_number'])) {
-            $where[] = ['third_round_id', 'like', '%' . $filters['round_number'] . '%'];
-        }
-        
-        $query = self::where($where);
-        
-        // 统计总数
-        $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')
-            ->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']);            
-        }
-        
-        return [
-            'list' => $list,
-            'total' => $total,
-            'page' => $page,
-            'limit' => $limit
-        ];
-    }
-    
-    /**
-     * 获取游戏记录详情
-     */
-    public static function getGameRecordDetail($id, $appId)
-    {
-        $record = self::where('id', $id)
-            ->where('app_id', $appId)
-            ->find();
-            
-        if (!$record) {
-            return null;
-        }
-        
-        $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']);
-        
-        // 动作类型文本
-        $record['action_type_text'] = self::getActionTypeText($record['action_type']);
-        
-        // 解析开奖结果
-        $record['result_data'] = !empty($record['result']) ? json_decode($record['result'], true) : [];
-        
-        return $record;
-    }
-    
-    /**
-     * 获取游戏统计信息
-     */
-    public static function getGameStatistics($appId, $filters = [])
-    {
-        $where = [
-            ['app_id', '=', $appId]
-        ];
-        
-        // 时间筛选
-        if (!empty($filters['start_time'])) {
-            $startTime = strtotime($filters['start_time'] . ' 00:00:00');
-            $where[] = ['create_time', '>=', $startTime];
-        }
-        
-        if (!empty($filters['end_time'])) {
-            $endTime = strtotime($filters['end_time'] . ' 23:59:59');
-            $where[] = ['create_time', '<=', $endTime];
-        }
-        
-        $statistics = self::where($where)
-            ->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'
-            ])
-            ->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);
-        } else {
-            $statistics['success_rate'] = '0.00';
-        }
-        
-        return $statistics;
-    }
-    
-    /**
-     * 获取所有游戏ID列表
-     */
-    public static function getAllGameIds($appId)
-    {
-        return self::where('app_id', $appId)
-            ->distinct(true)
-            ->column('game_id');
-    }
-    
-    /**
-     * 获取所有游戏玩法列表
-     */
-    public static function getAllPlayMethods($appId)
-    {
-        return self::where('app_id', $appId)
-            ->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';
+
+}

+ 198 - 0
app/model/MerchantDailyModel.php

@@ -0,0 +1,198 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+
+/**
+ * 商户每日数据统计模型 - 基于tp_game_bet_order表实时统计
+ */
+class MerchantDailyModel extends Model
+{
+    // 连接到fortue_tiger数据库
+    protected $connection = 'fortue_tiger';
+    
+    /**
+     * 获取商户每日数据列表
+     * @param int $merchantId 商户ID
+     * @param string $startDate 开始日期
+     * @param string $endDate 结束日期
+     * @param int $page 页码
+     * @param int $limit 每页数量
+     */
+    public static function getMerchantDailyList($merchantId, $startDate, $endDate, $page = 1, $limit = 10)
+    {
+        $startTime = strtotime($startDate . ' 00:00:00');
+        $endTime = strtotime($endDate . ' 23:59:59');
+        
+        // 生成日期数组
+        $dates = [];
+        $current = $startTime;
+        while ($current <= $endTime) {
+            $dates[] = date('Y-m-d', $current);
+            $current += 86400;
+        }
+        
+        // 按日期分组统计
+        $offset = ($page - 1) * $limit;
+        $paginatedDates = array_slice($dates, $offset, $limit);
+        
+        $list = [];
+        foreach ($paginatedDates as $date) {
+            $dayStart = strtotime($date . ' 00:00:00');
+            $dayEnd = strtotime($date . ' 23:59:59');
+            
+            // 获取游戏下注统计数据
+            $betStats = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->where('app_id', $merchantId)
+                ->where('create_time', '>=', $dayStart)
+                ->where('create_time', '<=', $dayEnd)
+                ->where('status', 1) // 只统计有效订单
+                ->field([
+                    'COUNT(DISTINCT uname) as bet_users',  // 投注用户数
+                    'COUNT(id) as bet_count',  // 注单数
+                    'SUM(bet) as bet_amount',  // 注单金额(下注分数)
+                    'SUM(amount) as game_profit',  // 游戏输赢(金额变化)
+                    'SUM(total_win_amount) as total_win',  // 总赢得金额
+                    'COUNT(DISTINCT game_id) as game_count'  // 游戏数量
+                ])
+                ->find();
+            
+            // 计算RTP(Return to Player)
+            $rtp = 0;
+            if ($betStats['bet_amount'] > 0) {
+                // RTP = (返还给玩家的金额 / 投注总额) * 100
+                $rtp = round(($betStats['total_win'] / $betStats['bet_amount']) * 100, 2);
+            }
+            
+            // 获取注册用户数
+            $registerUsers = Db::connect('fortue_tiger')
+                ->name('merchants_user')
+                ->where('app_id', $merchantId)
+                ->where('create_time', '>=', $dayStart)
+                ->where('create_time', '<=', $dayEnd)
+                ->count();
+            
+            // 获取登录用户数
+            $loginUsers = Db::connect('fortue_tiger')
+                ->name('merchants_user')
+                ->where('app_id', $merchantId)
+                ->where('login_time', '>=', $dayStart)
+                ->where('login_time', '<=', $dayEnd)
+                ->count();
+            
+            // 计算抽水额度(平台盈利 = 下注金额 - 赢得金额)
+            $commission = ($betStats['bet_amount'] ?? 0) - ($betStats['total_win'] ?? 0);
+            
+            // 获取免费游戏购买次数(假设action_type中某个值代表免费游戏)
+            $freeGameCount = Db::connect('fortue_tiger')
+                ->name('game_bet_order')
+                ->where('app_id', $merchantId)
+                ->where('create_time', '>=', $dayStart)
+                ->where('create_time', '<=', $dayEnd)
+                ->where('action_type', 5) // 假设5代表免费游戏
+                ->count();
+            
+            // 获取平台费用(假设从转账记录表获取)
+            $platformFee = 0;
+            if (Db::connect('fortue_tiger')->query("SHOW TABLES LIKE 'tp_transfer_log'")) {
+                $platformFee = Db::connect('fortue_tiger')
+                    ->name('transfer_log')
+                    ->where('merchant_id', $merchantId)
+                    ->where('type', 'platform_fee')
+                    ->where('create_time', '>=', $dayStart)
+                    ->where('create_time', '<=', $dayEnd)
+                    ->sum('amount');
+            }
+            
+            $list[] = [
+                'date' => $date,
+                'merchant_id' => $merchantId,
+                'game_profit' => abs($betStats['game_profit'] ?? 0) / 100,  // 转换为元
+                'game_rtp' => $rtp,
+                'bet_amount' => ($betStats['bet_amount'] ?? 0) / 100,  // 转换为元
+                'bet_count' => $betStats['bet_count'] ?? 0,
+                'bet_users' => $betStats['bet_users'] ?? 0,
+                'register_users' => $registerUsers,
+                'login_users' => $loginUsers,
+                'commission_amount' => $commission / 100,  // 转换为元
+                'platform_fee' => $platformFee / 100,  // 转换为元
+                'free_game_count' => $freeGameCount,
+                'game_count' => $betStats['game_count'] ?? 0
+            ];
+        }
+        
+        return [
+            'list' => $list,
+            'total' => count($dates),
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+    
+    /**
+     * 获取商户汇总统计
+     */
+    public static function getMerchantSummary($merchantId, $startDate, $endDate)
+    {
+        $startTime = strtotime($startDate . ' 00:00:00');
+        $endTime = strtotime($endDate . ' 23:59:59');
+        
+        // 获取汇总统计数据
+        $summary = Db::connect('fortue_tiger')
+            ->name('game_bet_order')
+            ->where('app_id', $merchantId)
+            ->where('create_time', '>=', $startTime)
+            ->where('create_time', '<=', $endTime)
+            ->where('status', 1)
+            ->field([
+                'COUNT(DISTINCT uname) as total_bet_users',
+                'COUNT(id) as total_bet_count',
+                'SUM(bet) as total_bet_amount',
+                'SUM(amount) as total_game_profit',
+                'SUM(total_win_amount) as total_win_amount',
+                'COUNT(DISTINCT game_id) as total_games',
+                'COUNT(DISTINCT DATE_FORMAT(FROM_UNIXTIME(create_time), "%Y-%m-%d")) as active_days'
+            ])
+            ->find();
+        
+        // 计算平均RTP
+        $avgRtp = 0;
+        if ($summary['total_bet_amount'] > 0) {
+            $avgRtp = round(($summary['total_win_amount'] / $summary['total_bet_amount']) * 100, 2);
+        }
+        
+        // 获取总注册用户
+        $totalRegisterUsers = Db::connect('fortue_tiger')
+            ->name('merchants_user')
+            ->where('app_id', $merchantId)
+            ->where('create_time', '>=', $startTime)
+            ->where('create_time', '<=', $endTime)
+            ->count();
+        
+        // 获取总登录用户
+        $totalLoginUsers = Db::connect('fortue_tiger')
+            ->name('merchants_user')
+            ->where('app_id', $merchantId)
+            ->where('login_time', '>=', $startTime)
+            ->where('login_time', '<=', $endTime)
+            ->count();
+        
+        return [
+            'total_bet_users' => $summary['total_bet_users'] ?? 0,
+            'total_bet_count' => $summary['total_bet_count'] ?? 0,
+            'total_bet_amount' => ($summary['total_bet_amount'] ?? 0) / 100,
+            'total_game_profit' => abs($summary['total_game_profit'] ?? 0) / 100,
+            'total_win_amount' => ($summary['total_win_amount'] ?? 0) / 100,
+            'avg_rtp' => $avgRtp,
+            'total_games' => $summary['total_games'] ?? 0,
+            'active_days' => $summary['active_days'] ?? 0,
+            'total_register_users' => $totalRegisterUsers,
+            'total_login_users' => $totalLoginUsers,
+            'total_commission' => (($summary['total_bet_amount'] ?? 0) - ($summary['total_win_amount'] ?? 0)) / 100
+        ];
+    }
+}

+ 241 - 0
app/model/MerchantHistoryModel.php

@@ -0,0 +1,241 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+
+/**
+ * 商户历史数据统计模型 - 基于tp_game_bet_order表统计所有历史数据
+ */
+class MerchantHistoryModel extends Model
+{
+    // 连接到fortue_tiger数据库
+    protected $connection = 'fortue_tiger';
+    
+    /**
+     * 获取商户历史数据统计
+     * @param int $merchantId 商户ID
+     * @param array $filters 过滤条件
+     */
+    public static function getMerchantHistoryStatistics($merchantId, $filters = [])
+    {
+        // 基础查询条件
+        $where = [
+            ['app_id', '=', $merchantId],
+            ['status', '=', 1]  // 只统计有效订单
+        ];
+        
+        // 日期范围过滤
+        if (!empty($filters['start_date'])) {
+            $startTime = strtotime($filters['start_date'] . ' 00:00:00');
+            $where[] = ['create_time', '>=', $startTime];
+        }
+        
+        if (!empty($filters['end_date'])) {
+            $endTime = strtotime($filters['end_date'] . ' 23:59:59');
+            $where[] = ['create_time', '<=', $endTime];
+        }
+        
+        // 获取汇总统计数据
+        $stats = Db::connect('fortue_tiger')
+            ->name('game_bet_order')
+            ->where($where)
+            ->field([
+                'COUNT(id) as total_orders',  // 注单数
+                'SUM(bet) as total_bet',  // 注单金额(分)
+                'SUM(amount) as total_profit',  // 游戏输赢(金额变化)
+                'SUM(total_win_amount) as total_win',  // 总赢得金额
+                'COUNT(DISTINCT uname) as bet_users',  // 投注用户数
+                'COUNT(DISTINCT CASE WHEN action_type = 5 THEN id END) as free_game_count'  // 购买免费游戏次数
+            ])
+            ->find();
+        
+        // 计算RTP(Return to Player)
+        $rtp = 0;
+        if ($stats['total_bet'] > 0) {
+            // RTP = (返还给玩家的金额 / 投注总额) * 100
+            $rtp = round(($stats['total_win'] / $stats['total_bet']) * 100, 2);
+        }
+        
+        // 获取注册用户数(根据时间范围)
+        $registerQuery = Db::connect('fortue_tiger')
+            ->name('merchants_user')
+            ->where('app_id', $merchantId);
+            
+        if (!empty($filters['start_date'])) {
+            $registerQuery->where('create_time', '>=', strtotime($filters['start_date'] . ' 00:00:00'));
+        }
+        
+        if (!empty($filters['end_date'])) {
+            $registerQuery->where('create_time', '<=', strtotime($filters['end_date'] . ' 23:59:59'));
+        }
+        
+        $registerUsers = $registerQuery->count();
+        
+        // 获取登录用户数(根据时间范围)
+        $loginQuery = Db::connect('fortue_tiger')
+            ->name('merchants_user')
+            ->where('app_id', $merchantId);
+            
+        if (!empty($filters['start_date'])) {
+            $loginQuery->where('login_time', '>=', strtotime($filters['start_date'] . ' 00:00:00'));
+        }
+        
+        if (!empty($filters['end_date'])) {
+            $loginQuery->where('login_time', '<=', strtotime($filters['end_date'] . ' 23:59:59'));
+        }
+        
+        $loginUsers = $loginQuery->where('login_time', '>', 0)->count();
+        
+        // 假设汇率(可以从配置或其他表获取)
+        $thbToUsdtRate = 0.028;  // 1 THB = 0.028 USDT (示例汇率)
+        
+        // 计算抽水额度(平台盈利 = 下注金额 - 赢得金额)
+        $commission = ($stats['total_bet'] ?? 0) - ($stats['total_win'] ?? 0);
+        
+        // 组装返回数据
+        $result = [
+            'rtp' => $rtp . '%',  // RTP百分比
+            'total_orders' => number_format($stats['total_orders'] ?? 0),  // 注单数
+            'total_bet_thb' => number_format(($stats['total_bet'] ?? 0) / 100, 2) . ' THB',  // 注单金额(THB)
+            'game_profit_thb' => number_format(abs($stats['total_profit'] ?? 0) / 100, 2) . ' THB',  // 游戏输赢(THB)
+            'total_bet_usdt' => number_format(($stats['total_bet'] ?? 0) / 100 * $thbToUsdtRate, 4) . ' USDT',  // 注单金额(USDT)
+            'game_profit_usdt' => number_format(abs($stats['total_profit'] ?? 0) / 100 * $thbToUsdtRate, 4) . ' USDT',  // 游戏输赢(USDT)
+            'login_users' => $loginUsers,  // 登录用户
+            'register_users' => $registerUsers,  // 注册用户
+            'bet_users' => $stats['bet_users'] ?? 0,  // 投注用户
+            'commission_usdt' => number_format($commission / 100 * $thbToUsdtRate, 4) . ' USDT',  // 抽水额度(USDT)
+            'free_game_count' => $stats['free_game_count'] ?? 0,  // 购买免费游戏次数
+            
+            // 原始数据(不带格式化)
+            'raw_data' => [
+                'rtp' => $rtp,
+                'total_orders' => $stats['total_orders'] ?? 0,
+                'total_bet' => ($stats['total_bet'] ?? 0) / 100,
+                'game_profit' => abs($stats['total_profit'] ?? 0) / 100,
+                'total_win' => ($stats['total_win'] ?? 0) / 100,
+                'commission' => $commission / 100,
+                'thb_to_usdt_rate' => $thbToUsdtRate
+            ]
+        ];
+        
+        return $result;
+    }
+    
+    /**
+     * 获取商户历史数据列表(按月份或按天统计)
+     */
+    public static function getMerchantHistoryList($merchantId, $groupBy = 'month', $page = 1, $limit = 10, $filters = [])
+    {
+        // 日期格式
+        $dateFormat = $groupBy === 'month' ? '%Y-%m' : '%Y-%m-%d';
+        
+        // 基础SQL
+        $sql = "SELECT 
+                    DATE_FORMAT(FROM_UNIXTIME(create_time), '{$dateFormat}') as period,
+                    COUNT(id) as total_orders,
+                    SUM(bet) as total_bet,
+                    SUM(amount) as game_profit,
+                    SUM(total_win_amount) as total_win,
+                    COUNT(DISTINCT uname) as bet_users,
+                    COUNT(DISTINCT CASE WHEN action_type = 5 THEN id END) as free_game_count
+                FROM tp_game_bet_order
+                WHERE app_id = ? AND status = 1";
+        
+        $params = [$merchantId];
+        
+        // 日期范围
+        if (!empty($filters['start_date'])) {
+            $sql .= " AND create_time >= ?";
+            $params[] = strtotime($filters['start_date'] . ' 00:00:00');
+        }
+        
+        if (!empty($filters['end_date'])) {
+            $sql .= " AND create_time <= ?";
+            $params[] = strtotime($filters['end_date'] . ' 23:59:59');
+        }
+        
+        $sql .= " GROUP BY period ORDER BY period DESC";
+        
+        // 获取总数
+        $countSql = "SELECT COUNT(DISTINCT DATE_FORMAT(FROM_UNIXTIME(create_time), '{$dateFormat}')) as total
+                     FROM tp_game_bet_order
+                     WHERE app_id = ? AND status = 1";
+        
+        $countParams = [$merchantId];
+        if (!empty($filters['start_date'])) {
+            $countSql .= " AND create_time >= ?";
+            $countParams[] = strtotime($filters['start_date'] . ' 00:00:00');
+        }
+        if (!empty($filters['end_date'])) {
+            $countSql .= " AND create_time <= ?";
+            $countParams[] = strtotime($filters['end_date'] . ' 23:59:59');
+        }
+        
+        $total = Db::connect('fortue_tiger')->query($countSql, $countParams)[0]['total'] ?? 0;
+        
+        // 分页
+        $sql .= " LIMIT " . (($page - 1) * $limit) . ", " . $limit;
+        
+        $list = Db::connect('fortue_tiger')->query($sql, $params);
+        
+        // 假设汇率
+        $thbToUsdtRate = 0.028;
+        
+        // 处理每条记录
+        foreach ($list as &$item) {
+            // 计算RTP
+            $item['rtp'] = 0;
+            if ($item['total_bet'] > 0) {
+                $item['rtp'] = round(($item['total_win'] / $item['total_bet']) * 100, 2);
+            }
+            
+            // 获取该时期的注册和登录用户
+            if ($groupBy === 'month') {
+                $periodStart = strtotime($item['period'] . '-01 00:00:00');
+                $periodEnd = strtotime(date('Y-m-t', $periodStart) . ' 23:59:59');
+            } else {
+                $periodStart = strtotime($item['period'] . ' 00:00:00');
+                $periodEnd = strtotime($item['period'] . ' 23:59:59');
+            }
+            
+            $item['register_users'] = Db::connect('fortue_tiger')
+                ->name('merchants_user')
+                ->where('app_id', $merchantId)
+                ->where('create_time', '>=', $periodStart)
+                ->where('create_time', '<=', $periodEnd)
+                ->count();
+            
+            $item['login_users'] = Db::connect('fortue_tiger')
+                ->name('merchants_user')
+                ->where('app_id', $merchantId)
+                ->where('login_time', '>=', $periodStart)
+                ->where('login_time', '<=', $periodEnd)
+                ->count();
+            
+            // 计算抽水
+            $commission = ($item['total_bet'] - $item['total_win']);
+            
+            // 格式化数据
+            $item['commission_usdt'] = $commission / 100 * $thbToUsdtRate;
+            $item['total_bet_thb'] = $item['total_bet'] / 100;
+            $item['total_bet_usdt'] = $item['total_bet'] / 100 * $thbToUsdtRate;
+            $item['game_profit_thb'] = abs($item['game_profit']) / 100;
+            $item['game_profit_usdt'] = abs($item['game_profit']) / 100 * $thbToUsdtRate;
+            
+            // 移除原始字段
+            unset($item['total_bet']);
+            unset($item['game_profit']);
+            unset($item['total_win']);
+        }
+        
+        return [
+            'list' => $list,
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+}

+ 5 - 6
app/model/MerchantsUserModel.php

@@ -109,8 +109,8 @@ class MerchantsUserModel extends Model
             $query->where('nickname', 'like', '%' . $filters['nickname'] . '%');
         }
 
-        if (!empty($filters['user_id'])) {
-            $query->where('user_id', $filters['user_id']);
+        if (!empty($filters['player_id'])) {
+            $query->where('user_id', $filters['player_id']);
         }
 
         if (isset($filters['status']) && $filters['status'] !== '') {
@@ -178,7 +178,7 @@ class MerchantsUserModel extends Model
      */
     public static function getPlayerDetail($playerId, $merchantId)
     {
-        $player = self::where('uname', $playerId)
+        $player = self::where('user_id', $playerId)
             ->where('app_id', $merchantId)
             ->find();
             
@@ -189,7 +189,6 @@ class MerchantsUserModel extends Model
             unset($player['short_token']);
             
             // 转换字段名
-            $player['player_id'] = $player['uname'];
             $player['merchant_id'] = $player['app_id'];
             $player['today_login_count'] = $player['today_count'];
             $player['history_login_count'] = $player['history_day_count'];
@@ -209,7 +208,7 @@ class MerchantsUserModel extends Model
     public static function updatePlayerStatus($playerIds, $merchantId, $status)
     {
         return self::where('app_id', $merchantId)
-            ->whereIn('uname', $playerIds)
+            ->whereIn('user_id', $playerIds)
             ->update(['status' => $status]);
     }
 
@@ -219,7 +218,7 @@ class MerchantsUserModel extends Model
     public static function updatePlayerAdjustStatus($playerIds, $merchantId, $adjustStatus)
     {
         return self::where('app_id', $merchantId)
-            ->whereIn('uname', $playerIds)
+            ->whereIn('user_id', $playerIds)
             ->update(['adjust_status' => $adjustStatus]);
     }
 

+ 20 - 0
route/app.php

@@ -49,6 +49,7 @@ Route::group('player', function () {
 // 游戏相关路由
 Route::group('game', function () {
     Route::get('list', 'Game/list');
+    Route::get('get_games', 'Game/getGames');
     Route::get('detail', 'Game/detail');
     Route::post('update', 'Game/update');
     Route::post('update_status', 'Game/updateStatus');
@@ -103,3 +104,22 @@ Route::group('transfer_log', function () {
     Route::get('statistics', 'TransferLog/statistics');
     Route::get('export', 'TransferLog/export');
 })->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);
+
+// 每日数据统计相关路由
+Route::group('daily_statistics', function () {
+    // 商户每日数据
+    Route::get('merchant_daily_list', 'DailyStatistics/merchantDailyList');
+    Route::get('merchant_summary', 'DailyStatistics/merchantSummary');
+    Route::get('export_merchant_daily', 'DailyStatistics/exportMerchantDaily');
+    
+    // 商户历史数据
+    Route::get('merchant_history', 'DailyStatistics/merchantHistory');
+    Route::get('merchant_history_list', 'DailyStatistics/merchantHistoryList');
+    Route::get('export_merchant_history', 'DailyStatistics/exportMerchantHistory');
+    
+    // 游戏每日数据
+    Route::get('game_daily_list', 'DailyStatistics/gameDailyList');
+    Route::get('game_summary', 'DailyStatistics/gameSummary');
+    Route::get('game_list', 'DailyStatistics/getGameList');
+    Route::get('export_game_daily', 'DailyStatistics/exportGameDaily');
+})->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);