first commit

This commit is contained in:
编码猿
2024-09-27 01:32:49 +08:00
commit 28ebe05a64
7399 changed files with 1174529 additions and 0 deletions

View File

@@ -0,0 +1 @@
78c21b46-ce1f-415d-b724-3cb2296a4730

View File

@@ -0,0 +1,114 @@
<?php
namespace app\http;
use app\facade\RedisCache;
use app\http\service\ChatCloseService;
use app\http\service\ChatMessageService;
use app\http\service\ChatService;
use app\http\service\MessageQueueService;
use think\facade\Log;
use think\swoole\Server;
class Swoole extends Server
{
protected $serverType = 'socket';
protected $port = 9502;
protected $sockType = SWOOLE_SOCK_TCP | SWOOLE_SSL;
protected $option = [
'worker_num'=> 4,
'task_worker_num' => 4,
'daemonize' => true,
'backlog' => 128,
'heartbeat_idle_time' => 600,
'heartbeat_check_interval' => 60,
'ssl_cert_file' => '/usr/local/nginx/conf/cert/jinhu11.pem',
'ssl_key_file' => '/usr/local/nginx/conf/cert/jinhu11.key',
];
public function onOpen($server, $request)
{
//建立连接时,应将用户信息入缓存,并将客服分配给该用户
//Cache::setCliUser($request->fd,['id'=>$request->fd, 'ip'=>$request->server['remote_addr']]);
//echo '连接建立';
//echo json_encode($request);
//Log::info(json_encode($request));
//Log::info('读$_COOKIE参数'.json_encode($_COOKIE));
//Log::info('读cookie参数'.$request->cookie['PHPSESSID']);
//取缓存
//Log::info('session原会话信息'.Cache::store('session_store')->get($request->cookie['PHPSESSID']));
//$session_data=$this->unserialize_php(Cache::store('session_store')->get($request->cookie['PHPSESSID']));
//读取user_id
//如果不存在user_id则为游客随机分配在线客服
//如果存在user_id则查询专属客服若专属客服不在线则随机分配在线客服
//Log::info('session自解码会话信息'.json_encode();
$chat_deal=new ChatService($server,$request);
$chat_deal->onOpen();
}
public function onMessage($server, $frame) {
//收到消息,根据用户信息发给指定人
$chat_message_deal=new ChatMessageService($server,$frame);
$chat_message_deal->deal();
/*$data = json_decode($frame->data,true);
switch ($data['type']) {
case 'openService' :
$chat_deal=new ChatService($server,$frame->fd,$data);
$result=$chat_deal->openService();
break;
default:
$result['message_type']='error';
$result['data']=['错误消息类型'];
}
$server->push($frame->fd,myResult($result['message_type'],['content'=>$result['data']]));*/
}
public function onClose($server, $fd) {
//连接关闭,将用户信息从缓存中移除,并存入聊天日志
$chat_deal=new ChatCloseService($server,$fd);
$chat_deal->onClose();
}
public function onStart($server) {
//清空所有缓存
$base_keys=['CHAT_USER_FD_MAP','CHAT_USER_FD','CHAT_USER_INFO','CHAT_USER_QUEUE','CHAT_CS_FD_MAP','CHAT_CS_FD','CHAT_CS_INFO','CUSTOMER_ONLINE_QUEUE','CHAT_ADMIN_FD_MAP','CHAT_ADMIN_FD','CHAT_ADMIN_INFO'];
$chat_list=RedisCache::keys('CHAT_DATA_*');
$offline_chat_list=RedisCache::keys('OFFLINE_CHAT_DATA_*');
RedisCache::batch_del(array_merge($base_keys,$chat_list,$offline_chat_list));
Log::info('主进程清除缓存结束');
//定时刷下数据链接试试看有没有效果。实际有效果但有个pipe的问题因为主进程和工作进程之间实际并没有共享数据库实例尝试在工作进程中开定时器刷新以防broken pipe的情况出现
/*swoole_timer_tick(1000*600, function () {
Db::name('users')->where(['user_id'=>0])->value('user_id');
});*/
}
public function onWorkerStart($server,$worker_id) {
//定时刷下数据链接试试看有没有效果。由于8个进程都会刷新减少刷新频率30分钟刷一次试下TP的自动重连机制暂不刷新
/*swoole_timer_tick(1000*1800, function () {
Db::name('users')->where(['user_id'=>0])->value('user_id');
});*/
if ($server->taskworker) {
Log::info('启动消息队列监听任务进程'.$worker_id);
//每个任务进程起一个监听尝试监听redis以便实现消息通知
while (true) {
if (($msgs = RedisCache::brpop('MESSAGE_QUEUE', 5))==null) {
//没有则继续监听
continue;
} else {
$message_queue_deal=new MessageQueueService($server,$msgs);
$message_queue_deal->deal();
}
}
} else {
Log::info('启动通话处理任务进程'.$worker_id);
}
}
public function onTask($server,$task_id,$src_worker_id,$data) {
//暂不使用
}
public function onFinish($server,$task_id,$data) {
//暂不使用
}
}

View File

@@ -0,0 +1 @@
fd7300e7-471e-47fd-bb61-4c9a80139305

View File

@@ -0,0 +1,21 @@
<?php
namespace app\http\middleware;
use think\facade\Request;
class CrossDomain
{
public function handle($request, \Closure $next)
{
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:*');
header('Access-Control-Allow-Headers:*');
header('Access-Control-Allow-Credentials:false');
if (Request::isOptions()) {
return response('',200);
}
return $next($request);
}
}

View File

@@ -0,0 +1 @@
3f3d7c94-5eb5-4886-b90f-8df14fd8e433

View File

