Authored by 徐炜

Merge remote-tracking branch 'origin/feature/customerService' into feature/customerService

@@ -82,6 +82,11 @@ app.use((req, res, next) => { @@ -82,6 +82,11 @@ app.use((req, res, next) => {
82 req.session = {}; 82 req.session = {};
83 } 83 }
84 84
  85 + // 获取客服开关,读cache
  86 + global.yoho.cache.get('customerServiceSwitch').then(resule => {
  87 + res.locals.customerServiceSwitch = resule || false;
  88 + }).catch(next);
  89 +
85 next(); 90 next();
86 }); 91 });
87 92
  1 +/**
  2 + * 设置cache controller
  3 + * @author: xiaoxiao<xiaoxiao.hao@yoho.cn>
  4 + * @date: 2016/12/21
  5 + */
  6 +
  7 +'use strict';
  8 +const cache = global.yoho.cache;
  9 +
  10 +const index = (req, res, next) => {
  11 + let customerServiceSwitch = req.query.customerServiceSwitch;
  12 +
  13 + if (typeof customerServiceSwitch === 'undefined') {
  14 + res.json(false);
  15 + return;
  16 + }
  17 +
  18 + cache.set('customerServiceSwitch', customerServiceSwitch ? true : false, -1).then(result => {
  19 + res.json(result);
  20 + }).catch(next);
  21 +};
  22 +
  23 +module.exports = {
  24 + index
  25 +};
@@ -13,6 +13,7 @@ var multipart = require('connect-multiparty'); @@ -13,6 +13,7 @@ var multipart = require('connect-multiparty');
13 var multipartMiddleware = multipart(); 13 var multipartMiddleware = multipart();
14 14
15 const rvCtrl = require(`${cRoot}/recent-view`); 15 const rvCtrl = require(`${cRoot}/recent-view`);
  16 +const cache = require(`${cRoot}/cache`);
16 const uploadCtrl = require(`${cRoot}/upload`); 17 const uploadCtrl = require(`${cRoot}/upload`);
17 const erp2goods = require(`${cRoot}/erp2goods`); 18 const erp2goods = require(`${cRoot}/erp2goods`);
18 19
@@ -22,4 +23,6 @@ router.post('/upload/image', multipartMiddleware, uploadCtrl.uploadImg); @@ -22,4 +23,6 @@ router.post('/upload/image', multipartMiddleware, uploadCtrl.uploadImg);
22 23
23 router.get('/erp2goods', erp2goods.find); 24 router.get('/erp2goods', erp2goods.find);
24 25
  26 +router.get('/cache', cache.index); // 设置cache
  27 +
