diff --git a/app/Http/Web/Controllers/MessengerController.php b/app/Http/Web/Controllers/MessengerController.php index 7faf1bf7..59a63ddd 100644 --- a/app/Http/Web/Controllers/MessengerController.php +++ b/app/Http/Web/Controllers/MessengerController.php @@ -2,108 +2,25 @@ namespace App\Http\Web\Controllers; +use App\Http\Web\Services\Messenger as MessengerService; +use App\Traits\Response as ResponseTrait; + /** * @RoutePrefix("/im") */ class MessengerController extends \Phalcon\Mvc\Controller { + use ResponseTrait; + /** * @Get("/init", name="im.init") */ public function initAction() { - $data = [ - 'mine' => [ - 'id' => '100000', //我的ID - 'username' => '纸飞机', //我的昵称 - 'sign' => '在深邃的编码世界,做一枚轻盈的纸飞机', //我的签名 - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', //我的头像 - 'status' => 'online', //在线状态 online:在线、hide:隐身 - ], - 'friend' => [ - [ - 'id' => '1000', - 'groupname' => '前端码农', - 'online' => 3, - 'list' => [ - [ - 'id' => '1000', - 'username' => '闲心', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', //我的头像 - 'status' => 'online', - ], - [ - 'id' => '1001', - 'username' => '妹儿美', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', //我的头像 - 'status' => 'online', - ] - ], - ], - [ - 'id' => '1001', - 'groupname' => '后端码农', - 'online' => 2, - 'list' => [ - [ - 'id' => '1003', - 'username' => '合肥马哥', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - 'status' => 'online', - ], - [ - 'id' => '1004', - 'username' => '合肥牛哥', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - 'status' => 'online', - ] - ], - ], - [ - 'id' => '1002', - 'groupname' => '全栈码农', - 'online' => 1, - 'list' => [ - [ - 'id' => '1005', - 'username' => '南拳', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - 'status' => 'online', - ], - [ - 'id' => '1006', - 'username' => '北腿', - 'sign' => '我是如此的不寒而栗', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - 'status' => 'online', - ] - ], - ], - ], - 'group' => [ - [ - 'id' => '1001', - 'groupname' => '前端码农', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - ], - [ - 'id' => '1002', - 'groupname' => '后端码农', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - ], - [ - 'id' => '1003', - 'groupname' => '全栈码农', - 'avatar' => '//wx2.sinaimg.cn/mw690/5db11ff4gy1flxmew7edlj203d03wt8n.jpg', - ], - ], - ]; + $service = new MessengerService(); + + $data = $service->init(); return $this->jsonSuccess(['data' => $data]); } @@ -162,7 +79,11 @@ class MessengerController extends \Phalcon\Mvc\Controller */ public function bindUserAction() { + $service = new MessengerService(); + $service->bindUser(); + + return $this->jsonSuccess(); } /** @@ -170,7 +91,11 @@ class MessengerController extends \Phalcon\Mvc\Controller */ public function sendMessageAction() { + $service = new MessengerService(); + $service->sendMessage(); + + return $this->jsonSuccess(); } /** diff --git a/app/Http/Web/Services/Messenger.php b/app/Http/Web/Services/Messenger.php index 3417fe33..41210f00 100644 --- a/app/Http/Web/Services/Messenger.php +++ b/app/Http/Web/Services/Messenger.php @@ -2,34 +2,63 @@ namespace App\Http\Web\Services; -use App\Services\Frontend\ChapterTrait; +use App\Repos\User as UserRepo; +use App\Services\Frontend\UserTrait; use GatewayClient\Gateway; class Messenger extends Service { - use ChapterTrait; + use UserTrait; - public function bindUser($id) + public function init() { - $user = $this->getCurrentUser(); + $user = $this->getLoginUser(); - $userId = $user->id > 0 ?: $this->session->getId(); + $mine = [ + 'id' => $user->id, + 'username' => $user->name, + 'sign' => $user->sign, + 'avatar' => $user->avatar, + 'status' => 'online', + ]; + + $friend = $this->handleFriendList($user->id); + + $group = $this->handleGroupList($user->id); + + return [ + 'mine' => $mine, + 'friend' => $friend, + 'group' => $group, + ]; + } + + public function bindUser() + { + $user = $this->getLoginUser(); $clientId = $this->request->getPost('client_id'); - $groupName = $this->getGroupName($id); - Gateway::$registerAddress = '127.0.0.1:1238'; - Gateway::bindUid($clientId, $userId); + Gateway::bindUid($clientId, $user->id); + + $userRepo = new UserRepo(); + + $chatGroups = $userRepo->findImChatGroups($user->id); + + if ($chatGroups->count() > 0) { + foreach ($chatGroups as $group) { + Gateway::joinGroup($clientId, $this->getGroupName($group->id)); + } + } - Gateway::joinGroup($clientId, $groupName); } - public function sendMessage($id) + public function sendMessage() { - $chapter = $this->checkChapterCache($id); + $user = $this->getLoginUser(); $from = $this->request->getPost('from'); $to = $this->request->getPost('to'); @@ -39,7 +68,7 @@ class Messenger extends Service 'avatar' => $from['avatar'], 'content' => $from['content'], 'fromid' => $from['id'], - 'id' => $to['id'], + 'id' => $from['id'], 'type' => $to['type'], 'timestamp' => 1000 * time(), 'mine' => false, @@ -50,11 +79,101 @@ class Messenger extends Service 'content' => $content, ]); - $groupName = $this->getGroupName($chapter->id); - Gateway::$registerAddress = '127.0.0.1:1238'; - Gateway::sendToGroup($groupName, $message); + if ($to['type'] == 'friend') { + + Gateway::sendToUid($to['id'], $message); + + } elseif ($to['type'] == 'group') { + + $excludeClientId = null; + + if ($user->id == $from['id']) { + $excludeClientId = Gateway::getClientIdByUid($user->id); + } + + $groupName = $this->getGroupName($to['id']); + + Gateway::sendToGroup($groupName, $message, $excludeClientId); + } + } + + protected function handleFriendList($userId) + { + $userRepo = new UserRepo(); + + $friendGroups = $userRepo->findImFriendGroups($userId); + $friends = $userRepo->findImFriends($userId); + + $items = []; + + $items[] = ['id' => 0, 'groupname' => '我的好友', 'list' => []]; + + if ($friendGroups->count() > 0) { + foreach ($friendGroups as $group) { + $items[] = ['id' => $group->id, 'groupname' => $group->name, 'online' => 0, 'list' => []]; + } + } + + if ($friends->count() == 0) { + return $items; + } + + $userIds = kg_array_column($friends->toArray(), 'friend_id'); + + $users = $userRepo->findByIds($userIds); + + $userMappings = []; + + foreach ($users as $user) { + $userMappings[$user->id] = [ + 'id' => $user->id, + 'username' => $user->name, + 'avatar' => $user->avatar, + 'sign' => $user->sign, + 'status' => 'online', + ]; + } + + foreach ($items as $key => $item) { + foreach ($friends as $friend) { + $userId = $friend->friend_id; + if ($item['id'] == $friend->group_id) { + $items[$key]['list'][] = $userMappings[$userId]; + } else { + $items[0]['list'][] = $userMappings[$userId]; + } + } + } + + return $items; + } + + protected function handleGroupList($userId) + { + $userRepo = new UserRepo(); + + $groups = $userRepo->findImChatGroups($userId); + + if ($groups->count() == 0) { + return []; + } + + $baseUrl = kg_ci_base_url(); + + $result = []; + + foreach ($groups->toArray() as $group) { + $group['avatar'] = $baseUrl . $group['avatar']; + $result[] = [ + 'id' => $group['id'], + 'groupname' => $group['name'], + 'avatar' => $group['avatar'], + ]; + } + + return $result; } protected function getGroupName($groupId) diff --git a/app/Http/Web/Views/vip/index.volt b/app/Http/Web/Views/vip/index.volt index 6b3040fd..783c0b92 100644 --- a/app/Http/Web/Views/vip/index.volt +++ b/app/Http/Web/Views/vip/index.volt @@ -51,14 +51,17 @@ {% block inline_js %} {% endblock %} \ No newline at end of file diff --git a/app/Library/Helper.php b/app/Library/Helper.php index bc296919..c913b063 100644 --- a/app/Library/Helper.php +++ b/app/Library/Helper.php @@ -130,6 +130,26 @@ function kg_site_base_url() return "{$scheme}://{$host}" . rtrim(dirname($path), '/'); } +/** + * 获取默认头像路径 + * + * @return string + */ +function kg_default_avatar_path() +{ + return '/img/avatar/default.png'; +} + +/** + * 获取默认封面路径 + * + * @return string + */ +function kg_default_cover_path() +{ + return '/img/cover/default.png'; +} + /** * 获取数据万象基准URL * @@ -146,11 +166,9 @@ function kg_ci_base_url() * 获取数据万象URL * * @param string $path - * @param int $width - * @param int $height * @return string */ -function kg_ci_img_url($path, $width = 0, $height = 0) +function kg_ci_img_url($path) { if (!$path) return ''; @@ -160,37 +178,33 @@ function kg_ci_img_url($path, $width = 0, $height = 0) $storage = new StorageService(); - return $storage->getCiImageUrl($path, $width, $height); + return $storage->getCiImageUrl($path); } /** * 获取头像数据万象URL * * @param string $path - * @param int $width - * @param int $height * @return string */ -function kg_ci_avatar_img_url($path, $width = 0, $height = 0) +function kg_ci_avatar_img_url($path) { - $path = $path ?: '/img/avatar/default.png'; + $path = $path ?: kg_default_avatar_path(); - return kg_ci_img_url($path, $width, $height); + return kg_ci_img_url($path); } /** * 获取封面数据万象URL * * @param string $path - * @param int $width - * @param int $height * @return string */ -function kg_ci_cover_img_url($path, $width = 0, $height = 0) +function kg_ci_cover_img_url($path) { - $path = $path ?: '/img/cover/default.png'; + $path = $path ?: kg_default_cover_path(); - return kg_ci_img_url($path, $width, $height); + return kg_ci_img_url($path); } /** diff --git a/app/Models/Course.php b/app/Models/Course.php index c96bdb5e..efb1ec3a 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -278,6 +278,8 @@ class Course extends Model if (Text::startsWith($this->cover, 'http')) { $this->cover = self::getCoverPath($this->cover); + } elseif (empty($this->cover)) { + $this->cover = kg_default_cover_path(); } if (!empty($attrs)) { diff --git a/app/Models/ImChatGroup.php b/app/Models/ImChatGroup.php index 826d727e..3c9a1f3f 100644 --- a/app/Models/ImChatGroup.php +++ b/app/Models/ImChatGroup.php @@ -3,6 +3,7 @@ namespace App\Models; use Phalcon\Mvc\Model\Behavior\SoftDelete; +use Phalcon\Text; class ImChatGroup extends Model { @@ -90,6 +91,12 @@ class ImChatGroup extends Model public function beforeCreate() { $this->create_time = time(); + + if (Text::startsWith($this->avatar, 'http')) { + $this->avatar = self::getAvatarPath($this->avatar); + } elseif (empty($this->avatar)) { + $this->avatar = kg_default_avatar_path(); + } } public function beforeUpdate() @@ -97,5 +104,21 @@ class ImChatGroup extends Model $this->update_time = time(); } + public function afterFetch() + { + if (!Text::startsWith($this->avatar, 'http')) { + $this->avatar = kg_ci_avatar_img_url($this->avatar); + } + } + + public static function getAvatarPath($url) + { + if (Text::startsWith($url, 'http')) { + return parse_url($url, PHP_URL_PATH); + } + + return $url; + } + } diff --git a/app/Models/ImFriend.php b/app/Models/ImFriend.php index c38b0f3e..fdcde989 100644 --- a/app/Models/ImFriend.php +++ b/app/Models/ImFriend.php @@ -26,6 +26,13 @@ class ImFriend extends Model */ public $friend_id; + /** + * 分组编号 + * + * @var integer + */ + public $group_id; + /** * 屏蔽标识 * diff --git a/app/Models/ImFriendGroupUser.php b/app/Models/ImFriendGroupUser.php deleted file mode 100644 index 53dafec1..00000000 --- a/app/Models/ImFriendGroupUser.php +++ /dev/null @@ -1,66 +0,0 @@ -create_time = time(); - } - - public function beforeUpdate() - { - $this->update_time = time(); - } - -} - diff --git a/app/Models/ImFriendMessage.php b/app/Models/ImFriendMessage.php new file mode 100644 index 00000000..9e48ab52 --- /dev/null +++ b/app/Models/ImFriendMessage.php @@ -0,0 +1,95 @@ +addBehavior( + new SoftDelete([ + 'field' => 'deleted', + 'value' => 1, + ]) + ); + } + + public function beforeCreate() + { + $this->create_time = time(); + } + + public function beforeUpdate() + { + $this->update_time = time(); + } + + public static function getChatId($aUserId, $bUserId) + { + $list = [$aUserId, $bUserId]; + + sort($list); + + return implode('_', $list); + } + +} diff --git a/app/Models/ImMessage.php b/app/Models/ImGroupMessage.php similarity index 73% rename from app/Models/ImMessage.php rename to app/Models/ImGroupMessage.php index 7f991b28..693c79a7 100644 --- a/app/Models/ImMessage.php +++ b/app/Models/ImGroupMessage.php @@ -4,12 +4,9 @@ namespace App\Models; use Phalcon\Mvc\Model\Behavior\SoftDelete; -class ImMessage extends Model +class ImGroupMessage extends Model { - const TYPE_FRIEND = 1; // 私聊 - const TYPE_GROUP = 2; // 群聊 - /** * 主键编号 * @@ -18,32 +15,25 @@ class ImMessage extends Model public $id; /** - * 类型 + * 群组编号 * * @var integer */ - public $type; + public $group_id; /** - * 发送方编号 + * 用户编号 * * @var integer */ - public $sender_id; + public $user_id; /** - * 接收方编号 - * - * @var integer - */ - public $receiver_id; - - /** - * 内容编号 + * 内容 * * @var string */ - public $content_id; + public $content; /** * 删除标识 @@ -68,7 +58,7 @@ class ImMessage extends Model public function getSource() { - return 'kg_im_message'; + return 'kg_im_group_message'; } public function initialize() diff --git a/app/Models/ImMessageContent.php b/app/Models/ImMessageContent.php deleted file mode 100644 index ad2246d5..00000000 --- a/app/Models/ImMessageContent.php +++ /dev/null @@ -1,27 +0,0 @@ -cover, 'http')) { $this->cover = self::getCoverPath($this->cover); + } elseif (empty($this->cover)) { + $this->cover = kg_default_cover_path(); } if (is_array($this->style) && !empty($this->style)) { diff --git a/app/Models/User.php b/app/Models/User.php index 7f953ff2..ee2d42a9 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -193,6 +193,8 @@ class User extends Model if (Text::startsWith($this->avatar, 'http')) { $this->avatar = self::getAvatarPath($this->avatar); + } elseif (empty($this->avatar)) { + $this->avatar = kg_default_avatar_path(); } } diff --git a/app/Repos/User.php b/app/Repos/User.php index 9a9c0f7d..ca784c4f 100644 --- a/app/Repos/User.php +++ b/app/Repos/User.php @@ -3,8 +3,10 @@ namespace App\Repos; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; -use App\Models\ImChatGroup as ImGroupModel; -use App\Models\ImChatGroupUser as ImGroupUserModel; +use App\Models\ImChatGroup as ImChatGroupModel; +use App\Models\ImChatGroupUser as ImChatGroupUserModel; +use App\Models\ImFriend as ImFriendModel; +use App\Models\ImFriendGroup as ImFriendGroupModel; use App\Models\User as UserModel; use Phalcon\Mvc\Model; use Phalcon\Mvc\Model\Resultset; @@ -113,17 +115,39 @@ class User extends Repository ->execute(); } + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendModel[] + */ public function findImFriends($userId) { - + return ImFriendModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->execute(); } - public function findImGroups($userId) + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendGroupModel[] + */ + public function findImFriendGroups($userId) + { + return ImFriendGroupModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->andWhere('deleted = 0') + ->execute(); + } + + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImChatGroupModel[] + */ + public function findImChatGroups($userId) { return $this->modelsManager->createBuilder() ->columns('g.*') - ->addFrom(ImGroupModel::class, 'g') - ->join(ImGroupUserModel::class, 'g.id = gu.user_id', 'gu') + ->addFrom(ImChatGroupModel::class, 'g') + ->join(ImChatGroupUserModel::class, 'g.id = gu.group_id', 'gu') ->where('gu.user_id = :user_id:', ['user_id' => $userId]) ->andWhere('g.deleted = 0') ->getQuery()->execute(); diff --git a/app/Services/Frontend/Messenger/ContactList.php b/app/Services/Frontend/Messenger/ContactList.php index 6dd03e9f..b0bbbfe7 100644 --- a/app/Services/Frontend/Messenger/ContactList.php +++ b/app/Services/Frontend/Messenger/ContactList.php @@ -2,18 +2,18 @@ namespace App\Services\Frontend\Messenger; -use App\Services\Frontend\CourseTrait; use App\Services\Frontend\Service as FrontendService; -use App\Services\Frontend\UserTrait; class ContactList extends FrontendService { - use CourseTrait, UserTrait; - - public function handle($id) + public function handle() { + $user = $this->getLoginUser(); + $mine = [ + + ]; } } diff --git a/public/static/web/js/im.js b/public/static/web/js/im.js index 3b6d2229..9a0048a0 100644 --- a/public/static/web/js/im.js +++ b/public/static/web/js/im.js @@ -4,6 +4,30 @@ layui.use(['jquery', 'layim'], function () { var layim = layui.layim; var socket = new WebSocket('ws://127.0.0.1:8282'); + socket.onopen = function () { + console.log('socket connect success'); + }; + + socket.onclose = function () { + console.log('socket connect close'); + }; + + socket.onerror = function () { + console.log('socket connect error'); + }; + + socket.onmessage = function (e) { + var data = JSON.parse(e.data); + console.log(data); + if (data.type === 'ping') { + socket.send('pong...'); + } else if (data.type === 'bind_user') { + bindUser(data.client_id); + } else if (data.type === 'show_message') { + showMessage(data.content); + } + }; + layim.config({ title: '即时聊天', init: { @@ -18,34 +42,12 @@ layui.use(['jquery', 'layim'], function () { uploadFile: { url: '/im/file/upload' }, + maxLength: 1500, find: '/im/find', msgbox: '/im/msg/box', chatLog: '/im/chat/log' }); - layim.on('ready', function (options) { - socket.onopen = function () { - console.log('socket connect success'); - }; - socket.onclose = function () { - console.log('socket connect close'); - }; - socket.onerror = function () { - console.log('socket connect error'); - }; - socket.onmessage = function (e) { - var data = JSON.parse(e.data); - console.log(data); - if (data.type === 'ping') { - socket.send('pong...'); - } else if (data.type === 'bind_user') { - bindUser(data.client_id); - } else if (data.type === 'show_message') { - showMessage(data.content); - } - }; - }); - layim.on('sendMessage', function (res) { sendMessage(res.mine, res.to); }); @@ -61,16 +63,13 @@ layui.use(['jquery', 'layim'], function () { function sendMessage(from, to) { $.ajax({ type: 'POST', - dataType: 'json', url: '/im/msg/send', data: {from: from, to: to} }); } function showMessage(message) { - if (message.fromid !== user.id) { - layim.getMessage(message); - } + layim.getMessage(message); } }); \ No newline at end of file