diff --git a/app/Http/Web/Controllers/MessengerController.php b/app/Http/Web/Controllers/MessengerController.php index 116e7e49..e721e66b 100644 --- a/app/Http/Web/Controllers/MessengerController.php +++ b/app/Http/Web/Controllers/MessengerController.php @@ -235,6 +235,30 @@ class MessengerController extends LayerController return $this->jsonSuccess($content); } + /** + * @Post("/friend/accept", name="web.im.accept_friend") + */ + public function acceptFriendAction() + { + $service = new MessengerService(); + + $service->acceptFriend(); + + return $this->jsonSuccess(); + } + + /** + * @Post("/friend/refuse", name="web.im.refuse_friend") + */ + public function refuseFriendAction() + { + $service = new MessengerService(); + + $service->refuseFriend(); + + return $this->jsonSuccess(); + } + /** * @Post("/group/apply", name="web.im.apply_group") */ @@ -249,14 +273,6 @@ class MessengerController extends LayerController return $this->jsonSuccess($content); } - /** - * @Post("/friend/accept", name="web.im.accept_friend") - */ - public function acceptFriendAction() - { - - } - /** * @Post("/group/accept", name="web.web.im.accept_group") */ diff --git a/app/Http/Web/Services/Messenger.php b/app/Http/Web/Services/Messenger.php index 4a8d8d67..fce1750d 100644 --- a/app/Http/Web/Services/Messenger.php +++ b/app/Http/Web/Services/Messenger.php @@ -6,6 +6,7 @@ use App\Builders\ImMessageList as ImMessageListBuilder; use App\Caches\ImHotGroupList as ImHotGroupListCache; use App\Caches\ImHotUserList as ImHotUserListCache; use App\Library\Paginator\Query as PagerQuery; +use App\Models\ImFriendGroup as ImFriendGroupModel; use App\Models\ImFriendMessage as ImFriendMessageModel; use App\Models\ImFriendUser as ImFriendUserModel; use App\Models\ImGroupMessage as ImGroupMessageModel; @@ -236,13 +237,7 @@ class Messenger extends Service } } - /** - * @todo 发送未读消息 - */ - - /** - * @todo 发送盒子消息 - */ + $this->pullUnreadFriendMessages($user->id); } public function sendMessage() @@ -375,63 +370,88 @@ class Messenger extends Service $validator->checkIfJoined($user->id, $friend->id); $validator->checkIfBlocked($user->id, $friend->id); - $friendUserRepo = new ImFriendUserRepo(); - - $friendUser = $friendUserRepo->findFriendUser($user->id, $friend->id); - - if (!$friendUser) { - $model = new ImFriendUserModel(); - $model->user_id = $user->id; - $model->friend_id = $friend->id; - $model->group_id = $group->id; - $model->create(); - } else { - $friendUser->group_id = $group->id; - $friendUser->update(); - } - - $this->handleApplyFriendNotice($user, $friend, $remark); + $this->handleApplyFriendNotice($user, $friend, $group, $remark); } public function acceptFriend() { - $post = $this->request->getPost(); - $user = $this->getLoginUser(); + $messageId = $this->request->getPost('message_id'); + $groupId = $this->request->getPost('group_id'); + $validator = new ImFriendUserValidator(); - $friend = $validator->checkFriend($post['friend_id']); - $group = $validator->checkGroup($post['group_id']); + $validator->checkGroup($groupId); + + $validator = new ImMessageValidator(); + + $message = $validator->checkMessage($messageId, 'system'); + + if ($message->item_type != ImSystemMessageModel::TYPE_FRIEND_REQUEST) { + return; + } + + $userRepo = new UserRepo(); + + $sender = $userRepo->findById($message->sender_id); $friendUserRepo = new ImFriendUserRepo(); - $friendUser = $friendUserRepo->findFriendUser($user->id, $friend->id); + $friendUser = $friendUserRepo->findFriendUser($user->id, $sender->id); + + $friendUserModel = new ImFriendUserModel(); if (!$friendUser) { - $model = new ImFriendUserModel(); - $model->user_id = $user->id; - $model->friend_id = $friend->id; - $model->group_id = $group->id; - $model->create(); + $friendUserModel->create([ + 'user_id' => $user->id, + 'friend_id' => $sender->id, + 'group_id' => $groupId, + ]); } - $this->handleAcceptFriendNotice(); + $friendUser = $friendUserRepo->findFriendUser($sender->id, $user->id); + + $groupId = $message->item_info['group']['id'] ?: 0; + + if (!$friendUser) { + $friendUserModel->create([ + 'user_id' => $user->id, + 'friend_id' => $sender->id, + 'group_id' => $groupId, + ]); + } + + $itemInfo = $message->item_info; + $itemInfo['status'] = ImSystemMessageModel::REQUEST_ACCEPTED; + $message->update(['item_info' => $itemInfo]); + + $this->handleAcceptFriendNotice($user, $sender); } public function refuseFriend() { - $friendId = $this->request->getPost('friend_id'); - $user = $this->getLoginUser(); - $userValidator = new UserValidator(); + $messageId = $this->request->getPost('message_id'); - $friend = $userValidator->checkUser($friendId); + $validator = new ImMessageValidator(); - /** - * @todo 向对方发拒绝添加好友的系统消息 - */ + $message = $validator->checkMessage($messageId, 'system'); + + if ($message->item_type != ImSystemMessageModel::TYPE_FRIEND_REQUEST) { + return; + } + + $itemInfo = $message->item_info; + $itemInfo['status'] = ImSystemMessageModel::REQUEST_REFUSED; + $message->update(['item_info' => $itemInfo]); + + $userRepo = new UserRepo(); + + $sender = $userRepo->findById($message->sender_id); + + $this->handleRefuseFriendNotice($user, $sender); } public function applyGroup() @@ -446,6 +466,44 @@ class Messenger extends Service { } + protected function pullUnreadFriendMessages($userId) + { + $userRepo = new UserRepo(); + + $messages = $userRepo->findUnreadImFriendMessages($userId); + + if ($messages->count() == 0) { + return; + } + + $builder = new ImMessageListBuilder(); + + $senders = $builder->getSenders($messages->toArray()); + + foreach ($messages as $message) { + + $message->update(['viewed' => 1]); + + $sender = $senders[$message->sender_id]; + + $content = kg_json_encode([ + 'type' => 'show_chat_msg', + 'message' => [ + 'username' => $sender['name'], + 'avatar' => $sender['avatar'], + 'content' => $message->content, + 'fromid' => $sender['id'], + 'id' => $sender['id'], + 'timestamp' => 1000 * $message->create_time, + 'type' => 'friend', + 'mine' => false, + ], + ]); + + Gateway::sendToUid($userId, $content); + } + } + protected function handleFriendList($userId) { $userRepo = new UserRepo(); @@ -621,7 +679,7 @@ class Messenger extends Service return $pager; } - protected function handleApplyFriendNotice(UserModel $sender, UserModel $receiver, $remark) + protected function handleApplyFriendNotice(UserModel $sender, UserModel $receiver, ImFriendGroupModel $group, $remark) { $userRepo = new UserRepo(); @@ -630,34 +688,59 @@ class Messenger extends Service $message = $userRepo->findImSystemMessage($receiver->id, $itemType); if ($message) { - - /** - * 请求未过期 - */ - if (time() - $message->create_time < 3 * 86400) { - return; - } - - if ($message->item_type['accepted'] == 1) { + $expired = time() - $message->create_time > 7 * 86400; + $pending = $message->item_type['status'] == ImSystemMessageModel::REQUEST_PENDING; + if (!$expired && $pending) { return; } } - $senderInfo = [ - 'id' => $sender->id, - 'name' => $sender->name, - 'avatar' => $sender->avatar, - ]; - $sysMsgModel = new ImSystemMessageModel(); $sysMsgModel->sender_id = $sender->id; $sysMsgModel->receiver_id = $receiver->id; $sysMsgModel->item_type = ImSystemMessageModel::TYPE_FRIEND_REQUEST; $sysMsgModel->item_info = [ - 'sender' => $senderInfo, + 'sender' => [ + 'id' => $sender->id, + 'name' => $sender->name, + 'avatar' => $sender->avatar, + ], + 'group' => [ + 'id' => $group->id, + 'name' => $group->name, + ], 'remark' => $remark, - 'accepted' => 0, + 'status' => ImSystemMessageModel::REQUEST_PENDING, + ]; + + $sysMsgModel->create(); + + Gateway::$registerAddress = '127.0.0.1:1238'; + + $online = Gateway::isUidOnline($receiver->id); + + if ($online) { + + $content = kg_json_encode(['type' => 'refresh_sys_msg']); + + Gateway::sendToUid($receiver->id, $content); + } + } + + protected function handleAcceptFriendNotice(UserModel $sender, UserModel $receiver) + { + $sysMsgModel = new ImSystemMessageModel(); + + $sysMsgModel->sender_id = $sender->id; + $sysMsgModel->receiver_id = $receiver->id; + $sysMsgModel->item_type = ImSystemMessageModel::TYPE_FRIEND_ACCEPTED; + $sysMsgModel->item_info = [ + 'sender' => [ + 'id' => $sender->id, + 'name' => $sender->name, + 'avatar' => $sender->avatar, + ] ]; $sysMsgModel->create(); @@ -674,42 +757,35 @@ class Messenger extends Service } } - protected function handleAcceptFriendNotice(UserModel $user, UserModel $friend) + protected function handleRefuseFriendNotice(UserModel $sender, UserModel $receiver) { $sysMsgModel = new ImSystemMessageModel(); - $sysMsgModel->user_id = $friend->id; - $sysMsgModel->item_id = $user->id; - $sysMsgModel->item_type = ImSystemMessageModel::TYPE_FRIEND_APPROVED; + $sysMsgModel->sender_id = $sender->id; + $sysMsgModel->receiver_id = $receiver->id; + $sysMsgModel->item_type = ImSystemMessageModel::TYPE_FRIEND_REFUSED; $sysMsgModel->item_info = [ - 'user' => ['id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar], + 'sender' => [ + 'id' => $sender->id, + 'name' => $sender->name, + 'avatar' => $sender->avatar, + ] ]; $sysMsgModel->create(); Gateway::$registerAddress = '127.0.0.1:1238'; - $online = Gateway::isUidOnline($friend->id); + $online = Gateway::isUidOnline($receiver->id); if ($online) { - $userRepo = new UserRepo(); + $content = kg_json_encode(['type' => 'show_msg_box']); - $msgCount = $userRepo->countUnreadImSystemMessages($friend->id); - - $message = kg_json_encode([ - 'type' => 'show_msg_box', - 'content' => ['msg_count' => $msgCount], - ]); - - Gateway::sendToUid($friend->id, $message); + Gateway::sendToUid($receiver->id, $content); } } - protected function handleRefuseFriendNotice() - { - } - protected function getGroupName($groupId) { return "group_{$groupId}"; diff --git a/app/Http/Web/Views/messenger/find.volt b/app/Http/Web/Views/messenger/find.volt index e5efadd7..75fe9de4 100644 --- a/app/Http/Web/Views/messenger/find.volt +++ b/app/Http/Web/Views/messenger/find.volt @@ -3,7 +3,7 @@ {% block content %}
{{ item.name }}
- 加入群组 + 加入群组
diff --git a/app/Http/Web/Views/messenger/sys_messages.volt b/app/Http/Web/Views/messenger/sys_messages.volt index 135d89bc..da89074b 100644 --- a/app/Http/Web/Views/messenger/sys_messages.volt +++ b/app/Http/Web/Views/messenger/sys_messages.volt @@ -1,20 +1,73 @@ -{% if pager.total_pages > 0 %} -
-
- {% for item in pager.items %} -
-
-
- {{ item.name }} -
-
{{ item.name }}
- -
-
- {% endfor %} -
-
- {{ partial('partials/pager_ajax') }} +{%- macro message_info(item) %} + + {% set item_type = item.item_type %} + {% set item_info = item.item_info %} + + {% if item_type == '1' %} + {% set sender = item_info.sender %} + {% set group = item_info.group %} + {% set remark = item_info.remark ? '附言:' ~ item_info.remark : '' %} +
  • + +

    + {{ sender.name }} + {{ date('Y-m-d H:i:s',item.create_time) }} +

    +

    申请添加你为好友 {{ remark }}

    +

    + {% if item_info.status == 'pending' %} + + + {% elseif item_info.status == 'accepted' %} + 已同意 + {% elseif item_info.status == 'refused' %} + 已拒绝 + {% endif %} +

    +
  • + {% elseif item_type == '2' %} +
  • +

    系统:{{ item_info.sender.name }} 接受了你的好友申请{{ date('Y-m-d H:i:s',item.create_time) }}

    +
  • + {% elseif item_type == '3' %} +
  • +

    系统:{{ item_info.sender.name }} 拒绝了你的好友申请{{ date('Y-m-d H:i:s',item.create_time) }}

    +
  • + {% elseif item_type == '4' %} + {% set remark = item_info.remark ? '附言:' ~ item_info.remark : '' %} +
  • + +

    + {{ item_info.sender.name }} + {{ date('Y-m-d H:i:s',item.create_time) }} +

    +

    申请加入群组 {{ remark }}

    +

    + {% if item_info.status == 'pending' %} + + + {% elseif item_info.status == 'accepted' %} + 已同意 + {% elseif item_info.status == 'refused' %} + 已拒绝 + {% endif %} +

    +
  • + {% elseif item_type == '5' %} +
  • +

    系统:{{ item_info.sender.name }} 接受了你的入群申请{{ date('Y-m-d H:i:s',item.create_time) }}

    +
  • + {% elseif item_type == '6' %} +
  • +

    系统:{{ item_info.sender.name }} 拒绝了你的入群申请{{ date('Y-m-d H:i:s',item.create_time) }}

    +
  • + {% endif %} +{%- endmacro %} + +{% if pager.items %} + {% endif %} \ No newline at end of file diff --git a/app/Models/ImSystemMessage.php b/app/Models/ImSystemMessage.php index 8b54c27d..0e0c9b55 100644 --- a/app/Models/ImSystemMessage.php +++ b/app/Models/ImSystemMessage.php @@ -7,12 +7,22 @@ use Phalcon\Mvc\Model\Behavior\SoftDelete; class ImSystemMessage extends Model { - const TYPE_FRIEND_REQUEST = 1; - const TYPE_GROUP_REQUEST = 2; - const TYPE_FRIEND_ACCEPTED = 3; - const TYPE_FRIEND_REFUSED = 4; - const TYPE_GROUP_ACCEPTED = 5; - const TYPE_GROUP_REFUSED = 6; + /** + * 请求状态 + */ + const REQUEST_PENDING = 'pending'; // 待处理 + const REQUEST_ACCEPTED = 'accepted'; // 已接受 + const REQUEST_REFUSED = 'refused'; // 已拒绝 + + /** + * 消息类型 + */ + const TYPE_FRIEND_REQUEST = 1; // 好友请求 + const TYPE_FRIEND_ACCEPTED = 2; // 好友被接受 + const TYPE_FRIEND_REFUSED = 3; // 好友被拒绝 + const TYPE_GROUP_REQUEST = 4; // 入群请求 + const TYPE_GROUP_ACCEPTED = 5; // 入群被接受 + const TYPE_GROUP_REFUSED = 6; // 入群被拒绝 /** * 主键编号 @@ -115,6 +125,10 @@ class ImSystemMessage extends Model public function beforeUpdate() { $this->update_time = time(); + + if (is_array($this->item_info) && !empty($this->item_info)) { + $this->item_info = kg_json_encode($this->item_info); + } } public function afterFetch() diff --git a/app/Repos/User.php b/app/Repos/User.php index a187d0ef..b58c96d6 100644 --- a/app/Repos/User.php +++ b/app/Repos/User.php @@ -6,6 +6,7 @@ use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Models\ImChatGroup as ImChatGroupModel; use App\Models\ImChatGroupUser as ImChatGroupUserModel; use App\Models\ImFriendGroup as ImFriendGroupModel; +use App\Models\ImFriendMessage as ImFriendMessageModel; use App\Models\ImFriendUser as ImFriendUserModel; use App\Models\ImSystemMessage as ImSystemMessageModel; use App\Models\User as UserModel; @@ -157,6 +158,18 @@ class User extends Repository ->getQuery()->execute(); } + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendMessageModel[] + */ + public function findUnreadImFriendMessages($userId) + { + return ImFriendMessageModel::find([ + 'conditions' => 'receiver_id = ?1 AND viewed = ?2', + 'bind' => [1 => $userId, 2 => 0], + ]); + } + /** * @param int $userId * @param int $itemType @@ -173,7 +186,7 @@ class User extends Repository /** * @param int $userId - * @return ResultsetInterface|Resultset|ImSystemMessageModel[] + * @return ResultsetInterface|Resultset|ImFriendMessageModel[] */ public function findUnreadImSystemMessages($userId) { diff --git a/app/Validators/ImFriendUser.php b/app/Validators/ImFriendUser.php index 5080ad16..e6b469ee 100644 --- a/app/Validators/ImFriendUser.php +++ b/app/Validators/ImFriendUser.php @@ -56,6 +56,8 @@ class ImFriendUser extends Validator if ($length > 30) { throw new BadRequestException('im_friend_user.remark_too_long'); } + + return $remark; } public function checkIfSelfApply($userId, $friendId) diff --git a/app/Validators/ImMessage.php b/app/Validators/ImMessage.php index 119c325b..0326c045 100644 --- a/app/Validators/ImMessage.php +++ b/app/Validators/ImMessage.php @@ -7,6 +7,7 @@ use App\Caches\User as UserCache; use App\Exceptions\BadRequest as BadRequestException; use App\Repos\ImFriendMessage as ImFriendMessageRepo; use App\Repos\ImGroupMessage as ImGroupMessageRepo; +use App\Repos\ImSystemMessage as ImSystemMessageRepo; class ImMessage extends Validator { @@ -23,6 +24,9 @@ class ImMessage extends Validator } elseif ($type == 'group') { $repo = new ImGroupMessageRepo(); $message = $repo->findById($id); + } elseif ($type == 'system') { + $repo = new ImSystemMessageRepo(); + $message = $repo->findById($id); } if (!$message) { @@ -57,7 +61,7 @@ class ImMessage extends Validator public function checkType($type) { - if (!in_array($type, ['friend', 'group'])) { + if (!in_array($type, ['friend', 'group', 'system'])) { throw new BadRequestException('im_message.invalid_type'); } diff --git a/public/static/web/js/im.find.js b/public/static/web/js/im.find.js index 7feeba2a..26a16cab 100644 --- a/public/static/web/js/im.find.js +++ b/public/static/web/js/im.find.js @@ -32,29 +32,42 @@ layui.use(['jquery', 'form', 'layer', 'layim'], function () { }, success: function (res) { layer.msg(res.msg, {icon: 1}); + layer.close(index); }, error: function (xhr) { var res = JSON.parse(xhr.responseText); layer.msg(res.msg, {icon: 2}); } }); - layer.close(index); } }); }); $('body').on('click', '.apply-group', function () { var groupId = $(this).attr('data-id'); - $.ajax({ - type: 'POST', - url: '/im/group/apply', - data: {group_id: groupId}, - success: function (res) { - layer.msg(res.msg, {icon: 1}); - }, - error: function (xhr) { - var res = JSON.parse(xhr.responseText); - layer.msg(res.msg, {icon: 2}); + var groupName = $(this).attr('data-name'); + var avatar = $(this).attr('data-avatar'); + layim.add({ + type: 'group', + groupname: groupName, + avatar: avatar, + submit: function (group, remark, index) { + $.ajax({ + type: 'POST', + url: '/im/group/apply', + data: { + group_id: groupId, + remark: remark + }, + success: function (res) { + layer.msg(res.msg, {icon: 1}); + layer.close(index); + }, + error: function (xhr) { + var res = JSON.parse(xhr.responseText); + layer.msg(res.msg, {icon: 2}); + } + }); } }); }); diff --git a/public/static/web/js/im.js b/public/static/web/js/im.js index 75f03d97..2a2b3df7 100644 --- a/public/static/web/js/im.js +++ b/public/static/web/js/im.js @@ -23,11 +23,11 @@ layui.use(['jquery', 'layim'], function () { socket.send('pong...'); } else if (data.type === 'bind_user') { bindUser(data.client_id); - refreshMessageBox(); + refreshSystemMessage(); } else if (data.type === 'show_chat_msg') { showChatMessage(data.message); - } else if (data.type === 'show_msg_box') { - refreshMessageBox(); + } else if (data.type === 'refresh_sys_msg') { + refreshSystemMessage(); } }; @@ -83,7 +83,7 @@ layui.use(['jquery', 'layim'], function () { layim.getMessage(message); } - function refreshMessageBox() { + function refreshSystemMessage() { $.ajax({ type: 'GET', url: '/im/msg/unread/count', diff --git a/public/static/web/js/im.msgbox.js b/public/static/web/js/im.msgbox.js index e4b466a6..a3736f55 100644 --- a/public/static/web/js/im.msgbox.js +++ b/public/static/web/js/im.msgbox.js @@ -47,86 +47,63 @@ layui.use(['jquery', 'layer', 'layim', 'laypage'], function () { } //操作 - var active = { - //同意 - agree: function (othis) { - var li = othis.parents('li') - , uid = li.data('uid') - , from_group = li.data('fromGroup') - , user = cache[uid]; - + var action = { + acceptFriend: function (othis) { + var li = othis.parents('li'); + var sender = li.find('.layim-msgbox-user'); //选择分组 parent.layui.layim.setFriendGroup({ - type: 'friend' - , username: user.username - , avatar: user.avatar - , group: parent.layui.layim.cache().friend //获取好友分组数据 - , submit: function (group, index) { - - //将好友追加到主面板 - parent.layui.layim.addList({ - type: 'friend' - , avatar: user.avatar //好友头像 - , username: user.username //好友昵称 - , groupid: group //所在的分组id - , id: uid //好友ID - , sign: user.sign //好友签名 + type: 'friend', + username: sender.data('name'), + avatar: sender.data('avatar'), + group: parent.layui.layim.cache().friend, + submit: function (group, index) { + $.ajax({ + type: 'POST', + url: '/im/friend/accept', + data: { + message_id: li.data('id'), + group_id: group + }, + success: function () { + //将好友追加到主面板 + parent.layui.layim.addList({ + type: 'friend', + username: sender.data('name'), + avatar: sender.data('avatar'), + id: sender.data('id'), + groupid: group, + }); + othis.parent().html('已同意'); + parent.layer.close(index); + } }); - parent.layer.close(index); - othis.parent().html('已同意'); - - - //实际部署时,请开启下述注释,并改成你的接口地址 - /* - $.post('/im/agreeFriend', { - uid: uid //对方用户ID - ,from_group: from_group //对方设定的好友分组 - ,group: group //我设定的好友分组 - }, function(res){ - if(res.code != 0){ - return layer.msg(res.msg); - } - - //将好友追加到主面板 - parent.layui.layim.addList({ - type: 'friend' - ,avatar: user.avatar //好友头像 - ,username: user.username //好友昵称 - ,groupid: group //所在的分组id - ,id: uid //好友ID - ,sign: user.sign //好友签名 - }); - parent.layer.close(index); - othis.parent().html('已同意'); - }); - */ - } }); - } - - //拒绝 - , refuse: function (othis) { - var li = othis.parents('li') - , uid = li.data('uid'); - + }, + refuseFriend: function (othis) { + var li = othis.parents('li'); layer.confirm('确定拒绝吗?', function (index) { - $.post('/im/refuseFriend', { - uid: uid //对方用户ID - }, function (res) { - if (res.code != 0) { - return layer.msg(res.msg); + $.ajax({ + type: 'POST', + url: '/im/friend/refuse', + data: {message_id: li.data('id')}, + success: function () { + layer.close(index); + othis.parent().html('已拒绝'); } - layer.close(index); - othis.parent().html('已拒绝'); }); }); + }, + acceptGroup: function (othis) { + }, + refuseGroup: function (othis) { } }; $('body').on('click', '.layui-btn', function () { var othis = $(this), type = othis.data('type'); - active[type] ? active[type].call(this, othis) : ''; + action[type] ? action[type].call(this, othis) : ''; }); }); \ No newline at end of file