1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-30 22:24:55 +08:00

完成消息盒子

This commit is contained in:
xiaochong0302 2020-06-28 19:49:09 +08:00
parent 4676a18a64
commit 8732b41ca0
13 changed files with 207 additions and 86 deletions

View File

@ -48,7 +48,6 @@ class ImHotGroupList extends Cache
'name' => $group->name, 'name' => $group->name,
'avatar' => $group->avatar, 'avatar' => $group->avatar,
'about' => $group->about, 'about' => $group->about,
'user_count' => $group->user_count,
]; ];
} }

View File

@ -48,11 +48,7 @@ class ImHotUserList extends Cache
'name' => $user->name, 'name' => $user->name,
'avatar' => $user->avatar, 'avatar' => $user->avatar,
'about' => $user->about, 'about' => $user->about,
'location' => $user->location,
'gender' => $user->gender,
'vip' => $user->vip, 'vip' => $user->vip,
'follower_count' => $user->follower_count,
'following_count' => $user->following_count,
]; ];
} }
@ -67,7 +63,7 @@ class ImHotUserList extends Cache
{ {
return UserModel::query() return UserModel::query()
->where('deleted = 0') ->where('deleted = 0')
->orderBy('follower_count DESC') ->orderBy('id DESC')
->limit($limit) ->limit($limit)
->execute(); ->execute();
} }

View File

