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