_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'].')'; } } if (!$where) { return []; } $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; } }