优化代码

main
gzydong 2021-07-05 21:52:44 +08:00
parent 4f895da1f0
commit f04fea506d
45 changed files with 1701 additions and 1254 deletions

109
LumenIM 同步SQL.sql Normal file
View File

@ -0,0 +1,109 @@
# lar_users_chat_list 数据表同步SQL
ALTER TABLE `lar_users_chat_list` RENAME `lar_talk_list`;
ALTER TABLE `lar_talk_list` DROP INDEX `idx_uid_type_friendid_group_id`;
ALTER TABLE `lar_talk_list` MODIFY `is_top` tinyint(4) unsigned DEFAULT '0' COMMENT '是否置顶[0:否;1:是;]';
ALTER TABLE `lar_talk_list` CHANGE `type` `talk_type` tinyint(3) unsigned DEFAULT '1' COMMENT '聊天类型[1:私信;2:群聊;]';
ALTER TABLE `lar_talk_list` CHANGE `uid` `user_id` int(11) DEFAULT '0' COMMENT '用户ID';
ALTER TABLE `lar_talk_list` CHANGE `not_disturb` `is_disturb` tinyint(4) unsigned DEFAULT '0' COMMENT '消息免打扰[0:否;1:是;]';
ALTER TABLE `lar_talk_list` ADD `receiver_id` int(11) unsigned DEFAULT '0' COMMENT '接收者ID用户ID 或 群ID';
ALTER TABLE `lar_talk_list` ADD `is_delete` tinyint(4) unsigned DEFAULT '0' COMMENT '是否删除[0:否;1:是;]';
ALTER TABLE `lar_talk_list` ADD `is_robot` tinyint(4) unsigned DEFAULT '0' COMMENT '是否机器人[0:否;1:是;]';
ALTER TABLE `lar_talk_list` ADD INDEX idx_user_id_receiver_id_talk_type (`user_id`,`receiver_id`,`talk_type`);
UPDATE `lar_talk_list` set `receiver_id` = if(`talk_type` = 1,`friend_id`,`group_id`),`is_delete` = if(`status` = 1,0,1);
ALTER TABLE `lar_talk_list` DROP COLUMN `friend_id`;
ALTER TABLE `lar_talk_list` DROP COLUMN `group_id`;
ALTER TABLE `lar_talk_list` DROP COLUMN `status`;
# lar_emoticon 数据表同步SQL
ALTER TABLE `lar_emoticon` MODIFY `name` varchar(50) NOT NULL DEFAULT '' COMMENT '分组名称';
ALTER TABLE `lar_emoticon` CHANGE `url` `icon` varchar(255) DEFAULT '' COMMENT '分组图标';
ALTER TABLE `lar_emoticon` ADD `status` tinyint(4) DEFAULT '0' COMMENT '分组状态[-1:已删除;0:正常;1:已禁用;]';
ALTER TABLE `lar_emoticon` ADD `updated_at` datetime DEFAULT NULL COMMENT '更新时间';
ALTER TABLE `lar_emoticon` DROP INDEX `name`;
ALTER TABLE `lar_emoticon` ADD UNIQUE uk_name (`name`);
# lar_emoticon_details 数据表同步SQL
ALTER TABLE `lar_emoticon_details` RENAME `lar_emoticon_item`;
ALTER TABLE `lar_emoticon_item` MODIFY `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '表情包详情ID';
ALTER TABLE `lar_emoticon_item` MODIFY `describe` varchar(20) DEFAULT '' COMMENT '表情描述';
ALTER TABLE `lar_emoticon_item` MODIFY `url` varchar(255) DEFAULT '' COMMENT '图片链接';
ALTER TABLE `lar_emoticon_item` ADD `updated_at` datetime DEFAULT NULL COMMENT '更新时间';
ALTER TABLE `lar_emoticon_item` comment '表情包详情表';
# lar_users 数据表同步SQL
ALTER TABLE `lar_users` ADD `is_robot` tinyint(4) unsigned DEFAULT '0' COMMENT '是否机器人[0:否;1:是;]';
ALTER TABLE `lar_users` ADD `updated_at` datetime DEFAULT NULL COMMENT '更新时间';
# lar_chat_records 数据表同步SQL
ALTER TABLE `lar_chat_records` RENAME `lar_talk_records`;
ALTER TABLE `lar_talk_records` DROP INDEX `idx_userid_receiveid`;
ALTER TABLE `lar_talk_records` CHANGE `source` `talk_type` tinyint(3) unsigned DEFAULT '1' COMMENT '对话类型[1:私信;2:群聊;]';
ALTER TABLE `lar_talk_records` MODIFY `msg_type` tinyint(3) unsigned DEFAULT '1' COMMENT '消息类型[1:文本消息;2:文件消息;3:会话消息;4:代码消息;5:投票消息;6:群公告;7:好友申请;8:登录通知;9:入群消息/退群消息;]';
ALTER TABLE `lar_talk_records` CHANGE `receive_id` `receiver_id` int(11) unsigned DEFAULT '0' COMMENT '接收者ID用户ID 或 群ID';
ALTER TABLE `lar_talk_records` MODIFY `is_revoke` tinyint(4) unsigned DEFAULT '0' COMMENT '是否撤回消息[0:否;1:是;]';
ALTER TABLE `lar_talk_records` MODIFY `content` text CHARACTER SET utf8mb4 COMMENT '文本消息 {@nickname@}';
ALTER TABLE `lar_talk_records` ADD `is_mark` tinyint(4) unsigned DEFAULT '0' COMMENT '是否重要消息[0:否;1:是;]';
ALTER TABLE `lar_talk_records` ADD `is_read` tinyint(4) DEFAULT '0' COMMENT '是否已读[0:否;1:是;]';
ALTER TABLE `lar_talk_records` ADD `quote_id` int(11) unsigned DEFAULT '0' COMMENT '引用消息ID';
ALTER TABLE `lar_talk_records` ADD `warn_users` varchar(200) NOT NULL DEFAULT '' COMMENT '@好友 、 多个用英文逗号 “,” 拼接 (0:代表所有人)';
ALTER TABLE `lar_talk_records` ADD `updated_at` datetime DEFAULT NULL COMMENT '更新时间';
ALTER TABLE `lar_talk_records` ADD INDEX idx_user_id_receiver_id (`user_id`,`receiver_id`);
UPDATE `lar_talk_records` SET `msg_type` = CASE WHEN msg_type = 3 THEN 9 WHEN msg_type = 4 THEN 3 WHEN msg_type = 5 THEN 4 ELSE msg_type END;
ALTER TABLE `lar_chat_records_code` RENAME `lar_talk_records_code`;
ALTER TABLE `lar_chat_records_delete` RENAME `lar_talk_records_delete`;
ALTER TABLE `lar_chat_records_forward` RENAME `lar_talk_records_forward`;
ALTER TABLE `lar_chat_records_invite` RENAME `lar_talk_records_invite`;
ALTER TABLE `lar_chat_records_file` RENAME `lar_talk_records_file`;
# lar_users_friends 数据表同步SQL
ALTER TABLE `lar_users_friends` MODIFY `active` tinyint(3) unsigned DEFAULT '1' COMMENT '主动好友申请方[1:user1;2:user2;]';
ALTER TABLE `lar_users_friends` MODIFY `status` tinyint(3) DEFAULT '0' COMMENT '好友状态 [-1:双方均解除好友关系;0:正常;1:user1 已删除对方;2:user2 已删除对方;]';
ALTER TABLE `lar_users_friends` CHANGE `agree_time` `updated_at` datetime DEFAULT NULL COMMENT '更新时间';
UPDATE `lar_users_friends` SET `status` = CASE WHEN `status` = 0 THEN -1 WHEN `status` = 1 THEN 0 ELSE `status` END;
# lar_users_friends_apply 数据表同步SQL
ALTER TABLE `lar_users_friends_apply` MODIFY `status` tinyint(4) unsigned DEFAULT '0' COMMENT '申请状态[0:等待处理;1:已同意;2:已拒绝;]';
-- ----------------------------
-- 以下是新增数据表
-- ----------------------------
CREATE TABLE `lar_robots` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '机器人ID',
`user_id` int(11) unsigned DEFAULT '0' COMMENT '关联用户ID',
`robot_name` varchar(20) NOT NULL DEFAULT '' COMMENT '机器人名称',
`describe` varchar(255) DEFAULT '' COMMENT '描述信息',
`logo` varchar(255) DEFAULT '' COMMENT '机器人logo',
`is_talk` tinyint(4) DEFAULT '0' COMMENT '可发送消息[0:否;1:是;]',
`status` tinyint(4) unsigned DEFAULT '0' COMMENT '状态[-1:已删除;0:正常;1:已禁用;]',
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='聊天机器人表';
CREATE TABLE `lar_talk_records_vote` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '投票ID',
`record_id` int(11) unsigned DEFAULT '0' COMMENT '消息记录ID',
`user_id` int(11) unsigned DEFAULT '0' COMMENT '用户ID',
`title` varchar(50) DEFAULT '' COMMENT '投票标题',
`answer_mode` tinyint(4) unsigned DEFAULT '0' COMMENT '答题模式[0:单选;1:多选;]',
`answer_option` json DEFAULT NULL COMMENT '答题选项',
`answer_num` smallint(6) unsigned DEFAULT '0' COMMENT '应答人数',
`answered_num` smallint(6) unsigned DEFAULT '0' COMMENT '已答人数',
`status` tinyint(4) unsigned DEFAULT '0' COMMENT '投票状态[0:投票中;1:已完成;]',
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_record_id` (`record_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='聊天对话记录(投票消息表)';
CREATE TABLE `lar_talk_records_vote_answer` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '答题ID',
`vote_id` int(11) unsigned DEFAULT '0' COMMENT '投票ID',
`user_id` int(11) unsigned DEFAULT '0' COMMENT '用户ID',
`option` char(1) NOT NULL DEFAULT '' COMMENT '投票选项[A、B、C 、D、E、F]',
`created_at` datetime DEFAULT NULL COMMENT '答题时间',
PRIMARY KEY (`id`),
KEY `idx_vote_id_user_id` (`vote_id`,`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='聊天对话记录(投票消息统计表)';

View File

@ -11,6 +11,8 @@ declare(strict_types=1);
namespace App\Amqp\Consumer;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Message\ConsumerMessage;
@ -19,11 +21,11 @@ use Hyperf\Amqp\Builder\QueueBuilder;
use PhpAmqpLib\Message\AMQPMessage;
use App\Model\User;
use App\Model\UsersFriend;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsCode;
use App\Model\Chat\ChatRecordsFile;
use App\Model\Chat\ChatRecordsInvite;
use App\Model\Chat\ChatRecordsForward;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsCode;
use App\Model\Chat\TalkRecordsFile;
use App\Model\Chat\TalkRecordsInvite;
use App\Model\Chat\TalkRecordsForward;
use App\Model\Group\Group;
use App\Service\SocketClientService;
use App\Constants\SocketConstants;
@ -140,39 +142,43 @@ class ChatMessageConsumer extends ConsumerMessage
*/
public function onConsumeTalk(array $data, AMQPMessage $message): string
{
$source = $data['data']['source'];
$talk_type = $data['data']['talk_type'];
$sender_id = $data['data']['sender_id'];
$receiver_id = $data['data']['receiver_id'];
$record_id = $data['data']['record_id'];
$fds = [];
$groupInfo = null;
if ($source == 1) {// 私聊
if ($talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge(
$this->socketClientService->findUserFds($data['data']['sender']),
$this->socketClientService->findUserFds($data['data']['receive'])
$this->socketClientService->findUserFds($sender_id),
$this->socketClientService->findUserFds($receiver_id)
);
} else if ($source == 2) {// 群聊
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($data['data']['receive']));
foreach ($userIds as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$uid));
} else if ($talk_type == TalkType::GROUP_CHAT) {
foreach (SocketRoom::getInstance()->getRoomMembers(strval($receiver_id)) as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($uid)));
}
$groupInfo = Group::where('id', $data['data']['receive'])->first(['group_name', 'avatar']);
$groupInfo = Group::where('id', $receiver_id)->first(['group_name', 'avatar']);
}
// 客户端ID去重
if (!$fds = array_unique($fds)) return Result::ACK;
if (!$fds = array_unique($fds)) {
return Result::ACK;
}
/** @var ChatRecord */
$result = ChatRecord::leftJoin('users', 'users.id', '=', 'chat_records.user_id')
->where('chat_records.id', $data['data']['record_id'])
$result = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->where('talk_records.id', $record_id)
->first([
'chat_records.id',
'chat_records.source',
'chat_records.msg_type',
'chat_records.user_id',
'chat_records.receive_id',
'chat_records.content',
'chat_records.is_revoke',
'chat_records.created_at',
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.content',
'talk_records.is_revoke',
'talk_records.created_at',
'users.nickname',
'users.avatar',
]);
@ -182,14 +188,34 @@ class ChatMessageConsumer extends ConsumerMessage
$file = $code_block = $forward = $invite = [];
switch ($result->msg_type) {
case 2:// 文件消息
$file = ChatRecordsFile::where('record_id', $result->id)->first(['id', 'record_id', 'user_id', 'file_source', 'file_type', 'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir']);
case TalkMsgType::FILE_MESSAGE:
$file = TalkRecordsFile::where('record_id', $result->id)->first([
'id', 'record_id', 'user_id', 'file_source', 'file_type',
'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir'
]);
$file = $file ? $file->toArray() : [];
$file && $file['file_url'] = get_media_url($file['save_dir']);
break;
case 3:// 入群消息/退群消息
$notifyInfo = ChatRecordsInvite::where('record_id', $result->id)->first([
case TalkMsgType::FORWARD_MESSAGE:
$forward = ['num' => 0, 'list' => []];
$forwardInfo = TalkRecordsForward::where('record_id', $result->id)->first(['records_id', 'text']);
if ($forwardInfo) {
$forward = [
'num' => count(parse_ids($forwardInfo->records_id)),
'list' => json_decode($forwardInfo->text, true) ?? []
];
}
break;
case TalkMsgType::CODE_MESSAGE:
$code_block = TalkRecordsCode::where('record_id', $result->id)->first(['record_id', 'code_lang', 'code']);
$code_block = $code_block ? $code_block->toArray() : [];
break;
case TalkMsgType::GROUP_INVITE_MESSAGE:
$notifyInfo = TalkRecordsInvite::where('record_id', $result->id)->first([
'record_id', 'type', 'operate_user_id', 'user_ids'
]);
@ -202,37 +228,22 @@ class ChatMessageConsumer extends ConsumerMessage
unset($notifyInfo, $userInfo);
break;
case 4:// 会话记录消息
$forward = ['num' => 0, 'list' => []];
$forwardInfo = ChatRecordsForward::where('record_id', $result->id)->first(['records_id', 'text']);
if ($forwardInfo) {
$forward = [
'num' => count(parse_ids($forwardInfo->records_id)),
'list' => json_decode($forwardInfo->text, true) ?? []
];
}
break;
case 5:// 代码块消息
$code_block = ChatRecordsCode::where('record_id', $result->id)->first(['record_id', 'code_lang', 'code']);
$code_block = $code_block ? $code_block->toArray() : [];
break;
}
$notify = [
'send_user' => $data['data']['sender'],
'receive_user' => $data['data']['receive'],
'source_type' => $data['data']['source'],
'sender_id' => $sender_id,
'receiver_id' => $receiver_id,
'talk_type' => $talk_type,
'data' => $this->formatTalkMessage([
'id' => $result->id,
'talk_type' => $result->talk_type,
'msg_type' => $result->msg_type,
'source' => $result->source,
"user_id" => $result->user_id,
"receiver_id" => $result->receiver_id,
'avatar' => $result->avatar,
'nickname' => $result->nickname,
'group_name' => $groupInfo ? $groupInfo->group_name : '',
'group_avatar' => $groupInfo ? $groupInfo->avatar : '',
"user_id" => $result->user_id,
"receive_id" => $result->receive_id,
"created_at" => $result->created_at,
"content" => $result->content,
"file" => $file,
@ -256,7 +267,7 @@ class ChatMessageConsumer extends ConsumerMessage
*/
public function onConsumeKeyboard(array $data, AMQPMessage $message): string
{
$fds = $this->socketClientService->findUserFds($data['data']['receive_user']);
$fds = $this->socketClientService->findUserFds($data['data']['receiver_id']);
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_KEYBOARD, $data['data']]));
@ -272,14 +283,20 @@ class ChatMessageConsumer extends ConsumerMessage
*/
public function onConsumeOnlineStatus(array $data, AMQPMessage $message): string
{
$friends = UsersFriend::getFriendIds((int)$data['data']['user_id']);
$user_id = (int)$data['data']['user_id'];
$status = (int)$data['data']['status'];
$fds = [];
foreach ($friends as $friend_id) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$friend_id));
foreach (UsersFriend::getFriendIds($user_id) as $friend_id) {
$fds = array_merge($fds, $this->socketClientService->findUserFds(intval($friend_id)));
}
$this->socketPushNotify(array_unique($fds), json_encode([SocketConstants::EVENT_ONLINE_STATUS, $data['data']]));
$this->socketPushNotify(array_unique($fds), json_encode([
SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => $status
]
]));
return Result::ACK;
}
@ -293,29 +310,26 @@ class ChatMessageConsumer extends ConsumerMessage
*/
public function onConsumeRevokeTalk(array $data, AMQPMessage $message): string
{
/** @var ChatRecord */
$record = ChatRecord::where('id', $data['data']['record_id'])->first(['id', 'source', 'user_id', 'receive_id']);
$record = TalkRecords::where('id', $data['data']['record_id'])->first(['id', 'talk_type', 'user_id', 'receiver_id']);
$fds = [];
if ($record->source == 1) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$record->user_id));
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$record->receive_id));
} else if ($record->source == 2) {
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($record->receive_id));
if ($record->talk_type == TalkType::PRIVATE_CHAT) {
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->user_id));
$fds = array_merge($fds, $this->socketClientService->findUserFds($record->receiver_id));
} else if ($record->talk_type == TalkType::GROUP_CHAT) {
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($record->receiver_id));
foreach ($userIds as $uid) {
$fds = array_merge($fds, $this->socketClientService->findUserFds((int)$uid));
}
}
$this->socketPushNotify(
array_unique($fds),
json_encode([SocketConstants::EVENT_REVOKE_TALK, [
$fds = array_unique($fds);
$this->socketPushNotify($fds, json_encode([SocketConstants::EVENT_REVOKE_TALK, [
'talk_type' => $record->talk_type,
'sender_id' => $record->user_id,
'receiver_id' => $record->receiver_id,
'record_id' => $record->id,
'source' => $record->source,
'user_id' => $record->user_id,
'receive_id' => $record->receive_id,
]])
);
]]));
return Result::ACK;
}
@ -331,7 +345,10 @@ class ChatMessageConsumer extends ConsumerMessage
{
$fds = $this->socketClientService->findUserFds($data['data']['receive']);
$this->socketPushNotify(array_unique($fds), json_encode([SocketConstants::EVENT_FRIEND_APPLY, $data['data']]));
$this->socketPushNotify(array_unique($fds), json_encode([
SocketConstants::EVENT_FRIEND_APPLY,
$data['data']
]));
return Result::ACK;
}
@ -360,12 +377,10 @@ class ChatMessageConsumer extends ConsumerMessage
{
$message = [
"id" => 0, // 消息记录ID
"source" => 1, // 消息来源[1:好友私信;2:群聊]
"talk_type" => 1, // 消息来源[1:好友私信;2:群聊]
"msg_type" => 1, // 消息类型
"user_id" => 0, // 发送者用户ID
"receive_id" => 0, // 接收者ID[好友ID或群ID]
"content" => '',// 文本消息
"is_revoke" => 0, // 消息是否撤销
"receiver_id" => 0, // 接收者ID[好友ID或群ID]
// 发送消息人的信息
"nickname" => "",// 用户昵称
@ -380,7 +395,11 @@ class ChatMessageConsumer extends ConsumerMessage
"invite" => [],
// 消息创建时间
"content" => '',// 文本消息
"created_at" => "",
// 消息属性
"is_revoke" => 0, // 消息是否撤销
];
return array_merge($message, array_intersect_key($data, $message));

View File

@ -22,9 +22,11 @@ use App\Cache\UnreadTalk;
use App\Constants\FileMediaType;
use App\Model\Group\Group;
use App\Model\Group\GroupMember;
use App\Model\TalkList;
use App\Service\TalkService;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\DbConnection\Db;
use League\Flysystem\Filesystem;
use Psr\Container\ContainerInterface;
@ -175,7 +177,5 @@ class TestCommand extends HyperfCommand
//var_dump(FriendRemark::getInstance());
//var_dump(Group::isManager(2054,116));
echo FileMediaType::getMediaType('png');
}
}

