<?php

use think\Db;
use addons\fastim\library\Common;
use addons\fastim\library\CommonCode;
use addons\fastim\library\controller\Base;
use think\exception\PDOException;

/**
 * im会话、消息类
 */
class Message extends Base
{
    protected $noNeedLogin = [];

    /**
     * 输入状态传递
     */
    public function inputStatusNotice($data)
    {
        if (isset($data['session_id'])) {
            // 通知对方在输入
            $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);
            if ($sessionInfo) {
                $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                    'event' => 'input_status',
                    'data'  => [
                        'session_id' => $data['session_id'],
                        'status'     => 'start'
                    ]
                ]);
            }
        }

        if (isset($data['end_input_session_id'])) {
            // 通知一个会话输入结束
            $sessionInfo = Common::sessionInfo($data['end_input_session_id'], $this->userInfo['id']);
            if ($sessionInfo) {
                $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                    'event' => 'input_status',
                    'data'  => [
                        'session_id' => $data['end_input_session_id'],
                        'status'     => 'end'
                    ]
                ]);
            }
        }
    }


    /**
     * 删除群成员
     */
    public function delGroupMember($data)
    {
        $groupChatInfo = Common::getImGroupChat($data['id']);
        if ($groupChatInfo['leader'] == $this->userInfo['id']) {
            if (Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $data['member_id'])
                ->delete()) {

                // 删除对应用户的会话
                $imSession = Common::imSession('group', $data['member_id'], $data['id']);
                Db::name('fastim_session')->where('id', $imSession['id'])->delete();

                // 发送被踢通知给被删除用户
                $groupImSession = Common::imSession('service', $data['member_id'], 2);
                $messageData    = Common::insertMessage([
                    'type'         => 'group_notice',
                    'group_id'     => $data['id'],
                    'session_id'   => $groupImSession['id'],
                    'sender_id'    => 0,
                    'recipient_id' => $data['member_id'],
                    'message'      => [
                        'action' => 'propose'
                    ]
                ]);
                if ($messageData) {
                    $sessionInfo                  = Common::sessionInfo($groupImSession['id'], $data['member_id']);
                    $sessionInfo['userInfo']      = Common::getImUserInfo($data['member_id']);
                    $sessionInfo['groupChatInfo'] = Common::getImGroupChat($data['id']);
                    $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $data['member_id']);

                    $this->swooleCommon->pushMessageToUser($data['member_id'], [
                        'event' => 'reload_session_list'
                    ]);
                }

                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'del-group-member',
                    'data'  => [
                        'msg'       => '已删除群成员~',
                        'member_id' => $data['member_id']
                    ]
                ]));
            }
        } else {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '您没有权限操作~',
                    'type' => 'error'
                ]
            ]));
            return;
        }
    }

    public function loadNoticeInfo($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id'], $data)) {
            return;
        }

        $message = Db::name('fastim_message')->where('id', $data['id'])->find();
        if (!$message) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '消息找不到啦,请重试~',
                    'type' => 'error'
                ]
            ]));
            return;
        }

        $message['message'] = json_decode($message['message'], true);
        if ($message['type'] == 'group_invitation') {
            $message['message'] = array_merge($message['message'], Common::invitationMessageResult($message));
        }

        if ($message['group_id']) {
            $message['groupChatInfo'] = Common::getImGroupChat($message['group_id']);
        }

        if ($message['type'] == 'friend_apply') {
            if ($message['sender_id'] == $this->userInfo['id']) {
                $message['userInfo'] = Common::getImUserInfo($message['recipient_id']);
                $imSession           = Common::imSession('single', $this->userInfo['id'], $message['recipient_id']);
            } else {
                $message['userInfo'] = Common::getImUserInfo($message['sender_id']);
                $imSession           = Common::imSession('single', $this->userInfo['id'], $message['sender_id']);
            }
            $message['user_session_id'] = $imSession['id'];
            $message['shield']          = Db::name('fastim_user_shield')
                ->where('user_id', $this->userInfo['id'])
                ->where('shield_id', ($message['sender_id'] == $this->userInfo['id'] ? $message['recipient_id'] : $message['sender_id']))
                ->value('id');

            $message['friendship'] = Db::name('fastim_friendship')
                ->where('user_id', $this->userInfo['id'])
                ->where('friend_id', ($message['sender_id'] == $this->userInfo['id'] ? $message['recipient_id'] : $message['sender_id']))
                ->value('user_id');
        } elseif ($message['type'] == 'group_apply') {
            // 入群申请
            if ($message['sender_id'] != $this->userInfo['id']) {
                $message['userInfo'] = Common::getImUserInfo($message['sender_id']);
            }
        } elseif ($message['type'] == 'group_notice') {
            if ($message['message']['action'] == 'quit') {
                $message['userInfo'] = Common::getImUserInfo($message['message']['quit_user']);
            } elseif ($message['message']['action'] == 'refuse') {
                $message['userInfo'] = Common::getImUserInfo($message['message']['refuse_user']);
            }
        } elseif ($message['type'] == 'group_invitation') {
            $message['invitationUser'] = Common::getImUserInfo($message['message']['invitation_user']);
            if ($message['message']['identity'] == 'admin') {
                $message['invitedUser'] = Common::getImUserInfo($message['message']['invited_user']);
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'notice_info',
            'data'  => [
                'info' => $message
            ]
        ]));
    }

    /**
     * 转发消息
     */
    public function forward($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['message_ids', 'pickuser', 'type'], $data)) {
            return;
        }

        $pickuser = explode(',', trim($data['pickuser'], ','));
        if (!$pickuser) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '请选择转发好友~'
            ]));
            return;
        }

        $message_ids = explode(',', trim($data['message_ids'], ','));

        // 转发收藏
        if ($data['type'] == 'collection') {
            $message      = Db::name('fastim_user_collection')
                ->whereIn('id', $message_ids)
                ->where('user_id', $this->userInfo['id'])
                ->select();
            $messageField = 'value';
        } elseif ($data['type'] == 'message') {
            $message      = Db::name('fastim_message')->whereIn('id', $message_ids)->select();
            $messageField = 'message';
        }

        if (!$message) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '你要转发的消息找不到啦~'
            ]));
            return;
        }

        foreach ($message as $key => $value) {
            if (in_array($value['type'], CommonCode::$messageJsonTypes)) {
                $message[$key]['message'] = json_decode($value[$messageField], true);
            } else {
                $message[$key]['message'] = htmlspecialchars_decode($value[$messageField]);
            }
        }

        // 获取所有接受人的会话ID
        $sessionIds = [];
        foreach ($pickuser as $key => $value) {
            $imSession    = Common::imSession('single', $this->userInfo['id'], $value);
            $sessionIds[] = $imSession['id'];
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'forward_message',
            'data'  => [
                'data'        => $data,
                'message'     => $message,
                'session_ids' => $sessionIds
            ]
        ]));
    }

    /**
     * 消息右击
     */
    public function messageOperation($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data)) {
            return false;
        }

        $messageInfo = Db::name('fastim_message')->where('id', $data['id'])->find();
        if (!$messageInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '消息找不到啦~'
            ]));
            return false;
        }

        // 复制和引用
        if ($data['action'] == 'message-copy' || $data['action'] == 'message-quote' || $data['action'] == 'message-to-do') {
            if ($messageInfo['type'] == 'link' || $messageInfo['type'] == 'file') {
                $messageInfo['message']     = json_decode($messageInfo['message'], true);
                $messageInfo['messageText'] = ($messageInfo['type'] == 'link') ? $messageInfo['message']['link_url'] : $messageInfo['message']['url'];
            } else {
                $messageInfo['messageText'] = Common::formatLastMessage($messageInfo, $this->userInfo['id']);
            }

            // 引用
            if ($data['action'] == 'message-quote') {
                $userInfo                   = Common::getImUserInfo($messageInfo['sender_id']);
                $messageInfo['messageText'] = '「' . $userInfo['nickname'] . ': ' . $messageInfo['messageText'] . '」';
            }

            // 待办
            if ($data['action'] == 'message-to-do') {
                Db::name('fastim_todo')->insert([
                    'user_id'    => $this->userInfo['id'],
                    'title'      => $messageInfo['messageText'],
                    'status'     => '0',
                    'createtime' => time()
                ]);
                $resMessage = [
                    'type' => 'success',
                    'msg'  => '已添加至待办~'
                ];
            }
        } elseif ($data['action'] == 'message-collection') {
            // 收藏
            if ($messageInfo['type'] == 'kbs_list') {
                $userInfo = Db::name('fastim_service')->where('id', 3)->find();
            } else {
                $userInfo = Common::getImUserInfo($messageInfo['sender_id']);
            }

            if (in_array($messageInfo['type'], CommonCode::$messageJsonTypes)) {
                $messageInfo['message'] = json_decode($messageInfo['message'], true);
                $messageInfo['message'] = json_encode($messageInfo['message'], JSON_UNESCAPED_UNICODE);
            }

            Db::name('fastim_user_collection')->insert([
                'user_id'    => $this->userInfo['id'],
                'group_id'   => 0,
                'type'       => $messageInfo['type'],
                'value'      => $messageInfo['message'],
                'from'       => $userInfo['nickname'] ?? '',
                'createtime' => time()
            ]);
            $resMessage = [
                'type' => 'success',
                'msg'  => '已添加至收藏~'
            ];
        } elseif ($data['action'] == 'message-delete') {
            // 删除消息

            $sessionInfo = Common::sessionInfo($messageInfo['session_id'], $this->userInfo['id']);
            if ($sessionInfo['type'] != 'single') {
                return;
            }

            Db::name('fastim_message')->where('id', $data['id'])->update([
                'deleteuser' => $this->userInfo['id']
            ]);
            $messageInfo = array_merge($messageInfo, Common::getLastMessage($this->userInfo['id'], $sessionInfo));
        } elseif ($data['action'] == 'message-new-window') {
            // 新窗口打开
            if ($messageInfo['type'] == 'link') {
                $messageInfo['message']    = json_decode($messageInfo['message'], true);
                $messageInfo['messageUrl'] = $messageInfo['message']['link_url'];
            } else {
                $messageInfo['messageUrl'] = $messageInfo['message'];
            }
        }

        if (isset($resMessage)) {
            $resMessage['method'] = 'show_msg';// 为uni端标记是showMsg
            $this->server->push($this->frame->fd, json_encode([
                'event' => (isset($data['source']) && $data['source'] == 'uni-app') ? 'message_operation' : 'show_msg',
                'data'  => $resMessage
            ]));
            return false;
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'message_operation',
            'data'  => [
                'method'      => 'operation',
                'data'        => $data,
                'messageInfo' => $messageInfo
            ]
        ]));
    }

    /**
     * 获取群聊的屏蔽状态
     */
    public function getGroupChatShield($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['session_id'], $data)) {
            return;
        }
        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);
        $shield      = Common::getGroupChatShield($sessionInfo['sessionUser']['id'], $this->userInfo['id']);
        $this->server->push($this->frame->fd, json_encode([
            'event' => 'group_chat_shield',
            'data'  => [
                'shield'     => $shield ? 'shield' : 'unshielded',
                'session_id' => $data['session_id']
            ]
        ]));
    }

    /**
     * 邀请加入群聊
     */
    public function invitationjoinGroupOption($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data, false, ['id' => '申请消息找不到啦~'])) {
            return;
        }

        $message = Db::name('fastim_message')->where('id', $data['id'])->where('type', 'group_invitation')->find();
        if (!$message) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '申请消息找不到啦~'
            ]));
            return;
        }

        $imGroupChatInfo    = Common::getImGroupChat($message['group_id']);
        $message['message'] = json_decode($message['message'], true);

        // 修改消息状态
        if ($message['message']['identity'] == 'admin') {
            if (($message['recipient_id'] != $imGroupChatInfo['leader']) || ($message['recipient_id'] != $this->userInfo['id'])) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '你没有权限操作~'
                ]));
                return;
            }
        } else {
            if ($message['recipient_id'] != $this->userInfo['id']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '你没有权限操作~'
                ]));
                return;
            }
        }

        $message['message']['result'] = ($data['action'] == 'agree') ? 1 : 2;
        $newMessage                   = json_encode($message['message']);
        Db::name('fastim_message')->where('id', $data['id'])->update(['message' => $newMessage]);

        $messageResultAll = Common::invitationMessageResult($message);
        if ($data['action'] == 'agree') {
            // 如果都同意了,用户入群
            if ($messageResultAll['user_result'] == 1 && $messageResultAll['leader_result'] == 1) {
                $imSession = Common::imSession('group', $message['message']['invited_user'], $message['group_id']);
                $groupUser = [
                    'group_id'      => $message['group_id'],
                    'user_id'       => $message['message']['invited_user'],
                    'session_id'    => $imSession['id'],
                    'user_group_id' => 0,// 邀请入群需双方同意，不要求用户选择分组
                    'jointime'      => time()
                ];
                Db::name('fastim_group_user')->insert($groupUser);

                $this->swooleCommon->pushMessageToGroup('system', [
                    'group_id'     => $message['group_id'],
                    'session_id'   => $imSession['id'],
                    'sender_id'    => $this->userInfo['id'],
                    'recipient_id' => $message['message']['invited_user'],
                    'message'      => [
                        'message'      => '你已经是群成员了，和大家打个招呼吧~',
                        'display_user' => $message['message']['invited_user']
                    ]
                ]);
            }

            $res = [
                'msg'  => '已同意加群申请~',
                'type' => 'success'
            ];
        } elseif ($data['action'] == 'refuse') {
            $res = [
                'msg'  => '已拒绝入群申请~',
                'type' => 'tips'
            ];

            // 如果被邀请人已经处理过邀请，给被邀请人发送拒绝消息
            $pushRefuseMessage = [];
            if ($messageResultAll['user_result'] == 1) {
                $pushRefuseMessage[] = $message['message']['invited_user'];
            }
            // 给邀请人推送拒绝消息
            if ($message['message']['invitation_user']) {
                $pushRefuseMessage[] = $message['message']['invitation_user'];
            }

            foreach ($pushRefuseMessage as $key => $recipientUserId) {
                $imSession                    = Common::imSession('service', $recipientUserId, 2);
                $sessionInfo                  = Common::sessionInfo($imSession['id'], $recipientUserId);
                $messageData                  = Common::insertMessage([
                    'type'         => 'group_notice',
                    'group_id'     => $message['group_id'],
                    'session_id'   => $sessionInfo['id'],
                    'sender_id'    => $this->userInfo['id'],
                    'recipient_id' => $recipientUserId,
                    'message'      => [
                        'action'      => 'refuse',
                        'refuse_user' => $message['message']['invited_user']
                    ]
                ]);
                $sessionInfo['userInfo']      = Common::getImUserInfo($message['message']['invited_user'], false, $message['message']['invited_user']);
                $sessionInfo['groupChatInfo'] = Common::getImGroupChat($message['group_id']);
                $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $recipientUserId);
            }
        }

        $imSession         = Common::imSession('service', $this->userInfo['id'], 2);
        $res['session_id'] = $imSession['id'];

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'new_friends_option',
            'data'  => $res
        ]));

        if ($this->userInfo['id'] == $imGroupChatInfo['leader']) {
            $this->swooleCommon->pushMessageToUser($message['message']['invited_user'], [
                'event' => 'reload_session_list'
            ]);
        } else {
            $this->swooleCommon->pushMessageToUser($imGroupChatInfo['leader'], [
                'event' => 'reload_session_list'
            ]);
        }
    }

    /**
     * 邀请好友加入群聊
     */
    public function invitationGroupmember($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'pickuser'], $data, false, ['pickuser' => '请选择需要邀请的好友~'])) {
            return;
        }

        $pickuser = explode(',', trim($data['pickuser'], ','));
        if (!$pickuser) {
            $msg = '请选择需要邀请的好友~';
        }

        $info = Common::getImGroupChat($data['id']);
        if (!$info) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '群聊找不到啦~'
            ]));
            return;
        }

        /**
         * 以下三个判断分别是
         * 群主本人邀请
         * 群聊设置了入群免验证
         * 群聊设置了成员邀请免验证
         * leaderResult:0=待管理员审核,1=管理员已同意,2=管理员已拒绝
         */
        $leaderResult = 0;
        if (($this->userInfo['id'] == $info['leader']) || ($info['add_mode'] == 1) || ($info['invite_join_group'] == 1)) {
            $leaderResult = 1;
        }
        $adminMessage = [
            'invitation_user' => $this->userInfo['id'],
            'result'          => $leaderResult,// 群主意见
            'identity'        => 'admin'
        ];
        $userMessage  = [
            'invitation_user' => $this->userInfo['id'],
            'result'          => 0,// 用户意见
            'identity'        => 'user'
        ];

        $adminImSession   = Common::imSession('service', $info['leader'], 2);
        $adminSessionInfo = Common::sessionInfo($adminImSession['id'], $this->userInfo['id']);
        $invitationUser   = Common::getImUserInfo($this->userInfo['id']); // 邀请人

        $sendInvitationNumber = 0;
        foreach ($pickuser as $key => $value) {
            // 检查是否已经是群成员
            if (Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $value)
                ->value('user_id')) {
                continue;
            }

            // 将以前给此用户和管理员发送过的邀请消息设置为失效
            $historyMessage    = Db::name('fastim_message')
                ->where('group_id', $data['id'])
                ->where('type', 'group_invitation')
                ->where('recipient_id=:invited_user OR recipient_id=:group_chat_leader')
                ->bind([
                    'invited_user'      => $value,
                    'group_chat_leader' => $info['leader']
                ])
                ->select();
            $reloadSessionList = false;// 若有消息失效,直接更新会话列表
            foreach ($historyMessage as $hkey => $hvalue) {
                $hvalue['message'] = json_decode($hvalue['message'], true);
                if ($hvalue['message']['invited_user'] == $value && $hvalue['message']['result'] == 0) {
                    $hvalue['message']['result'] = 3; // 失效
                    $hvalue['message']           = json_encode($hvalue['message']);
                    Db::name('fastim_message')->where('id', $hvalue['id'])->update(['message' => $hvalue['message']]);
                    $reloadSessionList = true;
                }
            }

            $invitedUser                 = Common::getImUserInfo($value); // 被邀请人
            $userMessage['invited_user'] = $adminMessage['invited_user'] = $value;

            // 管理员消息
            $adminMessageData = Common::insertMessage([
                'type'         => 'group_invitation',
                'group_id'     => $data['id'],
                'session_id'   => $adminSessionInfo['id'],
                'sender_id'    => 0,
                'recipient_id' => $info['leader'],
                'message'      => $adminMessage
            ]);
            if ($adminMessageData) {
                $adminMessageData['invitedUser']              = $invitedUser;
                $adminMessageData['invitationUser']           = $invitationUser;
                $adminMessageData['message']['user_result']   = 0;
                $adminMessageData['message']['leader_result'] = $leaderResult;
                $adminSessionInfo['groupChatInfo']            = $info;
                $adminSessionInfo['reloadSessionList']        = $reloadSessionList;
                $this->swooleCommon->newMessagePush($adminMessageData, $adminSessionInfo, $info['leader']);
            }

            // 被邀请人消息
            $userMessage['admin_message_id'] = $adminMessageData['id'];
            $invitationUserSession           = Common::imSession('service', $value, 2);
            $invitationUserSessionInfo       = Common::sessionInfo($invitationUserSession['id'], $this->userInfo['id']);
            $invitationUserMessageData       = Common::insertMessage([
                'type'         => 'group_invitation',
                'group_id'     => $data['id'],
                'session_id'   => $invitationUserSessionInfo['id'],
                'sender_id'    => 0,
                'recipient_id' => $value,
                'message'      => $userMessage
            ]);
            if ($invitationUserMessageData) {
                $invitationUserMessageData['invitedUser']              = $invitedUser;
                $invitationUserMessageData['invitationUser']           = $invitationUser;
                $invitationUserMessageData['message']['user_result']   = 0;
                $invitationUserMessageData['message']['leader_result'] = $leaderResult;
                $invitationUserSessionInfo['groupChatInfo']            = $info;
                $invitationUserSessionInfo['reloadSessionList']        = $reloadSessionList;
                $this->swooleCommon->newMessagePush($invitationUserMessageData, $invitationUserSessionInfo, $value);
            }

            $sendInvitationNumber++;
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'show_msg',
            'data'  => [
                'type' => $sendInvitationNumber > 0 ? 'success' : 'tips',
                'msg'  => $sendInvitationNumber > 0 ? '邀请已发送~' : '邀请发送失败或你邀请的好友已经是群成员了~'
            ]
        ]));
    }

    public function groupChatNoticeOpt($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'type'], $data)) {
            return false;
        }

        $info = Db::name('fastim_group_chat_notice')
            ->where('id', $data['id'])
            ->where('deletetime', null)
            ->find();
        if (!$info) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '公告找不到啦~'
            ]));
            return false;
        }
        $info = Common::formatGroupChatNotice($info, $this->userInfo['id'], false);

        if ($data['type'] == 'del') {
            Db::name('fastim_group_chat_notice')
                ->where('id', $info['id'])
                ->update([
                    'deletetime' => time()
                ]);
            // 更新公告列表
            $this->groupChatNotice([
                'group_id' => $info['group_id'],
                'method'   => 'list',
                'page'     => 1
            ]);
            return false;
        } elseif ($data['type'] == 'post-edit') {
            $info = Common::getImGroupChat($data['group_id']);
            if ($info && $info['leader'] == $this->userInfo['id']) {
                $uni = (isset($data['source']) && $data['source'] == 'uni-app') ? true : false;
                unset($data['type'], $data['method'], $data['source']);
                Db::name('fastim_group_chat_notice')
                    ->where('id', $data['id'])
                    ->update($data);

                if ($uni) {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => '更新公告成功~'
                    ]));
                } else {
                    // 更新公告列表
                    $this->groupChatNotice([
                        'group_id' => $data['group_id'],
                        'method'   => 'list',
                        'page'     => 1
                    ]);
                }
                return true;
            } else {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }
        } elseif ($data['type'] == 'get-users') {
            $where['l.type'] = 0;
            $orderStr        = 'l.createtime desc';
            if ($data['method'] == 'receipted-number') {
                $where['l.receipt'] = 1;
                $orderStr           = 'l.confirmtime desc';
            }

            if (!isset($data['page']) || $data['page'] == 1) {
                $min = 0;
            } else {
                $min = ($data['page'] - 1) * $this->pageCount;
            }

            $users = Db::name('fastim_reading_log')
                ->alias('l')
                ->field('l.user_id,l.receipt,l.createtime,l.confirmtime,gu.nickname,u.id,u.avatar,u.nickname as u_nickname,fu.avatar as fu_avatar,fu.nickname as fu_nickname,a.avatar as a_avatar,a.nickname as a_nickname,f.remark')
                ->join('fastim_group_user gu', 'gu.group_id=l.group_id AND gu.user_id=l.user_id')
                ->join('fastim_user u', 'u.id=l.user_id')
                ->join('user fu', 'fu.id=l.user_id', 'LEFT')
                ->join('admin a', 'a.id=u.admin_id', 'LEFT')
                ->join('fastim_friendship f', 'f.friend_id=u.id AND f.user_id=:user_id', 'LEFT')
                ->where($where)
                ->where('l.data_id', $data['id'])
                ->bind([
                    'user_id' => $this->userInfo['id']
                ])
                ->order($orderStr)
                ->limit($min, $this->pageCount)
                ->select();
            foreach ($users as $key => $value) {
                $users[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $value['remark'],
                    $value['u_nickname'],
                    $value['fu_nickname'],
                    $value['a_nickname']
                ], $value['id']));

                $users[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar'],
                    $value['fu_avatar'],
                    $value['a_avatar']
                ], $users[$key]['nickname']);

                if ($data['method'] == 'receipted-number') {
                    $users[$key]['createtime'] = Common::formatTimeAlong($value['confirmtime']);
                } else {
                    $users[$key]['createtime'] = Common::formatTimeAlong($value['createtime']);
                }

                unset($users[$key]['remark'], $users[$key]['u_nickname'], $users[$key]['fu_nickname'], $users[$key]['a_nickname'], $users[$key]['fu_avatar'], $users[$key]['a_avatar']);
            }

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'group-notice-users',
                'data'  => [
                    'users'    => $users,
                    'data'     => $data,
                    'nextpage' => (count($users) < $this->pageCount) ? false : true,
                ]
            ]));
            return false;
        } elseif ($data['type'] == 'get') {
            $info['popup'] = 1;
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'group_chat_notice_info',
            'data'  => [
                'info' => $info,
                'data' => $data
            ]
        ]));
    }

    public function groupChatNotice($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['group_id', 'method'], $data)) {
            return false;
        }

        $info = Common::getImGroupChat($data['group_id']);
        if (!$info) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '群聊找不到啦~'
            ]));
            return false;
        }

        if ($data['method'] == 'post') {

            if (!$this->swooleCommon->requiredParamCheck(['content'], $data)) {
                return false;
            }

            if ($info['leader'] != $this->userInfo['id']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }

            unset($data['method']);
            $data['publisher']  = $this->userInfo['id'];
            $data['createtime'] = time();

            // 公告入库
            Db::startTrans();
            try {
                Db::name('fastim_group_chat_notice')->insert($data);
                $data['id'] = Db::name('fastim_group_chat_notice')->getLastInsID();
                Db::commit();
            } catch (PDOException $e) {
                Db::rollback();
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => $e->getMessage()
                ]));
                return false;
            }

            // 推送群消息
            $this->swooleCommon->pushMessageToGroup('group_chat_notice', [
                'group_id'     => $data['group_id'],
                'session_id'   => 0,
                'sender_id'    => $this->userInfo['id'],
                'recipient_id' => 0,
                'message'      => $data
            ], $this->userInfo['id']);

            // 插入一条当前用户的群通知阅读记录
            Common::readGroupChatNotice($data['group_id'], $this->userInfo['id'], $data['id'], '', true);

            // 更新公告列表
            $this->groupChatNotice([
                'group_id' => $data['group_id'],
                'method'   => 'list',
                'page'     => 1
            ]);

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '公告发布成功~',
                    'type' => 'success'
                ]
            ]));
        } elseif ($data['method'] == 'list') {
            if (!isset($data['page']) || $data['page'] == 1) {
                $min = 0;
            } else {
                $min = ($data['page'] - 1) * $this->pageCount;
            }

            Common::readGroupChatNotice($data['group_id'], $this->userInfo['id'], 0, 'all');

            $list = Db::name('fastim_group_chat_notice')
                ->where('group_id', $data['group_id'])
                ->where('deletetime', null)
                ->order('top desc,createtime desc')
                ->limit($min, $this->pageCount)
                ->select();
            foreach ($list as $key => $value) {
                $list[$key] = Common::formatGroupChatNotice($value, $this->userInfo['id'], false);
            }
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'group_chat_notice',
                'data'  => [
                    'data'     => $data,
                    'list'     => $list,
                    'isLeader' => $info['leader'] == $this->userInfo['id'] ? true : false,
                    'nextpage' => (count($list) < $this->pageCount) ? false : true,
                ]
            ]));
        }
    }

    /**
     * at群成员
     */
    public function groupChatAt($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['session_id', 'method'], $data)) {
            return;
        }

        $sessionInfo = Common::sessionInfo($data['session_id']);
        if (!$sessionInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '会话找不到啦~'
            ]));
            return;
        }

        if ($data['method'] == 'get-all') {
            $info = Common::getImGroupChat($sessionInfo['chat_id']);
            if (!$info) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '群聊找不到啦~'
                ]));
                return;
            }

            $groupMember = Db::name('fastim_group_user')
                ->alias('gu')
                ->field('gu.nickname,gu.speaktime,gu.jointime,u.id,u.avatar,u.nickname as u_nickname,u.status,fu.avatar as fu_avatar,fu.nickname as fu_nickname,a.avatar as a_avatar,a.nickname as a_nickname,f.remark')
                ->join('fastim_user u', 'u.id=gu.user_id')
                ->join('user fu', 'fu.id=u.user_id', 'LEFT')
                ->join('admin a', 'a.id=u.admin_id', 'LEFT')
                ->join('fastim_friendship f', 'f.friend_id=u.id AND f.user_id=:user_id', 'LEFT')
                ->bind([
                    'user_id' => $this->userInfo['id']
                ]);

            if (isset($data['keywords']) && $data['keywords']) {
                $groupMember = $groupMember->where('gu.group_id', $info['id'])
                    ->where("gu.nickname LIKE :keywords OR u.nickname LIKE :keywords OR fu.nickname LIKE :keywords OR a.nickname LIKE :keywords OR remark LIKE :keywords")
                    ->bind([
                        'keywords' => '%' . $data['keywords'] . '%'
                    ])
                    ->order('gu.speaktime desc,gu.jointime desc')
                    ->select(false);
                $groupMember = Db::query($groupMember);
            } else {
                $groupMember = $groupMember->where('gu.group_id', $info['id'])->order('gu.speaktime desc,gu.jointime desc');
                $groupMember = $groupMember->select();
            }

            foreach ($groupMember as $key => $value) {
                // 去除当前用户(不在查询中使用!=)
                if ($value['id'] == $this->userInfo['id']) {
                    unset($groupMember[$key]);
                    continue;
                }
                // 原始昵称
                $groupMember[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $value['nickname'],
                    $value['u_nickname'],
                    $value['fu_nickname'],
                    $value['a_nickname']
                ], $value['id']));

                $groupMember[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar'],
                    $value['fu_avatar'],
                    $value['a_avatar']
                ], $groupMember[$key]['nickname']);

                unset($groupMember[$key]['u_nickname'], $groupMember[$key]['fu_nickname'], $groupMember[$key]['a_nickname'], $groupMember[$key]['fu_avatar'], $groupMember[$key]['a_avatar']);
            }

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'group_chat_at',
                'data'  => [
                    'data'         => $data,
                    'group_member' => array_values($groupMember)
                ]
            ]));
        }
    }

    /**
     * 群成员列表
     */
    public function groupChatMember($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'method'], $data)) {
            return;
        }

        $info = Common::getImGroupChat($data['id']);
        if (!$info) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '群聊找不到啦~'
            ]));
            return;
        }

        // 保存群聊昵称
        if ($data['method'] == 'save-groupmember-nickname') {
            if (!$this->swooleCommon->requiredParamCheck(['new_nickname'], $data, false, ['new_nickname' => '请输入正确的昵称~'])) {
                return;
            }
            Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->update([
                    'nickname' => $data['new_nickname']
                ]);
        }

        $groupMember = Db::name('fastim_group_user')
            ->alias('gu')
            ->field('gu.nickname,gu.speaktime,gu.jointime,u.id,u.avatar,u.nickname as u_nickname,u.status,fu.avatar as fu_avatar,fu.nickname as fu_nickname,a.avatar as a_avatar,a.nickname as a_nickname,f.remark,f.user_id as is_friend')
            ->join('fastim_user u', 'u.id=gu.user_id')
            ->join('user fu', 'fu.id=u.user_id', 'LEFT')
            ->join('admin a', 'a.id=u.admin_id', 'LEFT')
            ->join('fastim_friendship f', 'f.friend_id=u.id AND f.user_id=:user_id', 'LEFT')
            ->bind([
                'user_id' => $this->userInfo['id']
            ]);

        if (isset($data['keywords']) && $data['keywords']) {
            $groupMember = $groupMember->where('gu.group_id', $data['id'])
                ->where("gu.nickname LIKE :keywords OR u.nickname LIKE :keywords OR fu.nickname LIKE :keywords OR a.nickname LIKE :keywords OR remark LIKE :keywords")
                ->bind([
                    'keywords' => '%' . $data['keywords'] . '%'
                ])
                ->select(false);
            $groupMember = Db::query($groupMember);
        } else {
            $groupMember = $groupMember->where('gu.group_id', $data['id'])->order('gu.jointime desc');
            if (isset($data['limit'])) {
                $groupMember->limit($data['limit']);
            }
            $groupMember = $groupMember->select();
        }

        foreach ($groupMember as $key => $value) {
            // 原始昵称
            $groupMember[$key]['nickname_origin'] = Common::trueAttr(Common::nicknameSort([
                $value['remark'],
                $value['u_nickname'],
                $value['fu_nickname'],
                $value['a_nickname']
            ], $value['id']));

            $groupMember[$key]['avatar'] = Common::avatarSrc([
                $value['avatar'],
                $value['fu_avatar'],
                $value['a_avatar']
            ], $groupMember[$key]['nickname_origin']);

            if ($value['id'] == $this->userInfo['id']) {
                $groupMember[$key]['is_friend'] = true;
            }

            $groupMember[$key]['speaktime'] = Common::formatTime($value['speaktime'] ? $value['speaktime'] : $value['jointime']);
            unset($groupMember[$key]['remark'], $groupMember[$key]['u_nickname'], $groupMember[$key]['fu_nickname'], $groupMember[$key]['a_nickname'], $groupMember[$key]['fu_avatar'], $groupMember[$key]['a_avatar']);
        }

        if (isset($data['lettersort']) && (!isset($data['keywords']) || !$data['keywords'])) {
            // 按字母排序

            // 剔除群主
            $leader = [];
            foreach ($groupMember as $key => $value) {
                if ($value['id'] == $info['leader']) {
                    $leader = $value;
                    unset($groupMember[$key]);
                    break;
                }
            }
            $groupMember           = Common::initialPinyinArrSort($groupMember, 'nickname_origin');
            $groupMember['leader'] = $leader;
        } elseif (!isset($data['keywords']) || !$data['keywords']) {
            // 当前用户排第一，群主排第二
            // 直接返回
            foreach ($groupMember as $key => $value) {
                if ($value['id'] == $this->userInfo['id'] && $key > 0) {
                    $tempUser          = $groupMember[0];
                    $groupMember[0]    = $groupMember[$key];
                    $groupMember[$key] = $tempUser;
                }

                if (($value['id'] == $info['leader'] && $value['id'] != $this->userInfo['id']) && $key != 1) {
                    $tempUser          = $groupMember[1];
                    $groupMember[1]    = $groupMember[$key];
                    $groupMember[$key] = $tempUser;
                }
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'group_chat_member',
            'data'  => [
                'data'         => $data,
                'group_member' => $groupMember,
                'info'         => $info
            ]
        ]));
    }

    /**
     * 标记一个会话的消息已读
     */
    public function readMessage($data)
    {
        if (!isset($data['session_id']) || !$data['session_id']) {
            return;
        }

        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);

        if ($sessionInfo['type'] == 'single') {
            Db::name('fastim_message')
                ->where('session_id', $data['session_id'])
                ->where('recipient_id', $this->userInfo['id'])
                ->where('status', 0)
                ->update(['status' => 1]);

            // 推送已读消息给发送人
            $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                'event' => 'read_message',
                'data'  => [
                    'sessionType' => 'single',
                    'session_id'  => $data['session_id']
                ]
            ]);
        } elseif (isset($data['type']) && $data['type'] == 'group_chat_notice') {
            Common::readGroupChatNotice($sessionInfo['chat_id'], $this->userInfo['id'], $data['id'], $data['action']);
        } elseif ($sessionInfo['type'] == 'group') {
            // 群聊消息阅读
            $this->swooleCommon->readGroupMessage($sessionInfo);
        } elseif ($sessionInfo['type'] == 'service') {
            // 服务号消息阅读
            Common::readServiceMessage($sessionInfo['chat_id'], $this->userInfo['id'], $sessionInfo['id']);
        }

    }

    public function receiptGroupChatNotice($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'session_id'], $data)) {
            return false;
        }

        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);

        $log = Db::name('fastim_reading_log')
            ->where('type', 0)
            ->where('group_id', $sessionInfo['chat_id'])
            ->where('user_id', $this->userInfo['id'])
            ->where('data_id', $data['id'])
            ->find();
        if ($log) {
            Db::name('fastim_reading_log')
                ->where('id', $log['id'])
                ->update([
                    'receipt'     => 1,
                    'confirmtime' => time()
                ]);

            $receiptedCount = Db::name('fastim_reading_log')
                ->where('type', 0)
                ->where('group_id', $sessionInfo['chat_id'])
                ->where('data_id', $data['id'])
                ->where('receipt', 1)
                ->count();

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'receipt_group_chat_notice',
                'data'  => [
                    'msg'            => '确认成功~',
                    'receiptedCount' => $receiptedCount,
                    'data'           => $data
                ]
            ]));
        }
    }

    /**
     * 创建或打开与指定用户的会话窗口
     */
    public function openSession($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'type'], $data, false, [
            'id'   => '用户找不到啦~',
            'type' => '会话创建失败，请重试~'
        ])) {
            return;
        }

        if ($data['type'] == 'user') {
            // 是否是好友或对方是否允许临时会话
            $friendship  = Db::name('fastim_friendship')
                ->where('user_id', $data['id'])
                ->where('friend_id', $this->userInfo['id'])
                ->find();
            $tempSession = Common::imUserConfig($data['id'], 'temp_session');

            if (!$friendship && !$tempSession) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => [
                        'msg'  => '对方拒绝会话，请添加对方为好友再试~',
                        'type' => 'error'
                    ]
                ]));
                return;
            }

            $imSession = Common::imSession('single', $this->userInfo['id'], $data['id']);
        } elseif ($data['type'] == 'group') {
            $groupMember = Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->value('group_id');
            if (!$groupMember) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => [
                        'msg'  => '请先加入群聊再发送消息~',
                        'type' => 'error'
                    ]
                ]));
                return;
            }
            $imSession = Common::imSession('group', $this->userInfo['id'], $data['id']);
        } elseif ($data['type'] == 'service') {
            $imSession = Common::imSession('service', $this->userInfo['id'], $data['id']);
        }

        if (!$imSession) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '会话创建失败,请重试~',
                    'type' => 'error'
                ]
            ]));
            return;
        }

        $sessionInfo = Common::sessionInfo($imSession['id'], $this->userInfo['id']);
        if (!$sessionInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '会话创建失败,请重试~',
                    'type' => 'error'
                ]
            ]));
            return;
        }

        // 客服代表的欢迎消息发送
        if ($data['type'] == 'user' && $sessionInfo['sessionUser']['type'] == 'csr' && isset($imSession['create']) && $imSession['create']) {
            $welcomeNewNserMsg = $sessionInfo['sessionUser']['welcome_msg'] ? $sessionInfo['sessionUser']['welcome_msg'] : Db::name('fastim_config')
                ->where('name', 'welcome_new_user_msg')
                ->value('value');

            // 消息入库
            $messageData = Common::insertMessage([
                'type'         => 'default',
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => $sessionInfo['sessionUser']['id'],
                'recipient_id' => $this->userInfo['id'],
                'message'      => $welcomeNewNserMsg
            ]);
        }

        // 兼容前台imSession
        $sessionInfo['pushUser'] = $sessionInfo['sessionUser'];
        unset($sessionInfo['sessionUser']);

        // 置顶状态
        $sessionInfo['top'] = Db::name('fastim_session_top')
            ->where('user_id', $this->userInfo['id'])
            ->where('session_id', $imSession['id'])
            ->value('top');

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'open_session',
            'data'  => [
                'sessionInfo'          => $sessionInfo,
                'lastMessage'          => Common::getLastMessage($this->userInfo['id'], $sessionInfo),
                'unreadMessagesNumber' => 0,
                'shield'               => ($sessionInfo['type'] == 'group') ? Common::getGroupChatShield($sessionInfo['pushUser']['id'], $this->userInfo['id']) : false
            ]
        ]));
    }

    /**
     * 创建群聊
     */
    public function createGroup($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['data', 'pickuser'], $data, false, [
            'data'     => '资料错误,请重试~',
            'pickuser' => '请选择群成员!'
        ])) {
            return;
        }

        if (!$this->swooleCommon->requiredParamCheck(['nickname'], $data['data'], false, ['nickname' => '请输入正确的群名称!'])) {
            return;
        }

        $pickuser = explode(',', trim($data['pickuser'], ','));
        if (!$pickuser) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '请选择群成员!'
            ]));
            return;
        }

        $pickuser[] = $this->userInfo['id'];
        $pickuser   = array_unique($pickuser);

        unset($data['data']['id']);
        unset($data['data']['method']);
        $data['data']['max_user_count'] = (isset($data['data']['max_user_count']) && $data['data']['max_user_count']) ? $data['data']['max_user_count'] : CommonCode::$groupMaxUser;
        $data['data']['leader']         = $this->userInfo['id'];
        $data['data']['createtime']     = time();

        // 群聊数据入库
        Db::startTrans();
        try {
            Db::name('fastim_group_chat')->insert($data['data']);
            $groupId = Db::name('fastim_group_chat')->getLastInsID();
            // 群成员入库
            foreach ($pickuser as $key => $value) {
                $imSession   = Common::imSession('group', $value, $groupId);
                $groupUser[] = [
                    'group_id'   => $groupId,
                    'user_id'    => $value,
                    'session_id' => $imSession['id'],
                    'jointime'   => time()
                ];
            }
            Db::name('fastim_group_user')->insertAll($groupUser);

            // 推送群消息
            $this->swooleCommon->pushMessageToGroup('system', [
                'group_id'     => $groupId,
                'session_id'   => 0,
                'sender_id'    => $this->userInfo['id'],
                'recipient_id' => 0,
                'message'      => [
                    'message'      => '你已经是群成员了，和大家打个招呼吧~',
                    'display_user' => 'all'
                ]
            ]);

            Db::commit();
        } catch (PDOException $e) {
            Db::rollback();
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => $e->getMessage()
            ]));
            return;
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'create_group',
            'data'  => $groupId
        ]));
    }

    public function loadKbs($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id'], $data)) {
            return;
        }
        $kbs = Common::getKbs('', $data['id']);
        if (!$kbs) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '知识点找不到啦,请重试~',
                    'type' => 'error'
                ]
            ]));
            return;
        }

        // 消息入库
        $imSession   = Common::imSession('service', $this->userInfo['id'], 3);
        $messageData = Common::insertMessage([
            'type'         => 'default',
            'session_id'   => $imSession['id'],
            'sender_id'    => 0,
            'recipient_id' => $this->userInfo['id'],
            'message'      => $kbs['content']
        ]);
        if ($messageData) {
            $sessionInfo = Common::sessionInfo($imSession['id'], $this->userInfo['id']);
            $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $this->userInfo['id']);
        }
    }

    /**
     * 客服分配
     * @param array $array 待排序数组
     * @return void
     */
    public function distributionCsr($data)
    {
        // 当前用户和`智能客服`的会话
        $imSession   = Common::imSession('service', $this->userInfo['id'], 3);
        $sessionInfo = Common::sessionInfo($imSession['id'], $this->userInfo['id']);

        $where['u.type']   = 'csr';
        $where['u.status'] = 1;// 只获取在线的客服代表
        if (isset($data['group_id']) && $data['group_id']) {
            $where['u.group_id'] = $data['group_id'];
        }

        $distributionType = Db::name('fastim_config')->where('name', 'distribution_type')->value('value');

        $sysTempSession = Db::name('fastim_config')->where('name', 'temp_session')->value('value');

        if ($distributionType == 0) {
            // 轮训自动分配
            $csr = Db::name('fastim_user')
                ->alias('u')
                ->field('u.*, uc.value')
                ->join('fastim_user_config uc', "uc.user_id=u.id AND uc.name='temp_session'", 'LEFT')
                ->where($where)
                ->where(function ($query) use ($sysTempSession) {
                    if ($sysTempSession == 1) {
                        $query->where("uc.value IS NULL OR uc.value=1");
                    } else {
                        $query->where("uc.value=1");
                    }
                })
                ->order('u.last_reception_time asc')
                ->find();
        } elseif ($distributionType == 1) {
            // 按工作量分配
            $receptionCount = Db::name('fastim_user')
                ->alias('u')
                ->field('u.*, uc.value')
                ->join('fastim_user_config uc', "uc.user_id=u.id AND uc.name='temp_session'", 'LEFT')
                ->where($where)
                ->where(function ($query) use ($sysTempSession) {
                    if ($sysTempSession == 1) {
                        $query->where("uc.value IS NULL OR uc.value=1");
                    } else {
                        $query->where("uc.value=1");
                    }
                })
                ->min('u.reception_count');

            $csr = Db::name('fastim_user')
                ->alias('u')
                ->field('u.*, uc.value')
                ->join('fastim_user_config uc', "uc.user_id=u.id AND uc.name='temp_session'", 'LEFT')
                ->where($where)
                ->where(function ($query) use ($sysTempSession) {
                    if ($sysTempSession == 1) {
                        $query->where("uc.value IS NULL OR uc.value=1");
                    } else {
                        $query->where("uc.value=1");
                    }
                })
                ->where('u.reception_count', $receptionCount)
                ->order('u.last_reception_time asc')
                ->find();
        } elseif ($distributionType == 2) {
            // 用户自行选择
            $csrs = Db::name('fastim_user')
                ->alias('u')
                ->field('u.id,u.nickname,u.status,fu.nickname as fu_nickname,a.nickname as a_nickname,g.name,g.id as gid, uc.value')
                ->join('user fu', 'u.user_id=fu.id', 'LEFT')
                ->join('admin a', 'u.admin_id=a.id', 'LEFT')
                ->join('fastim_csr_group g', 'u.group_id=g.id', 'LEFT')
                ->join('fastim_user_config uc', "uc.user_id=u.id AND uc.name='temp_session'", 'LEFT')
                ->where($where)
                ->where(function ($query) use ($sysTempSession) {
                    if ($sysTempSession == 1) {
                        $query->where("uc.value IS NULL OR uc.value=1");
                    } else {
                        $query->where("uc.value=1");
                    }
                })
                ->order('u.last_reception_time asc')
                ->select();

            if (!$csrs && (isset($data['no_csr_tip']) && !$data['no_csr_tip'])) {
                return;// 来自知识库的调用,由于无客服代表在线,不提示联系人工
            }

            $csrsGroup = [];
            foreach ($csrs as $key => $value) {
                $csrs[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $csrs[$key]['nickname'],
                    $csrs[$key]['fu_nickname'],
                    $csrs[$key]['a_nickname']
                ], $csrs[$key]['id']));

                unset($csrs[$key]['a_nickname'], $csrs[$key]['fu_nickname']);

                if (array_key_exists($value['gid'], $csrsGroup)) {
                    $csrsGroup[$value['gid']]['csrs'][] = $csrs[$key];
                } else {
                    $csrsGroup[$value['gid']]['name']   = $value['name'];
                    $csrsGroup[$value['gid']]['csrs'][] = $csrs[$key];
                }
            }
            $csrsGroup = array_values($csrsGroup);

            $pushSendUserMessage = [
                'type'  => 'csrs',
                'csrs'  => $csrsGroup,
                'title' => $csrsGroup ? CommonCode::$kbsManualCSR : Db::name('fastim_config')
                    ->where('name', 'no_csr_tip')
                    ->value('value')
            ];

            $kbsMessageData = Common::insertMessage([
                'type'         => 'kbs_list',
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => 0,
                'recipient_id' => $this->userInfo['id'],
                'message'      => $pushSendUserMessage
            ]);
            $this->swooleCommon->newMessagePush($kbsMessageData, $sessionInfo, $this->userInfo['id']);
            return;
        }

        if (!$csr) {

            $onlineCSRCount = Db::name('fastim_user')
                ->alias('u')
                ->field('u.id, uc.value')
                ->join('fastim_user_config uc', "uc.user_id=u.id AND uc.name='temp_session'", 'LEFT')
                ->where('u.type', 'csr')
                ->where('u.status', 1)
                ->where(function ($query) use ($sysTempSession) {
                    if ($sysTempSession == 1) {
                        $query->where("uc.value IS NULL OR uc.value=1");
                    } else {
                        $query->where("uc.value=1");
                    }
                })
                ->count('u.id');

            if (!$onlineCSRCount) {
                // 一个在线客服也没有
                $pushMessage = Db::name('fastim_config')->where('name', 'no_csr_tip')->value('value');
            } elseif (isset($data['group_id']) && $data['group_id']) {
                $pushMessage = '抱歉，您选择的分组内没有找到在线的客服代表~';
            } else {
                $pushMessage = '客服代表分配失败,请重试~';
            }

            $kbsMessageData = Common::insertMessage([
                'type'         => 'default',
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => 0,
                'recipient_id' => $this->userInfo['id'],
                'message'      => $pushMessage
            ]);
            $this->swooleCommon->newMessagePush($kbsMessageData, $sessionInfo, $this->userInfo['id']);
            return;
        }

        $this->openSession([
            'id'   => $csr['id'],
            'type' => 'user'
        ]);
    }

    /**
     * 发送消息
     */
    public function sendMessage($data)
    {
        $paramCheck = $this->swooleCommon->requiredParamCheck([
            'session_id',
            'message',
            'tokens',
            'identity'
        ], $data, false, [
            'session_id' => '会话找不到啦~',
            'message'    => '请输入消息内容~'
        ]);
        if (!$paramCheck) {
            return false;
        }

        // 复检用户登录态是否注销
        if (isset($data['tokens']['fastim_token']) && ($data['identity'] == 'admin' || $data['identity'] == 'fauser')) {
            // 管理员或用户
            $userInfo = $data['identity'] == 'fauser' ? Common::checkFaUser($data['tokens']['fastim_token']) : Common::checkAdmin($data['tokens']['fastim_token']);
        } elseif (isset($data['tokens']['im_tourists_token']) && $data['identity'] == 'imuser') {
            // imuser
            $userInfo = Common::checkIMUser($data['tokens']['im_tourists_token']);
        }
        if (!$userInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '登录已失效，请重新登录~'
            ]));
            return false;
        }


        $messageStatus = 0;
        $data['type']  = $data['type'] ?? 'default';
        $sessionInfo   = Common::sessionInfo($data['session_id'], $this->userInfo['id']);

        if ($sessionInfo['type'] == 'single') {

            // 通知输入状态结束
            $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                'event' => 'input_status',
                'data'  => [
                    'session_id' => $data['session_id'],
                    'status'     => 'end'
                ]
            ]);

            // 客服代表随时可以发送消息
            if ($sessionInfo['user']['type'] != 'csr') {
                // 检查接受人
                $friendship    = Db::name('fastim_friendship')
                    ->where('friend_id', $this->userInfo['id'])
                    ->where('user_id', $sessionInfo['sessionUser']['id'])
                    ->find();
                $friendshipTwo = Db::name('fastim_friendship')
                    ->where('user_id', $this->userInfo['id'])
                    ->where('friend_id', $sessionInfo['sessionUser']['id'])
                    ->find();
                $tempSession   = Common::imUserConfig($sessionInfo['sessionUser']['id'], 'temp_session');
                if ((!$friendship || !$friendshipTwo) && !$tempSession) {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => [
                            'msg'  => '需要好友关系才能互相发送消息哦~',
                            'type' => 'error'
                        ]
                    ]));

                    $messageStatus = 4; // 消息发送失败
                }
            }

            // 检查屏蔽状态
            $shield = Db::name('fastim_user_shield')
                ->where('user_id', $sessionInfo['sessionUser']['id'])
                ->where('shield_id', $sessionInfo['user']['id'])
                ->value('id');
            if ($shield) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => [
                        'msg'  => '消息被对方拒收了~',
                        'type' => 'error'
                    ]
                ]));

                $messageStatus = 4; // 消息发送失败
            }

            // 消息入库
            $messageData = Common::insertMessage([
                'type'         => $data['type'],
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => $this->userInfo['id'],
                'recipient_id' => $sessionInfo['sessionUser']['id'],
                'message'      => $data['message'],
                'status'       => $messageStatus
            ]);

            if ($messageData) {
                if ($sessionInfo['sessionUser']['status'] == '忙碌') {
                    // 取得忙碌时的自动回复
                    $busyReply = Common::imUserConfig($sessionInfo['sessionUser']['id'], 'busy_reply');
                    if ($busyReply) {
                        $busyReply = CommonCode::$busyReplyPrefix . $busyReply;

                        // 自动回复消息入库
                        $busyReplyData = Common::insertMessage([
                            'type'         => 'default',
                            'session_id'   => $sessionInfo['id'],
                            'sender_id'    => $sessionInfo['sessionUser']['id'],
                            'recipient_id' => $this->userInfo['id'],
                            'message'      => $busyReply
                        ]);
                        if ($busyReplyData) {
                            $this->swooleCommon->newMessagePush($busyReplyData, $sessionInfo, $this->userInfo['id']);
                        }

                        // 通知发送自动回复的用户更新消息记录
                        $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                            'event' => 'reload_session',
                            'data'  => [
                                'session_id' => $data['session_id']
                            ]
                        ]);
                    }
                }

                // 推送新消息给接受人
                if ($messageData['status'] != 4) {
                    $sessionInfo['pushUser'] = Common::getImUserInfo($this->userInfo['id'], true, $sessionInfo['sessionUser']['id']);
                    $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $sessionInfo['sessionUser']['id']);

                    /**
                     * sendToYourself:是否是发送给自己的
                     * 发送给自己的任然需推送给自己的其他在线设备
                     * 此处做标记以在前端删除可能存在的原消息:`message_id`
                     */
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'send_message',
                        'data'  => [
                            'message_id'     => $data['message_id'],
                            'new_message_id' => $messageData['id'],
                            'status'         => 0,
                            'sendToYourself' => ($this->userInfo['id'] == $sessionInfo['sessionUser']['id']) ? true : false
                        ]
                    ]));
                }
            } else {
                $messageStatus = 4;
            }

            if ($messageStatus == 4) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'send_message',
                    'data'  => [
                        'message_id' => $data['message_id'],
                        'status'     => 4
                    ]
                ]));
            }
        } elseif ($sessionInfo['type'] == 'group') {
            if ($sessionInfo['sessionUser']['speak'] == 1 && $sessionInfo['sessionUser']['leader'] != $this->userInfo['id']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => [
                        'msg'  => '管理员已禁止发言~',
                        'type' => 'error'
                    ]
                ]));
            }

            // 推送群消息
            $messageData = $this->swooleCommon->pushMessageToGroup($data['type'], [
                'group_id'   => $sessionInfo['chat_id'],
                'session_id' => $sessionInfo['id'],
                'sender_id'  => $this->userInfo['id'],
                'message'    => $data['message']
            ], $this->userInfo['id'], $data['message_id'], isset($data['at_users']) ? $data['at_users'] : []);

            if (!$messageData) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'send_message',
                    'data'  => [
                        'message_id' => $data['message_id'],
                        'status'     => 4
                    ]
                ]));
            }
        } elseif ($sessionInfo['type'] == 'service' && $sessionInfo['chat_id'] == 3) {
            // 用户给智能客服发送消息

            // 消息入库
            $messageData = Common::insertMessage([
                'type'         => $data['type'],
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => $this->userInfo['id'],
                'recipient_id' => $sessionInfo['user_two'],
                'message'      => $data['message'],
                'status'       => 1
            ]);

            // 知识库阅读了此消息
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'send_message',
                'data'  => [
                    'message_id'     => $data['message_id'],
                    'new_message_id' => $messageData['id'] ?? 0,
                    'status'         => $messageData ? $messageData['status'] : 4
                ]
            ]));

            // 搜索知识库并自动回复-区分有收录和无收录,供前端做不同的显示
            if (in_array($data['message'], CommonCode::$manualCSRKeywords)) {
                $kbs       = false;
                $manualCSR = true;
            } else {
                $kbs       = Common::getKbs($data['message'], 0);
                $manualCSR = false;
            }

            if ($kbs) {
                $pushSendUserMessage = [
                    'title' => CommonCode::$kbsIncluded,
                    'type'  => 'included',
                    'kbs'   => $kbs
                ];
            } else {
                $distributionType = Db::name('fastim_config')->where('name', 'distribution_type')->value('value');

                if ($distributionType == 2) {
                    // 提示用户选择人工客服代表-带客服分组
                    if (!$manualCSR) {
                        $kbsMessageData = Common::insertMessage([
                            'type'         => 'default',
                            'session_id'   => $sessionInfo['id'],
                            'sender_id'    => 0,
                            'recipient_id' => $this->userInfo['id'],
                            'message'      => CommonCode::$kbsNotIncluded
                        ]);
                        $this->swooleCommon->newMessagePush($kbsMessageData, $sessionInfo, $this->userInfo['id']);
                    }

                    return $this->distributionCsr([
                        'no_csr_tip' => $manualCSR
                    ]);
                }

                $distributionGroupSelect = Db::name('fastim_config')
                    ->where('name', 'distribution_group_select')
                    ->value('value');

                $kbsNotIncludedTip = (!$manualCSR ? CommonCode::$kbsNotIncluded : '') . CommonCode::$kbsManualCSR;

                if ($distributionGroupSelect == 0) {
                    // 选择人工客服-先选择客服分组
                    $dbprefix       = config('database.prefix');
                    $sysTempSession = Db::name('fastim_config')->where('name', 'temp_session')->value('value');
                    $tempSessionSql = 'AND (' . ($sysTempSession == 1 ? 'uc.value IS NULL OR uc.value=1' : 'uc.value=1') . ')';

                    $groupCsrCountSql = "(SELECT count('u.id') FROM `{$dbprefix}fastim_user` `u` LEFT JOIN `{$dbprefix}fastim_user_config` `uc` ON `uc`.`user_id`=`u`.`id` AND `uc`.`name`='temp_session' WHERE u.type='csr' AND u.status=1 AND u.group_id=g.id {$tempSessionSql})";

                    $csrGroup = Db::name('fastim_csr_group')
                        ->alias('g')
                        ->field('g.id,g.name,' . $groupCsrCountSql . ' as csr_count')
                        ->where('g.status', '1')
                        ->where('g.deletetime', null)
                        ->order('g.weigh desc')
                        ->select();

                    $pushSendUserMessage = [
                        'type'      => 'distribution-group-select',
                        'title'     => $kbsNotIncludedTip,
                        'csr_group' => $csrGroup
                    ];
                } elseif ($distributionGroupSelect == 1) {
                    // 直接分配-提示用户是否接入人工
                    $pushSendUserMessage = [
                        'type'  => 'not-included',
                        'title' => $kbsNotIncludedTip
                    ];
                }
            }

            $kbsMessageData = Common::insertMessage([
                'type'         => 'kbs_list',
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => 0,
                'recipient_id' => $this->userInfo['id'],
                'message'      => $pushSendUserMessage
            ]);
            if ($kbsMessageData) {
                // 推送新消息给接受人
                $this->swooleCommon->newMessagePush($kbsMessageData, $sessionInfo, $this->userInfo['id']);
            }
        }
    }
}