Quellcode durchsuchen

feat:玩家数据功能

aiden vor 3 Monaten
Ursprung
Commit
e7e0c2db8f

+ 238 - 0
app/controller/GameOrder.php

@@ -0,0 +1,238 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\controller;
+
+use app\BaseController;
+use think\facade\Request;
+use app\model\GameOrderModel;
+
+/**
+ * 游戏订单控制器
+ */
+class GameOrder extends BaseController
+{
+    /**
+     * 获取订单记录列表
+     */
+    public function list()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 20, 'intval');
+        
+        // 筛选条件
+        $filters = [
+            // 时间筛选
+            'start_time' => Request::get('start_time', '', 'trim'),
+            'end_time' => Request::get('end_time', '', 'trim'),
+            // 游戏筛选
+            'game_id' => Request::get('game_id', '', 'trim'),
+            // 订单原因筛选
+            'order_reason' => Request::get('order_reason', '', 'trim'),
+            // 平台ID筛选
+            'platform_id' => Request::get('platform_id', '', 'trim'),
+            // 订单状态筛选
+            'order_status' => Request::get('order_status', ''),
+            // 订单编号筛选
+            'order_number' => Request::get('order_number', '', 'trim'),
+            // 母单号筛选
+            'parent_order' => Request::get('parent_order', '', 'trim'),
+            // 牌局编号筛选
+            'round_number' => Request::get('round_number', '', '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']);
+            
+            if (!$order) {
+                return json_error([], '订单不存在');
+            }
+            
+            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']);
+            
+            // 构建游戏列表
+            $games = [];
+            foreach ($gameIds as $gameId) {
+                $games[] = [
+                    'game_id' => $gameId,
+                    'game_name' => $this->getGameName($gameId)
+                ];
+            }
+            
+            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, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取订单原因列表失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 导出订单记录
+     */
+    public function export()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 筛选条件
+        $filters = [
+            'start_time' => Request::get('start_time', '', 'trim'),
+            'end_time' => Request::get('end_time', '', 'trim'),
+            'game_id' => Request::get('game_id', '', 'trim'),
+            'order_reason' => Request::get('order_reason', '', 'trim'),
+            'platform_id' => Request::get('platform_id', '', 'trim'),
+            'order_status' => Request::get('order_status', ''),
+            'order_number' => Request::get('order_number', '', 'trim'),
+            'parent_order' => Request::get('parent_order', '', 'trim'),
+            'round_number' => Request::get('round_number', '', 'trim'),
+        ];
+        
+        try {
+            // 获取所有符合条件的数据(不分页)
+            $result = GameOrderModel::getOrderRecords($userInfo['merchant_id'], 1, 100000, $filters);
+            
+            // 生成CSV数据
+            $csvData = "序号,母单号,子单号,牌局编号,平台昵称,玩家ID,所属商户,平台ID," .
+                      "游戏名称,变动金额,变更前,变更后,下注金额,总变动金额," .
+                      "总变动金额,最后结算金额,状态,原因,创建时间\n";
+            
+            foreach ($result['list'] as $index => $order) {
+                $csvData .= sprintf(
+                    "%d,%s,%s,%s,%s,%d,%s,%d,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%s,%s,%s\n",
+                    $index + 1,                                    // 序号
+                    $order['third_gid'],                           // 母单号
+                    $order['third_order_id'],                      // 子单号
+                    $order['third_round_id'],                      // 牌局编号
+                    $order['nickname'],                            // 平台昵称
+                    $order['uname'],                               // 玩家ID
+                    $userInfo['merchant_id'],                      // 所属商户
+                    $order['user_id'],                             // 平台ID
+                    $order['game_name'],                           // 游戏名称
+                    $order['amount'],                         // 变动金额
+                    $order['prev_amount'],                    // 变更前
+                    $order['next_amount'],                    // 变更后
+                    $order['bet'],                            // 下注金额
+                    $order['total_win_amount'],               // 总变动金额
+                    $order['total_amount'],                   // 总变动金额
+                    $order['next_amount'],                    // 最后结算金额
+                    $order['status_text'],                         // 状态
+                    $order['action_type_text'],                    // 原因
+                    $order['create_time'],                    // 创建时间
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="game_orders_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出订单记录失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取游戏名称
+     */
+    private function getGameName($gameId)
+    {
+        // 这里可以根据实际情况配置游戏ID对应的名称
+        $gameNames = [
+            'tiger' => '老虎机',
+            'fortune_tiger' => '财富老虎',
+            'dragon_tiger' => '龙虎斗',
+            'baccarat' => '百家乐',
+            // 可以继续添加其他游戏
+        ];
+        
+        return $gameNames[$gameId] ?? $gameId;
+    }
+}

+ 349 - 0
app/controller/GameRecord.php

@@ -0,0 +1,349 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\controller;
+
+use app\BaseController;
+use think\facade\Request;
+use app\model\GameRecordModel;
+use app\model\GameModel;
+
+/**
+ * 游戏记录控制器
+ */
+class GameRecord extends BaseController
+{
+    /**
+     * 获取游戏记录列表
+     */
+    public function list()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 20, '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'),
+        ];
+        
+        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']);
+            
+            // 添加游戏名称和图标到结果中
+            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'] : '';
+            }
+            
+            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'] = '';
+            }
+            
+            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;
+            }
+            
+            // 构建游戏列表
+            $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' => ''
+                    ];
+                }
+            }
+            
+            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)
+                ];
+            }
+            
+            return json_success($methods, '获取成功');
+        } catch (\Exception $e) {
+            return json_error([], '获取玩法列表失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 导出游戏记录
+     */
+    public function export()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 筛选条件
+        $filters = [
+            'start_time' => Request::get('start_time', '', 'trim'),
+            'end_time' => Request::get('end_time', '', 'trim'),
+            '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'),
+        ];
+        
+        try {
+            // 获取所有符合条件的数据(不分页)
+            $result = GameRecordModel::getGameRecords($userInfo['merchant_id'], 1, 100000, $filters);
+            
+            // 获取游戏信息映射
+            $gameIds = array_unique(array_column($result['list'], 'game_id'));
+            $gameInfoMap = $this->getGameInfoMap($gameIds, $userInfo['merchant_id']);
+            
+            // 生成CSV数据
+            $csvData = "序号,父局号,牌局ID,创建时间,牌局编号,平台昵称,玩家ID,所属商户," .
+                      "平台ID,游戏名称,游戏玩法,调控状态,免费触发,RTP,下注金额," .
+                      "应下注,应返奖,玩家输赢,下注前,结算后,总输赢,最后结算金额,操作\n";
+            
+            foreach ($result['list'] as $index => $record) {
+                $gameInfo = $gameInfoMap[$record['game_id']] ?? null;
+                $gameName = $gameInfo ? $gameInfo['title'] : $this->getGameName($record['game_id']);
+                
+                $csvData .= sprintf(
+                    "%d,%s,%s,%s,%s,%s,%d,%s,%d,%s,%s,%s,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%s\n",
+                    $index + 1,                                    // 序号
+                    $record['third_gid'],                          // 父局号
+                    $record['id'],                                 // 牌局ID
+                    $record['create_time_text'],                   // 创建时间
+                    $record['third_round_id'],                     // 牌局编号
+                    $record['nickname'],                           // 平台昵称
+                    $record['uname'],                              // 玩家ID
+                    $userInfo['merchant_id'],                      // 所属商户
+                    $record['user_id'],                            // 平台ID
+                    $gameName,                                      // 游戏名称
+                    $this->getPlayMethodName($record['bet_game_play_type']), // 游戏玩法
+                    $record['status_text'],                        // 调控状态
+                    '',                                            // 免费触发(暂时为空)
+                    '',                                            // RTP(暂时为空)
+                    $record['bet_amount_yuan'],                    // 下注金额
+                    0.00,                                          // 应下注
+                    0.00,                                          // 应返奖
+                    $record['amount_yuan'],                        // 玩家输赢
+                    $record['prev_amount_yuan'],                   // 下注前
+                    $record['next_amount_yuan'],                   // 结算后
+                    $record['amount_yuan'],                        // 总输赢
+                    $record['balance_amount_yuan'],                // 最后结算金额
+                    $record['action_type_text']                    // 操作
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="game_records_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出游戏记录失败:' . $e->getMessage());
+        }
+    }
+    
+    /**
+     * 获取游戏名称
+     */
+    private function getGameName($gameId)
+    {
+        // 这里可以根据实际情况配置游戏ID对应的名称
+        $gameNames = [
+            'tiger' => '老虎机',
+            'fortune_tiger' => '财富老虎',
+            // 可以继续添加其他游戏
+        ];
+        
+        return $gameNames[$gameId] ?? $gameId;
+    }
+    
+    /**
+     * 获取玩法名称
+     */
+    private function getPlayMethodName($methodId)
+    {
+        // 这里可以根据实际情况配置玩法ID对应的名称
+        $methodNames = [
+            1 => '普通模式',
+            2 => '免费模式',
+            3 => '特殊模式',
+            // 可以继续添加其他玩法
+        ];
+        
+        return $methodNames[$methodId] ?? '未知玩法';
+    }
+    
+    /**
+     * 获取游戏信息映射
+     */
+    private function getGameInfoMap($gameIds, $merchantId)
+    {
+        if (empty($gameIds)) {
+            return [];
+        }
+        
+        $gameInfos = GameModel::whereIn('game_id', $gameIds)
+            ->where('merchant_id', $merchantId)
+            ->field(['game_id', 'title', 'title_en', 'image', 'image_en'])
+            ->select()
+            ->toArray();
+        
+        $map = [];
+        foreach ($gameInfos as $gameInfo) {
+            $map[$gameInfo['game_id']] = $gameInfo;
+        }
+        
+        return $map;
+    }
+}

+ 157 - 0
app/controller/TransferLog.php

@@ -0,0 +1,157 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\controller;
+
+use app\BaseController;
+use think\facade\Request;
+use app\model\TransferLogModel;
+
+/**
+ * 转账记录控制器
+ */
+class TransferLog extends BaseController
+{
+    /**
+     * 获取转账记录列表
+     */
+    public function list()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 获取查询参数
+        $page = Request::get('page', 1, 'intval');
+        $limit = Request::get('limit', 20, 'intval');
+        
+        // 筛选条件
+        $filters = [
+            // 时间筛选
+            'start_time' => Request::get('start_time', '', 'trim'),
+            'end_time' => Request::get('end_time', '', 'trim'),
+            // 平台ID筛选
+            'platform_id' => Request::get('platform_id', '', 'trim'),
+            // 状态筛选
+            'status' => Request::get('status', ''),
+            // 转账流水号筛选
+            'tx_id' => Request::get('tx_id', '', 'trim'),
+        ];
+        
+        try {
+            $result = TransferLogModel::getTransferLogs($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 {
+            $transfer = TransferLogModel::getTransferDetail($id, $userInfo['merchant_id']);
+            
+            if (!$transfer) {
+                return json_error([], '记录不存在');
+            }
+            
+            return json_success($transfer, '获取成功');
+        } 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 = TransferLogModel::getTransferStatistics($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 export()
+    {
+        $userInfo = $this->request->userInfo;
+        
+        // 筛选条件
+        $filters = [
+            'start_time' => Request::get('start_time', '', 'trim'),
+            'end_time' => Request::get('end_time', '', 'trim'),
+            'platform_id' => Request::get('platform_id', '', 'trim'),
+            'status' => Request::get('status', ''),
+            'tx_id' => Request::get('tx_id', '', 'trim'),
+        ];
+        
+        try {
+            // 获取所有符合条件的数据(不分页)
+            $result = TransferLogModel::getTransferLogs($userInfo['merchant_id'], 1, 100000, $filters);
+            
+            // 生成CSV数据
+            $csvData = "创建时间,商户,玩家ID,平台ID,平台昵称,转账流水号,转账金额,转账前余额," .
+                      "转账后余额,转账金额,转账前余额,转账后余额,状态/原因,IP\n";
+            
+            foreach ($result['list'] as $transfer) {
+                $csvData .= sprintf(
+                    "%s,%s,%d,%d,%s,%s,%s,%s,%s,%s,%s\n",
+                    $transfer['create_time'],                   // 创建时间
+                    $transfer['merchant_name'],                 // 商户
+                    $transfer['uname'],                          // 玩家ID
+                    $transfer['user_id'],                        // 平台ID
+                    $transfer['platform_nickname'],             // 平台昵称
+                    $transfer['tx_id'],                          // 转账流水号
+                    $transfer['amount'],                    // 转账金额
+                    $transfer['prev_amount'],               // 转账前余额
+                    $transfer['next_amount'],               // 转账后余额
+                    $transfer['status_text'],                    // 状态/原因
+                    $transfer['ip']                              // IP
+                );
+            }
+            
+            // 返回CSV数据
+            return response($csvData)
+                ->header(['Content-Type' => 'text/csv; charset=utf-8'])
+                ->header(['Content-Disposition' => 'attachment; filename="transfer_logs_' . date('YmdHis') . '.csv"'])
+                ->header(['Cache-Control' => 'no-cache, must-revalidate']);
+                
+        } catch (\Exception $e) {
+            return json_error([], '导出转账记录失败:' . $e->getMessage());
+        }
+    }
+}

+ 274 - 0
app/model/GameOrderModel.php

@@ -0,0 +1,274 @@
+<?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 = 'fortune_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' => '老虎机',
+            'fortune_tiger' => '财富老虎',
+            'dragon_tiger' => '龙虎斗',
+            'baccarat' => '百家乐',
+            // 可以继续添加其他游戏
+        ];
+        
+        return $gameNames[$gameId] ?? $gameId;
+    }
+}

+ 254 - 0
app/model/GameRecordModel.php

@@ -0,0 +1,254 @@
+<?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 = 'fortune_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] ?? '其他';
+    }
+}