View File

@ -7,7 +7,7 @@ namespace App\Constants;
*
* @package App\Constants
*/
class TalkMessageType
class TalkMsgType
{
const TEXT_MESSAGE = 1;//文本消息
const FILE_MESSAGE = 2;//文件消息
@ -16,5 +16,6 @@ class TalkMessageType
const VOTE_MESSAGE = 5;//投票消息
const GROUP_NOTICE_MESSAGE = 6;//群公告
const FRIEND_APPLY_MESSAGE = 7;//好友申请
const USER_LOGIN = 8;//登录通知
const USER_LOGIN_MESSAGE = 8;//登录通知
const GROUP_INVITE_MESSAGE = 9;//入群退群消息
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Constants;
class TalkType
{
/**
* 私聊
*/
const PRIVATE_CHAT = 1;
/**
* 群聊
*/
const GROUP_CHAT = 2;
public static function getTypes()
{
return [
self::PRIVATE_CHAT,
self::GROUP_CHAT
];
}
}

View File

@ -22,7 +22,7 @@ use App\Cache\Repository\LockRedis;
/**
* Class ArticleController
* @Controller(path="/api/v1/article")
* @Controller(prefix="/api/v1/article")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1

View File

@ -19,7 +19,7 @@ use App\Service\SmsCodeService;
/**
* 授权相关控制器
* @Controller(path="/api/v1/auth")
* @Controller(prefix="/api/v1/auth")
*/
class AuthController extends CController
{

View File

@ -22,14 +22,14 @@ use App\Service\SocketClientService;
use App\Service\UserService;
use App\Constants\SocketConstants;
use App\Model\UsersFriendsApply;
use App\Model\UsersChatList;
use App\Model\TalkList;
use App\Cache\FriendApply;
use App\Cache\FriendRemark;
use App\Cache\ServerRunID;
/**
* Class ContactsController
* @Controller(path="/api/v1/contacts")
* @Controller(prefix="/api/v1/contacts")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
@ -59,9 +59,8 @@ class ContactsController extends CController
$rows = $this->contactsService->getContacts($this->uid());
if ($rows) {
$runArr = ServerRunID::getInstance()->getServerRunIdAll();
foreach ($rows as $k => $row) {
// 查询用户当前是否在线
$rows[$k]['online'] = $this->socketClientService->isOnlineAll($row['id'], $runArr);
foreach ($rows as $row) {
$row->is_online = $this->socketClientService->isOnlineAll($row->id, $runArr);
}
}
@ -129,8 +128,8 @@ class ContactsController extends CController
}
// 删除好友会话列表
UsersChatList::delItem($user_id, $params['friend_id'], 2);
UsersChatList::delItem($params['friend_id'], $user_id, 2);
TalkList::delItem($user_id, $params['friend_id'], 2);
TalkList::delItem($params['friend_id'], $user_id, 2);
// ... TODO 推送消息(待完善)

View File

@ -16,15 +16,15 @@ use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Model\Article\ArticleAnnex;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsFile;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsFile;
use App\Model\Group\Group;
use Hyperf\HttpServer\Contract\ResponseInterface;
use League\Flysystem\Filesystem;
/**
* Class DownloadController
* @Controller(path="/api/v1/download")
* @Controller(prefix="/api/v1/download")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
@ -51,7 +51,7 @@ class DownloadController extends CController
'cr_id' => 'required|integer'
]);
$recordsInfo = ChatRecord::select(['msg_type', 'source', 'user_id', 'receive_id'])->where('id', $params['cr_id'])->first();
$recordsInfo = TalkRecords::select(['msg_type', 'talk_type', 'user_id', 'receiver_id'])->where('id', $params['cr_id'])->first();
if (!$recordsInfo) {
return $this->response->fail('文件不存在!');
}
@ -60,18 +60,18 @@ class DownloadController extends CController
// 判断消息是否是当前用户发送(如果是则跳过权限验证)
if ($recordsInfo->user_id != $user_id) {
if ($recordsInfo->source == 1) {
if ($recordsInfo->receive_id != $user_id) {
if ($recordsInfo->talk_type == 1) {
if ($recordsInfo->receiver_id != $user_id) {
return $this->response->fail('非法请求!');
}
} else {
if (!Group::isMember($recordsInfo->receive_id, $user_id)) {
if (!Group::isMember($recordsInfo->receiver_id, $user_id)) {
return $this->response->fail('非法请求!');
}
}
}
$info = ChatRecordsFile::select(['save_dir', 'original_name'])->where('record_id', $params['cr_id'])->first();
$info = TalkRecordsFile::select(['save_dir', 'original_name'])->where('record_id', $params['cr_id'])->first();
if (!$info || !$filesystem->has($info->save_dir)) {
return $this->response->fail('文件不存在或没有下载权限!');
}

View File

@ -17,14 +17,14 @@ use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Constants\ResponseCode;
use App\Model\Emoticon;
use App\Model\EmoticonDetail;
use App\Model\EmoticonItem;
use App\Service\EmoticonService;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
/**
* Class EmoticonController
* @Controller(path="/api/v1/emoticon")
* @Controller(prefix="/api/v1/emoticon")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
@ -49,11 +49,11 @@ class EmoticonController extends CController
$user_id = $this->uid();
if ($ids = $this->emoticonService->getInstallIds($user_id)) {
$items = Emoticon::whereIn('id', $ids)->get(['id', 'name', 'url']);
$items = Emoticon::whereIn('id', $ids)->get(['id', 'name', 'icon']);
foreach ($items as $item) {
$emoticonList[] = [
'emoticon_id' => $item->id,
'url' => get_media_url($item->url),
'url' => get_media_url($item->icon),
'name' => $item->name,
'list' => $this->emoticonService->getDetailsAll([
['emoticon_id', '=', $item->id],
@ -80,12 +80,12 @@ class EmoticonController extends CController
*/
public function getSystemEmoticon()
{
$items = Emoticon::get(['id', 'name', 'url'])->toArray();
$items = Emoticon::get(['id', 'name', 'icon'])->toArray();
if ($items) {
$ids = $this->emoticonService->getInstallIds($this->uid());
array_walk($items, function (&$item) use ($ids) {
$item['status'] = in_array($item['id'], $ids) ? 1 : 0;
$item['url'] = get_media_url($item['url']);
$item['icon'] = get_media_url($item['icon']);
});
}
@ -107,17 +107,19 @@ class EmoticonController extends CController
]);
$user_id = $this->uid();
if ($params['type'] == 2) {
// 移除表情包
if ($params['type'] == 2) {
$isTrue = $this->emoticonService->removeSysEmoticon($user_id, $params['emoticon_id']);
if (!$isTrue) {
return $this->response->fail('移除表情包失败!');
}
return $this->response->success([], '移除表情包成功...');
} else {
}
// 添加表情包
$emoticonInfo = Emoticon::where('id', $params['emoticon_id'])->first(['id', 'name', 'url']);
$emoticonInfo = Emoticon::where('id', $params['emoticon_id'])->first(['id', 'name', 'icon']);
if (!$emoticonInfo) {
return $this->response->fail('添加表情包失败!');
}
@ -128,7 +130,7 @@ class EmoticonController extends CController
$data = [
'emoticon_id' => $emoticonInfo->id,
'url' => get_media_url($emoticonInfo->url),
'url' => get_media_url($emoticonInfo->icon),
'name' => $emoticonInfo->name,
'list' => $this->emoticonService->getDetailsAll([
['emoticon_id', '=', $emoticonInfo->id]
@ -137,7 +139,6 @@ class EmoticonController extends CController
return $this->response->success($data, '添加表情包成功...');
}
}
/**
* 自定义上传表情包
@ -171,12 +172,12 @@ class EmoticonController extends CController
return $this->response->fail('图片上传失败!');
}
$result = EmoticonDetail::create([
$result = EmoticonItem::create([
'user_id' => $this->uid(),
'url' => $path,
'file_suffix' => $ext,
'file_size' => $file->getSize(),
'created_at' => time()
'created_at' => date('Y-m-d H:i:s')
]);
if (!$result) {
@ -189,30 +190,6 @@ class EmoticonController extends CController
]);
}
/**
* 收藏聊天图片的我的表情包
* @RequestMapping(path="collect-emoticon", methods="post")
*
* @return ResponseInterface
*/
public function collectEmoticon()
{
$params = $this->request->inputs(['record_id']);
$this->validate($params, [
'record_id' => 'required|integer'
]);
[$isTrue, $data] = $this->emoticonService->collect($this->uid(), $params['record_id']);
if (!$isTrue) {
return $this->response->fail('添加表情失败!');
}
return $this->response->success([
'emoticon' => $data
]);
}
/**
* 移除收藏的表情包
* @RequestMapping(path="del-collect-emoticon", methods="post")

View File

@ -11,13 +11,14 @@
namespace App\Controller\Api\V1;
use App\Cache\SocketRoom;
use App\Constants\TalkType;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Model\UsersFriend;
use App\Model\UsersChatList;
use App\Model\TalkList;
use App\Model\Group\Group;
use App\Model\Group\GroupMember;
use App\Model\Group\GroupNotice;
@ -28,7 +29,7 @@ use Psr\Http\Message\ResponseInterface;
/**
* Class GroupController
* @Controller(path="/api/v1/group")
* @Controller(prefix="/api/v1/group")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
@ -76,9 +77,9 @@ class GroupController extends CController
// ... 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => (int)$data['group_id'], // 接收者ID
'source' => 2, // 接收者类型[1:好友;2:群组;]
'sender_id' => $user_id,
'receiver_id' => (int)$data['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => (int)$data['record_id']
]));
@ -141,9 +142,9 @@ class GroupController extends CController
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => (int)$params['group_id'], // 接收者ID
'source' => 2, // 接收者类型[1:好友;2:群组;]
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
@ -174,9 +175,9 @@ class GroupController extends CController
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => (int)$params['group_id'], // 接收者ID
'source' => 2, // 接收者类型[1:好友;2:群组;]
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
@ -245,9 +246,9 @@ class GroupController extends CController
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => (int)$params['group_id'], // 接收者ID
'source' => 2, // 接收者类型[1:好友;2:群组;]
'sender_id' => $user_id,
'receiver_id' => (int)$params['group_id'],
'talk_type' => TalkType::GROUP_CHAT,
'record_id' => $record_id
]));
@ -288,13 +289,13 @@ class GroupController extends CController
return $this->response->success([
'group_id' => $groupInfo->id,
'group_name' => $groupInfo->group_name,
'group_profile' => $groupInfo->profile,
'profile' => $groupInfo->profile,
'avatar' => $groupInfo->avatar,
'created_at' => $groupInfo->created_at,
'is_manager' => $groupInfo->creator_id == $user_id,
'manager_nickname' => $groupInfo->nickname,
'visit_card' => GroupMember::visitCard($user_id, $group_id),
'not_disturb' => UsersChatList::where('uid', $user_id)->where('group_id', $group_id)->where('type', 2)->value('not_disturb') ?? 0,
'is_disturb' => (int)TalkList::where('user_id', $user_id)->where('receiver_id', $group_id)->where('talk_type', TalkType::GROUP_CHAT)->value('is_disturb'),
'notice' => $notice ? $notice->toArray() : []
]);
}

View File

@ -12,26 +12,23 @@ namespace App\Controller\Api\V1;
use App\Cache\LastMessage;
use App\Cache\UnreadTalk;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use Psr\Http\Message\ResponseInterface;
use App\Model\EmoticonDetail;
use App\Model\FileSplitUpload;
use App\Model\User;
use App\Model\UsersChatList;
use App\Model\TalkList;
use App\Model\UsersFriend;
use App\Model\Group\Group;
use App\Service\TalkService;
use App\Amqp\Producer\ChatMessageProducer;
use App\Constants\SocketConstants;
use League\Flysystem\Filesystem;
/**
* Class TalkController
* @Controller(path="/api/v1/talk")
* @Controller(prefix="/api/v1/talk")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
@ -44,6 +41,25 @@ class TalkController extends CController
*/
public $talkService;
/**
* 判断是否是好友或者群成员关系
*
* @param int $user_id 用户ID
* @param int $receiver_id 接收者ID
* @param int $talk_type 对话类型
* @return bool
*/
private function isFriendOrGroupMember(int $user_id, int $receiver_id, int $talk_type)
{
if ($talk_type == TalkType::PRIVATE_CHAT) {
return UsersFriend::isFriend($user_id, $receiver_id, true);
} else if ($talk_type == TalkType::GROUP_CHAT) {
return Group::isMember($receiver_id, $user_id);
}
return false;
}
/**
* 获取用户对话列表
* @RequestMapping(path="list", methods="get")
@ -70,68 +86,55 @@ class TalkController extends CController
*/
public function create()
{
$params = $this->request->inputs(['type', 'receive_id']);
$params = $this->request->inputs(['talk_type', 'receiver_id']);
$this->validate($params, [
'type' => 'required|in:1,2',
'receive_id' => 'present|integer|min:0'
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1'
]);
$user_id = $this->uid();
if ($params['type'] == 1) {
if (!UsersFriend::isFriend($user_id, $params['receive_id'])) {
return $this->response->fail('暂不属于好友关系,无法进行聊天!');
}
} else {
if (!Group::isMember($params['receive_id'], $user_id)) {
return $this->response->fail('暂不属于群成员,无法进行群聊!');
}
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法进行聊天!');
}
$result = UsersChatList::addItem($user_id, $params['receive_id'], $params['type']);
$result = TalkList::addItem($user_id, $params['receiver_id'], $params['talk_type']);
if (!$result) {
return $this->response->fail('创建失败!');
}
$data = [
'id' => $result['id'],
'type' => $result['type'],
'group_id' => $result['group_id'],
'friend_id' => $result['friend_id'],
'talk_type' => $result['talk_type'],
'receiver_id' => $result['receiver_id'],
'is_top' => 0,
'msg_text' => '',
'not_disturb' => 0,
'online' => 1,
'is_disturb' => 0,
'is_online' => 1,
'avatar' => '',
'name' => '',
'remark_name' => '',
'avatar' => '',
'unread_num' => 0,
'msg_text' => '',
'updated_at' => date('Y-m-d H:i:s')
];
if ($result['type'] == 1) {
if ($result['talk_type'] == TalkType::PRIVATE_CHAT) {
$userInfo = User::where('id', $user_id)->first(['nickname', 'avatar']);
$data['name'] = $userInfo->nickname;
$data['avatar'] = $userInfo->avatar;
$data['unread_num'] = UnreadTalk::getInstance()->read($result['friend_id'], $user_id);
} else if ($result['type'] == 2) {
$groupInfo = Group::where('id', $result['group_id'])->first(['group_name', 'avatar']);
$data['name'] = $userInfo->nickname;
$data['unread_num'] = UnreadTalk::getInstance()->read($data['receiver_id'], $user_id);
} else if ($result['talk_type'] == TalkType::GROUP_CHAT) {
$groupInfo = Group::where('id', $data['receiver_id'])->first(['group_name', 'avatar']);
$data['name'] = $groupInfo->group_name;
$data['avatar'] = $groupInfo->avatar;
}
$records = LastMessage::getInstance()->read(
(int)$result['type'], $user_id,
$result['type'] == 1 ? (int)$result['friend_id'] : (int)$result['group_id']
);
$records = LastMessage::getInstance()->read($result['talk_type'], $user_id, $result['receiver_id']);
if ($records) {
$data['msg_text'] = $records['text'];
$data['updated_at'] = $records['created_at'];
}
return $this->response->success(['talkItem' => $data]);
return $this->response->success($data);
}
/**
@ -147,7 +150,7 @@ class TalkController extends CController
'list_id' => 'required|integer|min:0'
]);
return UsersChatList::delItem($this->uid(), $params['list_id'])
return TalkList::delItem($this->uid(), $params['list_id'])
? $this->response->success([], '对话列表删除成功...')
: $this->response->fail('对话列表删除失败!');
}
@ -166,7 +169,7 @@ class TalkController extends CController
'type' => 'required|in:1,2',
]);
return UsersChatList::topItem($this->uid(), $params['list_id'], $params['type'] == 1)
return TalkList::topItem($this->uid(), $params['list_id'], $params['type'] == 1)
? $this->response->success([], '对话列表置顶(或取消置顶)成功...')
: $this->response->fail('对话列表置顶(或取消置顶)失败!');
}
@ -179,14 +182,14 @@ class TalkController extends CController
*/
public function setNotDisturb()
{
$params = $this->request->inputs(['receive_id', 'type', 'not_disturb']);
$params = $this->request->inputs(['talk_type', 'receiver_id', 'is_disturb']);
$this->validate($params, [
'receive_id' => 'required|integer|min:0',
'type' => 'required|in:1,2',
'not_disturb' => 'required|in:0,1',
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'is_disturb' => 'required|in:0,1',
]);
$isTrue = UsersChatList::notDisturbItem($this->uid(), $params['receive_id'], $params['type'], $params['not_disturb']);
$isTrue = TalkList::setNotDisturb($this->uid(), $params['receiver_id'], $params['talk_type'], $params['is_disturb']);
return $isTrue
? $this->response->success([], '免打扰设置成功...')
@ -201,143 +204,20 @@ class TalkController extends CController
*/
public function updateUnreadNum()
{
$params = $this->request->inputs(['receive', 'type']);
$params = $this->request->inputs(['talk_type', 'receiver_id']);
$this->validate($params, [
'receive' => 'required|integer|min:0',
'type' => 'required|integer|min:0'
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
]);
// 设置好友消息未读数
if ($params['type'] == 1) {
UnreadTalk::getInstance()->reset((int)$params['receive'], $this->uid());
if ($params['talk_type'] == TalkType::PRIVATE_CHAT) {
UnreadTalk::getInstance()->reset((int)$params['receiver_id'], $this->uid());
}
return $this->response->success();
}
/**
* 撤回聊天对话消息
* @RequestMapping(path="revoke-records", methods="post")
*
* @return ResponseInterface
*/
public function revokeChatRecords()
{
$params = $this->request->inputs(['record_id']);
$this->validate($params, [
'record_id' => 'required|integer|min:0'
]);
[$isTrue, $message,] = $this->talkService->revokeRecord($this->uid(), $params['record_id']);
if ($isTrue) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_REVOKE_TALK, [
'record_id' => $params['record_id']
]));
}
return $isTrue
? $this->response->success([], $message)
: $this->response->fail($message);
}
/**
* 删除聊天记录
* @RequestMapping(path="remove-records", methods="post")
*
* @return ResponseInterface
*/
public function removeChatRecords()
{
$params = $this->request->inputs(['source', 'record_id', 'receive_id']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'record_id' => 'required|ids',
'receive_id' => 'required|integer|min:0'
]);
$record_ids = explode(',', $params['record_id']);
$isTrue = $this->talkService->removeRecords(
$this->uid(),
$params['source'],
$params['receive_id'],
$record_ids
);
return $isTrue
? $this->response->success([], '删除成功...')
: $this->response->fail('删除失败!');
}
/**
* 转发聊天记录(待优化)
* @RequestMapping(path="forward-records", methods="post")
*
* @return ResponseInterface
*/
public function forwardChatRecords()
{
$params = $this->request->inputs(['source', 'records_ids', 'receive_id', 'forward_mode', 'receive_user_ids', 'receive_group_ids']);
$this->validate($params, [
// 消息来源[1:好友消息;2:群聊消息;]
'source' => 'required|in:1,2',
// 聊天记录ID多个逗号拼接
'records_ids' => 'required',
// 接收者ID好友ID或者群聊ID
'receive_id' => 'required|integer|min:0',
// 转发方方式[1:逐条转发;2:合并转发;]
'forward_mode' => 'required|in:1,2',
// 转发的好友的ID
//'receive_user_ids' => 'array',
// 转发的群聊ID
//'receive_group_ids' => 'array',
]);
$receive_user_ids = $receive_group_ids = [];
if (isset($params['receive_user_ids']) && !empty($params['receive_user_ids'])) {
$receive_user_ids = array_map(function ($friend_id) {
return ['source' => 1, 'id' => $friend_id];
}, $params['receive_user_ids']);
}
if (isset($params['receive_group_ids']) && !empty($params['receive_group_ids'])) {
$receive_group_ids = array_map(function ($group_id) {
return ['source' => 2, 'id' => $group_id];
}, $params['receive_group_ids']);
}
$items = array_merge($receive_user_ids, $receive_group_ids);
$user_id = $this->uid();
if ($params['forward_mode'] == 1) {// 单条转发
$ids = $this->talkService->forwardRecords($user_id, $params['receive_id'], $params['records_ids']);
} else {// 合并转发
$ids = $this->talkService->mergeForwardRecords($user_id, $params['receive_id'], $params['source'], $params['records_ids'], $items);
}
if (!$ids) {
return $this->response->fail('转发失败!');
}
if ($receive_user_ids) {
foreach ($receive_user_ids as $v) {
UnreadTalk::getInstance()->increment($user_id, (int)$v['id']);
}
}
// 消息推送队列
foreach ($ids as $value) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => intval($value['receive_id']), // 接收者ID
'source' => intval($value['source']), // 接收者类型 1:好友;2:群组
'record_id' => $value['record_id']
]));
}
return $this->response->success([], '转发成功...');
}
/**
* 获取对话面板中的聊天记录
* @RequestMapping(path="records", methods="get")
@ -346,29 +226,23 @@ class TalkController extends CController
*/
public function getChatRecords()
{
$params = $this->request->inputs(['record_id', 'source', 'receive_id']);
$params = $this->request->inputs(['talk_type', 'receiver_id', 'record_id']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'record_id' => 'required|integer|min:0',
'receive_id' => 'required|integer|min:1',
]);
$user_id = $this->uid();
$limit = 30;
// 判断是否属于群成员
if ($params['source'] == 2 && Group::isMember($params['receive_id'], $user_id) == false) {
return $this->response->success([
'rows' => [],
'record_id' => 0,
'limit' => $limit
], '非群聊成员不能查看群聊信息!');
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法查看聊天记录!');
}
$limit = 30;
$result = $this->talkService->getChatRecords(
$user_id,
$params['receive_id'],
$params['source'],
$params['receiver_id'],
$params['talk_type'],
$params['record_id'],
$limit
);
@ -388,12 +262,12 @@ class TalkController extends CController
*/
public function getForwardRecords()
{
$params = $this->request->inputs(['records_id']);
$params = $this->request->inputs(['record_id']);
$this->validate($params, [
'records_id' => 'required|integer|min:0'
'record_id' => 'required|integer|min:1'
]);
$rows = $this->talkService->getForwardRecords($this->uid(), $params['records_id']);
$rows = $this->talkService->getForwardRecords($this->uid(), $params['record_id']);
return $this->response->success(['rows' => $rows]);
}
@ -406,36 +280,37 @@ class TalkController extends CController
*/
public function findChatRecords()
{
$params = $this->request->inputs(['record_id', 'source', 'receive_id', 'msg_type']);
$params = $this->request->inputs(['talk_type', 'receiver_id', 'record_id', 'msg_type']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'record_id' => 'required|integer|min:0',
'receive_id' => 'required|integer|min:1',
'msg_type' => 'required|in:0,1,2,3,4,5,6',
'msg_type' => 'required|integer',
]);
$user_id = $this->uid();
$limit = 30;
// 判断是否属于群成员
if ($params['source'] == 2 && Group::isMember($params['receive_id'], $user_id) == false) {
return $this->response->success([
'rows' => [],
'record_id' => 0,
'limit' => $limit
], '非群聊成员不能查看群聊信息!');
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法查看聊天记录!');
}
if (in_array($params['msg_type'], [1, 2, 4, 5])) {
$types = [
TalkMsgType::TEXT_MESSAGE,
TalkMsgType::FILE_MESSAGE,
TalkMsgType::FORWARD_MESSAGE,
TalkMsgType::CODE_MESSAGE
];
if (in_array($params['msg_type'], $types)) {
$msg_type = [$params['msg_type']];
} else {
$msg_type = [1, 2, 4, 5];
$msg_type = $types;
}
$limit = 30;
$result = $this->talkService->getChatRecords(
$user_id,
$params['receive_id'],
$params['source'],
$params['receiver_id'],
$params['talk_type'],
$params['record_id'],
$limit,
$msg_type
@ -450,261 +325,23 @@ class TalkController extends CController
/**
* 搜索聊天记录(待开发)
* @RequestMapping(path="search-chat-records", methods="get")
* @RequestMapping(path="records-search", methods="get")
*
* @return ResponseInterface
*/
public function searchChatRecords()
{
return $this->response->success();
}
/**
* 获取聊天记录上下文数据(待开发)
* @RequestMapping(path="get-records-context", methods="get")
* @RequestMapping(path="records-context", methods="get")
*
* @return ResponseInterface
*/
public function getRecordsContext()
{
}
/**
* 上传聊天对话图片(待优化)
* @RequestMapping(path="send-image", methods="post")
*
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function sendImage(Filesystem $filesystem)
{
$params = $this->request->inputs(['source', 'receive_id']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'receive_id' => 'required|integer|min:1'
]);
$file = $this->request->file('img');
if (!$file || !$file->isValid()) {
return $this->response->fail();
}
$ext = $file->getExtension();
if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) {
return $this->response->fail('图片格式错误目前仅支持jpg、png、jpeg、gif和webp');
}
try {
$path = 'media/images/talks/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
$user_id = $this->uid();
// 创建图片消息记录
$record_id = $this->talkService->createImgMessage([
'source' => $params['source'],
'msg_type' => 2,
'user_id' => $user_id,
'receive_id' => $params['receive_id'],
], [
'user_id' => $user_id,
'file_suffix' => $ext,
'file_size' => $file->getSize(),
'save_dir' => $path,
'original_name' => $file->getClientFilename(),
]);
if (!$record_id) {
return $this->response->fail('图片上传失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => intval($params['receive_id']), // 接收者ID
'source' => intval($params['source']), // 接收者类型[1:好友;2:群组;]
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['source'], $user_id, (int)$params['receive_id'], [
'text' => '[图片消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送代码块消息
* @RequestMapping(path="send-code-block", methods="post")
*
* @return ResponseInterface
*/
public function sendCodeBlock()
{
$params = $this->request->inputs(['source', 'receive_id', 'lang', 'code']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'receive_id' => 'required|integer|min:1',
'lang' => 'required',
'code' => 'required'
]);
$user_id = $this->uid();
$record_id = $this->talkService->createCodeMessage([
'source' => $params['source'],
'msg_type' => 5,
'user_id' => $user_id,
'receive_id' => $params['receive_id'],
], [
'user_id' => $user_id,
'code_lang' => $params['lang'],
'code' => $params['code']
]);
if (!$record_id) {
return $this->response->fail('消息发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => intval($params['receive_id']), // 接收者ID
'source' => intval($params['source']), // 接收者类型[1:好友;2:群组;]
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['source'], $user_id, (int)$params['receive_id'], [
'text' => '[代码消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送文件消息
* @RequestMapping(path="send-file", methods="post")
*
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function sendFile(Filesystem $filesystem)
{
$params = $this->request->inputs(['hash_name', 'receive_id', 'source']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'receive_id' => 'required|integer|min:1',
'hash_name' => 'required',
]);
$user_id = $this->uid();
$file = FileSplitUpload::where('user_id', $user_id)->where('hash_name', $params['hash_name'])->where('file_type', 1)->first();
if (!$file || empty($file->save_dir)) {
return $this->response->fail('文件不存在...');
}
$save_dir = "files/talks/" . date('Ymd') . '/' . create_random_filename($file->file_ext);
try {
$filesystem->copy($file->save_dir, $save_dir);
} catch (\Exception $e) {
return $this->response->fail('文件不存在...');
}
$record_id = $this->talkService->createFileMessage([
'source' => $params['source'],
'msg_type' => 2,
'user_id' => $user_id,
'receive_id' => $params['receive_id']
], [
'user_id' => $user_id,
'file_source' => 1,
'original_name' => $file->original_name,
'file_suffix' => $file->file_ext,
'file_size' => $file->file_size,
'save_dir' => $save_dir,
]);
if (!$record_id) {
return $this->response->fail('表情发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => intval($params['receive_id']), // 接收者ID
'source' => intval($params['source']), // 接收者类型[1:好友;2:群组;]
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['source'], $user_id, (int)$params['receive_id'], [
'text' => '[文件消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送表情包消息
* @RequestMapping(path="send-emoticon", methods="post")
*
* @return ResponseInterface
*/
public function sendEmoticon()
{
$params = $this->request->inputs(['source', 'receive_id', 'emoticon_id']);
$this->validate($params, [
'source' => 'required|in:1,2',// 消息来源[1:好友消息;2:群聊消息;]
'receive_id' => 'required|integer|min:1',
'emoticon_id' => 'required|integer|min:1',
]);
$user_id = $this->uid();
$emoticon = EmoticonDetail::where('id', $params['emoticon_id'])->where('user_id', $user_id)->first([
'url', 'file_suffix', 'file_size'
]);
if (!$emoticon) {
return $this->response->fail('表情不存在!');
}
$record_id = $this->talkService->createEmoticonMessage([
'source' => $params['source'],
'msg_type' => 2,
'user_id' => $user_id,
'receive_id' => $params['receive_id'],
], [
'user_id' => $user_id,
'file_suffix' => $emoticon->file_suffix,
'file_size' => $emoticon->file_size,
'save_dir' => $emoticon->url,
'original_name' => '表情',
]);
if (!$record_id) {
return $this->response->fail('表情发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender' => $user_id, // 发送者ID
'receive' => intval($params['receive_id']), // 接收者ID
'source' => intval($params['source']), // 接收者类型[1:好友;2:群组;]
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['source'], $user_id, (int)$params['receive_id'], [
'text' => '[表情包消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
}

View File

@ -0,0 +1,434 @@
<?php
namespace App\Controller\Api\V1;
use App\Amqp\Producer\ChatMessageProducer;
use App\Cache\LastMessage;
use App\Cache\UnreadTalk;
use App\Constants\SocketConstants;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\EmoticonItem;
use App\Model\FileSplitUpload;
use App\Model\Group\Group;
use App\Model\UsersFriend;
use App\Service\EmoticonService;
use App\Service\TalkService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use League\Flysystem\Filesystem;
/**
* Class TalkController
* @Controller(prefix="/api/v1/talk/message")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
*/
class TalkMessageController extends CController
{
/**
* @Inject
* @var TalkService
*/
public $talkService;
/**
* 判断是否是好友或者群成员关系
*
* @param int $user_id 用户ID
* @param int $receiver_id 接收者ID
* @param int $talk_type 对话类型
* @return bool
*/
private function isFriendOrGroupMember(int $user_id, int $receiver_id, int $talk_type)
{
if ($talk_type == TalkType::PRIVATE_CHAT) {
return UsersFriend::isFriend($user_id, $receiver_id, true);
} else if ($talk_type == TalkType::GROUP_CHAT) {
return Group::isMember($receiver_id, $user_id);
}
return false;
}
/**
* 发送代码块消息
* @RequestMapping(path="code", methods="post")
*/
public function code()
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'lang', 'code']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'lang' => 'required',
'code' => 'required'
]);
$user_id = $this->uid();
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!');
}
$record_id = $this->talkService->createCodeMessage([
'talk_type' => $params['talk_type'],
'msg_type' => TalkMsgType::CODE_MESSAGE,
'user_id' => $user_id,
'receiver_id' => $params['receiver_id'],
], [
'user_id' => $user_id,
'code_lang' => $params['lang'],
'code' => $params['code']
]);
if (!$record_id) {
return $this->response->fail('消息发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[代码消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送图片消息
* @RequestMapping(path="image", methods="post")
*/
public function image(Filesystem $filesystem)
{
$params = $this->request->inputs(['talk_type', 'receiver_id']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1'
]);
$user_id = $this->uid();
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!');
}
$file = $this->request->file('image');
if (!$file || !$file->isValid()) {
return $this->response->fail();
}
$ext = $file->getExtension();
if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) {
return $this->response->fail('图片格式错误目前仅支持jpg、png、jpeg、gif和webp');
}
try {
$path = 'media/images/talks/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
// 创建图片消息记录
$record_id = $this->talkService->createImgMessage([
'talk_type' => $params['talk_type'],
'msg_type' => TalkMsgType::FILE_MESSAGE,
'user_id' => $user_id,
'receiver_id' => $params['receiver_id'],
], [
'user_id' => $user_id,
'file_suffix' => $ext,
'file_size' => $file->getSize(),
'save_dir' => $path,
'original_name' => $file->getClientFilename(),
]);
if (!$record_id) {
return $this->response->fail('图片上传失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id,
]));
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[图片消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送文件消息
* @RequestMapping(path="file", methods="post")
*/
public function file(Filesystem $filesystem)
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'hash_name']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'hash_name' => 'required',
]);
$user_id = $this->uid();
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!');
}
$file = FileSplitUpload::where('user_id', $user_id)->where('hash_name', $params['hash_name'])->where('file_type', 1)->first();
if (!$file || empty($file->save_dir)) {
return $this->response->fail('文件不存在...');
}
try {
$save_dir = "files/talks/" . date('Ymd') . '/' . create_random_filename($file->file_ext);
$filesystem->copy($file->save_dir, $save_dir);
} catch (\Exception $e) {
return $this->response->fail('文件不存在...');
}
$record_id = $this->talkService->createFileMessage([
'talk_type' => $params['talk_type'],
'msg_type' => TalkMsgType::FILE_MESSAGE,
'user_id' => $user_id,
'receiver_id' => $params['receiver_id']
], [
'user_id' => $user_id,
'file_source' => 1,
'original_name' => $file->original_name,
'file_suffix' => $file->file_ext,
'file_size' => $file->file_size,
'save_dir' => $save_dir,
]);
if (!$record_id) {
return $this->response->fail('表情发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[文件消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 发送投票消息
* @RequestMapping(path="vote", methods="post")
*/
public function vote()
{
}
/**
* 发送表情包消息
* @RequestMapping(path="emoticon", methods="post")
*/
public function emoticon()
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'emoticon_id']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'emoticon_id' => 'required|integer|min:1',
]);
$user_id = $this->uid();
if (!$this->isFriendOrGroupMember($user_id, $params['receiver_id'], $params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!');
}
$emoticon = EmoticonItem::where('id', $params['emoticon_id'])->where('user_id', $user_id)->first([
'url', 'file_suffix', 'file_size'
]);
if (!$emoticon) {
return $this->response->fail('表情不存在!');
}
$record_id = $this->talkService->createEmoticonMessage([
'talk_type' => $params['talk_type'],
'msg_type' => TalkMsgType::FILE_MESSAGE,
'user_id' => $user_id,
'receiver_id' => $params['receiver_id'],
], [
'user_id' => $user_id,
'file_suffix' => $emoticon->file_suffix,
'file_size' => $emoticon->file_size,
'save_dir' => $emoticon->url,
'original_name' => '图片表情',
]);
if (!$record_id) {
return $this->response->fail('表情发送失败!');
}
// 消息推送队列
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => (int)$params['receiver_id'],
'talk_type' => (int)$params['talk_type'],
'record_id' => $record_id
]));
LastMessage::getInstance()->save((int)$params['talk_type'], $user_id, (int)$params['receiver_id'], [
'text' => '[表情包消息]',
'created_at' => date('Y-m-d H:i:s')
]);
return $this->response->success();
}
/**
* 转发消息记录
* @RequestMapping(path="forward", methods="post")
*/
public function forward()
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'records_ids', 'forward_mode', 'receive_user_ids', 'receive_group_ids']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'records_ids' => 'required', // 聊天记录ID多个逗号拼接
'forward_mode' => 'required|in:1,2',// 转发方方式[1:逐条转发;2:合并转发;]
]);
$receive_user_ids = $receive_group_ids = [];
if (isset($params['receive_user_ids']) && !empty($params['receive_user_ids'])) {
$receive_user_ids = array_map(function ($friend_id) {
return ['talk_type' => TalkType::PRIVATE_CHAT, 'id' => (int)$friend_id];
}, $params['receive_user_ids']);
}
if (isset($params['receive_group_ids']) && !empty($params['receive_group_ids'])) {
$receive_group_ids = array_map(function ($group_id) {
return ['talk_type' => TalkType::GROUP_CHAT, 'id' => (int)$group_id];
}, $params['receive_group_ids']);
}
$items = array_merge($receive_user_ids, $receive_group_ids);
$user_id = $this->uid();
if ($params['forward_mode'] == 1) {// 单条转发
$ids = $this->talkService->forwardRecords($user_id, $params['receiver_id'], $params['records_ids']);
} else {// 合并转发
$ids = $this->talkService->mergeForwardRecords($user_id, $params['receiver_id'], $params['talk_type'], $params['records_ids'], $items);
}
if (!$ids) {
return $this->response->fail('转发失败!');
}
if ($receive_user_ids) {
foreach ($receive_user_ids as $v) {
UnreadTalk::getInstance()->increment($user_id, $v['id']);
}
}
// 消息推送队列
foreach ($ids as $value) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $user_id,
'receiver_id' => $value['receiver_id'],
'talk_type' => $value['talk_type'],
'record_id' => $value['record_id'],
]));
}
return $this->response->success([], '转发成功...');
}
/**
* 收藏聊天图片
* @RequestMapping(path="collect", methods="post")
*/
public function collect(EmoticonService $service)
{
$params = $this->request->inputs(['record_id']);
$this->validate($params, [
'record_id' => 'required|integer'
]);
[$isTrue, $data] = $service->collect($this->uid(), $params['record_id']);
if (!$isTrue) return $this->response->fail('添加表情失败!');
return $this->response->success([
'emoticon' => $data
]);
}
/**
* 撤销聊天记录
* @RequestMapping(path="revoke", methods="post")
*/
public function revoke()
{
$params = $this->request->inputs(['record_id']);
$this->validate($params, [
'record_id' => 'required|integer|min:0'
]);
[$isTrue, $message,] = $this->talkService->revokeRecord($this->uid(), $params['record_id']);
if ($isTrue) {
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_REVOKE_TALK, [
'record_id' => $params['record_id']
]));
}
return $isTrue
? $this->response->success([], $message)
: $this->response->fail($message);
}
/**
* 删除聊天记录
* @RequestMapping(path="delete", methods="post")
*/
public function delete()
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'record_id']);
$this->validate($params, [
'talk_type' => 'required|in:1,2',
'receiver_id' => 'required|integer|min:1',
'record_id' => 'required|ids',
]);
$isTrue = $this->talkService->removeRecords(
$this->uid(),
$params['talk_type'],
$params['receiver_id'],
parse_ids($params['record_id'])
);
return $isTrue
? $this->response->success([], '删除成功...')
: $this->response->fail('删除失败!');
}
}

