1.优化websocket中的jackpot.hit

2.优化/api/game/betMyOrders接口,新增中奖号码字段result_number
This commit is contained in:
2026-05-28 17:13:59 +08:00
parent c3ac33ec3d
commit 99df6b378a
7 changed files with 118 additions and 2 deletions

View File

@@ -96,6 +96,7 @@ class PlayRecord extends Backend
'channel.name as channel__name',
'game_record.period_no as gameRecord__period_no',
'game_record.status as gameRecord__status',
'game_record.result_number as gameRecord__result_number',
])
->order($order)
->paginate($limit);
@@ -120,6 +121,9 @@ class PlayRecord extends Backend
'status' => isset($row['gameRecord__status']) && is_numeric((string) $row['gameRecord__status'])
? (int) $row['gameRecord__status']
: null,
'result_number' => isset($row['gameRecord__result_number']) && $row['gameRecord__result_number'] !== '' && $row['gameRecord__result_number'] !== null
? (string) $row['gameRecord__result_number']
: null,
];
unset(
$row['user__username'],
@@ -127,6 +131,7 @@ class PlayRecord extends Backend
$row['channel__name'],
$row['gameRecord__period_no'],
$row['gameRecord__status'],
$row['gameRecord__result_number'],
);
$list[$idx] = $row;
}

View File

@@ -401,8 +401,40 @@ class Game extends MobileBase
'list_rows' => $pageSize,
]);
$periodIds = [];
foreach ($paginate->items() as $item) {
$periodIdValue = filter_var($item->period_id ?? null, FILTER_VALIDATE_INT);
if ($periodIdValue !== false && $periodIdValue > 0) {
$periodIds[] = $periodIdValue;
}
}
$periodIds = array_values(array_unique($periodIds));
$resultNumberByPeriodId = [];
if ($periodIds !== []) {
$periodRows = Db::name('game_record')
->whereIn('id', $periodIds)
->field(['id', 'result_number'])
->select()
->toArray();
foreach ($periodRows as $row) {
if (!is_array($row)) {
continue;
}
$pid = filter_var($row['id'] ?? null, FILTER_VALIDATE_INT);
if ($pid === false || $pid <= 0) {
continue;
}
$rn = filter_var($row['result_number'] ?? null, FILTER_VALIDATE_INT);
$resultNumberByPeriodId[$pid] = ($rn === false ? null : $rn);
}
}
$rows = [];
foreach ($paginate->items() as $item) {
$periodIdValue = filter_var($item->period_id ?? null, FILTER_VALIDATE_INT);
if ($periodIdValue === false) {
$periodIdValue = 0;
}
$rows[] = [
'order_no' => (string) $item->id,
'period_no' => $item->period_no,
@@ -410,7 +442,7 @@ class Game extends MobileBase
// 整笔压注金额(本笔总扣款)
'bet_amount' => $item->total_amount,
'total_amount' => $item->total_amount,
'result_number' => null,
'result_number' => $periodIdValue > 0 ? ($resultNumberByPeriodId[$periodIdValue] ?? null) : null,
'win_amount' => $item->win_amount,
'status' => (string) $item->status,
'create_time' => $item->create_time,

View File

@@ -106,6 +106,61 @@ final class GameWebSocketSubscriptionRegistry
return $finalTopics;
}
/**
* 增量订阅:将 topics 合并到现有订阅集合(不会移除旧 topic
*
* 兼容部分客户端“多次 subscribe 但只携带增量 topic”的行为避免后续误覆盖导致 bet.win/jackpot.hit 丢订阅。
*
* @param list<string> $topics
* @return list<string> 合并后的订阅列表(去重排序)
*/
public static function mergeSubscriptions(int $connectionId, array $topics): array
{
if ($connectionId <= 0 || !isset(self::$connectionMeta[$connectionId])) {
return [];
}
$clean = [];
foreach ($topics as $t) {
if (!is_string($t)) {
continue;
}
$v = trim($t);
if ($v === '' || strlen($v) > 64) {
continue;
}
$clean[$v] = true;
}
if ($clean === []) {
return self::$connectionMeta[$connectionId]['topics'];
}
$existing = self::$connectionMeta[$connectionId]['topics'];
$mergedMap = [];
foreach ($existing as $t) {
$mergedMap[$t] = true;
}
foreach (array_keys($clean) as $t) {
$mergedMap[$t] = true;
}
$finalTopics = array_keys($mergedMap);
sort($finalTopics);
// 只需要把新增 topic 写入 topicIndex旧 topic 已存在索引)
$existingMap = [];
foreach ($existing as $t) {
$existingMap[$t] = true;
}
foreach ($finalTopics as $topic) {
if (!isset($existingMap[$topic])) {
self::$topicIndex[$topic][$connectionId] = true;
}
}
self::$connectionMeta[$connectionId]['topics'] = $finalTopics;
return $finalTopics;
}
/**
* 获取订阅了指定 topic 的所有 connection_id。
*

View File

@@ -170,10 +170,24 @@ class GameWebSocketServer
if ($action === 'subscribe') {
$rawTopics = $decoded['topics'] ?? [];
$rawList = is_array($rawTopics) ? $rawTopics : [];
$finalTopics = GameWebSocketSubscriptionRegistry::replaceSubscriptions($connection->id, $rawList);
$replace = false;
if (!empty($decoded['replace'])) {
$replace = true;
}
if (isset($decoded['mode']) && is_string($decoded['mode']) && trim($decoded['mode']) === 'replace') {
$replace = true;
}
$before = GameWebSocketSubscriptionRegistry::meta($connection->id);
$beforeTopics = is_array($before) ? ($before['topics'] ?? []) : [];
$finalTopics = $replace
? GameWebSocketSubscriptionRegistry::replaceSubscriptions($connection->id, $rawList)
: GameWebSocketSubscriptionRegistry::mergeSubscriptions($connection->id, $rawList);
Log::channel('ws')->info('subscribe', [
'connection_id' => $connection->id,
'user_id' => GameWebSocketSubscriptionRegistry::userIdOf($connection->id),
'replace' => $replace,
'before_topics' => $beforeTopics,
'topics' => $finalTopics,
'requested_count' => is_array($rawTopics) ? count($rawTopics) : 0,
]);

View File

@@ -34,6 +34,7 @@ export default {
update_time: 'Updated',
gameRecord_period_no: 'Round (relation)',
gameRecord_status: 'Round status',
result_number: 'Result number',
'gameRecord_status 0': 'Open for betting',
'gameRecord_status 1': 'Closed',
'gameRecord_status 2': 'Settling tickets',

View File

@@ -34,6 +34,7 @@ export default {
update_time: '更新时间',
gameRecord_period_no: '对局期号',
gameRecord_status: '期状态',
result_number: '中奖号码',
'gameRecord_status 0': '下注开放',
'gameRecord_status 1': '已封盘',
'gameRecord_status 2': '算票中',

View File

@@ -147,6 +147,14 @@ const baTable = new baTableClass(
'5': t('game.playRecord.gameRecord_status 5'),
},
},
{
label: t('game.playRecord.result_number'),
prop: 'gameRecord.result_number',
align: 'center',
width: 110,
operator: 'eq',
showOverflowTooltip: true,
},
{ label: t('game.playRecord.user_id'), prop: 'user_id', align: 'center', show: false, width: 90, operator: 'RANGE' },
{
label: t('game.playRecord.user_username'),