1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-07-24 00:41:43 +08:00

设计消息盒子

This commit is contained in:
xiaochong0302 2020-06-23 20:28:04 +08:00
parent 148d2fdc4d
commit 9185eb0731
15 changed files with 470 additions and 61 deletions

View File

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

View File

@ -48,9 +48,11 @@ class ImHotUserList extends Cache
'name' => $user->name,
'avatar' => $user->avatar,
'about' => $user->about,
'sign' => $user->sign,
'location' => $user->location,
'gender' => $user->gender,
'vip' => $user->vip,
'follower_count' => $user->follower_count,
'following_count' => $user->following_count,
];
}

View File

@ -94,20 +94,26 @@ class MessengerController extends LayerController
*/
public function searchAction()
{
$query = $this->request->getQuery('query', ['trim', 'string']);
$type = $this->request->getQuery('type', ['trim', 'string']);
$type = $this->request->getQuery('type');
$query = $this->request->getQuery('query');
$target = $this->request->getQuery('target');
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$service = new MessengerService();
if ($type == 'user') {
$pager = $service->searchUsers($query);
$this->view->pick('messenger/find_users');
$target = $target ?: 'tab-users';
$pager = $service->searchUsers($query);
} else {
$pager = $service->searchGroups($query);
$this->view->pick('messenger/find_groups');
$target = $target ?: 'tab-groups';
$pager = $service->searchGroups($query);
}
$pager->items = kg_array_object($pager->items);
$pager->target = $target;
$this->view->setVar('pager', $pager);
}
@ -200,17 +206,17 @@ class MessengerController extends LayerController
}
/**
* @Post("/friend/approve", name="web.im.approve_friend")
* @Post("/friend/accept", name="web.im.accept_friend")
*/
public function approveFriendAction()
public function acceptFriendAction()
{
}
/**
* @Post("/group/approve", name="web.web.im.approve_group")
* @Post("/group/accept", name="web.web.im.accept_group")
*/
public function approveGroupAction()
public function acceptGroupAction()
{
}

View File

