123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- <?php
- // +----------------------------------------------------------------------
- // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
- // +----------------------------------------------------------------------
- // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
- // +----------------------------------------------------------------------
- // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
- // +----------------------------------------------------------------------
- // | Author: CRMEB Team <admin@crmeb.com>
- // +----------------------------------------------------------------------
- namespace app\webscoket;
- use app\services\message\service\StoreServiceLogServices;
- use app\services\message\service\StoreServiceRecordServices;
- use app\services\message\service\StoreServiceServices;
- use app\services\order\StoreOrderRefundServices;
- use app\services\order\StoreOrderServices;
- use app\services\product\product\StoreProductServices;
- use app\services\user\UserServices;
- use app\services\wechat\WechatUserServices;
- use app\jobs\notice\template\WechatTemplateJob;
- use crmeb\services\wechat\Messages;
- use crmeb\services\wechat\OfficialAccount;
- use crmeb\utils\Arr;
- use think\facade\Log;
- /**
- * socket 事件基础类
- * Class BaseHandler
- * @package app\webscoket
- */
- abstract class BaseHandler
- {
- /**
- * @var Manager
- */
- protected $manager;
- /**
- * @var Room
- */
- protected $room;
- /**
- * @var int
- */
- protected $fd;
- /**
- * 用户聊天端
- * @var int|null
- */
- protected $formType;
- /**
- * 登陆
- * @param array $data
- * @param Response $response
- * @return mixed
- */
- abstract public function login(array $data, Response $response);
- /**
- * 事件入口
- * @param $event
- * @return |null
- */
- public function handle($event)
- {
- [$method, $result, $manager, $room] = $event;
- $this->manager = $manager;
- $this->room = $room;
- $this->fd = array_shift($result);
- $this->formType = array_shift($result);
- if (method_exists($this, $method)) {
- if (($method == 'login' || $method == 'kefu_login') && is_string($result[0])) {
- $result[0] = ['token' => $result[0]];
- }
- return $this->{$method}(...$result);
- } else {
- Log::error('socket 回调事件' . $method . '不存在,消息内容为:' . json_encode($result));
- return null;
- }
- }
- /**
- * 聊天事件
- * @param array $data
- * @param Response $response
- * @return bool|\think\response\Json|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function chat(array $data = [], Response $response)
- {
- $user = $this->room->get($this->fd);
- if (!$user) {
- return $response->fail('聊天用户不存在');
- }
- $to_uid = $data['to_uid'] ?? 0;
- $msn_type = $data['type'] ?? 0;
- $msn = $data['msn'] ?? '';
- $formType = $this->formType ?? null;
- //是否为游客
- $isTourist = $data['is_tourist'] ?? 0;
- $tourist_uid = $data['tourist_uid'] ?? 0;
- $isTourist = $isTourist && $tourist_uid;
- $tourist_avatar = $data['tourist_avatar'] ?? '';
- $uid = $isTourist ? $tourist_uid : $user['uid'];
- if (!$to_uid) {
- return $response->message('err_tip', ['msg' => '用户不存在']);
- }
- if ($to_uid == $uid) {
- return $response->message('err_tip', ['msg' => '不能和自己聊天']);
- }
- /** @var StoreServiceLogServices $logServices */
- $logServices = app()->make(StoreServiceLogServices::class);
- if (!in_array($msn_type, StoreServiceLogServices::MSN_TYPE)) {
- return $response->message('err_tip', ['msg' => '格式错误']);
- }
- $msn = trim(strip_tags(str_replace(["\n", "\t", "\r", " "], '', htmlspecialchars_decode($msn))));
- $data = compact('to_uid', 'msn_type', 'msn', 'uid');
- $data['add_time'] = time();
- $data['is_tourist'] = $data['is_tourist'] ?? 0;
- //获取收消息人的所有fd信息
- $toUserFd = $this->manager->userFd($user['type'] == 2 ? 1 : 2, $to_uid);
- $toUser = ['to_uid' => -1];
- $fremaData = [];
- foreach ($toUserFd as $value) {
- if ($frem = $this->room->get($value)) {
- $fremaData[] = $frem;
- //如果当收消息人在和当前发消息人对话中
- if ($frem['to_uid'] == $user['uid']) {
- $toUser = $frem;
- }
- }
- }
- //是否在线
- //是否和当前用户对话
- $online = $toUserFd && $toUser && $toUser['to_uid'] !== -1;
- $data['type'] = $online ? 1 : 0;
- $data = $logServices->save($data);
- $data = $data->toArray();
- $data['_add_time'] = $data['add_time'];
- $data['add_time'] = strtotime($data['add_time']);
- $_userInfo = [];
- if (!$isTourist) {
- /** @var StoreServiceServices $userService */
- $userService = app()->make(StoreServiceServices::class);
- $_userInfo = $userService->get(['uid' => $data['uid']], ['nickname', 'avatar']);
- if (!$_userInfo) {
- /** @var UserServices $userService */
- $userService = app()->make(UserServices::class);
- $_userInfo = $userService->getUserInfo($data['uid'], 'nickname,avatar');
- }
- }
- if ($isTourist || !$_userInfo) {
- $avatar = sys_config('tourist_avatar');
- $_userInfo['avatar'] = $tourist_avatar ? $tourist_avatar : Arr::getArrayRandKey(is_array($avatar) ? $avatar : []);
- $_userInfo['nickname'] = '游客' . $uid;
- }
- $data['nickname'] = $_userInfo['nickname'];
- $data['avatar'] = $_userInfo['avatar'];
- //商品消息类型
- $data['productInfo'] = [];
- if ($msn_type == StoreServiceLogServices::MSN_TYPE_GOODS && $msn) {
- /** @var StoreProductServices $productServices */
- $productServices = app()->make(StoreProductServices::class);
- $productInfo = $productServices->getProductInfo((int)$msn, 'store_name,IFNULL(sales,0) + IFNULL(ficti,0) as sales,image,slider_image,price,vip_price,ot_price,stock,id');
- $data['productInfo'] = $productInfo ? $productInfo->toArray() : [];
- }
- //订单消息类型
- $data['orderInfo'] = [];
- if ($msn_type == StoreServiceLogServices::MSN_TYPE_ORDER && $msn) {
- /** @var StoreOrderServices $orderServices */
- $orderServices = app()->make(StoreOrderServices::class);
- $order = $orderServices->getUserOrderDetail($msn, $uid);
- if ($order) {
- $order = $orderServices->tidyOrder($order->toArray(), true, true);
- $order['add_time_y'] = date('Y-m-d', $order['add_time']);
- $order['add_time_h'] = date('H:i:s', $order['add_time']);
- $data['orderInfo'] = $order;
- }
- }
- if ($msn_type == StoreServiceLogServices::MSN_TYPE_REFUND_ORDER && $msn) {
- /** @var StoreOrderRefundServices $orderRefundServices */
- $orderRefundServices = app()->make(StoreOrderRefundServices::class);
- $order = $orderRefundServices->refundDetail($msn);
- if ($order) {
- $order['add_time_y'] = date('Y-m-d', $order['add_time']);
- $order['add_time_h'] = date('H:i:s', $order['add_time']);
- $data['orderInfo'] = $order;
- }
- }
- //用户向客服发送消息,判断当前客服是否在登录中
- /** @var StoreServiceRecordServices $serviceRecored */
- $serviceRecored = app()->make(StoreServiceRecordServices::class);
- $unMessagesCount = $logServices->getMessageNum(['uid' => $uid, 'to_uid' => $to_uid, 'type' => 0, 'is_tourist' => $isTourist ? 1 : 0]);
- //记录当前用户和他人聊天记录
- $data['recored'] = $serviceRecored->saveRecord($uid, $to_uid, $msn, $formType ?? 0, $msn_type, $unMessagesCount, $isTourist, $data['nickname'], $data['avatar']);
- //是否在线
- if ($online) {
- $this->manager->pushing($toUserFd, $response->message('reply', $data)->getData());
- } else {
- //用户在线,可是没有和当前用户进行聊天,给当前用户发送未读条数
- if ($toUserFd && $toUser && isset($toUser['to_uid']) && $toUser['to_uid'] != $uid) {
- $data['recored']['nickname'] = $_userInfo['nickname'];
- $data['recored']['avatar'] = $_userInfo['avatar'];
- $this->manager->pushing($toUserFd, $response->message('mssage_num', [
- 'uid' => $uid,
- 'num' => $unMessagesCount,
- 'recored' => $data['recored']
- ])->getData());
- }
- if (!$isTourist) {
- //用户不在线
- /** @var WechatUserServices $wechatUserServices */
- $wechatUserServices = app()->make(WechatUserServices::class);
- $userInfo = $wechatUserServices->getOne(['uid' => $to_uid, 'user_type' => 'wechat'], 'nickname,subscribe,openid,headimgurl');
- if ($userInfo && $userInfo['subscribe'] && $userInfo['openid']) {
- $description = '您有新的消息,请注意查收!';
- if ($formType !== null) {
- $head = '客服接待消息提醒';
- $url = sys_config('site_url') . '/kefu/mobile_chat?toUid=' . $uid . '&nickname=' . $_userInfo['nickname'];
- } else {
- $head = '客服回复消息提醒';
- $url = sys_config('site_url') . '/pages/extension/customer_list/chat?uid=' . $uid;
- }
- $message = Messages::newsMessage($head, $description, $url, $_userInfo['avatar']);
- $userInfo = $userInfo->toArray();
- try {
- OfficialAccount::staffService()->message($message)->to($userInfo['openid'])->send();
- } catch (\Exception $e) {
- if ($msn_type == 3) {
- $msn = '[图片]';
- } elseif ($msn_type == 4) {
- $msn = '[语音]';
- } elseif ($msn_type == 5) {
- $msn = '[商品]';
- } elseif ($msn_type == 6) {
- $msn = '[订单]';
- } elseif ($msn_type == 7) {
- $msn = '[退款订单]';
- }
- // $res = WechatTemplateJob::dispatchDo('sendServiceNoticeNew', [$userInfo['openid'], [
- // 'first' => $head,
- // 'keyword1' => $formType !== null ? '客服接待' : '客服回复',
- // 'keyword2' => '回复中',
- // 'keyword3' => date('Y-m-d H:i:s', time()),
- // 'remark' => '消息内容:' . $msn . ';点击查看更多消息!'
- // ], $url]);
- // if (!$res) Log::error($userInfo['nickname'] . '发送失败' . $e->getMessage());
- }
- }
- }
- }
- return $response->message('chat', $data);
- }
- /**
- * 切换用户聊天
- * @param array $data
- * @param Response $response
- * @return \think\response\Json
- */
- public function to_chat(array $data = [], Response $response)
- {
- $toUid = $data['id'] ?? 0;
- $res = $this->room->get($this->fd);
- if ($res && $toUid) {
- $uid = $res['uid'];
- $this->manager->updateTabelField((int)$res['type'], (int)$uid, (int)$toUid);
- //不是游客进入记录
- if (!$res['tourist']) {
- /** @var StoreServiceRecordServices $service */
- $service = app()->make(StoreServiceRecordServices::class);
- $service->update(['user_id' => $uid, 'to_uid' => $toUid], ['mssage_num' => 0]);
- /** @var StoreServiceLogServices $logServices */
- $logServices = app()->make(StoreServiceLogServices::class);
- $logServices->update(['uid' => $toUid, 'to_uid' => $uid], ['type' => 1]);
- }
- return $response->message('mssage_num', ['uid' => $toUid, 'num' => 0, 'recored' => (object)[]]);
- }
- }
- /**
- * 测试原样返回
- * @param array $data
- * @param Response $response
- * @return bool|\think\response\Json|null
- */
- public function test(array $data = [], Response $response)
- {
- return $response->success($data);
- }
- /**
- * 关闭连接触发
- * @param array $data
- * @param Response $response
- */
- public function close(array $data = [], Response $response)
- {
- $uid = $data['uid'] ?? 0;
- if ($uid) {
- /** @var StoreServiceRecordServices $service */
- $service = app()->make(StoreServiceRecordServices::class);
- $service->updateRecord(['to_uid' => $uid], ['online' => 0]);
- $this->manager->pushing($this->manager->userFd(Manager::KEFU_TYPE_NUM), $response->message('online', [
- 'online' => 0,
- 'uid' => $uid
- ]), $this->fd);
- }
- }
- }
|