ソースを参照

Merge branch 'dev' of http://git.bocai108.com:10180/Ethan/Customer-Service into dev

Jonlin 6 年 前
コミット
74484e7205

+ 13 - 3
application/admin/controller/System.php

@@ -2,6 +2,7 @@
 namespace app\admin\controller;
 
 use app\admin\model\Office;
+use think\cache\driver\Redis;
 
 /**
  * 管理系统系统设置类
@@ -355,7 +356,7 @@ class System extends Base
     }
 
     // 历史会话记录详情
-    public function detail($id)
+    public function detail($id, $type='')
     {
         $chat = db('chat_log')->where('servicelog_id',$id)->order('time_line')->select();
         $html = '';
@@ -383,13 +384,22 @@ class System extends Base
             }
 
         }
-        $servicelog = db('service_log')->where('servicelog_id',$id)->find();
+        $redis = new Redis;
+        if ($type === 'onLine') {
+            $servicelog = json_decode($redis->handler()->Hget('SERVICELOG', $id), true);
+        } else {
+            $servicelog = db('service_log')->where('servicelog_id',$id)->find();
+        }
         //满意度
         $evaluate = db('evaluate')->where('evaluate_id',$servicelog['evaluate_id'])->find();
         $evaluate = '<img width="40px" style="margin-top:15px;" src="'.$evaluate['evaluate_url'].'"/>';
 
         //$alarm报警信息
-        $alarm =  db('alarm')->where('servicelog_id',$id)->find();
+        if ($type === 'onLine') {
+            $alarm = json_decode($redis->handler()->Hget('SERVICELOG', $id), true);
+        } else {
+            $alarm =  db('alarm')->where('servicelog_id',$id)->find();
+        }
 
         //会话超时标准
         $verifyAllTime =  db('systemconfig')->where('systemconfig_name','质检会话时长设置')->find();

+ 1 - 1
application/admin/view/index/index.html

@@ -415,7 +415,7 @@
                             "<td>"+customFormatDateTime(start_time,'',2)+"</td>" +
                             "<td>"+cvtList[key].allCount+"</td>" +
                             "<td>" +
-                                "<a href='/admin/system/detail/id/"+cvtList[key].servicelog_id+".html'>" +
+                                "<a href='/admin/system/detail/id/"+cvtList[key].servicelog_id+"/type/onLine.html'>" +
                                     "<button type='button' class='btn btn-primary btn-sm'>" +
                                         "<i class='fa fa-paste'></i> 详情" +
                                     "</button>" +

+ 3 - 3
thinkphp/library/think/cache/driver/Redis.php

@@ -23,10 +23,10 @@ use think\cache\Driver;
 class Redis extends Driver
 {
     protected $options = [
-        'host'       => '127.0.0.1',
-        'port'       => 6379,
+        'host'       => '192.168.2.200',
+        'port'       => 26379,
         'password'   => '',
-        'select'     => 0,
+        'select'     => 1,
         'timeout'    => 0,
         'expire'     => 0,
         'persistent' => false,

+ 199 - 65
vendor/GatewayWorker_windows/Applications/whisper/Events.php

@@ -39,6 +39,7 @@ class Events
     public static $redis = null;
     public static $logic = null;
 
+    const  KFSERVICES = 'KFSERVICES';          //KFSERVICES:KF10 1213131=>22这样的 客服工单hash表 健为连接号,值为工单号
     const  KFINFOKEY = 'KFINFO';              //客服信息hash表
     const  USERINFOKEY = 'USERINFO';          //用户信息hash表
     const  USERLIST = 'USERLIST';             //用户排队表
@@ -70,7 +71,7 @@ class Events
         foreach ($group as $groupid => $gname) {
             $users = self::getUselistData($groupid);
             if (!empty($users)) {
-                Gateway::sendToGroup('group_' . $groupid, json_encode(['type' => 'lineupCount', count($users)], 256));
+                Gateway::sendToGroup('group_' . $groupid, json_encode(['type' => 'lineupCount', 'data' => ['count' => count($users)]], 256));
             }
         }
     }
@@ -186,6 +187,9 @@ class Events
                 case 'getEvaluate';
                     self::getEvaluate($message['data']);
                     break;
+                case 'debug':
+                    self::debug($message['data']);
+                    break;
             }
         }
         return true;
@@ -401,7 +405,7 @@ class Events
                 'intime' => time(),
                 'signature' => $kfinfo['signature'],
                 'status' => 2, // 1为在线(接收分配、接收消息)2为隐身(不接收分配、只接收消息)3、休息
-                'user_info' => [],  //在会话的用户cid  key为clientid ,值为工单号
+                'user_info' => [],  //在会话的用户cid  key为clientid ,值为工单号               ///////弃用 改为hash数据了
             ];
 
         self::$redis->hset(self::KFINFOKEY, $uid, json_encode($newinfo, 256));
@@ -472,11 +476,18 @@ class Events
     {
         $uid = intval($message['uid']);
         $group = intval($message['group']);
+        $userTmpInfo = self::getUserInfoCache($uid);
+        if (empty($userTmpInfo)) {
+            self::MySendMsg($client_id, (json_encode(['message_type' => 'reLoginErr', 'msg' => '不存在的用户....'], 256)));
+            Gateway::closeCurrentClient();
+            return true;
+        }
+
 
         $last = self::UserHasOldTalk($uid);
-        if (!isset(self::$global->groupmap[$group])&&!$last) {
+        if (!isset(self::$global->groupmap[$group]) && !$last) {
             self::MySendMsg($client_id, (json_encode(['message_type' => 'reLoginErr', 'msg' => '不存在客服组....'], 256)));
-            return  true;
+            return true;
             //Gateway::closeCurrentClient();
         }
 
@@ -491,20 +502,27 @@ class Events
         if ($hisdata) {
             $hisdata = json_decode($hisdata, true);
             $oldclientid = $hisdata['client_id'];
-            self::MySendMsg($oldclientid, json_encode(['type' => 'reLoginErr', 'msg' => '相同账号登陆,本次退出'], 256));
-            self::MySendMsg($client_id, json_encode(['type' => 'reLoginErr', 'msg' => '相同账号登陆,本次退出'], 256));
+            self::MySendMsg($oldclientid, json_encode(['type' => 'reLoginErr', 'msg' => '相同账号登陆1,本次退出'], 256));
+            self::MySendMsg($client_id, json_encode(['type' => 'reLoginErr', 'msg' => '相同账号登陆2,本次退出'], 256));
             Gateway::closeClient($oldclientid);
             Gateway::closeCurrentClient();
             return;
         }
 
         $onlinekf = self::getOnlineKfData($group, 1);
-        if (empty($onlinekf)&&empty($last)) {
+        if (empty($onlinekf) && empty($last)) {
             Gateway::sendToClient($client_id, json_encode(['message_type' => 'notice', 'content' => '暂时没有客服上班,请稍后再咨询。'], 256));
             //Gateway::closeClient($client_id);
             return;
         }
 
+        $groupMax = self::$global->systemconfig['maxWait'];
+        $noworders = self::getUselistData($group);
+        if ($noworders && count($noworders) > intval($groupMax['systemconfig_data'])) {
+            Gateway::sendToClient($client_id, json_encode(['message_type' => 'notice', 'content' => '组排队人数超过上限,请稍后在连线。'], 256));
+            return;
+        }
+
         self::$redis->hset('loginTmp:' . $uid, 'uid', time());
         self::$redis->expire('loginTmp:' . $uid, 5);
 
@@ -519,10 +537,15 @@ class Events
             'group' => $message['group'],
             'intime' => time(),
             'kfuid' => '',
-            'ip' => $_SESSION['remotip'],
             'serverid' => 0,
             'client_id' => $client_id
         ];
+        if ($last) {
+            $data['group'] = $last['group_id'];
+            $data['intime'] = $last['intime'];
+            $data['kfuid'] = $last['kf_id'];
+            $data['serverid'] = $last['servicelog_id'];
+        }
         self::$redis->hset(self::USERLIST, $uid, json_encode($data, 256));
         self::$redis->hset(self::USERINFOKEY, $uid, json_encode($data, 256));
 
@@ -581,7 +604,8 @@ class Events
             echo "客服发生异常退出\n";
             return;
         }
-        $user_info = $uinfo['user_info'];
+        //$user_info = $uinfo['user_info'];
+        $user_info = self::$redis->hgetall(self::getKfServiceKey($uid));
         $kfid = self::getkfid($uid);
         $now = time();
         $starttime = $now - 86400 * 7;
@@ -602,9 +626,10 @@ class Events
         echo "客服退出: " . $uid . "\n";
         self::$db->query($sql);
         self::$db->update('ws_users')->cols(array('online_status' => 0, 'online_connectid' => ''))->where('id=' . $kfid)->query();
+        self::$redis->del(self::getKfServiceKey($uid));
         self::writeLogKfStatus($uid, 0);
 
-        return;
+        return true;
     }
 
     //用户下线了          系统调用,不能手动调用
@@ -691,14 +716,15 @@ class Events
         // 删除当前工单.
         self::$redis->hdel('SERVICELOG', $servicelogId);
         // 当前服务客服删除当前人员.
-        $kfUserList = self::ArrayDataopt($kfInfo['user_info'], $data['client_id'], 0);
+        //$kfUserList = self::ArrayDataopt($kfInfo['user_info'], $data['client_id'], 0);
+        self::$redis->hdel(self::getKfServiceKey(self::getkfuid($data['kf_id'])), $data['client_id']);
         // 删除当前人员信息.
         self::$redis->hdel('USERINFO', $data['user_id']);
         // 当前客服所接待人员.
-        $kfInfo['user_info'] = $kfUserList;
-        $kfInfo['task'] = count($kfUserList);
+        //$kfInfo['user_info'] = $kfUserList;
+        //$kfInfo['task'] = count($kfUserList);
         // 存入客服信息.
-        self::$redis->HSET('KFINFO', 'KF' . $data['kf_id'], json_encode($kfInfo, 256));
+        //self::$redis->HSET('KFINFO', 'KF' . $data['kf_id'], json_encode($kfInfo, 256));
         // 发送消息给用户.
         $chat_message = [
             'message_type' => 'closeBysever',
@@ -795,63 +821,87 @@ class Events
      * @param $group
      * @param $uid
      */
