|
@@ -55,7 +55,21 @@ class Events
|
|
|
self::$global = self::$logic->getGlbData();
|
|
self::$global = self::$logic->getGlbData();
|
|
|
|
|
|
|
|
self::TimerThing($worker);
|
|
self::TimerThing($worker);
|
|
|
|
|
+ // 管理员实时监控.
|
|
|
|
|
+ /*Timer::add(6, function () {
|
|
|
|
|
+ // 获取在线管理员总数.
|
|
|
|
|
+ $adminListCount = self::$redis->lLen('adminList');
|
|
|
|
|
+ // 获取在线管理员
|
|
|
|
|
+ $adminList = self::$redis->lrange('adminList', 0, $adminListCount);
|
|
|
|
|
+ if ($adminList) {
|
|
|
|
|
+ self::systemMonitoring($adminList);
|
|
|
|
|
+ }
|
|
|
|
|
+ });*/
|
|
|
|
|
|
|
|
|
|
+ // 检查对话时效给出.
|
|
|
|
|
+ Timer::add(6, function () {
|
|
|
|
|
+ self::overTime();
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -147,7 +161,9 @@ class Events
|
|
|
$tmp_id = isset($message['data']['id']) ? $message['data']['id'] : 0;
|
|
$tmp_id = isset($message['data']['id']) ? $message['data']['id'] : 0;
|
|
|
self::kfgetuserinfo($client_id, intval($tmp_id));
|
|
self::kfgetuserinfo($client_id, intval($tmp_id));
|
|
|
break;
|
|
break;
|
|
|
|
|
+ // 客服聊天
|
|
|
case 'chatMessage':
|
|
case 'chatMessage':
|
|
|
|
|
+ self::chatMessage($message['data']);
|
|
|
break;
|
|
break;
|
|
|
// 转接
|
|
// 转接
|
|
|
case 'changeGroup':
|
|
case 'changeGroup':
|
|
@@ -178,6 +194,47 @@ class Events
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ //客服聊天
|
|
|
|
|
+ public static function chatMessage($message)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 获取当前会话工单.
|
|
|
|
|
+ $data = json_decode(self::$redis->HGET('SERVICELOG',$message['conversationId']), true);
|
|
|
|
|
+ $chat_message = [
|
|
|
|
|
+ 'message_type' => 'chatMessage',
|
|
|
|
|
+ 'data' => [
|
|
|
|
|
+ 'name' => $message['from_name'],
|
|
|
|
|
+ 'id' => $message['from_id'],
|
|
|
|
|
+ 'time' => date('H:i'),
|
|
|
|
|
+ 'content' => $message['content'],
|
|
|
|
|
+ ]
|
|
|
|
|
+ ];
|
|
|
|
|
+ if (isset($message['isFirst']) && $message['isFirst']) {
|
|
|
|
|
+ $data['alarm_corresponding'] = time() - $data['start_time'];
|
|
|
|
|
+ }
|
|
|
|
|
+ // 发送消息.
|
|
|
|
|
+ if (substr($message['from_id'],0,2) === 'KF') {
|
|
|
|
|
+ $data['userLastTime'] = time();
|
|
|
|
|
+ Gateway::sendToClient($data['client_id'], json_encode($chat_message));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $data['serverLastTime'] = time();
|
|
|
|
|
+ Gateway::sendToClient($data['kf_client_id'], json_encode($chat_message));
|
|
|
|
|
+ }
|
|
|
|
|
+ // 保存修改后的工单信息.
|
|
|
|
|
+ $redis->HSET('SERVICELOG', $message['conversationId'], $data);
|
|
|
|
|
+
|
|
|
|
|
+ // 聊天信息入库
|
|
|
|
|
+ $insertChatData = [
|
|
|
|
|
+ 'from_id' => $message['data']['from_id'],
|
|
|
|
|
+ 'from_name' => $message['data']['from_name'],
|
|
|
|
|
+ 'to_id' => $message['data']['to_id'],
|
|
|
|
|
+ 'to_name' => $message['data']['to_name'],
|
|
|
|
|
+ 'content' => $message['data']['content'],
|
|
|
|
|
+ 'servicelog_id' => $message['data']['conversationId'],
|
|
|
|
|
+ 'time_line' => time()
|
|
|
|
|
+ ];
|
|
|
|
|
+ self::$db->insert('ws_chat_log')->cols($insertChatData)->query();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
//得到一个用户详细信息
|
|
//得到一个用户详细信息
|
|
|
public static function kfgetuserinfo($clientid, $id)
|
|
public static function kfgetuserinfo($clientid, $id)
|
|
|
{
|
|
{
|
|
@@ -328,13 +385,15 @@ class Events
|
|
|
{
|
|
{
|
|
|
// 查询token是否存在.
|
|
// 查询token是否存在.
|
|
|
$systemConfigData = self::$db->query("SELECT `id` FROM `ws_admins` where `token`= '$token'");
|
|
$systemConfigData = self::$db->query("SELECT `id` FROM `ws_admins` where `token`= '$token'");
|
|
|
- //print_r(self::$global->adminList);
|
|
|
|
|
if ($systemConfigData) {
|
|
if ($systemConfigData) {
|
|
|
- $adminList = self::$global->adminList;
|
|
|
|
|
- $adminList[] = $client_id;
|
|
|
|
|
- self::$global->adminList = $adminList;
|
|
|
|
|
|
|
+ $adminList = self::$redis->lpush('adminList', $client_id);
|
|
|
self::systemMonitoring([$client_id]);
|
|
self::systemMonitoring([$client_id]);
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ $chat_message = [
|
|
|
|
|
+ 'message_type' => 'tips',
|
|
|
|
|
+ 'data' => '管理员不存在'
|
|
|
|
|
+ ];
|
|
|
|
|
+ Gateway::sendToClient($client_id, json_encode($chat_message, 256));
|
|
|
Gateway::closeClient($client_id);
|
|
Gateway::closeClient($client_id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -545,14 +604,18 @@ class Events
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 客服结束会话
|
|
|
|
|
|
|
+ * 工单结束
|
|
|
* @param int $client_id 连接id
|
|
* @param int $client_id 连接id
|
|
|
*
|
|
*
|
|
|
* tips: 当服务端主动退出的时候,会出现 exit status 9.原因是:服务端主动断开之后,连接的客户端会走这个方法,而短时间内进程
|
|
* tips: 当服务端主动退出的时候,会出现 exit status 9.原因是:服务端主动断开之后,连接的客户端会走这个方法,而短时间内进程
|
|
|
* 需要处理这多的逻辑,又有cas操作,导致进程退出会超时,然后会被内核杀死,从而报出错误 9.实际对真正的业务没有任何的影响。
|
|
* 需要处理这多的逻辑,又有cas操作,导致进程退出会超时,然后会被内核杀死,从而报出错误 9.实际对真正的业务没有任何的影响。
|
|
|
*/
|
|
*/
|
|
|
- public static function serverClose($client_id, $servicelog_id, $userId, $kf_id, $groupId)
|
|
|
|
|
|
|
+ public static function serverClose($servicelogId)
|
|
|
{
|
|
{
|
|
|
|
|
+ // 删除当前工单.
|
|
|
|
|
+ //self::$redis->hdel('SERVICELOG', $servicelogId);
|
|
|
|
|
+ $data = json_decode(self::$redis->HGET('SERVICELOG', $servicelogId), true);
|
|
|
|
|
+ print_r($data);
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -969,71 +1032,48 @@ class Events
|
|
|
$systemConfigData = self::$db->query("SELECT `systemconfig_data`,`systemconfig_enName`,`systemconfig_content` FROM `ws_systemconfig`");
|
|
$systemConfigData = self::$db->query("SELECT `systemconfig_data`,`systemconfig_enName`,`systemconfig_content` FROM `ws_systemconfig`");
|
|
|
foreach ($systemConfigData as $k => $v) {
|
|
foreach ($systemConfigData as $k => $v) {
|
|
|
if ($v['systemconfig_enName'] == 'overtime') {
|
|
if ($v['systemconfig_enName'] == 'overtime') {
|
|
|
- self::$global->overtime = $v;
|
|
|
|
|
|
|
+ $configOvertime = $v;
|
|
|
} elseif ($v['systemconfig_enName'] == 'unoperated') {
|
|
} elseif ($v['systemconfig_enName'] == 'unoperated') {
|
|
|
- self::$global->unoperated = $v;
|
|
|
|
|
|
|
+ $configUnoperated = $v;
|
|
|
} elseif ($v['systemconfig_enName'] == 'noResponse') {
|
|
} elseif ($v['systemconfig_enName'] == 'noResponse') {
|
|
|
- self::$global->noResponse = $v;
|
|
|
|
|
|
|
+ $configNoResponse = $v;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// 查询未断开的工单.
|
|
// 查询未断开的工单.
|
|
|
- $serviceLog = self::$db->query("SELECT `servicelog_id`,`client_id`,`start_time`,`user_id`,`kf_id`,`group_id` FROM `ws_service_log` WHERE `status`='1' OR `status`='3'");
|
|
|
|
|
- $whereOr = '1=0';
|
|
|
|
|
- foreach ($serviceLog as $k => $v) {
|
|
|
|
|
- if ($k == 0) {
|
|
|
|
|
- $whereOr = "`servicelog_id`=" . $v['servicelog_id'];
|
|
|
|
|
- } else {
|
|
|
|
|
- $whereOr .= " OR `servicelog_id`=" . $v['servicelog_id'];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 查询最后一次会话.
|
|
|
|
|
- //$chatLog = self::$db->query("SELECT `servicelog_id`,MAX(`time_line`) FROM `ws_chat_log` WHERE ".$whereOr." group by `servicelog_id`");
|
|
|
|
|
- $chatLog = self::$db->query("
|
|
|
|
|
- select * from ws_chat_log as a where time_line=(
|
|
|
|
|
- select max(b.time_line) from ws_chat_log as b where a.servicelog_id = b.servicelog_id and from_id not like 'KF%' and (" . $whereOr . ") group by servicelog_id
|
|
|
|
|
- )
|
|
|
|
|
- ");
|
|
|
|
|
- $setOvertime = strtotime('-' . (self::$global->overtime['systemconfig_data'] - 60) . ' second');
|
|
|
|
|
- $overtime = strtotime('-' . (self::$global->overtime['systemconfig_data']) . ' second');
|
|
|
|
|
- $setUnoperated = strtotime('-' . (self::$global->unoperated['systemconfig_data'] - 60) . ' second');
|
|
|
|
|
- $unoperated = strtotime('-' . (self::$global->unoperated['systemconfig_data']) . ' second');
|
|
|
|
|
- $noResponse = strtotime('-' . (self::$global->noResponse['systemconfig_data']) . ' second');
|
|
|
|
|
|
|
+ $serviceLog = self::$redis->hGetall('SERVICELOG');
|
|
|
|
|
+ $setOvertime = strtotime('-' . ($configOvertime['systemconfig_data'] - 60) . ' second');
|
|
|
|
|
+ $overtime = strtotime('-' . ($configOvertime['systemconfig_data']) . ' second');
|
|
|
|
|
+ $setUnoperated = strtotime('-' . ($configUnoperated['systemconfig_data'] - 60) . ' second');
|
|
|
|
|
+ $unoperated = strtotime('-' . ($configUnoperated['systemconfig_data']) . ' second');
|
|
|
|
|
+ $noResponse = strtotime('-' . ($configNoResponse['systemconfig_data']) . ' second');
|
|
|
foreach ($serviceLog as $k => $v) {
|
|
foreach ($serviceLog as $k => $v) {
|
|
|
- if (!strlen(array_search($v['servicelog_id'], array_column($chatLog, 'servicelog_id')))) {
|
|
|
|
|
- if ($v['start_time'] <= $unoperated) {
|
|
|
|
|
- $servicelog_id = $v['servicelog_id'];
|
|
|
|
|
- self::$db->query("update `ws_service_log` set `servicelog_close_type` = 1 where `servicelog_id`= '$servicelog_id'");
|
|
|
|
|
- self::serverClose($v['client_id'], $servicelog_id, $v['user_id'], 'KF' . $v['kf_id'], $v['group_id']);
|
|
|
|
|
- // 如果小于设定时间前一分钟则给出提示.
|
|
|
|
|
- } elseif ($v['start_time'] <= $setUnoperated) {
|
|
|
|
|
|
|
+ // 无效会话关闭.如果没有说一句话.
|
|
|
|
|
+ $data = json_decode($v, true);
|
|
|
|
|
+ if (!$data['userLastTime']) {
|
|
|
|
|
+ if ($data['start_time'] <= $unoperated) {
|
|
|
|
|
+ self::serverClose($k);
|
|
|
|
|
+ // 如果小于设定时间前一分钟则给出提示.
|
|
|
|
|
+ } elseif ($data['start_time'] <= $setUnoperated) {
|
|
|
$chat_message = [
|
|
$chat_message = [
|
|
|
'message_type' => 'overtime',
|
|
'message_type' => 'overtime',
|
|
|
'data' => [
|
|
'data' => [
|
|
|
'content' => self::$global->unoperated['systemconfig_content'],
|
|
'content' => self::$global->unoperated['systemconfig_content'],
|
|
|
]
|
|
]
|
|
|
];
|
|
];
|
|
|
- Gateway::sendToClient($v['client_id'], json_encode($chat_message, 256));
|
|
|
|
|
|
|
+ Gateway::sendToClient($data['client_id'], json_encode($chat_message, 256));
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 双方静默超时.
|
|
|
|
|
- foreach ($chatLog as $k => $v) {
|
|
|
|
|
- // 如果对话为客服的最后一次对话且时间小于设定时间则结束工单.
|
|
|
|
|
- if ($v['time_line'] <= $overtime) {
|
|
|
|
|
- $found_key = array_search($v['servicelog_id'], array_column($serviceLog, 'servicelog_id'));
|
|
|
|
|
- $servicelog_id = $v['servicelog_id'];
|
|
|
|
|
- self::$db->query("update `ws_service_log` set `servicelog_close_type` = 2 where `servicelog_id`= '$servicelog_id'");
|
|
|
|
|
- self::serverClose($serviceLog[$found_key]['client_id'], $servicelog_id, $serviceLog[$found_key]['user_id'], 'KF' . $serviceLog[$found_key]['kf_id'], $serviceLog[$found_key]['group_id']);
|
|
|
|
|
- // 如果对话为客服的最后一次对话且时间小于设定时间前一分钟则给出提示.
|
|
|
|
|
- } elseif ($v['time_line'] <= $setOvertime) {
|
|
|
|
|
|
|
+ // 双方静默超时.
|
|
|
|
|
+ } elseif ($data['userLastTime'] <= $overtime && $data['serverLastTime'] <= $overtime) {
|
|
|
|
|
+ self::serverClose($k);
|
|
|
|
|
+ // 如果小于设定时间前一分钟则给出提示.
|
|
|
|
|
+ } elseif ($data['userLastTime'] <= $setOvertime && $data['serverLastTime'] <= $setOvertime) {
|
|
|
$chat_message = [
|
|
$chat_message = [
|
|
|
'message_type' => 'overtime',
|
|
'message_type' => 'overtime',
|
|
|
'data' => [
|
|
'data' => [
|
|
|
'content' => self::$global->overtime['systemconfig_content'],
|
|
'content' => self::$global->overtime['systemconfig_content'],
|
|
|
]
|
|
]
|
|
|
];
|
|
];
|
|
|
- $found_key = array_search($v['servicelog_id'], array_column($serviceLog, 'servicelog_id'));
|
|
|
|
|
- Gateway::sendToClient($serviceLog[$found_key]['client_id'], json_encode($chat_message, 256));
|
|
|
|
|
|
|
+ Gateway::sendToClient($data['client_id'], json_encode($chat_message, 256));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1044,57 +1084,53 @@ class Events
|
|
|
*/
|
|
*/
|
|
|
private static function systemMonitoring($adminList)
|
|
private static function systemMonitoring($adminList)
|
|
|
{
|
|
{
|
|
|
- // 查询未结束工单.
|
|
|
|
|
- $serviceLog = self::$db->query("select ws_service_log.servicelog_id,ws_users.user_name as server_name,ws_service_log.user_name,kf_id,start_time,end_time,ws_service_log.group_id,evaluate_id,intime,ws_service_log.status,alarm_userSensitive,alarm_serverSensitive,alarm_corresponding
|
|
|
|
|
- from `ws_service_log`
|
|
|
|
|
- join `ws_alarm` on ws_service_log.servicelog_id=ws_alarm.servicelog_id
|
|
|
|
|
- join `ws_users` on ws_service_log.kf_id=ws_users.id
|
|
|
|
|
- WHERE ws_service_log.status='1' OR ws_service_log.status='3'");
|
|
|
|
|
|
|
+ // 查询正进行的工单.
|
|
|
|
|
+ $serviceLog = self::$redis->hGetall('SERVICELOG');
|
|
|
// 查询系统设置表.
|
|
// 查询系统设置表.
|
|
|
$systemconfig = self::$db->query("SELECT `systemconfig_data`,`systemconfig_enName` FROM `ws_systemconfig` WHERE `systemconfig_enName`='verifyReturnTime' or `systemconfig_enName`='verifyAllTime'");
|
|
$systemconfig = self::$db->query("SELECT `systemconfig_data`,`systemconfig_enName` FROM `ws_systemconfig` WHERE `systemconfig_enName`='verifyReturnTime' or `systemconfig_enName`='verifyAllTime'");
|
|
|
- $returnTimeKey = array_search('verifyReturnTime', array_column($systemconfig, 'systemconfig_enName'));
|
|
|
|
|
// 质检会话响应时长.
|
|
// 质检会话响应时长.
|
|
|
|
|
+ $returnTimeKey = array_search('verifyReturnTime', array_column($systemconfig, 'systemconfig_enName'));
|
|
|
$verifyReturnTime = $systemconfig[$returnTimeKey]['systemconfig_data'];
|
|
$verifyReturnTime = $systemconfig[$returnTimeKey]['systemconfig_data'];
|
|
|
- $allTimeKey = array_search('verifyAllTime', array_column($systemconfig, 'systemconfig_enName'));
|
|
|
|
|
// 质检会话时长.
|
|
// 质检会话时长.
|
|
|
|
|
+ $allTimeKey = array_search('verifyAllTime', array_column($systemconfig, 'systemconfig_enName'));
|
|
|
$verifyAllTime = $systemconfig[$allTimeKey]['systemconfig_data'];
|
|
$verifyAllTime = $systemconfig[$allTimeKey]['systemconfig_data'];
|
|
|
- // 差评次数.
|
|
|
|
|
- $evaluateCount = 0;
|
|
|
|
|
- // 未结束工单id.
|
|
|
|
|
- $servicelog_ids = '';
|
|
|
|
|
- $overtimeNumber = 0; // 会话超时次数.
|
|
|
|
|
- $overtimeTime = []; // 会话超时时间.
|
|
|
|
|
- $userSensitive = 0; // 用户敏感词报警次数.
|
|
|
|
|
- $serverSensitive = 0; // 客服敏感词报警次数.
|
|
|
|
|
- $csdNumber = 0; // 响应超时次数.
|
|
|
|
|
- $csdTime = []; // 响应超时时间.
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ $evaluateCount = 0; // 差评总次数.
|
|
|
|
|
+ $overtimeNumber = 0; // 会话超时总次数.
|
|
|
|
|
+ $overtimeTime = []; // 每次会话超时时间.
|
|
|
|
|
+ $userSensitive = 0; // 用户敏感词报警总次数.
|
|
|
|
|
+ $serverSensitive = 0; // 客服敏感词报警总次数.
|
|
|
|
|
+ $csdNumber = 0; // 响应超时总次数.
|
|
|
|
|
+ $csdTime = []; // 每次响应超时时间.
|
|
|
foreach ($serviceLog as $k => $v) {
|
|
foreach ($serviceLog as $k => $v) {
|
|
|
- // 工单报警总次数.
|
|
|
|
|
|
|
+ $data = json_decode($v, true);
|
|
|
|
|
+ // 工单报警次数.
|
|
|
$allCount = 0;
|
|
$allCount = 0;
|
|
|
- // 差评次数.
|
|
|
|
|
- if ($v['evaluate_id'] == 3) {
|
|
|
|
|
- $evaluateCount++;
|
|
|
|
|
- $allCount++;
|
|
|
|
|
|
|
+ if ($data['evaluate_id'] == 3) {
|
|
|
|
|
+ $evaluateCount++; // 差评次数.
|
|
|
|
|
+ $allCount++; // 工单报警次数.
|
|
|
}
|
|
}
|
|
|
- $duration = time() - $v['start_time'];
|
|
|
|
|
// 会话超时.
|
|
// 会话超时.
|
|
|
|
|
+ $duration = time() - $data['start_time'];
|
|
|
if ($duration > $verifyAllTime) {
|
|
if ($duration > $verifyAllTime) {
|
|
|
- $overtimeNumber++;
|
|
|
|
|
- $allCount++;
|
|
|
|
|
- $overtimeTime[] = $duration;
|
|
|
|
|
|
|
+ $overtimeNumber++; // 会话超时总次数.
|
|
|
|
|
+ $allCount++; // 工单报警次数.
|
|
|
|
|
+ $overtimeTime[] = $duration; // 响应超时时间.
|
|
|
}
|
|
}
|
|
|
// 敏感词报警.
|
|
// 敏感词报警.
|
|
|
- $userSensitive += $v['alarm_userSensitive'];
|
|
|
|
|
- $allCount += $v['alarm_userSensitive'];
|
|
|
|
|
- $serverSensitive += $v['alarm_serverSensitive'];
|
|
|
|
|
- $allCount += $v['alarm_serverSensitive'];
|
|
|
|
|
|
|
+ $userSensitive += $data['alarm_userSensitive'];
|
|
|
|
|
+ $allCount += $data['alarm_userSensitive'];
|
|
|
|
|
+ $serverSensitive += $data['alarm_serverSensitive'];
|
|
|
|
|
+ $allCount += $data['alarm_serverSensitive'];
|
|
|
// 响应超时.
|
|
// 响应超时.
|
|
|
- if ($v['alarm_corresponding'] > $verifyReturnTime) {
|
|
|
|
|
- $csdTime[] = $v['alarm_corresponding'];
|
|
|
|
|
- $csdNumber++;
|
|
|
|
|
- $allCount++;
|
|
|
|
|
|
|
+ if ($data['alarm_corresponding'] > $verifyReturnTime) {
|
|
|
|
|
+ $csdTime[] = $data['alarm_corresponding']; // 响应超时时间.
|
|
|
|
|
+ $csdNumber++; // 响应超时总次数.
|
|
|
|
|
+ $allCount++; // 工单报警次数.
|
|
|
}
|
|
}
|
|
|
- $serviceLog[$k]['allCount'] = $allCount;
|
|
|
|
|
|
|
+ $serviceLog[$k] = $data;
|
|
|
|
|
+ $serviceLog[$k]['allCount'] = $allCount; // 工单报警次数.
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
self::DebugOut([$serviceLog, $csdTime, $verifyReturnTime], 'systemMonitoring');
|
|
self::DebugOut([$serviceLog, $csdTime, $verifyReturnTime], 'systemMonitoring');
|