+ 216 - 0
app/model/TransferLogModel.php

@@ -0,0 +1,216 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+use think\facade\Db;
+
+/**
+ * 转账记录模型
+ */
+class TransferLogModel extends Model
+{
+    protected $name = 'merchants_user_balance_transfer_logs';
+    protected $connection = 'fortune_tiger';
+    protected $pk = 'id';
+    
+    // 状态常量
+    const STATUS_FAILED = 0;        // 失败
+    const STATUS_SUCCESS = 1;       // 成功
+    const STATUS_PENDING = 2;       // 待处理
+    
+    /**
+     * 获取转账记录列表
+     */
+    public static function getTransferLogs($merchantId, $page = 1, $limit = 20, $filters = [])
+    {
+        $where = [
+            ['app_id', '=', $merchantId]
+        ];
+        
+        // 时间筛选
+        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 ($filters['status'] !== '') {
+            $where[] = ['status', '=', $filters['status']];
+        }
+        
+        // 转账流水号筛选
+        if (!empty($filters['tx_id'])) {
+            $where[] = ['tx_id', 'like', '%' . $filters['tx_id'] . '%'];
+        }
+        
+        $query = self::where($where);
+        
+        // 统计总数
+        $total = $query->count();
+        
+        // 获取列表数据
+        $list = $query->field([
+                'id', 'user_id', 'uname', 'tx_id', 'ptx_id', 'amount',
+                'prev_amount', 'next_amount', 'status', 'ip', 
+                'message', 'create_time'
+            ])
+            ->order('create_time', 'desc')
+            ->page($page, $limit)
+            ->select()
+            ->toArray();
+        
+        // 获取用户信息
+        $userIds = array_unique(array_column($list, 'user_id'));
+        $userMap = [];
+        if (!empty($userIds)) {
+            // 从用户表获取用户信息
+            $users = Db::connect('merchant_admin')
+                ->table('merchant_user')
+                ->whereIn('user_id', $userIds)
+                ->field('user_id, nick_name')
+                ->select();
+            
+            foreach ($users as $user) {
+                $userMap[$user['user_id']] = $user['nick_name'];
+            }
+        }
+        
+        // 格式化数据
+        foreach ($list as &$item) {            
+            // 格式化金额(分转元)
+            $item['amount'] = bcdiv($item['amount'], "100", 2);
+            $item['prev_amount'] = bcdiv($item['prev_amount'], "100", 2);
+            $item['next_amount'] = bcdiv($item['next_amount'], "100", 2);
+            
+            // 状态文本
+            $item['status_text'] = self::getStatusText($item['status']);
+            
+            // 商户名称
+            $item['merchant_name'] = $userMap[$item['user_id']] ?? '';
+            
+            // 平台昵称(从uname获取)
+            $item['platform_nickname'] = '玩家' . $item['uname'];
+        }
+        
+        return [
+            'list' => $list,
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+    
+    /**
+     * 获取转账记录详情
+     */
+    public static function getTransferDetail($id, $appId)
+    {
+        $transfer = self::where('id', $id)
+            ->where('app_id', $appId)
+            ->find();
+            
+        if (!$transfer) {
+            return null;
+        }
+        
+        $transfer = $transfer->toArray();
+        
+        // 格式化数据
+        $transfer['create_time_text'] = date('Y-m-d H:i:s', $transfer['create_time']);
+        
+        // 格式化金额
+        $transfer['amount_yuan'] = round($transfer['amount'] / 100, 2);
+        $transfer['prev_amount_yuan'] = round($transfer['prev_amount'] / 100, 2);
+        $transfer['next_amount_yuan'] = round($transfer['next_amount'] / 100, 2);
+        
+        // 状态文本
+        $transfer['status_text'] = self::getStatusText($transfer['status']);
+        
+        // 获取用户信息
+        $user = Db::connect('merchant_admin')
+            ->table('merchant_user')
+            ->where('user_id', $transfer['user_id'])
+            ->field('user_id, nick_name')
+            ->find();
+        
+        $transfer['merchant_name'] = $user ? $user['nick_name'] : '';
+        $transfer['platform_nickname'] = '玩家' . $transfer['uname'];
+        
+        return $transfer;
+    }
+    
+    /**
+     * 获取转账统计信息
+     */
+    public static function getTransferStatistics($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_transfers',
+                'COUNT(DISTINCT uname) as total_players',
+                'SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_in_amount',
+                'SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END) as total_out_amount',
+                'SUM(amount) as net_amount',
+                'SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as success_transfers',
+                'SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as failed_transfers',
+                'SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as pending_transfers'
+            ])
+            ->find()
+            ->toArray();
+        
+        // 格式化金额
+        $statistics['total_in_amount_yuan'] = round($statistics['total_in_amount'] / 100, 2);
+        $statistics['total_out_amount_yuan'] = round($statistics['total_out_amount'] / 100, 2);
+        $statistics['net_amount_yuan'] = round($statistics['net_amount'] / 100, 2);
+        
+        // 计算成功率
+        if ($statistics['total_transfers'] > 0) {
+            $statistics['success_rate'] = round($statistics['success_transfers'] / $statistics['total_transfers'] * 100, 2);
+        } else {
+            $statistics['success_rate'] = 0;
+        }
+        
+        return $statistics;
+    }
+    
+    /**
+     * 获取状态文本
+     */
+    public static function getStatusText($status)
+    {
+        $statusMap = [
+            self::STATUS_FAILED => '失败',
+            self::STATUS_SUCCESS => '成功',
+            self::STATUS_PENDING => '待处理'
+        ];
+        
+        return $statusMap[$status] ?? '未知';
+    }
+}