-    private static function userOnlineTask($group = 0, $uid = 0, $last=[], $client_id='')
+    private static function userOnlineTask($group = 0, $uid = 0, $last = [], $client_id = '')
     {
+
         $allusergkarr = self::getUserListData();
         if (empty($allusergkarr)) {
             return;
         }
 
         $allkfgkarr = self::getWorkKfData();
-        if (empty($allkfgkarr)&&!$last) {
+        ///做某个组的客户是还有人服务检测,如果此组没有客服在线了,要把对应排队的人kh踢掉
+        self::Kf_user_click($allkfgkarr, $allusergkarr);
+
+        if (empty($allkfgkarr) && !$last) {
             return;
         }
-
-        $maxset = (self::$global->systemconfig)['KFMaxServices'] ?? 5;
-        $maxset = intval($maxset);
-
+        $maxset = intval((self::$global->systemconfig)['KFMaxServices']['systemconfig_data']);
         if ($group && $uid) {
             // 指定用指定组 [可能存在断线重连的情况] 如果存在旧的会话,直接连线客服和用户
             //否则按先到后到以及客服最大服务数限制
             if ($last) {
                 self::BeginOldTalk(self::getkfuid($last['kf_id']), $uid, $last['group_id'], $last['servicelog_id']);
+                // 查询工单历史会话.
+                $serviceid = $last['servicelog_id'];
+                $chatLog = self::$db->select('*')->from('ws_chat_log')->where("servicelog_id=$serviceid")->orderByDESC(['time_line'])->row();
                 $toOld_message = [
                     'message_type' => 'toOld',
                     'data' => [
+                        'chatLog' => $chatLog ?? [],
                         'content' => '接入至未结束的会话'
                     ]
                 ];
                 Gateway::sendToCurrentClient(json_encode($toOld_message, 256));
                 return;
-            } else {
-                //系统定时调用时,无组,无用户
-                foreach ($allusergkarr as $group => $gusersArr) {
-                    if (!isset($allkfgkarr[$group]) || count($allkfgkarr[$group]) <= 0) {
-                        //所属客服组无人在线
-                        continue;
-                    }
-                    $nowkfs = $allkfgkarr[$group];
-                    $count = count($nowkfs);
+            }
+        }
+
+
+        //系统定时调用时,无组,无用户
+        foreach ($allusergkarr as $group => $gusersArr) {
+            if (!isset($allkfgkarr[$group]) || count($allkfgkarr[$group]) <= 0) {
+                //所属客服组无人在线
+                continue;
+            }
+            $nowkfs = $allkfgkarr[$group];
+            $count = count($nowkfs);
+            $i = 0;
+
+            foreach ($gusersArr as $user) {
+                if ($nowkfs[$i]['task'] >= $maxset) {
+                    break;
+                }
+                $nowkfs[$i]['task']++;
+
+                self::BeginTalk($nowkfs[$i]['id'], $user['id'], $group, 0, $user);
+                self::$redis->hdel(self::USERLIST, $user['id']);
+
+                $i++;
+                if ($i >= $count) {
                     $i = 0;
+                }
+            }
+        }
+
 
-                    foreach ($gusersArr as $user) {
-                        if ($nowkfs[$i]['task'] > $maxset) {
-                            break;
-                        }
-                        $nowkfs[$i]['task']++;
+        return;
 
-                        self::BeginTalk($nowkfs[$i]['id'], $user['id'], $group, 0, $user);
-                        self::$redis->hdel(self::USERLIST, $user['id']);
+    }
 
-                        $i++;
-                        if ($i >= $count) {
-                            $i = 0;
-                        }
-                    }
+    //踢掉某个组没有客服的用户
+    private static function Kf_user_click($kfArrays, $userLIsts)
+    {
+        foreach ($userLIsts as $group => $groupusers) {
+            $haskf = isset($kfArrays[$group]) ? 1 : 0;
+            if (!$haskf) {
+                foreach ($groupusers as $user) {
+                    Gateway::sendToClient($user['client_id'], json_encode(['message_type' => 'notice', 'data' => ['msg' => "没有客服人员在线,请稍后再试。"]], 256));
+                    Gateway::closeClient($user['client_id']);
                 }
-                return;
             }
         }
+        return true;
     }
 
     //开启一个会话
@@ -902,16 +952,14 @@ class Events
 
         $redisData = array_merge($server, $armarr, ['kf_client_id' => $kfinfo['client_id'], 'server_name' => $kfinfo['name']]);
         self::$redis->hset(self::SERVICELOG, $serviceid, json_encode($redisData, 256));
-
-        $kfinfo['user_info'] = array_merge($kfinfo['user_info'], [$userInfo['client_id'] => $serviceid]);
-        $kfinfo['task'] = count($kfinfo['user_info']);
-        self::$redis->hset(self::KFINFOKEY, $kfuid, json_encode($kfinfo, 256));
+        self::setKfTasks($kfuid, $userInfo['client_id'], 1, $serviceid);
 
         $userInfo['serverid'] = $serviceid;
         $userInfo['kfuid'] = $kfuid;
         self::$redis->hset(self::USERINFOKEY, $uid, json_encode($userInfo, 256));
 
         // 通知会员发送信息绑定客服的id
+
         $noticeUser = [
             'message_type' => 'connect',
             'data' => [
@@ -923,7 +971,6 @@ class Events
         ];
         self::MySendMsg($userInfo['client_id'], json_encode($noticeUser, 256));
 
-
         $sayHello = (self::$global->replay)['2'];
         if (!empty($sayHello) && 1 == $sayHello['status']) {
             $chat_message = [
@@ -939,7 +986,9 @@ class Events
             unset($chat_message);
         }
 
-
+        $userInfo['intime'] = date("H:i", $userInfo['intime']);  ///后改为只显示小时分
+        $ut_tmp = self::getUserInfoCache($uid);
+        $userInfo = array_merge($userInfo, ['account_name' => $ut_tmp['account_name'], 'nick_name' => $ut_tmp['nick_name'], 'account_email' => $ut_tmp['account_email'], 'account_phone' => $ut_tmp['account_phone'], 'address' => $ut_tmp['address'], 'remark' => $ut_tmp['remark'], 'label' => self::$global->accountslabel[$ut_tmp['label_id']]['name']]);
         $noticeKf = [
             'message_type' => 'connect',
             'data' => [
@@ -977,7 +1026,7 @@ class Events
         $data['website'] = $userInfo['website'];
         $data['system'] = $userInfo['system'];
         $data['browse'] = $userInfo['browse'];
-        $data['status'] = $userInfo['status'];
+        $data['status'] = 1;
         self::$redis->hset(self::SERVICELOG, $serviceid, json_encode($data, 256));
 
         // 更改用户连接客服信息
@@ -986,18 +1035,14 @@ class Events
         self::$redis->hset(self::USERINFOKEY, $uid, json_encode($userInfo, 256));
         // 更改客服连接信息.
         $kfinfo = json_decode(self::$redis->hget(self::KFINFOKEY, $kfuid), true);
-        $kfUsers = json_decode($kfinfo['user_info'], true);
+        $kfUsers = self::$redis->hgetall(self::getKfServiceKey($kfuid));
         foreach ($kfUsers as $key => $value) {
             if ($value == $serviceid) {
                 // 删除之前的当前用户连接
-                unset($kfUsers[$key]);
+                self::$redis->hdel(self::getKfServiceKey($kfuid), $key);
             }
         }
-        // 增加现在用户的连接到客服
-        $kfUsers[$userInfo['client_id']] = $serviceid;
-        $kfinfo['user_info'] = $kfUsers;
-        // 将数据存入redis
-        self::$redis->hset('KFINFO', $kfuid, json_encode($kfinfo, 256));
+        self::$redis->hset(self::getKfServiceKey($kfuid), $userInfo['client_id'], $serviceid);
 
         // 通知会员发送信息绑定客服的id
         $noticeUser = [
@@ -1072,6 +1117,8 @@ class Events
             $now = json_decode($val, true);
             if ($now && $now['status'] == 1) {
                 //客分组后的数组
+                $tmp = self::getKfTasks($now['id']);
+                $now['task'] = $tmp ? count($tmp) : 0;
                 $allkfgkarr[$now['group']][] = $now;
             }
         }
@@ -1185,9 +1232,8 @@ class Events
         $nowTalking = $onlineKf = 0;
         if (!empty($allkf)) {
             foreach ($allkf as $kfuid => $val) {
-                $tmp = json_decode($val, true);
                 $onlineKf++;
-                $nowTalking += count($tmp['user_info']);
+                $nowTalking = 0;
             }
         }
 
@@ -1299,6 +1345,15 @@ class Events
             self::$global->replay = $arr;
         }
 
+        $arr = [];
+        $bq = self::$db->query("select  *  from ws_accountslabel");
+        if ($bq) {
+            foreach ($bq as $val) {
+                $arr[$val['id']] = $val;
+            }
+            self::$global->accountslabel = $arr;
+        }
+
     }
 
     /**
@@ -1479,15 +1534,9 @@ class Events
         unset($oldlog['servicelog_id']);
 
         ///更新redis数据
-        $kf_info_from['user_info'] = self::ArrayDataopt($kf_info_from['user_info'], $user_info['client_id'], 0);
-        $kf_info_from['task'] = count($kf_info_from['user_info']);
-        self::$redis->hset(self::KFINFOKEY, $fromkfuid, json_encode($kf_info_from, 256));
-
-        ///////旧工单部分数据更新回库
-        /// 查询工单会话总数.
+        self::updteKfTasksByservicd($fromkfuid, $serviceid, $user_info['client_id'], 0);
 
         self:: BeginTalk($toukfid, $uid, $groupidto, 0, $user_info);
-
         self::servicetrutoother('OUT', $fromkfuid, $toukfid, $serviceid, $uid);
         $newUserInfo = json_decode(self::$redis->hget(self::USERINFOKEY, $uid), true);
         self::servicetrutoother('IN', $toukfid, $fromkfuid, $newUserInfo['serverid'], $uid);
@@ -1764,6 +1813,91 @@ class Events
         }
     }
 
+    //调试使用
+    public static function debug($dataArray)
+    {
+
+
+    }
+
+
+    //客服的工单hash健名
+    public static function getKfServiceKey($kfuid)
+    {
+        return self::KFSERVICES . ':' . $kfuid;
+    }
+
+
+    //获取客服所有连接信息及工单信息
+    public static function getKfTasks($kfuid)
+    {
+        $all = self::$redis->hgetall(self::getKfServiceKey($kfuid));
+        if (empty($all)) {
+            return false;
+        }
+        return $all;
+    }
+
+    //设置或删除客服的连接  opt==0删除 1添加
+    public static function setKfTasks($kfuid, $clientid, $opt = 0, $serviceid = 0)
+    {
+        $k = self::getKfServiceKey($kfuid);
+        if ($opt == 0) {
+            self::$redis->hdel($k, $clientid);
+            return;
+        }
+        self::$redis->hset($k, $clientid, $serviceid);
+    }
+
+    //有旧单时,更新连接ID
+    public static function updteKfTasksByservicd($kfuid, $serciceid, $newclientid, $opt = 1)
+    {
+        $tkey = self::getKfServiceKey($kfuid);
+        $all = self::getKfTasks($kfuid);
+        $serciceid = intval($serciceid);
+
+
+        if ($opt == 1) {
+            if (empty($all)) {
+                self::$redis->hset($tkey, $newclientid, $serciceid);
+                return;
+            }
+            foreach ($all as $cid => $nowserverid) {
+                if (intval($nowserverid) == $serciceid) {
+                    self::$redis->hdel(self::getKfServiceKey($kfuid), $cid);
+                }
+            }
+            self::$redis->hset($tkey, $newclientid, $serciceid);
+            return true;
+        } else {
+            if (empty($all)) {
+                return;
+            }
+            foreach ($all as $cid => $nowserverid) {
+                if (intval($nowserverid) == $serciceid) {
+                    self::$redis->hdel(self::getKfServiceKey($kfuid), $cid);
+                }
+            }
+            return true;
+        }
+
+    }
+
+    //缓存获取用户信息
+    public static function getUserInfoCache($uid, $cacheTime = 180)
+    {
+        $uid = intval($uid);
+        $key = 'TmpUserInfo:' . $uid;
+        $cache = self::$redis->hget($key, $uid);
+        if ($cache && $cacheTime) {
+            return json_decode($cache, true);
+        }
+        $date = self::$db->select('*')->from('ws_accounts')->where("id= $uid ")->row();
+        self::$redis->hset($key, $uid, json_encode($date, 256));
+        self::$redis->EXPIRE($key, $cacheTime);
+        return $date;
+    }
+
 
 }
 

+ 4 - 0
vendor/GatewayWorker_windows/Applications/whisper/start_gateway.php

@@ -35,9 +35,13 @@ $gateway->startPort = 2900;
 // 服务注册地址
 $gateway->registerAddress = '127.0.0.1:1238';
 
+
 // 心跳间隔
 $gateway->pingInterval = 5;
 $gateway->pingNotResponseLimit = 2;
+$tmpPath = isset($_SERVER['TEMP']) ? $_SERVER['TEMP'] : '/tmp';
+Worker::$logFile = $tmpPath . '/workerman.log';
+Worker::$stdoutFile = $tmpPath . '/stdout.log';
 // 心跳数据
 //$gateway->pingData = '{"message_type":"ping"}';