1132 lines
45 KiB
Plaintext
1132 lines
45 KiB
Plaintext
<?php
|
||
|
||
namespace server\modules\api\controller;
|
||
|
||
use server\components\Db;
|
||
use server\components\ApiException;
|
||
use server\components\Base;
|
||
use server\model\UserModel;
|
||
use server\components\Utility;
|
||
use server\components\Log;
|
||
use server\lib\Gateway;
|
||
|
||
/**
|
||
* 聊天服务类
|
||
* @author: lzh
|
||
*/
|
||
class ChatLogic extends Base
|
||
{
|
||
const WORD_TIP1 = "亲,您好,下方按钮是目前可用充值方式,请点选您需要的充值方式.";
|
||
const WORD_TIP2 = "亲,您好,非常高兴能为您服务,请问有什么可以帮您的呢?";
|
||
const WORD_TIP3 = "请点击上方小卡片进行充值,充好后截图告诉我一下,我给您加金币";
|
||
const INIT_AUTO_TIME = 10 * 60;
|
||
|
||
private static $_requestParam;
|
||
|
||
private $_model;
|
||
|
||
|
||
/**
|
||
* 初始化.
|
||
*
|
||
* @param array $param
|
||
*/
|
||
public function __construct($param)
|
||
{
|
||
self::$_requestParam = $param;
|
||
|
||
parent::__construct();
|
||
|
||
$this->_model = new UserModel(self::$_db);
|
||
}
|
||
|
||
|
||
/**
|
||
* 链接关闭处理方法
|
||
* @param $ws
|
||
* @param $clientId
|
||
*/
|
||
public function close()
|
||
{
|
||
$clientId = self::$_requestParam;
|
||
echo '关闭连接:' . $clientId . PHP_EOL;
|
||
|
||
//获取断开连接的用户信息
|
||
$userInfo = json_decode(self::$_redis->hget('fd', $clientId), true);
|
||
|
||
//用户
|
||
if ($userInfo['type'] == 'userInit') {
|
||
$userInfo['id'] = $userInfo['uid'];
|
||
$userCli = self::$_db->row("SELECT kf_id FROM `ws_service_log` WHERE end_time=0 AND client_id='{$clientId}'");
|
||
$kfId = 'KF' . $userCli['kf_id'];
|
||
$kf = json_decode(self::$_redis->hget('kfList', $kfId), true);
|
||
|
||
if ($kf) {
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $kf['client_id'],
|
||
'msg_type' => 'delUser',
|
||
'data' => ['userinfo' => $userInfo, 'id' => $userInfo['uid']]
|
||
];
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
$kf['service_num'] -= 1;
|
||
self::$_redis->hset('kfList', $kfId, json_encode($kf));
|
||
}
|
||
|
||
self::$_redis->srem('user_set_' . $userInfo['group_id'] . '_' . $kfId, $userInfo['uid']);
|
||
self::$_redis->hdel('users', "{$kfId}-{$userInfo['uid']}");
|
||
$this->setUserInfoByClientId($clientId, null);
|
||
}
|
||
|
||
//客服
|
||
if (isset($userInfo['type']) && $userInfo['type'] == 'init') {
|
||
|
||
$kfId = $this->kf2Num($userInfo['uid']);
|
||
|
||
$allKf = self::$_redis->hgetall('kfList');
|
||
$allfd = [];
|
||
|
||
foreach ($allKf as $tmp) {
|
||
$tmp = json_decode($tmp, true);
|
||
$allfd[] = $tmp['client_id'];
|
||
}
|
||
if (!in_array($clientId, $allfd)) return false;
|
||
|
||
self::$_db->update('ws_users')
|
||
->cols(['online' => '2'])
|
||
->where(" id=:kf_id ")
|
||
->bindValues(['kf_id' => $kfId])
|
||
->query();
|
||
|
||
echo '---客服下线---' . date("Y-m-d H:i:s") . '-->' . $kfId . PHP_EOL;
|
||
|
||
// 通知当前正在服务的用户
|
||
$res = self::$_db->select('client_id,user_id')
|
||
->from('ws_service_log')
|
||
->where('kf_id=:kf_id AND end_time=0')
|
||
->bindValues(['kf_id' => $kfId])
|
||
->query();
|
||
|
||
if (!empty($res)) {
|
||
foreach ($res as $item) {
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $item['client_id'],
|
||
'msg_type' => 'kf_offline',
|
||
'data' => [
|
||
'id' => $item['user_id'],
|
||
'kf_id' => $userInfo['uid'],
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
}
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
}
|
||
self::$_redis->hdel('kfList', $userInfo['uid']);
|
||
$this->setUserInfoByClientId($clientId, null);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 客服初始链接
|
||
* @param $data
|
||
* @param $ws
|
||
* @param $request
|
||
*/
|
||
public function init()
|
||
{
|
||
var_dump("客服初始化");
|
||
$userInfo = [
|
||
'type' => 'init',
|
||
'uid' => self::$_requestParam['user']['uid'],
|
||
'client_id' => self::$_requestParam['client_id'],
|
||
'name' => self::$_requestParam['user']['name'],
|
||
'avatar' => self::$_requestParam['user']['avatar'],
|
||
'sex' => self::$_requestParam['user']['sex'],
|
||
'ip' => self::$_requestParam['client_ip'],
|
||
'group_id' => self::$_requestParam['param']['group_id'],
|
||
'kf_type' => self::$_requestParam['user']['kf_type'],
|
||
];
|
||
$this->setUserInfoByClientId(self::$_requestParam['client_id'], $userInfo);
|
||
|
||
$kfId = $this->kf2Num(self::$_requestParam['user']['uid']);
|
||
|
||
// 检测是否重连
|
||
// self::checkRepetitionLine($userInfo['client_id'], $userInfo['uid'], 'kf');
|
||
|
||
self::$_db->update('ws_users')
|
||
->cols(['online' => '1'])
|
||
->where(" id=:kf_id ")
|
||
->bindValues(['kf_id' => $kfId])
|
||
->query();
|
||
|
||
// 通知当前正在服务的用户
|
||
$res = self::$_db->select('client_id,user_id,group_id')
|
||
->from('ws_service_log')
|
||
->where('kf_id=:kf_id AND end_time=0')
|
||
->bindValues(['kf_id' => $kfId])
|
||
->query();
|
||
|
||
if (!empty($res)) {
|
||
foreach ($res as $item) {
|
||
$member_info = self::$_redis->hget('users', "KF{$kfId}-{$item['user_id']}");
|
||
$member_info = !empty($member_info) ? json_decode($member_info, true) : [];
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $item['client_id'],
|
||
'msg_type' => 'kf_online',
|
||
'data' => [
|
||
'id' => $item['user_id'],
|
||
'kf_id' => self::$_requestParam['user']['uid'],
|
||
"common_words_map" => $this->_getCommonWords($kfId, $member_info['param'], $item['group_id']),
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
}
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
}
|
||
|
||
$kf = ['id' => $kfId, 'user_name' => self::$_requestParam['user']['name']];
|
||
$log = $this->_model->dataToDb($userInfo, $kf);
|
||
$log['service_num'] = 0;
|
||
$log['sex'] = self::$_requestParam['user']['sex'];
|
||
//将客服信息存储到redis
|
||
self::$_redis->hset('kfList', $log['user_id'], json_encode($log));
|
||
echo '---客服上线---' . date("Y-m-d H:i:s") . '-->' . $kfId . PHP_EOL;
|
||
}
|
||
|
||
|
||
/**
|
||
* 用户初始链接
|
||
* @param $data
|
||
* @param $ws
|
||
* @param $request
|
||
* @return bool
|
||
*/
|
||
public function userInit()
|
||
{
|
||
try {
|
||
var_dump("用户初始化");
|
||
$commonWords = [];
|
||
$commonKf = false;
|
||
if (empty(self::$_requestParam['param']['group_id'])) {
|
||
throw new ApiException(400, 'group_id不能为空');
|
||
}
|
||
$user_init = self::$_requestParam;
|
||
$user_info = self::$_requestParam['param'];
|
||
|
||
// 普通客服,随机分配
|
||
if (isset(self::$_requestParam['param']['kf_type']) && self::$_requestParam['param']['kf_type'] == 2) {
|
||
if (empty(self::$_requestParam['param']['kf_id'])) {
|
||
$kf = $this->getChatKf(self::$_requestParam['user']['uid'], self::$_requestParam['param']['group_id']);
|
||
$kfId = isset($kf['kf_id']) ? $kf['kf_id'] : $kf['id'];
|
||
} else {
|
||
$kf = $this->_model->getkfById(self::$_requestParam['param']['kf_id'], self::$_requestParam['param']['group_id'], 2);
|
||
if (empty($kf)) {
|
||
throw new ApiException(400, '不存在该客服');
|
||
}
|
||
$kfId = $kf['id'];
|
||
}
|
||
$commonKf = true;
|
||
} else {
|
||
//根据组与客服ID从数据库获取客服信息
|
||
$kf = $this->_model->getkfById(self::$_requestParam['param']['kf_id'], self::$_requestParam['param']['group_id'], 1);
|
||
if ($kf['online'] == 1) {
|
||
if (!isset($user_info['user_level'])) $user_info['user_level'] = '';
|
||
$commonWords = $this->_getCommonWords($kf['id'], $user_info, $kf['group_id']); // 获取用户的常用语
|
||
}
|
||
if (!$kf) {
|
||
throw new ApiException(400, '不存在该客服');
|
||
}
|
||
$kfId = $kf['id'];
|
||
}
|
||
|
||
// 存储用户信息
|
||
self::$_redis->hset('users', "KF{$kfId}-{$user_init['user']['uid']}", json_encode($user_init));
|
||
|
||
$checkBool = $this->_inBlacklist($kfId, self::$_requestParam['user']['uid'], $kf['group_id']);
|
||
if ($checkBool) {
|
||
throw new ApiException(400, '已在该客服黑名单');
|
||
}
|
||
|
||
// 检测是否是充值用户
|
||
$check_pay = self::$_db->from('ws_finish_recharge')->select('id')->where("uid = " . self::$_requestParam['user']['uid'] . " and kf_id = " . $kfId)->query();
|
||
|
||
|
||
$userInfo = [
|
||
'type' => 'userInit',
|
||
'uid' => self::$_requestParam['user']['uid'],
|
||
'name' => self::$_requestParam['user']['name'],
|
||
'avatar' => self::$_requestParam['user']['avatar'],
|
||
'group_id' => $kf['group_id'],
|
||
'kf_type' => $kf['kf_type'],
|
||
'data' => '',
|
||
'ip' => self::$_requestParam['client_ip'],
|
||
'client_id' => self::$_requestParam['client_id'],
|
||
'access_token' => self::$_requestParam['user']['access_token'],
|
||
'is_pay_user' => !empty($check_pay) ? true : false,
|
||
'offline_msg' => [],
|
||
];
|
||
|
||
// 存储用户信息
|
||
$this->setUserInfoByClientId(self::$_requestParam['client_id'], $userInfo);
|
||
|
||
// $kfId = $this->kf2Num(self::$_requestParam['param']['kf_id']);
|
||
|
||
// $saveData['kf_id'] = self::$_requestParam['param']['kf_id'];
|
||
// $saveData['user_info'] = json_encode($userInfo);
|
||
// self::$_redis->hmset("link_user_".self::$_requestParam['user']['uid'],$saveData);
|
||
|
||
//避免用户重复初始化
|
||
$res = self::$_db->select('id,client_id,end_time')->from('ws_service_log')
|
||
->where('user_id=:user_id AND kf_id=:kf_id')
|
||
->bindValues([
|
||
'user_id' => self::$_requestParam['user']['uid'],
|
||
'kf_id' => $kfId
|
||
])
|
||
->row();
|
||
if (empty($res)) {
|
||
//写入ws_service_log
|
||
if (isset($kf['kf_id'])) $kf['id'] = $kfId;
|
||
$log = $this->_model->dataToDb($userInfo, $kf);
|
||
self::$_db->insert('ws_service_log')
|
||
->cols($log)
|
||
->query();
|
||
$kfInfo = json_decode(self::$_redis->hget('kfList', 'KF' . $kfId), true);
|
||
if (self::$_redis->hexists('kfList', 'KF' . $kfId)) {
|
||
$kfInfo['service_num'] += 1;
|
||
self::$_redis->hset('kfList', 'KF' . $kfId, json_encode($kfInfo));
|
||
}
|
||
//记录今日连接数
|
||
if (!self::$_redis->exists('statistics_cli_' . date("Ymd") . '_' . $kf['group_id'])) {
|
||
$expireTime = mktime(23, 59, 59) - time(); //每天零点过期
|
||
self::$_redis->setex('statistics_cli_' . date("Ymd") . '_' . $kf['group_id'], $expireTime, 1);
|
||
} else {
|
||
self::$_redis->incr('statistics_cli_' . date("Ymd") . '_' . $kf['group_id']);
|
||
}
|
||
} else {
|
||
self::$_db->update('ws_service_log')
|
||
->cols(['end_time' => 0, 'start_time' => time(), 'client_id' => self::$_requestParam['client_id']])
|
||
->where('user_id=:user_id AND kf_id=:kf_id')
|
||
->bindValues([
|
||
'user_id' => self::$_requestParam['user']['uid'],
|
||
'kf_id' => $kfId
|
||
])
|
||
->query();
|
||
}
|
||
|
||
self::$_redis->sadd('user_set_' . $kf['group_id'] . '_KF' . $kfId, self::$_requestParam['user']['uid']);
|
||
|
||
if (!empty($res) && $res['end_time'] == 0) { } else {
|
||
//获取客服client_id
|
||
$kfClientId = json_decode(self::$_redis->hget('kfList', 'KF' . $kfId), true)['client_id'];
|
||
if ($kfClientId) {
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $kfClientId,
|
||
'msg_type' => 'connect',
|
||
'data' => [
|
||
"user_info" => [
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'name' => self::$_requestParam['user']['name'],
|
||
'avatar' => self::$_requestParam['user']['avatar'],
|
||
'data' => '',
|
||
'ip' => self::$_requestParam['client_ip'],
|
||
'group_id' => $kf['group_id'],
|
||
'is_pay_user' => !empty($check_pay) ? true : false,
|
||
'offline_msg' => [],
|
||
]
|
||
]
|
||
];
|
||
$toInfo = [
|
||
'to_name' => self::$_requestParam['user']['name'],
|
||
'to_id' => self::$_requestParam['user']['uid']
|
||
];
|
||
$initAutoTime = self::$_redis->get('inittime_' . $kfId . '_' . self::$_requestParam['user']['uid']);
|
||
if (time() - $initAutoTime > self::INIT_AUTO_TIME) {
|
||
// 客服自动回复
|
||
if (!$commonKf) {
|
||
$greetings = json_decode(self::$_redis->hget('greetings', $kfId), true);
|
||
// if($this->hasPayment($kfId)){
|
||
if ($greetings['status'] == 1) {
|
||
$sendData[] = $this->autoReply($kfClientId, '', $greetings['content'], $toInfo);
|
||
}
|
||
// }
|
||
} else {
|
||
$greetings = json_decode(self::$_redis->hget('greetings', $kfId), true);
|
||
if ($greetings['status'] == 1) {
|
||
$sendData[] = $this->autoReply($kfClientId, '', $greetings['content'], $toInfo);
|
||
}
|
||
}
|
||
}
|
||
|
||
$kfInfo = json_decode(self::$_redis->hget('kfList', 'KF' . $kfId), true);
|
||
$kfInfo['service_num'] += 1;
|
||
self::$_redis->hset('kfList', 'KF' . $kfId, json_encode($kfInfo));
|
||
}
|
||
}
|
||
|
||
//分配链接客服信息
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'connect',
|
||
'data' => [
|
||
"kf_id" => "KF{$kfId}",
|
||
"kf_name" => $kf['user_name'],
|
||
"kf_avatar" => $kf['user_avatar'],
|
||
"is_online" => $kf['online'], // 1 在线;2 离线
|
||
"common_words_map" => $commonWords
|
||
]
|
||
];
|
||
self::$_redis->setex('inittime_' . $kfId . '_' . self::$_requestParam['user']['uid'], self::INIT_AUTO_TIME, time());
|
||
// // 重复初始化时,将旧的连接挤下去
|
||
// if(!empty($res) && $res['client_id'] != self::$_requestParam['client_ip']){
|
||
// Gateway::closeClient($res['client_id']);
|
||
// }
|
||
|
||
} catch (ApiException $e) {
|
||
// $errorCode = $e->getCode();
|
||
// $errorMsg = $e->getMessage();
|
||
throw new ApiException($e->getCode(), $e->getMessage());
|
||
}
|
||
|
||
$this->sendMessage(
|
||
empty($errorCode) ? 200 : $errorCode,
|
||
empty($errorMsg) ? 'ok' : $errorMsg,
|
||
empty($sendData) ? '' : $sendData
|
||
);
|
||
|
||
|
||
// // 记录日志.
|
||
// Log::instance('user_' . $clientIp)->addInfo(json_encode([
|
||
// 'responseMsg' => [
|
||
// 'code' => empty($errorCode) ? 200 : $errorCode,
|
||
// 'message' => empty($errorMsg) ? 'ok' : $errorMsg,
|
||
// 'data' => $sendData
|
||
// ]
|
||
// ], JSON_UNESCAPED_UNICODE));
|
||
}
|
||
|
||
|
||
/**
|
||
* 收到消息后发送回执信息
|
||
*/
|
||
public function sendReceiptMsg()
|
||
{
|
||
try {
|
||
|
||
if (empty(self::$_requestParam['param']['msg_id'])) {
|
||
throw new ApiException(400, '消息ID不能为空');
|
||
}
|
||
$clientId = self::$_redis->get(self::$_requestParam['param']['msg_id']);
|
||
self::$_redis->del(self::$_requestParam['param']['msg_id']);
|
||
if($clientId){
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $clientId,
|
||
'msg_type' => 'received',
|
||
'data' => [
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'to_uid_is_online' => 1, // 在线
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
}else{
|
||
echo "延时已超过60s".PHP_EOL;
|
||
}
|
||
} catch (ApiException $e) {
|
||
throw new ApiException($e->getCode(), $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 客户端提交信息处理(用户与客服)
|
||
* @param $data
|
||
* @param $ws
|
||
* @param $request
|
||
*/
|
||
public function chat()
|
||
{
|
||
try {
|
||
$content = self::$_requestParam['param']['content'];
|
||
$content = htmlentities($content);
|
||
$contentType = empty(self::$_requestParam['param']['content_type']) ? "" : self::$_requestParam['param']['content_type'];
|
||
$kfType = '';
|
||
|
||
if (empty(self::$_requestParam['param']['to_id'])) {
|
||
throw new ApiException(400, '参数错误');
|
||
}
|
||
if (empty(self::$_requestParam['param']['msg_id'])) {
|
||
throw new ApiException(400, 'msg_id不能为空');
|
||
}
|
||
if (empty(self::$_requestParam['user']['group_id'])) {
|
||
throw new ApiException(400, '平台ID不能为空');
|
||
}
|
||
|
||
if (self::$_requestParam['param']['type'] == 'user') {
|
||
if ($contentType == 'img') {
|
||
if(strpos(self::$_requestParam['param']['content'],'[') === 0){
|
||
global $configFile;
|
||
$str = "img[" . $configFile['site_url'];
|
||
$content = str_replace("[", $str, self::$_requestParam['param']['content']);
|
||
}else{
|
||
$url = $this->base64ToImg(self::$_requestParam['param']['content']);
|
||
$content = "img[$url]";
|
||
}
|
||
} else {
|
||
$content = str_replace("[", "face[", $content);
|
||
$content = $this->filterEmoji($content);
|
||
}
|
||
$userId = self::$_requestParam['user']['uid'];
|
||
$kfId = self::$_requestParam['param']['to_id'];
|
||
|
||
$checkBool = $this->_inBlacklist($kfId, self::$_requestParam['user']['uid'], self::$_requestParam['user']['group_id']);
|
||
if ($checkBool) {
|
||
throw new ApiException(400, '已在该客服黑名单');
|
||
}
|
||
} else {
|
||
if (strpos($content, "img[/") === 0) {
|
||
global $configFile;
|
||
// $oldUrl = $content;
|
||
$content = substr_replace($content, $configFile['site_url'], 4, 0);
|
||
}
|
||
$userId = self::$_requestParam['param']['to_id'];
|
||
$kfId = self::$_requestParam['user']['uid'];
|
||
}
|
||
|
||
// $addData['to_id'] = "KF3";
|
||
$addData['to_id'] = self::$_requestParam['param']['to_id'];
|
||
$addData['to_name'] = self::$_requestParam['param']['to_name'];
|
||
$addData['content'] = $content;
|
||
$addData['from_id'] = self::$_requestParam['user']['uid'];
|
||
$addData['from_name'] = self::$_requestParam['user']['name'];
|
||
$addData['from_avatar'] = self::$_requestParam['user']['avatar'];
|
||
$addData['time_line'] = time();
|
||
$addData['msg_id'] = self::$_requestParam['param']['msg_id'];
|
||
|
||
|
||
$offlineType = 'user';
|
||
if (self::$_requestParam['param']['type'] === 'user') {
|
||
$offlineType = 'kf';
|
||
} else {
|
||
$kfType = json_decode(self::$_redis->hget('kfList', self::$_requestParam['user']['uid']), true)['kf_type'];
|
||
}
|
||
|
||
if (!$this->isKfOnline($kfId)) {
|
||
echo "开始记录离线消息: " . self::$_requestParam['user']['uid'] . '-->' . $kfId . PHP_EOL;
|
||
// self::$_db->insert('ws_offline_msg')->cols($addData)->query();
|
||
$allOffmsg = json_decode(self::$_redis->hget('offmsg_' . $kfId, $userId),true);
|
||
|
||
if($allOffmsg !== null && count($allOffmsg) > 100){
|
||
array_splice($allOffmsg, 0, count($allOffmsg) - 100);
|
||
}
|
||
$allOffmsg[] = $addData;
|
||
self::$_redis->hset('offmsg_' . $kfId, $userId, json_encode($allOffmsg));
|
||
$addData['is_offline_msg'] = 1;
|
||
}
|
||
|
||
// self::$_redis->hset('link_user_'.$userId,'chat_log',json_encode($addData));
|
||
$table = $this->getTableName('ws_chat_log', $userId);
|
||
self::$_db->insert($table)
|
||
->cols($addData)
|
||
->query();
|
||
// self::$_db->insert('ws_chat_log')
|
||
// ->cols($addData)
|
||
// ->query();
|
||
|
||
//获取用户当前服务的客服
|
||
$link = $this->_model->getUidLinks(self::$_requestParam['param']['to_id'], self::$_requestParam['param']['type'], self::$_requestParam['user']['group_id'], $kfType);
|
||
if (self::$_requestParam['param']['type'] == 'kf') {
|
||
$sayType = $this->_checkContent($content);
|
||
if (!empty(self::$_requestParam['param']['payment'])) {
|
||
$paymentType = self::$_requestParam['param']['payment'];
|
||
}
|
||
|
||
$content = str_replace("face[", "[", $content);
|
||
|
||
if (strpos($content, "img[") === 0) {
|
||
$content = str_replace("]", "", str_replace("img[", "", $content));
|
||
if(!empty($content)) {
|
||
$imgSize = getimagesize($content);
|
||
// $oldUrl = str_replace("]", "", str_replace("img[", "", $oldUrl));
|
||
// $relativeUrl = dirname(dirname(dirname(dirname(dirname(__FILE__))))).'/public/'.$oldUrl;
|
||
}
|
||
|
||
}
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $link['client_id'],
|
||
'msg_type' => $sayType,
|
||
'is_resend' => 1,
|
||
'data' => [
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'name' => self::$_requestParam['user']['name'],
|
||
'avatar' => self::$_requestParam['user']['avatar'],
|
||
'img_type' => empty($paymentType) ? "" : $paymentType,
|
||
'img_width' => empty($imgSize[0]) ? "" : $imgSize[0],
|
||
'img_height' => empty($imgSize[1]) ? "" : $imgSize[1],
|
||
'content' => $content,
|
||
'data' => isset(self::$_requestParam['param']['data']) ? self::$_requestParam['param']['data'] : '',
|
||
'time' => date('Y-m-d H:i:s'),
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
'kf_type' => $kfType
|
||
]
|
||
];
|
||
self::$_redis->setex(self::$_requestParam['param']['msg_id'], 60, self::$_requestParam['client_id']);
|
||
// 用户不在线时推送给游戏提示
|
||
$toUidIsOnline = $this->isUserOnlineToKf($kfId, self::$_requestParam['user']['group_id'], $userId);
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'server_received',
|
||
'data' => [
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
'id' => self::$_requestParam['param']['to_id'],
|
||
'to_uid_is_online' => 1,
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
if (!$toUidIsOnline) {
|
||
$fflineMsg = $sendData[0];
|
||
unset($sendData[0]);
|
||
$kfInfo = json_decode(self::$_redis->hget('kfList', self::$_requestParam['user']['uid']), true);
|
||
if (!empty($kfInfo['kf_type']) && $kfInfo['kf_type'] == 2) {
|
||
$fflineMsg['data']['kf_type'] = 2;
|
||
}
|
||
$api = '/api/Customer/PushOfflineMsg';
|
||
echo "推送消息给离线用户: " . self::$_requestParam['user']['uid'] . '-->' . self::$_requestParam['param']['to_id'] . PHP_EOL;
|
||
$taskData = [
|
||
'method' => 'pushOfflineMsg',
|
||
'params' => [
|
||
'api' => $api,
|
||
'to_id' => self::$_requestParam['param']['to_id']
|
||
],
|
||
'data' => $fflineMsg
|
||
];
|
||
Gateway::sendByTask($taskData);
|
||
}
|
||
} else {
|
||
$toUidIsOnline = $this->isKfOnline(self::$_requestParam['param']['to_id']);
|
||
$sayType = $this->_checkContent($content);
|
||
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $link['client_id'],
|
||
'msg_type' => $sayType,
|
||
'data' => [
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'name' => self::$_requestParam['user']['name'],
|
||
'avatar' => self::$_requestParam['user']['avatar'],
|
||
'content' => $content,
|
||
'data' => isset(self::$_requestParam['user']['data']) ? self::$_requestParam['user']['data'] : '',
|
||
'time' => date('Y-m-d H:i:s'),
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
]
|
||
];
|
||
self::$_redis->setex(self::$_requestParam['param']['msg_id'], 30, self::$_requestParam['client_id']);
|
||
|
||
// 充值类客服才检测充值信息
|
||
if ($link['kf_type'] === 1) {
|
||
$paymentTypeId = $this->_checkCanReply($content);
|
||
}
|
||
if (!empty($paymentTypeId)) {
|
||
$payInfo = self::$_db->select("name,account_num,payment_img,open_bank,branch_bank")->from('ws_payment')
|
||
->where('payment_type=:payment_type AND kf_id=:kf_id AND is_use=1 AND status=1')
|
||
->bindValues(['payment_type' => $paymentTypeId, 'kf_id' => $this->kf2Num(self::$_requestParam['param']['to_id'])])
|
||
->row();
|
||
if (empty($payInfo)) {
|
||
$toInfo = [
|
||
'to_name' => self::$_requestParam['user']['name'],
|
||
'to_id' => self::$_requestParam['user']['uid']
|
||
];
|
||
|
||
$replyData = $this->autoReply($link['client_id'], '', "抱歉~ 当前暂不支持此支付方式", $toInfo);
|
||
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'received',
|
||
'data' => [
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
array_push($sendData, $replyData);
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
|
||
return false;
|
||
}
|
||
$qrcode = $payInfo['payment_img'];
|
||
$toInfo = [
|
||
'to_name' => self::$_requestParam['user']['name'],
|
||
'to_id' => self::$_requestParam['user']['uid']
|
||
];
|
||
// 客服自动回复
|
||
$sendData[] = $this->autoReply($link['client_id'], $content, "img[$qrcode]", $toInfo, $payInfo);
|
||
$sendData[] = $this->autoReply($link['client_id'], $content, self::WORD_TIP3, $toInfo);
|
||
}
|
||
}
|
||
|
||
if (!$toUidIsOnline) { //发送对象不在线则不等回执消息,直接推
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'received',
|
||
'data' => [
|
||
'msg_id' => self::$_requestParam['param']['msg_id'],
|
||
'id' => self::$_requestParam['user']['uid'],
|
||
'to_uid_is_online' => 2,
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
}
|
||
} catch (ApiException $e) {
|
||
// $errorCode = $e->getCode();
|
||
// $errorMsg = $e->getMessage();
|
||
throw new ApiException($e->getCode(), $e->getMessage());
|
||
}
|
||
|
||
$this->sendMessage(
|
||
empty($errorCode) ? 200 : $errorCode,
|
||
empty($errorMsg) ? 'ok' : $errorMsg,
|
||
empty($sendData) ? '' : $sendData
|
||
);
|
||
}
|
||
|
||
|
||
/**
|
||
* 检测是否有重连
|
||
* @return [type] [description]
|
||
*/
|
||
public function checkRepetitionLine()
|
||
{
|
||
$uid = self::$_requestParam['user']['uid'];
|
||
$cid = self::$_requestParam['client_id'];
|
||
|
||
// 检测是否在线
|
||
$check = self::isKfOnline($uid);
|
||
// 发送占线消息
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $cid,
|
||
'msg_type' => 'login_check',
|
||
'data' => [
|
||
'uid' => $uid,
|
||
'result' => $check,
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
}
|
||
|
||
|
||
/**
|
||
* 关闭是否有重复连接
|
||
* @param [type] $cid [description] 服务标识id
|
||
* @param [type] $uid [description] 用户id
|
||
* @param string $type [description] 类型: user:用户, kf:客服
|
||
* @return [type] [description]
|
||
*/
|
||
public function closeRepetitionLine()
|
||
{
|
||
$uid = self::$_requestParam['user']['uid'];
|
||
$cid = self::$_requestParam['client_id'];
|
||
$type = self::$_requestParam['param']['type'];
|
||
// 检测是否在线
|
||
$kf = json_decode(self::$_redis->hget('kfList', $uid), true);
|
||
|
||
if (!$kf) return false;
|
||
// 发送占线消息, 并下线
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $kf['client_id'],
|
||
'msg_type' => 'repetition_line',
|
||
'data' => [
|
||
'uid' => $uid,
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
// 关闭服务连接
|
||
Gateway::closeClient($cid);
|
||
Gateway::closeClient($kf['client_id']);
|
||
}
|
||
|
||
/**
|
||
* 切换客服组
|
||
*
|
||
*/
|
||
public function changeGroup()
|
||
{
|
||
|
||
//分配客服
|
||
$kf = $this->getRandCommonKf(self::$_requestParam['user']['group_id']);
|
||
$user = self::$_requestParam['param']['user_id'];
|
||
// 如果没有在线客服,则提示客户端
|
||
if (!$kf) {
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'changeGroupResult',
|
||
'data' => ['status' => false, 'content' => '暂无可转接客服~']
|
||
];
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
return false;
|
||
}
|
||
|
||
self::$_db->update('ws_service_log')
|
||
->cols(['group_id' => $kf['group_id'], 'kf_id' => $kf['kf_id']])
|
||
->where(" user_id=:user_id ")
|
||
->bindValues(['user_id' => self::$_requestParam['param']['user_id']])
|
||
->query();
|
||
|
||
echo '---切换后的客服信息---start' . PHP_EOL;
|
||
var_dump($kf);
|
||
echo '---切换后的客服信息---end' . PHP_EOL;
|
||
|
||
//根据用户获取当前链接列表
|
||
$link = $this->_model->getUidLinks(self::$_requestParam['param']['user_id'], 'kf', self::$_requestParam['user']['group_id'], 2);
|
||
|
||
//推送给原客服
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => self::$_requestParam['client_id'],
|
||
'msg_type' => 'changeGroupResult',
|
||
'data' => ['status' => true, 'content' => '转接成功']
|
||
];
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
|
||
//推送给新客服
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $kf['client_id'],
|
||
'msg_type' => 'connect',
|
||
'data' => [
|
||
"user_info" => [
|
||
'id' => self::$_requestParam['param']['user_id'],
|
||
'name' => self::$_requestParam['param']['user_name'],
|
||
'avatar' => self::$_requestParam['param']['avatar'],
|
||
'group_id' => self::$_requestParam['user']['group_id'],
|
||
'data' => $link['data'],
|
||
'ip' => self::$_requestParam['client_ip']
|
||
],
|
||
]
|
||
];
|
||
|
||
// 推送被转接用户建立新连接
|
||
$sendData[] = [
|
||
'type' => 'single',
|
||
'target' => $link['client_id'],
|
||
'msg_type' => 'connect',
|
||
'data' => [
|
||
'kf_id' => $kf['user_id'],
|
||
'kf_name' => $kf['user_name'],
|
||
"kf_avatar" => $kf['user_avatar'],
|
||
"is_online" => 1, // 1 在线;2 离线
|
||
"common_words_map" => []
|
||
]
|
||
];
|
||
$this->sendMessage(200, 'ok', $sendData);
|
||
}
|
||
|
||
|
||
/**
|
||
* 随机分配在线普通客服
|
||
*/
|
||
private function getRandCommonKf($groupId)
|
||
{
|
||
|
||
$allOnlineKf = self::$_redis->hgetall('kfList');
|
||
$tmpArr = [];
|
||
|
||
foreach ($allOnlineKf as $item) {
|
||
$item = json_decode($item, true);
|
||
if ($item['kf_type'] == 2 && $item['group_id'] == $groupId) {
|
||
$tmpArr[] = $item['kf_id'];
|
||
}
|
||
}
|
||
if (!empty($tmpArr)) {
|
||
$randKfId = $tmpArr[array_rand($tmpArr)];
|
||
$kf = json_decode($allOnlineKf['KF' . $randKfId], true);
|
||
}
|
||
|
||
if (!empty($kf)) {
|
||
$kf['online'] = 1;
|
||
return $kf;
|
||
}
|
||
return;
|
||
|
||
// foreach ($allOnlineKf as $item) {
|
||
// $item = json_decode($item,true);
|
||
// if($item['kf_type'] == 2 && $item['group_id'] == $groupId && ($kfConfig['max_service'] == 0 || $item['service_num'] <= $kfConfig['max_service'])){
|
||
// $tmpArr[$item['service_num']] = $item['kf_id'];
|
||
// }
|
||
// }
|
||
// if(!empty($tmpArr)){
|
||
// ksort($tmpArr);
|
||
// $kf = json_decode($allOnlineKf['KF'.current($tmpArr)],true);
|
||
// }
|
||
}
|
||
|
||
/**
|
||
* 分配聊天客服
|
||
*/
|
||
private function getChatKf($uid, $groupId)
|
||
{
|
||
$allLinkKf = self::$_db->select('kf_id,end_time')->from('ws_service_log')
|
||
->where('user_id=:user_id AND group_id=:group_id AND kf_type=2')
|
||
->bindValues(['user_id' => $uid, 'group_id' => $groupId])
|
||
->query();
|
||
|
||
if (!empty($allLinkKf)) {
|
||
array_multisort(array_column($allLinkKf, 'end_time'), SORT_DESC, $allLinkKf);
|
||
$kfId = $allLinkKf[0]['kf_id'];
|
||
$kf = json_decode(self::$_redis->hget('kfList', 'KF' . $kfId), true);
|
||
if (!empty($kf)) $kf['online'] = 1;
|
||
}
|
||
|
||
// 最近聊过的客服不在线
|
||
if (empty($kf)) {
|
||
// 随机选个在线
|
||
$kf = $this->getRandCommonKf($groupId);
|
||
|
||
// 一个在线的也没有
|
||
if (empty($kf)) {
|
||
if (isset($kfId)) {
|
||
$kf = self::$_db->select('id,user_name,user_avatar,kf_type,group_id')->from("ws_users")
|
||
->where('group_id=:group_id AND status=1 AND kf_type=2 AND id=:id')
|
||
->bindValues(['group_id' => $groupId, 'id' => $kfId])
|
||
->row();
|
||
}
|
||
|
||
//从未联系过客服的新玩家或以前联系过的客服被禁用了
|
||
if (empty($kf)) {
|
||
$kf = self::$_db->select('id,user_name,user_avatar,kf_type,group_id')->from("ws_users")
|
||
->where('group_id=:group_id AND status=1 AND kf_type=2')
|
||
->bindValues(['group_id' => $groupId])
|
||
->row();
|
||
}
|
||
if (empty($kf)) throw new ApiException(400, '抱歉,暂无客服服务.');
|
||
$kf['online'] = 2;
|
||
}
|
||
}
|
||
|
||
return $kf;
|
||
}
|
||
|
||
/**
|
||
* 查看用户是否在线
|
||
*/
|
||
private function isKfOnline($kfId)
|
||
{
|
||
if (is_numeric($kfId)) $kfId = 'KF' . $kfId;
|
||
return self::$_redis->hexists('kfList', $kfId);
|
||
}
|
||
|
||
/**
|
||
* 查看客服对应的用户是否在线
|
||
*/
|
||
private function isUserOnlineToKf($kfId, $groupId, $uid)
|
||
{
|
||
if (is_numeric($kfId)) $kfId = 'KF' . $kfId;
|
||
return self::$_redis->sismember('user_set_' . $groupId . '_' . $kfId, $uid);
|
||
}
|
||
|
||
|
||
/**
|
||
* 检测是否是表情图片等
|
||
*/
|
||
private function _checkContent($content)
|
||
{
|
||
$content = trim($content);
|
||
if (strpos($content, 'img[') === 0) {
|
||
return "img";
|
||
}
|
||
|
||
return "text";
|
||
}
|
||
|
||
private function base64EncodeImage($image_file)
|
||
{
|
||
$imageInfo = getimagesize($image_file);
|
||
$base64 = "" . chunk_split(base64_encode(file_get_contents($image_file)));
|
||
return $base64;
|
||
}
|
||
|
||
/**
|
||
* 检查聊天内容,是否触发自动回复
|
||
*/
|
||
private function _checkCanReply($content)
|
||
{
|
||
$res = $this->_getAllPaymentType();
|
||
foreach ($res as $item) {
|
||
if ($content == $item['type_name']) return $item['id'];
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 获取用户那显示的常用语
|
||
*/
|
||
private function _getCommonWords($kfId, $member = [], $group_id = 0)
|
||
{
|
||
|
||
$status = true;
|
||
// 处理透传
|
||
if ($member['data'] != '') {
|
||
$param = json_decode($member['data'], true);
|
||
if (isset($param['user_level'])) $member['user_level'] = $param['user_level'];
|
||
$member['phone_mobel'] = isset($param['phone_mobel']) ? $param['phone_mobel'] : '';
|
||
$member['client_version'] = isset($param['client_version']) ? $param['client_version'] : '';
|
||
if (!$member['phone_mobel'] || !$member['client_version']) $status = false;
|
||
} else {
|
||
$status = false;
|
||
}
|
||
|
||
if (isset($member['user_level']) && $member['user_level'] !== '') {
|
||
$pay_type = self::$_db->row("SELECT * FROM `ws_member_level` WHERE level = {$member['user_level']} AND group_id = {$group_id}");
|
||
if ($pay_type && isset($pay_type['rules']) && $pay_type['rules']) {
|
||
$res = self::$_db->query("SELECT ws_payment_type.id,ws_payment_type.type_name,ws_payment_type.alias_id FROM `ws_payment` INNER JOIN `ws_payment_type` ON `ws_payment`.`payment_type`=`ws_payment_type`.`id` WHERE `ws_payment`.`kf_id`={$kfId} AND `ws_payment`.`status`=1 AND `ws_payment`.`is_use`=1 AND `ws_payment_type`.`id` IN ({$pay_type['rules']})");
|
||
} else {
|
||
// $res = self::$_db->query("SELECT ws_payment_type.id,ws_payment_type.type_name,ws_payment_type.alias_id FROM `ws_payment` INNER JOIN `ws_payment_type` ON `ws_payment`.`payment_type`=`ws_payment_type`.`id` WHERE `ws_payment`.`kf_id`={$kfId} AND `ws_payment`.`status`=1 AND `ws_payment`.`is_use`=1");
|
||
$res = [];
|
||
}
|
||
} else {
|
||
$res = self::$_db->query("SELECT ws_payment_type.id,ws_payment_type.type_name,ws_payment_type.alias_id FROM `ws_payment` INNER JOIN `ws_payment_type` ON `ws_payment`.`payment_type`=`ws_payment_type`.`id` WHERE `ws_payment`.`kf_id`={$kfId} AND `ws_payment`.`status`=1 AND `ws_payment`.`is_use`=1");
|
||
}
|
||
|
||
// 如果如果是老版本sdk将不显示新的支付类型
|
||
if ($status === true) {
|
||
$check_version = $member['phone_mobel'] == 'ios' ? version_compare($member['client_version'], '1.0.1', '<') : version_compare($member['client_version'], '1.1.4', '<');
|
||
}
|
||
if ($status == false || (isset($check_version) && $check_version)) {
|
||
foreach($res as $k => $v) {
|
||
if ($v['alias_id'] == 'baitiao' || $v['alias_id'] == 'cloud_pay') {
|
||
unset($res[$k]);
|
||
}
|
||
}
|
||
$res = array_values($res);
|
||
}
|
||
|
||
return $res;
|
||
}
|
||
|
||
/**
|
||
* 获取所有支付类型
|
||
*/
|
||
private function _getAllPaymentType()
|
||
{
|
||
$payment = json_decode(self::$_redis->get('payment'), true);
|
||
if (empty($payment)) {
|
||
$payment = self::$_db->select('id,alias_id,type_name')->from('ws_payment_type')
|
||
->where('status=1')
|
||
->query();
|
||
self::$_redis->set('payment', json_encode($payment));
|
||
}
|
||
|
||
return $payment;
|
||
}
|
||
|
||
/**
|
||
* 自动回复
|
||
*/
|
||
private function autoReply($clientId, $content, $msg, $toInfo, $payInfo = '')
|
||
{
|
||
$paymentType = "";
|
||
if (!empty($content) && strpos($msg, "img[") === 0) {
|
||
$payment = $this->_getAllPaymentType();
|
||
foreach ($payment as $key => $value) {
|
||
if ($content == $value['type_name']) {
|
||
$paymentType = $value['alias_id'];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
$sendData = [
|
||
'type' => 'single',
|
||
'target' => $clientId,
|
||
'msg_type' => 'auto_reply',
|
||
'data' => [
|
||
'content' => $msg,
|
||
'payment' => $paymentType,
|
||
'data' => [
|
||
'name' => empty($payInfo['name']) ? "" : $payInfo['name'],
|
||
'account_num' => empty($payInfo['account_num']) ? "" : $payInfo['account_num'],
|
||
'open_bank' => empty($payInfo['open_bank']) ? "" : $payInfo['open_bank'],
|
||
'branch_bank' => empty($payInfo['branch_bank']) ? "" : $payInfo['branch_bank'],
|
||
'to_id' => $toInfo['to_id'],
|
||
'to_name' => $toInfo['to_name'],
|
||
],
|
||
'time' => date('Y-m-d H:i:s'),
|
||
]
|
||
];
|
||
|
||
return $sendData;
|
||
}
|
||
|
||
/**
|
||
* 根据用户连接号设置用户信息
|
||
* @param $fd
|
||
* @param $data
|
||
* @return mixed
|
||
*/
|
||
public function setUserInfoByClientId($fd, $data)
|
||
{
|
||
if (empty($fd)) return false;
|
||
if (empty($data)) {
|
||
self::$_redis->hdel('fd', $fd);
|
||
|
||
self::$_db->update('ws_service_log')->cols(array('end_time' => time()))
|
||
->where("client_id={$fd} and end_time = 0")->query();
|
||
return false;
|
||
}
|
||
self::$_redis->hset('fd', $fd, json_encode($data));
|
||
}
|
||
|
||
|
||
private function kf2Num($kfId)
|
||
{
|
||
if (!is_numeric($kfId) && strpos($kfId, 'KF') === 0) {
|
||
$kfId = substr($kfId, 2);
|
||
}
|
||
return $kfId;
|
||
}
|
||
|
||
/**
|
||
* 查看充值客服是否拥有支付账号
|
||
*/
|
||
private function hasPayment($kfId)
|
||
{
|
||
$res = self::$_db->select('id')->from('ws_payment')
|
||
->where(['kf_id=:kf_id AND is_use=1 AND status=1'])
|
||
->bindValues(['kf_id' => $kfId])
|
||
->row();
|
||
if ($res) return true;
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 检测黑名单
|
||
*/
|
||
private function _inBlacklist($kfId, $uid, $group)
|
||
{
|
||
$kfId = $this->kf2Num($kfId);
|
||
$blacklist = json_decode(self::$_redis->hget('blacklist_' . $group, $kfId), true);
|
||
if (!empty($blacklist)) {
|
||
$blacklist = array_keys($blacklist);
|
||
if (in_array($uid, $blacklist)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
} |