View File

@ -22,7 +22,7 @@ use Psr\Http\Message\ResponseInterface;
/**
* 上传文件控制器
* @Controller(path="/api/v1/upload")
* @Controller(prefix="/api/v1/upload")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1

View File

@ -24,7 +24,7 @@ use Psr\Http\Message\ResponseInterface;
/**
* Class UsersController
* @Controller(path="/api/v1/users")
* @Controller(prefix="/api/v1/users")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1

View File

@ -88,7 +88,6 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 1,
'notify' => '好友上线通知...'
]));
}
}
@ -137,7 +136,6 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 0,
'notify' => '好友离线通知通知...'
]));
}
}

View File

@ -30,13 +30,15 @@ class AppExceptionHandler extends ExceptionHandler
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$this->logger->error($throwable->getTraceAsString());
$isDev = config('app_env') == 'dev';
$data = json_encode([
'code' => ResponseCode::SERVER_ERROR,
'message' => 'Internal Server Error.',
'errors' => config('app_env') == 'dev' ? $throwable->getTrace() : [],
'error' => $isDev ? $throwable->getMessage() : 'Internal Server Error.',
'traces' => $isDev ? $throwable->getTrace() : [],
], JSON_UNESCAPED_UNICODE);
$this->sendAdminEmail($throwable);
!$isDev && $this->sendAdminEmail($throwable);
return $response->withHeader('Server', 'Lumen IM')->withStatus(500)->withBody(new SwooleStream($data));
}
@ -57,10 +59,6 @@ class AppExceptionHandler extends ExceptionHandler
*/
public function sendAdminEmail(Throwable $throwable)
{
if (config('app_env') != 'dev') {
return;
}
$error = implode(':', [
'error',
md5($throwable->getFile() . $throwable->getCode() . $throwable->getLine()),

View File

@ -1,44 +0,0 @@
<?php
declare (strict_types=1);
namespace App\Model\Chat;
use App\Model\BaseModel;
/**
* 聊天记录数据表模型
*
* @property int $id 聊天消息ID
* @property int $source 消息来源[1:好友消息;2:群聊消息]
* @property int $msg_type 消息类型[1:文本消息;2:文件消息;3:入群消息/退群消息;4:会话记录消息;5:代码块消息]
* @property int $user_id 发送者ID[0:代表系统消息; >0: 用户ID]
* @property int $receive_id 接收者ID[用户ID 群ID]
* @property string $content 文本消息
* @property int $is_revoke 是否撤回消息[0:;1:]
* @property string $created_at 创建时间
* @package App\Model\Chat
*/
class ChatRecord extends BaseModel
{
protected $table = 'chat_records';
protected $fillable = [
'source',
'msg_type',
'user_id',
'receive_id',
'content',
'is_revoke',
'created_at',
];
protected $casts = [
'id' => 'integer',
'source' => 'integer',
'msg_type' => 'integer',
'user_id' => 'integer',
'receive_id' => 'integer',
'is_revoke' => 'integer'
];
}

View File

@ -0,0 +1,57 @@
<?php
declare (strict_types=1);
namespace App\Model\Chat;
use App\Model\BaseModel;
/**
* 聊天记录数据表模型
*
* @property integer $id 聊天消息ID
* @property int $talk_type 对话类型
* @property int $msg_type 消息类型
* @property int $user_id 发送者ID
* @property int $receiver_id 接收者ID
* @property int $is_revoke 是否撤回消息
* @property int $is_mark 是否重要消息
* @property int $is_read 是否已读
* @property int $quote_id 引用消息ID
* @property string $warn_users @好友
* @property string $content 文本消息
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model\Chat
*/
class TalkRecords extends BaseModel
{
protected $table = 'talk_records';
protected $fillable = [
'talk_type',
'msg_type',
'user_id',
'receiver_id',
'is_revoke',
'is_mark',
'is_read',
'quote_id',
'warn_users',
'content',
'created_at',
'updated_at',
];
protected $casts = [
'id' => 'integer',
'talk_type' => 'integer',
'msg_type' => 'integer',
'user_id' => 'integer',
'receiver_id' => 'integer',
'is_revoke' => 'integer',
'is_mark' => 'integer',
'is_read' => 'integer',
'quote_id' => 'integer',
];
}

View File

@ -17,9 +17,9 @@ use App\Model\BaseModel;
* @property string $created_at 创建时间
* @package App\Model\Chat
*/
class ChatRecordsCode extends BaseModel
class TalkRecordsCode extends BaseModel
{
protected $table = 'chat_records_code';
protected $table = 'talk_records_code';
protected $fillable = [
'record_id',

View File

@ -15,9 +15,9 @@ use App\Model\BaseModel;
* @property string $created_at 删除时间
* @package App\Model\Chat
*/
class ChatRecordsDelete extends BaseModel
class TalkRecordsDelete extends BaseModel
{
protected $table = 'chat_records_delete';
protected $table = 'talk_records_delete';
protected $fillable = [];

View File

@ -23,9 +23,9 @@ use App\Model\BaseModel;
* @property string $created_at 上传时间
* @package App\Model\Chat
*/
class ChatRecordsFile extends BaseModel
class TalkRecordsFile extends BaseModel
{
protected $table = 'chat_records_file';
protected $table = 'talk_records_file';
protected $fillable = [
'record_id',

View File

@ -17,9 +17,9 @@ use App\Model\BaseModel;
* @property int $created_at 转发时间
* @package App\Model\Chat
*/
class ChatRecordsForward extends BaseModel
class TalkRecordsForward extends BaseModel
{
protected $table = 'chat_records_forward';
protected $table = 'talk_records_forward';
protected $fillable = [
'record_id',

View File

@ -16,9 +16,9 @@ use App\Model\BaseModel;
* @property string $user_ids 用户ID(多个用 , 分割)
* @package App\Model\Chat
*/
class ChatRecordsInvite extends BaseModel
class TalkRecordsInvite extends BaseModel
{
protected $table = 'chat_records_invite';
protected $table = 'talk_records_invite';
protected $fillable = [
'record_id',

View File

@ -7,10 +7,12 @@ namespace App\Model;
/**
* 表情包分组数据表模型
*
* @property int $id 分组ID
* @property integer $id 分组ID
* @property string $name 分组名称
* @property string $url 默认表情
* @property string $icon 分组图标
* @property integer $status 分组状态
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class Emoticon extends BaseModel
@ -21,6 +23,8 @@ class Emoticon extends BaseModel
protected $casts = [
'id' => 'integer',
'created_at' => 'datetime'
'status' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}

View File

@ -7,19 +7,20 @@ namespace App\Model;
/**
* 表情包数据表模型
*
* @property int $id 表情包ID
* @property int $emoticon_id 分组ID
* @property int $id 表情包详情ID
* @property int $emoticon_id 表情分组ID
* @property int $user_id 用户ID
* @property string $describe 表情描述
* @property string $url 表情链接
* @property string $file_suffix 文件前缀
* @property int $file_size 表情包文件大小
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class EmoticonDetail extends BaseModel
class EmoticonItem extends BaseModel
{
protected $table = 'emoticon_details';
protected $table = 'emoticon_item';
protected $fillable = [
'emoticon_id',
@ -29,6 +30,7 @@ class EmoticonDetail extends BaseModel
'file_suffix',
'file_size',
'created_at',
'updated_at',
];
protected $casts = [
@ -36,6 +38,7 @@ class EmoticonDetail extends BaseModel
'emoticon_id' => 'integer',
'user_id' => 'integer',
'file_size' => 'integer',
'created_at' => 'integer'
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}

45
app/Model/Robot.php Normal file
View File

@ -0,0 +1,45 @@
<?php
declare (strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
/**
* Class Robot
*
* @property int $id 机器人ID
* @property int $user_id 关联用户ID
* @property int $robot_name 机器人名称
* @property int $describe 描述信息
* @property int $logo 机器人logo
* @property int $is_talk 可发送消息
* @property int $status 状态
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class Robot extends Model
{
protected $table = 'Robot';
protected $fillable = [
'user_id',
'robot_name',
'describe',
'logo',
'is_talk',
'status',
'created_at',
'updated_at',
];
protected $casts = [
'user_id' => 'integer',
'is_talk' => 'integer',
'status' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}

164
app/Model/TalkList.php Normal file
View File

@ -0,0 +1,164 @@
<?php
declare (strict_types=1);
namespace App\Model;
/**
* 聊天列表组数据表模型
*
* @property integer $id 聊天列表ID
* @property integer $talk_type 聊天类型[1:好友;2:群聊;]
* @property integer $user_id 用户ID或消息发送者ID
* @property integer $receiver_id 接收者ID[好友ID或群ID]
* @property integer $is_delete 是否删除
* @property integer $is_top 是否置顶
* @property integer $is_disturb 消息免打扰
* @property integer $is_robot 是否机器人
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class TalkList extends BaseModel
{
protected $table = 'talk_list';
protected $fillable = [
'talk_type',
'user_id',
'receiver_id',
'is_delete',
'is_top',
'is_robot',
'is_disturb',
'created_at',
'updated_at'
];
protected $casts = [
'id' => 'integer',
'talk_type' => 'integer',
'user_id' => 'integer',
'receiver_id' => 'integer',
'is_delete' => 'integer',
'is_top' => 'integer',
'is_robot' => 'integer',
'is_disturb' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
/**
* 创建聊天列表记录
*
* @param int $user_id 用户ID
* @param int $receiver_id 接收者ID
* @param int $talk_type 创建类型[1:私聊;2:群聊;]
* @return array
*/
public static function addItem(int $user_id, int $receiver_id, int $talk_type)
{
$result = self::query()->where([
['user_id', '=', $user_id],
['talk_type', '=', $talk_type],
['receiver_id', '=', $receiver_id],
])->first();
if (!$result) {
$result = self::query()->create([
'talk_type' => $talk_type,
'user_id' => $user_id,
'receiver_id' => $receiver_id,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
}
$result->is_top = 0;
$result->is_delete = 0;
$result->is_disturb = 0;
$result->updated_at = date('Y-m-d H:i:s');
$result->save();
return [
'id' => $result->id,
'talk_type' => $result->talk_type,
'receiver_id' => $result->receiver_id,
];
}
/**
* 聊天对话列表置顶操作
*
* @param int $user_id 用户ID
* @param int $list_id 对话列表ID
* @param bool $is_top 是否置顶true: false:否)
* @return bool
*/
public static function topItem(int $user_id, int $list_id, $is_top = true)
{
return (bool)self::query()->where([
['id', '=', $list_id],
['user_id', '=', $user_id],
])->update([
'is_top' => $is_top ? 1 : 0,
'updated_at' => date('Y-m-d H:i:s')
]);
}
/**
* 删除聊天列表
*
* @param int $user_id 用户ID
* @param int $id 聊天列表ID、好友ID或群聊ID
* @param int $type ID类型[1:聊天列表ID;2:好友ID;3:群聊ID;]
* @return bool
*/
public static function delItem(int $user_id, int $id, $type = 1)
{
$model = self::query();
if ($type == 1) {
$model->where('id', $id)->where('user_id', $user_id);
} else {
$model->where([
['talk_type', '=', $type == 2 ? 1 : 2],
['user_id', '=', $user_id],
['receiver_id', '=', $id],
]);
}
return (bool)$model->update([
'is_delete' => 0,
'updated_at' => date('Y-m-d H:i:s')
]);
}
/**
* 设置消息免打扰
*
* @param int $user_id 用户ID
* @param int $receiver_id 接收者ID
* @param int $talk_type 接收者类型[1:好友;2:群组;]
* @param int $is_disturb 是否免打扰
* @return boolean
*/
public static function setNotDisturb(int $user_id, int $receiver_id, int $talk_type, int $is_disturb)
{
$result = self::query()
->where([
['user_id', '=', $user_id],
['talk_type', '=', $talk_type],
['receiver_id', '=', $receiver_id],
])
->first(['id', 'is_disturb']);
if (!$result || $is_disturb == $result->is_disturb) {
return false;
}
return (bool)self::query()->where('id', $result->id)->update([
'is_disturb' => $is_disturb,
'updated_at' => date('Y-m-d H:i:s')
]);
}
}

View File

@ -18,7 +18,9 @@ use Qbhy\HyperfAuth\Authenticatable;
* @property string $avatar 头像
* @property integer $gender 性别
* @property string $motto 座右铭
* @property integer $created_at 注册时间
* @property string $is_robot 是否机器人
* @property string $created_at 注册时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class User extends BaseModel implements Authenticatable
@ -35,7 +37,9 @@ class User extends BaseModel implements Authenticatable
'password',
'motto',
'email',
'created_at'
'is_robot',
'created_at',
'updated_at',
];
protected $casts = [];

View File

@ -1,149 +0,0 @@
<?php
declare (strict_types=1);
namespace App\Model;
/**
* 聊天列表组数据表模型
*
* @property int $id 聊天列表ID
* @property int $type 聊天类型[1:好友;2:群聊;]
* @property int $uid 用户ID
* @property int $friend_id 好友ID
* @property int $group_id 群组ID
* @property int $status 列表状态
* @property int $is_top 是否置顶
* @property int $not_disturb 是否消息免打扰
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
* @package App\Model
*/
class UsersChatList extends BaseModel
{
protected $table = 'users_chat_list';
protected $fillable = [
'type',
'uid',
'friend_id',
'group_id',
'status',
'is_top',
'not_disturb',
'created_at',
'updated_at'
];
protected $casts = [
'id' => 'integer',
'type' => 'integer',
'uid' => 'integer',
'friend_id' => 'integer',
'group_id' => 'integer',
'status' => 'integer',
'is_top' => 'integer',
'not_disturb' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
/**
* 创建聊天列表记录
*
* @param int $user_id 用户ID
* @param int $receive_id 接收者ID
* @param int $type 创建类型 1:私聊 2:群聊
* @return array
*/
public static function addItem(int $user_id, int $receive_id, int $type)
{
$result = self::query()->where('uid', $user_id)->where('type', $type)->where($type == 1 ? 'friend_id' : 'group_id', $receive_id)->first();
if ($result) {
$result->status = 1;
$result->updated_at = date('Y-m-d H:i:s');
$result->save();
return [
'id' => $result->id,
'type' => $result->type,
'friend_id' => $result->friend_id,
'group_id' => $result->group_id,
];
}
if (!$result = self::query()->create([
'type' => $type,
'uid' => $user_id,
'status' => 1,
'friend_id' => $type == 1 ? $receive_id : 0,
'group_id' => $type == 2 ? $receive_id : 0,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
])) {
return [];
}
return [
'id' => $result->id,
'type' => $result->type,
'friend_id' => $result->friend_id,
'group_id' => $result->group_id,
];
}
/**
* 聊天对话列表置顶操作
*
* @param int $user_id 用户ID
* @param int $list_id 对话列表ID
* @param bool $is_top 是否置顶true: false:否)
* @return bool
*/
public static function topItem(int $user_id, int $list_id, $is_top = true)
{
return (bool)self::query()->where('id', $list_id)->where('uid', $user_id)->update([
'is_top' => $is_top ? 1 : 0,
'updated_at' => date('Y-m-d H:i:s')
]);
}
/**
* 删除聊天列表
*
* @param int $user_id 用户ID
* @param int $id 聊天列表ID、好友ID或群聊ID
* @param int $type ID类型 1聊天列表ID 2:好友ID 3:群聊ID
* @return bool
*/
public static function delItem(int $user_id, int $id, $type = 1)
{
$data = ['status' => 0, 'updated_at' => date('Y-m-d H:i:s')];
if ($type == 1) {
return (bool)self::query()->where('id', $id)->where('uid', $user_id)->update($data);
} else if ($type == 2) {
return (bool)self::query()->where('uid', $user_id)->where('friend_id', $id)->update($data);
} else {
return (bool)self::query()->where('uid', $user_id)->where('group_id', $id)->update($data);
}
}
/**
* 设置消息免打扰
*
* @param int $user_id 用户ID
* @param int $receive_id 接收者ID
* @param int $type 接收者类型1:好友 2:群组)
* @param int $not_disturb 是否免打扰
* @return boolean
*/
public static function notDisturbItem(int $user_id, int $receive_id, int $type, int $not_disturb)
{
$result = self::query()->where('uid', $user_id)->where($type == 1 ? 'friend_id' : 'group_id', $receive_id)->where('status', 1)->first(['id', 'not_disturb']);
if (!$result || $not_disturb == $result->not_disturb) {
return false;
}
return (bool)self::query()->where('id', $result->id)->update(['not_disturb' => $not_disturb]);
}
}

View File

@ -57,9 +57,9 @@ class UsersFriend extends BaseModel
SELECT users.id,users.nickname,users.avatar,users.motto,users.gender,tmp_table.friend_remark from {$prefix}users users
INNER join
(
SELECT id as rid,user2 as uid,user1_remark as friend_remark from {$prefix}users_friends where user1 = {$uid} and `status` = 1
SELECT id as rid,user2 as uid,user1_remark as friend_remark from {$prefix}users_friends where user1 = {$uid} and `status` = 0
UNION all
SELECT id as rid,user1 as uid,user2_remark as friend_remark from {$prefix}users_friends where user2 = {$uid} and `status` = 1
SELECT id as rid,user1 as uid,user2_remark as friend_remark from {$prefix}users_friends where user2 = {$uid} and `status` = 0
) tmp_table on tmp_table.uid = users.id
SQL;
@ -92,7 +92,7 @@ SQL;
return true;
}
$isTrue = self::query()->where('user1', $user_id1)->where('user2', $user_id2)->where('status', 1)->exists();
$isTrue = self::query()->where('user1', $user_id1)->where('user2', $user_id2)->where('status', 0)->exists();
if ($isTrue) {
redis()->setex($cacheKey, 60 * 5, 1);
}
@ -109,7 +109,7 @@ SQL;
public static function getFriendIds(int $user_id)
{
$prefix = config('databases.default.prefix');
$sql = "SELECT user2 as uid from {$prefix}users_friends where user1 = {$user_id} and `status` = 1 UNION all SELECT user1 as uid from {$prefix}users_friends where user2 = {$user_id} and `status` = 1";
$sql = "SELECT user2 as uid from {$prefix}users_friends where user1 = {$user_id} and `status` = 0 UNION all SELECT user1 as uid from {$prefix}users_friends where user2 = {$user_id} and `status` = 0";
return array_map(function ($item) {
return $item->uid;
}, Db::select($sql));

View File

@ -210,23 +210,25 @@ class ArticleService extends BaseService
/**
* 删除笔记分类
*
* @param int $uid 用户ID
* @param int $user_id 用户ID
* @param int $class_id 分类ID
* @return bool
* @throws Exception
*/
public function delArticleClass(int $uid, int $class_id)
public function delArticleClass(int $user_id, int $class_id)
{
if (!ArticleClass::where('id', $class_id)->where('user_id', $uid)->exists()) {
return false;
}
$result = ArticleClass::where('id', $class_id)->where('user_id', $user_id)->first(['id', 'sort']);
if (!$result) return false;
$count = Article::where('user_id', $uid)->where('class_id', $class_id)->count();
if ($count > 0) {
return false;
}
$count = Article::where('user_id', $user_id)->where('class_id', $class_id)->count();
if ($count > 0) return false;
return (bool)ArticleClass::where('id', $class_id)->where('user_id', $uid)->where('is_default', 0)->delete();
Db::transaction(function () use ($user_id, $class_id, $result) {
ArticleClass::where('id', $class_id)->where('user_id', $user_id)->where('is_default', 0)->delete();
ArticleClass::where('user_id', $user_id)->where('sort', '>', $result->sort)->decrement('sort');
});
return true;
}
/**

View File

@ -40,19 +40,12 @@ class ContactsService extends BaseService
SELECT users.id,users.nickname,users.avatar,users.motto,users.gender,tmp_table.friend_remark from {$prefix}users users
INNER join
(
SELECT id as rid,user2 as uid,user1_remark as friend_remark from {$prefix}users_friends where user1 = {$user_id} and `status` = 1
SELECT id as rid,user2 as uid,user1_remark as friend_remark from {$prefix}users_friends where user1 = {$user_id} and `status` in (0,2)
UNION all
SELECT id as rid,user1 as uid,user2_remark as friend_remark from {$prefix}users_friends where user2 = {$user_id} and `status` = 1
SELECT id as rid,user1 as uid,user2_remark as friend_remark from {$prefix}users_friends where user2 = {$user_id} and `status` in (0,1)
) tmp_table on tmp_table.uid = users.id
SQL;
$rows = Db::select($sql);
array_walk($rows, function (&$item) {
$item = (array)$item;
});
return $rows;
return Db::select($sql);
}
/**

View File

@ -2,9 +2,11 @@
namespace App\Service;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsFile;
use App\Model\EmoticonDetail;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsFile;
use App\Model\EmoticonItem;
use App\Model\Group\Group;
use App\Model\UsersEmoticon;
@ -91,47 +93,42 @@ class EmoticonService extends BaseService
*/
public function collect(int $user_id, int $record_id)
{
$result = ChatRecord::where([
$result = TalkRecords::where([
['id', '=', $record_id],
['msg_type', '=', 2],
['msg_type', '=', TalkMsgType::FILE_MESSAGE],
['is_revoke', '=', 0],
])->first(['id', 'source', 'msg_type', 'user_id', 'receive_id', 'is_revoke']);
])->first(['id', 'talk_type', 'receiver_id', 'msg_type', 'user_id', 'is_revoke']);
if (!$result) {
return [false, []];
}
if (!$result) return [false, []];
if ($result->source == 1) {
if ($result->user_id != $user_id && $result->receive_id != $user_id) {
if ($result->talk_type == TalkType::PRIVATE_CHAT) {
if ($result->user_id != $user_id && $result->receiver_id != $user_id) {
return [false, []];
}
} else {
if (!Group::isMember($result->receive_id, $user_id)) {
if (!Group::isMember($result->receiver_id, $user_id)) {
return [false, []];
}
}
$fileInfo = ChatRecordsFile::where('record_id', $result->id)->where('file_type', 1)->first([
$fileInfo = TalkRecordsFile::where('record_id', $result->id)->where('file_type', 1)->first([
'file_suffix',
'file_size',
'save_dir'
]);
if (!$fileInfo) {
return [false, []];
}
if (!$fileInfo) return [false, []];
$result = EmoticonDetail::where('user_id', $user_id)->where('url', $fileInfo->save_dir)->first();
if ($result) {
return [false, []];
}
$result = EmoticonItem::where('user_id', $user_id)->where('url', $fileInfo->save_dir)->first();
if ($result) return [false, []];
$res = EmoticonDetail::create([
$res = EmoticonItem::create([
'user_id' => $user_id,
'url' => $fileInfo->save_dir,
'file_suffix' => $fileInfo->file_suffix,
'file_size' => $fileInfo->file_size,
'created_at' => time()
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
return $res ? [true, ['media_id' => $res->id, 'src' => get_media_url($res->url)]] : [false, []];
@ -147,7 +144,7 @@ class EmoticonService extends BaseService
*/
public function deleteCollect(int $user_id, array $ids)
{
return EmoticonDetail::whereIn('id', $ids)->where('user_id', $user_id)->delete();
return EmoticonItem::whereIn('id', $ids)->where('user_id', $user_id)->delete();
}
/**
@ -158,7 +155,7 @@ class EmoticonService extends BaseService
*/
public function getDetailsAll(array $where = [])
{
$items = EmoticonDetail::where($where)->get(['id as media_id', 'url as src'])->toArray();
$items = EmoticonItem::where($where)->get(['id as media_id', 'url as src'])->toArray();
foreach ($items as $k => $item) {
$items[$k]['src'] = get_media_url($item['src']);
}

View File

@ -4,11 +4,13 @@ declare(strict_types=1);
namespace App\Service;
use App\Cache\LastMessage;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsInvite;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsInvite;
use App\Model\Group\Group;
use App\Model\Group\GroupMember;
use App\Model\UsersChatList;
use App\Model\TalkList;
use Hyperf\DbConnection\Db;
use Exception;
@ -41,13 +43,16 @@ class GroupService extends BaseService
'group_member.leader',
])->toArray();
$arr = UsersChatList::where([
['uid', '=', $user_id],
['type', '=', 2],
])->get(['group_id', 'not_disturb'])->keyBy('group_id')->toArray();
$list = [];
if ($items) {
$list = TalkList::query()->where('user_id', $user_id)
->where('talk_type', TalkType::GROUP_CHAT)
->whereIn('receiver_id', array_column($items, 'id'))
->get(['receiver_id', 'is_disturb'])->keyBy('receiver_id')->toArray();
}
foreach ($items as $key => $item) {
$items[$key]['not_disturb'] = isset($arr[$item['id']]) ? $arr[$item['id']]['not_disturb'] : 0;
$items[$key]['is_disturb'] = isset($list[$item['id']]) ? $list[$item['id']]['is_disturb'] : 0;
}
return $items;
@ -82,23 +87,18 @@ class GroupService extends BaseService
'created_at' => date('Y-m-d H:i:s')
]);
foreach ($friend_ids as $k => $uid) {
foreach ($friend_ids as $friend_id) {
$groupMember[] = [
'group_id' => $insRes->id,
'user_id' => $uid,
'leader' => $user_id == $uid ? 2 : 0,
'is_mute' => 0,
'is_quit' => 0,
'user_card' => '',
'user_id' => $friend_id,
'leader' => $user_id == $friend_id ? 2 : 0,
'created_at' => date('Y-m-d H:i:s'),
];
$chatList[] = [
'type' => 2,
'uid' => $uid,
'friend_id' => 0,
'group_id' => $insRes->id,
'status' => 1,
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => $friend_id,
'receiver_id' => $insRes->id,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
];
@ -108,19 +108,20 @@ class GroupService extends BaseService
throw new Exception('创建群成员信息失败');
}
if (!Db::table('users_chat_list')->insert($chatList)) {
if (!Db::table('talk_list')->insert($chatList)) {
throw new Exception('创建群成员的聊天列表失败');
}
$result = ChatRecord::create([
'msg_type' => 3,
'source' => 2,
$result = TalkRecords::create([
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => 0,
'receive_id' => $insRes->id,
'created_at' => date('Y-m-d H:i:s')
'receiver_id' => $insRes->id,
'msg_type' => TalkMsgType::GROUP_INVITE_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
]);
ChatRecordsInvite::create([
TalkRecordsInvite::create([
'record_id' => $result->id,
'type' => 1,
'operate_user_id' => $user_id,
@ -133,7 +134,7 @@ class GroupService extends BaseService
return [false, 0];
}
LastMessage::getInstance()->save(2, $user_id, $insRes->id, [
LastMessage::getInstance()->save(TalkType::GROUP_CHAT, $user_id, $insRes->id, [
'text' => '[入群通知]',
'created_at' => date('Y-m-d H:i:s')
]);
@ -165,7 +166,7 @@ class GroupService extends BaseService
'is_quit' => 1,
'deleted_at' => date('Y-m-d H:i:s'),
]);
}, 2);
});
return true;
}
@ -192,34 +193,32 @@ class GroupService extends BaseService
$updateArr = $insertArr = $updateArr1 = $insertArr1 = [];
$members = GroupMember::where('group_id', $group_id)->whereIn('user_id', $friend_ids)->get(['id', 'user_id', 'is_quit'])->keyBy('user_id')->toArray();
$chatArr = UsersChatList::where('group_id', $group_id)->whereIn('uid', $friend_ids)->get(['id', 'uid', 'status'])->keyBy('uid')->toArray();
$chatArr = TalkList::where('talk_type', TalkType::GROUP_CHAT)
->where('receiver_id', $group_id)
->whereIn('user_id', $friend_ids)
->get(['id', 'user_id', 'is_delete'])
->keyBy('user_id')->toArray();
foreach ($friend_ids as $uid) {
if (!isset($members[$uid])) {
$insertArr[] = [
'group_id' => $group_id,
'user_id' => $uid,
'leader' => 0,
'is_mute' => 0,
'is_quit' => 0,
'user_card' => '',
'created_at' => date('Y-m-d H:i:s')
];
} else if ($members[$uid]['status'] == 1) {
} else if ($members[$uid]['is_quit'] == 1) {
$updateArr[] = $members[$uid]['id'];
}
if (!isset($chatArr[$uid])) {
$insertArr1[] = [
'type' => 2,
'uid' => $uid,
'friend_id' => 0,
'group_id' => $group_id,
'status' => 1,
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => $uid,
'receiver_id' => $group_id,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
];
} else if ($chatArr[$uid]['status'] == 0) {
} else if ($chatArr[$uid]['is_delete'] == 1) {
$updateArr1[] = $chatArr[$uid]['id'];
}
}
@ -240,25 +239,26 @@ class GroupService extends BaseService
}
if ($updateArr1) {
UsersChatList::whereIn('id', $updateArr1)->update([
'status' => 1,
TalkList::whereIn('id', $updateArr1)->update([
'is_delete' => 1,
'created_at' => date('Y-m-d H:i:s')
]);
}
if ($insertArr1) {
Db::table('users_chat_list')->insert($insertArr1);
Db::table('talk_list')->insert($insertArr1);
}
$result = ChatRecord::create([
'msg_type' => 3,
'source' => 2,
$result = TalkRecords::create([
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => 0,
'receive_id' => $group_id,
'created_at' => date('Y-m-d H:i:s')
'receiver_id' => $group_id,
'msg_type' => TalkMsgType::GROUP_INVITE_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
]);
ChatRecordsInvite::create([
TalkRecordsInvite::create([
'record_id' => $result->id,
'type' => 1,
'operate_user_id' => $user_id,
@ -271,7 +271,7 @@ class GroupService extends BaseService
return [false, 0];
}
LastMessage::getInstance()->save(2, $user_id, $group_id, [
LastMessage::getInstance()->save(TalkType::GROUP_CHAT, $user_id, $group_id, [
'text' => '[入群通知]',
'created_at' => date('Y-m-d H:i:s')
]);
@ -304,25 +304,32 @@ class GroupService extends BaseService
throw new Exception('更新记录失败...');
}
$result = ChatRecord::create([
'msg_type' => 3,
'source' => 2,
$result = TalkRecords::create([
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => 0,
'receive_id' => $group_id,
'receiver_id' => $group_id,
'msg_type' => TalkMsgType::GROUP_INVITE_MESSAGE,
'content' => $user_id,
'created_at' => date('Y-m-d H:i:s')
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
]);
$record_id = $result->id;
ChatRecordsInvite::create([
TalkRecordsInvite::create([
'record_id' => $result->id,
'type' => 2,
'operate_user_id' => $user_id,
'user_ids' => $user_id
]);
UsersChatList::where('uid', $user_id)->where('type', 2)->where('group_id', $group_id)->update(['status' => 0]);
TalkList::where([
['talk_type', '=', TalkType::GROUP_CHAT],
['user_id', '=', $user_id],
['receiver_id', '=', $group_id],
])->update([
'is_delete' => 1
]);
Db::commit();
} catch (Exception $e) {
@ -358,23 +365,24 @@ class GroupService extends BaseService
throw new Exception('更新记录失败...');
}
$result = ChatRecord::create([
'msg_type' => 3,
'source' => 2,
$result = TalkRecords::create([
'talk_type' => TalkType::GROUP_CHAT,
'user_id' => 0,
'receive_id' => $group_id,
'created_at' => date('Y-m-d H:i:s')
'receiver_id' => $group_id,
'msg_type' => TalkMsgType::GROUP_INVITE_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
ChatRecordsInvite::create([
TalkRecordsInvite::create([
'record_id' => $result->id,
'type' => 3,
'operate_user_id' => $user_id,
'user_ids' => implode(',', $member_ids)
]);
UsersChatList::whereIn('uid', $member_ids)->where('group_id', $group_id)->update([
'status' => 0,
TalkList::whereIn('user_id', $member_ids)->where('receiver_id', $group_id)->where('talk_type', TalkType::GROUP_CHAT)->update([
'is_delete' => 1,
'updated_at' => date('Y-m-d H:i:s')
]);

View File

@ -2,12 +2,15 @@
namespace App\Service;
use App\Constants\SocketConstants;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use Hyperf\Di\Annotation\Inject;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use App\Amqp\Producer\ChatMessageProducer;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\TalkRecords;
use App\Model\Group\Group;
use App\Model\UsersFriend;
use App\Cache\LastMessage;
@ -32,56 +35,56 @@ class MessageHandleService
public function onTalk($server, Frame $frame, $data)
{
$user_id = $this->socketClientService->findFdUserId($frame->fd);
if ($user_id != $data['send_user']) {
if ($user_id != $data['sender_id']) {
return;
}
// 验证消息类型 私聊|群聊
if (!in_array($data['source_type'], [1, 2])) {
if (!in_array($data['talk_type'], TalkType::getTypes())) {
return;
}
// 验证发送消息用户与接受消息用户之间是否存在好友或群聊关系(后期走缓存)
if ($data['source_type'] == 1) {// 私信
if ($data['talk_type'] == TalkType::PRIVATE_CHAT) {
// 判断发送者和接受者是否是好友关系
if (!UsersFriend::isFriend((int)$data['send_user'], (int)$data['receive_user'], true)) {
if (!UsersFriend::isFriend((int)$data['sender_id'], (int)$data['receiver_id'], true)) {
return;
}
} else if ($data['source_type'] == 2) {// 群聊
} else if ($data['talk_type'] == TalkType::GROUP_CHAT) {
// 判断是否属于群成员
if (!Group::isMember((int)$data['receive_user'], (int)$data['send_user'])) {
if (!Group::isMember((int)$data['receiver_id'], (int)$data['sender_id'])) {
return;
}
}
$result = ChatRecord::create([
'source' => $data['source_type'],
'msg_type' => 1,
'user_id' => $data['send_user'],
'receive_id' => $data['receive_user'],
$result = TalkRecords::create([
'talk_type' => $data['talk_type'],
'user_id' => $data['sender_id'],
'receiver_id' => $data['receiver_id'],
'msg_type' => TalkMsgType::TEXT_MESSAGE,
'content' => htmlspecialchars($data['text_message']),
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
if (!$result) return;
// 判断是否私聊
if ($result->source == 1) {
if ($result->talk_type == TalkType::PRIVATE_CHAT) {
// 设置好友消息未读数
UnreadTalk::getInstance()->increment($result->user_id, $result->receive_id);
UnreadTalk::getInstance()->increment($result->user_id, $result->receiver_id);
}
// 缓存最后一条聊天消息
LastMessage::getInstance()->save($result->source, $result->user_id, $result->receive_id, [
LastMessage::getInstance()->save($result->talk_type, $result->user_id, $result->receiver_id, [
'text' => mb_substr($result->content, 0, 30),
'created_at' => $result->created_at
]);
// 推送消息
push_amqp(new ChatMessageProducer('event_talk', [
'sender' => intval($data['send_user']), // 发送者ID
'receive' => intval($data['receive_user']), // 接收者ID
'source' => intval($data['source_type']), // 接收者类型[1:好友;2:群组;]
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_TALK, [
'sender_id' => $result->user_id,
'receiver_id' => $result->receiver_id,
'talk_type' => $result->talk_type,
'record_id' => $result->id
]));
}
@ -92,12 +95,13 @@ class MessageHandleService
* @param Response|Server $server
* @param Frame $frame
* @param array|string $data 解析后数据
* @return false
*/
public function onKeyboard($server, Frame $frame, $data)
{
push_amqp(new ChatMessageProducer('event_keyboard', [
'send_user' => intval($data['send_user']), // 发送者ID
'receive_user' => intval($data['receive_user']), // 接收者ID
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_KEYBOARD, [
'sender_id' => intval($data['sender_id']),
'receiver_id' => intval($data['receiver_id']),
]));
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Service;
class TalkMessageService
{
}

View File

@ -4,16 +4,18 @@ namespace App\Service;
use App\Cache\ServerRunID;
use App\Constants\FileMediaType;
use App\Constants\TalkMsgType;
use App\Constants\TalkType;
use Exception;
use App\Model\User;
use App\Model\UsersChatList;
use App\Model\TalkList;
use App\Model\UsersFriend;
use App\Model\Group\Group;
use App\Model\Chat\ChatRecord;
use App\Model\Chat\ChatRecordsCode;
use App\Model\Chat\ChatRecordsFile;
use App\Model\Chat\ChatRecordsForward;
use App\Model\Chat\ChatRecordsInvite;
use App\Model\Chat\TalkRecords;
use App\Model\Chat\TalkRecordsCode;
use App\Model\Chat\TalkRecordsFile;
use App\Model\Chat\TalkRecordsForward;
use App\Model\Chat\TalkRecordsInvite;
use App\Traits\PagingTrait;
use Hyperf\DbConnection\Db;
use App\Cache\FriendRemark;
@ -33,17 +35,21 @@ class TalkService extends BaseService
public function talks(int $user_id)
{
$filed = [
'list.id', 'list.type', 'list.friend_id', 'list.group_id', 'list.updated_at', 'list.not_disturb', 'list.is_top',
'list.id', 'list.talk_type', 'list.receiver_id', 'list.updated_at', 'list.is_disturb', 'list.is_top',
'users.avatar as user_avatar', 'users.nickname',
'group.group_name', 'group.avatar as group_avatar'
];
$rows = UsersChatList::from('users_chat_list as list')
->leftJoin('users', 'users.id', '=', 'list.friend_id')
->leftJoin('group', 'group.id', '=', 'list.group_id')
->where('list.uid', $user_id)
->where('list.status', 1)
->orderBy('updated_at', 'desc')
$rows = TalkList::from('talk_list as list')
->leftJoin('users', function ($join) {
$join->on('users.id', '=', 'list.receiver_id')->where('list.talk_type', '=', TalkType::PRIVATE_CHAT);
})
->leftJoin('group', function ($join) {
$join->on('group.id', '=', 'list.receiver_id')->where('list.talk_type', '=', TalkType::GROUP_CHAT);
})
->where('list.user_id', $user_id)
->where('list.is_delete', 0)
->orderBy('list.updated_at', 'desc')
->get($filed)
->toArray();
@ -54,36 +60,35 @@ class TalkService extends BaseService
return array_map(function ($item) use ($user_id, $socketFDService, $runIdAll) {
$data['id'] = $item['id'];
$data['type'] = $item['type'];
$data['friend_id'] = $item['friend_id'];
$data['group_id'] = $item['group_id'];
$data['name'] = ''; // 对方昵称/群名称
$data['talk_type'] = $item['talk_type'];
$data['receiver_id'] = $item['receiver_id'];
$data['avatar'] = ''; // 默认头像
$data['name'] = ''; // 对方昵称/群名称
$data['remark_name'] = ''; // 好友备注
$data['unread_num'] = 0; // 未读消息数量
$data['unread_num'] = 0; // 未读消息
$data['is_online'] = false; // 是否在线
$data['is_top'] = $item['is_top'];
$data['is_disturb'] = $item['is_disturb'];
$data['msg_text'] = '......';
$data['updated_at'] = $item['updated_at'];
$data['online'] = 0;
$data['is_top'] = $item['is_top'];
$data['not_disturb'] = $item['not_disturb'];
if ($item['type'] == 1) {
if ($item['talk_type'] == TalkType::PRIVATE_CHAT) {
$data['name'] = $item['nickname'];
$data['avatar'] = $item['user_avatar'];
$data['unread_num'] = UnreadTalk::getInstance()->read((int)$item['friend_id'], $user_id);
$data['online'] = $socketFDService->isOnlineAll($item['friend_id'], $runIdAll);
$data['unread_num'] = UnreadTalk::getInstance()->read($item['receiver_id'], $user_id);
$data['is_online'] = $socketFDService->isOnlineAll($item['receiver_id'], $runIdAll);
$remark = FriendRemark::getInstance()->read($user_id, (int)$item['friend_id']);
$remark = FriendRemark::getInstance()->read($user_id, $item['receiver_id']);
if ($remark) {
$data['remark_name'] = $remark;
} else {
$info = UsersFriend::select('user1', 'user2', 'user1_remark', 'user2_remark')
->where('user1', ($user_id < $item['friend_id']) ? $user_id : $item['friend_id'])
->where('user2', ($user_id < $item['friend_id']) ? $item['friend_id'] : $user_id)->first();
->where('user1', ($user_id < $item['receiver_id']) ? $user_id : $item['receiver_id'])
->where('user2', ($user_id < $item['receiver_id']) ? $item['receiver_id'] : $user_id)->first();
if ($info) {
$data['remark_name'] = $info->user1 == $item['friend_id'] ? $info->user2_remark : $info->user1_remark;
$data['remark_name'] = $info->user1 == $item['receiver_id'] ? $info->user2_remark : $info->user1_remark;
FriendRemark::getInstance()->save($user_id, (int)$item['friend_id'], $data['remark_name']);
FriendRemark::getInstance()->save($user_id, (int)$item['receiver_id'], $data['remark_name']);
}
}
} else {
@ -91,7 +96,7 @@ class TalkService extends BaseService
$data['avatar'] = $item['group_avatar'];
}
$records = LastMessage::getInstance()->read((int)$item['type'], $user_id, $item['type'] == 1 ? (int)$item['friend_id'] : (int)$item['group_id']);
$records = LastMessage::getInstance()->read($data['talk_type'], $user_id, $data['receiver_id']);
if ($records) {
$data['msg_text'] = $records['text'];
$data['updated_at'] = $records['created_at'];
@ -112,12 +117,12 @@ class TalkService extends BaseService
public function updateUnreadTalkList(int $user_id, $data)
{
foreach ($data as $friend_id => $num) {
UsersChatList::updateOrCreate([
'uid' => $user_id,
'friend_id' => intval($friend_id),
'type' => 1
TalkList::updateOrCreate([
'talk_type' => TalkType::PRIVATE_CHAT,
'user_id' => $user_id,
'receiver_id' => $friend_id,
], [
'status' => 1,
'is_delete' => 0,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
]);
@ -137,16 +142,16 @@ class TalkService extends BaseService
$files = $codes = $forwards = $invites = [];
foreach ($rows as $value) {
switch ($value['msg_type']) {
case 2:
case TalkMsgType::FILE_MESSAGE:
$files[] = $value['id'];
break;
case 3:
case TalkMsgType::GROUP_INVITE_MESSAGE:
$invites[] = $value['id'];
break;
case 4:
case TalkMsgType::FORWARD_MESSAGE:
$forwards[] = $value['id'];
break;
case 5:
case TalkMsgType::CODE_MESSAGE:
$codes[] = $value['id'];
break;
}
@ -154,22 +159,22 @@ class TalkService extends BaseService
// 查询聊天文件信息
if ($files) {
$files = ChatRecordsFile::whereIn('record_id', $files)->get(['id', 'record_id', 'user_id', 'file_source', 'file_type', 'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir'])->keyBy('record_id')->toArray();
$files = TalkRecordsFile::whereIn('record_id', $files)->get(['id', 'record_id', 'user_id', 'file_source', 'file_type', 'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir'])->keyBy('record_id')->toArray();
}
// 查询群聊邀请信息
if ($invites) {
$invites = ChatRecordsInvite::whereIn('record_id', $invites)->get(['record_id', 'type', 'operate_user_id', 'user_ids'])->keyBy('record_id')->toArray();
$invites = TalkRecordsInvite::whereIn('record_id', $invites)->get(['record_id', 'type', 'operate_user_id', 'user_ids'])->keyBy('record_id')->toArray();
}
// 查询代码块消息
if ($codes) {
$codes = ChatRecordsCode::whereIn('record_id', $codes)->get(['record_id', 'code_lang', 'code'])->keyBy('record_id')->toArray();
$codes = TalkRecordsCode::whereIn('record_id', $codes)->get(['record_id', 'code_lang', 'code'])->keyBy('record_id')->toArray();
}
// 查询消息转发信息
if ($forwards) {
$forwards = ChatRecordsForward::whereIn('record_id', $forwards)->get(['record_id', 'records_id', 'text'])->keyBy('record_id')->toArray();
$forwards = TalkRecordsForward::whereIn('record_id', $forwards)->get(['record_id', 'records_id', 'text'])->keyBy('record_id')->toArray();
}
foreach ($rows as $k => $row) {
@ -179,13 +184,31 @@ class TalkService extends BaseService
$rows[$k]['invite'] = [];
switch ($row['msg_type']) {
case 2:// 文件消息
case TalkMsgType::FILE_MESSAGE:// 文件消息
$rows[$k]['file'] = $files[$row['id']] ?? [];
if ($rows[$k]['file']) {
$rows[$k]['file']['file_url'] = get_media_url($rows[$k]['file']['save_dir']);
}
break;
case 3:// 入群消息/退群消息
case TalkMsgType::FORWARD_MESSAGE:// 会话记录消息
if (isset($forwards[$row['id']])) {
$rows[$k]['forward'] = [
'num' => substr_count($forwards[$row['id']]['records_id'], ',') + 1,
'list' => json_decode($forwards[$row['id']]['text'], true) ?? []
];
}
break;
case TalkMsgType::CODE_MESSAGE:// 代码块消息
$rows[$k]['code_block'] = $codes[$row['id']] ?? [];
if ($rows[$k]['code_block']) {
$rows[$k]['code_block']['code'] = htmlspecialchars_decode($rows[$k]['code_block']['code']);
unset($rows[$k]['code_block']['record_id']);
}
break;
case TalkMsgType::GROUP_INVITE_MESSAGE:// 入群消息/退群消息
if (isset($invites[$row['id']])) {
$rows[$k]['invite'] = [
'type' => $invites[$row['id']]['type'],
@ -203,21 +226,6 @@ class TalkService extends BaseService
}
}
break;
case 4:// 会话记录消息
if (isset($forwards[$row['id']])) {
$rows[$k]['forward'] = [
'num' => substr_count($forwards[$row['id']]['records_id'], ',') + 1,
'list' => json_decode($forwards[$row['id']]['text'], true) ?? []
];
}
break;
case 5:// 代码块消息
$rows[$k]['code_block'] = $codes[$row['id']] ?? [];
if ($rows[$k]['code_block']) {
$rows[$k]['code_block']['code'] = htmlspecialchars_decode($rows[$k]['code_block']['code']);
unset($rows[$k]['code_block']['record_id']);
}
break;
}
}
@ -229,64 +237,65 @@ class TalkService extends BaseService
* 查询对话页面的历史聊天记录
*
* @param int $user_id 用户ID
* @param int $receive_id 接收者ID好友ID或群ID
* @param int $source 消息来源 1:好友消息 2:群聊消息
* @param int $receiver_id 接收者ID好友ID或群ID
* @param int $talk_type 对话类型[1:好友消息;2:群聊消息;]
* @param int $record_id 上一次查询的聊天记录ID
* @param int $limit 查询数据长度
* @param array $msg_type 消息类型
* @return array
*/
public function getChatRecords(int $user_id, int $receive_id, int $source, int $record_id, $limit = 30, $msg_type = [])
public function getChatRecords(int $user_id, int $receiver_id, int $talk_type, int $record_id, $limit = 30, $msg_type = [])
{
$fields = [
'chat_records.id',
'chat_records.source',
'chat_records.msg_type',
'chat_records.user_id',
'chat_records.receive_id',
'chat_records.content',
'chat_records.is_revoke',
'chat_records.created_at',
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.is_revoke',
'talk_records.content',
'talk_records.created_at',
'users.nickname',
'users.avatar as avatar',
];
$rowsSqlObj = ChatRecord::select($fields);
$rowsSqlObj = TalkRecords::select($fields);
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'chat_records.user_id');
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'talk_records.user_id');
if ($record_id) {
$rowsSqlObj->where('chat_records.id', '<', $record_id);
$rowsSqlObj->where('talk_records.id', '<', $record_id);
}
if ($source == 1) {
$rowsSqlObj->where(function ($query) use ($user_id, $receive_id) {
if ($talk_type == TalkType::PRIVATE_CHAT) {
$rowsSqlObj->where(function ($query) use ($user_id, $receiver_id) {
$query->where([
['chat_records.user_id', '=', $user_id],
['chat_records.receive_id', '=', $receive_id]
['talk_records.user_id', '=', $user_id],
['talk_records.receiver_id', '=', $receiver_id]
])->orWhere([
['chat_records.user_id', '=', $receive_id],
['chat_records.receive_id', '=', $user_id]
['talk_records.user_id', '=', $receiver_id],
['talk_records.receiver_id', '=', $user_id]
]);
});
} else {
$rowsSqlObj->where('chat_records.receive_id', $receive_id);
$rowsSqlObj->where('chat_records.source', $source);
$rowsSqlObj->where('talk_records.receiver_id', $receiver_id);
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
}
if ($msg_type) {
$rowsSqlObj->whereIn('chat_records.msg_type', $msg_type);
$rowsSqlObj->whereIn('talk_records.msg_type', $msg_type);
}
//过滤用户删除记录
$rowsSqlObj->whereNotExists(function ($query) use ($user_id) {
$prefix = config('databases.default.prefix');
$query->select(Db::raw(1))->from('chat_records_delete');
$query->whereRaw("{$prefix}chat_records_delete.record_id = {$prefix}chat_records.id and {$prefix}chat_records_delete.user_id = {$user_id}");
$query->select(Db::raw(1))->from('talk_records_delete');
$query->whereRaw("{$prefix}talk_records_delete.record_id = {$prefix}talk_records.id and {$prefix}talk_records_delete.user_id = {$user_id}");
$query->limit(1);
});
$rows = $rowsSqlObj->orderBy('chat_records.id', 'desc')->limit($limit)->get()->toArray();
return $this->handleChatRecords($rows);
return $this->handleChatRecords(
$rowsSqlObj->orderBy('talk_records.id', 'desc')->limit($limit)->get()->toArray()
);
}
/**
@ -298,35 +307,35 @@ class TalkService extends BaseService
*/
public function getForwardRecords(int $user_id, int $record_id)
{
$result = ChatRecord::where('id', $record_id)->first([
'id', 'source', 'msg_type', 'user_id', 'receive_id', 'content', 'is_revoke', 'created_at'
$result = TalkRecords::where('id', $record_id)->first([
'id', 'talk_type', 'msg_type', 'user_id', 'receiver_id', 'content', 'is_revoke', 'created_at'
]);
// 判断是否有权限查看
if ($result->source == 1 && ($result->user_id != $user_id && $result->receive_id != $user_id)) {
if ($result->talk_type == TalkType::PRIVATE_CHAT && ($result->user_id != $user_id && $result->receiver_id != $user_id)) {
return [];
} else if ($result->source == 2 && !Group::isMember($result->receive_id, $user_id)) {
} else if ($result->talk_type == TalkType::GROUP_CHAT && !Group::isMember($result->receiver_id, $user_id)) {
return [];
}
$forward = ChatRecordsForward::where('record_id', $record_id)->first();
$forward = TalkRecordsForward::where('record_id', $record_id)->first();
$fields = [
'chat_records.id',
'chat_records.source',
'chat_records.msg_type',
'chat_records.user_id',
'chat_records.receive_id',
'chat_records.content',
'chat_records.is_revoke',
'chat_records.created_at',
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.is_revoke',
'talk_records.content',
'talk_records.created_at',
'users.nickname',
'users.avatar as avatar',
];
$rowsSqlObj = ChatRecord::select($fields);
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'chat_records.user_id');
$rowsSqlObj->whereIn('chat_records.id', explode(',', $forward->records_id));
$rowsSqlObj = TalkRecords::select($fields);
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'talk_records.user_id');
$rowsSqlObj->whereIn('talk_records.id', explode(',', $forward->records_id));
return $this->handleChatRecords($rowsSqlObj->get()->toArray());
}
@ -335,19 +344,20 @@ class TalkService extends BaseService
* 批量删除聊天消息
*
* @param int $user_id 用户ID
* @param int $source 消息来源 1:好友消息 2:群聊消息
* @param int $receive_id 好友ID或者群聊ID
* @param int $talk_type 对话类型[1:好友消息;2:群聊消息;]
* @param int $receiver_id 好友ID或者群聊ID
* @param array $record_ids 聊天记录ID
* @return bool
*/
public function removeRecords(int $user_id, int $source, int $receive_id, array $record_ids)
public function removeRecords(int $user_id, int $talk_type, int $receiver_id, array $record_ids)
{
if ($source == 1) {// 私聊信息
$ids = ChatRecord::whereIn('id', $record_ids)->where(function ($query) use ($user_id, $receive_id) {
$query->where([['user_id', '=', $user_id], ['receive_id', '=', $receive_id]])->orWhere([['user_id', '=', $receive_id], ['receive_id', '=', $user_id]]);
})->where('source', 1)->pluck('id');
if ($talk_type == TalkType::PRIVATE_CHAT) {// 私聊信息
$ids = TalkRecords::whereIn('id', $record_ids)->where(function ($query) use ($user_id, $receiver_id) {
$query->where([['user_id', '=', $user_id], ['receiver_id', '=', $receiver_id]])
->orWhere([['user_id', '=', $receiver_id], ['receiver_id', '=', $user_id]]);
})->where('talk_type', $talk_type)->pluck('id');
} else {// 群聊信息
$ids = ChatRecord::whereIn('id', $record_ids)->where('source', 2)->pluck('id');
$ids = TalkRecords::whereIn('id', $record_ids)->where('talk_type', TalkType::GROUP_CHAT)->pluck('id');
}
// 判断要删除的消息在数据库中是否存在
@ -356,7 +366,7 @@ class TalkService extends BaseService
}
// 判读是否属于群消息并且判断是否是群成员
if ($source == 2 && !Group::isMember($receive_id, $user_id)) {
if ($talk_type == TalkType::GROUP_CHAT && !Group::isMember($receiver_id, $user_id)) {
return false;
}
@ -368,7 +378,7 @@ class TalkService extends BaseService
];
}, $ids->toArray());
return Db::table('chat_records_delete')->insert($data);
return Db::table('talk_records_delete')->insert($data);
}
/**
@ -380,7 +390,7 @@ class TalkService extends BaseService
*/
public function revokeRecord(int $user_id, int $record_id)
{
$result = ChatRecord::where('id', $record_id)->first(['id', 'source', 'user_id', 'receive_id', 'created_at']);
$result = TalkRecords::where('id', $record_id)->first(['id', 'talk_type', 'user_id', 'receiver_id', 'created_at']);
if (!$result) return [false, '消息记录不存在'];
// 判断是否在两分钟之内撤回消息超过2分钟不能撤回消息
@ -388,12 +398,12 @@ class TalkService extends BaseService
return [false, '已超过有效的撤回时间', []];
}
if ($result->source == 1) {
if ($result->user_id != $user_id && $result->receive_id != $user_id) {
if ($result->talk_type == TalkType::PRIVATE_CHAT) {
if ($result->user_id != $user_id && $result->receiver_id != $user_id) {
return [false, '非法操作', []];
}
} else if ($result->source == 2) {
if (!Group::isMember($result->receive_id, $user_id)) {
} else if ($result->talk_type == TalkType::GROUP_CHAT) {
if (!Group::isMember($result->receiver_id, $user_id)) {
return [false, '非法操作', []];
}
}
@ -409,57 +419,64 @@ class TalkService extends BaseService
*
* @param int $user_id 转发的用户ID
* @param int $record_id 转发消息的记录ID
* @param array $receive_ids 接受者数组 例如:[['source' => 1,'id' => 3045],['source' => 1,'id' => 3046],['source' =>
* 1,'id' => 1658]] 二维数组
* @param array $receiver_ids 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function forwardRecords(int $user_id, int $record_id, array $receive_ids)
public function forwardRecords(int $user_id, int $record_id, array $receiver_ids)
{
$result = ChatRecord::where('id', $record_id)->whereIn('msg_type', [1, 2, 5])->first();
if (!$result) {
return [];
}
$msgTypeArray = [
TalkMsgType::TEXT_MESSAGE,
TalkMsgType::FILE_MESSAGE,
TalkMsgType::CODE_MESSAGE
];
$result = TalkRecords::where('id', $record_id)->whereIn('msg_type', $msgTypeArray)->first();
if (!$result) return [];
// 根据消息类型判断用户是否有转发权限
if ($result->source == 1) {
if ($result->user_id != $user_id && $result->receive_id != $user_id) {
if ($result->talk_type == TalkType::PRIVATE_CHAT) {
if ($result->user_id != $user_id && $result->receiver_id != $user_id) {
return [];
}
} else if ($result->source == 2) {
if (!Group::isMember($result->receive_id, $user_id)) {
} else if ($result->talk_type == TalkType::GROUP_CHAT) {
if (!Group::isMember($result->receiver_id, $user_id)) {
return [];
}
}
$fileInfo = null;
$codeBlock = null;
if ($result->msg_type == 2) {
$fileInfo = ChatRecordsFile::where('record_id', $record_id)->first();
} else if ($result->msg_type == 5) {
$codeBlock = ChatRecordsCode::where('record_id', $record_id)->first();
$fileInfo = $codeBlock = null;
if ($result->msg_type == TalkMsgType::FILE_MESSAGE) {
$fileInfo = TalkRecordsFile::where('record_id', $record_id)->first();
} else if ($result->msg_type == TalkMsgType::CODE_MESSAGE) {
$codeBlock = TalkRecordsCode::where('record_id', $record_id)->first();
}
$insRecordIds = [];
Db::beginTransaction();
try {
foreach ($receive_ids as $item) {
$res = ChatRecord::create([
'source' => $item['source'],
foreach ($receiver_ids as $item) {
$res = TalkRecords::create([
'talk_type' => $item['talk_type'],
'msg_type' => $result->msg_type,
'user_id' => $user_id,
'receive_id' => $item['id'],
'receiver_id' => $item['id'],
'content' => $result->content,
'created_at' => date('Y-m-d H:i:s')
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
if (!$res) {
throw new Exception('插入消息记录失败');
}
$insRecordIds[] = $res->id;
$insRecordIds[] = [
'record_id' => $res->id,
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
if ($result->msg_type == 2) {
if (!ChatRecordsFile::create([
if ($result->msg_type == TalkMsgType::FILE_MESSAGE) {
if (!TalkRecordsFile::create([
'record_id' => $res->id,
'user_id' => $fileInfo->user_id,
'file_source' => $fileInfo->file_source,
@ -473,8 +490,8 @@ class TalkService extends BaseService
])) {
throw new Exception('插入文件消息记录失败');
}
} else if ($result->msg_type == 5) {
if (!ChatRecordsCode::create([
} else if ($result->msg_type == TalkMsgType::CODE_MESSAGE) {
if (!TalkRecordsCode::create([
'record_id' => $res->id,
'user_id' => $user_id,
'code_lang' => $codeBlock->code_lang,
@ -499,43 +516,39 @@ class TalkService extends BaseService
* 转发消息(多条合并转发)
*
* @param int $user_id 转发的用户ID
* @param int $receive_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $source 消息来源 1:好友消息 2:群聊消息
* @param int $receiver_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $talk_type 消息来源 1:好友消息 2:群聊消息
* @param array $records_ids 转发消息的记录ID
* @param array $receive_ids 接受者数组 例如:[['source' => 1,'id' => 3045],['source' => 1,'id' => 3046],['source' =>
* 1,'id' => 1658]] 二维数组
* @return array|bool
* @param array $receive_ids 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function mergeForwardRecords(int $user_id, int $receive_id, int $source, array $records_ids, array $receive_ids)
public function mergeForwardRecords(int $user_id, int $receiver_id, int $talk_type, array $records_ids, array $receive_ids)
{
// 支持转发的消息类型
$msg_type = [1, 2, 5];
$msg_type = [
TalkMsgType::TEXT_MESSAGE,
TalkMsgType::FILE_MESSAGE,
TalkMsgType::CODE_MESSAGE
];
$sqlObj = ChatRecord::whereIn('id', $records_ids);
$sqlObj = TalkRecords::whereIn('id', $records_ids);
// 验证是否有权限转发
if ($source == 2) {// 群聊消息
// 判断是否是群聊成员
if (!Group::isMember($receive_id, $user_id)) {
return false;
}
if ($talk_type == TalkType::PRIVATE_CHAT) {
if (!UsersFriend::isFriend($user_id, $receiver_id)) return [];
$sqlObj = $sqlObj->where('receive_id', $receive_id)->whereIn('msg_type', $msg_type)->where('source', 2)->where('is_revoke', 0);
} else {// 私聊消息
// 判断是否存在好友关系
if (!UsersFriend::isFriend($user_id, $receive_id)) {
return [];
}
$sqlObj = $sqlObj->where(function ($query) use ($user_id, $receive_id) {
$sqlObj = $sqlObj->where(function ($query) use ($user_id, $receiver_id) {
$query->where([
['user_id', '=', $user_id],
['receive_id', '=', $receive_id]
['receiver_id', '=', $receiver_id]
])->orWhere([
['user_id', '=', $receive_id],
['receive_id', '=', $user_id]
['user_id', '=', $receiver_id],
['receiver_id', '=', $user_id]
]);
})->whereIn('msg_type', $msg_type)->where('source', 1)->where('is_revoke', 0);
})->whereIn('msg_type', $msg_type)->where('talk_type', $talk_type)->where('is_revoke', 0);
} else {
if (!Group::isMember($receiver_id, $user_id)) return [];
$sqlObj = $sqlObj->where('receiver_id', $receiver_id)->whereIn('msg_type', $msg_type)->where('talk_type', TalkType::GROUP_CHAT)->where('is_revoke', 0);
}
$result = $sqlObj->get();
@ -545,26 +558,26 @@ class TalkService extends BaseService
return [];
}
$rows = ChatRecord::leftJoin('users', 'users.id', '=', 'chat_records.user_id')
->whereIn('chat_records.id', array_slice($records_ids, 0, 3))
->get(['chat_records.msg_type', 'chat_records.content', 'users.nickname']);
$rows = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->whereIn('talk_records.id', array_slice($records_ids, 0, 3))
->get(['talk_records.msg_type', 'talk_records.content', 'users.nickname']);
$jsonText = [];
foreach ($rows as $row) {
switch ($row->msg_type) {
case 1:
case TalkMsgType::TEXT_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => mb_substr(str_replace(PHP_EOL, "", $row->content), 0, 30)
];
break;
case 2:
case TalkMsgType::FILE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【文件消息】'
];
break;
case 3:
case TalkMsgType::CODE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【代码消息】'
@ -577,12 +590,13 @@ class TalkService extends BaseService
Db::beginTransaction();
try {
foreach ($receive_ids as $item) {
$res = ChatRecord::create([
'source' => $item['source'],
'msg_type' => 4,
$res = TalkRecords::create([
'talk_type' => $item['talk_type'],
'user_id' => $user_id,
'receive_id' => $item['id'],
'created_at' => date('Y-m-d H:i:s')
'receiver_id' => $item['id'],
'msg_type' => TalkMsgType::FORWARD_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
if (!$res) {
@ -591,11 +605,11 @@ class TalkService extends BaseService
$insRecordIds[] = [
'record_id' => $res->id,
'receive_id' => $item['id'],
'source' => $item['source']
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
if (!ChatRecordsForward::create([
if (!TalkRecordsForward::create([
'record_id' => $res->id,
'user_id' => $user_id,
'records_id' => implode(',', $records_ids),
@ -619,51 +633,50 @@ class TalkService extends BaseService
* 关键词搜索聊天记录
*
* @param int $user_id 用户ID
* @param int $receive_id 接收者ID(用户ID或群聊接收ID)
* @param int $source 聊天来源1:私信 2:群聊)
* @param int $receiver_id 接收者ID
* @param int $talk_type 对话类型[1:私信;2:群聊;]
* @param int $page 当前查询分页
* @param int $page_size 分页大小
* @param array $params 查询参数
* @return array
*/
public function searchRecords(int $user_id, int $receive_id, int $source, int $page, int $page_size, array $params)
public function searchRecords(int $user_id, int $receiver_id, int $talk_type, int $page, int $page_size, array $params)
{
$fields = [
'chat_records.id',
'chat_records.source',
'chat_records.msg_type',
'chat_records.user_id',
'chat_records.receive_id',
'chat_records.content',
'chat_records.is_revoke',
'chat_records.created_at',
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.content',
'talk_records.is_revoke',
'talk_records.created_at',
'users.nickname',
'users.avatar as avatar',
];
$rowsSqlObj = ChatRecord::select($fields)->leftJoin('users', 'users.id', '=', 'chat_records.user_id');
if ($source == 1) {
$rowsSqlObj->where(function ($query) use ($user_id, $receive_id) {
$rowsSqlObj = TalkRecords::select($fields)->leftJoin('users', 'users.id', '=', 'talk_records.user_id');
if ($talk_type == 1) {
$rowsSqlObj->where(function ($query) use ($user_id, $receiver_id) {
$query->where([
['chat_records.user_id', '=', $user_id],
['chat_records.receive_id', '=', $receive_id]
['talk_records.user_id', '=', $user_id],
['talk_records.receiver_id', '=', $receiver_id]
])->orWhere([
['chat_records.user_id', '=', $receive_id],
['chat_records.receive_id', '=', $user_id]
['talk_records.user_id', '=', $receiver_id],
['talk_records.receiver_id', '=', $user_id]
]);
});
} else {
$rowsSqlObj->where('chat_records.receive_id', $receive_id);
$rowsSqlObj->where('chat_records.source', $source);
$rowsSqlObj->where('talk_records.receiver_id', $receiver_id);
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
}
if (isset($params['keywords'])) {
$rowsSqlObj->where('chat_records.content', 'like', "%{$params['keywords']}%");
$rowsSqlObj->where('talk_records.content', 'like', "%{$params['keywords']}%");
}
if (isset($params['date'])) {
$rowsSqlObj->whereDate('chat_records.created_at', $params['date']);
$rowsSqlObj->whereDate('talk_records.created_at', $params['date']);
}
$count = $rowsSqlObj->count();
@ -671,7 +684,7 @@ class TalkService extends BaseService
return $this->getPagingRows([], 0, $page, $page_size);
}
$rows = $rowsSqlObj->orderBy('chat_records.id', 'desc')->forPage($page, $page_size)->get()->toArray();
$rows = $rowsSqlObj->orderBy('talk_records.id', 'desc')->forPage($page, $page_size)->get()->toArray();
return $this->getPagingRows($this->handleChatRecords($rows), $count, $page, $page_size);
}
@ -687,7 +700,7 @@ class TalkService extends BaseService
Db::beginTransaction();
try {
$message['created_at'] = date('Y-m-d H:i:s');
$insert = ChatRecord::create($message);
$insert = TalkRecords::create($message);
if (!$insert) {
throw new Exception('插入聊天记录失败...');
@ -697,7 +710,7 @@ class TalkService extends BaseService
$fileInfo['file_type'] = FileMediaType::getMediaType($fileInfo['file_suffix']);
$fileInfo['created_at'] = date('Y-m-d H:i:s');
if (!ChatRecordsFile::create($fileInfo)) {
if (!TalkRecordsFile::create($fileInfo)) {
throw new Exception('插入聊天记录(文件消息)失败...');
}
@ -722,14 +735,14 @@ class TalkService extends BaseService
Db::beginTransaction();
try {
$message['created_at'] = date('Y-m-d H:i:s');
$insert = ChatRecord::create($message);
$insert = TalkRecords::create($message);
if (!$insert) {
throw new Exception('插入聊天记录失败...');
}
$codeBlock['record_id'] = $insert->id;
$codeBlock['created_at'] = date('Y-m-d H:i:s');
if (!ChatRecordsCode::create($codeBlock)) {
if (!TalkRecordsCode::create($codeBlock)) {
throw new Exception('插入聊天记录(代码消息)失败...');
}
@ -754,14 +767,14 @@ class TalkService extends BaseService
Db::beginTransaction();
try {
$message['created_at'] = date('Y-m-d H:i:s');
$insert = ChatRecord::create($message);
$insert = TalkRecords::create($message);
if (!$insert) {
throw new Exception('插入聊天记录失败...');
}
$emoticon['record_id'] = $insert->id;
$emoticon['created_at'] = date('Y-m-d H:i:s');
if (!ChatRecordsFile::create($emoticon)) {
if (!TalkRecordsFile::create($emoticon)) {
throw new Exception('插入聊天记录(代码消息)失败...');
}
@ -775,7 +788,7 @@ class TalkService extends BaseService
}
/**
* 创建代码块消息
* 创建文件消息
*
* @param array $message
* @param array $emoticon
@ -786,14 +799,15 @@ class TalkService extends BaseService
Db::beginTransaction();
try {
$message['created_at'] = date('Y-m-d H:i:s');
$insert = ChatRecord::create($message);
$insert = TalkRecords::create($message);
if (!$insert) {
throw new Exception('插入聊天记录失败...');
}
$emoticon['record_id'] = $insert->id;
$emoticon['file_type'] = FileMediaType::getMediaType($emoticon['file_suffix']);
$emoticon['created_at'] = date('Y-m-d H:i:s');
if (!ChatRecordsFile::create($emoticon)) {
if (!TalkRecordsFile::create($emoticon)) {
throw new Exception('插入聊天记录(代码消息)失败...');
}

View File

@ -55,6 +55,7 @@ class UserService extends BaseService
try {
$data['password'] = Hash::make($data['password']);
$data['created_at'] = date('Y-m-d H:i:s');
$data['updated_at'] = date('Y-m-d H:i:s');
$result = User::create($data);

80
message.php Normal file
View File

@ -0,0 +1,80 @@
<?php
// 对话的消息推送协议
$talk_message = [
'sender_id' => 0, //发送者ID
'receiver_id' => 0, //接收者ID
'talk_type' => 0, //对话类型[1:私聊;2:群聊;]
'data' => [
"id" => 0, // 消息记录ID
"talk_type" => 1, // 对话来源
"msg_type" => 1, // 消息类型
"user_id" => 0, // 发送者用户ID
"receiver_id" => 0, // 接收者ID
"nickname" => '',// 用户昵称
"avatar" => '',// 用户头像
"group_name" => '',// 群组名称
"group_avatar" => '',// 群组头像
"file" => [],
"code_block" => [],
"forward" => [],
"invite" => [],
"content" => '',// 文本消息
"created_at" => '',
"is_revoke" => 0, // 消息是否撤销
]
];
// 撤销聊天消息推送协议
$revoke_talk_message = [
'talk_type' => 0,//对话类型
'sender_id' => 0,//发送者ID
'receiver_id' => 0,//接收者ID
'record_id' => 0,//撤销的记录
];
// 好友在线状态通知消息推送协议
$online_status_message = [
'user_id' => 0,//用户ID
'status' => 0,//在线状态[0:离线;1:在线;]
];
// 键盘输入事件消息推送协议
$keyboard_message = [
'sender_id' => 0,
'receiver_id' => 0,
];
// 好友申请消息推送协议
$friend_apply_message = [
'sender_id' => 0, //发送者ID
'receiver_id' => 0, //接收者ID
'remark' => '',//申请备注
'friend' => [
'user_id' => 0,
'avatar' => '',
'nickname' => '',
'mobile' => '',
]
];
// 好友申请回调消息推送协议
$friend_apply_callback_message = [
'sender_id' => 0, //发送者ID
'receiver_id' => 0, //接收者ID
'status' => 0, //处理备注[0:未处理;1:已同意;2:已拒绝;]
'remark' => '',//处理备注
'friend' => [
'user_id' => 0,
'avatar' => '',
'nickname' => '',
'mobile' => '',
]
];
// ACK已读消息推送协议
$read_message = [
'sender_id' => 0, //发送者ID
'receiver_id' => 0, //接收者ID
'msg_id' => 0 //已读消息ID
];

View File

@ -17,11 +17,12 @@ class CreateUsersTable extends Migration
$table->string('mobile', 11)->default('')->unique()->comment('手机号');
$table->string('nickname', 20)->default('')->comment('用户昵称');
$table->string('avatar', 255)->default('')->comment('用户头像地址');
$table->unsignedTinyInteger('gender')->default(0)->unsigned()->comment('用户性别[0:未知;1:男;2:女]');
$table->unsignedTinyInteger('gender')->default(0)->comment('用户性别[0:未知;1:男;2:女]');
$table->string('password', 255)->default('')->comment('用户密码');
$table->string('motto', 100)->default('')->comment('用户座右铭');
$table->string('email', 30)->default('')->comment('用户邮箱');
$table->dateTime('created_at')->nullable()->comment('注册时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';

View File

@ -4,6 +4,7 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateEmoticonTable extends Migration
{
/**
@ -13,9 +14,11 @@ class CreateEmoticonTable extends Migration
{
Schema::create('emoticon', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('表情分组ID');
$table->string('name', 100)->default('')->comment('表情分组名称');
$table->string('url', 255)->default('')->comment('图片地址');
$table->unsignedInteger('created_at')->nullable(true)->default(0)->comment('创建时间');
$table->string('name', 50)->default('')->nullable(false)->comment('分组名称');
$table->string('icon', 255)->default('')->comment('分组图标');
$table->unsignedTinyInteger('status')->default(0)->comment('分组状态[-1:已删除;0:正常;1:已禁用;]');
$table->dateTime('created_at')->nullable()->comment('创建时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';

View File

@ -4,29 +4,31 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateEmoticonDetailsTable extends Migration
class CreateEmoticonItemTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('emoticon_details', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('表情包ID');
Schema::create('emoticon_item', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('表情包详情ID');
$table->unsignedInteger('emoticon_id')->default(0)->comment('表情分组ID');
$table->unsignedInteger('user_id')->default(0)->comment('用户ID0代码系统表情包');
$table->string('describe', 20)->default('')->comment('表情关键字描述');
$table->string('url', 255)->default('')->comment('表情链接');
$table->string('describe', 20)->default('')->comment('表情描述');
$table->string('url', 255)->default('')->comment('图片链接');
$table->string('file_suffix', 10)->default('')->comment('文件后缀名');
$table->unsignedBigInteger('file_size')->default(0)->comment('文件大小(单位字节)');
$table->unsignedInteger('created_at')->nullable(true)->default(0)->comment('添加时间');
$table->dateTime('created_at')->nullable()->comment('创建时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
});
$prefix = config('databases.default.prefix');
DB::statement("ALTER TABLE `{$prefix}emoticon_details` comment '聊天表情包'");
DB::statement("ALTER TABLE `{$prefix}emoticon_item` comment '表情包详情表'");
}
/**
@ -34,6 +36,6 @@ class CreateEmoticonDetailsTable extends Migration
*/
public function down(): void
{
Schema::dropIfExists('emoticon_details');
Schema::dropIfExists('emoticon_item');
}
}

View File

@ -0,0 +1,42 @@
<?php
use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
use Hyperf\DbConnection\Db;
class CreateRobotsTable extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('robots', function (Blueprint $table) {
$table->unsignedInteger('id', true)->comment('机器人ID');
$table->unsignedInteger('user_id')->comment('关联用户ID');
$table->string('robot_name', 30)->default('')->comment('机器人名称');
$table->string('describe', 255)->default('')->comment('描述信息');
$table->string('logo', 255)->default('')->comment('机器人logo');
$table->unsignedTinyInteger('is_talk')->default(0)->unsigned()->comment('可发送消息[0:否;1:是;]');
$table->unsignedTinyInteger('status')->default(0)->unsigned()->comment('状态[-1:已删除;0:正常;1:已禁用;]');
$table->dateTime('created_at')->nullable()->comment('注册时间');
$table->dateTime('updated_at')->nullable()->comment('更新时间');
$table->charset = 'utf8';
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
});
$prefix = config('databases.default.prefix');
Db::statement("ALTER TABLE `{$prefix}robots` comment '聊天机器人表'");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('robots');
}
}

9
更新计划.md Normal file
View File

@ -0,0 +1,9 @@
-- 更新计划 --
1. 修改 users 相关字段 ok
2. 添加 robts 数据表及迁移文件 ok
3. 修改表情相关数据表及相关接口 ok
4.