From df29da7440bd38c68dec903303f6148f130864c4 Mon Sep 17 00:00:00 2001 From: lkddi Date: Tue, 14 Apr 2026 21:53:36 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=A0=E9=80=81=E9=87=91=E5=B8=81=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E7=A7=81=E8=81=8A=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/ChatController.php | 10 ++-- tests/Feature/ChatControllerTest.php | 67 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/ChatController.php b/app/Http/Controllers/ChatController.php index 5e011b0..6d93e3e 100644 --- a/app/Http/Controllers/ChatController.php +++ b/app/Http/Controllers/ChatController.php @@ -1244,7 +1244,7 @@ class ChatController extends Controller * 用户间赠送金币(任何登录用户均可调用) * * 从自己的余额中扣除指定金额,转入对方账户, - * 并在房间内通过「系统传音」广播一条赠送提示。 + * 并以私聊消息的方式仅通知赠送双方。 */ public function giftGold(Request $request): JsonResponse { @@ -1287,20 +1287,20 @@ class ChatController extends Controller $sender->decrement('jjb', $amount); $receiver->increment('jjb', $amount); - // 广播一条消息:发送者/接收者路由到 say2(下方包厢),其他人路由到 say1(公屏) - // 原理:前端 isRelatedToMe = isMe || to_user===me → say2;否则 → say1 + // 写入真正的私聊消息,避免其他旁观用户在公屏看到赠金币通知。 $giftMsg = [ 'id' => $this->chatState->nextMessageId($roomId), 'room_id' => $roomId, 'from_user' => $sender->username, 'to_user' => $toName, - 'content' => "悄悄赠送给你 {$amount} 金币!💝", - 'is_secret' => false, + 'content' => "赠送了你 {$amount} 金币!💝", + 'is_secret' => true, 'font_color' => '#b45309', 'action' => '', 'sent_at' => now()->toDateTimeString(), ]; + // 推入 Redis + WebSocket + 异步落库,保持与普通私聊一致的展示与历史记录行为。 $this->chatState->pushMessage($roomId, $giftMsg); broadcast(new MessageSent($roomId, $giftMsg)); SaveMessageJob::dispatch($giftMsg); diff --git a/tests/Feature/ChatControllerTest.php b/tests/Feature/ChatControllerTest.php index 94b3c15..79e700a 100644 --- a/tests/Feature/ChatControllerTest.php +++ b/tests/Feature/ChatControllerTest.php @@ -274,6 +274,73 @@ class ChatControllerTest extends TestCase $this->assertEquals(0, Redis::hexists("room:{$room->id}:users", $user->username)); } + /** + * 测试双击名片赠金币会写入私聊消息,且只有赠送双方能看到历史记录。 + */ + public function test_gift_gold_creates_secret_message_visible_only_to_participants(): void + { + $room = Room::create(['room_name' => 'gift-gold']); + $sender = User::factory()->create(['jjb' => 500]); + $receiver = User::factory()->create(['jjb' => 100]); + $outsider = User::factory()->create(); + + $response = $this->actingAs($sender)->postJson(route('gift.gold'), [ + 'to_user' => $receiver->username, + 'room_id' => $room->id, + 'amount' => 88, + ]); + + $response->assertOk(); + $response->assertJsonFragment([ + 'status' => 'success', + 'message' => "赠送成功!已向 {$receiver->username} 赠送 88 金币。", + ]); + + // 余额应同步完成转移,确保消息不是“通知成功但金额未变”。 + $this->assertSame(412, $sender->fresh()->jjb); + $this->assertSame(188, $receiver->fresh()->jjb); + + $messages = Redis::lrange("room:{$room->id}:messages", 0, -1); + $giftMessage = collect($messages) + ->map(fn (string $item) => json_decode($item, true)) + ->first(fn (array $item) => ($item['from_user'] ?? null) === $sender->username + && ($item['to_user'] ?? null) === $receiver->username + && ($item['content'] ?? null) === '赠送了你 88 金币!💝'); + + $this->assertNotNull($giftMessage); + $this->assertTrue((bool) ($giftMessage['is_secret'] ?? false)); + + // 赠送方查看房间历史时,应保留这条私聊通知。 + $senderHistory = $this->actingAs($sender) + ->get(route('chat.room', $room->id)) + ->viewData('historyMessages'); + $this->assertTrue(collect($senderHistory)->contains( + fn (array $item) => ($item['from_user'] ?? null) === $sender->username + && ($item['to_user'] ?? null) === $receiver->username + && ($item['content'] ?? null) === '赠送了你 88 金币!💝' + )); + + // 接收方查看房间历史时,也应看到这条私聊通知。 + $receiverHistory = $this->actingAs($receiver) + ->get(route('chat.room', $room->id)) + ->viewData('historyMessages'); + $this->assertTrue(collect($receiverHistory)->contains( + fn (array $item) => ($item['from_user'] ?? null) === $sender->username + && ($item['to_user'] ?? null) === $receiver->username + && ($item['content'] ?? null) === '赠送了你 88 金币!💝' + )); + + // 旁观者不应在历史消息里看到别人的赠金币私聊。 + $outsiderHistory = $this->actingAs($outsider) + ->get(route('chat.room', $room->id)) + ->viewData('historyMessages'); + $this->assertFalse(collect($outsiderHistory)->contains( + fn (array $item) => ($item['from_user'] ?? null) === $sender->username + && ($item['to_user'] ?? null) === $receiver->username + && ($item['content'] ?? null) === '赠送了你 88 金币!💝' + )); + } + /** * 测试会员用户首次进房时会把专属欢迎主题写入历史消息。 */