first commit
This commit is contained in:
270
金壶/ydyd_service/application/http/service/ChatService.php
Normal file
270
金壶/ydyd_service/application/http/service/ChatService.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user