service = &$service; } /** * 客服登录 */ public function kefu_login(TcpConnection &$connection, array $res, Response $response) { if (!isset($res['data']) || !$token = $res['data']) { return $response->close(['msg' => '授权失败!']); } // TODO: 根据你的系统实现客服token验证 $kefuInfo = [ 'uid' => $res['data']['uid'] ?? 1, 'name' => $res['data']['name'] ?? '客服', ]; $connection->kefuUser = (object)$kefuInfo; $connection->user = (object)['uid' => $kefuInfo['uid'], 'nickname' => $kefuInfo['name'] ?? '客服']; $this->service->setKefuUser($connection); return $response->success(); } /** * 用户登录 */ public function login(TcpConnection &$connection, array $res, Response $response) { if (!isset($res['data']) || !$token = $res['data']) { return $response->close(['msg' => '授权失败!']); } // 通过 token 查询用户 $userInfo = User::where('token', $token)->find(); if (!$userInfo) { return $response->close(['msg' => '用户不存在']); } $connection->user = (object)$userInfo->toArray(); $connection->chatToUid = $connection->to_uid ?? 0; $this->service->setUser($connection); return $response->success([ 'msg' => '登录成功', 'to_uid' => $connection->chatToUid, ]); } /** * 用户切换到与某人聊天(参照熙思研 to_chat) * 前端打开某用户聊天窗口时调用,用于标记消息已读、重置未读数 */ public function to_chat(TcpConnection &$connection, array $res, Response $response) { $to_uid = $res['data']['id'] ?? $res['data']['to_uid'] ?? 0; $connection->chatToUid = $to_uid; if (isset($connection->user) && $connection->chatToUid) { $uid = $connection->user->uid; // 标记对方发给我的消息为已读 ChatRecord::markAsRead($uid, $connection->chatToUid); $response->send('mssage_num', [ 'uid' => $connection->chatToUid, 'num' => 0, 'recored' => (object)[], ]); } } /** * 发送消息(参照熙思研模式:在 WS handler 内直接保存聊天记录到数据库) */ public function chat(TcpConnection &$connection, array $res, Response $response) { if (!isset($connection->user) || !$connection->user) { return $response->send('err_tip', ['msg' => '请先登录']); } $to_uid = $res['data']['to_uid'] ?? $connection->chatToUid ?? 0; $msn_type = $res['data']['type'] ?? ChatRecord::TYPE_TEXT; $msn = $res['data']['msn'] ?? ''; $form_type = $res['form_type'] ?? $connection->form_type ?? ChatRecord::FROM_PC; $uid = $connection->user->uid ?? 0; if (!$to_uid) { return $response->send('err_tip', ['msg' => '用户不存在']); } if ($to_uid == $uid) { return $response->send('err_tip', ['msg' => '不能和自己聊天']); } if (!in_array($msn_type, [ChatRecord::TYPE_TEXT, ChatRecord::TYPE_VOICE, ChatRecord::TYPE_IMAGE])) { return $response->send('err_tip', ['msg' => '格式错误']); } // 清洗消息内容 $msn = trim(strip_tags(str_replace(["\n", "\t", "\r", " "], '', htmlspecialchars_decode($msn)))); // 判断对方是否在线且正在与当前用户聊天 $connections = $this->service->user(); $online = isset($connections[$to_uid]) && isset($connections[$to_uid]->chatToUid) && $connections[$to_uid]->chatToUid == $uid; // ========== 关键:在 WS handler 内直接保存聊天记录 ========== $record = ChatRecord::saveRecord($uid, $to_uid, $msn, $msn_type, $form_type); // 如果对方在线且正在聊天,直接标记已读 if ($online) { ChatRecord::where('id', $record->id)->update(['is_read' => ChatRecord::READ]); $record->is_read = ChatRecord::READ; } // 更新会话关系 $relation = ChatUserRelation::getOrCreate($uid, $to_uid); if ($relation) { $relation->update_time = time(); $relation->save(); } // 获取发送者用户信息 $user = User::find($uid); $nickname = $user->nickname ?? $connection->user->nickname ?? '用户'; $avatar = $user->avatar ?? $connection->user->avatar ?? ''; // 未读消息计数 $unreadCount = ChatRecord::getUnreadCount($to_uid, $uid); // 构造返回数据 $data = [ 'record_id' => $record->id, 'user_id' => $uid, 'to_user_id' => $to_uid, 'content' => $msn, 'type' => $msn_type, 'type_text' => ChatRecord::getTypeText($msn_type), 'form_type' => $form_type, 'is_read' => $online ? ChatRecord::READ : ChatRecord::UNREAD, 'create_time' => $record->create_time, 'nickname' => $nickname, 'avatar' => $avatar, ]; // 给自己回复 $response->send('chat', $data); // 发送给对方 if ($online) { // 对方在线且正在聊天:直接推送消息 $replyData = $data; $replyData['is_read'] = ChatRecord::READ; $response->connection($this->service->user()[$to_uid])->send('reply', $replyData); } elseif (isset($connections[$to_uid])) { // 对方在线但没在聊天:推送未读消息提醒 $response->connection($this->service->user()[$to_uid])->send('mssage_num', [ 'uid' => $uid, 'num' => $unreadCount, 'recored' => [ 'nickname' => $nickname, 'avatar' => $avatar, ], ]); } // 对方不在线:什么都不做,等对方上线后通过 HTTP API 拉取 } }