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,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);
}
}
}
}