+ 1 - 1
config/database.php

@@ -57,7 +57,7 @@ return [
             // 开启字段缓存
             'fields_cache'    => false,
         ],
-        'fortue_tiger' => [
+        'fortune_tiger' => [
             // 数据库类型
             'type'            => env('DB_TYPE', 'mysql'),
             // 服务器地址

+ 37 - 0
config/permission.php

@@ -114,5 +114,42 @@ return [
                 'list' => '权限列表',
             ]
         ],
+        
+        // 游戏记录管理模块
+        'GameRecord' => [
+            'module' => '游戏记录',
+            'actions' => [
+                'list' => '查看游戏记录列表',
+                'detail' => '查看游戏记录详情',
+                'statistics' => '查看游戏统计',
+                'getGames' => '获取游戏列表',
+                'getPlayMethods' => '获取玩法列表',
+                'export' => '导出游戏记录',
+            ]
+        ],
+        
+        // 游戏订单管理模块
+        'GameOrder' => [
+            'module' => '游戏订单',
+            'actions' => [
+                'list' => '查看订单列表',
+                'detail' => '查看订单详情',
+                'statistics' => '查看订单统计',
+                'getGames' => '获取游戏列表',
+                'getOrderReasons' => '获取订单原因列表',
+                'export' => '导出订单记录',
+            ]
+        ],
+        
+        // 转账记录管理模块
+        'TransferLog' => [
+            'module' => '转账记录',
+            'actions' => [
+                'list' => '查看转账记录列表',
+                'detail' => '查看转账记录详情',
+                'statistics' => '查看转账统计',
+                'export' => '导出转账记录',
+            ]
+        ],
     ]
 ];

