username) ->where('towho', $username) ->exists(); // 对方是否也将我加为好友 $theyAdded = FriendRequest::where('who', $username) ->where('towho', $me->username) ->exists(); return response()->json([ 'is_friend' => $iAdded, 'mutual' => $iAdded && $theyAdded, ]); } /** * 添加好友。 * * 流程: * 1. 校验目标用户存在、且不是自己 * 2. 检查是否已经添加过 * 3. 写入 friend_requests 记录 * 4. 检查是否互相好友(B 是否已将 A 加为好友) * 5. 广播 FriendAdded 事件通知对方(携带互相状态) * 6. 若对方在线,向对方发送正确的悄悄话 * * @param string $username 目标用户名 */ public function addFriend(Request $request, string $username): JsonResponse { $me = Auth::user(); // 不能加自己 if ($me->username === $username) { return response()->json(['status' => 'error', 'message' => '不能将自己加为好友'], 422); } // 检查目标用户是否存在 $target = User::where('username', $username)->first(); if (! $target) { return response()->json(['status' => 'error', 'message' => '用户不存在'], 404); } // 是否已添加 $exists = FriendRequest::where('who', $me->username)->where('towho', $username)->exists(); if ($exists) { return response()->json(['status' => 'error', 'message' => '已是好友,无需重复添加'], 422); } // 写入好友关系(A → B) FriendRequest::create([ 'who' => $me->username, 'towho' => $username, 'sub_time' => now(), ]); // 检查 B 是否已将 A 加为好友(互相好友判断) $hasAddedBack = FriendRequest::where('who', $username) ->where('towho', $me->username) ->exists(); // 广播给对方(仅对方可见),携带是否已回加的状态;用数字 ID 作为频道名,避免中文名 broadcast(new FriendAdded($me->username, $username, $target->id, $hasAddedBack)); // 若对方在线,推送聊天区悄悄话(文案根据互相状态区分) $this->notifyOnlineUser($username, $me->username, 'added', $request->input('room_id'), $hasAddedBack); return response()->json([ 'status' => 'success', 'message' => '已成功添加 '.$username.' 为好友 🎉', ]); } /** * 删除好友。 * * 流程: * 1. 删除 friend_requests 中「我 → 对方」的记录 * 2. 检查对方是否也将我加为好友(之前是否互相) * 3. 广播 FriendRemoved 事件通知对方 * 4. 若对方在线,向对方发送悄悄话 * * @param string $username 目标用户名 */ public function removeFriend(Request $request, string $username): JsonResponse { $me = Auth::user(); $deleted = FriendRequest::where('who', $me->username) ->where('towho', $username) ->delete(); if (! $deleted) { return response()->json(['status' => 'error', 'message' => '好友关系不存在'], 404); } // 检查 B 之前是否也将 A 加为好友(删除前的互相状态) $hadAddedBack = FriendRequest::where('who', $username) ->where('towho', $me->username) ->exists(); // 查询目标用户 ID(用于私有频道,避免中文名非法) $targetUser = User::where('username', $username)->first(); // 广播给对方,携带之前的互相好友状态;用数字 ID 避免中文频道名 broadcast(new FriendRemoved($me->username, $username, $targetUser?->id ?? 0, $hadAddedBack)); // 若对方在线,推送聊天区悄悄话(文案根据互相状态区分) $this->notifyOnlineUser($username, $me->username, 'removed', $request->input('room_id'), $hadAddedBack); return response()->json([ 'status' => 'success', 'message' => '已将 '.$username.' 从好友列表移除', ]); } /** * 获取当前用户的好友列表(我添加的 + 对方也添加我的 = 双向好友标记)。 */ public function index(): JsonResponse { $me = Auth::user(); // 我添加的所有人 $myAdded = FriendRequest::where('who', $me->username)->pluck('towho'); // 也把我加了的 $addedMe = FriendRequest::where('towho', $me->username)->pluck('who'); $friends = User::whereIn('username', $myAdded) ->get(['username', 'usersf', 'user_level', 'sex']) ->map(function ($u) use ($addedMe) { return [ 'username' => $u->username, 'headface' => $u->headface, 'user_level' => $u->user_level, 'sex' => $u->sex, 'mutual' => $addedMe->contains($u->username), // 是否互相添加 ]; }); return response()->json(['status' => 'success', 'friends' => $friends]); } /** * 若目标用户在线,向其发送系统悄悄话通知。 * * 根据 $action 和 $mutual 显示不同文案,避免「你们已是好友」的误导提示。 * * @param string $targetUsername 接收通知的用户名 * @param string $fromUsername 发起操作的用户名 * @param string $action 'added' | 'removed' | 'online' * @param int|null $roomId 当前房间 ID * @param bool $mutual 是否互相好友(added: B 是否已回加;removed: 之前是否互相) */ private function notifyOnlineUser( string $targetUsername, string $fromUsername, string $action, ?int $roomId = null, bool $mutual = false, ): void { if (! $roomId) { return; } // 检查对方是否在该房间在线 $onlineUsers = $this->chatState->getRoomUsers($roomId); if (! isset($onlineUsers[$targetUsername])) { return; } // 根据操作类型和互相状态生成不同文案(含内联快捷操作链接) $btnStyle = 'font-weight:bold;text-decoration:underline;margin-left:6px;'; $btnAdd = "➕ 回加好友"; $btnRemove = "🗑️ 同步移除"; $content = match ($action) { 'added' => $mutual ? "💚 {$fromUsername} 将你加为好友了!你们现在互为好友 🎉" : "💚 {$fromUsername} 将你加为好友了!但你还没有添加对方为好友。{$btnAdd}", 'removed' => $mutual ? "💔 {$fromUsername} 已将你从好友列表移除。你的好友列表中仍保留对方。{$btnRemove}" : "💔 {$fromUsername} 已将你从他的好友列表移除。", 'online' => "🟢 你的好友 {$fromUsername} 上线啦!", default => '', }; if (! $content) { return; } // 删除相关用灰色,其他用绿色 $fontColor = $action === 'removed' ? '#6b7280' : '#16a34a'; // 构建系统悄悄话消息 $msg = [ 'id' => $this->chatState->nextMessageId($roomId), 'room_id' => $roomId, 'from_user' => '系统', 'to_user' => $targetUsername, 'content' => $content, 'is_secret' => true, 'font_color' => $fontColor, 'action' => '', 'sent_at' => now()->toDateTimeString(), ]; $this->chatState->pushMessage($roomId, $msg); broadcast(new \App\Events\MessageSent($roomId, $msg)); } }