From 3eaf37a6483aed16e0b2a3ce1ca84745e30f0e64 Mon Sep 17 00:00:00 2001 From: pllx Date: Thu, 30 Apr 2026 11:03:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BA=A7=E9=A9=BE=E4=B8=8E?= =?UTF-8?q?=E4=BC=9A=E5=91=98=E5=85=A5=E5=9C=BA=E9=87=8D=E5=A4=8D=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/ChatController.php | 9 ++- app/Services/RideService.php | 3 + tests/Feature/ChatControllerTest.php | 73 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/ChatController.php b/app/Http/Controllers/ChatController.php index 2e49a6e..828b052 100644 --- a/app/Http/Controllers/ChatController.php +++ b/app/Http/Controllers/ChatController.php @@ -197,7 +197,11 @@ class ChatController extends Controller // 统一走通用进场播报逻辑,管理员不再发送单独的特殊登录提示。 [$text, $color] = $this->broadcast->buildEntryBroadcast($user); - $vipPresencePayload = $this->broadcast->buildVipPresencePayload($user, 'join'); + $ridePresencePayload = $this->rideService->buildPresencePayload($user); + // 座驾优先级高于会员进场主题,避免同一用户进房时同时播放两套全屏特效。 + $vipPresencePayload = $ridePresencePayload + ? [] + : $this->broadcast->buildVipPresencePayload($user, 'join'); $generalWelcomeMsg = [ 'id' => $this->chatState->nextMessageId($id), @@ -232,14 +236,13 @@ class ChatController extends Controller broadcast(new \App\Events\EffectBroadcast($id, $vipPresencePayload['presence_effect'], $user->username))->toOthers(); } - $ridePresencePayload = $this->rideService->buildPresencePayload($user); if ($ridePresencePayload) { $rideWelcomeMsg = [ 'id' => $this->chatState->nextMessageId($id), 'room_id' => $id, 'from_user' => '座驾播报', 'to_user' => '大家', - 'content' => "{$ridePresencePayload['ride_icon']} {$ridePresencePayload['welcome_text']}", + 'content' => "{$ridePresencePayload['ride_icon']} {$ridePresencePayload['identity_text']} · {$ridePresencePayload['welcome_text']}", 'is_secret' => false, 'font_color' => '#0f766e', 'action' => 'ride_presence', diff --git a/app/Services/RideService.php b/app/Services/RideService.php index fc459af..5059c50 100644 --- a/app/Services/RideService.php +++ b/app/Services/RideService.php @@ -28,6 +28,7 @@ class RideService */ public function __construct( private readonly UserCurrencyService $currencyService, + private readonly ChatUserPresenceService $chatUserPresenceService, ) {} /** @@ -234,12 +235,14 @@ class RideService '{name}' => $user->username, '{ride}' => $item->name, ]); + $identitySummary = $this->chatUserPresenceService->buildIdentitySummary($user); return [ 'ride_key' => $rideKey, 'ride_name' => $item->name, 'ride_icon' => (string) ($item->icon ?? '🚘'), 'effect_title' => "{$user->username} 乘坐【{$item->name}】闪亮登场", + 'identity_text' => ChatContentSanitizer::htmlText($identitySummary['inline']), 'welcome_text' => ChatContentSanitizer::htmlText($rendered), ]; } diff --git a/tests/Feature/ChatControllerTest.php b/tests/Feature/ChatControllerTest.php index 9022719..4b4328c 100644 --- a/tests/Feature/ChatControllerTest.php +++ b/tests/Feature/ChatControllerTest.php @@ -1142,6 +1142,79 @@ class ChatControllerTest extends TestCase ], $response->viewData('initialRideEffectOptions')); } + /** + * 测试会员用户有座驾时优先播放座驾,并在座驾播报中展示完整身份摘要。 + */ + public function test_ride_presence_takes_priority_over_vip_presence_and_includes_identity_summary(): void + { + $room = Room::create(['room_name' => 'rvip']); + $vipLevel = VipLevel::factory()->create([ + 'name' => '至尊会员', + 'icon' => '👑', + 'join_effect' => 'lightning', + 'join_banner_style' => 'storm', + 'allow_custom_messages' => true, + ]); + $user = User::factory()->create([ + 'vip_level_id' => $vipLevel->id, + 'hy_time' => now()->addDays(30), + 'custom_join_message' => '{username} 带着风暴王座闪耀降临', + 'has_received_new_gift' => true, + ]); + $department = Department::create([ + 'name' => '战备部', + 'rank' => 90, + 'color' => '#0f766e', + 'sort_order' => 1, + ]); + $position = Position::create([ + 'department_id' => $department->id, + 'name' => '试飞官', + 'icon' => '🛡️', + 'rank' => 90, + 'level' => 90, + 'sort_order' => 1, + ]); + UserPosition::create([ + 'user_id' => $user->id, + 'position_id' => $position->id, + 'appointed_at' => now(), + 'is_active' => true, + ]); + $ride = Ride::query()->updateOrCreate(['slug' => 'ride_99a'], [ + 'name' => '99A测试座驾', + 'effect_key' => '99a', + 'description' => '测试座驾', + 'icon' => '🛡️', + 'price' => 28888, + 'duration_days' => 7, + 'sort_order' => 90, + 'is_active' => true, + 'welcome_message' => '【{name}】乘坐【{ride}】闪亮登场', + ]); + UserRidePurchase::create([ + 'user_id' => $user->id, + 'ride_id' => $ride->id, + 'status' => 'active', + 'price_paid' => 28888, + 'expires_at' => now()->addDays(3), + ]); + + $response = $this->actingAs($user)->get(route('chat.room', $room->id)); + + $response->assertOk(); + $history = collect($response->viewData('historyMessages')); + $rideMessage = $history->first(fn (array $message): bool => ($message['welcome_kind'] ?? '') === 'ride_presence'); + $vipPresenceMessage = $history->first(fn (array $message): bool => ($message['action'] ?? '') === 'vip_presence'); + + $this->assertNotNull($rideMessage); + $this->assertNull($vipPresenceMessage); + $this->assertStringContainsString('部门 战备部 · 职务 🛡️ 试飞官 · 会员 👑 至尊会员', $rideMessage['content']); + $this->assertStringContainsString($user->username, $rideMessage['content']); + $this->assertSame('99a', $response->viewData('initialRideEffect')); + $this->assertNull($response->viewData('initialPresenceTheme')); + } + /** * 测试过期座驾用户进房时不会触发座驾播报。 */