index.html 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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. <style>
  19. dl dd{
  20. height: 30px;
  21. }
  22. input.layui-input.layui-unselect {
  23. height: 30px;
  24. }
  25. </style>
  26. <body class="gray-bg">
  27. <div class="wrapper wrapper-content">
  28. <div class="row">
  29. <div class="col-sm-2">
  30. <div class="ibox float-e-margins">
  31. <div class="ibox-title" style="display: flex; justify-content: center;">
  32. <!--<span class="label label-primary pull-right">今天</span>-->
  33. <h3>敏感词报警</h3>
  34. </div>
  35. <div class="ibox-content" style="text-align: center">
  36. <h1 class="no-margins"><span id="allSensitive">0</span><span style="font-size: 14px; margin-left: 10px">次</span></h1>
  37. <small></small>
  38. </div>
  39. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px;">
  40. <div style="justify-content: center; display: flex">
  41. <div style="text-align: right;">访客次数</div>
  42. <div style="margin-left: 20px; width: 30px" id="userSensitive">0</div>
  43. </div>
  44. <div style="justify-content: center; display: flex">
  45. <div style="text-align: right;">客服次数</div>
  46. <div style="margin-left: 20px; width: 30px" id="serverSensitive">0</div>
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. <div class="col-sm-2">
  52. <div class="ibox float-e-margins">
  53. <div class="ibox-title" style="display: flex; justify-content: center;">
  54. <!--<span class="label label-primary pull-right">今天</span>-->
  55. <h3>平均响应超时</h3>
  56. </div>
  57. <div class="ibox-content" style="text-align: center">
  58. <h1 class="no-margins"><span id="csdTime">0</span><span style="font-size: 14px; margin-left: 10px">秒</span></h1>
  59. <small></small>
  60. </div>
  61. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  62. <div style="justify-content: center; display: flex">
  63. <div style="text-align: right;">响应超时次数</div>
  64. <div style="margin-left: 20px; text-align: right;" id="csdNumber">0</div>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. <div class="col-sm-2">
  70. <div class="ibox float-e-margins">
  71. <div class="ibox-title" style="display: flex; justify-content: center;">
  72. <!--<span class="label label-primary pull-right">今天</span>-->
  73. <h3>平均会话超时</h3>
  74. </div>
  75. <div class="ibox-content" style="text-align: center">
  76. <h1 class="no-margins"><span id="overtimeTime">0</span><span style="font-size: 14px; margin-left: 10px">秒</span></h1>
  77. <small></small>
  78. </div>
  79. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  80. <div style="justify-content: center; display: flex">
  81. <div style="text-align: right;">会话超时次数</div>
  82. <div style="margin-left: 20px; text-align: right;" id="overtimeNumber">0</div>
  83. </div>
  84. </div>
  85. </div>
  86. </div>
  87. <div class="col-sm-2">
  88. <div class="ibox float-e-margins">
  89. <div class="ibox-title" style="display: flex; justify-content: center;">
  90. <!--<span class="label label-primary pull-right">今天</span>-->
  91. <h3>满意度报警</h3>
  92. </div>
  93. <div class="ibox-content" style="text-align: center">
  94. <h1 class="no-margins"><span id="evaluateCount1">0</span><span style="font-size: 14px; margin-left: 10px">次</span></h1>
  95. <small></small>
  96. </div>
  97. <div class="ibox-content" style="font-size: 12px; padding: 5px 20px 5px; height: 45px; line-height: 3;">
  98. <div style="justify-content: center; display: flex">
  99. <div style="text-align: right;">不满意次数</div>
  100. <div style="margin-left: 20px; text-align: right;" id="evaluateCount2">0</div>
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <div class="ibox float-e-margins">
  107. <input style="display:none;" type="text" value="1" id="type">
  108. <div style="display: flex;">
  109. <div class="ibox-title" style="width: 100px; cursor:pointer;" id="current1" onclick="current(1)">
  110. <h5>当前会话</h5>
  111. </div>
  112. <div class="ibox-title" id="current2" style="width: 100px; cursor:pointer; background: #eee" onclick="current(2)">
  113. <h5>登陆客服</h5>
  114. </div>
  115. <div class="ibox-title" style="width: calc(100% - 200px); background: #eee;">
  116. </div>
  117. </div>
  118. <div class="ibox-content">
  119. <!--搜索框开始-->
  120. <form id="realTimeForm" role="form" method="post" class="form-inline">
  121. <div class="content clearfix m-b">
  122. <div class="form-group" style="margin-top: 5px;">
  123. <label>分组名称:</label>
  124. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  125. <input type="hidden" id="group_id"/>
  126. <select lay-verify="required" lay-filter="group">
  127. <option value="">全部客服组</option>
  128. {if !empty($groups)}
  129. {foreach name="groups" item="vo"}
  130. <option value="{$vo['id']}">{$vo['name']}</option>
  131. {/foreach}
  132. {/if}
  133. </select>
  134. </div>
  135. </div>
  136. <div class="form-group" style="margin-left: 40px;margin-top: 5px;">
  137. <label>报警状态:</label>
  138. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  139. <input type="hidden" id="alarm_id"/>
  140. <select lay-verify="required" lay-filter="alarm">
  141. <option value="">所有会话</option>
  142. <option value="1">正常会话</option>
  143. <option value="2">报警会话</option>
  144. </select>
  145. </div>
  146. </div>
  147. </div>
  148. </form>
  149. <!--搜索框结束-->
  150. <div id="realTimeTable" class="example-wrap">
  151. <div class="example">
  152. <table class="table table-hover table-striped">
  153. <thead>
  154. <tr>
  155. <th>会话ID</th>
  156. <th>访客进线时间</th>
  157. <th>接待客服</th>
  158. <th>访客名</th>
  159. <th>会话开始时间</th>
  160. <th>报警次数</th>
  161. <th>操作</th>
  162. </tr>
  163. </thead>
  164. <tbody id="table">
  165. <tr>
  166. <td colspan="999" style="text-align: center">暂无数据</td>
  167. </tr>
  168. </tbody>
  169. </table>
  170. </div>
  171. </div>
  172. <!-- End Example Pagination -->
  173. <!--搜索框开始-->
  174. <form id='commentForm' style="display: none" role="form" method="get" class="form-inline">
  175. <div class="content clearfix m-b">
  176. <div class="form-group">
  177. <label>分组名称:</label>
  178. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  179. <select lay-verify="required" lay-filter="group" name="type1" id="type1">
  180. <option value="">全部客服组</option>
  181. {if !empty($groups)}
  182. {foreach name="groups" item="vo"}
  183. <option value="{$vo['id']}">{$vo['name']}</option>
  184. {/foreach}
  185. {/if}
  186. </select>
  187. </div>
  188. </div>
  189. <div class="form-group" style="margin-left: 40px">
  190. <label>登陆状态:</label>
  191. <div class="input-group col-sm-4 layui-form" style="width: 120px;">
  192. <select lay-verify="required" lay-filter="alarm" name="type2" id="type2">
  193. <option value="">所有状态</option>
  194. <option value="1">在线状态</option>
  195. <option value="3">休息状态</option>
  196. <option value="2">隐身状态</option>
  197. </select>
  198. </div>
  199. </div>
  200. <div class="form-group" style="display: none">
  201. <lable>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</lable>
  202. <select name="type3" id="type3" class="form-control">
  203. <option value="0">所有会话</option>
  204. <option value="1">正常会话</option>
  205. <option value="2">报警回话</option>
  206. </select>
  207. </div>
  208. <div class="form-group">
  209. <lable>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</lable>
  210. <button class="btn btn-primary btn-sm" type="button" style="margin-top:5px" id="search">搜索
  211. </button>
  212. </div>
  213. </div>
  214. </form>
  215. <!--搜索框结束-->
  216. <div id="commentTable" style="display: none" class="example-wrap">
  217. <div class="example">
  218. <table id="cusTable">
  219. <thead>
  220. <th data-field="uidname">客服</th>
  221. <th data-field="ip">IP</th>
  222. <th data-field="status">状态</th>
  223. <th data-field="hhl">当前会话量</th>
  224. <th data-field="jdl">今日接待量</th>
  225. <th data-field="pjhysc">今日平均会话时长</th>
  226. <th data-field="cpl">今日参评率</th>
  227. <th data-field="mydl">今日满意度</th>
  228. <th data-field="pjxysc">今日平均响应时长</th>
  229. <th data-field="jrxxsc">今日休息时长</th>
  230. <th data-field="fxx">发消息</th>
  231. </thead>
  232. </table>
  233. </div>
  234. </div>
  235. <!-- End Example Pagination -->
  236. </div>
  237. </div>
  238. </div>
  239. <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
  240. <script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  241. <script src="/static/admin/js/plugins/echarts/echarts.min.js"></script>
  242. <script src="/static/customer/js/md5.js"></script>
  243. <script src="__JS__/jquery.min.js?v=2.1.4"></script>
  244. <script src="__JS__/bootstrap.min.js?v=3.3.6"></script>
  245. <script src="__JS__/content.min.js?v=1.0.0"></script>
  246. <script src="__JS__/plugins/bootstrap-table/bootstrap-table.min.js"></script>
  247. <script src="__JS__/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
  248. <script src="__JS__/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
  249. <script src="__JS__/plugins/layer/layer.min.js"></script>
  250. <script src="__JS__/plugins/validate/jquery.validate.min.js"></script>
  251. <script src="__JS__/plugins/validate/messages_zh.min.js"></script>
  252. <script src="__JS__/layui/layui.js"></script>
  253. <script src="__JS__/jquery.form.js"></script>
  254. <script type="text/javascript">
  255. function current(id) {
  256. $("#type").val(id);
  257. if (id == 1) {
  258. $("#current1").css("background","#fff");
  259. $("#current2").css("background","#eee");
  260. $("#realTimeForm").css("display","block");
  261. $("#realTimeTable").css("display","block");
  262. $("#commentForm").css("display","none");
  263. $("#commentTable").css("display","none");
  264. } else if (id == 2) {
  265. $("#current2").css({"background":"#fff"});
  266. $("#current1").css({"background":"#eee"});
  267. $("#realTimeForm").css({"display":"none"});
  268. $("#realTimeTable").css({"display":"none"});
  269. $("#commentForm").css({"display":"block"});
  270. $("#commentTable").css({"display":"block"});
  271. initTable()
  272. }
  273. }
  274. layui.use(['form', 'upload'], function(){
  275. var form = layui.form;
  276. form.on('select(group)', function(value){
  277. $("#group_id").val(value.value);
  278. onSearch()
  279. });
  280. form.on('select(alarm)', function(value){
  281. $("#alarm_id").val(value.value);
  282. onSearch()
  283. });
  284. });
  285. function initTable() {
  286. //先销毁表格
  287. $('#cusTable').bootstrapTable('destroy');
  288. //初始化表格,动态从服务器加载数据
  289. $("#cusTable").bootstrapTable({
  290. method: "get", //使用get请求到服务器获取数据
  291. url: "{:url('kfonitoring/kfjiankong')}", //获取数据的地址
  292. striped: true, //表格显示条纹
  293. pagination: true, //启动分页
  294. pageSize: 50, //每页显示的记录数
  295. pageNumber: 1, //当前第几页
  296. pageList: [20, 50], //记录数可选列表
  297. sidePagination: "server", //表示服务端请求
  298. paginationFirstText: "首页",
  299. paginationPreText: "上一页",
  300. paginationNextText: "下一页",
  301. paginationLastText: "尾页",
  302. queryParamsType: "undefined",
  303. queryParams: function queryParams(params) { //设置查询参数
  304. var param = {
  305. pageNumber: params.pageNumber,
  306. pageSize: params.pageSize,
  307. searchText: $('#type1').val() + ',' + $('#type2').val() + ',' + $('#type3').val()
  308. };
  309. return param;
  310. },
  311. onLoadSuccess: function (res) { //加载成功时执行
  312. if (111 == res.code) {
  313. window.location.reload();
  314. }
  315. layer.msg("加载成功", {time: 1000});
  316. },
  317. onLoadError: function () { //加载失败时执行
  318. layer.msg("加载数据失败");
  319. }
  320. });
  321. }
  322. $(document).ready(function () {
  323. //调用函数,初始化表格
  324. initTable();
  325. //当点击查询按钮的时候执行
  326. $("#search").bind("click", initTable);
  327. });
  328. </script>
  329. <!--webSocket-->
  330. <script>
  331. let config = {
  332. socket: '{$socket}',
  333. token: '{$token}',
  334. };
  335. let myData = [];
  336. let date = new Date(new Date().setHours(0, 0, 0, 0)) / 1000;
  337. let getLocation = window.location.href;
  338. let host = getLocation.split('/admin')[0];
  339. //let apiToken = hex_md5('customer-service'+date+host);
  340. let apiToken = hex_md5('customer-service'+host);
  341. let socket = new WebSocket('ws://' + config.socket+'?apiToken=' + apiToken);
  342. socket.onopen = function(res) {
  343. console.log('握手成功');
  344. // 登录
  345. let login_data = JSON.stringify({
  346. type: 'adminInit',
  347. token: config.token
  348. });
  349. socket.send(login_data);
  350. };
  351. // 心跳检测.
  352. setInterval(function(){
  353. socket.send(JSON.stringify({
  354. type: 'ping',
  355. }));
  356. }, 5000);
  357. socket.onmessage = function(res) {
  358. var data = eval("("+res.data+")");
  359. switch(data['message_type']){
  360. // 服务端ping客户端
  361. case 'monitor':
  362. myData = data.data.cvtList;
  363. putMonitor(data.data);
  364. break;
  365. }
  366. };
  367. socket.onclose = function(res) {
  368. layer.alert('实时监控连接失败', {
  369. title: '错误提示', icon: 2, closeBtn: 0
  370. }, '');
  371. };
  372. /**
  373. * 时间戳转化为年 月 日 时 分 秒
  374. * time: 传入时间戳
  375. * format:返回格式,支持自定义,但参数必须与formateArr里保持一致
  376. */
  377. function customFormatDateTime(timeStamp,custom,isDtae) {
  378. var date = new Date();
  379. date.setTime(timeStamp * 1000);
  380. var y = date.getFullYear();
  381. var m = date.getMonth() + 1;
  382. m = m < 10 ? ('0' + m) : m;
  383. var d = date.getDate();
  384. d = d < 10 ? ('0' + d) : d;
  385. var h = date.getHours();
  386. h = h < 10 ? ('0' + h) : h;
  387. var minute = date.getMinutes();
  388. var second = date.getSeconds();
  389. minute = minute < 10 ? ('0' + minute) : minute;
  390. second = second < 10 ? ('0' + second) : second;
  391. if (isDtae == 0){
  392. return y + custom + m //+'student';
  393. }else if (isDtae ==1){
  394. return y + custom + m + custom + d;
  395. } else if (isDtae ==2) {
  396. return h + ':' + minute;
  397. } else {
  398. return y + '-' + m + '-' + d + '-' + h + ':' + minute + ':' + second;
  399. }
  400. };
  401. function onSearch() {
  402. let table = "";
  403. let cvtList = searchData();
  404. for(key in cvtList){
  405. let start_time = cvtList[key].start_time;
  406. let intime = cvtList[key].intime
  407. if (key != "length") {
  408. table += "<tr>" +
  409. "<td>"+cvtList[key].servicelog_id+"</td>" +
  410. "<td>"+customFormatDateTime(intime,'',2)+"</td>" +
  411. "<td>"+cvtList[key].server_name+"</td>" +
  412. "<td>"+cvtList[key].user_name+"</td>" +
  413. "<td>"+customFormatDateTime(start_time,'',2)+"</td>" +
  414. "<td>"+cvtList[key].allCount+"</td>" +
  415. "<td>" +
  416. "<a href='/admin/system/detail/id/"+cvtList[key].servicelog_id+"/type/onLine.html'>" +
  417. "<button type='button' class='btn btn-primary btn-sm'>" +
  418. " 详情" +
  419. "</button>" +
  420. "</a>" +
  421. "</td>" +
  422. "</tr>"
  423. }
  424. }
  425. if (table) {
  426. $("#table").html(table);
  427. } else {
  428. $("#table").html("<tr>" +
  429. "<td colspan='6' style='text-align: center'>暂无数据</td>" +
  430. "</tr>");
  431. }
  432. }
  433. function searchData() {
  434. let group_id = $("#group_id").val();
  435. let alarm_id = $("#alarm_id").val();
  436. let newData = [];
  437. if (group_id && alarm_id) {
  438. if (alarm_id == 1) {
  439. for (keys in myData) {
  440. if (group_id == myData[keys].group_id && !myData[keys].allCount) {
  441. newData.push(myData[keys])
  442. }
  443. }
  444. } else if (alarm_id == 2) {
  445. for (keys in myData) {
  446. if (group_id == myData[keys].group_id && myData[keys].allCount) {
  447. newData.push(myData[keys])
  448. }
  449. }
  450. }
  451. } else if(group_id) {
  452. for (keys in myData) {
  453. if (group_id == myData[keys].group_id) {
  454. newData.push(myData[keys])
  455. }
  456. }
  457. } else if(alarm_id) {
  458. if (alarm_id == 1) {
  459. for (keys in myData) {
  460. if (!myData[keys].allCount) {
  461. newData.push(myData[keys])
  462. }
  463. }
  464. } else if (alarm_id == 2) {
  465. for (keys in myData) {
  466. if (myData[keys].allCount) {
  467. newData.push(myData[keys])
  468. }
  469. }
  470. }
  471. } else {
  472. newData = myData
  473. }
  474. return newData;
  475. }
  476. function msg(id) {
  477. layui.use('layer', function () {
  478. layer.open({
  479. type: 2,
  480. title: '请输入消息内容',
  481. area: ['500px', '600px'], //自定义文本域宽高
  482. content:'/admin/kfnotice/add.html?uid='+id
  483. });
  484. }
  485. )
  486. }
  487. // 渲染
  488. function putMonitor(data) {
  489. $("#allSensitive").html(data.userSensitive + data.serverSensitive);
  490. $("#userSensitive").html(data.userSensitive);
  491. $("#serverSensitive").html(data.serverSensitive);
  492. $("#csdNumber").html(data.csdNumber);
  493. $("#overtimeNumber").html(data.overtimeNumber);
  494. $("#evaluateCount1").html(data.evaluateCount);
  495. $("#evaluateCount2").html(data.evaluateCount);
  496. // 响应超时.
  497. let n = data.csdTime.length;
  498. let csdTime = 0;
  499. for(keys in data.csdTime){
  500. csdTime += data.csdTime[keys]
  501. }
  502. csdTime = csdTime ? Math.ceil(csdTime/n) : 0;
  503. $("#csdTime").html(csdTime);
  504. // 会话超时.
  505. let m = data.overtimeTime.length;
  506. let overtimeTime = 0;
  507. for(keys in data.overtimeTime){
  508. overtimeTime += data.overtimeTime[keys]
  509. }
  510. overtimeTime = overtimeTime ? Math.ceil(overtimeTime/m) : 0;
  511. $("#overtimeTime").html(overtimeTime);
  512. onSearch();
  513. }
  514. </script>
  515. </body>
  516. </html>