增加每日游戏三杰榜
This commit is contained in:
@@ -26,6 +26,7 @@ use App\Models\User;
|
|||||||
use App\Services\AppointmentService;
|
use App\Services\AppointmentService;
|
||||||
use App\Services\ChatStateService;
|
use App\Services\ChatStateService;
|
||||||
use App\Services\ChatUserPresenceService;
|
use App\Services\ChatUserPresenceService;
|
||||||
|
use App\Services\DailyGameProfitLeaderboardService;
|
||||||
use App\Services\MessageFilterService;
|
use App\Services\MessageFilterService;
|
||||||
use App\Services\PositionPermissionService;
|
use App\Services\PositionPermissionService;
|
||||||
use App\Services\RideService;
|
use App\Services\RideService;
|
||||||
@@ -63,6 +64,7 @@ class ChatController extends Controller
|
|||||||
private readonly VipService $vipService,
|
private readonly VipService $vipService,
|
||||||
private readonly \App\Services\ShopService $shopService,
|
private readonly \App\Services\ShopService $shopService,
|
||||||
private readonly UserCurrencyService $currencyService,
|
private readonly UserCurrencyService $currencyService,
|
||||||
|
private readonly DailyGameProfitLeaderboardService $dailyGameProfitLeaderboardService,
|
||||||
private readonly AppointmentService $appointmentService,
|
private readonly AppointmentService $appointmentService,
|
||||||
private readonly RoomBroadcastService $broadcast,
|
private readonly RoomBroadcastService $broadcast,
|
||||||
private readonly PositionPermissionService $positionPermissionService,
|
private readonly PositionPermissionService $positionPermissionService,
|
||||||
@@ -372,6 +374,7 @@ class ChatController extends Controller
|
|||||||
'pendingDivorce' => $pendingDivorceData,
|
'pendingDivorce' => $pendingDivorceData,
|
||||||
'roomPermissionMap' => $roomPermissionMap,
|
'roomPermissionMap' => $roomPermissionMap,
|
||||||
'hasRoomManagementPermission' => in_array(true, $roomPermissionMap, true),
|
'hasRoomManagementPermission' => in_array(true, $roomPermissionMap, true),
|
||||||
|
'dailyGameProfitLeaders' => $this->dailyGameProfitLeaderboardService->topThree(),
|
||||||
'dailyStatusCatalog' => ChatDailyStatusCatalog::groupedOptions(),
|
'dailyStatusCatalog' => ChatDailyStatusCatalog::groupedOptions(),
|
||||||
'activeDailyStatus' => $this->chatUserPresenceService->currentDailyStatus($user),
|
'activeDailyStatus' => $this->chatUserPresenceService->currentDailyStatus($user),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件功能:每日游戏净盈利前三榜读服务
|
||||||
|
*
|
||||||
|
* 聚合百家乐与赛马当天金币流水,给聊天室顶部悬浮榜提供轻量数据。
|
||||||
|
*
|
||||||
|
* @author ChatRoom Laravel
|
||||||
|
*
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Enums\CurrencySource;
|
||||||
|
use App\Models\UserCurrencyLog;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能:查询百家乐与赛马每日净盈利前三用户。
|
||||||
|
*/
|
||||||
|
class DailyGameProfitLeaderboardService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 每日榜单固定称号。
|
||||||
|
*/
|
||||||
|
private const TITLES = [
|
||||||
|
1 => '金库爆破王',
|
||||||
|
2 => '马桌双修财神',
|
||||||
|
3 => '金币收割机',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参与净盈利统计的游戏流水来源。
|
||||||
|
*/
|
||||||
|
private const GAME_PROFIT_SOURCES = [
|
||||||
|
CurrencySource::BACCARAT_BET,
|
||||||
|
CurrencySource::BACCARAT_WIN,
|
||||||
|
CurrencySource::HORSE_BET,
|
||||||
|
CurrencySource::HORSE_WIN,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期的游戏净盈利前三榜。
|
||||||
|
*
|
||||||
|
* @return Collection<int, object{rank:int,title:string,user_id:int,username:string,headface_url:string,net_profit:int}>
|
||||||
|
*/
|
||||||
|
public function topThree(?string $date = null): Collection
|
||||||
|
{
|
||||||
|
$statsDate = CarbonImmutable::parse($date ?? today()->toDateString())->startOfDay();
|
||||||
|
$cacheKey = 'daily_game_profit_leaderboard:v2:'.$statsDate->toDateString();
|
||||||
|
|
||||||
|
return Cache::remember($cacheKey, 300, function () use ($statsDate) {
|
||||||
|
$rangeStart = $statsDate;
|
||||||
|
$rangeEnd = $statsDate->addDay();
|
||||||
|
|
||||||
|
return UserCurrencyLog::query()
|
||||||
|
->join('users', 'users.id', '=', 'user_currency_logs.user_id')
|
||||||
|
->where('user_currency_logs.currency', 'gold')
|
||||||
|
->whereIn('user_currency_logs.source', array_map(
|
||||||
|
fn (CurrencySource $source): string => $source->value,
|
||||||
|
self::GAME_PROFIT_SOURCES
|
||||||
|
))
|
||||||
|
->where('user_currency_logs.created_at', '>=', $rangeStart)
|
||||||
|
->where('user_currency_logs.created_at', '<', $rangeEnd)
|
||||||
|
->where('users.username', '!=', 'AI小班长')
|
||||||
|
->groupBy('user_currency_logs.user_id', 'users.username', 'users.usersf')
|
||||||
|
->havingRaw('SUM(user_currency_logs.amount) > 0')
|
||||||
|
->orderByRaw('SUM(user_currency_logs.amount) DESC')
|
||||||
|
->orderBy('user_currency_logs.user_id')
|
||||||
|
->limit(3)
|
||||||
|
->selectRaw('user_currency_logs.user_id, users.username, users.usersf, SUM(user_currency_logs.amount) as net_profit')
|
||||||
|
->get()
|
||||||
|
->values()
|
||||||
|
->map(function (object $row, int $index): object {
|
||||||
|
$rank = $index + 1;
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
'rank' => $rank,
|
||||||
|
'title' => self::TITLES[$rank],
|
||||||
|
'user_id' => (int) $row->user_id,
|
||||||
|
'username' => (string) $row->username,
|
||||||
|
'headface_url' => $this->resolveHeadfaceUrl((string) ($row->usersf ?: '1.gif')),
|
||||||
|
'net_profit' => (int) $row->net_profit,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析榜单头像地址。
|
||||||
|
*/
|
||||||
|
private function resolveHeadfaceUrl(string $headface): string
|
||||||
|
{
|
||||||
|
if (str_starts_with($headface, 'storage/')) {
|
||||||
|
return '/'.$headface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '/images/headface/'.strtolower($headface);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -170,6 +170,7 @@ a:hover {
|
|||||||
.room-title-bar {
|
.room-title-bar {
|
||||||
background: var(--bg-header);
|
background: var(--bg-header);
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -178,6 +179,10 @@ a:hover {
|
|||||||
border-bottom: 1px solid var(--border-blue);
|
border-bottom: 1px solid var(--border-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.room-title-main {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.room-title-bar .room-name {
|
.room-title-bar .room-name {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -188,6 +193,145 @@ a:hover {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-board {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 34px;
|
||||||
|
width: 132px;
|
||||||
|
color: #fff7ed;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.28;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-board-title {
|
||||||
|
color: #fde68a;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatars {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-wrap {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 999px;
|
||||||
|
object-fit: cover;
|
||||||
|
background: rgba(255, 255, 255, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-1 {
|
||||||
|
background: linear-gradient(135deg, #fde047, #f59e0b 48%, #fff7ad);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-1::before {
|
||||||
|
content: "1";
|
||||||
|
position: absolute;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #f59e0b;
|
||||||
|
color: #fff7ed;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 0 0 1px rgba(255, 247, 237, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-2 {
|
||||||
|
background: linear-gradient(135deg, #f8fafc, #94a3b8 48%, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-2::before {
|
||||||
|
content: "2";
|
||||||
|
position: absolute;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #64748b;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-3 {
|
||||||
|
background: linear-gradient(135deg, #fed7aa, #c2410c 48%, #ffedd5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-3::before {
|
||||||
|
content: "3";
|
||||||
|
position: absolute;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #c2410c;
|
||||||
|
color: #fff7ed;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 0 0 1px rgba(255, 247, 237, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-wrap::after {
|
||||||
|
content: attr(data-username);
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: -24px;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
max-width: 110px;
|
||||||
|
padding: 3px 7px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(15, 23, 42, 0.88);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.2;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.12s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-wrap:hover::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-empty {
|
||||||
|
color: #dbeafe;
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.82;
|
||||||
|
}
|
||||||
|
|
||||||
/* 公告/祝福语滚动条(复刻原版 marquee) */
|
/* 公告/祝福语滚动条(复刻原版 marquee) */
|
||||||
.room-announcement-bar {
|
.room-announcement-bar {
|
||||||
background: linear-gradient(to right, #a8d8a8, #c8f0c8, #a8d8a8);
|
background: linear-gradient(to right, #a8d8a8, #c8f0c8, #a8d8a8);
|
||||||
@@ -956,6 +1100,48 @@ a:hover {
|
|||||||
overflow-y: auto !important;
|
overflow-y: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-board {
|
||||||
|
top: 5px;
|
||||||
|
right: 6px;
|
||||||
|
width: 102px;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-board-title {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatars {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-wrap {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-rank-1::before,
|
||||||
|
.daily-game-profit-avatar-rank-2::before,
|
||||||
|
.daily-game-profit-avatar-rank-3::before {
|
||||||
|
width: 11px;
|
||||||
|
height: 11px;
|
||||||
|
font-size: 8px;
|
||||||
|
line-height: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daily-game-profit-avatar-wrap::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── 手机端隐藏房间介绍 ── */
|
/* ── 手机端隐藏房间介绍 ── */
|
||||||
.room-desc {
|
.room-desc {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|||||||
@@ -7,9 +7,28 @@
|
|||||||
|
|
||||||
{{-- 顶部标题栏(第一行:房间名称 + 介绍) --}}
|
{{-- 顶部标题栏(第一行:房间名称 + 介绍) --}}
|
||||||
<div class="room-title-bar">
|
<div class="room-title-bar">
|
||||||
<div class="room-name">●{{ $room->name }}●<span style="font-size:12px; font-weight:normal;">在线<span
|
<div class="room-title-main">
|
||||||
id="online-count">0</span>人</span></div>
|
<div class="room-name">●{{ $room->name }}●<span style="font-size:12px; font-weight:normal;">在线<span
|
||||||
<div class="room-desc" id="room-title-display">{{ $room->description ?? '欢迎光临本聊天室!畅所欲言,文明聊天。' }}
|
id="online-count">0</span>人</span></div>
|
||||||
|
<div class="room-desc" id="room-title-display">{{ $room->description ?? '欢迎光临本聊天室!畅所欲言,文明聊天。' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="daily-game-profit-board" aria-label="今日游戏三杰">
|
||||||
|
<div class="daily-game-profit-board-title">今日游戏三杰</div>
|
||||||
|
@if (($dailyGameProfitLeaders ?? collect())->isNotEmpty())
|
||||||
|
<div class="daily-game-profit-avatars">
|
||||||
|
@foreach ($dailyGameProfitLeaders as $leader)
|
||||||
|
<span class="daily-game-profit-avatar-wrap daily-game-profit-avatar-rank-{{ $leader->rank }}"
|
||||||
|
data-username="{{ $leader->username }}">
|
||||||
|
<img class="daily-game-profit-avatar" src="{{ $leader->headface_url }}" alt="{{ $leader->username }}"
|
||||||
|
onerror="this.src='/images/headface/1.gif'">
|
||||||
|
</span>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="daily-game-profit-empty">今日财神位待开张</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Enums\CurrencySource;
|
||||||
use App\Events\MessageSent;
|
use App\Events\MessageSent;
|
||||||
use App\Models\Department;
|
use App\Models\Department;
|
||||||
use App\Models\Gift;
|
use App\Models\Gift;
|
||||||
@@ -16,6 +17,7 @@ use App\Models\Ride;
|
|||||||
use App\Models\Room;
|
use App\Models\Room;
|
||||||
use App\Models\Sysparam;
|
use App\Models\Sysparam;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\UserCurrencyLog;
|
||||||
use App\Models\UserPosition;
|
use App\Models\UserPosition;
|
||||||
use App\Models\UserRidePurchase;
|
use App\Models\UserRidePurchase;
|
||||||
use App\Models\VipLevel;
|
use App\Models\VipLevel;
|
||||||
@@ -67,6 +69,57 @@ class ChatControllerTest extends TestCase
|
|||||||
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试聊天室顶部会展示百家乐与赛马今日净盈利前三。
|
||||||
|
*/
|
||||||
|
public function test_room_header_displays_daily_game_profit_top_three(): void
|
||||||
|
{
|
||||||
|
Cache::flush();
|
||||||
|
Sysparam::updateOrCreate(['alias' => 'superlevel'], ['body' => '100']);
|
||||||
|
|
||||||
|
$room = Room::create(['room_name' => 'profitroom']);
|
||||||
|
$viewer = User::factory()->create(['username' => '围观群众', 'user_level' => 1]);
|
||||||
|
$first = User::factory()->create(['username' => '第一赢家', 'user_level' => 1]);
|
||||||
|
$second = User::factory()->create(['username' => '第二赢家', 'user_level' => 1]);
|
||||||
|
$third = User::factory()->create(['username' => '第三赢家', 'user_level' => 1]);
|
||||||
|
$yesterdayWinner = User::factory()->create(['username' => '昨日财神', 'user_level' => 1]);
|
||||||
|
$breakEvenUser = User::factory()->create(['username' => '白忙选手', 'user_level' => 1]);
|
||||||
|
$admin = User::factory()->create(['username' => '超级管理员', 'user_level' => 100]);
|
||||||
|
$bot = User::factory()->create(['username' => 'AI小班长', 'user_level' => 1]);
|
||||||
|
|
||||||
|
$this->recordGameGoldLog($first, CurrencySource::BACCARAT_WIN, 10000);
|
||||||
|
$this->recordGameGoldLog($first, CurrencySource::BACCARAT_BET, -2500);
|
||||||
|
$this->recordGameGoldLog($second, CurrencySource::HORSE_WIN, 6000);
|
||||||
|
$this->recordGameGoldLog($second, CurrencySource::HORSE_BET, -1000);
|
||||||
|
$this->recordGameGoldLog($third, CurrencySource::BACCARAT_WIN, 3000);
|
||||||
|
$this->recordGameGoldLog($yesterdayWinner, CurrencySource::HORSE_WIN, 50000, now()->subDay());
|
||||||
|
$this->recordGameGoldLog($breakEvenUser, CurrencySource::BACCARAT_WIN, 1000);
|
||||||
|
$this->recordGameGoldLog($breakEvenUser, CurrencySource::BACCARAT_BET, -1000);
|
||||||
|
$this->recordGameGoldLog($admin, CurrencySource::BACCARAT_WIN, 999999);
|
||||||
|
$this->recordGameGoldLog($bot, CurrencySource::HORSE_WIN, 888888);
|
||||||
|
|
||||||
|
$response = $this->actingAs($viewer)->get(route('chat.room', $room->id));
|
||||||
|
|
||||||
|
$leaders = $response->viewData('dailyGameProfitLeaders');
|
||||||
|
|
||||||
|
$this->assertSame(['超级管理员', '第一赢家', '第二赢家'], $leaders->pluck('username')->all());
|
||||||
|
$this->assertSame([999999, 7500, 5000], $leaders->pluck('net_profit')->all());
|
||||||
|
$this->assertStringStartsWith('/images/headface/', $leaders->first()->headface_url);
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertSee('今日游戏三杰');
|
||||||
|
$response->assertSee('class="daily-game-profit-avatar"', false);
|
||||||
|
$response->assertSee('data-username="超级管理员"', false);
|
||||||
|
$response->assertSee('data-username="第一赢家"', false);
|
||||||
|
$response->assertSee('data-username="第二赢家"', false);
|
||||||
|
$response->assertDontSee('金库爆破王');
|
||||||
|
$response->assertDontSee('马桌双修财神');
|
||||||
|
$response->assertDontSee('金币收割机');
|
||||||
|
$response->assertDontSee('+999,999');
|
||||||
|
$response->assertDontSee('+7,500');
|
||||||
|
$response->assertDontSee('+5,000');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试关闭房间会拒绝普通用户直接进入。
|
* 测试关闭房间会拒绝普通用户直接进入。
|
||||||
*/
|
*/
|
||||||
@@ -1499,6 +1552,23 @@ class ChatControllerTest extends TestCase
|
|||||||
$response->assertStatus(403);
|
$response->assertStatus(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录一条游戏金币流水,用于构造每日游戏净盈利榜测试数据。
|
||||||
|
*/
|
||||||
|
private function recordGameGoldLog(User $user, CurrencySource $source, int $amount, \DateTimeInterface|string|null $createdAt = null): void
|
||||||
|
{
|
||||||
|
UserCurrencyLog::forceCreate([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'username' => $user->username,
|
||||||
|
'currency' => 'gold',
|
||||||
|
'amount' => $amount,
|
||||||
|
'balance_after' => max(0, 100000 + $amount),
|
||||||
|
'source' => $source->value,
|
||||||
|
'remark' => '每日游戏净盈利榜测试',
|
||||||
|
'created_at' => $createdAt ?? now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建带指定聊天室权限的在职职务用户。
|
* 创建带指定聊天室权限的在职职务用户。
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user