whisper.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. var uinfo = {
  2. id: 'KF' + uid,
  3. username: uname,
  4. avatar: avatar,
  5. group: group
  6. };
  7. // 创建一个Socket实例
  8. var socket = new WebSocket('wss://' + socket_server+'?apiToken=8444fb09eec653b322a4ad74b836aed0');
  9. // 打开Socket
  10. socket.onopen = function (res) {
  11. layui.use(['layer'], function () {
  12. var layer = layui.layer;
  13. layer.ready(function () {
  14. layer.msg('链接成功', {time: 1000});
  15. });
  16. });
  17. // 登录
  18. /*var login_data = '{"type":"init", "uid":"' + uinfo.id + '", "token":"OTY3NDMwIyRAJSFeKi8xNTYyMzEzOTAwLzE=", "name" : "' + uinfo.username + '", "avatar" : "'
  19. + uinfo.avatar + '", "group": ' + uinfo.group + '}';*/
  20. var login_data = '{"type":"init","data":{"uid":"' + uinfo.id + '", "token":"ODMzNDk5IyRAJSFeKi8xNTYyNTc2NDY4LzE=","name":"' + uinfo.username + '","avatar":"","group":1}}';
  21. socket.send(login_data);
  22. };
  23. // 监听消息
  24. socket.onmessage = function (res) {
  25. var data = eval("(" + res.data + ")");console.log(data)
  26. switch (data['message_type']) {
  27. // 服务端ping客户端
  28. case 'ping':
  29. socket.send('{"type":"ping"}');
  30. break;
  31. // 添加用户
  32. case 'connect':
  33. addUser(data.data.user_info);
  34. break;
  35. // 移除访客到主面板
  36. case 'delUser':
  37. delUser(data.data);
  38. break;
  39. // 监测聊天数据
  40. case 'chatMessage':
  41. showUserMessage(data.data, data.data.content);
  42. break;
  43. }
  44. };
  45. // 监听失败
  46. socket.onerror = function(err){
  47. layer.alert('连接失败,请联系管理员', {icon: 2, title: '错误提示'});
  48. };
  49. $(function () {
  50. // 获取服务用户列表
  51. $.getJSON('/service/index/getUserList', function(res){
  52. if(1 == res.code && res.data.length > 0){
  53. $.each(res.data, function(k, v){
  54. addUser(v);
  55. });
  56. var id = $(".layui-unselect").find('li').eq(0).data('id');
  57. var name = $(".layui-unselect").find('li').eq(0).data('name');
  58. var avatar = $(".layui-unselect").find('li').eq(0).data('avatar');
  59. var ip = $(".layui-unselect").find('li').eq(0).data('ip');
  60. // 默认设置第一个用户为当前对话的用户
  61. $("#active-user").attr('data-id', id).attr('data-name', name).attr('data-avatar', avatar).attr('data-ip', ip);
  62. $(".layui-unselect").find('li').eq(0).addClass('active').find('span:eq(1)').removeClass('layui-badge').text('');
  63. $("#f-user").val(name);
  64. $("#f-ip").val(ip);
  65. $.getJSON('/service/index/getCity', {ip: ip}, function(res){
  66. $("#f-area").val(res.data);
  67. });
  68. // 拉取和这个人的聊天记录
  69. $("#u-" + id).show();
  70. getChatLog(id, 1);
  71. }
  72. });
  73. // 监听快捷键发送
  74. document.getElementById('msg-area').addEventListener('keydown', function (e) {
  75. if (e.keyCode != 13) return;
  76. e.preventDefault(); // 取消事件的默认动作
  77. sendMessage();
  78. });
  79. // 点击表情
  80. var index;
  81. $("#face").click(function (e) {
  82. e.stopPropagation();
  83. layui.use(['layer'], function () {
  84. var layer = layui.layer;
  85. var isShow = $(".layui-whisper-face").css('display');
  86. if ('block' == isShow) {
  87. layer.close(index);
  88. return;
  89. }
  90. var height = $(".chat-box").height() - 110;
  91. layer.ready(function () {
  92. index = layer.open({
  93. type: 1,
  94. offset: [height + 'px', $(".layui-side").width() + 'px'],
  95. shade: false,
  96. title: false,
  97. closeBtn: 0,
  98. area: '395px',
  99. content: showFaces()
  100. });
  101. });
  102. });
  103. });
  104. $(document).click(function (e) {
  105. layui.use(['layer'], function () {
  106. var layer = layui.layer;
  107. if (isShow) {
  108. layer.close(index);
  109. return false;
  110. }
  111. });
  112. });
  113. // 发送消息
  114. $("#send").click(function () {
  115. sendMessage();
  116. });
  117. // hover用户
  118. $(".layui-unselect li").hover(function () {
  119. $(this).find('i').show();
  120. }, function () {
  121. $(this).find('i').hide();
  122. });
  123. // 关闭用户
  124. $('.close').click(function () {
  125. var uid = $(this).parent().data('id');
  126. $(this).parent().remove(); // 清除左侧的用户列表
  127. $('#u-' + uid).remove(); // 清除右侧的聊天详情
  128. });
  129. // 检测滚动,异步加载更多聊天数据
  130. $(".chat-box").scroll(function () {
  131. var top = $(".chat-box").scrollTop();
  132. });
  133. // 会员转接
  134. $("#scroll-link").click(function(){
  135. var id = $("#active-user").attr('data-id');
  136. var name = $("#active-user").attr('data-name');
  137. var avatar = $("#active-user").attr('data-avatar');
  138. var ip = $("#active-user").attr('data-ip');
  139. if(id == '' || name == ''){
  140. layer.msg("请选择要转接的会员");
  141. }
  142. // 二次确认
  143. var layerIndex = null;
  144. layerIndex = layer.confirm('确定转接 ' + name + ' ?', {
  145. title: '转接提示',
  146. closeBtn: 0,
  147. icon: 3,
  148. btn: ['确定', '取消'] // 按钮
  149. }, function(){
  150. layer.close(layerIndex);
  151. layerIndex = layer.open({
  152. title: '',
  153. type: 1,
  154. area: ['30%', '40%'],
  155. content: $("#change-box")
  156. });
  157. // 监听选择
  158. layui.use(['form'], function(){
  159. var form = layui.form;
  160. form.on('select(group)', function (data) {
  161. if(uinfo.group == data.value){
  162. layer.msg("已经在该分组,不需要转接!");
  163. }else{
  164. layer.close(layerIndex);
  165. var group = data.value; // 分组
  166. // 交换分组
  167. var change_data = '{"type":"changeGroup", "uid":"' + id + '", "name" : "' + name + '", "avatar" : "'
  168. + avatar + '", "group": ' + group + ', "ip" : "' + ip + '"}';
  169. //console.log(change_data);
  170. socket.send(change_data);
  171. // 将该会员从我的会话中移除
  172. delUser({id: id});
  173. layer.msg('转接成功');
  174. }
  175. });
  176. });
  177. }, function(){
  178. });
  179. });
  180. });
  181. var isShow = false;
  182. layui.use(['element', 'form'], function () {
  183. var element = layui.element;
  184. var form = layui.form;
  185. });
  186. // 图片 文件上传
  187. layui.use(['upload', 'layer'], function () {
  188. var upload = layui.upload;
  189. var layer = layui.layer;
  190. // 执行实例
  191. var uploadInstImg = upload.render({
  192. elem: '#image' // 绑定元素
  193. , accept: 'images'
  194. , exts: 'jpg|jpeg|png|gif'
  195. , url: '/service/upload/uploadImg' // 上传接口
  196. , done: function (res) {
  197. sendMessage('img[' + res.data.src + ']');
  198. showBigPic();
  199. }
  200. , error: function () {
  201. // 请求异常回调
  202. }
  203. });
  204. var uploadInstFile = upload.render({
  205. elem: '#file' // 绑定元素
  206. , accept: 'file'
  207. , exts: 'zip|rar'
  208. , url: '/service/upload/uploadFile' // 上传接口
  209. , done: function (res) {
  210. sendMessage('file(' + res.data.src + ')[' + res.msg + ']');
  211. }
  212. , error: function () {
  213. // 请求异常回调
  214. }
  215. });
  216. });
  217. // 展示表情数据
  218. function showFaces() {
  219. isShow = true;
  220. var alt = getFacesIcon();
  221. var _html = '<div class="layui-whisper-face"><ul class="layui-clear whisper-face-list">';
  222. layui.each(alt, function (index, item) {
  223. _html += '<li title="' + item + '" onclick="checkFace(this)"><img src="/static/service/js/layui/images/face/' + index + '.gif" /></li>';
  224. });
  225. _html += '</ul></div>';
  226. return _html;
  227. }
  228. // 选择表情
  229. function checkFace(obj) {
  230. var word = $(".msg-area").val() + ' face' + $(obj).attr('title') + ' ';
  231. $(".msg-area").val(word).focus();
  232. }
  233. // 发送消息
  234. function sendMessage(sendMsg) {
  235. var msg = (typeof(sendMsg) == 'undefined') ? $(".msg-area").val() : sendMsg;
  236. if ('' == msg) {
  237. layui.use(['layer'], function () {
  238. var layer = layui.layer;
  239. return layer.msg('请输入回复内容', {time: 1000});
  240. });
  241. return false;
  242. }
  243. var word = msgFactory(msg, 'mine', uinfo);
  244. var uid = $("#active-user").attr('data-id');
  245. var uname = $("#active-user").attr('data-name');
  246. socket.send(JSON.stringify({
  247. type: 'chatMessage',
  248. data: {to_id: uid, to_name: uname, content: msg, from_name: uinfo.username,
  249. from_id: uinfo.id, from_avatar: uinfo.avatar, conversationId: 49, isFirst: true}
  250. }));
  251. $("#u-" + uid).append(word);
  252. $(".msg-area").val('');
  253. // 滚动条自动定位到最底端
  254. wordBottom();
  255. }
  256. // 关闭工单
  257. function cc() {
  258. var uid = $("#active-user").attr('data-id');
  259. socket.send(JSON.stringify({
  260. type: 'kfCloseUser',
  261. data: {to_id: uid,kf_id:1,group_id:1,conversationId:13}
  262. }));
  263. }
  264. // 上线
  265. function dd() {
  266. var uid = $("#active-user").attr('data-id');
  267. socket.send(JSON.stringify({
  268. type: 'kfOnline',
  269. data: {status: 1,uid: uinfo.id}
  270. }));
  271. }
  272. // 拒接
  273. function ee() {
  274. var uid = $("#active-user").attr('data-id');
  275. socket.send(JSON.stringify({
  276. type: 'kfOnline',
  277. data: {status: 2,uid: uinfo.id}
  278. }));
  279. }
  280. // 展示客服发送来的消息
  281. function showUserMessage(uinfo, content) {
  282. if ($('#f-' + uinfo.id).length == 0) {
  283. addUser(uinfo);
  284. }
  285. // 未读条数计数
  286. if (!$('#f-' + uinfo.id).hasClass('active')) {
  287. var num = $('#f-' + uinfo.id).find('span:eq(1)').text();
  288. if (num == '') num = 0;
  289. num = parseInt(num) + 1;
  290. $('#f-' + uinfo.id).find('span:eq(1)').removeClass('layui-badge').addClass('layui-badge').text(num);
  291. }
  292. var word = msgFactory(content, 'user', uinfo);
  293. setTimeout(function () {
  294. $("#u-" + uinfo.id).append(word);
  295. // 滚动条自动定位到最底端
  296. wordBottom();
  297. showBigPic();
  298. }, 200);
  299. }
  300. // 消息发送工厂
  301. function msgFactory(content, type, uinfo) {
  302. var _html = '';
  303. if ('mine' == type) {
  304. _html += '<li class="whisper-chat-mine">';
  305. } else {
  306. _html += '<li>';
  307. }
  308. _html += '<div class="whisper-chat-user">';
  309. _html += '<img src="' + uinfo.avatar + '">';
  310. if ('mine' == type) {
  311. _html += '<cite><i>' + getDate() + '</i>' + uinfo.username + '</cite>';
  312. } else {
  313. _html += '<cite>' + uinfo.name + '<i>' + getDate() + '</i></cite>';
  314. }
  315. _html += '</div><div class="whisper-chat-text">' + replaceContent(content) + '</div>';
  316. _html += '</li>';
  317. return _html;
  318. }
  319. // 获取日期
  320. function getDate() {
  321. var d = new Date(new Date());
  322. return d.getFullYear() + '-' + digit(d.getMonth() + 1) + '-' + digit(d.getDate())
  323. + ' ' + digit(d.getHours()) + ':' + digit(d.getMinutes()) + ':' + digit(d.getSeconds());
  324. }
  325. //补齐数位
  326. var digit = function (num) {
  327. return num < 10 ? '0' + (num | 0) : num;
  328. };
  329. // 滚动条自动定位到最底端
  330. function wordBottom() {
  331. var box = $(".chat-box");
  332. box.scrollTop(box[0].scrollHeight);
  333. }
  334. // 切换在线用户
  335. function changeUserTab(obj) {
  336. obj.addClass('active').siblings().removeClass('active');
  337. wordBottom();
  338. }
  339. // 添加用户到面板
  340. function addUser(data) {
  341. console.log(data)
  342. var _html = '<li class="layui-nav-item" data-id="' + data.id + '" id="f-' + data.id +
  343. '" data-name="' + data.name + '" data-avatar="' + data.avatar + '" data-ip="' + data.ip + '">';
  344. _html += '<img src="' + data.avatar + '">';
  345. _html += '<span class="user-name">' + data.name + '</span>';
  346. _html += '<span class="layui-badge" style="margin-left:5px">0</span>';
  347. _html += '<i class="layui-icon close" style="display:none">ဇ</i>';
  348. _html += '</li>';
  349. // 添加左侧列表
  350. $("#user_list").append(_html);
  351. // 如果没有选中人,选中第一个
  352. var hasActive = 0;
  353. $("#user_list li").each(function(){
  354. if($(this).hasClass('active')){
  355. hasActive = 1;
  356. }
  357. });
  358. var _html2 = '';
  359. _html2 += '<ul id="u-' + data.id + '">';
  360. _html2 += '</ul>';
  361. // 添加主聊天面板
  362. $('.chat-box').append(_html2);
  363. if(0 == hasActive){
  364. $("#user_list").find('li').eq(0).addClass('active').find('span:eq(1)').removeClass('layui-badge').text('');
  365. $("#u-" + data.id).show();
  366. var id = $(".layui-unselect").find('li').eq(0).data('id');
  367. var name = $(".layui-unselect").find('li').eq(0).data('name');
  368. var ip = $(".layui-unselect").find('li').eq(0).data('ip');
  369. var avatar = $(".layui-unselect").find('li').eq(0).data('avatar');
  370. // 设置当前会话用户
  371. $("#active-user").attr('data-id', id).attr('data-name', name).attr('data-avatar', avatar).attr('data-ip', ip);
  372. $("#f-user").val(name);
  373. $("#f-ip").val(ip);
  374. $.getJSON('/service/index/getCity', {ip: ip}, function(res){
  375. $("#f-area").val(res.data);
  376. });
  377. }
  378. getChatLog(data.id, 1);
  379. checkUser();
  380. }
  381. // 操作新连接用户的 dom操作
  382. function checkUser() {
  383. $(".layui-unselect").find('li').unbind("click"); // 防止事件叠加
  384. // 切换用户
  385. $(".layui-unselect").find('li').bind('click', function () {
  386. changeUserTab($(this));
  387. var uid = $(this).data('id');
  388. var avatar = $(this).data('avatar');
  389. var name = $(this).data('name');
  390. var ip = $(this).data('ip');
  391. // 展示相应的对话信息
  392. $('.chat-box ul').each(function () {
  393. if ('u-' + uid == $(this).attr('id')) {
  394. $(this).addClass('show-chat-detail').siblings().removeClass('show-chat-detail').attr('style', '');
  395. return false;
  396. }
  397. });
  398. // 去除消息提示
  399. $(this).find('span').eq(1).removeClass('layui-badge').text('');
  400. // 设置当前会话的用户
  401. $("#active-user").attr('data-id', uid).attr('data-name', name).attr('data-avatar', avatar).attr('data-ip', ip);
  402. // 右侧展示详情
  403. $("#f-user").val(name);
  404. $("#f-ip").val(ip);
  405. $.getJSON('/service/index/getCity', {ip: ip}, function(res){
  406. $("#f-area").val(res.data);
  407. });
  408. getChatLog(uid, 1);
  409. wordBottom();
  410. });
  411. }
  412. // 删除用户聊天面板
  413. function delUser(data) {
  414. $("#f-" + data.id).remove(); // 清除左侧的用户列表
  415. $('#u-' + data.id).remove(); // 清除右侧的聊天详情
  416. }
  417. // 发送快捷语句
  418. function sendWord(obj) {
  419. var msg = $(obj).data('word');
  420. sendMessage(msg);
  421. }
  422. // 获取聊天记录
  423. function getChatLog(uid, page, flag) {
  424. $.getJSON('/service/index/getChatLog', {uid: uid, page: page}, function(res){
  425. if(1 == res.code && res.data.length > 0){
  426. if(res.msg == res.total){
  427. var _html = '<div class="layui-flow-more">没有更多了</div>';
  428. }else{
  429. var _html = '<div class="layui-flow-more"><a href="javascript:;" data-page="' + parseInt(res.msg + 1)
  430. + '" onclick="getMore(this)"><cite>更多记录</cite></a></div>';
  431. }
  432. var len = res.data.length;
  433. for(var i = 0; i < len; i++){
  434. var v = res.data[len - i - 1];
  435. if ('mine' == v.type) {
  436. _html += '<li class="whisper-chat-mine">';
  437. } else {
  438. _html += '<li>';
  439. }
  440. _html += '<div class="whisper-chat-user">';
  441. _html += '<img src="' + v.from_avatar + '">';
  442. if ('mine' == v.type) {
  443. _html += '<cite><i>' + v.time_line + '</i>' + v.from_name + '</cite>';
  444. } else {
  445. _html += '<cite>' + v.from_name + '<i>' + v.time_line + '</i></cite>';
  446. }
  447. _html += '</div><div class="whisper-chat-text">' + replaceContent(v.content) + '</div>';
  448. _html += '</li>';
  449. }
  450. setTimeout(function () {
  451. // 滚动条自动定位到最底端
  452. if(typeof flag == 'undefined'){
  453. $("#u-" + uid).html(_html);
  454. wordBottom();
  455. }else{
  456. $("#u-" + uid).prepend(_html);
  457. }
  458. showBigPic();
  459. }, 100);
  460. }
  461. });
  462. }
  463. // 显示大图
  464. function showBigPic(){
  465. $(".layui-whisper-photos").on('click', function () {
  466. var src = this.src;
  467. layer.photos({
  468. photos: {
  469. data: [{
  470. "alt": "大图模式",
  471. "src": src
  472. }]
  473. }
  474. , shade: 0.5
  475. , closeBtn: 2
  476. , anim: 0
  477. , resize: false
  478. , success: function (layero, index) {
  479. }
  480. });
  481. });
  482. }
  483. // 获取更多的的记录
  484. function getMore(obj){
  485. $(obj).remove();
  486. var page = $(obj).attr('data-page');
  487. var uid = $(".layui-unselect").find('li').eq(0).data('id');
  488. getChatLog(uid, page, 1);
  489. }
  490. // 打卡下班
  491. function loginOut(){
  492. layer.msg("正在关闭,未咨询完的用户", {time: 50000});
  493. var len = $("#user_list li").length;
  494. var closeNum = 0;
  495. if(len == closeNum){
  496. window.location.href = '/service/login/loginOut';
  497. }
  498. $("#user_list li").each(function(){
  499. var uid = $(this).data('id');
  500. var activeUid = $("#active-user").attr('data-id');
  501. if(uid == activeUid){
  502. $("#active-user").attr('data-id', -999);
  503. }
  504. socket.send(JSON.stringify({
  505. type: 'closeUser', uid: uid
  506. }));
  507. $(this).parent().remove(); // 清除左侧的用户列表
  508. $('#u-' + uid).remove(); // 清除右侧的聊天详情
  509. closeNum++;
  510. if(closeNum == len){
  511. setTimeout(function(){
  512. window.location.href = '/service/login/loginOut';
  513. }, 1500); // 此处等待用户真的退出了
  514. }
  515. });
  516. }