@ -1,12 +1,3 @@
{%- macro last_login_info(user) %}
{% if user.last_login_ip %}
<span class="layui-badge layui-bg-gray">学员</span>
{% endif %}
{% if user.last_login_time %}
<span class="layui-badge layui-bg-gray">学员</span>
{% endif %}
{%- endmacro %}
{%- macro gender_info(value) %} {%- macro gender_info(value) %}
{% if value == 1 %} {% if value == 1 %}
<span class="layui-badge layui-bg-red">男</span> <span class="layui-badge layui-bg-red">男</span>
@ -72,9 +63,9 @@
<th>编号</th> <th>编号</th>
<th>昵称</th> <th>昵称</th>
<th>性别</th> <th>性别</th>
<th>最后登录</th>
<th>教学角色</th> <th>教学角色</th>
<th>后台角色</th> <th>后台角色</th>
<th>活跃时间</th>
<th>注册时间</th> <th>注册时间</th>
<th>操作</th> <th>操作</th>
</tr> </tr>
@ -85,9 +76,9 @@
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td><span title="{{ item.about }}">{{ item.name }}</span>{{ status_info(item) }}</td> <td><span title="{{ item.about }}">{{ item.name }}</span>{{ status_info(item) }}</td>
<td>{{ gender_info(item.gender) }}</td> <td>{{ gender_info(item.gender) }}</td>
<td>{{ last_login_info(item) }}</td>
<td>{{ edu_role_info(item) }}</td> <td>{{ edu_role_info(item) }}</td>
<td>{{ admin_role_info(item) }}</td> <td>{{ admin_role_info(item) }}</td>
<td>{{ date('Y-m-d H:i:s',item.active_time) }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td> <td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">

View File

@ -202,11 +202,15 @@ class MessengerController extends LayerController
} }
/** /**
* @Post("/stats/update", name="web.im.update_stats") * @Post("/online/update", name="web.im.update_online")
*/ */
public function updateStatsAction() public function updateOnlineAction()
{ {
$service = new MessengerService();
$service->updateOnline();
return $this->jsonSuccess();
} }
/** /**

View File

@ -43,9 +43,9 @@ class Messenger extends Service
'status' => 'online', 'status' => 'online',
]; ];
$friend = $this->handleFriendList($user->id); $friend = $this->handleFriendList($user);
$group = $this->handleGroupList($user->id); $group = $this->handleGroupList($user);
return [ return [
'mine' => $mine, 'mine' => $mine,
@ -225,6 +225,11 @@ class Messenger extends Service
{ {
$user = $this->getLoginUser(); $user = $this->getLoginUser();
$user->update([
'online' => 1,
'active_time' => time(),
]);
$clientId = $this->request->getPost('client_id'); $clientId = $this->request->getPost('client_id');
Gateway::$registerAddress = $this->getRegisterAddress(); Gateway::$registerAddress = $this->getRegisterAddress();
@ -241,7 +246,12 @@ class Messenger extends Service
} }
} }
$this->pullUnreadFriendMessages($user->id); $this->pullUnreadFriendMessages($user);
/**
* @todo 隐身登录
*/
$this->pushFriendOnlineTips($user, 'online');
} }
public function sendMessage() public function sendMessage()
@ -344,6 +354,21 @@ class Messenger extends Service
} }
} }
public function updateOnline()
{
$status = $this->request->getPost('status');
$user = $this->getLoginUser();
$online = $status == 'online' ? 1 : 0;
$user->update(['online' => $online]);
$this->pushFriendOnlineTips($user, $status);
return $user;
}
public function updateSignature() public function updateSignature()
{ {
$sign = $this->request->getPost('sign'); $sign = $this->request->getPost('sign');
@ -500,17 +525,17 @@ class Messenger extends Service
$userRepo = new UserRepo(); $userRepo = new UserRepo();
$sender = $userRepo->findById($message->sender_id); $applicant = $userRepo->findById($message->sender_id);
$groupUserRepo = new ImChatGroupUserRepo(); $groupUserRepo = new ImChatGroupUserRepo();
$groupUser = $groupUserRepo->findGroupUser($group->id, $sender->id); $groupUser = $groupUserRepo->findGroupUser($group->id, $applicant->id);
if (!$groupUser) { if (!$groupUser) {
$groupUserModel = new ImChatGroupUserModel(); $groupUserModel = new ImChatGroupUserModel();
$groupUserModel->create([ $groupUserModel->create([
'group_id' => $group->id, 'group_id' => $group->id,
'user_id' => $sender->id, 'user_id' => $applicant->id,
]); ]);
} }
@ -518,7 +543,9 @@ class Messenger extends Service
$itemInfo['status'] = ImSystemMessageModel::REQUEST_ACCEPTED; $itemInfo['status'] = ImSystemMessageModel::REQUEST_ACCEPTED;
$message->update(['item_info' => $itemInfo]); $message->update(['item_info' => $itemInfo]);
$this->handleAcceptGroupNotice($user, $sender, $group); $this->handleAcceptGroupNotice($user, $applicant, $group);
$this->handleNewGroupUserNotice($applicant, $group);
} }
public function refuseGroup() public function refuseGroup()
@ -554,16 +581,18 @@ class Messenger extends Service
$this->handleRefuseGroupNotice($user, $sender); $this->handleRefuseGroupNotice($user, $sender);
} }
protected function pullUnreadFriendMessages($userId) protected function pullUnreadFriendMessages(UserModel $user)
{ {
$userRepo = new UserRepo(); $userRepo = new UserRepo();
$messages = $userRepo->findUnreadImFriendMessages($userId); $messages = $userRepo->findUnreadImFriendMessages($user->id);
if ($messages->count() == 0) { if ($messages->count() == 0) {
return; return;
} }
Gateway::$registerAddress = $this->getRegisterAddress();
$builder = new ImMessageListBuilder(); $builder = new ImMessageListBuilder();
$senders = $builder->getSenders($messages->toArray()); $senders = $builder->getSenders($messages->toArray());
@ -588,16 +617,55 @@ class Messenger extends Service
], ],
]); ]);
Gateway::sendToUid($userId, $content); Gateway::sendToUid($user->id, $content);
} }
} }
protected function handleFriendList($userId) protected function pushFriendOnlineTips(UserModel $user, $status)
{
/**
* 检查间隔,避免频繁提醒干扰
*/
if (time() - $user->update_time < 600) {
return;
}
$userRepo = new UserRepo();
$friendUsers = $userRepo->findImFriendUsers($user->id);
if ($friendUsers->count() == 0) {
return;
}
$friendIds = kg_array_column($friendUsers->toArray(), 'friend_id');
$friends = $userRepo->findByIds($friendIds);
Gateway::$registerAddress = $this->getRegisterAddress();
foreach ($friends as $friend) {
if (Gateway::isUidOnline($friend->id)) {
$content = kg_json_encode([
'type' => 'show_online_tips',
'friend' => [
'id' => $user->id,
'name' => $user->name,
'avatar' => $user->avatar,
],
'status' => $status == 'online' ? 'online' : 'offline',
]);
Gateway::sendToUid($friend->id, $content);
}
}
}
protected function handleFriendList(UserModel $user)
{ {
$userRepo = new UserRepo(); $userRepo = new UserRepo();
$friendGroups = $userRepo->findImFriendGroups($userId); $friendGroups = $userRepo->findImFriendGroups($user->id);
$friendUsers = $userRepo->findImFriendUsers($userId); $friendUsers = $userRepo->findImFriendUsers($user->id);
$items = []; $items = [];
@ -634,7 +702,7 @@ class Messenger extends Service
'username' => $user->name, 'username' => $user->name,
'avatar' => $user->avatar, 'avatar' => $user->avatar,
'sign' => $user->sign, 'sign' => $user->sign,
'status' => 'online', 'status' => $user->online ? 'online' : 'offline',
]; ];
} }
@ -652,11 +720,11 @@ class Messenger extends Service
return $items; return $items;
} }
protected function handleGroupList($userId) protected function handleGroupList(UserModel $user)
{ {
$userRepo = new UserRepo(); $userRepo = new UserRepo();
$groups = $userRepo->findImChatGroups($userId); $groups = $userRepo->findImChatGroups($user->id);
if ($groups->count() == 0) { if ($groups->count() == 0) {
return []; return [];
@ -809,7 +877,7 @@ class Messenger extends Service
$online = Gateway::isUidOnline($receiver->id); $online = Gateway::isUidOnline($receiver->id);
if ($online) { if ($online) {
$content = kg_json_encode(['type' => 'show_sys_msg']); $content = kg_json_encode(['type' => 'refresh_msg_box']);
Gateway::sendToUid($receiver->id, $content); Gateway::sendToUid($receiver->id, $content);
} }
} }
@ -883,7 +951,7 @@ class Messenger extends Service
$online = Gateway::isUidOnline($receiver->id); $online = Gateway::isUidOnline($receiver->id);
if ($online) { if ($online) {
$content = kg_json_encode(['type' => 'show_sys_msg']); $content = kg_json_encode(['type' => 'refresh_msg_box']);
Gateway::sendToUid($receiver->id, $content); Gateway::sendToUid($receiver->id, $content);
} }
} }
@ -932,7 +1000,7 @@ class Messenger extends Service
$online = Gateway::isUidOnline($receiver->id); $online = Gateway::isUidOnline($receiver->id);
if ($online) { if ($online) {
$content = kg_json_encode(['type' => 'show_sys_msg']); $content = kg_json_encode(['type' => 'refresh_msg_box']);
Gateway::sendToUid($receiver->id, $content); Gateway::sendToUid($receiver->id, $content);
} }
} }
@ -992,14 +1060,44 @@ class Messenger extends Service
Gateway::$registerAddress = $this->getRegisterAddress(); Gateway::$registerAddress = $this->getRegisterAddress();
$online = Gateway::isUidOnline($receiver->id); if (Gateway::isUidOnline($receiver->id)) {
$content = kg_json_encode(['type' => 'refresh_msg_box']);
if ($online) {
$content = kg_json_encode(['type' => 'show_sys_msg']);
Gateway::sendToUid($receiver->id, $content); Gateway::sendToUid($receiver->id, $content);
} }
} }
protected function handleNewGroupUserNotice(UserModel $newUser, ImChatGroupModel $group)
{
$groupRepo = new ImChatGroupRepo();
$users = $groupRepo->findGroupUsers($group->id);
if ($users->count() == 0) {
return;
}
Gateway::$registerAddress = $this->getRegisterAddress();
foreach ($users as $user) {
$content = kg_json_encode([
'type' => 'new_group_user',
'user' => [
'id' => $newUser->id,
'name' => $newUser->name,
'avatar' => $newUser->avatar,
],
'group' => [
'id' => $group->id,
'name' => $group->name,
'avatar' => $group->avatar,
],
]);
if (Gateway::isUidOnline($user->id)) {
Gateway::sendToUid($user->id, $content);
}
}
}
protected function getGroupName($groupId) protected function getGroupName($groupId)
{ {
return "group_{$groupId}"; return "group_{$groupId}";

View File

@ -4,6 +4,9 @@
{% for item in pager.items %} {% for item in pager.items %}
<div class="layui-col-md2"> <div class="layui-col-md2">
<div class="user-card"> <div class="user-card">
{% if item.vip == 0 %}
<span class="vip">会员</span>
{% endif %}
<div class="avatar"> <div class="avatar">
<a href="javascript:" title="{{ item.about|e }}"><img src="{{ item.avatar }}" alt="{{ item.name }}"></a> <a href="javascript:" title="{{ item.about|e }}"><img src="{{ item.avatar }}" alt="{{ item.name }}"></a>
</div> </div>

View File

@ -4,6 +4,9 @@
{% for item in pager.items %} {% for item in pager.items %}
<div class="layui-col-md2"> <div class="layui-col-md2">
<div class="user-card"> <div class="user-card">
{% if item.vip == 0 %}
<span class="vip">会员</span>
{% endif %}
<div class="avatar"> <div class="avatar">
<a href="javascript:" title="{{ item.about|e }}"><img src="{{ item.avatar }}" alt="{{ item.name }}"></a> <a href="javascript:" title="{{ item.about|e }}"><img src="{{ item.avatar }}" alt="{{ item.name }}"></a>
</div> </div>

View File

@ -13,7 +13,7 @@
<div class="info"> <div class="info">
<h3>{{ user.name }} {{ vip_flag }}</h3> <h3>{{ user.name }} {{ vip_flag }}</h3>
<p><span><i class="layui-icon layui-icon-location"></i></span><span>{{ user.location }}</span></p> <p><span><i class="layui-icon layui-icon-location"></i></span><span>{{ user.location }}</span></p>
<p><span><i class="layui-icon layui-icon-time"></i></span><span>{{ date('Y-m-d H:i',user.last_login_time) }}</span></p> <p><span><i class="layui-icon layui-icon-time"></i></span><span>{{ date('Y-m-d H:i',user.active_time) }}</span></p>
</div> </div>
{% if user.about %} {% if user.about %}
<div class="about">{{ user.about }}</div> <div class="about">{{ user.about }}</div>

View File

@ -93,7 +93,14 @@ class User extends Model
public $admin_role; public $admin_role;
/** /**
* VIP标识 * 在线标识
*
* @var int
*/
public $online;
/**
* 会员标识
* *
* @var int * @var int
*/ */
@ -113,20 +120,6 @@ class User extends Model
*/ */
public $deleted; public $deleted;
/**
* 最近登录IP
*
* @var string
*/
public $last_login_ip;
/**
* 最近登录时间
*
* @var int
*/
public $last_login_time;
/** /**
* VIP期限 * VIP期限
* *
@ -142,18 +135,11 @@ class User extends Model
public $lock_expiry_time; public $lock_expiry_time;
/** /**
* 关注数量 * 活跃时间
* *
* @var int * @var int
*/ */
public $following_count; public $active_time;
/**
* 粉丝数量
*
* @var int
*/
public $follower_count;
/** /**
* 创建时间 * 创建时间

View File

@ -54,9 +54,6 @@ class User extends Repository
} }
switch ($sort) { switch ($sort) {
case 'popular':
$orderBy = 'follower_count DESC';
break;
default: default:
$orderBy = 'id DESC'; $orderBy = 'id DESC';
break; break;

View File

@ -30,7 +30,7 @@ class UserInfo extends FrontendService
'gender' => $user->gender, 'gender' => $user->gender,
'vip' => $user->vip, 'vip' => $user->vip,
'locked' => $user->locked, 'locked' => $user->locked,
'last_login_time' => $user->last_login_time, 'active_time' => $user->active_time,
'create_time' => $user->create_time, 'create_time' => $user->create_time,
]; ];
} }

View File

@ -1153,6 +1153,7 @@
float: left; float: left;
width: 100%; width: 100%;
height: 220px; height: 220px;
position: relative;
text-align: center; text-align: center;
background-color: #fff; background-color: #fff;
border-radius: 2px; border-radius: 2px;
@ -1184,6 +1185,19 @@
font-size: 12px; font-size: 12px;
} }
.user-card .vip {
position: absolute;
top: 8px;
right: 8px;
padding: 1px 3px;
border-radius: 2px;
text-align: center;
font-size: 12px;
line-height: 1.5em;
background-color: orange;
color: white;
}
.user-card .action span { .user-card .action span {
cursor: pointer; cursor: pointer;
} }
@ -1312,6 +1326,12 @@
padding: 0 5px; padding: 0 5px;
} }
.im-user-list .vip {
top: 5px;
right: 5px;
font-size: 10px;
}
.layim-msgbox { .layim-msgbox {
margin: 15px; margin: 15px;
} }
@ -1324,15 +1344,7 @@
border-bottom: 1px dotted #e2e2e2; border-bottom: 1px dotted #e2e2e2;
} }
.layim-msgbox .layim-msgbox-tips { .layim-msgbox-system {
margin: 0;
padding: 10px 0;
border: none;
text-align: center;
color: #999;
}
.layim-msgbox .layim-msgbox-system {
padding: 0 10px 10px 10px; padding: 0 10px 10px 10px;
} }

View File

@ -23,17 +23,21 @@ layui.use(['jquery', 'layim'], function () {
socket.send('pong...'); socket.send('pong...');
} else if (data.type === 'bind_user') { } else if (data.type === 'bind_user') {
bindUser(data); bindUser(data);
showSystemMessage(); refreshMessageBox();
} else if (data.type === 'new_group_user') {
showNewGroupUserMessage(data);
} else if (data.type === 'show_online_tips') {
showOnlineTips(data);
} else if (data.type === 'show_chat_msg') { } else if (data.type === 'show_chat_msg') {
showChatMessage(data); showChatMessage(data);
} else if (data.type === 'show_sys_msg') { } else if (data.type === 'refresh_msg_box') {
showSystemMessage(); refreshMessageBox();
} else if (data.type === 'friend_accepted') { } else if (data.type === 'friend_accepted') {
friendAccepted(data); friendAccepted(data);
showSystemMessage(); refreshMessageBox();
} else if (data.type === 'group_accepted') { } else if (data.type === 'group_accepted') {
groupAccepted(data); groupAccepted(data);
showSystemMessage(); refreshMessageBox();
} }
}; };
@ -61,6 +65,14 @@ layui.use(['jquery', 'layim'], function () {
sendChatMessage(res); sendChatMessage(res);
}); });
layim.on('online', function (status) {
$.ajax({
type: 'POST',
url: '/im/online/update',
data: {status: status}
});
});
layim.on('sign', function (sign) { layim.on('sign', function (sign) {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
@ -89,7 +101,17 @@ layui.use(['jquery', 'layim'], function () {
layim.getMessage(res.message); layim.getMessage(res.message);
} }
function showSystemMessage() { function showNewGroupUserMessage(res) {
var content = '<a href="/user/' + res.user.id + '" target="_blank">[' + res.user.name + ']</a> 加入群聊';
layim.getMessage({
system: true,
type: 'group',
id: res.group.id,
content: content
});
}
function refreshMessageBox() {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: '/im/msg/unread/count', url: '/im/msg/unread/count',
@ -101,6 +123,16 @@ layui.use(['jquery', 'layim'], function () {
}); });
} }
function showOnlineTips(res) {
var msg = res.friend.name + '上线了';
layer.msg(msg, {
icon: 6,
offset: 'b',
anim: 6
});
layim.setFriendStatus(res.friend.id, res.status);
}
function friendAccepted(res) { function friendAccepted(res) {
layim.addList({ layim.addList({
type: 'friend', type: 'friend',