25 module.exports = router; 28 module.exports = router;
@@ -27,7 +27,8 @@ const personalController = require(`${cRoot}/qrcode`); @@ -27,7 +27,8 @@ const personalController = require(`${cRoot}/qrcode`);
27 // const FavoriteController = require(`${cRoot}/Favorite`); 27 // const FavoriteController = require(`${cRoot}/Favorite`);
28 // const CouponsController = require(`${cRoot}/coupons`); 28 // const CouponsController = require(`${cRoot}/coupons`);
29 29
30 -const homeNav = [ 30 +const homeNav = (req, res) => {
  31 + return [
31 { 32 {
32 title: '交易管理', 33 title: '交易管理',
33 subNav: [ 34 subNav: [
@@ -48,7 +49,12 @@ const homeNav = [ @@ -48,7 +49,12 @@ const homeNav = [
48 49
49 /* {name: '我的投诉', href: '/home/complaints'}, */ 50 /* {name: '我的投诉', href: '/home/complaints'}, */
50 {name: '我的信息', href: '/home/message', count: 0}, 51 {name: '我的信息', href: '/home/message', count: 0},
51 - {name: '在线客服', href: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409', isBlank: true} 52 + {
  53 + name: '在线客服',
  54 + href: res.locals.customerServiceSwitch ?
  55 + '/service/client' : 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409',
  56 + isBlank: true
  57 + }
52 ] 58 ]
53 }, 59 },
54 { 60 {
@@ -60,11 +66,12 @@ const homeNav = [ @@ -60,11 +66,12 @@ const homeNav = [
60 {name: '兑换礼品卡', href: '/home/gift'} 66 {name: '兑换礼品卡', href: '/home/gift'}
61 ] 67 ]
62 } 68 }
63 -]; 69 + ];
  70 +};
64 71
65 -const getActiveNav = (req)=>{ 72 +const getActiveNav = (req, res)=>{
66 73
67 - let mHomeNav = _.cloneDeep(homeNav); 74 + let mHomeNav = _.cloneDeep(homeNav(req, res));
68 75
69 return mHomeNav.map((item) => { 76 return mHomeNav.map((item) => {
70 item.subNav = item.subNav.map((nav) => { 77 item.subNav = item.subNav.map((nav) => {
@@ -94,7 +101,7 @@ const getActiveNav = (req)=>{ @@ -94,7 +101,7 @@ const getActiveNav = (req)=>{
94 101
95 const getHomeNav = (req, res, next) => { 102 const getHomeNav = (req, res, next) => {
96 res.locals.path = [{href: helpers.urlFormat('/'), name: 'YOHO!BUY 有货首页'}, {name: '个人中心'}]; 103 res.locals.path = [{href: helpers.urlFormat('/'), name: 'YOHO!BUY 有货首页'}, {name: '个人中心'}];
97 - res.locals.homeNav = getActiveNav(req); 104 + res.locals.homeNav = getActiveNav(req, res);
98 res.locals.userThumb = '//img10.static.yhbimg.com/headimg/' + 105 res.locals.userThumb = '//img10.static.yhbimg.com/headimg/' +
99 '2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100'; 106 '2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
100 next(); 107 next();
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 <meta name="apple-mobile-web-app-status-bar-style" content="black" /> 10 <meta name="apple-mobile-web-app-status-bar-style" content="black" />
11 <meta content="telephone=no" name="format-detection" /> 11 <meta content="telephone=no" name="format-detection" />
12 <meta content="email=no" name="format-detection" /> 12 <meta content="email=no" name="format-detection" />
  13 + <meta name="renderer" content="webkit">
13 {{#if devEnv}} 14 {{#if devEnv}}
14 <link rel="stylesheet" href="//localhost:5002/css/index.css"> 15 <link rel="stylesheet" href="//localhost:5002/css/index.css">
15 {{^}} 16 {{^}}
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <img class="code" src="{{csSetting.qrCode}}"> 3 <img class="code" src="{{csSetting.qrCode}}">
4 <div class="scan"> 4 <div class="scan">
5 <span class="icon"></span> 5 <span class="icon"></span>
6 - <span class="tip">扫描二维码<br>现在手机客户端</span> 6 + <span class="tip">扫描二维码<br>下载手机客户端</span>
7 </div> 7 </div>
8 </div> 8 </div>
9 <a href="{{csSetting.pcAdLink}}" target="_blank"> 9 <a href="{{csSetting.pcAdLink}}" target="_blank">
@@ -15,7 +15,9 @@ @@ -15,7 +15,9 @@
15 <p class="star-text">非常满意</p> 15 <p class="star-text">非常满意</p>
16 </div> 16 </div>
17 <div class="detail-reason"> 17 <div class="detail-reason">
  18 + <div class="dis-wrap">
18 <div class="discontent"></div> 19 <div class="discontent"></div>
  20 + </div>
19 <textarea class="other-reason" maxlength="50" placeholder="请您输入不满意的其他原因" spellcheck="false"></textarea> 21 <textarea class="other-reason" maxlength="50" placeholder="请您输入不满意的其他原因" spellcheck="false"></textarea>
20 </div> 22 </div>
21 </div> 23 </div>
@@ -189,7 +189,7 @@ @@ -189,7 +189,7 @@
189 </div> 189 </div>
190 <div class="left"> 190 <div class="left">
191 <span class="iconfont rgbf">&#xe602;</span> 191 <span class="iconfont rgbf">&#xe602;</span>
192 - <a href="http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409" target="_blank"> 192 + <a href="{{#if customerServiceSwitch}}/service/client{{else}}http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409{{/if}}" target="_blank">
193 <span class="red">便捷</span> 193 <span class="red">便捷</span>
194 <span class="rgbf">在线客服</span> 194 <span class="rgbf">在线客服</span>
195 </a> 195 </a>
@@ -51,6 +51,7 @@ var tipTpl = require('hbs/service/tip.hbs'), @@ -51,6 +51,7 @@ var tipTpl = require('hbs/service/tip.hbs'),
51 var processInfo = { 51 var processInfo = {
52 scrollLoad: false, 52 scrollLoad: false,
53 manual: false, 53 manual: false,
  54 + completeClose: false, // 评价完成后关闭
54 promoter: 1, // 评论发起者 1:客户自己 2:客服 55 promoter: 1, // 评论发起者 1:客户自己 2:客服
55 savedEval: false // 是否保存过评论 56 savedEval: false // 是否保存过评论
56 }; 57 };
@@ -412,16 +413,23 @@ function pageInit() { @@ -412,16 +413,23 @@ function pageInit() {
412 */ 413 */
413 function handleCusMsg(rec, msgType, message) { 414 function handleCusMsg(rec, msgType, message) {
414 var dom, 415 var dom,
415 - image; 416 + image,
  417 + mode = 2,
  418 + width = 100,
  419 + height = 100;
416 420
417 message.newContent = emojiPrefix(message.newContent); 421 message.newContent = emojiPrefix(message.newContent);
418 422
419 // 用户头像处理 423 // 用户头像处理
420 if (!rec.userHead) { 424 if (!rec.userHead) {
421 rec.userHead = assetsPrefix + socketConf.defaultUserHead; 425 rec.userHead = assetsPrefix + socketConf.defaultUserHead;
  426 + } else {
  427 + rec.userHead = rec.userHead
  428 + .replace(/\{mode\}/, mode)
  429 + .replace(/\{width\}/, width)
  430 + .replace(/\{height\}/, height);
422 } 431 }
423 432
424 -  
425 // 图片添加标签 433 // 图片添加标签
426 if (msgType === 2) { 434 if (msgType === 2) {
427 message.newContent = '<img class="img-msg" src="' + message.content + '">'; 435 message.newContent = '<img class="img-msg" src="' + message.content + '">';
@@ -479,9 +487,9 @@ function pageInit() { @@ -479,9 +487,9 @@ function pageInit() {
479 if (msgType === 2) { 487 if (msgType === 2) {
480 message.newContent = '<img class="img-msg" src="' + message.content + '">'; 488 message.newContent = '<img class="img-msg" src="' + message.content + '">';
481 489
482 - dom = cusTpl({  
483 - userHead: rec.userHead,  
484 - userName: rec.userName, 490 + dom = csTpl({
  491 + csHead: rec.csHead,
  492 + csName: rec.csName,
485 sendTimeShort: rec.sendTimeShort, 493 sendTimeShort: rec.sendTimeShort,
486 newContent: message.newContent 494 newContent: message.newContent
487 }); 495 });
@@ -506,9 +514,12 @@ function pageInit() { @@ -506,9 +514,12 @@ function pageInit() {
506 /** 514 /**
507 * 显示评价弹框 515 * 显示评价弹框
508 */ 516 */
509 - function showEvalModal(isclose) { 517 + function showEvalModal(cptClose) {
510 var $evalModal = $('#makeEvaluation'); 518 var $evalModal = $('#makeEvaluation');
511 519
  520 + // 评价完成后关闭
  521 + processInfo.completeClose = cptClose;
  522 +
512 // 没有接入人工 523 // 没有接入人工
513 if (!processInfo.manual) { 524 if (!processInfo.manual) {
514 return; 525 return;
@@ -545,11 +556,6 @@ function pageInit() { @@ -545,11 +556,6 @@ function pageInit() {
545 if (res && res.code === 200) { 556 if (res && res.code === 200) {
546 // 评价原因 557 // 评价原因
547 len && discontentHtml(len, data); 558 len && discontentHtml(len, data);
548 -  
549 - if (isclose) {  
550 - // 评价完成后,是否关闭窗口  
551 - window.close();  
552 - }  
553 } 559 }
554 $evalModal.modal('show'); 560 $evalModal.modal('show');
555 } 561 }
@@ -627,10 +633,12 @@ function pageInit() { @@ -627,10 +633,12 @@ function pageInit() {
627 break; 633 break;
628 634
629 case allTypes.OP_LEAVE: 635 case allTypes.OP_LEAVE:
  636 + socketChat.clear();
630 offlineTip(message); 637 offlineTip(message);
631 break; 638 break;
632 639
633 case allTypes.OFFLINE: 640 case allTypes.OFFLINE:
  641 + socketChat.clear();
634 offlineTip(message); 642 offlineTip(message);
635 break; 643 break;
636 644
@@ -680,10 +688,12 @@ function pageInit() { @@ -680,10 +688,12 @@ function pageInit() {
680 688
681 onClose: function() { 689 onClose: function() {
682 $iconEval.hide(); 690 $iconEval.hide();
  691 + $iconMs.hide();
683 $reconnect = $msgList.find('.list-item') 692 $reconnect = $msgList.find('.list-item')
684 .last().find('.reconnect'); 693 .last().find('.reconnect');
685 694
686 if (!$reconnect.length) { 695 if (!$reconnect.length) {
  696 + socketChat.clear();
687 offlineTip(); 697 offlineTip();
688 } 698 }
689 }, 699 },
@@ -693,6 +703,7 @@ function pageInit() { @@ -693,6 +703,7 @@ function pageInit() {
693 }, 703 },
694 704
695 socketClosedCb: function() { 705 socketClosedCb: function() {
  706 + socketChat.clear();
696 offlineTip(); 707 offlineTip();
697 } 708 }
698 })); 709 }));
@@ -710,6 +721,10 @@ function pageInit() { @@ -710,6 +721,10 @@ function pageInit() {
710 heightBefore, 721 heightBefore,
711 heightAfter; 722 heightAfter;
712 723
  724 + var mode = 2,
  725 + width = 100,
  726 + height = 100;
  727 +
713 msgList = msgList.reverse(); 728 msgList = msgList.reverse();
714 len = msgList.length; 729 len = msgList.length;
715 730
@@ -732,6 +747,11 @@ function pageInit() { @@ -732,6 +747,11 @@ function pageInit() {
732 case allRTs.CU_SEND: 747 case allRTs.CU_SEND:
733 if (!item.userHead) { 748 if (!item.userHead) {
734 item.userHead = assetsPrefix + socketConf.defaultUserHead; 749 item.userHead = assetsPrefix + socketConf.defaultUserHead;
  750 + } else {
  751 + item.userHead = item.userHead
  752 + .replace(/\{mode\}/, mode)
  753 + .replace(/\{width\}/, width)
  754 + .replace(/\{height\}/, height);
735 } 755 }
736 dom += cusTpl({ 756 dom += cusTpl({
737 userHead: item.userHead, 757 userHead: item.userHead,
@@ -916,6 +936,11 @@ function pageInit() { @@ -916,6 +936,11 @@ function pageInit() {
916 socketConfCM.type = allRTs.EVAL_NOTICE; 936 socketConfCM.type = allRTs.EVAL_NOTICE;
917 socketConfCM.uuid = uuid.v4(); 937 socketConfCM.uuid = uuid.v4();
918 socketChat.send(socketConfCM); 938 socketChat.send(socketConfCM);
  939 +
  940 + // 完成后关闭
  941 + if (processInfo.completeClose) {
  942 + window.close();
  943 + }
919 } 944 }
920 }, 945 },
921 error: function() { 946 error: function() {
@@ -45,10 +45,6 @@ function socketInit(opts) { @@ -45,10 +45,6 @@ function socketInit(opts) {
45 console.log('websocket is open'); 45 console.log('websocket is open');
46 }; 46 };
47 47
48 - socketIns.onclose = options.onClose || function() {  
49 - console.log('websocket is closed');  
50 - };  
51 -  
52 socketIns.onerror = options.onError || function(err) { 48 socketIns.onerror = options.onError || function(err) {
53 console.log(err); 49 console.log(err);
54 }; 50 };
@@ -59,6 +55,12 @@ function socketInit(opts) { @@ -59,6 +55,12 @@ function socketInit(opts) {
59 if (window.WebSocket) { 55 if (window.WebSocket) {
60 setTimeout(function() { 56 setTimeout(function() {
61 times = 1; 57 times = 1;
  58 +
  59 + // socket对象存在或者正在链接
  60 + if(socket || socket && socket.readyState === WebSocket.CONNECTING) {
  61 + return;
  62 + }
  63 +
62 socket = socketConnect(); 64 socket = socketConnect();
63 connectId = setInterval(function() { 65 connectId = setInterval(function() {
64 if (socket.readyState !== WebSocket.OPEN) { 66 if (socket.readyState !== WebSocket.OPEN) {
@@ -68,11 +70,16 @@ function socketInit(opts) { @@ -68,11 +70,16 @@ function socketInit(opts) {
68 times++; 70 times++;
69 } else { 71 } else {
70 clearInterval(connectId); 72 clearInterval(connectId);
  73 + socket = null;
71 74
72 // 连接失败回调 75 // 连接失败回调
73 options.connectFailCb(); 76 options.connectFailCb();
74 } 77 }
75 } else { 78 } else {
  79 + socket.onclose = options.onClose || function() {
  80 + console.log('websocket is closed');
  81 + };
  82 +
76 clearInterval(connectId); 83 clearInterval(connectId);
77 } 84 }
78 }, 5000); 85 }, 5000);
@@ -89,6 +96,7 @@ function sendMsg(msg) { @@ -89,6 +96,7 @@ function sendMsg(msg) {
89 if (!window.WebSocket) { 96 if (!window.WebSocket) {
90 return; 97 return;
91 } 98 }
  99 +
92 if (socket.readyState === WebSocket.OPEN) { 100 if (socket.readyState === WebSocket.OPEN) {
93 socket.send(JSON.stringify(msg)); 101 socket.send(JSON.stringify(msg));
94 } else { 102 } else {
@@ -99,16 +107,16 @@ function sendMsg(msg) { @@ -99,16 +107,16 @@ function sendMsg(msg) {
99 /** 107 /**
100 * 关闭socket 108 * 关闭socket
101 */ 109 */
102 -function closeSocket() { 110 +function clearSocket() {
103 if (socket) { 111 if (socket) {
104 - socket.close(); 112 + socket = null;
105 } 113 }
106 } 114 }
107 115
108 module.exports = { 116 module.exports = {
109 socket: socket, 117 socket: socket,
110 init: socketInit, 118 init: socketInit,
111 - close: closeSocket, 119 + clear: clearSocket,
112 send: sendMsg 120 send: sendMsg
113 }; 121 };
114 122
@@ -52,6 +52,7 @@ var config = { @@ -52,6 +52,7 @@ var config = {
52 serviceSortCode: '', 52 serviceSortCode: '',
53 customerSettingId: 0, // 预留字段, 53 customerSettingId: 0, // 预留字段,
54 roleType: 0, // 0: 用户,1:客服 54 roleType: 0, // 0: 用户,1:客服
  55 + clientType: 1, // 用户终端类别 1、PC、2、H5、3、IOS、4、安卓
55 chatMessage: { 56 chatMessage: {
56 messageObjectId: '', // 没有用 57 messageObjectId: '', // 没有用
57 type: 0, // 消息内容类型: 1:文本 2:图片 3:语音 4: 订单 58 type: 0, // 消息内容类型: 1:文本 2:图片 3:语音 4: 订单
@@ -272,6 +272,7 @@ $color-3a3a3a: #3a3a3a; @@ -272,6 +272,7 @@ $color-3a3a3a: #3a3a3a;
272 margin-bottom: 3px; 272 margin-bottom: 3px;
273 color: #c5c5c5; 273 color: #c5c5c5;
274 font-size: 12px; 274 font-size: 12px;
  275 + font-family: Helvetica;
275 } 276 }
276 277
277 .msg-bubble { 278 .msg-bubble {
@@ -281,7 +282,7 @@ $color-3a3a3a: #3a3a3a; @@ -281,7 +282,7 @@ $color-3a3a3a: #3a3a3a;
281 padding: 9px; 282 padding: 9px;
282 color: #ffffff; 283 color: #ffffff;
283 line-height: 1.5; 284 line-height: 1.5;
284 - letter-spacing: 2px; 285 + letter-spacing: 1px;
285 word-break: break-all; 286 word-break: break-all;
286 background-color: #3a3a3a; 287 background-color: #3a3a3a;
287 border-radius: 3px; 288 border-radius: 3px;
@@ -328,6 +329,7 @@ $color-3a3a3a: #3a3a3a; @@ -328,6 +329,7 @@ $color-3a3a3a: #3a3a3a;
328 margin-bottom: 3px; 329 margin-bottom: 3px;
329 color: #c5c5c5; 330 color: #c5c5c5;
330 font-size: 12px; 331 font-size: 12px;
  332 + font-family: Helvetica;
331 text-align: right; 333 text-align: right;
332 } 334 }
333 335
@@ -339,7 +341,7 @@ $color-3a3a3a: #3a3a3a; @@ -339,7 +341,7 @@ $color-3a3a3a: #3a3a3a;
339 padding: 9px; 341 padding: 9px;
340 color: #3a3a3a; 342 color: #3a3a3a;
341 line-height: 1.5; 343 line-height: 1.5;
342 - letter-spacing: 2px; 344 + letter-spacing: 1px;
343 word-break: break-all; 345 word-break: break-all;
344 background-color: #ffffff; 346 background-color: #ffffff;
345 border-radius: 3px; 347 border-radius: 3px;
@@ -1067,9 +1069,13 @@ $color-3a3a3a: #3a3a3a; @@ -1067,9 +1069,13 @@ $color-3a3a3a: #3a3a3a;
1067 .detail-reason { 1069 .detail-reason {
1068 display: none; 1070 display: none;
1069 1071
1070 - .discontent { 1072 + .dis-wrap {
  1073 + margin-left: 8px;
1071 max-height: 155px; 1074 max-height: 155px;
1072 - overflow: scroll; 1075 + overflow-y: scroll;
  1076 + overflow-x: hidden;
  1077 +
  1078 + .discontent {
1073 margin-bottom: 30px; 1079 margin-bottom: 30px;
1074 1080
1075 .dis-row { 1081 .dis-row {
@@ -1079,7 +1085,7 @@ $color-3a3a3a: #3a3a3a; @@ -1079,7 +1085,7 @@ $color-3a3a3a: #3a3a3a;
1079 .type { 1085 .type {
1080 position: relative; 1086 position: relative;
1081 display: inline-block; 1087 display: inline-block;
1082 - width: 166px; 1088 + width: 155px;
1083 height: 40px; 1089 height: 40px;
1084 padding: 0 2px; 1090 padding: 0 2px;
1085 font-size: 12px; 1091 font-size: 12px;
@@ -1112,6 +1118,7 @@ $color-3a3a3a: #3a3a3a; @@ -1112,6 +1118,7 @@ $color-3a3a3a: #3a3a3a;
1112 } 1118 }
1113 } 1119 }
1114 } 1120 }
  1121 + }
1115 1122
1116 textarea { 1123 textarea {
1117 height: 120px; 1124 height: 120px;