@@ -0,0 +1,190 @@
<?php
namespace app\http\service;
use app\facade\AppConstant;
use app\facade\RedisCache;
use think\captcha\Captcha;
use think\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
class ChatCloseService extends CommonService
{
protected $fd=0;
protected $server=null;
public function __construct($server, $fd)
{
$this->fd=$fd;
$this->server=$server;
}
public function onClose() {
$fd_store=RedisCache::hget('CHAT_USER_FD_MAP',$this->fd);
if ($fd_store) {
//删除并存储相应的对话记录
//先取出所有的keys
$chat_list=RedisCache::keys('CHAT_DATA_'.$fd_store.'_*');
//做相应的对话处理
$cs_store=[];
$remove_flag=[];
$add_data=[];
$tmp_add_data['create_time']=date('Y-m-d H:i:s');
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$fd_store),true);
if ($user_info_data['guest_flag']) {
$tmp_add_data['user_id']=0;
$tmp_add_data['user_session']=$fd_store;
} else {
$tmp_add_data['user_id']=$fd_store;
$tmp_add_data['user_session']='';
}
foreach ($chat_list as $v) {
//取出用户本次通话的记录
$chat_message_list=RedisCache::lrange($v);
//第一条系统发出的,不做判断
if (count($chat_message_list)>1) {
$remove_flag[]=false;
} else {
$remove_flag[]=true;
}
//取出用户目前的存储id
$this_cs_store=substr($v,strlen('CHAT_DATA_'.$fd_store.'_'));
//存入数据库的数据组装
$tmp_add_data['admin_user_id']=$this_cs_store;
$tmp_add_data['message']=json_encode($chat_message_list);
$tmp_add_data['offline_flag']=0;
$add_data[]=$tmp_add_data;
$cs_store[]=$this_cs_store;
}
//离线消息部分
//先取出所有的keys
$offline_chat_list=RedisCache::keys('OFFLINE_CHAT_DATA_'.$fd_store.'_*');
foreach ($offline_chat_list as $v) {
//取出用户本次离线消息的记录
$offline_chat_message_list=RedisCache::lrange($v);
//取出客服目前的存储id
$this_cs_store=substr($v,strlen('OFFLINE_CHAT_DATA_'.$fd_store.'_'));
//存入数据库的数据组装
$tmp_add_data['admin_user_id']=$this_cs_store;
$tmp_add_data['message']=json_encode($offline_chat_message_list);
$tmp_add_data['offline_flag']=1;
$add_data[]=$tmp_add_data;
}
//--
$this->noticeUserLeave($this->server,$fd_store,$cs_store,$remove_flag,$user_info_data);
//删除
RedisCache::batch_del($chat_list);
RedisCache::batch_del($offline_chat_list);
//用户关闭连接,删除相应缓存
RedisCache::hdel('CHAT_USER_FD_MAP',$this->fd);
RedisCache::hdel('CHAT_USER_FD',$fd_store);
RedisCache::hdel('CHAT_USER_INFO',$fd_store);
RedisCache::lrem('CHAT_USER_QUEUE',$fd_store,0);
//广播通知
$this->pushUserQueueNum($this->server);
//聊天记录存入数据库
if (count($add_data)>0) {
Db::name('chat_message')->insertAll($add_data);
}
} else {
$fd_store=RedisCache::hget('CHAT_CS_FD_MAP',$this->fd);
if ($fd_store) {
//先删除并存储相应的对话记录
//先取出所有的keys
$chat_list=RedisCache::keys('CHAT_DATA_*_'.$fd_store);
//做相应的对话处理,待实现
$user_store=[];
$add_data=[];
$tmp_add_data['create_time']=date('Y-m-d H:i:s');
$tmp_add_data['admin_user_id']=$fd_store;
foreach ($chat_list as $v) {
//取出用户本次通话的记录
$chat_message_list=RedisCache::lrange($v);
//取出用户目前的存储id
$this_user_store=substr($v,strlen('CHAT_DATA_'),strrpos($v,'_'.$fd_store)-strlen('CHAT_DATA_'));
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$this_user_store),true);
if ($user_info_data['guest_flag']) {
$tmp_add_data['user_id']=0;
$tmp_add_data['user_session']=$this_user_store;
} else {
$tmp_add_data['user_id']=$this_user_store;
$tmp_add_data['user_session']='';
}
$tmp_add_data['message']=json_encode($chat_message_list);
$tmp_add_data['offline_flag']=0;
$tmp_add_data['read_flag']=1;
$add_data[]=$tmp_add_data;
$user_store[]=$this_user_store;
}
//离线消息部分
//先取出所有的keys
$offline_chat_list=RedisCache::keys('OFFLINE_CHAT_DATA_*_'.$fd_store);
foreach ($offline_chat_list as $v) {
//取出用户本次离线消息的记录
$offline_chat_message_list=RedisCache::lrange($v);
//取出用户目前的存储id
$this_user_store=substr($v,strlen('OFFLINE_CHAT_DATA_'),strrpos($v,'_'.$fd_store)-strlen('OFFLINE_CHAT_DATA_'));
if (checkGuestFlag($this_user_store)) {
$tmp_add_data['user_id']=0;
$tmp_add_data['user_session']=$this_user_store;
} else {
$tmp_add_data['user_id']=$this_user_store;
$tmp_add_data['user_session']='';
}
$tmp_add_data['message']=json_encode($offline_chat_message_list);
$tmp_add_data['offline_flag']=1;
$tmp_add_data['read_flag']=0;
$add_data[]=$tmp_add_data;
}
//--
$this->noticeCSLeave($this->server,$user_store,$fd_store);
//删除
RedisCache::batch_del($chat_list);
RedisCache::batch_del($offline_chat_list);
//客服关闭连接,删除相应缓存
RedisCache::hdel('CHAT_CS_FD_MAP',$this->fd);
RedisCache::hdel('CHAT_CS_FD',$fd_store);
RedisCache::hdel('CHAT_CS_INFO',$fd_store);
RedisCache::lrem('CUSTOMER_ONLINE_QUEUE',$fd_store,0);
//聊天记录存入数据库
if (count($add_data)>0) {
Db::name('chat_message')->insertAll($add_data);
}
} else {
Log::info('普通工作人员关闭连接'.$this->fd);
//普通工作人员
$fd_store=RedisCache::hget('CHAT_ADMIN_FD_MAP',$this->fd);
if ($fd_store) {
//普通工作人员关闭连接,删除相应缓存
RedisCache::hdel('CHAT_ADMIN_FD_MAP',$this->fd);
RedisCache::hdel('CHAT_ADMIN_FD',$fd_store);
RedisCache::hdel('CHAT_ADMIN_INFO',$fd_store);
}
}
}
}
}

View File

