| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <?php
- // +----------------------------------------------------------------------
- // | Chat 消息处理类(参照熙思研模式:在 WS handler 内直接保存聊天记录)
- // +----------------------------------------------------------------------
- namespace app\services\workerman\chat;
- use app\model\api\ChatRecord;
- use app\model\api\ChatUserRelation;
- use app\model\api\User;
- use app\services\workerman\Response;
- use Workerman\Connection\TcpConnection;
- class ChatHandle
- {
- protected $service;
- public function __construct(ChatService &$service)
- {
- $this->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 拉取
- }
- }
|