@ -8,12 +8,15 @@ use App\Caches\ImHotUserList as ImHotUserListCache;
use App\Library\Paginator\Query as PagerQuery;
use App\Models\ImFriendMessage as ImFriendMessageModel;
use App\Models\ImFriendUser as ImFriendUserModel;
use App\Models\ImSystemMessage as ImSystemMessageModel;
use App\Models\User as UserModel;
use App\Repos\ImChatGroup as ImChatGroupRepo;
use App\Repos\ImFriendMessage as ImFriendMessageRepo;
use App\Repos\ImFriendUser as ImFriendUserRepo;
use App\Repos\ImGroupMessage as ImGroupMessageRepo;
use App\Repos\User as UserRepo;
use App\Validators\ImChatGroup as ImChatGroupValidator;
use App\Validators\ImFriendUser as ImFriendUserValidator;
use App\Validators\ImMessage as ImMessageValidator;
use App\Validators\User as UserValidator;
use GatewayClient\Gateway;
@ -44,14 +47,42 @@ class Messenger extends Service
];
}
public function searchUsers($query)
public function searchUsers($name)
{
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$params['name'] = $name;
$sort = $pagerQuery->getSort();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$userRepo = new UserRepo();
$pager = $userRepo->paginate($params, $sort, $page, $limit);
return $this->handleUserPager($pager);
}
public function searchGroups($query)
public function searchGroups($name)
{
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$params['name'] = $name;
$sort = $pagerQuery->getSort();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$groupRepo = new ImChatGroupRepo();
$pager = $groupRepo->paginate($params, $sort, $page, $limit);
return $this->handleGroupPager($pager);
}
public function getHotUsers()
@ -141,7 +172,7 @@ class Messenger extends Service
$pager = $messageRepo->paginate($params, $sort, $page, $limit);
return $this->handleChatLog($pager);
return $this->handleChatLogPager($pager);
} elseif ($params['type'] == 'group') {
@ -151,7 +182,7 @@ class Messenger extends Service
$pager = $messageRepo->paginate($params, $sort, $page, $limit);
return $this->handleChatLog($pager);
return $this->handleChatLogPager($pager);
}
}
@ -207,7 +238,7 @@ class Messenger extends Service
}
$message = json_encode([
'type' => 'show_message',
'type' => 'show_chat_msg',
'content' => $content,
]);
@ -256,13 +287,19 @@ class Messenger extends Service
public function applyFriend()
{
$friendId = $this->request->getPost('friend_id');
$post = $this->request->getPost();
$user = $this->getLoginUser();
$userValidator = new UserValidator();
$validator = new ImFriendUserValidator();
$friend = $userValidator->checkUser($friendId);
$friend = $validator->checkFriend($post['friend_id']);
$group = $validator->checkGroup($post['group_id']);
$remark = $validator->checkRemark($post['remark']);
$validator->checkIfSelfApply($user->id, $friend->id);
$validator->checkIfJoined($user->id, $friend->id);
$validator->checkIfBlocked($user->id, $friend->id);
$friendUserRepo = new ImFriendUserRepo();
@ -272,23 +309,26 @@ class Messenger extends Service
$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();
}
/**
* @todo 向对方发好友申请的系统消息
*/
$this->handleApplyFriendNotice($user, $friend, $remark);
}
public function approveFriend()
public function acceptFriend()
{
$friendId = $this->request->getPost('friend_id');
$post = $this->request->getPost();
$user = $this->getLoginUser();
$userValidator = new UserValidator();
$validator = new ImFriendUserValidator();
$friend = $userValidator->checkUser($friendId);
$friend = $validator->checkFriend($post['friend_id']);
$group = $validator->checkGroup($post['group_id']);
$friendUserRepo = new ImFriendUserRepo();
@ -298,12 +338,11 @@ class Messenger extends Service
$model = new ImFriendUserModel();
$model->user_id = $user->id;
$model->friend_id = $friend->id;
$model->group_id = $group->id;
$model->create();
}
/**
* @todo 向对方发通过好友申请的系统消息
*/
$this->handleAcceptFriendNotice();
}
public function refuseFriend()
@ -325,7 +364,7 @@ class Messenger extends Service
{
}
public function approveGroup()
public function acceptGroup()
{
}
@ -342,11 +381,20 @@ class Messenger extends Service
$items = [];
$items[] = ['id' => 0, 'groupname' => '我的好友', 'list' => []];
$items[] = [
'id' => 0,
'groupname' => '我的好友',
'list' => [],
];
if ($friendGroups->count() > 0) {
foreach ($friendGroups as $group) {
$items[] = ['id' => $group->id, 'groupname' => $group->name, 'online' => 0, 'list' => []];
$items[] = [
'id' => $group->id,
'groupname' => $group->name,
'online' => 0,
'list' => [],
];
}
}
@ -410,7 +458,7 @@ class Messenger extends Service
return $result;
}
protected function handleChatLog($pager)
protected function handleChatLogPager($pager)
{
if ($pager->total_items == 0) {
return $pager;
@ -442,6 +490,135 @@ class Messenger extends Service
return $pager;
}
protected function handleUserPager($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$users = $pager->items->toArray();
$baseUrl = kg_ci_base_url();
$items = [];
foreach ($users as $user) {
$user['avatar'] = $baseUrl . $user['avatar'];
$items[] = [
'id' => $user['id'],
'name' => $user['name'],
'avatar' => $user['avatar'],
'about' => $user['about'],
'location' => $user['location'],
'gender' => $user['gender'],
'vip' => $user['vip'],
'follower_count' => $user['follower_count'],
'following_count' => $user['following_count'],
];
}
$pager->items = $items;
return $pager;
}
protected function handleGroupPager($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$groups = $pager->items->toArray();
$baseUrl = kg_ci_base_url();
$items = [];
foreach ($groups as $group) {
$group['avatar'] = $baseUrl . $group['avatar'];
$items[] = [
'id' => $group['id'],
'name' => $group['name'],
'avatar' => $group['avatar'],
'about' => $group['about'],
'user_count' => $group['user_count'],
];
}
$pager->items = $items;
return $pager;
}
protected function handleApplyFriendNotice(UserModel $user, UserModel $friend, $remark)
{
$sysMsgModel = new ImSystemMessageModel();
$sysMsgModel->user_id = $friend->id;
$sysMsgModel->item_id = $user->id;
$sysMsgModel->item_type = ImSystemMessageModel::TYPE_APPLY_FRIEND;
$sysMsgModel->item_info = [
'user' => ['id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar],
'remark' => $remark,
];
$sysMsgModel->create();
Gateway::$registerAddress = '127.0.0.1:1238';
$online = Gateway::isUidOnline($friend->id);
if ($online) {
$userRepo = new UserRepo();
$msgCount = $userRepo->countUnreadImSystemMessages($friend->id);
$message = kg_json_encode([
'type' => 'show_msg_box',
'content' => ['msg_count' => $msgCount],
]);
Gateway::sendToUid($friend->id, $message);
}
}
protected function handleAcceptFriendNotice(UserModel $user, UserModel $friend)
{
$sysMsgModel = new ImSystemMessageModel();
$sysMsgModel->user_id = $friend->id;
$sysMsgModel->item_id = $user->id;
$sysMsgModel->item_type = ImSystemMessageModel::TYPE_FRIEND_APPROVED;
$sysMsgModel->item_info = [
'user' => ['id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar],
];
$sysMsgModel->create();
Gateway::$registerAddress = '127.0.0.1:1238';
$online = Gateway::isUidOnline($friend->id);
if ($online) {
$userRepo = new UserRepo();
$msgCount = $userRepo->countUnreadImSystemMessages($friend->id);
$message = kg_json_encode([
'type' => 'show_msg_box',
'content' => ['msg_count' => $msgCount],
]);
Gateway::sendToUid($friend->id, $message);
}
}
protected function handleRefuseFriendNotice()
{
}
protected function getGroupName($groupId)
{
return "group_{$groupId}";

View File

@ -3,8 +3,9 @@
{% block content %}
<div class="im-search">
<form class="layui-form" action="{{ url({'for':'web.im.search'}) }}">
<input class="layui-input" type="text" name="query" value="{{ request.get('query')|striptags }}" placeholder="请输入关键字...">
<form class="layui-form" method="get" action="{{ url({'for':'web.im.find'}) }}">
<input class="layui-input" type="text" name="query" placeholder="请输入关键字...">
<button class="layui-hide" type="submit" lay-submit="true" lay-filter="im_search">搜索</button>
</form>
</div>

View File

@ -9,7 +9,7 @@
</div>
<div class="name layui-elip" title="{{ item.name|e }}">{{ item.name }}</div>
<div class="action">
<a href="javascript:" class="layui-badge-rim apply-friend" data-id="{{ item.id }}">加为好友</a>
<a href="javascript:" class="layui-badge-rim apply-friend" data-id="{{ item.id }}" data-name="{{ item.name }}" data-avatar="{{ item.avatar }}">加为好友</a>
</div>
</div>
</div>

View File

@ -0,0 +1,127 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImSystemMessage extends Model
{
const TYPE_APPLY_FRIEND = 1;
const TYPE_APPLY_GROUP = 2;
const TYPE_FRIEND_ACCEPTED = 3;
const TYPE_FRIEND_REFUSED = 4;
const TYPE_GROUP_ACCEPTED = 5;
const TYPE_GROUP_REFUSED = 6;
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 发送方编号
*
* @var integer
*/
public $sender_id;
/**
* 接收方编号
*
* @var integer
*/
public $receiver_id;
/**
* 条目类型
*
* @var string
*/
public $item_type;
/**
* 条目内容
*
* @var string
*/
public $item_info;
/**
* 优先级
*
* @var integer
*/
public $priority;
/**
* 阅读标识
*
* @var integer
*/
public $viewed;
/**
* 删除标识
*
* @var integer
*/
public $deleted;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_system_message';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
if (!empty($this->item_info)) {
$this->item_info = kg_json_encode($this->item_info);
} else {
$this->item_info = '';
}
}
public function beforeUpdate()
{
$this->update_time = time();
}
public function afterFetch()
{
if (!empty($this->item_info)) {
$this->item_info = json_decode($this->item_info, true);
}
}
}

View File

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

View File

@ -7,6 +7,7 @@ use App\Models\ImChatGroup as ImChatGroupModel;
use App\Models\ImChatGroupUser as ImChatGroupUserModel;
use App\Models\ImFriendGroup as ImFriendGroupModel;
use App\Models\ImFriendUser as ImFriendUserModel;
use App\Models\ImSystemMessage as ImSystemMessageModel;
use App\Models\User as UserModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
@ -52,6 +53,9 @@ class User extends Repository
}
switch ($sort) {
case 'popular':
$orderBy = 'follower_count DESC';
break;
default:
$orderBy = 'id DESC';
break;
@ -153,4 +157,12 @@ class User extends Repository
->getQuery()->execute();
}
public function countUnreadImSystemMessages($userId)
{
return ImSystemMessageModel::count([
'conditions' => 'user_id = ?1 AND viewed = ?2',
'bind' => [1 => $userId, 2 => 0],
]);
}
}

View File

@ -3,11 +3,61 @@
namespace App\Validators;
use App\Exceptions\BadRequest as BadRequestException;
use App\Models\ImFriendGroup as ImFriendGroupModel;
use App\Repos\ImFriendGroup as ImFriendGroupRepo;
use App\Repos\ImFriendUser as ImFriendUserRepo;
use App\Repos\User as UserRepo;
class ImFriendUser extends Validator
{
public function checkFriend($id)
{
$repo = new UserRepo();
$user = $repo->findById($id);
if (!$user) {
throw new BadRequestException('im_friend_user.user_not_found');
}
return $user;
}
public function checkGroup($id)
{
/**
* 返回默认分组
*/
if (empty($id)) {
$group = new ImFriendGroupModel();
$group->id = 0;
$group->name = '我的好友';
return $group;
}
$repo = new ImFriendGroupRepo();
$group = $repo->findById($id);
if (!$group) {
throw new BadRequestException('im_friend_user.group_not_found');
}
return $group;
}
public function checkRemark($remark)
{
$value = $this->filter->sanitize($remark, ['trim', 'string']);
$length = kg_strlen($value);
if ($length > 30) {
throw new BadRequestException('im_friend_user.remark_too_long');
}
}
public function checkIfSelfApply($userId, $friendId)
{
if ($userId == $friendId) {
@ -19,7 +69,7 @@ class ImFriendUser extends Validator
{
$repo = new ImFriendUserRepo();
$record = $repo->findFriendUser($userId, $friendId);
$record = $repo->findFriendUser($friendId, $userId);
if ($record && $record->blocked == 0) {
throw new BadRequestException('im_friend_user.has_joined');
@ -30,7 +80,7 @@ class ImFriendUser extends Validator
{
$repo = new ImFriendUserRepo();
$record = $repo->findFriendUser($userId, $friendId);
$record = $repo->findFriendUser($friendId, $userId);
if ($record && $record->blocked == 1) {
throw new BadRequestException('im_friend_user.blocked');

View File

@ -340,11 +340,13 @@ $error['im_chat_group.name_too_long'] = '群组名太长超过30字符';
$error['im_chat_group.about_too_long'] = '群组简介太长超过255字符';
$error['im_chat_group_user.has_joined'] = '已经加入过群组';
$error['im_chat_group_user.blocked'] = '被群组屏蔽';
$error['im_chat_group_user.blocked'] = '对方拒绝接收消息';
$error['im_friend_user.user_not_found'] = '用户不存在';
$error['im_friend_user.remark_too_long'] = '验证信息太长超过30字符';
$error['im_friend_user.self_apply'] = '不能添加自己为好友';
$error['im_friend_user.has_joined'] = '已经是好友啦';
$error['im_friend_user.blocked'] = '被对方屏蔽';
$error['im_friend_user.blocked'] = '对方拒绝接收消息';
$error['im_message.not_found'] = '消息不存在';
$error['im_message.invalid_type'] = '无效的消息类型';

View File

@ -15,7 +15,6 @@
position: relative;
margin-bottom: 10px;
padding: 0 130px 10px 60px;
padding-bottom: 10px;
line-height: 22px;
border-bottom: 1px dotted #e2e2e2;
}

View File

@ -1138,12 +1138,11 @@
}
.learning-course-card .progress {
width: 260px;
padding: 15px 0 15px 5px;
padding-top: 15px;
padding-bottom: 10px;
}
.learning-course-card .duration {
padding: 0 5px;
font-size: 12px;
color: #666;
}

View File

@ -1,25 +1,49 @@
layui.use(['jquery', 'layer'], function () {
layui.use(['jquery', 'form', 'layer', 'layim'], function () {
var $ = layui.jquery;
var form = layui.form;
var layer = layui.layer;
var layim = layui.layim;
$('.apply-friend').on('click', function () {
form.on('submit(im_search)', function (data) {
var usersUrl = '/im/search?limit=12&target=tab-users&type=user&query=' + data.field.query;
var groupsUrl = '/im/search?limit=12&target=tab-groups&type=group&query=' + data.field.query;
layui.ajaxLoadHtml(usersUrl, 'tab-users');
layui.ajaxLoadHtml(groupsUrl, 'tab-groups');
return false;
});
$('body').on('click', '.apply-friend', function () {
var friendId = $(this).attr('data-id');
$.ajax({
type: 'POST',
url: '/im/friend/apply',
data: {friend_id: friendId},
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 username = $(this).attr('data-name');
var avatar = $(this).attr('data-avatar');
layim.add({
type: 'friend',
username: username,
avatar: avatar,
submit: function (groupId, remark, index) {
$.ajax({
type: 'POST',
url: '/im/friend/apply',
data: {
friend_id: friendId,
group_id: groupId,
remark: remark
},
success: function (res) {
layer.msg(res.msg, {icon: 1});
},
error: function (xhr) {
var res = JSON.parse(xhr.responseText);
layer.msg(res.msg, {icon: 2});
}
});
layer.close(index);
}
});
});
$('.apply-group').on('click', function () {
$('body').on('click', '.apply-group', function () {
var groupId = $(this).attr('data-id');
$.ajax({
type: 'POST',

View File

@ -23,8 +23,10 @@ layui.use(['jquery', 'layim'], function () {
socket.send('pong...');
} else if (data.type === 'bind_user') {
bindUser(data.client_id);
} else if (data.type === 'show_message') {
showMessage(data.content);
} else if (data.type === 'show_chat_msg') {
showChatMessage(data.content);
} else if (data.type === 'show_msg_box') {
showMessageBox(data.content);
}
};
@ -49,7 +51,7 @@ layui.use(['jquery', 'layim'], function () {
});
layim.on('sendMessage', function (res) {
sendMessage(res.mine, res.to);
sendChatMessage(res.mine, res.to);
});
layim.on('sign', function (sign) {
@ -68,7 +70,7 @@ layui.use(['jquery', 'layim'], function () {
});
}
function sendMessage(from, to) {
function sendChatMessage(from, to) {
$.ajax({
type: 'POST',
url: '/im/msg/send',
@ -76,8 +78,12 @@ layui.use(['jquery', 'layim'], function () {
});
}
function showMessage(message) {
layim.getMessage(message);
function showChatMessage(content) {
layim.getMessage(content);
}
function showMessageBox(content) {
layim.msgbox(content.msg_count);
}
});