index.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>后台首页</title>
  7. <link rel="shortcut icon" href="favicon.ico">
  8. <link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  9. <link href="https://cdn.staticfile.org/font-awesome/4.4.0/css/font-awesome.css?v=4.4.0" rel="stylesheet">
  10. <link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  11. <link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
  12. <link href="__CSS__/font-awesome.min.css?v=4.4.0" rel="stylesheet">
  13. <link href="__CSS__/plugins/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
  14. <link href="__CSS__/animate.min.css" rel="stylesheet">
  15. <link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
  16. <link href="__JS__/layui/css/myLayui.css" rel="stylesheet">
  17. </head>
  18. <body class="gray-bg">
  19. <div class="wrapper wrapper-content">
  20. <div class="row">
  21. <div class="col-sm-2">
  22. <div class="ibox float-e-margins">
  23. <div class="ibox-title" style="display: flex; justify-content: center;">
  24. <!--<span class="label label-primary pull-right">今天</span>-->
  25. <h3>敏感词报警</h3>
  26. </div>
  27. <div class="ibox-content" style="text-align: center">
  28. <h1 class="no-margins"><span id="allSensitive">0</span><span style="font-size: 14px; margin-left: 10px">次</span></h1>
  29. <small></small>
  30. </div>
  31. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px;">
  32. <div style="display: flex">
  33. <div style="width: 80px; text-align: right;">访客次数</div>
  34. <div style="margin-left: 20px; text-align: right;" id="userSensitive">0</div>
  35. </div>
  36. <div style="display: flex">
  37. <div style="width: 80px; text-align: right;">客服次数</div>
  38. <div style="margin-left: 20px; text-align: right;" id="serverSensitive">0</div>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. <div class="col-sm-2">
  44. <div class="ibox float-e-margins">
  45. <div class="ibox-title" style="display: flex; justify-content: center;">
  46. <!--<span class="label label-primary pull-right">今天</span>-->
  47. <h3>平均响应超时</h3>
  48. </div>
  49. <div class="ibox-content" style="text-align: center">
  50. <h1 class="no-margins"><span id="csdTime">0</span><span style="font-size: 14px; margin-left: 10px">秒</span></h1>
  51. <small></small>
  52. </div>
  53. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  54. <div style="display: flex">
  55. <div style="width: 80px; text-align: right;">响应超时次数</div>
  56. <div style="margin-left: 20px; text-align: right;" id="csdNumber">0</div>
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. <div class="col-sm-2">
  62. <div class="ibox float-e-margins">
  63. <div class="ibox-title" style="display: flex; justify-content: center;">
  64. <!--<span class="label label-primary pull-right">今天</span>-->
  65. <h3>平均会话超时</h3>
  66. </div>
  67. <div class="ibox-content" style="text-align: center">
  68. <h1 class="no-margins"><span id="overtimeTime">0</span><span style="font-size: 14px; margin-left: 10px">秒</span></h1>
  69. <small></small>
  70. </div>
  71. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  72. <div style="display: flex">
  73. <div style="width: 80px; text-align: right;">会话超时次数</div>
  74. <div style="margin-left: 20px; text-align: right;" id="overtimeNumber">0</div>
  75. </div>
  76. </div>
  77. </div>
  78. </div>
  79. <div class="col-sm-2">
  80. <div class="ibox float-e-margins">
  81. <div class="ibox-title" style="display: flex; justify-content: center;">
  82. <!--<span class="label label-primary pull-right">今天</span>-->
  83. <h3>满意度报警</h3>
  84. </div>
  85. <div class="ibox-content" style="text-align: center">
  86. <h1 class="no-margins"><span id="evaluateCount1">0</span><span style="font-size: 14px; margin-left: 10px">次</span></h1>
  87. <small></small>
  88. </div>
  89. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  90. <div style="display: flex">
  91. <div style="width: 80px; text-align: right;">不满意次数</div>
  92. <div style="margin-left: 20px; text-align: right;" id="evaluateCount2">0</div>
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. </div>
  98. <div class="ibox float-e-margins">
  99. <div class="ibox-title">
  100. <h5>会话监控</h5>
  101. </div>
  102. <div class="ibox-content">
  103. <!--搜索框开始-->
  104. <form id='commentForm' role="form" method="post" class="form-inline">
  105. <div class="content clearfix m-b">
  106. <div class="form-group">
  107. <label>分组名称:</label>
  108. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  109. <input type="hidden" id="group_id"/>
  110. <select lay-verify="required" lay-filter="group">
  111. <option value="">全部客服组</option>
  112. {if !empty($groups)}
  113. {foreach name="groups" item="vo"}
  114. <option value="{$vo['id']}">{$vo['name']}</option>
  115. {/foreach}
  116. {/if}
  117. </select>
  118. </div>
  119. </div>
  120. <div class="form-group" style="margin-left: 40px">
  121. <label>报警状态:</label>
  122. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  123. <input type="hidden" id="alarm_id"/>
  124. <select lay-verify="required" lay-filter="alarm">
  125. <option value="">所有会话</option>
  126. <option value="1">正常会话</option>
  127. <option value="2">报警会话</option>
  128. </select>
  129. </div>
  130. </div>
  131. </div>
  132. </form>
  133. <!--搜索框结束-->
  134. <div class="example-wrap">
  135. <div class="example">
  136. <table id="cusTable" class="table table-hover table-striped">
  137. <thead>
  138. <tr>
  139. <th>会话ID</th>
  140. <th>访客进线时间</th>
  141. <th>接待客服</th>
  142. <th>访客名</th>
  143. <th>会话开始时间</th>
  144. <th>报警次数</th>
  145. <th>操作</th>
  146. </tr>
  147. </thead>
  148. <tbody id="table">
  149. <tr>
  150. <td colspan="999" style="text-align: center">暂无数据</td>
  151. </tr>
  152. </tbody>
  153. </table>
  154. </div>
  155. </div>
  156. <!-- End Example Pagination -->
  157. </div>
  158. </div>
  159. </div>
  160. <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
  161. <script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  162. <script src="/static/admin/js/plugins/echarts/echarts.min.js"></script>
  163. <script src="/static/customer/js/md5.js"></script>
  164. <script src="__JS__/jquery.min.js?v=2.1.4"></script>
  165. <script src="__JS__/bootstrap.min.js?v=3.3.6"></script>
  166. <script src="__JS__/content.min.js?v=1.0.0"></script>
  167. <script src="__JS__/plugins/bootstrap-table/bootstrap-table.min.js"></script>
  168. <script src="__JS__/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
  169. <script src="__JS__/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
  170. <script src="__JS__/plugins/layer/layer.min.js"></script>
  171. <script src="__JS__/plugins/validate/jquery.validate.min.js"></script>
  172. <script src="__JS__/plugins/validate/messages_zh.min.js"></script>
  173. <script src="__JS__/layui/layui.js"></script>
  174. <script src="__JS__/jquery.form.js"></script>
  175. <script type="text/javascript">
  176. layui.use(['form', 'upload'], function(){
  177. var form = layui.form;
  178. form.on('select(group)', function(value){
  179. $("#group_id").val(value.value);
  180. onSearch()
  181. });
  182. form.on('select(alarm)', function(value){
  183. $("#alarm_id").val(value.value);
  184. onSearch()
  185. });
  186. });
  187. </script>
  188. <!--webSocket-->
  189. <script>
  190. let config = {
  191. socket: '{$socket}',
  192. token: '{$token}',
  193. };
  194. let myData = [];
  195. let date = new Date(new Date().setHours(0, 0, 0, 0)) / 1000;
  196. let getLocation = window.location.href;
  197. let host = getLocation.split('/admin')[0];
  198. let apiToken = hex_md5('customer-service'+date+host);
  199. let socket = new WebSocket('ws://' + config.socket+'?apiToken=' + apiToken);
  200. socket.onopen = function(res) {
  201. console.log('握手成功');
  202. // 登录
  203. let login_data = JSON.stringify({
  204. type: 'adminInit',
  205. token: config.token
  206. });
  207. socket.send(login_data);
  208. };
  209. socket.onmessage = function(res) {
  210. var data = eval("("+res.data+")");
  211. switch(data['message_type']){
  212. // 服务端ping客户端
  213. case 'monitor':
  214. myData = data.data.cvtList;
  215. putMonitor(data.data);
  216. break;
  217. }
  218. };
  219. /**
  220. * 时间戳转化为年 月 日 时 分 秒
  221. * time: 传入时间戳
  222. * format:返回格式,支持自定义,但参数必须与formateArr里保持一致
  223. */
  224. function customFormatDateTime(timeStamp,custom,isDtae) {
  225. var date = new Date();
  226. date.setTime(timeStamp * 1000);
  227. var y = date.getFullYear();
  228. var m = date.getMonth() + 1;
  229. m = m < 10 ? ('0' + m) : m;
  230. var d = date.getDate();
  231. d = d < 10 ? ('0' + d) : d;
  232. var h = date.getHours();
  233. h = h < 10 ? ('0' + h) : h;
  234. var minute = date.getMinutes();
  235. var second = date.getSeconds();
  236. minute = minute < 10 ? ('0' + minute) : minute;
  237. second = second < 10 ? ('0' + second) : second;
  238. if (isDtae == 0){
  239. return y + custom + m //+'student';
  240. }else if (isDtae ==1){
  241. return y + custom + m + custom + d;
  242. } else if (isDtae ==2) {
  243. return h + ':' + minute;
  244. } else {
  245. return y + '-' + m + '-' + d + '-' + h + ':' + minute + ':' + second;
  246. }
  247. };
  248. function onSearch() {
  249. let table = "";
  250. let cvtList = searchData();
  251. for(key in cvtList){
  252. let start_time = cvtList[key].start_time;
  253. let intime = cvtList[key].intime
  254. if (key != "length") {
  255. table += "<tr>" +
  256. "<td>"+cvtList[key].servicelog_id+"</td>" +
  257. "<td>"+customFormatDateTime(intime,'',2)+"</td>" +
  258. "<td>"+cvtList[key].server_name+"</td>" +
  259. "<td>"+cvtList[key].user_name+"</td>" +
  260. "<td>"+customFormatDateTime(start_time,'',2)+"</td>" +
  261. "<td>"+cvtList[key].allCount+"</td>" +
  262. "<td>" +
  263. "<a href='/admin/system/detail/id/"+cvtList[key].servicelog_id+".html'>" +
  264. "<button type='button' class='btn btn-primary btn-sm'>" +
  265. "<i class='fa fa-paste'></i> 详情" +
  266. "</button>" +
  267. "</a>" +
  268. "</td>" +
  269. "</tr>"
  270. }
  271. }
  272. if (table) {
  273. $("#table").html(table);
  274. } else {
  275. $("#table").html("<tr>" +
  276. "<td colspan='6' style='text-align: center'>暂无数据</td>" +
  277. "</tr>");
  278. }
  279. }
  280. function searchData() {
  281. let group_id = $("#group_id").val();
  282. let alarm_id = $("#alarm_id").val();
  283. let newData = [];
  284. if (group_id && alarm_id) {
  285. if (alarm_id == 1) {
  286. for (keys in myData) {
  287. if (group_id == myData[key].group_id && !myData[key].allCount) {
  288. newData.push(myData[key])
  289. }
  290. }
  291. } else if (alarm_id == 2) {
  292. for (keys in myData) {
  293. if (group_id == myData[key].group_id && myData[key].allCount) {
  294. newData.push(myData[key])
  295. }
  296. }
  297. }
  298. } else if(group_id) {
  299. for (keys in myData) {
  300. if (group_id == myData[key].group_id) {
  301. newData.push(myData[key])
  302. }
  303. }
  304. } else if(alarm_id) {
  305. if (alarm_id == 1) {
  306. for (keys in myData) {
  307. if (!myData[key].allCount) {
  308. newData.push(myData[key])
  309. }
  310. }
  311. } else if (alarm_id == 2) {
  312. for (keys in myData) {
  313. if (myData[key].allCount) {
  314. newData.push(myData[key])
  315. }
  316. }
  317. }
  318. } else {
  319. newData = myData
  320. }
  321. return newData;
  322. }
  323. // 渲染
  324. function putMonitor(data) {
  325. $("#allSensitive").html(data.userSensitive + data.serverSensitive);
  326. $("#userSensitive").html(data.userSensitive);
  327. $("#serverSensitive").html(data.serverSensitive);
  328. $("#csdNumber").html(data.csdNumber);
  329. $("#overtimeNumber").html(data.overtimeNumber);
  330. $("#evaluateCount1").html(data.evaluateCount);
  331. $("#evaluateCount2").html(data.evaluateCount);
  332. // 响应超时.
  333. let n = data.csdTime.length;
  334. let csdTime = 0;
  335. for(keys in data.csdTime){
  336. csdTime += data.csdTime[keys]
  337. }
  338. csdTime = csdTime ? Math.ceil(csdTime/n) : 0;
  339. $("#csdTime").html(csdTime);
  340. // 会话超时.
  341. let m = data.overtimeTime.length;
  342. let overtimeTime = 0;
  343. for(keys in data.overtimeTime){
  344. overtimeTime += data.overtimeTime[keys]
  345. }
  346. overtimeTime = overtimeTime ? Math.ceil(overtimeTime/m) : 0;
  347. $("#overtimeTime").html(overtimeTime);
  348. onSearch();
  349. }
  350. </script>
  351. </body>
  352. </html>