@@ -0,0 +1,481 @@
<?php
namespace app\http\service;
use app\facade\AppConstant;
use app\facade\RedisCache;
use think\captcha\Captcha;
use think\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
class ChatMessageService extends CommonService
{
protected $fd=0;
protected $message_data=[];
protected $server=null;
protected $fd_store='';
public function __construct($server,$frame)
{
$this->server=$server;
$this->fd=$frame->fd;
$this->message_data = json_decode($frame->data,true);
if ($this->message_data['type']!='ping') {
Log::info('收到消息数据:'.$frame->data);
}
}
public function deal() {
switch ($this->message_data['type']) {
case 'ping' ://心跳检测
$message_type='ping';
$push_data='心跳检测';
$this->server->push($this->fd,myResult($message_type,$push_data));
//保持会话
$push_data=[];
$session_id='';
$need_check=false;
$fd_store=RedisCache::hget('CHAT_CS_FD_MAP',$this->fd);
if ($fd_store) {
$cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$fd_store),true);
$session_id=$cs_info_data['session_id'];
$need_check=true;
$check_field='admin_user_id';
} else {
$fd_store=RedisCache::hget('CHAT_USER_FD_MAP',$this->fd);
if ($fd_store) {
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$fd_store),true);
$session_id=$user_info_data['session_id'];
if (!checkGuestFlag($fd_store)) {
$need_check=true;
$check_field='user_id';
}
} else {
$fd_store=RedisCache::hget('CHAT_ADMIN_FD_MAP',$this->fd);
if ($fd_store) {
$admin_info_data = json_decode(RedisCache::hget('CHAT_ADMIN_INFO',$fd_store),true);
$session_id=$admin_info_data['session_id'];
$need_check=true;
$check_field='admin_user_id';
}
}
}
if ($session_id!='' && $need_check) {
//查看会话是否存在
$session_redis=RedisCache::store('session_store');
//Log::info('ping当前会话ID'.$session_id);
$session_data=$this->unserializePhp($session_redis->get($session_id));
//Log::info('ping当前会话信息'.json_encode($session_data));
if ($session_data) {
if (isset($session_data[$check_field])) {
$session_redis->expire($session_id,Config::get('session.expire'));
} else {
$message_type='initError';
$push_data['content']='您已退出登录';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
} else {
$message_type='initError';
$push_data['content']='您已退出登录';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
//切换缓存
RedisCache::store('default');
}
break;
case 'openService' ://客服专有,打开对外服务(进入在线客服队列)
if ($this->csInit()) { $this->openService(); }
break;
case 'getUserChat' ://客服专有,从用户等待队列中获得一个用户对话
if ($this->csInit()) { $this->getUserChat(); }
break;
case 'closeService' ://客服专有,关闭对外服务(离开在线客服队列,但目前正在对话中的,仍保持通讯)
if ($this->csInit()) { $this->closeService(); }
break;
case 'closeUserChat' ://客服专有,关闭和指定用户的对话
if ($this->csInit()) { $this->closeUserChat(); }
break;
case 'chatCSMessage' ://客服专有
if ($this->csInit()) { $this->chatCSMessage(); }
break;
case 'getChatCSMessage' ://客服专有
if ($this->csInit()) { $this->getChatCSMessage(); }
break;
case 'switchToOther' ://客服专有
//转接给其他客服
if ($this->csInit()) { $this->switchToOther(); }
break;
case 'chatMessage' ://用户专有
if ($this->userInit()) { $this->chatMessage(); }
break;
case 'getChatMessage' ://用户专有
if ($this->userInit()) { $this->getChatMessage(); }
break;
case 'reConnect' ://用户专有
//重新进入分配和等待客服队列
if ($this->userInit()) { $this->reConnect(); }
break;
default:
break;
/*$result['message_type']='error';
$result['data']=['错误消息类型'];*/
}
}
protected function csInit() {
//客服初始化
//读出fd所对应的客服
$fd_store=RedisCache::hget('CHAT_CS_FD_MAP',$this->fd);
if ($fd_store) {
$this->fd_store=$fd_store;
return true;
} else {
$message_type='initError';
$push_data['content']='没有对应工作台信息';
$this->server->push($this->fd,myResult($message_type,$push_data));
return false;
}
}
protected function userInit() {
//用户初始化
//读出fd所对应的用户
$fd_store=RedisCache::hget('CHAT_USER_FD_MAP',$this->fd);
if ($fd_store) {
$this->fd_store=$fd_store;
return true;
} else {
$message_type='initError';
$push_data['content']='没有建立通话';
$this->server->push($this->fd,myResult($message_type,$push_data));
return false;
}
}
protected function openService() {
//打开服务,增加到在线客服队列
//查看队列中是否已经存在
$online_cs_list = RedisCache::lrange("CUSTOMER_ONLINE_QUEUE");
if (!in_array($this->fd_store,$online_cs_list)) {
RedisCache::lpush("CUSTOMER_ONLINE_QUEUE",$this->fd_store);
}
/*$message_type='openService';
$push_data['content']='打开对外服务成功';
$this->server->push($this->fd,myResult($message_type,$push_data));*/
//不再自动分配
}
protected function closeService() {
//关闭对外服务,从在线客服队列中移除
RedisCache::lrem('CUSTOMER_ONLINE_QUEUE',$this->fd_store,0);
/*$result['message_type']='closeService';
$result['data']=['关闭对外服务成功'];*/
}
protected function chatCSMessage() {
//客服消息
$offline_flag=true;
//先看双方有没有建立连接
$user_store_id=$this->message_data['data']['to_id'];
$link_check = RedisCache::llen('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store);
if ($link_check>0) {
//双方在对话中
//读出用户对应的fd
$fd_store=RedisCache::hget('CHAT_USER_FD',$user_store_id);
if ($fd_store) {
$now_time=date('Y-m-d H:i:s');
$message_type='chatMessage';
$cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$this->fd_store),true);
$push_data=["cs_info"=>$cs_info_data,"time"=>$now_time,"content"=>$this->message_data['data']['content']];
$this->server->push($fd_store,myResult($message_type,$push_data));
//增加到对话记录中
RedisCache::lpush('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store,json_encode(['time'=>$now_time,"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$user_store_id]));
$offline_flag=false;
}
/*else {
$message_type='error';
$push_data['content']='消息发送失败,用户已离线';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
} else {
$message_type='error';
$push_data['content']='消息发送失败,双方未建立连接';
$this->server->push($this->fd,myResult($message_type,$push_data));*/
}
//离线消息
if ($offline_flag) {
if (!checkGuestFlag($user_store_id)) {
//离线留言
//创建离线留言
RedisCache::lpush('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store,json_encode(['time'=>date('m-d H:i:s'),"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$user_store_id]));
} else {
$message_type='error';
$push_data['content']='不能对游客进行离线留言';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
}
protected function getChatCSMessage() {
//Log::info('客服获取聊天记录'.$this->fd);
//获得历史聊天记录
$push_data['to_id']=$user_store_id=$this->message_data['data']['to_id'];
$push_data['from_times']=$from_times=$this->message_data['data']['from_times'];
$push_data['times']=$times=$this->message_data['data']['times'];
//user_id或user_session=$user_store_id
if (checkGuestFlag($user_store_id)) {
$user_where['user_session']=$user_store_id;
} else {
$user_where['user_id'] = $user_store_id;
}
$cs_where['admin_user_id']=[$this->fd_store,0];
$order['id']='desc';
//$chat_cs_message_count=Db::name('chat_message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->count();
$chat_cs_message_count=Db::name('chat_message')->where($user_where)->where($cs_where)->count();
//$chat_cs_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->order($order)->limit($from_times,$times)->select();
$chat_cs_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where($user_where)->where($cs_where)->order($order)->limit($from_times,$times)->select();
foreach ($chat_cs_message as $k=>$v) {
$chat_cs_message_list=json_decode($v['message'],true);
$chat_cs_message_result=[];
foreach ($chat_cs_message_list as $value) {
$chat_cs_message_result[]=json_decode($value,true);
}
//$chat_cs_message[$k]['message']=array_reverse($chat_cs_message_result);
$chat_cs_message[$k]['message']=$chat_cs_message_result;
}
$message_type='getChatCSMessage';
$push_data['message_count']=$chat_cs_message_count;
$push_data['chat_message']=$chat_cs_message;
//Log::info('客服获取聊天记录结果'.myResult($message_type,$push_data));
$this->server->push($this->fd,myResult($message_type,$push_data));
}
protected function closeUserChat($message_type='disconnect') {
//客服关闭和对方对话
$user_store_id=$this->message_data['data']['to_id'];
//先看双方有没有建立连接
$link_check = RedisCache::llen('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store);
if ($link_check>0) {
$this->noticeCSLeave($this->server,$user_store_id,$this->fd_store,$message_type);
//存储并删除对话
$add_data['create_time']=date('Y-m-d H:i:s');
$add_data['admin_user_id']=$this->fd_store;
if (checkGuestFlag($user_store_id)) {
$add_data['user_id']=0;
$add_data['user_session']=$user_store_id;
} else {
$add_data['user_id']=$user_store_id;
$add_data['user_session']='';
}
$add_data['message']=json_encode(RedisCache::lrange('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store));
$add_data['offline_flag']=0;
Db::name('chat_message')->insert($add_data);
RedisCache::batch_del(['CHAT_DATA_'.$user_store_id.'_'.$this->fd_store]);
}
//看看有没有离线消息
$link_check = RedisCache::llen('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store);
if ($link_check>0) {
//存储并删除对话
$add_data['create_time']=date('Y-m-d H:i:s');
$add_data['admin_user_id']=$this->fd_store;
if (checkGuestFlag($user_store_id)) {
$add_data['user_id']=0;
$add_data['user_session']=$user_store_id;
} else {
$add_data['user_id']=$user_store_id;
$add_data['user_session']='';
}
$add_data['message']=json_encode(RedisCache::lrange('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store));
$add_data['offline_flag']=1;
$add_data['read_flag']=0;
Db::name('chat_message')->insert($add_data);
RedisCache::batch_del(['OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store]);
}
}
protected function switchToOther() {
//转接其他客服
//先看双方有没有建立连接
Log::info('CHAT_DATA_'.$this->message_data['data']['to_id'].'_'.$this->fd_store);
$link_check = RedisCache::llen('CHAT_DATA_'.$this->message_data['data']['to_id'].'_'.$this->fd_store);
if ($link_check>0) {
//双方在对话中
//读出用户对应的fd
$fd_store=RedisCache::hget('CHAT_USER_FD',$this->message_data['data']['to_id']);
if ($fd_store) {
//看看转向的客服有没有建立连接
Log::info('转接的目标客服id:'.$this->message_data['data']['to_cs_id']);
$to_cs_fd=RedisCache::hget('CHAT_CS_FD',$this->message_data['data']['to_cs_id']);
Log::info('转接的目标客服fd:'.$to_cs_fd);
if ($to_cs_fd) {
$this->closeUserChat('switchToOther');
$this->createChatRelation($this->server,$fd_store,$this->message_data['data']['to_id'],$to_cs_fd,$this->message_data['data']['to_cs_id']);
$message_type='switchToOther';
$push_data['content']='转接成功';
$push_data['user_id']=$this->message_data['data']['to_id'];
$this->server->push($this->fd,myResult($message_type,$push_data));
} else {
$message_type='error';
$push_data['content']='转接失败,目标客服未开启工作台';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
} else {
$message_type='error';
$push_data['content']='转接失败,用户已离线';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
} else {
$message_type='error';
$push_data['content']='转接失败,双方未建立连接';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
protected function chatMessage() {
//用户消息
//先看双方有没有建立连接
//Log::info('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id']);
//增加留言功能
if ($this->message_data['data']['to_id']>0) {
$offline_flag=true;
$link_check = RedisCache::llen('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id']);
if ($link_check>0) {
//双方在对话中
//读出用户对应的fd
$fd_store=RedisCache::hget('CHAT_CS_FD',$this->message_data['data']['to_id']);
if ($fd_store) {
$now_time=date('Y-m-d H:i:s');
$message_type='chatMessage';
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$this->fd_store),true);
$push_data=["user_info"=>$user_info_data,"time"=>$now_time,"content"=>$this->message_data['data']['content']];
$this->server->push($fd_store,myResult($message_type,$push_data));
//增加到对话记录中
RedisCache::lpush('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id'],json_encode(['time'=>$now_time,"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$this->message_data['data']['to_id']]));
$offline_flag=false;
}
/*else {
$message_type='error';
$push_data['content']='消息发送失败,客服已离线';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
} else {
$message_type='error';
$push_data['content']='消息发送失败,双方未建立连接';
$this->server->push($this->fd,myResult($message_type,$push_data));*/
}
//离线消息
if ($offline_flag) {
if (!checkGuestFlag($this->fd_store)) {
//离线留言
//创建离线留言
RedisCache::lpush('OFFLINE_CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id'],json_encode(['time'=>date('Y-m-d H:i:s'),"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$this->message_data['data']['to_id']]));
} else {
$message_type='error';
$push_data['content']='游客不能进行留言,请先登录';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
} else {
if (!checkGuestFlag($this->fd_store)) {
//离线留言
//创建离线留言
RedisCache::lpush('OFFLINE_CHAT_DATA_' . $this->fd_store . '_0', json_encode(['time' => date('Y-m-d H:i:s'), "content" => $this->message_data['data']['content'], "from_id" => $this->fd_store, "to_id" => 0]));
} else {
$message_type='error';
$push_data['content']='游客不能进行留言,请先登录';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
}
protected function getChatMessage() {
//获得历史聊天记录
$push_data['to_id']=$cs_store_id=$this->message_data['data']['to_id'];
$push_data['from_times']=$from_times=$this->message_data['data']['from_times'];
$push_data['times']=$times=$this->message_data['data']['times'];
if (checkGuestFlag($this->fd_store)) {
$user_where['user_session']=$this->fd_store;
} else {
$user_where['user_id'] = $this->fd_store;
}
$user_where['read_flag'] = 1;
//$user_where['user_id']=$this->fd_store;
//$user_where['user_session']=$this->fd_store;
$cs_where['admin_user_id']=[$cs_store_id,0];
$order['id']='desc';
//$chat_message_count=Db::name('chat_message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->count();
//$chat_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->order($order)->limit($from_times,$times)->select();
$chat_message_count=Db::name('chat_message')->where($user_where)->where($cs_where)->count();
$chat_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where($user_where)->where($cs_where)->order($order)->limit($from_times,$times)->select();
foreach ($chat_message as $k=>$v) {
$chat_message_list=json_decode($v['message'],true);
$chat_message_result=[];
foreach ($chat_message_list as $value) {
$chat_message_result[]=json_decode($value,true);
}
//$chat_message[$k]['message']=array_reverse($chat_message_result);
$chat_message[$k]['message']=$chat_message_result;
}
$message_type='getChatMessage';
$push_data['message_count']=$chat_message_count;
$push_data['chat_message']=$chat_message;
$this->server->push($this->fd,myResult($message_type,$push_data));
}
protected function reConnect() {
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$this->fd_store),true);
$this->assignCS($this->server, $this->fd, $this->fd_store,$user_info_data['guest_flag']);
}
protected function getUserChat() {
$assign_flag=false;
//从等待队列中获得一个用户对话,应优先客服专属的用户
$online_user_list = RedisCache::lrange("CHAT_USER_QUEUE");
if (count($online_user_list)>0) {
//查询有没有专属用户
$sp_user_list=Db::name('users')->where(['user_id'=>$online_user_list,'custom_service_id'=>$this->fd_store])->column('user_id');
if ($sp_user_list!=null) {
//取第一个专属用户
foreach ($online_user_list as $v) {
if (in_array($v,$sp_user_list)) {
//从队列删除
RedisCache::lrem('CHAT_USER_QUEUE',$v,0);
//广播通知
$this->pushUserQueueNum($this->server);
//可建立通话关系
$user_id=$v;
$assign_flag=true;
break;
}
}
} else {
//从队列中取一个用户
$user_id=RedisCache::rpop("CHAT_USER_QUEUE");
//广播通知
$this->pushUserQueueNum($this->server);
$assign_flag=true;
}
}
if ($assign_flag) {
//获得用户的fd
$user_fd=RedisCache::hget('CHAT_USER_FD',$user_id);;
//建立对话关系
$this->createChatRelation($this->server,$user_fd,$user_id,$this->fd,$this->fd_store);
} else {
$message_type='error';
$push_data['content']='暂无用户需要服务';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
}

View File

@@ -0,0 +1,270 @@
<?php
namespace app\http\service;
use app\facade\RedisCache;
use think\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
class ChatService extends CommonService
{
protected $session_id='';
protected $session_data=[];
protected $fd=0;
protected $ip='';
protected $store_id=0;
protected $guest_flag=true;
protected $user_type='user';
protected $init_flag=true; //客服专用
protected $construct_flag=true; //初始化是否成功
protected $server=null;
public function __construct($server,$request)
{
$this->server=$server;
$this->fd=$request->fd;
//取IP地址后续用于区域判别和记录
$this->ip=$request->server['remote_addr'];
//取会话数据
if (isset($request->cookie[Config::get("access.SESSION_DEFAULT_NAME")])) {
$this->session_id=$request->cookie[Config::get("access.SESSION_DEFAULT_NAME")];
$this->session_data=$this->unserializePhp(Cache::store('session_store')->get($this->session_id));
//切换缓存
Cache::store('default');
} else {
$this->construct_flag=false;
Log::info('没有会话ID的数据'.json_encode($request));
}
if ($this->construct_flag) {
//用户类型
if (strpos($request->header['origin'], 'admin')) {
$this->user_type = 'cs_admin';
}
if ($this->user_type == 'user') {
//缺省游客信息
$user_info_data['guest_flag'] = true;
$user_info_data['user_name'] = '游客';
$user_info_data['area_name'] = '-';
$this->session_data['user_id'] = $this->session_data['user_id'] ?? 0;
//存储用户fd对应表
if ($this->session_data['user_id'] == 0) {
$this->store_id = $this->session_id;
} else {
$this->store_id = $this->session_data['user_id'];
//取用户信息
$user_info_result = Db::name("users")
->field('phone as user_name,area_id,buyer_status,custom_service_id')
->where(['user_id' => $this->store_id])
->find();
if ($user_info_result != null) {
$user_info_data = $user_info_result;
if ($user_info_result['buyer_status'] != 0) {
//取得用户的采购商名称
$user_info_data['buyer_name'] = Db::name('buyer')->where(['buyer_user_id' => $this->store_id])->value('name');
}
if ($user_info_result['custom_service_id'] != 0) {
//取得用户的专属客服信息
$user_info_data['sp_cs_info'] = Db::name('admin_user')->field('mobile,nickname,cs_code,cs_status')->where(['admin_user_id' => $user_info_result['custom_service_id']])->find();
}
if ($user_info_result['area_id'] != 0) {
$user_info_data['area_name'] = $this->getIDArea($user_info_result['area_id']);
} else {
$user_info_data['area_name'] = '-';
}
$user_info_data['guest_flag'] = false;
$this->guest_flag = false;
}
}
$user_info_data['ip_addr'] = $this->ip;
$user_info_data['ip_area'] = $this->getIPArea($this->ip);
$old_fd = RedisCache::hget('CHAT_USER_FD', $this->store_id);
if ($old_fd != $this->fd) {
if ($old_fd) {
//如果存在fd说明用户已经有一个窗口建立了连接需要先关闭原来的连接
$server->disconnect($old_fd, 1000, '重复开启对话');
$chat_deal = new ChatCloseService($server, $old_fd);
$chat_deal->onClose();
}
RedisCache::hset('CHAT_USER_FD', $this->store_id, $this->fd);
//存储fd和用户信息对应缓存
RedisCache::hset('CHAT_USER_FD_MAP', $this->fd, $this->store_id);
//存储用户信息
//增加用户ID以便通讯使用
$user_info_data['user_store'] = $this->store_id;
//存储session_id以便ping时保持会话
$user_info_data['session_id']=$this->session_id;
RedisCache::hset('CHAT_USER_INFO', $this->store_id, json_encode($user_info_data));
}
//相等什么都不做,实际的可能性也不存在
} else {
//客服
$this->session_data['admin_user_id'] = $this->session_data['admin_user_id'] ?? 0;
//存储客服fd对应表
if ($this->session_data['admin_user_id'] == 0) {
$this->init_flag = false;
} else {
$this->store_id = $this->session_data['admin_user_id'];
//判断是客服还是普通工作人员
$admin_info_data = Db::name("admin_user")
->field('admin_user_id as cs_store,mobile,cs_code,nickname,cs_status')
->where(['admin_user_id' => $this->store_id])
->find();
if ($admin_info_data==null) {
$this->init_flag = false;
} else {
if ($admin_info_data['cs_status']==1) {
//客服人员
$old_fd = RedisCache::hget('CHAT_CS_FD', $this->store_id);
if ($old_fd != $this->fd) {
if ($old_fd) {
//如果存在fd说明客服已经有一个窗口建立了连接需要先关闭原来的连接
$server->disconnect($old_fd, 1000, '重复开启对话');
$chat_deal = new ChatCloseService($server, $old_fd);
$chat_deal->onClose();
}
//存储session_id以便ping时保持会话
$admin_info_data['session_id'] = $this->session_id;
RedisCache::hset('CHAT_CS_FD', $this->store_id, $this->fd);
RedisCache::hset('CHAT_CS_FD_MAP', $this->fd, $this->store_id);
//存储客服信息
RedisCache::hset('CHAT_CS_INFO', $this->store_id, json_encode($admin_info_data));
}
//相等什么都不做,实际的可能性也不存在
} else {
//普通工作人员
$this->user_type = 'normal_admin';
$old_fd = RedisCache::hget('CHAT_ADMIN_FD', $this->store_id);
if ($old_fd != $this->fd) {
if ($old_fd) {
//如果存在fd说明工作人员已经有一个窗口建立了连接需要先关闭原来的连接
$server->disconnect($old_fd, 1000, '重复开启对话');
$chat_deal = new ChatCloseService($server, $old_fd);
$chat_deal->onClose();
}
//存储session_id以便ping时保持会话
$admin_info_data['session_id'] = $this->session_id;
RedisCache::hset('CHAT_ADMIN_FD', $this->store_id, $this->fd);
RedisCache::hset('CHAT_ADMIN_FD_MAP', $this->fd, $this->store_id);
//存储客服信息
RedisCache::hset('CHAT_ADMIN_INFO', $this->store_id, json_encode($admin_info_data));
}
//相等什么都不做,实际的可能性也不存在
}
}
}
}
}
}
public function onOpen() {
if ($this->construct_flag) {
if ($this->user_type=='user') {
$this->onUserOpen();
} else {
$this->onCSOpen();
}
} else {
$message_type='initError';
$push_data['content']='初始化连接异常';
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
public function onUserOpen() {
//连接成功通知
$result['message_type']='success';
$result['data']='在线客服已连接';
//返回连接成功的消息
$this->server->push($this->fd,myResult($result['message_type'],$result['data']));
//离线消息部分
if (!$this->guest_flag) {
$cs_id_list=[];
$offline_chat_message_list=[];
//是注册用户,则需要处理离线消息部分
//先取出所有的keys
$offline_chat_list=RedisCache::keys('OFFLINE_CHAT_DATA_'.$this->store_id.'_*');
foreach ($offline_chat_list as $v) {
//取出用户本次离线消息的记录
$offline_chat_message_list=array_merge($offline_chat_message_list,RedisCache::lrange($v));
//取出客服目前的存储id
$cs_id_list[]=substr($v,strlen('OFFLINE_CHAT_DATA_'.$this->store_id.'_'));
}
//数据库中未读离线消息处理
$user_where['user_id'] = $this->store_id;
//$user_where['offline_flag'] = 0;//由于目前未读消息只有可能是离线消息,暂不增加离线字段判断
$user_where['read_flag'] = 0;
$chat_message=Db::name('chat_message')->field('admin_user_id,offline_flag,message')->where($user_where)->select();
//把数据置为已读
$update_data['read_flag'] = 1;
Db::name('chat_message')->where($user_where)->update($update_data);
foreach ($chat_message as $k=>$v) {
$chat_message_list=json_decode($v['message'],true);
$offline_chat_message_list=array_merge($offline_chat_message_list,$chat_message_list);
//取出客服目前的存储id
$cs_id_list[]=$v['admin_user_id'];
}
//取出客服信息
$cs_info_data = Db::name("admin_user")
->where(['admin_user_id' => $cs_id_list])
->column('admin_user_id as cs_store,mobile,cs_code,nickname','admin_user_id');
//组装离线消息信息
$offline_chat_message_array=[];
foreach ($offline_chat_message_list as $k=>$v) {
$tmp_message=json_decode($v,true);
$offline_chat_message_array[$tmp_message['time'].$k]=$tmp_message;
}
ksort($offline_chat_message_array);
foreach ($offline_chat_message_array as $v) {
$message_type='chatMessage';
$push_data=["cs_info"=>$cs_info_data[$v['from_id']],"time"=>$v['time'],"content"=>$v['content'],"offline"=>1];
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
//分配客服
$this->assignCS($this->server,$this->fd,$this->store_id,$this->guest_flag);
}
public function onCSOpen() {
if (!$this->init_flag) {
$message_type='initError';
$push_data['content']='请先登录管理系统';
} else {
//暂时没有其他事情,由客服手动决定是否开始接受客户请求
$message_type='success';
$push_data['content']='在线办公已连接';
}
$this->server->push($this->fd,myResult($message_type,$push_data));
if ($this->user_type == 'cs_admin') {
if ($message_type=='success') {
Log::info('发送等待用户数');
//发送等待用户数
$this->pushUserQueueNum($this->server,$this->fd);
}
}
}
}

View File

@@ -0,0 +1,274 @@
<?php
namespace app\http\service;
use app\facade\AppConstant;
use app\facade\RedisCache;
use think\captcha\Captcha;
use think\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Env;
use think\facade\Log;
class CommonService
{
const TALK_WORDS=[
'hello_words'=>'您好,欢迎您使用金壶医药商城,请问您有什么疑问,我将为您在线解答。',
'work_time'=>'工作日9:00-17:30',
];
/*protected function initBaseChat($user_store,$cs_store) {
Log::info('用户ID'.$user_store.'客服ID'.$cs_store);
$cs_info_data = RedisCache::hget('CHAT_CS_INFO',$cs_store);
$user_info_data = RedisCache::hget('CHAT_USER_INFO',$user_store);
$result['cs_info_data']=$cs_info_data;
$result['user_info_data']=$user_info_data;
return $result;
}*/
/*protected function pushToCS($server,$cs_store,$user_info_data) {
//找出客服对应的fd
$fd_store=RedisCache::hget('CHAT_CS_FD',$cs_store);
if ($fd_store) {
$push_data['message_type']='connect';
$push_data['data']=["user_info"=>$user_info_data];
$server->push($fd_store,myResult($push_data['message_type'],$push_data['data']));
}
}
protected function pushToUser($server,$user_store,$cs_info_data) {
//找出用户对应的fd
$fd_store=RedisCache::hget('CHAT_USER_FD',$user_store);
if ($fd_store) {
$push_data['message_type']='connect';
$push_data['data']=["cs_info"=>$cs_info_data];
$server->push($fd_store,myResult($push_data['message_type'],$push_data['data']));
}
}*/
//当前在线等待用户数
protected function pushUserQueueNum($server,$fd=0) {
$user_queue_num=RedisCache::llen('CHAT_USER_QUEUE');
$fd_list=[];
if ($fd>0) {
//单播
$fd_list[]=$fd;
} else {
//广播在线客服
$fd_list=RedisCache::hkeys('CHAT_CS_FD_MAP');
}
Log::info('向客服'.json_encode($fd_list).'发送在线等待人数'.$user_queue_num);
foreach ($fd_list as $v) {
$message_type='userQueueNum';
$push_data=["user_queue_num"=>$user_queue_num];
$server->push($v,myResult($message_type,$push_data));
}
}
//建立对话关系,并通知双方
protected function createChatRelation($server,$user_fd,$user_store,$cs_fd,$cs_store){
$now_time=date('Y-m-d H:i:s');
$cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$cs_store),true);
$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$user_store),true);
//建立对话关系
//RedisCache::hset('CHAT_RELATION', $user_store, $cs_store);
RedisCache::lpush('CHAT_DATA_'.$user_store.'_'.$cs_store,json_encode(['time'=>$now_time,"content"=>self::TALK_WORDS['hello_words'],"from_id"=>$cs_store,"to_id"=>$user_store]));
//通知用户
$message_type = 'connect';
$push_data = $cs_info_data;
$server->push($user_fd,myResult($message_type,$push_data));
//通知客服
$message_type = 'connect';
$push_data = ["user_info"=>$user_info_data];
$server->push($cs_fd,myResult($message_type,$push_data));
//发送模版问侯
$message_type='chatMessage';
$push_data=["cs_info"=>$cs_info_data,"time"=>$now_time,"content"=>self::TALK_WORDS['hello_words']];
$server->push($user_fd,myResult($message_type,$push_data));
//如果有未存入数据库的离线消息,要发给客服
//取出用户本次离线消息的记录
$offline_chat_message_list=RedisCache::lrange('OFFLINE_CHAT_DATA_'.$user_store.'_'.$cs_store);
if (!$offline_chat_message_list) {
$offline_chat_message_list=[];
}
Log::info('和客服离线留言数据:'.json_encode($offline_chat_message_list));
if (!checkGuestFlag($user_store)) {
//还要取出离线留言
$offline_chat_message_list_0=RedisCache::lrange('OFFLINE_CHAT_DATA_'.$user_store.'_0');
if ($offline_chat_message_list_0) {
$offline_chat_message_list=array_merge($offline_chat_message_list,$offline_chat_message_list_0);
}
}
Log::info('加上和系统离线留言数据:'.json_encode($offline_chat_message_list));
//组装离线消息信息
$offline_chat_message_array=[];
foreach ($offline_chat_message_list as $k=>$v) {
$tmp_message=json_decode($v,true);
$offline_chat_message_array[$tmp_message['time'].$k]=$tmp_message;
}
ksort($offline_chat_message_array);
foreach ($offline_chat_message_array as $v) {
$message_type='chatMessage';
$push_data=["user_info"=>$user_info_data,"time"=>$v['time'],"content"=>$v['content'],"offline"=>1];
$server->push($cs_fd,myResult($message_type,$push_data));
}
//--
//模版问侯也发送给客服,因为是模拟客服发送,需要换种消息类型
$message_type='systemChatMessage';
$push_data=["user_info"=>$user_info_data,"time"=>$now_time,"content"=>self::TALK_WORDS['hello_words']];
$server->push($cs_fd,myResult($message_type,$push_data));
}
//自动分配客服(用户使用)
protected function assignCS($server,$fd,$store_id,$guest_flag){
$assign_flag=false;
$online_cs_list = RedisCache::lrange("CUSTOMER_ONLINE_QUEUE");
if (count($online_cs_list)>0) {
if (!$guest_flag) {
//如果不是游客,则看用户是否有专属客服
//若专属客服不在线,则自动分配在线客服
//从数据库中取用户专属客服
$cs_admin_id = Db::name("users")->where(['user_id' => $store_id])->value('custom_service_id');
if (in_array($cs_admin_id, $online_cs_list)) {
$assign_flag = true;
}
}
//如果未分配,则取一个在线客服
if (!$assign_flag) {
$cs_admin_id = RedisCache::rpoplpush("CUSTOMER_ONLINE_QUEUE");
if ($cs_admin_id) {
$assign_flag=true;
}
}
}
if ($assign_flag) {
//获得客服的fd
$cs_fd=RedisCache::hget('CHAT_CS_FD',$cs_admin_id);;
//建立对话关系
$this->createChatRelation($server,$fd,$store_id,$cs_fd,$cs_admin_id);
} else {
//没有分配成功,进入等待队列,该队列用户可考虑留言功能
RedisCache::lpush("CHAT_USER_QUEUE", $store_id);
$message_type='wait';
if (checkGuestFlag($store_id)) {
$push_data['content']='在线客服服务时间为'.self::TALK_WORDS['work_time'].'。当前暂无客服接待,您可以等待,登录平台可以进行离线留言';
} else {
$push_data['content']='在线客服服务时间为'.self::TALK_WORDS['work_time'].'。当前暂无客服接待,您可以离线留言或等待';
}
$server->push($fd,myResult($message_type,$push_data));
//向所有在线客服发送等待用户数
$this->pushUserQueueNum($server);
}
}
//用户关闭通知(用户使用)
protected function noticeUserLeave($server,$user_store,$cs_store,$remove_flag,$user_info_data){
//通知用户
$message_type = 'disconnect';
//$user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$user_store),true);
$push_data = $user_info_data;
//群体通知
if (is_array($cs_store)) {
if (count($cs_store) > 0) {
foreach ($cs_store as $k=>$v) {
$cs_fd = RedisCache::hget('CHAT_CS_FD', $v);
if ($cs_fd != null) {
$push_data['remove_flag']=$remove_flag[$k];
Log::info('是否需要关闭'.json_encode($push_data['remove_flag']));
$server->push($cs_fd, myResult($message_type, $push_data));
}
}
/*$cs_fd_list = RedisCache::hmget('CHAT_CS_FD', $cs_store);
if ($cs_fd_list !== false) {
foreach ($cs_fd_list as $v) {
$server->push($v, myResult($message_type, $push_data));
}
}*/
}
} else {
//获得用户的fd
$cs_fd=RedisCache::hget('CHAT_CS_FD',$cs_store);
$server->push($cs_fd,myResult($message_type,$push_data));
}
}
//客服关闭通知(客服使用)
protected function noticeCSLeave($server,$user_store,$cs_store,$message_type='disconnect'){
//通知用户
$cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$cs_store),true);
$push_data = $cs_info_data;
//群体通知
if (is_array($user_store)) {
if (count($user_store) > 0) {
$user_fd_list = RedisCache::hmget('CHAT_USER_FD', $user_store);
if ($user_fd_list !== false) {
foreach ($user_fd_list as $v) {
$server->push($v, myResult($message_type, $push_data));
}
}
}
} else {
//获得用户的fd
$user_fd=RedisCache::hget('CHAT_USER_FD',$user_store);
$server->push($user_fd,myResult($message_type,$push_data));
}
}
//IP获取地址
public function getIPArea($ip)
{
require_once Env::get('extend_path').'ip2region/Ip2Region.php';
$ip2region = new \Ip2Region();
$info = $ip2region->btreeSearch($ip);
$city = explode('|', $info['region']);
if (0 != $info['city_id']) {
return $city['2'] . $city['3'] . $city['4'];
} else {
return $city['0'];
}
}
//通过area_id获取地址
public function getIDArea($area_id)
{
$tmp_area_data=Db::name('area')->field('area_name,parent_area_id')->where(['id'=>$area_id])->find();
if ($tmp_area_data==null) {
return '';
}
if ($tmp_area_data['parent_area_id']!=0) {
return $this->getIDArea($tmp_area_data['parent_area_id']).'-'.$tmp_area_data['area_name'];
} else {
return $tmp_area_data['area_name'];
}
}
//解析session数据
protected function unserializePhp($session_data) {
$return_data = array();
$offset = 0;
while ($offset < strlen($session_data)) {
if (!strstr(substr($session_data, $offset), "|")) {
return false;
}
$pos = strpos($session_data, "|", $offset);
$num = $pos - $offset;
$varname = substr($session_data, $offset, $num);
$offset += $num + 1;
$data = unserialize(substr($session_data, $offset));
$return_data[$varname] = $data;
$offset += strlen(serialize($data));
}
return $return_data;
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace app\http\service;
use app\facade\AppConstant;
use app\facade\RedisCache;
use think\captcha\Captcha;
use think\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
class MessageQueueService extends CommonService
{
protected $fd=0;
protected $message_data=[];
protected $server=null;
protected $fd_store='';
public function __construct($server,$msgs)
{
$this->server=$server;
$this->message_data = json_decode($msgs[1],true);
Log::info('数组数据:'.json_encode($this->message_data));
}
public function deal() {
//处理具体的消息推送
switch ($this->message_data['type']) {
case 'noticeOrder' ://通知打开控制台的管理员,订单的情况
Log::info('处理noticeOrder');
if ($this->csInit()) { $this->noticeOrder(); }
break;
case 'workRmind' ://通知打开控制台的普通工作人员
Log::info('处理workRmind');
if ($this->csInit()) { $this->workRmind(); }
break;
case 'verifyRmind' ://通知打开控制台的普通工作人员
Log::info('处理verifyRmind');
if ($this->csInit()) { $this->verifyRmind(); }
break;
case 'adminLogout' ://通知管理用户已退出
if ($this->csInit()) { $this->adminLogout(); }
break;
case 'logout' ://通知用户已退出
if ($this->userInit()) { $this->logout(); }
break;
default:
break;
/*$result['message_type']='error';
$result['data']=['错误消息类型'];*/
}
}
protected function csInit() {
//客服初始化
//读出fd所对应的客服
$cs_fd = RedisCache::hget('CHAT_CS_FD', $this->message_data['admin_user_id']);
if ($cs_fd) {
$this->fd = $cs_fd;
return true;
}
$admin_fd = RedisCache::hget('CHAT_ADMIN_FD', $this->message_data['admin_user_id']);
if ($admin_fd) {
$this->fd = $admin_fd;
return true;
}
return false;
}
protected function userInit() {
//用户初始化
//读出fd所对应的用户
$user_fd = RedisCache::hget('CHAT_USER_FD', $this->message_data['user_id']);
if ($user_fd) {
$this->fd = $user_fd;
return true;
}
return false;
}
protected function noticeOrder() {
$message_type='noticeOrder';
$push_data['message']=$this->message_data['message'];
$push_data['phone']=$this->message_data['phone'];
$push_data['name']=$this->message_data['name'];
$push_data['time']=$this->message_data['time'];
$push_data['goods_amount']=$this->message_data['goods_amount'];
$push_data['order_id']=$this->message_data['order_id'];
$push_data['order_sn']=$this->message_data['order_sn'];
if ($this->server->exist($this->fd)) {
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
protected function workRmind() {
$message_type='workRmind';
$push_data['message']=$this->message_data['message'];
$push_data['phone']=$this->message_data['phone'];
$push_data['name']=$this->message_data['name'];
$push_data['time']=$this->message_data['time'];
$push_data['goods_amount']=$this->message_data['goods_amount'];
$push_data['shipping_fee']=$this->message_data['shipping_fee'];
$push_data['total_amount']=$this->message_data['total_amount'];
$push_data['deal_url']=$this->message_data['deal_url'];
$push_data['order_id']=$this->message_data['order_id'];
$push_data['order_sn']=$this->message_data['order_sn'];
if ($this->server->exist($this->fd)) {
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
protected function verifyRmind() {
$message_type='verifyRmind';
$push_data['message']=$this->message_data['message'];
$push_data['phone']=$this->message_data['phone'];
$push_data['name']=$this->message_data['name'];
$push_data['time']=$this->message_data['time'];
$push_data['offline_deadline']=$this->message_data['offline_deadline'];
$push_data['deal_url']=$this->message_data['deal_url'];
if ($this->server->exist($this->fd)) {
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
protected function adminLogout() {
$message_type='initError';
$push_data['content']='您已退出登录';
if ($this->server->exist($this->fd)) {
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
protected function logout() {
$message_type='initError';
$push_data['content']='您已退出登录';
if ($this->server->exist($this->fd)) {
$this->server->push($this->fd,myResult($message_type,$push_data));
}
}
}