GameOrderModel.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. declare (strict_types = 1);
  3. namespace app\model;
  4. use think\Model;
  5. use think\facade\Db;
  6. /**
  7. * 游戏订单模型
  8. */
  9. class GameOrderModel extends Model
  10. {
  11. protected $name = 'game_bet_order';
  12. protected $connection = 'fortune_tiger';
  13. protected $pk = 'id';
  14. // 状态常量
  15. const STATUS_PENDING = 0; // 待处理
  16. const STATUS_SUCCESS = 1; // 成功
  17. const STATUS_FAILED = 2; // 失败
  18. const STATUS_CANCELLED = 3; // 已取消
  19. // 动作类型常量
  20. const ACTION_TYPE_BET = 1; // 下注
  21. const ACTION_TYPE_SETTLE = 2; // 结算
  22. const ACTION_TYPE_CANCEL = 3; // 取消
  23. /**
  24. * 获取订单记录列表
  25. */
  26. public static function getOrderRecords($appId, $page = 1, $limit = 20, $filters = [])
  27. {
  28. $where = [
  29. ['app_id', '=', $appId]
  30. ];
  31. // 时间筛选
  32. if (!empty($filters['start_time'])) {
  33. $startTime = strtotime($filters['start_time'] . ' 00:00:00');
  34. $where[] = ['create_time', '>=', $startTime];
  35. }
  36. if (!empty($filters['end_time'])) {
  37. $endTime = strtotime($filters['end_time'] . ' 23:59:59');
  38. $where[] = ['create_time', '<=', $endTime];
  39. }
  40. // 游戏筛选
  41. if (!empty($filters['game_id'])) {
  42. $where[] = ['game_id', '=', $filters['game_id']];
  43. }
  44. // 订单原因筛选
  45. if (!empty($filters['order_reason'])) {
  46. $where[] = ['action_type', '=', $filters['order_reason']];
  47. }
  48. // 平台ID筛选
  49. if (!empty($filters['platform_id'])) {
  50. $where[] = ['uname', '=', $filters['platform_id']];
  51. }
  52. // 订单状态筛选
  53. if ($filters['order_status'] !== '') {
  54. $where[] = ['status', '=', $filters['order_status']];
  55. }
  56. // 订单编号筛选(支持母单号、子单号、牌局编号)
  57. if (!empty($filters['order_number'])) {
  58. $where[] = ['third_order_id', 'like', '%' . $filters['order_number'] . '%'];
  59. }
  60. // 母单号筛选
  61. if (!empty($filters['parent_order'])) {
  62. $where[] = ['third_gid', 'like', '%' . $filters['parent_order'] . '%'];
  63. }
  64. // 牌局编号筛选
  65. if (!empty($filters['round_number'])) {
  66. $where[] = ['third_round_id', 'like', '%' . $filters['round_number'] . '%'];
  67. }
  68. $query = self::where($where);
  69. // 统计总数
  70. $total = $query->count();
  71. // 获取列表数据
  72. $list = $query->field([
  73. 'id', 'user_id', 'uname', 'nickname', 'third_gid', 'third_order_id',
  74. 'third_round_id', 'parent_id', 'game_id', 'game_type', 'status',
  75. 'message', 'amount', 'bet', 'prev_amount', 'next_amount',
  76. 'action_type', 'ip', 'create_time', 'total_win_amount', 'total_amount'
  77. ])
  78. ->order('create_time', 'desc')
  79. ->page($page, $limit)
  80. ->select()
  81. ->toArray();
  82. // 格式化数据
  83. foreach ($list as &$item) {
  84. // 格式化金额(分转元)
  85. $item['amount'] = bcdiv((string)$item['amount'], '100', 2);
  86. $item['bet'] = bcdiv((string)$item['bet'], '100', 2);
  87. $item['prev_amount'] = bcdiv((string)$item['prev_amount'], '10000', 2);
  88. $item['next_amount'] = bcdiv((string)$item['next_amount'], '10000', 2);
  89. $item['total_win_amount'] = bcdiv((string)$item['total_win_amount'], '10000', 2);
  90. $item['total_amount'] = bcdiv((string)$item['total_amount'], '10000', 2);
  91. // 状态文本
  92. $item['status_text'] = self::getStatusText($item['status']);
  93. // 动作类型文本
  94. $item['action_type_text'] = self::getActionTypeText($item['action_type']);
  95. // 游戏名称
  96. $item['game_name'] = self::getGameName($item['game_id']);
  97. }
  98. return [
  99. 'list' => $list,
  100. 'total' => $total,
  101. 'page' => $page,
  102. 'limit' => $limit
  103. ];
  104. }
  105. /**
  106. * 获取订单详情
  107. */
  108. public static function getOrderDetail($id, $appId)
  109. {
  110. $order = self::where('id', $id)
  111. ->where('app_id', $appId)
  112. ->find();
  113. if (!$order) {
  114. return null;
  115. }
  116. $order = $order->toArray();
  117. // 格式化数据
  118. $order['create_time_text'] = date('Y-m-d H:i:s', $order['create_time']);
  119. // 格式化金额
  120. $order['amount_yuan'] = bcdiv((string)$order['amount'], '100', 2);
  121. $order['bet_yuan'] = bcdiv((string)$order['bet'], '100', 2);
  122. $order['prev_amount_yuan'] = bcdiv((string)$order['prev_amount'], '10000', 2);
  123. $order['next_amount_yuan'] = bcdiv((string)$order['next_amount'], '10000', 2);
  124. $order['total_win_amount_yuan'] = bcdiv((string)$order['total_win_amount'], '10000', 2);
  125. $order['total_amount_yuan'] = bcdiv((string)$order['total_amount'], '10000', 2);
  126. // 状态文本
  127. $order['status_text'] = self::getStatusText($order['status']);
  128. // 动作类型文本
  129. $order['action_type_text'] = self::getActionTypeText($order['action_type']);
  130. // 游戏名称
  131. $order['game_name'] = self::getGameName($order['game_id']);
  132. return $order;
  133. }
  134. /**
  135. * 获取订单统计信息
  136. */
  137. public static function getOrderStatistics($appId, $filters = [])
  138. {
  139. $where = [
  140. ['app_id', '=', $appId]
  141. ];
  142. // 时间筛选
  143. if (!empty($filters['start_time'])) {
  144. $startTime = strtotime($filters['start_time'] . ' 00:00:00');
  145. $where[] = ['create_time', '>=', $startTime];
  146. }
  147. if (!empty($filters['end_time'])) {
  148. $endTime = strtotime($filters['end_time'] . ' 23:59:59');
  149. $where[] = ['create_time', '<=', $endTime];
  150. }
  151. $statistics = self::where($where)
  152. ->field([
  153. 'COUNT(*) as total_orders',
  154. 'COUNT(DISTINCT uname) as total_players',
  155. 'SUM(bet) as total_bet_amount',
  156. 'SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_win_amount',
  157. 'SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END) as total_loss_amount',
  158. 'SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as success_orders',
  159. 'SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as failed_orders',
  160. 'SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) as cancelled_orders'
  161. ])
  162. ->find()
  163. ->toArray();
  164. // 格式化金额
  165. $statistics['total_bet_amount_yuan'] = bcdiv((string)$statistics['total_bet_amount'], '100', 2);
  166. $statistics['total_win_amount_yuan'] = bcdiv((string)$statistics['total_win_amount'], '100', 2);
  167. $statistics['total_loss_amount_yuan'] = bcdiv((string)$statistics['total_loss_amount'], '100', 2);
  168. $net_amount = bcsub((string)$statistics['total_loss_amount'], (string)$statistics['total_win_amount']);
  169. $statistics['net_amount_yuan'] = bcdiv($net_amount, '100', 2);
  170. // 计算成功率
  171. if ($statistics['total_orders'] > 0) {
  172. $rate = bcdiv((string)$statistics['success_orders'], (string)$statistics['total_orders'], 4);
  173. $statistics['success_rate'] = bcmul($rate, '100', 2);
  174. } else {
  175. $statistics['success_rate'] = '0.00';
  176. }
  177. return $statistics;
  178. }
  179. /**
  180. * 获取所有游戏ID列表
  181. */
  182. public static function getAllGameIds($appId)
  183. {
  184. return self::where('app_id', $appId)
  185. ->distinct(true)
  186. ->column('game_id');
  187. }
  188. /**
  189. * 获取状态文本
  190. */
  191. public static function getStatusText($status)
  192. {
  193. $statusMap = [
  194. self::STATUS_PENDING => '待处理',
  195. self::STATUS_SUCCESS => '成功',
  196. self::STATUS_FAILED => '失败',
  197. self::STATUS_CANCELLED => '已取消'
  198. ];
  199. return $statusMap[$status] ?? '未知';
  200. }
  201. /**
  202. * 获取动作类型文本
  203. */
  204. public static function getActionTypeText($actionType)
  205. {
  206. $actionTypeMap = [
  207. self::ACTION_TYPE_BET => '下注',
  208. self::ACTION_TYPE_SETTLE => '结算',
  209. self::ACTION_TYPE_CANCEL => '取消'
  210. ];
  211. return $actionTypeMap[$actionType] ?? '其他';
  212. }
  213. /**
  214. * 获取游戏名称
  215. */
  216. private static function getGameName($gameId)
  217. {
  218. // 这里可以根据实际情况配置游戏ID对应的名称
  219. $gameNames = [
  220. 'tiger' => '老虎机',
  221. 'fortune_tiger' => '财富老虎',
  222. 'dragon_tiger' => '龙虎斗',
  223. 'baccarat' => '百家乐',
  224. // 可以继续添加其他游戏
  225. ];
  226. return $gameNames[$gameId] ?? $gameId;
  227. }
  228. }