浏览代码

'在线监控'

Ethan 6 年之前
父节点
当前提交
a51e716366

+ 7 - 0
application/admin/controller/Index.php

@@ -12,6 +12,13 @@ class Index extends Base
     // 后台默认首页
     public function indexPage()
     {
+        $this->assign([
+            'socket' => config('socket'),
+            'token' => session('token'),
+        ]);
+
+
+
         $data = db('now_data')->where('id', 1)->find();
 
         // 生成从 8点 到 22点的时间数组

+ 1 - 0
application/admin/controller/Login.php

@@ -64,6 +64,7 @@ class Login extends Controller
             ];
             db('admins')->where('id', $userInfo['id'])->update($param);
 
+            session('token', $token);
             $this->assign([
                 'token' => $token,
                 'user_name' => $userName

+ 31 - 0
application/admin/view/index/index.html

@@ -123,6 +123,7 @@
 <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
 <script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
 <script src="/static/admin/js/plugins/echarts/echarts.min.js"></script>
+<script src="/static/customer/js/md5.js"></script>
 <script type="text/javascript">
     var data = {$show_data};
     // 基于准备好的dom,初始化echarts实例
@@ -187,5 +188,35 @@
     // 使用刚指定的配置项和数据显示图表。
     myChart.setOption(option);
 </script>
+<!--webSocket-->
+<script>
+    let config = {
+        socket: '{$socket}',
+        token: '{$token}',
+    };
+    let date = new Date(new Date().setHours(0, 0, 0, 0)) / 1000;
+    let getLocation = window.location.href;
+    let host = getLocation.split('/admin')[0];
+    let apiToken = hex_md5('customer-service'+date+host);
+    let socket = new WebSocket('ws://' + config.socket+'?apiToken=' + apiToken);
+    socket.onopen = function(res) {
+        console.log('握手成功');
+        // 登录
+        let login_data = JSON.stringify({
+            type: 'adminInit',
+            token:  config.token
+        });
+        socket.send(login_data);
+    };
+    socket.onmessage = function(res) {
+        var data = eval("("+res.data+")");
+        switch(data['message_type']){
+            // 服务端ping客户端
+            case 'helloMessage':
+                console.log(data);
+                break;
+        }
+    };
+</script>
 </body>
 </html>

+ 67 - 0
application/index/controller/Alarm.php

@@ -0,0 +1,67 @@
+<?php
+namespace app\index\controller;
+
+/**
+ * 报警类
+ */
+class Alarm extends Common
+{
+
+
+    /**
+     * 敏感词报警
+     *
+     * @access public
+     * @return array JsonString
+     */
+    public function sensitiveAlarm()
+    {
+        // 验证token.
+        $tokenStatus = $this->verifyApiToken();
+        $code        = -2;
+        $msg         = '错误';
+        if ($tokenStatus === false) {
+            $msg = 'token错误';
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }
+
+        try {
+            $conversationId         = input('get.conversationId');
+            $type                   = input('get.type');
+            $where['servicelog_id'] = $conversationId;
+            // 获取数据.
+            if ($type === '1') {
+                $field = ['alarm_userSensitive'];
+                $alarm = model('Alarm')->findAlarm($field, $where);
+                // 修改或新增数据.
+                if (empty($alarm) === true) {
+                    $data['alarm_userSensitive'] = 1;
+                    $data['servicelog_id']       = $conversationId;
+                    model('Alarm')->addAlarm($data);
+                } else {
+                    $data['alarm_userSensitive'] = ($alarm['alarm_userSensitive'] + 1);
+                    model('Alarm')->updateAlarm($where, $data);
+                }
+            } else {
+                $field = ['alarm_serverSensitive'];
+                $alarm = model('Alarm')->findAlarm($field, $where);
+                // 修改或新增数据.
+                if (empty($alarm) === true) {
+                    $data['alarm_serverSensitive'] = 1;
+                    $data['servicelog_id']         = $conversationId;
+                    model('Alarm')->addAlarm($data);
+                } else {
+                    $data['alarm_serverSensitive'] = ($alarm['alarm_serverSensitive'] + 1);
+                    model('Alarm')->updateAlarm($where, $data);
+                }
+            }//end if
+
+            return json(['code' => 1, 'data' => [], 'msg' => '成功']);
+        } catch (\Exception $e) {
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }//end try
+
+    }//end sensitiveAlarm()
+
+
+}

+ 1 - 0
application/index/controller/Common.php

@@ -24,6 +24,7 @@ class Common extends Controller
         $controller  = $request->controller();
         $module      = $request->module();
         $apiToken    = md5(strtolower($action.'Customer-Service'.$controller.strtotime(date('Y-m-d')).$module));
+        //print_r([$apiToken, $getApiToken]);die;
         if ($getApiToken === $apiToken) {
             return true;
         } else {

+ 40 - 10
application/index/controller/Evaluate.php

@@ -46,7 +46,7 @@ class Evaluate extends Common
     public function putEvaluate()
     {
         // 验证token.
-        /*$tokenStatus = $this->verifyApiToken();
+        $tokenStatus = $this->verifyApiToken();
         $code        = -2;
         $msg         = '错误';
         if ($tokenStatus === false) {
@@ -54,24 +54,54 @@ class Evaluate extends Common
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
 
-        try {*/
+        try {
             // 获取数据.
-            $evaluateId                = input('get.evaluateId');
-            $conversationId            = input('get.conversationId');
-            $evaluateContent           = input('get.evaluateContent');
-            $where['servicelog_id']    = $conversationId;
+            $evaluateId               = input('get.evaluateId');
+            $conversationId           = input('get.conversationId');
+            $evaluateContent          = input('get.evaluateContent');
+            $where['servicelog_id']   = $conversationId;
             $data['evaluate_content'] = $evaluateContent;
-            $data['evaluate_id']       = $evaluateId;
-            $data['evaluate_id']       = $evaluateId;
+            $data['evaluate_id']      = $evaluateId;
             // 评价.
             $result = model('serviceLog')->getEvaluate($where, $data);
 
             return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
-        /*} catch (\Exception $e) {
+        } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
-        }//end try*/
+        }//end try
 
     }//end putEvaluate()
 
 
+    /**
+     * 最小回合
+     *
+     * @access public
+     * @return array JsonString
+     */
+    public function minRound()
+    {
+        // 验证token.
+        $tokenStatus = $this->verifyApiToken();
+        $code        = -2;
+        $msg         = '错误';
+        if ($tokenStatus === false) {
+            $msg = 'token错误';
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }
+
+        try {
+            // 获取数据.
+            $where['systemconfig_enName'] = 'round';
+            // 评价.
+            $result = model('systemconfig')->findSystemconfig($where);
+
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
+        } catch (\Exception $e) {
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }//end try
+
+    }//end minRound()
+
+
 }

+ 46 - 1
application/index/controller/Index.php

@@ -4,8 +4,53 @@ namespace app\index\controller;
 
 use think\Controller;
 
-class Index extends Controller
+class Index extends Common
 {
+
+
+    /**
+     * 获取敏感词
+     *
+     * @access public
+     * @return array JsonString
+     */
+    public function sensitiveWords()
+    {
+        // 验证token.
+        $tokenStatus = $this->verifyApiToken();
+        $code        = -2;
+        $msg         = '错误';
+        if ($tokenStatus === false) {
+            $msg = 'token错误';
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }
+
+        try {
+            // 获取敏感词.
+            $wordsField = ['*'];
+            $sysWordsWhere['sensitivewords_status'] = 1;
+            $sysWordsWhere['sensitivewords_for']    = 1;
+            // 查询客服敏感词.
+            $userSensitive = model('sensitivewords')->selectWords($wordsField, $sysWordsWhere);
+            // 获取敏感词.
+            $wordsField = ['*'];
+            $sysWordsWhere['sensitivewords_status'] = 1;
+            $sysWordsWhere['sensitivewords_for']    = 2;
+            // 查询用户敏感词.
+            $serverSensitive = model('sensitivewords')->selectWords($wordsField, $sysWordsWhere);
+            $data            = [
+                'userSensitive'   => $userSensitive,
+                'serverSensitive' => $serverSensitive,
+            ];
+
+            return json(['code' => 1, 'data' => $data, 'msg' => '成功']);
+        } catch (\Exception $e) {
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }//end try
+
+    }//end sensitiveWords()
+
+
     public function index()
     {
         return $this->fetch();

+ 60 - 0
application/index/model/Alarm.php

@@ -0,0 +1,60 @@
+<?php
+namespace app\index\model;
+
+use think\Model;
+
+/**
+ * 工单报警模型
+ */
+class Alarm extends Model
+{
+
+
+    /**
+     * 获取工单报警
+     *
+     * @access public
+     * @param mixed $field 查询字段
+     * @param mixed $where 条件
+     * @return array 返回类型
+     */
+    public function findAlarm($field, $where)
+    {
+        $result = $this->field($field)->where($where)->find();
+        return $result;
+
+    }//end findAlarm()
+
+
+    /**
+     * 新增工单报警
+     *
+     * @access public
+     * @param mixed $data 数据
+     * @return array 返回类型
+     */
+    public function addAlarm($data)
+    {
+        $result = $this->insert($data);
+        return $result;
+
+    }//end addAlarm()
+
+
+    /**
+     * 修改工单报警
+     *
+     * @access public
+     * @param mixed $where 条件
+     * @param mixed $data 数据
+     * @return array 返回类型
+     */
+    public function updateAlarm($where, $data)
+    {
+        $result = $this->where($where)->update($data);
+        return $result;
+
+    }//end updateAlarm()
+
+
+}

+ 34 - 0
application/index/model/Sensitivewords.php

@@ -0,0 +1,34 @@
+<?php
+namespace app\index\model;
+
+use think\Model;
+
+/**
+ * 敏感词模型
+ */
+class Sensitivewords extends Model
+{
+
+
+    /**
+     * 数据筛选
+     *
+     * @access public
+     * @param mixed $field 字段
+     * @param mixed $where 条件
+     * @return array 返回类型
+     */
+    public function selectWords($field, $where=[])
+    {
+        $result = $this->field($field);
+        if (empty($where) === false) {
+            $result = $result->where($where);
+        }
+
+        $result = $result->select();
+        return $result;
+
+    }//end selectWords()
+
+
+}

+ 27 - 0
application/index/model/Systemconfig.php

@@ -0,0 +1,27 @@
+<?php
+namespace app\index\model;
+
+use think\Model;
+
+/**
+ * 系统设置模型
+ */
+class Systemconfig extends Model
+{
+
+
+    /**
+     * 查询系统设置
+     *
+     * @access public
+     * @return array 返回类型
+     */
+    public function findSystemconfig($where)
+    {
+        $result = $this->where($where)->find();
+        return $result;
+
+    }//end findSystemconfig()
+
+
+}

+ 0 - 1
application/service/controller/Common.php

@@ -25,7 +25,6 @@ class Common extends Base
         $apiToken     = md5(strtolower($action.'Customer-Service'.$controller.strtotime(date('Y-m-d')).$module));
         //print_r([$apiToken,$getApiToken]);die;
         // 验证服务器token.
-
         if ($getApiToken === $apiToken && empty($getUserToken) === false) {
             $usersField          = [
                 'id',

+ 0 - 43
application/service/controller/Index.php

@@ -94,49 +94,6 @@ class Index extends Common
     }//end userWords()
 
 
-    /**
-     * 获取敏感词
-     *
-     * @access public
-     * @return array JsonString
-     */
-    public function sensitiveWords()
-    {
-        // 验证token.
-        $tokenStatus = $this->verifyToken();
-        $code        = -2;
-        $msg         = '错误';
-        if ($tokenStatus === false) {
-            $msg = 'token错误';
-            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
-        }
-
-        try {
-            // 获取快捷语.
-            $wordsField = ['*'];
-            $sysWordsWhere['sensitivewords_status'] = 1;
-            $sysWordsWhere['sensitivewords_for']    = 1;
-            // 查询系统快捷语.
-            $userSensitive = model('sensitivewords')->selectWords($wordsField, $sysWordsWhere);
-            // 获取快捷语.
-            $wordsField = ['*'];
-            $sysWordsWhere['sensitivewords_status'] = 1;
-            $sysWordsWhere['sensitivewords_for']    = 2;
-            // 查询系统快捷语.
-            $serverSensitive = model('sensitivewords')->selectWords($wordsField, $sysWordsWhere);
-            $data            = [
-                'userSensitive'   => $userSensitive,
-                'serverSensitive' => $serverSensitive,
-            ];
-
-            return json(['code' => 1, 'data' => $data, 'msg' => '成功']);
-        } catch (\Exception $e) {
-            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
-        }//end try
-
-    }//end sensitiveWords()
-
-
     public function index()
     {
         $getUserInfo = $this->getUserInfo();

+ 22 - 35
application/service/controller/Upload.php

@@ -7,45 +7,32 @@ class Upload extends Base
     //上传图片
     public function uploadImg()
     {
-        // 验证token.
-        $tokenStatus = $this->verifyToken();
-        $code        = -2;
-        $msg         = '错误';
-        if ($tokenStatus === false) {
-            $msg = 'token错误';
-            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
-        }
-
-        try {
-            $file = request()->file('file');
+        $file = request()->file('file');
 
-            $fileInfo = $file->getInfo();
-            /*if($fileInfo['size'] > 1024 * 1024 * 2){
-                // 上传失败获取错误信息
-                return json( ['code' => -2, 'data' => '', 'msg' => '文件超过2M'] );
-            }*/
+        $fileInfo = $file->getInfo();
+        if ($fileInfo['size'] > 1024 * 512 * 2) {
+            // 上传失败获取错误信息.
+            return json(['code' => -2, 'data' => '', 'msg' => '文件超过0.5M'] );
+        }
 
-            //检测图片格式
-            $ext = explode('.', $fileInfo['name']);
-            $ext = array_pop($ext);
+        //检测图片格式
+        $ext = explode('.', $fileInfo['name']);
+        $ext = array_pop($ext);
 
-            $extArr = explode('|', 'jpg|png|gif|jpeg');
-            if(!in_array($ext, $extArr)){
-                return json(['code' => -3, 'data' => '', 'msg' => '只能上传jpg|png|gif|jpeg的文件']);
-            }
+        $extArr = explode('|', 'jpg|png|gif|jpeg');
+        if(!in_array($ext, $extArr)){
+            return json(['code' => -3, 'data' => '', 'msg' => '只能上传jpg|png|gif|jpeg的文件']);
+        }
 
-            // 移动到框架应用根目录/public/uploads/ 目录下
-            $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
-            if($info){
-                $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
-                return json(['code' => 0, 'data' => ['src' => $src ], 'msg' => '']);
-            }else{
-                // 上传失败获取错误信息
-                return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
-            }
-        } catch (\Exception $e) {
-            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
-        }//end try
+        // 移动到框架应用根目录/public/uploads/ 目录下
+        $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
+        if($info){
+            $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
+            return json(['code' => 0, 'data' => ['src' => $src ], 'msg' => '']);
+        }else{
+            // 上传失败获取错误信息
+            return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
+        }
     }
 
     //上传文件

+ 256 - 0
public/static/customer/js/md5.js

@@ -0,0 +1,256 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << ((len) % 32);
+  x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+
+  for(var i = 0; i < x.length; i += 16)
+  {
+    var olda = a;
+    var oldb = b;
+    var oldc = c;
+    var oldd = d;
+
+    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+
+    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+  }
+  return Array(a, b, c, d);
+
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data)
+{
+  var bkey = str2binl(key);
+  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
+
+  var ipad = Array(16), opad = Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
+  return core_md5(opad.concat(hash), 512 + 128);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str)
+{
+  var bin = Array();
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
+  return bin;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a base-64 string
+ */
+function binl2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
+                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
+                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+    for(var j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+    }
+  }
+  return str;
+}

+ 7 - 3
public/static/customer/js/whisper-cli.js

@@ -27,7 +27,7 @@ if(config != undefined && config.socket != undefined){
         // 登录
         /*var login_data = '{"type":"userInit", "uid": "' + config.uid + '", "name" : "' + config.name +
             '", "avatar" : "' + config.avatar + '", "group" : ' + config.group + '}';*/
-        var login_data = '{"type":"userInit","data":{"uid":"' + config.uid + '","name":"anon_5d1ef6fe753a1","avatar":"","group":1}}';
+        var login_data = '{"type":"userInit","data":{"uid":"' + config.uid + '","name":"'+config.name+'","avatar":"","group":"'+config.group+'"}}';
         console.log(login_data)
         socket.send(login_data);
 
@@ -217,7 +217,11 @@ function sendMsg(sendMsg){
     _html += '<div class="author-name">我 ';
     _html += '<small class="chat-date">' + time + '</small>';
     _html += '</div><div class="chat-text">' + content + '</div></div>';
-
+console.log(JSON.stringify({
+    type: 'chatMessage',
+    data: {to_id: kf_id, to_name: kf_name, content: msg, from_name: config.name,
+        from_id: config.uid, from_avatar: config.avatar, conversationId: 1}
+}))
     // 发送消息
     socket.send(JSON.stringify({
         type: 'chatMessage',
@@ -249,7 +253,7 @@ function sendMsg(sendMsg){
 function showMsg(info, flag){
     // 清除系统消息
     document.getElementsByClassName('whisper-chat-system').innerHTML = '';
-    console.log(info)
+
 
     var _html = document.getElementById('chat-list').innerHTML;
     var content = replaceContent(info.content);

+ 5 - 5
public/static/service/js/whisper.js

@@ -20,13 +20,13 @@ socket.onopen = function (res) {
     /*var login_data = '{"type":"init", "uid":"' + uinfo.id + '", "token":"OTY3NDMwIyRAJSFeKi8xNTYyMzEzOTAwLzE=", "name" : "' + uinfo.username + '", "avatar" : "'
         + uinfo.avatar + '", "group": ' + uinfo.group + '}';*/
 
-    var login_data = '{"type":"init","data":{"uid":"' + uinfo.id + '", "token":"OTY3NDMwIyRAJSFeKi8xNTYyMzEzOTAwLzE=","name":"' + uinfo.username + '","avatar":"","group":1}}';
+    var login_data = '{"type":"init","data":{"uid":"' + uinfo.id + '", "token":"ODMzNDk5IyRAJSFeKi8xNTYyNTc2NDY4LzE=","name":"' + uinfo.username + '","avatar":"","group":1}}';
     socket.send(login_data);
 };
 
 // 监听消息
 socket.onmessage = function (res) {
-    var data = eval("(" + res.data + ")");
+    var data = eval("(" + res.data + ")");console.log(data)
 
     switch (data['message_type']) {
         // 服务端ping客户端
@@ -293,7 +293,7 @@ function sendMessage(sendMsg) {
     socket.send(JSON.stringify({
         type: 'chatMessage',
         data: {to_id: uid, to_name: uname, content: msg, from_name: uinfo.username,
-            from_id: uinfo.id, from_avatar: uinfo.avatar, conversationId: 1}
+            from_id: uinfo.id, from_avatar: uinfo.avatar, conversationId: 49, isFirst: true}
     }));
 
     $("#u-" + uid).append(word);
@@ -309,7 +309,7 @@ function cc() {
 
     socket.send(JSON.stringify({
         type: 'kfCloseUser',
-        data: {to_id: uid}
+        data: {to_id: uid,kf_id:1,group_id:1,conversationId:13}
     }));
 }
 
@@ -340,7 +340,7 @@ function showUserMessage(uinfo, content) {
     if ($('#f-' + uinfo.id).length == 0) {
         addUser(uinfo);
     }
-console.log(content)
+
     // 未读条数计数
     if (!$('#f-' + uinfo.id).hasClass('active')) {
         var num = $('#f-' + uinfo.id).find('span:eq(1)').text();

+ 149 - 17
vendor/GatewayWorker_windows/Applications/whisper/Events.php

@@ -108,6 +108,11 @@ class Events
                 self::overTime();
             });
 
+            // 检查对话时效给出.
+            Timer::add(20, function () {
+                self::systemMonitoring();
+            });
+
 
         }
     }
@@ -165,7 +170,7 @@ class Events
                 'data' => [
                     'name' => '智能助手',
                     'time' => date('H:i'),
-                    'content' => htmlspecialchars($sayHello['0']['word'])
+                    'content' => $sayHello['0']['word']
                 ]
             ];
             Gateway::sendToClient($client_id, json_encode($hello, 256));
@@ -203,6 +208,11 @@ class Events
         $message = json_decode($message, true);
         if (isset($message['type'])) {
             switch ($message['type']) {
+                // 管理员初始化
+                case 'adminInit':
+                    $token = $message['token'];
+                    self::adminInit($client_id, $token);
+                    break;
                 // 客服初始化
                 case 'init':
                     $data = $message['data'];
@@ -224,10 +234,9 @@ class Events
                             'message_type' => 'chatMessage',
                             'data' => [
                                 'name' => $message['data']['from_name'],
-                                'avatar' => $message['data']['from_avatar'],
                                 'id' => $message['data']['from_id'],
                                 'time' => date('H:i'),
-                                'content' => htmlspecialchars($message['data']['content']),
+                                'content' => $message['data']['content'],
                             ]
                         ];
                         Gateway::sendToClient($client['0'], json_encode($chat_message));
@@ -237,7 +246,6 @@ class Events
                         $serviceLog = [
                             'from_id' => $message['data']['from_id'],
                             'from_name' => $message['data']['from_name'],
-                            'from_avatar' => $message['data']['from_avatar'],
                             'to_id' => $message['data']['to_id'],
                             'to_name' => $message['data']['to_name'],
                             'content' => $message['data']['content'],
@@ -248,6 +256,12 @@ class Events
                         self::$db->insert('ws_chat_log')->cols($serviceLog)->query();
                         unset($serviceLog);
                     }
+                    if (isset($message['data']['isFirst']) && $message['data']['isFirst']) {
+                        $servicelog_id = $message['data']['conversationId'];
+                        $serviceLog = self::$db->query("select `start_time` from `ws_service_log` where `servicelog_id`= '$servicelog_id'");
+                        $corresponding = time() - $serviceLog[0]['start_time'];
+                        self::$db->query("update `ws_alarm` set `alarm_corresponding` = '$corresponding',alarm_respond=2 where `servicelog_id`= '$servicelog_id'");
+                    }
                     break;
                 // 转接
                 case 'changeGroup':
@@ -268,7 +282,13 @@ class Events
                     unset($reLink);
 
                     // 记录该客服与该会员的服务结束
-                    self::$db->query("update `ws_service_log` set `end_time` = " . time() . " , `status` = '2' where `client_id`= '" . $userClient . "'");
+                    $servicelog_id = $message['data']['conversationId'];
+                    self::$db->query("update `ws_service_log` set `end_time` = " . time() . " , `status` = '2' where `servicelog_id`= '" . $servicelog_id . "'");
+
+                    // 修改会话时长
+                    $serviceLog = self::$db->query("select `start_time` from `ws_service_log` where `servicelog_id`= '$servicelog_id'");
+                    $cvtOvertime = time() - $serviceLog[0]['start_time'];
+                    self::$db->query("update `ws_alarm` set `alarm_cvtOvertime` = '$cvtOvertime' where `servicelog_id`= '$servicelog_id'");
 
                     // 从当前客服的服务表中删除这个会员
                     $old = $kfList = self::$global->kfList;
@@ -354,15 +374,11 @@ class Events
                     break;
                 // 客服关闭会话.
                 case 'kfCloseUser':
+                    $userId = $message['data']['to_id'];
                     $client = Gateway::getClientIdByUid($userId);
                     if (!empty($client)) {
-                        $userId = $message['data']['to_id'];
-                        $kfId = $message['data']['kf_id'];
-                        $groupId = $message['data']['group_id'];
                         $clientId = $client['0'];
-                        $sql = "select 'servicelog_id' from `ws_service_log` where `user_id`= '$userId' and `client_id`= '$clientId' and `status`!= '2' and `group_id`!= '$groupId' and `kf_id`!= '$kfId'";
-                        $serviceLog = self::$db->query($sql);
-                        self::serverClose($clientId, $serviceLog[0]['servicelog_id']);
+                        self::serverClose($clientId, $message['data']['conversationId']);
                     }
                     break;
                 // 客服更改状态.
@@ -399,7 +415,6 @@ class Events
                     }
             }
         }
-
     }
 
     //获取在线客服列表
@@ -495,6 +510,13 @@ class Events
         }
         self::$db->update('ws_service_log')->cols(['status' => 2, 'end_time' => time()])->where('servicelog_id=' . $oldlog['servicelog_id'])->query();
         unset($oldlog['servicelog_id']);
+
+        // 修改会话时长
+        $servicelog_id = $oldlog['servicelog_id'];
+        $serviceLog = self::$db->query("select `start_time` from `ws_service_log` where `servicelog_id`= '$servicelog_id'");
+        $cvtOvertime = time() - $serviceLog[0]['start_time'];
+        self::$db->query("update `ws_alarm` set `alarm_cvtOvertime` = '$cvtOvertime' where `servicelog_id`= '$servicelog_id'");
+
         $oldlog = array_merge($oldlog, ['kf_id' => intval(trim($toukfid, 'KF')), 'start_time' => time(), 'end_time' => 0, 'status' => 1, 'evaluate_id' => 0]);
         $new_id = self::$db->insert('ws_service_log')->cols($oldlog)->query();
         if (!$new_id) {
@@ -564,7 +586,7 @@ class Events
                     'client_id' => $client_id,
                     'task' => 0,
                     'signature' => $kfinfo['signature'],
-                    'status' => 2,// 1为在线(接收分配、接收消息)2为隐身(不接收分配、只接收消息)
+                    'status' => 2,// 1为在线(接收分配、接收消息)2为隐身(不接收分配、只接收消息)3、休息
                     'user_info' => []
                 ];
             } while (!self::$global->cas('kfList', $kfList, $newKfList));
@@ -585,14 +607,41 @@ class Events
         $_SESSION['uid'] = $message['uid'];
         $_SESSION['name'] = $message['name'];
 
+
         Gateway::joinGroup($client_id, 'group_' . $message['group']);
 
+        $chat_message = [
+            'message_type' => 'loginSuccess',
+        ];
+        Gateway::sendToClient($client_id, json_encode($chat_message, 256));
+        unset($chat_message);
+
+
         self::writeLogKfStatus($message['uid'], 2);
 
         // TODO 尝试拉取用户来服务 [二期规划]
 
     }
 
+
+    /**
+     * 管理员
+     * @param $client_id 服务ID
+     * @param $message 数据
+     */
+    public static function adminInit($client_id, $token)
+    {
+        // 查询token是否存在.
+        $systemConfigData = self::$db->query("SELECT `id` FROM `ws_admins` where `token`= '$token'");
+        if ($systemConfigData) {
+            $adminList = self::$global->adminList;
+            $adminList[] = $client_id;
+            self::$global->adminList = $adminList;
+        } else {
+            Gateway::closeClient($client_id);
+        }
+    }
+
     //客服登陆验证
     public static function KfloginChedk($client, $messageArray)
     {
@@ -698,6 +747,12 @@ class Events
         $uid = isset($_SESSION['uid']) ? $_SESSION['uid'] : false;
         //echo "下线:$uid  - $client_id - $isKefuoff \n";
 
+        $adminList = self::$global->adminList ?? [];
+        $key = array_search($client_id ,$adminList);
+        if (strlen($key)) {
+            array_splice($adminList,$key,1);
+            self::$global->adminList = $adminList;
+        }
         if (empty($uid)) {
             return;
         }
@@ -731,6 +786,12 @@ class Events
                 Gateway::sendToClient($val, json_encode(['type' => 'serviceoffline', 'msg' => '客户人员下线!'], 256));
                 if (isset($simpliUsersID_UID_Arr[$val])) {
                     self::$db->query("update `ws_service_log` set `status` = '2',end_time=$now  where `user_id`= '$simpliUsersID_UID_Arr[$val]' and  kf_id='$uid' and  group_id=$group  and  `status`!=2 ");
+
+                    // 修改会话时长
+                    $serviceLog = self::$db->query("select `start_time`,`servicelog_id` from `ws_service_log` where `user_id`= '$simpliUsersID_UID_Arr[$val]' and  kf_id='$uid' and  group_id=$group  and  `status`!=2");
+                    $servicelog_id = $serviceLog[0]['servicelog_id'];
+                    $cvtOvertime = time() - $serviceLog[0]['start_time'];
+                    self::$db->query("update `ws_alarm` set `alarm_cvtOvertime` = '$cvtOvertime' where `servicelog_id`= '$servicelog_id'");
                 }
                 Gateway::closeClient($val);
             }
@@ -860,6 +921,11 @@ class Events
         //echo "客户退出:". $sql ."\n";
         self::$db->query($sql);
         $isServiceUserOut = false;
+
+        // 修改会话时长
+        $serviceLog = self::$db->query("select `start_time` from `ws_service_log` where `servicelog_id`= '$servicelog_id'");
+        $cvtOvertime = time() - $serviceLog[0]['start_time'];
+        self::$db->query("update `ws_alarm` set `alarm_cvtOvertime` = '$cvtOvertime' where `servicelog_id`= '$servicelog_id'");
         // 将会员服务信息,从客服的服务列表中移除
         $old = $kfList = self::$global->kfList;
         foreach ($kfList as $k => $v) {
@@ -1163,6 +1229,10 @@ class Events
             $hisSession = self::$db->select('*')->from('ws_service_log')->where('user_id=:user_id and kf_id=:kf_id and group_id=:group_id and status in (1,3)')->bindValues(array('user_id' => $res['data']['3']['id'], 'kf_id' => intval(ltrim($res['data']['0'], 'KF')), 'group_id' => $group))->row();
             if (!$hisSession) {
                 $conversationId = self::$db->insert('ws_service_log')->cols($serviceLog)->query();
+                $alarmData = [
+                    'servicelog_id' => $conversationId,
+                ];
+                self::$db->insert('ws_alarm')->cols($alarmData)->query();
             } else {
                 self::$db->update('ws_service_log')->cols(['status' => 1])->where('servicelog_id=' . $hisSession['servicelog_id'])->query();
                 $conversationId = $hisSession['servicelog_id'];
@@ -1194,7 +1264,7 @@ class Events
                         //'avatar' => self::$global->kfList[$group][$res['data']['0']],
                         'id' => $res['data']['0'],
                         'time' => date('H:i'),
-                        'content' => htmlspecialchars($sayHello['0']['word'])
+                        'content' => $sayHello['0']['word']
                     ]
                 ];
                 Gateway::sendToClient($client_id, json_encode($chat_message, 256));
@@ -1463,7 +1533,7 @@ class Events
             'data' => [
                 'name' => '智能助手',
                 'time' => date('H:i'),
-                'content' => $getRobot ? htmlspecialchars($getRobot[0]['robot_content']) : 'error',
+                'content' => $getRobot ? $getRobot[0]['robot_content'] : 'error',
             ]
         ];
         sleep(1);
@@ -1564,7 +1634,7 @@ class Events
                     $chat_message = [
                         'message_type' => 'overtime',
                         'data' => [
-                            'content' => htmlspecialchars(self::$global->unoperated['systemconfig_content']),
+                            'content' => self::$global->unoperated['systemconfig_content'],
                         ]
                     ];
                     Gateway::sendToClient($v['client_id'], json_encode($chat_message, 256));
@@ -1583,7 +1653,7 @@ class Events
                 $chat_message = [
                     'message_type' => 'overtime',
                     'data' => [
-                        'content' => htmlspecialchars(self::$global->overtime['systemconfig_content']),
+                        'content' => self::$global->overtime['systemconfig_content'],
                     ]
                 ];
                 $found_key = array_search($v['servicelog_id'], array_column($serviceLog, 'servicelog_id'));
@@ -1592,6 +1662,68 @@ class Events
         }
     }
 
+    /**
+     * 系统监控
+     * @param $message 数据
+     */
+    private static function systemMonitoring()
+    {
+        print_r(["select * from `ws_service_log` join `ws_alarm` on `ws_service_log.servicelog_id`=`ws_alarm.servicelog_id` WHERE `status`='1' OR `status`='3'"]);
+        // 查询未结束工单.
+        $serviceLog = self::$db->query("select * from `ws_service_log` join `ws_alarm` on `ws_service_log.servicelog_id`=`ws_alarm.servicelog_id` WHERE `status`='1' OR `status`='3'");
+        // 查询系统设置表.
+        /*$systemconfig = self::$db->query("SELECT `systemconfig_data` FROM `ws_systemconfig` WHERE `systemconfig_enName`='verifyReturnTime' or `systemconfig_enName`='verifyAllTime'");
+        $found_key = array_search('verifyReturnTime', array_column($systemconfig, 'systemconfig_enName'));
+        // 质检会话响应时长.
+        $verifyReturnTime = $systemconfig[$found_key]['systemconfig_data'];
+        $found_key = array_search('verifyAllTime', array_column($systemconfig, 'systemconfig_enName'));
+        // 质检会话时长.
+        $verifyAllTime = $systemconfig[$found_key]['systemconfig_data'];
+        // 差评次数.
+        $evaluateCount = 0;
+        // 未结束工单id.
+        $servicelog_ids = '';
+        $overtimeNumber = 0; // 会话超时次数.
+        $overtimeTime = []; // 会话超时时间.
+        $userSensitive = 0; // 用户敏感词报警次数.
+        $serverSensitive = 0; // 客服敏感词报警次数.
+        $csdNumber = 0; // 响应超时次数.
+        $csdTime = []; // 响应超时时间.
+        foreach ($serviceLog  as $k => $v) {
+            // 差评次数.
+            if ($v['evaluate_id'] == 3) {
+                $evaluateCount++;
+            }
+            $duration = time() - $v['start_time'];
+            // 会话超时.
+            if ($duration > $verifyAllTime) {
+                $overtimeNumber++;
+                $overtimeTime[] = $duration;
+            }
+            // 敏感词报警.
+            $userSensitive += $v['alarm_userSensitive'];
+            $serverSensitive += $v['alarm_serverSensitive'];
+            // 响应超时.
+            if ($v['alarm_corresponding'] > $verifyReturnTime) {
+                $csdTime[] = $v['alarm_corresponding'];
+                $csdNumber++;
+            }
+        }*/
+        print_r(["select * from `ws_service_log` join `ws_alarm` on `ws_service_log.servicelog_id`=`ws_alarm.servicelog_id` WHERE `status`='1' OR `status`='3'"]);
+        // 查询对话时效设置.
+        /*$adminList = self::$global->adminList ?? [];
+        foreach ($adminList as $v) {
+            $chat_message = [
+                'message_type' => 'overtime',
+                'data' => [
+                    '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));
+        }*/
+    }
+
 
     //客服在线状态写组
     private static function writeLogKfStatus($kf, $status, $flag = 1)