+ 28 - 0
route/app.php

@@ -75,3 +75,31 @@ Route::group('behavior_log', function () {
     Route::get('get_behavior_types', 'BehaviorLog/getBehaviorTypes');
     Route::get('export', 'BehaviorLog/export');
 })->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);
+
+// 游戏记录相关路由
+Route::group('game_record', function () {
+    Route::get('list', 'GameRecord/list');
+    Route::get('detail', 'GameRecord/detail');
+    Route::get('statistics', 'GameRecord/statistics');
+    Route::get('get_games', 'GameRecord/getGames');
+    Route::get('get_play_methods', 'GameRecord/getPlayMethods');
+    Route::get('export', 'GameRecord/export');
+})->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);
+
+// 游戏订单相关路由
+Route::group('game_order', function () {
+    Route::get('list', 'GameOrder/list');
+    Route::get('detail', 'GameOrder/detail');
+    Route::get('statistics', 'GameOrder/statistics');
+    Route::get('get_games', 'GameOrder/getGames');
+    Route::get('get_order_reasons', 'GameOrder/getOrderReasons');
+    Route::get('export', 'GameOrder/export');
+})->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);
+
+// 转账记录相关路由
+Route::group('transfer_log', function () {
+    Route::get('list', 'TransferLog/list');
+    Route::get('detail', 'TransferLog/detail');
+    Route::get('statistics', 'TransferLog/statistics');
+    Route::get('export', 'TransferLog/export');
+})->middleware([\app\middleware\AuthMiddleware::class, \app\middleware\BehaviorLogMiddleware::class]);