fastchat.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
  2. var FastChat = {
  3. ws: {
  4. SocketTask: null,
  5. Timer: null,
  6. ErrorMsg: [],
  7. MaxRetryCount: 3,// 最大重连次数
  8. CurrentRetryCount: 0,
  9. url: null
  10. },
  11. audio: {
  12. context: new window.AudioContext(),
  13. source: null,
  14. buffer: null
  15. },
  16. cookie_prefix:'',// 同config.php里边的cookie前缀设置,未修改过请忽略
  17. config: null,
  18. url: null,
  19. window_is_show: false,
  20. fast_move: false,
  21. session_id: 0,
  22. is_cross_domain: false,// 是否跨域,若为站外调用,则在js中建立游客cookie
  23. allowed_close_window: true,// 是否允许ecs关闭窗口(当预览图片时,不允许关闭),
  24. initialize: function (url = document.domain, modulename = 'index', initSuccess = null) {
  25. FastChat.url = url;
  26. if(document.domain !== url){
  27. FastChat.is_cross_domain = true;
  28. }
  29. var initialize_url = FastChat.buildUrl(url, modulename, 'initialize');
  30. $.ajax({
  31. url: initialize_url,
  32. success: function (data) {
  33. if (data.code === 403) {
  34. return;
  35. } else if (data.code !== 1) {
  36. layer.msg(data.msg);
  37. return;
  38. }
  39. FastChat.config = data.data;
  40. FastChat.bulidChat(data.data);
  41. FastChat.show_popover((!FastChat.getCookie('new_user')) ? data.data.new_user_tip : data.data.new_msg);
  42. // 站外调用游客身份cookie建立
  43. if (FastChat.is_cross_domain) {
  44. FastChat.setCookie('fastchat_tourists', FastChat.config.token_list.fastchat_tourists_token, 10);
  45. }
  46. // 构建ws的url
  47. FastChat.ws.url = FastChat.buildUrl('billiards.websocket.xunsoftware.com', modulename, 'ws', data.data.websocket_port);
  48. if (modulename === 'admin') {
  49. // 立即链接 Websocket
  50. FastChat.ConnectSocket();
  51. } else {
  52. // 若用户 N 秒后任在此页面,链接Socket
  53. setTimeout(function () {
  54. if (!FastChat.ws.SocketTask || FastChat.ws.SocketTask.readyState === 3 || FastChat.ws.SocketTask.readyState === 2) {
  55. FastChat.ConnectSocket();
  56. }
  57. }, 10000);
  58. }
  59. if (typeof initSuccess == 'function') {
  60. initSuccess();
  61. }
  62. if (data.data.new_msg) {
  63. // 抖动按钮和播放提示音
  64. FastChat.new_message_prompt('#chat_button');
  65. }
  66. }
  67. })
  68. FastChat.eventReg();
  69. },
  70. ConnectSocket: function () {
  71. if ("WebSocket" in window) {
  72. var ws = new WebSocket(FastChat.ws.url);
  73. FastChat.ws.SocketTask = ws;
  74. ws.onopen = function () {
  75. FastChat.ws.CurrentRetryCount = 0;
  76. // 重新发送所有出错的消息
  77. if (FastChat.ws.ErrorMsg.length > 0) {
  78. for (let i in FastChat.ws.ErrorMsg) {
  79. FastChat.ws_send(FastChat.ws.ErrorMsg[i]);
  80. }
  81. FastChat.ws.ErrorMsg = [];
  82. }
  83. if (FastChat.ws.Timer != null) {
  84. clearInterval(FastChat.ws.Timer);
  85. }
  86. if ($('#error_warning').html()) {
  87. $('#error_warning').html('');
  88. $('#chat_button').popover('hide');
  89. }
  90. FastChat.ws.Timer = setInterval(FastChat.ws_send, 28000);//定时发送心跳
  91. };
  92. ws.onmessage = function (evt) {
  93. var msg = $.parseJSON(evt.data);
  94. if (msg.code === 0) {
  95. layer.msg(msg.msg);
  96. }
  97. FastChat.domsg(msg);
  98. };
  99. ws.onclose = function (e) {
  100. if (FastChat.ws.Timer != null) {
  101. clearInterval(FastChat.ws.Timer);
  102. }
  103. $('#error_warning').html('网络链接已断开');
  104. FastChat.show_popover('WebSocket 链接已断开');
  105. if (FastChat.ws.MaxRetryCount) {
  106. FastChat.ws.Timer = setInterval(FastChat.retry_webSocket, 3000);//每3秒重新连接一次
  107. }
  108. };
  109. ws.onerror = function (e) {
  110. // 错误
  111. console.error('websocket 错误:', e);
  112. $('#error_warning').html('WebSocket 发生错误');
  113. FastChat.show_popover('WebSocket 发生错误,请查看控制台');
  114. };
  115. } else {
  116. layer.msg(FastChat.config.chat_name + ':您的浏览器不支持 WebSocket!');
  117. }
  118. },
  119. retry_webSocket: function () {
  120. if (FastChat.ws.CurrentRetryCount < FastChat.ws.MaxRetryCount) {
  121. FastChat.ws.CurrentRetryCount++;
  122. FastChat.ConnectSocket();
  123. console.log('重连 WebSocket 第' + FastChat.ws.CurrentRetryCount + '次');
  124. } else {
  125. if (FastChat.ws.Timer != null) {
  126. clearInterval(FastChat.ws.Timer);
  127. }
  128. if (FastChat.ws.ReConnection) {
  129. console.log('每隔10秒将再次尝试重连 WebSocket')
  130. FastChat.ws.Timer = setInterval(FastChat.ConnectSocket, 10000);//每10秒重新连接一次
  131. }
  132. }
  133. },
  134. bulidChat: function (data) {
  135. $("<div>")
  136. .attr({
  137. 'data-toggle': "popover",
  138. 'data-title': '新消息',
  139. 'data-placement': "auto left",
  140. 'data-content': '',
  141. 'style': 'position: fixed;top: 100px;width: 48px;height: 48px;right: 90px;z-index: 9999;',
  142. 'data-html': true,
  143. 'data-template': '<div class="chat_button_popover popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
  144. id: 'chat_button',
  145. class: 'chat_button'
  146. })
  147. .appendTo("body");
  148. $("<img>")
  149. .attr({
  150. src: FastChat.config.__CDN__ + "/assets/addons/fastchat/img/fastchat.png",
  151. ondragstart: "return false;",
  152. style: 'width: 100%;height: 100%;'
  153. })
  154. .appendTo("#chat_button");
  155. $("body").append(data.window_html);
  156. $('#search_input').attr('placeholder', data.search_tip);
  157. if (!FastChat.ws.SocketTask || FastChat.ws.SocketTask.readyState === 3 || FastChat.ws.SocketTask.readyState === 2) {
  158. $('#error_warning').html('链接中...');
  159. }
  160. let send_tis_key = parseInt(data.send_message_key) === 1 ? 'Enter' : 'Ctrl+Enter';
  161. $('#send_tis').html('按下' + send_tis_key + '发送消息');
  162. var username = data.user_info ? data.user_info.username : '未登录';
  163. $('#modal-title').html(data.chat_name + ' - ' + username);
  164. },
  165. buildSession: function (item) {
  166. if (item.existing_session || $('#session_list').children("[data-session='" + item.id + "']").length) {
  167. // 去掉该会话再添加最新的
  168. $('#session_list').children("[data-session='" + item.id + "']").remove();
  169. }
  170. $('#session_list').prepend(
  171. '<li class="person" data-session="' + item.id + '" data-session_user="' + item.session_user + '">' +
  172. '<img class="person_avatar" src="' + item.avatar + '" alt="" />' +
  173. '<div class="session_info_item">' +
  174. '<span class="name">' + item.nickname + '</span>' +
  175. '<span class="time">' + item.last_time + '</span>' +
  176. '</div><div class="session_info_item">' +
  177. '<span class="preview">' + item.last_message + '</span>' +
  178. (item.unread_msg_count ? '<span class="unread_msg_count">' + item.unread_msg_count + '</span>' : '<span class="unread_msg_count count_hide"></span>') +
  179. '</div>' +
  180. '</li>'
  181. );
  182. if (!item.online) {
  183. // 把头像变灰色
  184. FastChat.edit_online_status(item.session_user, 0);
  185. }
  186. },
  187. buildSessionTime: function (data, page) {
  188. if (parseInt(page) === 1) {
  189. $('.chat_scroll').append('<div class="conversation-start"><span>' + data + '</span></div>');
  190. } else {
  191. $('.chat_scroll').prepend('<div class="conversation-start"><span>' + data + '</span></div>');
  192. }
  193. },
  194. buildRecord: function (data, page) {
  195. if (parseInt(page) === 1) {
  196. $('.chat_scroll').append('<div class="bubble ' + data.sender + '">' + data.message + '</div>');
  197. } else {
  198. $('.chat_scroll').prepend('<div class="bubble ' + data.sender + '">' + data.message + '</div>');
  199. }
  200. },
  201. changeSession: function (event) {
  202. if (event.length === 0) {
  203. FastChat.session_id = 0;
  204. $('#session_user_name').html('无会话');
  205. return;
  206. }
  207. $('.person').removeClass("active");
  208. if ($('.chat-container .right').css('display') != 'none' &&
  209. $('.chat-container .left').css('display') != 'none') {
  210. event.addClass("active");
  211. }
  212. let session_id = event.data('session');
  213. // 加载聊天记录
  214. var load_message = {
  215. c: 'Message',
  216. a: 'chat_record',
  217. data: {
  218. session_id: session_id,
  219. page: 1
  220. }
  221. };
  222. FastChat.session_id = session_id;
  223. FastChat.ws_send(load_message);
  224. // 清理红点
  225. event.children(".session_info_item").children(".unread_msg_count").eq(0).hide(200);
  226. // 获取焦点
  227. $('#message').focus();
  228. $('.chat_emoji').hide();
  229. },
  230. buildChatImg: function (filename, facename, is_filepath = false) {
  231. if (is_filepath) {
  232. return '<img title="' + facename + '" src="' + filename + '" />';
  233. } else {
  234. return '<img title="' + facename + '" src="' + FastChat.config.__CDN__ + '/assets/addons/fastchat/img/emoji/' + filename + '" />';
  235. }
  236. },
  237. buildChatA: function (filepath, file_suffix) {
  238. return '<a href="' + filepath + '">点击下载:' + file_suffix + ' 文件</a>';
  239. },
  240. buildUrl: function (url, modulename, type = 'ws', wsport = 8282) {
  241. // 用户的身份通过读取 cookie 来识别
  242. var protocol = window.location.protocol + '//';
  243. var port = window.location.port;
  244. port = port ? ':' + port:'';
  245. if (type === 'ws') {
  246. // 用户的身份通过 FastChat.config.token_list.kefu_token 来识别
  247. // 游客的身份通过 FastChat.config.token_list.fastchat_tourists_token 来识别
  248. let token = '&token=' + (FastChat.config.token_list.fastchat_token ? FastChat.config.token_list.fastchat_token : '');
  249. let fastchat_user = '&fastchat_user=' + (FastChat.config.token_list.fastchat_tourists_token ? FastChat.config.token_list.fastchat_tourists_token : '');
  250. protocol = parseInt(FastChat.config.wss_switch) === 1 ? 'wss://':'ws://';
  251. return protocol + url + ':' + wsport + '?modulename=' +
  252. modulename + token + fastchat_user;
  253. } else if (type === 'initialize') {
  254. if (FastChat.is_cross_domain){
  255. return protocol + url + port + '/addons/fastchat/index/initialize?modulename=' +
  256. modulename + '&tourists_token=' + FastChat.getCookie('fastchat_tourists');
  257. }
  258. return protocol + url + port + '/addons/fastchat/index/initialize?modulename=' +
  259. modulename;
  260. } else if (type === 'upload') {
  261. return protocol + url + port + '/addons/fastchat/index/upload?modulename=' +
  262. modulename;
  263. } else if (type === 'load_message_prompt') {
  264. return protocol + url + port + '/addons/fastchat/index/load_message_prompt?modulename=' +
  265. modulename;
  266. }
  267. },
  268. // 设置搜索框选中的预选词
  269. setSelectedItem: function () {
  270. if (FastChat.search_primary < 0) {
  271. FastChat.search_primary = $('#search_users').find('li').length - 1;
  272. } else if (FastChat.search_primary > $('#search_users').find('li').length - 1) {
  273. FastChat.search_primary = 0;
  274. }
  275. $('#search_users').find('li').removeClass('select_item')
  276. .eq(FastChat.search_primary).addClass('select_item');
  277. // 将预选词放入输入框
  278. $('#search_input').val($('#search_users').find('li').eq(FastChat.search_primary).data('nickname'));
  279. FastChat.search_select_id = $('#search_users').find('li').eq(FastChat.search_primary).data('userid');
  280. },
  281. postAddSession: function () {
  282. if (!FastChat.search_select_id) {
  283. layer.msg('用户找不到啦!');
  284. }
  285. $('#search_input').val('');
  286. var load_message = {
  287. c: 'Message',
  288. a: 'add_session',
  289. data: {
  290. user_id: FastChat.search_select_id
  291. }
  292. };
  293. FastChat.ws_send(load_message);
  294. },
  295. sendMessage: function (message) {
  296. var load_message = {
  297. c: 'Message',
  298. a: 'send_message',
  299. data: {
  300. message: message,
  301. session_id: FastChat.session_id
  302. }
  303. };
  304. FastChat.ws_send(load_message);
  305. var data = {
  306. sender: 'me',
  307. message: message
  308. }
  309. FastChat.buildRecord(data, 1);
  310. $('#message').html('');
  311. var re = new RegExp("<img(.*)>", "g");
  312. message = message.replace(re, '[图片]');
  313. re = new RegExp("<a(.*)</a>", "g");
  314. message = message.replace(re, '[链接]');
  315. // 修改该会话的最后消息
  316. let session = $('#session_list').children("[data-session='" + FastChat.session_id + "']");
  317. session.children(".session_info_item").children(".time").eq(0).html('刚刚');
  318. session.children(".session_info_item").children(".preview").eq(0).html(message);
  319. let first_session = $('#session_list li').eq(0);
  320. first_session.before(session);
  321. if ($('#chat_scroll').children('.conversation-start').children('span').eq(0).html() === '还没有消息') {
  322. $('#chat_scroll').children('.conversation-start').children('span').eq(0).html('刚刚');
  323. }
  324. $('.chat_scroll').scrollTop($('.chat_scroll')[0].scrollHeight);
  325. },
  326. show_window: function () {
  327. FastChat.window_is_show = true;
  328. if (!FastChat.getCookie('new_user')) {
  329. FastChat.setCookie('new_user', true, 365);
  330. }
  331. // 检查 websocket 是否连接
  332. if (!FastChat.ws.SocketTask || FastChat.ws.SocketTask.readyState === 3 || FastChat.ws.SocketTask.readyState === 2) {
  333. FastChat.ConnectSocket();
  334. }
  335. // 隐藏会话按钮和提示消息
  336. $('#chat_button').popover('hide');
  337. $('#chat_button').hide(200);
  338. $('#FastChat').modal({
  339. keyboard: false,
  340. show: true
  341. });
  342. // 找到当前会话,去掉红点标记(直接重载当前会话)
  343. if (FastChat.session_id) {
  344. var load_message = {
  345. c: 'Message',
  346. a: 'chat_record',
  347. data: {
  348. session_id: FastChat.session_id,
  349. page: 1
  350. }
  351. };
  352. FastChat.ws_send(load_message);
  353. // 清理红点
  354. let session = $('#session_list').children("[data-session='" + FastChat.session_id + "']");
  355. session.children(".session_info_item").children(".unread_msg_count").eq(0).hide(200);
  356. } else {
  357. FastChat.changeSession($('.person').eq(0));
  358. }
  359. },
  360. forecast_add_session: function (e) {
  361. // 预添加会话
  362. FastChat.search_select_id = $(e.currentTarget).data('userid');
  363. FastChat.postAddSession();//添加会话
  364. $('#search_users').hide(200);
  365. $('#search_input').val('');
  366. FastChat.search_select_id = 0;
  367. // 显示会话窗口
  368. FastChat.show_window();
  369. },
  370. show_popover: function (content) {
  371. if (!FastChat.window_is_show && content) {
  372. $('#chat_button').attr("data-content", content);
  373. $('#chat_button').popover('show');
  374. }
  375. },
  376. edit_online_status: function (user_id, status) {
  377. if (status) {
  378. $('#session_list').children("[data-session_user='" + user_id + "']").children(".person_avatar").removeClass("person_head_gray");
  379. } else {
  380. $('#session_list').children("[data-session_user='" + user_id + "']").children(".person_avatar").addClass("person_head_gray");
  381. }
  382. },
  383. edit_shielding_status: function (blacklist, code, session_id) {
  384. // code:1=屏蔽成功,2=解除屏蔽成功,3=通过blacklist判断屏蔽状态
  385. if (code === 3) {
  386. if (blacklist) {
  387. $('.shielding').html('取消屏蔽');
  388. } else {
  389. $('.shielding').html('屏蔽此人');
  390. }
  391. return;
  392. }
  393. if (code === 1 && parseInt(session_id) === parseInt(FastChat.session_id)) {
  394. $('.shielding').html('取消屏蔽');
  395. } else if (code === 2 && parseInt(session_id) === parseInt(FastChat.session_id)) {
  396. $('.shielding').html('屏蔽此人');
  397. }
  398. },
  399. domsg: function (msg) {
  400. if (msg.msgtype === 'config') {
  401. // 加载会话列表
  402. var load_message = {
  403. c: 'Message',
  404. a: 'session_list'
  405. };
  406. FastChat.ws_send(load_message);
  407. if (!FastChat.window_is_show && msg.data.new_msg) {
  408. // 窗口关闭状态
  409. FastChat.show_popover(msg.data.new_msg);
  410. // 抖动按钮和播放提示音
  411. FastChat.new_message_prompt('#chat_button');
  412. }
  413. // console.log('接受到config',msg);
  414. } else if (msg.msgtype === 'offline') {
  415. FastChat.edit_online_status(msg.user_id, 0);
  416. } else if (msg.msgtype === 'online') {
  417. FastChat.edit_online_status(msg.user_id, 1);
  418. } else if (msg.msgtype === 'test') {
  419. console.log(msg)
  420. } else if (msg.msgtype === 'shielding_session') {
  421. FastChat.edit_shielding_status(false, msg.code, msg.session_id);
  422. } else if (msg.msgtype === 'welcome_tourists') {
  423. if (msg.code == 1) {
  424. FastChat.setCookie('fastchat_tourists', msg.data, 10);
  425. }
  426. } else if (msg.msgtype === 'search_user') {
  427. if (msg.data.length) {
  428. FastChat.search_primary = -1;
  429. $('#search_users').html('');
  430. $.each(msg.data, function (index, item) {
  431. $('#search_users').show(200);
  432. $('#search_users').append(
  433. '<li class="fastchat_user" data-userid="' + item.id + '" data-nickname="' + item.nickname + '">' +
  434. '<img src="' + item.avatar + '" alt="" />' +
  435. '<span class="name">' + item.nickname + '</span>' +
  436. '<span class="go_chat">聊天</span>' +
  437. '</li>'
  438. );
  439. })
  440. } else {
  441. $('#search_users').html('');
  442. $('#search_users').show(200);
  443. $('#search_users').append(
  444. '<li class="fastchat_user" data-userid="0">' +
  445. '<span class="name">找不到该用户!</span>' +
  446. '</li>'
  447. );
  448. }
  449. } else if (msg.msgtype === 'add_session') {
  450. if (msg.code === 1) {
  451. FastChat.buildSession(msg.data);
  452. FastChat.changeSession($('.person').eq(0));
  453. FastChat.edit_shielding_status(msg.data.blacklist, 3);
  454. }
  455. } else if (msg.msgtype === 'message_list') {
  456. $('#session_list').html('');
  457. for (let i in msg.data) {
  458. FastChat.buildSession(msg.data[i]);
  459. }
  460. if (FastChat.window_is_show) {
  461. FastChat.changeSession($('.person').eq(0));
  462. }
  463. } else if (msg.msgtype === 'chat_record') {
  464. // 聊天记录
  465. if (msg.code === 0) {
  466. return;
  467. }
  468. if (parseInt(msg.data.page) === 1) {
  469. $('.chat_scroll').html('');
  470. }
  471. var chat_record = msg.data.chat_record
  472. $('#session_user_name').html(msg.data.session_info.nickname ? msg.data.session_info.nickname : '游客');
  473. FastChat.chat_record_page = msg.data.next_page;
  474. for (let i in chat_record) {
  475. if (msg.data.page === 1) {
  476. FastChat.buildSessionTime(chat_record[i].datetime, msg.data.page);
  477. }
  478. for (let y in chat_record[i].data) {
  479. FastChat.buildRecord(chat_record[i].data[y], msg.data.page)
  480. }
  481. if (msg.data.page !== 1) {
  482. FastChat.buildSessionTime(chat_record[i].datetime, msg.data.page);
  483. }
  484. }
  485. FastChat.edit_shielding_status(msg.data.session_info.blacklist, 3);
  486. setTimeout(() => {
  487. $('.chat_scroll').scrollTop($('.chat_scroll')[0].scrollHeight);
  488. }, 500)
  489. } else if (msg.msgtype === 'clear') {
  490. FastChat.ws.MaxRetryCount = 0;
  491. FastChat.ws.ReConnection = false;
  492. // 删除
  493. var delTimer = setInterval(function () {
  494. if ($('#chat_button').length != 0) {
  495. console.warn('禁止匿名聊天,清退链接!');
  496. $('#chat_button').popover('hide');
  497. $('#chat_button').remove();
  498. $('#FastChat').modal('hide');
  499. clearInterval(delTimer);
  500. }
  501. }, 100);
  502. var load_message = {
  503. c: 'Message',
  504. a: 'clear'
  505. };
  506. FastChat.ws_send(load_message);
  507. } else if (msg.msgtype === 'new_message') {
  508. var message_content = msg.data.nickname + '发来新的消息!';
  509. let mp3 = new Audio("https://pbbaby.xunsoftware.com/uploads/audio/order.mp3");
  510. mp3.loop = false;
  511. mp3.play();
  512. if (FastChat.window_is_show) {
  513. // 窗口打开状态
  514. FastChat.new_message_prompt('#FastChat');
  515. } else {
  516. // 窗口关闭状态
  517. FastChat.show_popover(message_content);
  518. // 抖动按钮和播放提示音
  519. FastChat.new_message_prompt('#chat_button');
  520. }
  521. // 检查是否有该会话
  522. let session = $('#session_list').children("[data-session='" + msg.data.id + "']");
  523. if (session.length === 0) {
  524. FastChat.buildSession(msg.data);
  525. } else {
  526. // 修改该会话的最后消息
  527. session.children(".session_info_item").children(".time").eq(0).html(msg.data.last_time);
  528. session.children(".session_info_item").children(".preview").eq(0).html(msg.data.last_message);
  529. // 将会话移动到第一位
  530. let first_session = $('#session_list li').eq(0);
  531. first_session.before(session);
  532. if ($('#chat_scroll').children('.conversation-start').children('span').eq(0).html() === '还没有消息') {
  533. $('#chat_scroll').children('.conversation-start').children('span').eq(0).html('刚刚');
  534. }
  535. // 必要时,直接去除红点
  536. if (parseInt(msg.data.id) === parseInt(FastChat.session_id) && FastChat.window_is_show) {
  537. FastChat.buildRecord(msg.data, 1);
  538. var load_message = {
  539. c: 'Message',
  540. a: 'read_message',
  541. data: {
  542. record_id: msg.data.record_id
  543. }
  544. };
  545. FastChat.ws_send(load_message);
  546. $('.chat_scroll').scrollTop($('.chat_scroll')[0].scrollHeight);
  547. return;
  548. }
  549. if (msg.data.unread_msg_count > 0) {
  550. session.children(".session_info_item").children(".unread_msg_count").eq(0).html(msg.data.unread_msg_count).show(200);
  551. } else {
  552. session.children(".session_info_item").children(".unread_msg_count").eq(0).hide(200);
  553. }
  554. }
  555. }
  556. },
  557. playSound: function () {
  558. FastChat.audio.source = FastChat.audio.context.createBufferSource();
  559. FastChat.audio.source.buffer = FastChat.audio.buffer;
  560. FastChat.audio.source.loop = false;
  561. FastChat.audio.source.connect(FastChat.audio.context.destination);
  562. FastChat.audio.source.start(0); //立即播放
  563. },
  564. loadAudioFile: function (url) {
  565. var xhr = new XMLHttpRequest(); //通过XHR下载音频文件
  566. xhr.open('GET', url, true);
  567. xhr.responseType = 'arraybuffer';
  568. xhr.onload = function (e) { //下载完成
  569. FastChat.audio.context.decodeAudioData(this.response,
  570. function (buffer) { //解码成功时的回调函数
  571. FastChat.audio.buffer = buffer;
  572. FastChat.playSound();
  573. },
  574. function (e) { //解码出错时的回调函数
  575. console.log('音频解码失败', e);
  576. });
  577. };
  578. xhr.send();
  579. },
  580. new_message_prompt: function (event) {
  581. // 抖动元素和播放提示音乐
  582. $(event).addClass('fastchat-shake-horizontal');
  583. setTimeout(function () {
  584. $(event).removeClass('fastchat-shake-horizontal');
  585. }, 400);
  586. if (FastChat.audio.buffer) {
  587. FastChat.playSound();
  588. } else {
  589. let url = FastChat.buildUrl(FastChat.url, 'index', 'load_message_prompt');
  590. FastChat.loadAudioFile(url);
  591. }
  592. },
  593. getCookie: function (cname) {
  594. var name = FastChat.cookie_prefix + cname + "=";
  595. var decodedCookie = document.cookie
  596. var ca = decodedCookie.split(';');
  597. for (var i = 0; i < ca.length; i++) {
  598. var c = ca[i];
  599. while (c.charAt(0) === ' ') {
  600. c = c.substring(1);
  601. }
  602. if (c.indexOf(name) === 0) {
  603. return c.substring(name.length, c.length);
  604. }
  605. }
  606. return '';
  607. },
  608. setCookie: function (cname, cvalue, exdays) {
  609. var d = new Date();
  610. d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
  611. var expires = "expires=" + d.toUTCString();
  612. document.cookie = FastChat.cookie_prefix + cname + "=" + cvalue + ";" + expires + ";path=/";
  613. },
  614. ws_send: function (message) {
  615. if (!message) {
  616. message = {c: 'Message', a: 'ping'};
  617. }
  618. if (FastChat.ws.SocketTask && FastChat.ws.SocketTask.readyState == 1) {
  619. FastChat.ws.SocketTask.send(JSON.stringify(message));
  620. } else {
  621. console.log('消息发送出错', message)
  622. FastChat.ws.ErrorMsg.push(message);
  623. }
  624. },
  625. eventReg: function () {
  626. // 点击轻提示和FastChat悬浮球的事件
  627. $(document).on('click', '.chat_button_popover,#chat_button', function () {
  628. FastChat.show_window();
  629. });
  630. // 拖动悬浮球的事情
  631. $(document).on('mousedown', '#chat_button', function (e) {
  632. $(document).find("iframe").css("pointer-events", "none");
  633. FastChat.fast_move = true;
  634. FastChat.fast_x = e.pageX - parseInt($("#chat_button").css("left"));
  635. FastChat.fast_y = e.pageY - parseInt($("#chat_button").css("top"));
  636. $(document).on('mousemove', function (e) {
  637. if (FastChat.fast_move) {
  638. var x = e.pageX - FastChat.fast_x;//控件左上角到屏幕左上角的相对位置
  639. var y = e.pageY - FastChat.fast_y;
  640. $("#chat_button").css({"top": y, "left": x});
  641. }
  642. }).mouseup(function () {
  643. $(document).find("iframe").css("pointer-events", "auto");
  644. FastChat.fast_move = false;
  645. });
  646. });
  647. // 滑动聊天记录的事件
  648. document.addEventListener('scroll', function (event) {
  649. if (event.target.id === 'chat_scroll') {
  650. if (parseInt($(event.target).scrollTop()) === 0 && FastChat.chat_record_page !== 'done') {
  651. // 加载历史聊天记录
  652. var load_message = {
  653. c: 'Message',
  654. a: 'chat_record',
  655. data: {
  656. session_id: FastChat.session_id,
  657. page: FastChat.chat_record_page
  658. }
  659. };
  660. FastChat.ws_send(load_message);
  661. }
  662. }
  663. }, true);
  664. // 隐藏窗口时
  665. $(document).on('hidden.bs.modal', '#FastChat', function (e) {
  666. $('#chat_button').show(200);
  667. FastChat.window_is_show = false;
  668. });
  669. // 屏蔽用户
  670. $(document).on('click', '.shielding', function () {
  671. var load_message = {
  672. c: 'Message',
  673. a: 'shielding_session',
  674. data: {
  675. session_id: FastChat.session_id
  676. }
  677. };
  678. FastChat.ws_send(load_message);
  679. });
  680. // 监听子框架的点击事件-一键添加会话窗口
  681. /*$('iframe').contents().find('.fastchat_user').bind('click',function(e){
  682. FastChat.forecast_add_session(e);
  683. });*/
  684. // 添加会话窗口
  685. $(document).on('click', '.fastchat_user', function (e) {
  686. FastChat.forecast_add_session(e);
  687. });
  688. // 显示表情选择面板
  689. $(document).on('click', '.smiley', function (e) {
  690. $('.chat_emoji').toggle(200);
  691. // 获取焦点
  692. $('#message').focus();
  693. });
  694. // 选择表情
  695. $(document).on('click', '.chat_emoji img', function (e) {
  696. $('#message').append(e.target);
  697. $('.chat_emoji').hide();
  698. $('#message').focus();
  699. });
  700. // 用户选择了文件
  701. $(document).on('change', '#chatfile', function (e) {
  702. if (!$('#chatfile')[0].files[0]) {
  703. return;
  704. }
  705. // 上传文件
  706. var formData = new FormData();
  707. formData.append("file", $('#chatfile')[0].files[0]);
  708. var url = FastChat.buildUrl(FastChat.url, 'index', 'upload');
  709. $.ajax({
  710. url: url, /*接口域名地址*/
  711. type: 'post',
  712. data: formData,
  713. contentType: false,
  714. processData: false,
  715. success: function (res) {
  716. if (res.code === 1) {
  717. var file_name = res.data.url.split('.');
  718. var file_suffix = file_name[file_name.length - 1];
  719. if (file_suffix === 'png' ||
  720. file_suffix === 'jpg' ||
  721. file_suffix === 'gif' ||
  722. file_suffix === 'jpeg') {
  723. var message = FastChat.buildChatImg(res.data.url, '', true);
  724. FastChat.sendMessage(message);
  725. } else {
  726. var file_name = res.data.url.split('.');
  727. var file_suffix = file_name[file_name.length - 1];
  728. var message = FastChat.buildChatA(res.data.url, file_suffix);
  729. FastChat.sendMessage(message);
  730. }
  731. } else {
  732. layer.msg(res.msg);
  733. }
  734. },
  735. error: function (e) {
  736. layer.msg('文件上传失败,请重试!');
  737. },
  738. complete: function () {
  739. $('#chatfile').val('');
  740. }
  741. })
  742. });
  743. // 用户点击聊天记录窗口,隐藏表情面板
  744. $(document).on('click', '#chat_scroll', function () {
  745. if ($('.chat_emoji').css('display') === 'block') {
  746. $('.chat_emoji').hide();
  747. }
  748. });
  749. // 右键菜单
  750. $(document).on('contextmenu', '.person', function (e) {
  751. FastChat.select_session_id = $(e.currentTarget).data('session');
  752. var popupmenu = $('.fastchat_menu');
  753. popupmenu.hide();
  754. let l = ($(document).width() - e.clientX) < popupmenu.width() ? (e.clientX - popupmenu.width()) : e.clientX;
  755. let t = ($(document).height() - e.clientY) < popupmenu.height() ? (e.clientY - popupmenu.height()) : e.clientY;
  756. popupmenu.css({left: l, top: t}).show(200);
  757. e.preventDefault();
  758. }).click(function () {
  759. // 菜单的隐藏
  760. $('.fastchat_menu').hide();
  761. });
  762. // 点击右键菜单项
  763. $(document).on('click', '.fastchat_menu_item', function (e) {
  764. var action = $(e.currentTarget).data('action');
  765. if (FastChat.select_session_id && action === 'del') {
  766. // 删除会话
  767. $('#session_list').children("[data-session='" + FastChat.select_session_id + "']").remove();
  768. var load_message = {
  769. c: 'Message',
  770. a: 'del_session',
  771. data: {
  772. session_id: FastChat.select_session_id
  773. }
  774. };
  775. FastChat.ws_send(load_message);
  776. } else if (FastChat.select_session_id && action === 'shielding') {
  777. // FastChat.shielding_session(window.FastChat.select_session_id);
  778. }
  779. });
  780. // 切换会话人
  781. $(document).on('click', '#session_list li', function (e) {
  782. if ($('.chat-container .right').css('display') === 'none') {
  783. $('.chat-container .right').show();
  784. $('.chat-container .left').hide();
  785. }
  786. FastChat.changeSession($(e.currentTarget));
  787. });
  788. // 手机版聊天窗口兼容
  789. $(document).on('hide.bs.modal', '#FastChat', function (e) {
  790. if ($('.chat-container .left').css('display') === 'none') {
  791. $('.chat-container .left').show(200);
  792. $('.chat-container .right').hide();
  793. return false;
  794. }
  795. });
  796. // 预览图片
  797. $(document).on('click', '.chat_scroll .bubble img', function (e) {
  798. var img_obj = $(e.target)[0];
  799. FastChat.allowed_close_window = false;// 按下ecs不允许关闭会话窗口
  800. layer.photos({
  801. photos: {
  802. "title":"聊天图片预览",
  803. "id":"record",
  804. data:[
  805. {
  806. "src":img_obj.src
  807. }
  808. ]
  809. },
  810. end:function () {
  811. // 图片预览已关闭
  812. FastChat.allowed_close_window = true;
  813. },anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数)
  814. });
  815. })
  816. // 搜索框失去焦点
  817. $(document).on('blur', '#search_input', function () {
  818. // $('#search_input').val('');
  819. setTimeout(function () {
  820. // 等待点击事件冒泡-防止搜索结果中的蓝色聊天文字不能被点击
  821. $('#search_users').hide(200);
  822. FastChat.search_select_id = 0;
  823. }, 250);
  824. })
  825. // 禁止回车键换行
  826. $(document).on('keypress', '#message', function (event) {
  827. if (parseInt(FastChat.config.send_message_key) === 1 && parseInt(event.keyCode) === 13 && !event.ctrlKey) {
  828. event.preventDefault()
  829. }
  830. });
  831. // 按键监听 FastChat.config.ecs_exit == 1
  832. $(document).on('keyup', function (event) {
  833. // 对ecs键的监听
  834. if (parseInt(event.keyCode) === 27 && FastChat.window_is_show) {
  835. if (parseInt(FastChat.config.ecs_exit) === 1 && FastChat.allowed_close_window) {
  836. $('#FastChat').modal('hide');
  837. } else {
  838. layer.closeAll();
  839. }
  840. }
  841. });
  842. // 按键发送消息监听
  843. $(document).on('keydown', '#message', function (event) {
  844. var message = $(event.currentTarget).html();
  845. if (parseInt(FastChat.config.send_message_key) === 1 && parseInt(event.keyCode) === 13 && !event.ctrlKey) {
  846. if (message) {
  847. FastChat.sendMessage(message);
  848. }
  849. } else if (parseInt(FastChat.config.send_message_key) === 1 && parseInt(event.keyCode) === 13 && event.ctrlKey) {
  850. // Enter发送消息时,用户按下了ctrl+Enter
  851. if (FastChat.browserType() === "IE" || FastChat.browserType() === "Edge") {
  852. $(event.currentTarget).html(message + "<div></div>");
  853. } else if (FastChat.browserType() === "FF") {
  854. $(event.currentTarget).html(message + "<br/><br/>");
  855. } else {
  856. $(event.currentTarget).html(message + "<div><br/></div>");
  857. }
  858. // 获得焦点
  859. var o = document.getElementById("message").lastChild;
  860. var sel = window.getSelection();
  861. var range = document.createRange();
  862. range.selectNodeContents(event.currentTarget);
  863. range.collapse(false);
  864. range.setEndAfter(o);
  865. range.setStartAfter(o);
  866. sel.removeAllRanges();
  867. sel.addRange(range);
  868. } else if (parseInt(FastChat.config.send_message_key) === 0 && parseInt(event.keyCode) === 13 && event.ctrlKey) {
  869. if (message) {
  870. FastChat.sendMessage(message);
  871. }
  872. }
  873. });
  874. $(document).on('keyup', '#search_input', function (event) {
  875. if (parseInt(event.keyCode) === 13) {
  876. var user = $('#search_input').val();
  877. if (user.length <= 0) {
  878. // 无搜索词,且预选框已显示,隐藏预选框
  879. if ($('#search_users').css('display') !== 'none') {
  880. $('#search_users').hide(200);
  881. FastChat.search_select_id = 0;
  882. } else {
  883. layer.msg('请输入要查找的用户!');
  884. }
  885. return;
  886. } else {
  887. // 有预选人,添加会话
  888. if ($('#search_users').css('display') !== 'none' && FastChat.search_select_id) {
  889. FastChat.postAddSession();
  890. $('#search_users').hide(200);
  891. FastChat.search_select_id = 0;
  892. return;
  893. }
  894. }
  895. var load_message = {
  896. c: 'Message',
  897. a: 'search_user',
  898. data: user
  899. };
  900. FastChat.ws_send(load_message);
  901. } else if (parseInt(event.keyCode) === 38) {
  902. FastChat.search_primary--;
  903. FastChat.setSelectedItem();
  904. } else if (parseInt(event.keyCode) === 40) {
  905. FastChat.search_primary++;
  906. FastChat.setSelectedItem();
  907. }
  908. event.preventDefault()
  909. })
  910. },
  911. browserType: function () {
  912. var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
  913. var isOpera = false;
  914. if (userAgent.indexOf('Edge') > -1) {
  915. return "Edge";
  916. }
  917. if (userAgent.indexOf('.NET') > -1) {
  918. return "IE";
  919. }
  920. if (userAgent.indexOf("Opera") > -1 || userAgent.indexOf("OPR") > -1) {
  921. isOpera = true;
  922. return "Opera"
  923. }
  924. ; //判断是否Opera浏览器
  925. if (userAgent.indexOf("Firefox") > -1) {
  926. return "FF";
  927. } //判断是否Firefox浏览器
  928. if (userAgent.indexOf("Chrome") > -1) {
  929. return "Chrome";
  930. }
  931. if (userAgent.indexOf("Safari") > -1) {
  932. return "Safari";
  933. } //判断是否Safari浏览器
  934. if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera) {
  935. return "IE";
  936. }
  937. ; //判断是否IE浏览器
  938. }
  939. }