1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-26 20:52:44 +08:00

设计即时通信结构

This commit is contained in:
xiaochong0302 2020-06-19 20:22:04 +08:00
parent c7cc2210fb
commit 1dce158ee6
15 changed files with 1027 additions and 2 deletions

View File

@ -5,13 +5,232 @@ namespace App\Http\Web\Controllers;
/**
* @RoutePrefix("/im")
*/
class MessengerController extends Controller
class MessengerController extends \Phalcon\Mvc\Controller
{
/**
* @Get("/init", name="web.index")
* @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',
],
],
];
return $this->jsonSuccess(['data' => $data]);
}
/**
* @Get("/group/members", name="im.group_members")
*/
public function groupMembersAction()
{
$data = [
'list' => [
[
'id' => '1000',
'username' => '闲心',
'sign' => '我是如此的不寒而栗',
'status' => 'online',
],
[
'id' => '1001',
'username' => '妹儿美',
'sign' => '我是如此的不寒而栗',
'status' => 'online',
]
]
];
return $this->jsonSuccess(['data' => $data]);
}
/**
* @Get("/msg/box", name="im.msg_box")
*/
public function messageBoxAction()
{
}
/**
* @Get("/chat/log", name="im.chat_log")
*/
public function chatLogAction()
{
}
/**
* @Get("/find", name="im.find")
*/
public function findAction()
{
}
/**
* @Post("/user/bind", name="im.bind_user")
*/
public function bindUserAction()
{
}
/**
* @Post("/msg/send", name="im.send_msg")
*/
public function sendMessageAction()
{
}
/**
* @Post("/img/upload", name="im.upload_img")
*/
public function uploadImageAction()
{
}
/**
* @Post("/file/upload", name="im.upload_file")
*/
public function uploadFileAction()
{
}
/**
* @Post("/stats/update", name="im.update_stats")
*/
public function updateStatsAction()
{
}
/**
* @Post("/sign/update", name="im.update_sign")
*/
public function updateSignAction()
{
}
/**
* @Post("/friend/apply", name="im.apply_friend")
*/
public function applyFriendAction()
{
}
/**
* @Post("/group/apply", name="im.apply_group")
*/
public function applyGroupAction()
{
}
/**
* @Post("/friend/approve", name="im.approve_friend")
*/
public function approveFriendAction()
{
}
/**
* @Post("/group/approve", name="im.approve_group")
*/
public function approveGroupAction()
{
}

View File

@ -31,6 +31,10 @@
{{ js_include('web/js/common.js') }}
{{ js_include('web/js/fixbar.js') }}
{% if auth_user.id > 0 %}
{{ js_include('web/js/im.js') }}
{% endif %}
{% block include_js %}{% endblock %}
{% block inline_js %}{% endblock %}
</body>

101
app/Models/ImChatGroup.php Normal file
View File

@ -0,0 +1,101 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImChatGroup extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 课程编号
*
* @var integer
*/
public $course_id;
/**
* 名称
*
* @var string
*/
public $name;
/**
* 图标
*
* @var string
*/
public $avatar;
/**
* 简介
*
* @var string
*/
public $about;
/**
* 状态
*
* @var integer
*/
public $deleted;
/**
* 成员数
*
* @var integer
*/
public $user_count;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_chat_group';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Models;
class ImChatGroupUser extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 群组编号
*
* @var integer
*/
public $group_id;
/**
* 用户编号
*
* @var integer
*/
public $user_id;
/**
* 优先级
*
* @var integer
*/
public $priority;
/**
* 屏蔽标识
*
* @var integer
*/
public $blocked;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_chat_group_user';
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

65
app/Models/ImFriend.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace App\Models;
class ImFriend extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 用户编号
*
* @var integer
*/
public $user_id;
/**
* 好友编号
*
* @var integer
*/
public $friend_id;
/**
* 屏蔽标识
*
* @var integer
*/
public $blocked;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_friend';
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImFriendGroup extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 名称
*
* @var string
*/
public $name;
/**
* 优先级
*
* @var integer
*/
public $priority;
/**
* 状态
*
* @var integer
*/
public $deleted;
/**
* 成员数
*
* @var integer
*/
public $user_count;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_friend_group';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Models;
class ImFriendGroupUser extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 分组编号
*
* @var integer
*/
public $group_id;
/**
* 用户编号
*
* @var integer
*/
public $user_id;
/**
* 优先级
*
* @var integer
*/
public $priority;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_friend_group_user';
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

96
app/Models/ImMessage.php Normal file
View File

@ -0,0 +1,96 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImMessage extends Model
{
const TYPE_FRIEND = 1; // 私聊
const TYPE_GROUP = 2; // 群聊
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 类型
*
* @var integer
*/
public $type;
/**
* 发送方编号
*
* @var integer
*/
public $sender_id;
/**
* 接收方编号
*
* @var integer
*/
public $receiver_id;
/**
* 内容编号
*
* @var string
*/
public $content_id;
/**
* 删除标识
*
* @var integer
*/
public $deleted;
/**
* 创建时间
*
* @var integer
*/
public $create_time;
/**
* 更新时间
*
* @var integer
*/
public $update_time;
public function getSource()
{
return 'kg_im_message';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Models;
class ImMessageContent extends Model
{
/**
* 主键编号
*
* @var integer
*/
public $id;
/**
* 内容
*
* @var string
*/
public $content;
public function getSource()
{
return 'kg_im_message_content';
}
}

View File

@ -50,6 +50,13 @@ class User extends Model
*/
public $title;
/**
* 签名
*
* @var string
*/
public $sign;
/**
* 介绍
*

77
app/Repos/ImChat.php Normal file
View File

@ -0,0 +1,77 @@
<?php
namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImMessage as ImChatModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class ImChat extends Repository
{
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{
$builder = $this->modelsManager->createBuilder();
$builder->from(ImChatModel::class);
$builder->where('1 = 1');
if (!empty($where['sender_id'])) {
$builder->andWhere('sender_id = :sender_id:', ['sender_id' => $where['sender_id']]);
}
if (!empty($where['receiver_id'])) {
$builder->andWhere('receiver_id = :receiver_id:', ['receiver_id' => $where['receiver_id']]);
}
if (!empty($where['type'])) {
$builder->andWhere('type = :type:', ['type' => $where['type']]);
}
if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
switch ($sort) {
default:
$orderBy = 'id DESC';
break;
}
$builder->orderBy($orderBy);
$pager = new PagerQueryBuilder([
'builder' => $builder,
'page' => $page,
'limit' => $limit,
]);
return $pager->paginate();
}
/**
* @param int $id
* @return ImChatModel|Model|bool
*/
public function findById($id)
{
return ImChatModel::findFirst($id);
}
/**
* @param array $ids
* @param string|array $columns
* @return ResultsetInterface|Resultset|ImChatModel[]
*/
public function findByIds($ids, $columns = '*')
{
return ImChatModel::query()
->columns($columns)
->inWhere('id', $ids)
->execute();
}
}

90
app/Repos/ImGroup.php Normal file
View File

@ -0,0 +1,90 @@
<?php
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\User as UserModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class ImGroup extends Repository
{
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{
$builder = $this->modelsManager->createBuilder();
$builder->from(ImGroupModel::class);
$builder->where('1 = 1');
if (!empty($where['course_id'])) {
$builder->andWhere('sender_id = :sender_id:', ['sender_id' => $where['sender_id']]);
}
if (!empty($where['name'])) {
$builder->andWhere('name LIKE :name:', ['name' => "%{$where['name']}%"]);
}
if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
switch ($sort) {
default:
$orderBy = 'id DESC';
break;
}
$builder->orderBy($orderBy);
$pager = new PagerQueryBuilder([
'builder' => $builder,
'page' => $page,
'limit' => $limit,
]);
return $pager->paginate();
}
/**
* @param int $id
* @return ImGroupModel|Model|bool
*/
public function findById($id)
{
return ImGroupModel::findFirst($id);
}
/**
* @param array $ids
* @param string|array $columns
* @return ResultsetInterface|Resultset|ImGroupModel[]
*/
public function findByIds($ids, $columns = '*')
{
return ImGroupModel::query()
->columns($columns)
->inWhere('id', $ids)
->execute();
}
/**
* @param int $groupId
* @return ResultsetInterface|Resultset|UserModel[]
*/
public function findGroupUsers($groupId)
{
return $this->modelsManager->createBuilder()
->columns('u.*')
->addFrom(UserModel::class, 'u')
->join(ImGroupUserModel::class, 'u.id = gu.user_id', 'gu')
->where('gu.group_id = :group_id:', ['group_id' => $groupId])
->andWhere('u.deleted = 0')
->getQuery()->execute();
}
}

View File

@ -3,6 +3,8 @@
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\User as UserModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
@ -111,4 +113,20 @@ class User extends Repository
->execute();
}
public function findImFriends($userId)
{
}
public function findImGroups($userId)
{
return $this->modelsManager->createBuilder()
->columns('g.*')
->addFrom(ImGroupModel::class, 'g')
->join(ImGroupUserModel::class, 'g.id = gu.user_id', 'gu')
->where('gu.user_id = :user_id:', ['user_id' => $userId])
->andWhere('g.deleted = 0')
->getQuery()->execute();
}
}

View File

@ -0,0 +1,19 @@
<?php
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)
{
}
}

View File

@ -0,0 +1,76 @@
layui.use(['jquery', 'layim'], function () {
var $ = layui.jquery;
var layim = layui.layim;
var socket = new WebSocket('ws://127.0.0.1:8282');
layim.config({
title: '即时聊天',
init: {
url: '/im/init'
},
members: {
url: '/im/group/members'
},
uploadImage: {
url: '/im/img/upload'
},
uploadFile: {
url: '/im/file/upload'
},
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);
});
function bindUser(clientId) {
$.ajax({
type: 'POST',
url: '/im/user/bind',
data: {client_id: clientId}
});
}
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);
}
}
});