kefu/server/modules/api/controller/ChatLogic.php

1118 lines
44 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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']);
$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'),
]
];
echo '---客服下线 推送下线通知: 用户 ==> '.$item['user_id'].',client_id ==> '.$item['client_id'].'---' . PHP_EOL;
}
$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')
->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_online',
'data' => [
'id' => $item['user_id'],
'kf_id' => self::$_requestParam['user']['uid'],
"common_words_map" => $this->_getCommonWords($kfId),
'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不能为空');
}
// 普通客服,随机分配
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) {
$user_level = null;
if (isset(self::$_requestParam['param']['user_level'])) $user_level = self::$_requestParam['param']['user_level'];
$commonWords = $this->_getCommonWords($kf['id'], $user_level, self::$_requestParam['param']['group_id']); // 获取用户的常用语
}
if (!$kf) {
throw new ApiException(400, '不存在该客服');
}
$kfId = $kf['id'];
}
$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 {
$cols = [
'end_time' => 0,
'start_time' => time(),
'client_id' => self::$_requestParam['client_id'],
'user_ip' => self::$_requestParam['client_ip']
];
self::$_db->update('ws_service_log')
->cols($cols)
->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 = htmlspecialchars(self::$_requestParam['param']['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 {
// 查看 是否在白名单中
$ip = self::$_requestParam['client_ip'];
$white_list = json_decode(self::$_redis->hget('white_list', self::$_requestParam['user']['group_id']), true);
if ($white_list && !in_array($ip, $white_list)) {
throw new ApiException(400, '该客服ip不在白名单中,ip='.$ip);
}
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, $user_level = null, $groupId = null)
{
$where = '';
if ($user_level !== null && $groupId !== null) {
$pay_type = self::$_db->select('rules')->from('ws_member_level')
->where('level=:level AND group_id=:group_id')
->bindValues([
'level' => $user_level,
'group_id' => $groupId
])
->row();
if ($pay_type && isset($pay_type['rules']) && $pay_type['rules']) {
$where = ' AND ws_payment_type.id IN('.$pay_type['rules'].')';
}
}
$sql = "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".$where;
$res = self::$_db->query($sql);
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;
}
}