|
|
|
|
|
/**
|
|
|
* 在线客服客户页
|
|
|
*
|
...
|
...
|
@@ -10,6 +9,7 @@ var $ = require('yoho-jquery'), |
|
|
uuid = require('uuid'),
|
|
|
emojiMap = require('./emoji-map'),
|
|
|
countdown = require('./countdown'),
|
|
|
tab = require('./tab-hidden'),
|
|
|
socketChat = require('./socket-chat'),
|
|
|
socketConf = require('./socket-config'),
|
|
|
common = require('../../../config/common');
|
...
|
...
|
@@ -20,9 +20,13 @@ var cmEntity, |
|
|
encryptedUid,
|
|
|
cursorPosition,
|
|
|
hasMore = true,
|
|
|
titleInterval,
|
|
|
docTitle = document.title,
|
|
|
$document = $(document),
|
|
|
$msgList = $('.msg-list'),
|
|
|
$msgEdit = $('.msg-edit'),
|
|
|
$leaveMsg = $('#leaveMsg'),
|
|
|
$close = $('.header .close'),
|
|
|
$sendOrder = $('.send-order'),
|
|
|
$sendImgInput = $('#sendImg'),
|
|
|
$history = $('.about-his.has-his'),
|
...
|
...
|
@@ -33,7 +37,7 @@ var cmEntity, |
|
|
$panelMainBody = $('.panel-main .main-body');
|
|
|
|
|
|
var processInfo = {
|
|
|
csId: 0, // 客服Id
|
|
|
manual: false,
|
|
|
promoter: 1, // 评论发起者 1:客户自己 2:客服
|
|
|
savedEval: false // 是否保存过评论
|
|
|
};
|
...
|
...
|
@@ -67,24 +71,29 @@ for (key in urls) { |
|
|
}
|
|
|
}
|
|
|
|
|
|
// (function() {
|
|
|
// var param = {
|
|
|
// return_type: 'jsonp',
|
|
|
// method: 'open.passport.get'
|
|
|
// };
|
|
|
// TODO 开发环境拿不到那个jsonp 这段代码仅供开发用
|
|
|
// socketChat.init(Object.assign(socketConf, {
|
|
|
//
|
|
|
// onOpen: function() {
|
|
|
// console.log('websocket opened!');
|
|
|
// },
|
|
|
//
|
|
|
// onMessage: function(e) {
|
|
|
// var received = JSON.parse(e.data);
|
|
|
//
|
|
|
// cmEntity.conversationId = received.newConversationId !== 0 ?
|
|
|
// received.newConversationId :
|
|
|
// received.conversationId;
|
|
|
//
|
|
|
// $.getJSON('//www.yohobuy.com/common/passport/?callback=?', param, function(jsonData) {
|
|
|
// if (jsonData && jsonData.data && jsonData.data.result !== -1) {
|
|
|
// if(jsonData.data.headIco) {
|
|
|
// socketConf.conversationMessage.userHead = jsonData.data.headIco;
|
|
|
// socketConf.conversationMessage.userName = window.getUser()[0];
|
|
|
// }
|
|
|
// // 保存过程中信息
|
|
|
// getMessage(received);
|
|
|
// },
|
|
|
//
|
|
|
// // 原始配置信息用于重新连线
|
|
|
// originConf = JSON.parse(JSON.stringify(socketConf));
|
|
|
// }
|
|
|
// });
|
|
|
// }());
|
|
|
// onClose: function() {
|
|
|
// console.log('websocket closed!');
|
|
|
// }
|
|
|
//
|
|
|
// }));
|
|
|
|
|
|
/**
|
|
|
* 设置光标位置
|
...
|
...
|
@@ -222,9 +231,8 @@ function toggleAnswer(e) { |
|
|
/**
|
|
|
* 连线客服
|
|
|
*/
|
|
|
function connectService() {
|
|
|
function manualService() {
|
|
|
cmEntity.type = 2;
|
|
|
console.log(cmEntity);
|
|
|
socketChat.send(JSON.stringify(cmEntity));
|
|
|
|
|
|
}
|
...
|
...
|
@@ -286,13 +294,16 @@ function enterSuccess(message) { |
|
|
* @param message 内部消息对象
|
|
|
* @private
|
|
|
*/
|
|
|
function _linkSuccess(msgType, message) {
|
|
|
function linkSuccess(msgType, message) {
|
|
|
|
|
|
var OUT_SERVICE = 0,
|
|
|
LINE_UP = 1,
|
|
|
MANUAL_SERVICE = 2;
|
|
|
MANUAL_SERVICE = 2,
|
|
|
ADMIN_MANUAL_SERVICE = 3;
|
|
|
|
|
|
var liHtml;
|
|
|
var liHtml,
|
|
|
$iconEval = $('.icon.evaluate'),
|
|
|
$iconMs = $('.icon.manual-service');
|
|
|
|
|
|
switch (msgType) {
|
|
|
|
...
|
...
|
@@ -323,6 +334,29 @@ function _linkSuccess(msgType, message) { |
|
|
<span class="tip">${message.content}</span>
|
|
|
</p>
|
|
|
</div>`;
|
|
|
|
|
|
// 接入人工客服需要评价
|
|
|
processInfo.manual = true;
|
|
|
|
|
|
// 显示评价&隐藏人工
|
|
|
$iconEval.show();
|
|
|
$iconMs.hide();
|
|
|
break;
|
|
|
|
|
|
case ADMIN_MANUAL_SERVICE: // 3是管理员分配客服成功
|
|
|
liHtml =
|
|
|
`<div class="list-item">
|
|
|
<p class="push-tip">
|
|
|
<span class="tip">${message.content}</span>
|
|
|
</p>
|
|
|
</div>`;
|
|
|
|
|
|
// 接入人工客服需要评价
|
|
|
processInfo.manual = true;
|
|
|
|
|
|
// 显示评价&隐藏人工
|
|
|
$iconEval.show();
|
|
|
$iconMs.hide();
|
|
|
break;
|
|
|
|
|
|
default:
|
...
|
...
|
@@ -339,7 +373,7 @@ function _linkSuccess(msgType, message) { |
|
|
* @param text 文本
|
|
|
* @private
|
|
|
*/
|
|
|
function _emojiPrefix(text) {
|
|
|
function emojiPrefix(text) {
|
|
|
if (typeof text === 'string') {
|
|
|
return text.replace(/src="(\d{3}).gif"/g, 'src="/img/service/emoji/$1.gif"');
|
|
|
}
|
...
|
...
|
@@ -351,10 +385,10 @@ function _emojiPrefix(text) { |
|
|
* 处理客户消息
|
|
|
* @private
|
|
|
*/
|
|
|
function _handleCusMsg(rec, msgType, message) {
|
|
|
function handleCusMsg(rec, msgType, message) {
|
|
|
var liHtml;
|
|
|
|
|
|
message.newContent = _emojiPrefix(message.newContent);
|
|
|
message.newContent = emojiPrefix(message.newContent);
|
|
|
|
|
|
// 图片添加标签
|
|
|
if (msgType === 2) {
|
...
|
...
|
@@ -372,8 +406,6 @@ function _handleCusMsg(rec, msgType, message) { |
|
|
</div>
|
|
|
</div>`;
|
|
|
|
|
|
|
|
|
// targetItem.replaceWith(liHtml);
|
|
|
$msgList.append(liHtml);
|
|
|
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
|
|
|
|
...
|
...
|
@@ -383,7 +415,7 @@ function _handleCusMsg(rec, msgType, message) { |
|
|
* 链接终端倒计时
|
|
|
* @private
|
|
|
*/
|
|
|
function _breakCountdown(message) {
|
|
|
function breakCountdown(message) {
|
|
|
var liHtml;
|
|
|
|
|
|
liHtml =
|
...
|
...
|
@@ -401,25 +433,21 @@ function _breakCountdown(message) { |
|
|
|
|
|
// 倒计时信息
|
|
|
countdown(message.newContent, $('.tip .countdown'));
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理客服消息
|
|
|
* @private
|
|
|
*/
|
|
|
function _handleCsMsg(rec, msgType, message) {
|
|
|
function handleCsMsg(rec, msgType, message) {
|
|
|
|
|
|
var liHtml;
|
|
|
|
|
|
message.newContent = _emojiPrefix(message.newContent);
|
|
|
|
|
|
message.newContent = emojiPrefix(message.newContent);
|
|
|
if (msgType === 2) {
|
|
|
message.newContent =
|
|
|
`<img class="img-msg" src="${message.content}">`;
|
|
|
}
|
|
|
|
|
|
liHtml = `<div class="list-item guest">
|
|
|
<img src="${rec.csHead}" class="avatar">
|
|
|
<div class="item-detail">
|
...
|
...
|
@@ -440,8 +468,8 @@ function _handleCsMsg(rec, msgType, message) { |
|
|
function showEvalModal() {
|
|
|
var $evalModal = $('#makeEvaluation');
|
|
|
|
|
|
// 没有客服不可以评价
|
|
|
if (!processInfo.csId) {
|
|
|
// 没有接入人工
|
|
|
if (!processInfo.manual) {
|
|
|
return;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -457,10 +485,10 @@ function showEvalModal() { |
|
|
|
|
|
html +=
|
|
|
`<div class="dis-row">
|
|
|
<span class="type" data-id="${data[i].id}">
|
|
|
<span class="type" data-id="${data[i].id}" data-content="${data[i].content}">
|
|
|
${data[i].content}
|
|
|
</span>
|
|
|
<span class="type" data-id="${data[i + 1].id}">
|
|
|
<span class="type" data-id="${data[i + 1].id}" data-content="${data[i].content}">
|
|
|
${data[i + 1].content}
|
|
|
</span>
|
|
|
</div>`;
|
...
|
...
|
@@ -472,10 +500,10 @@ function showEvalModal() { |
|
|
for (r = 1, i = 0; r <= ceilRows - 1; r++) {
|
|
|
html +=
|
|
|
`<div class="dis-row">
|
|
|
<span class="type" data-id="${data[i].id}">
|
|
|
<span class="type" data-id="${data[i].id}" data-content="${data[i].content}">
|
|
|
${data[i].content}
|
|
|
</span>
|
|
|
<span class="type" data-id="${data[i + 1].id}">
|
|
|
<span class="type" data-id="${data[i + 1].id}" data-content="${data[i].content}">
|
|
|
${data[i + 1].content}
|
|
|
</span>
|
|
|
</div>`;
|
...
|
...
|
@@ -483,7 +511,7 @@ function showEvalModal() { |
|
|
}
|
|
|
html +=
|
|
|
`<div class="dis-row">
|
|
|
<span class="type" data-id="${data[len - 1].id}">
|
|
|
<span class="type" data-id="${data[len - 1].id}" data-content="${data[i].content}">
|
|
|
${data[len - 1].content}
|
|
|
</span>
|
|
|
</div>`;
|
...
|
...
|
@@ -516,15 +544,24 @@ function showEvalModal() { |
|
|
* 处理收到消息
|
|
|
*/
|
|
|
function getMessage(rec) {
|
|
|
|
|
|
var tipTpl,
|
|
|
recType = rec.type,
|
|
|
message = rec.message,
|
|
|
msgType = message.type,
|
|
|
isHidden = tab.tabIsHidden(),
|
|
|
allTypes = socketConf.recType;
|
|
|
|
|
|
console.log('客户收到消息!', rec);
|
|
|
|
|
|
if (isHidden) {
|
|
|
titleInterval = setInterval(function() {
|
|
|
document.title = '您有新消息!';
|
|
|
setTimeout(function() {
|
|
|
document.title = docTitle;
|
|
|
}, 300);
|
|
|
}, 600);
|
|
|
}
|
|
|
|
|
|
switch (recType) {
|
|
|
|
|
|
case allTypes.ENTER:
|
...
|
...
|
@@ -532,20 +569,20 @@ function getMessage(rec) { |
|
|
break;
|
|
|
|
|
|
case allTypes.LINK_SUCCESS:
|
|
|
_linkSuccess(msgType, message);
|
|
|
linkSuccess(msgType, message);
|
|
|
break;
|
|
|
|
|
|
case allTypes.CU_SEND:
|
|
|
_handleCusMsg(rec, msgType, message);
|
|
|
handleCusMsg(rec, msgType, message);
|
|
|
break;
|
|
|
|
|
|
case allTypes.BREAK_TIME:
|
|
|
_breakCountdown(message);
|
|
|
breakCountdown(message);
|
|
|
break;
|
|
|
|
|
|
case allTypes.ROBOT_SEND:
|
|
|
rec.csName = rec.csName || '客服机器人';
|
|
|
message.newContent = message.newContent || '机器人暂时无法提供服务';
|
|
|
message.newContent = message.newContent || '非常抱歉,小YO不是很理解您的问题,您也可以联系<a>人工客服</a>';
|
|
|
tipTpl = `<div class="list-item guest">
|
|
|
<img src="/img/service/robot-avatar.png" class="avatar">
|
|
|
<div class="item-detail">
|
...
|
...
|
@@ -559,20 +596,17 @@ function getMessage(rec) { |
|
|
break;
|
|
|
|
|
|
case allTypes.CS_SEND:
|
|
|
|
|
|
// 处理客服消息
|
|
|
_handleCsMsg(rec, msgType, message);
|
|
|
handleCsMsg(rec, msgType, message);
|
|
|
break;
|
|
|
|
|
|
case allTypes.EVAL_INVITE:
|
|
|
|
|
|
// 客服发起
|
|
|
processInfo.promoter = 2;
|
|
|
showEvalModal();
|
|
|
break;
|
|
|
|
|
|
case allTypes.CS_CHATTING:
|
|
|
|
|
|
// 正在人工会话
|
|
|
csChatting(message);
|
|
|
break;
|
...
|
...
|
@@ -618,10 +652,10 @@ function msgResolve(msgList) { |
|
|
|
|
|
if (hasMore) {
|
|
|
for (item of msgList) {
|
|
|
item.message.newContent = _emojiPrefix(item.message.newContent);
|
|
|
item.message.newContent = emojiPrefix(item.message.newContent);
|
|
|
if (item.message.type === 2) {
|
|
|
item.message.newContent =
|
|
|
['<img class="msg-img" src="', item.message.newContent, '">'].join('');
|
|
|
['<img class="img-msg" src="', item.message.newContent, '">'].join('');
|
|
|
}
|
|
|
|
|
|
// 客户自己的消息
|
...
|
...
|
@@ -683,30 +717,11 @@ function fetchHistoryMsg() { |
|
|
});
|
|
|
}
|
|
|
|
|
|
// 初始化socket连接
|
|
|
socketChat.init(Object.assign(socketConf, {
|
|
|
|
|
|
onOpen: function() {
|
|
|
console.log('websocket opened!');
|
|
|
},
|
|
|
|
|
|
onMessage: function(e) {
|
|
|
var received = JSON.parse(e.data);
|
|
|
|
|
|
cmEntity.conversationId = received.newConversationId !== 0 ?
|
|
|
received.newConversationId :
|
|
|
received.conversationId;
|
|
|
|
|
|
// 保存过程中信息
|
|
|
processInfo.csId = received.csId;
|
|
|
getMessage(received);
|
|
|
},
|
|
|
|
|
|
onClose: function() {
|
|
|
console.log('websocket closed!');
|
|
|
}
|
|
|
|
|
|
}));
|
|
|
// tab页title重置
|
|
|
tab.tabVisible(function() {
|
|
|
document.title = docTitle;
|
|
|
clearInterval(titleInterval);
|
|
|
});
|
|
|
|
|
|
// 提交留言
|
|
|
$leaveMsg.find('.submit').click(function() {
|
...
|
...
|
@@ -740,28 +755,35 @@ $makeEvalModal.find('.submit').click(function() { |
|
|
star = mEval.find('.star.positive').length,
|
|
|
reasonTypes = mEval.find('.dis-row .type.chosen');
|
|
|
|
|
|
var reasonIds,
|
|
|
idArray = [];
|
|
|
|
|
|
$.each(reasonTypes, function(index, item) {
|
|
|
idArray.push($(item).data('id'));
|
|
|
});
|
|
|
var data = {
|
|
|
conversationId: cmEntity.conversationId,
|
|
|
encryptedUid: encryptedUid,
|
|
|
promoter: processInfo.promoter,
|
|
|
stars: star
|
|
|
};
|
|
|
|
|
|
reasonIds = idArray.join(':');
|
|
|
var contents,
|
|
|
reasonIds,
|
|
|
idArray = [],
|
|
|
contentArray = [];
|
|
|
|
|
|
if (star < 4) {
|
|
|
$.each(reasonTypes, function(index, item) {
|
|
|
idArray.push($(item).data('id'));
|
|
|
contentArray.push($(item).data('content'));
|
|
|
});
|
|
|
|
|
|
reasonIds = idArray.join(':');
|
|
|
contents = contentArray.join(':');
|
|
|
data.reasonIds = reasonIds;
|
|
|
data.reasonMsgs = contents;
|
|
|
data.reasonMsg = reason;
|
|
|
}
|
|
|
|
|
|
$.ajax({
|
|
|
type: 'POST',
|
|
|
url: urls.makeEval,
|
|
|
data: {
|
|
|
conversationId: cmEntity.conversationId,
|
|
|
csId: processInfo.csId,
|
|
|
pid: cmEntity.platId,
|
|
|
promoter: processInfo.promoter,
|
|
|
reasonIds: reasonIds || '',
|
|
|
reasonMsgs: reason,
|
|
|
stars: star,
|
|
|
encryptedUid: encryptedUid
|
|
|
},
|
|
|
data: data,
|
|
|
success: function(res) {
|
|
|
if (res && res.code === 200) {
|
|
|
processInfo.promoter = 1;
|
...
|
...
|
@@ -874,32 +896,35 @@ $sendImgInput.fileupload({ |
|
|
// 订单信息、常见问题
|
|
|
$rightHeadTab.on('click', function() {
|
|
|
var $el = $(this),
|
|
|
orderTab = $el.hasClass('order');
|
|
|
|
|
|
if ($el.hasClass('active')) {
|
|
|
$siblings = $el.siblings(),
|
|
|
$panRight = $('.panel-right'),
|
|
|
order = $el.hasClass('order'),
|
|
|
active = $el.hasClass('active'),
|
|
|
$qaUse = $panRight.find('.qa-use'),
|
|
|
$orderUse = $panRight.find('.order-use');
|
|
|
|
|
|
if (active) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (orderTab) {
|
|
|
$('.right-head .tab.order').toggleClass('active');
|
|
|
$('.right-head .tab.qa').toggleClass('active');
|
|
|
$('.right-body.order').show();
|
|
|
$('.right-body.qa').hide();
|
|
|
$('.right-footer.qa').hide();
|
|
|
$el.addClass('active');
|
|
|
$siblings.removeClass('active');
|
|
|
|
|
|
if (order) {
|
|
|
$qaUse.hide();
|
|
|
$orderUse.show();
|
|
|
} else {
|
|
|
$('.right-head .tab.order').toggleClass('active');
|
|
|
$('.right-head .tab.qa').toggleClass('active');
|
|
|
$('.right-body.order').hide();
|
|
|
$('.right-body.qa').show();
|
|
|
$('.right-footer.qa').show();
|
|
|
$qaUse.show();
|
|
|
$orderUse.hide();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 星评
|
|
|
$('.make-eval .stars .star').on('click', function() {
|
|
|
$document.on('click', '.make-eval .star', function() {
|
|
|
var el, i, len,
|
|
|
tag = $(this),
|
|
|
index = tag.index(),
|
|
|
$detailReason = $('.detail-reason'),
|
|
|
textEl = $('.make-eval .star-text'),
|
|
|
startList = $('.make-eval .stars .star');
|
|
|
|
...
|
...
|
@@ -917,11 +942,13 @@ $('.make-eval .stars .star').on('click', function() { |
|
|
el.index() > index && el.removeClass('positive');
|
|
|
}
|
|
|
|
|
|
index < 3 && $detailReason.show();
|
|
|
index >= 3 && $detailReason.hide();
|
|
|
textEl.text(starText[index]);
|
|
|
});
|
|
|
|
|
|
// 选择不满意类型
|
|
|
$(document).on('click', '.dis-row .type', function(e) {
|
|
|
$document.on('click', '.dis-row .type', function(e) {
|
|
|
$(e.target).toggleClass('chosen');
|
|
|
});
|
|
|
|
...
|
...
|
@@ -958,7 +985,7 @@ $msgEdit.find('.util .icon').on('click', function(e) { |
|
|
},
|
|
|
|
|
|
3: function() {
|
|
|
connectService();
|
|
|
manualService();
|
|
|
}
|
|
|
};
|
|
|
|
...
|
...
|
@@ -969,13 +996,11 @@ $msgEdit.find('.util .icon').on('click', function(e) { |
|
|
});
|
|
|
|
|
|
// 设置表情
|
|
|
$('.emoji-component .emoji').on('click', setEmoji);
|
|
|
$document.on('click', '.emoji-component .emoji', setEmoji);
|
|
|
|
|
|
// 重新连线
|
|
|
$msgList.on('click', '.reconnect', function() {
|
|
|
|
|
|
socketChat.init(Object.assign(originConf, {
|
|
|
|
|
|
onOpen: function() {
|
|
|
console.log('websocket opened!');
|
|
|
},
|
...
|
...
|
@@ -985,8 +1010,8 @@ $msgList.on('click', '.reconnect', function() { |
|
|
var received = JSON.parse(jsonString);
|
|
|
|
|
|
cmEntity.conversationId = received.newConversationId !== 0 ?
|
|
|
received.newConversationId :
|
|
|
received.conversationId;
|
|
|
received.newConversationId :
|
|
|
received.conversationId;
|
|
|
|
|
|
getMessage(received);
|
|
|
},
|
...
|
...
|
@@ -1002,8 +1027,8 @@ $msgList.on('click', '.reconnect', function() { |
|
|
$msgEdit.find('.send').on('click', sendMessage);
|
|
|
|
|
|
// 关闭聊天窗口
|
|
|
$('.header .close').click(function() {
|
|
|
if (processInfo.csId && !processInfo.savedEval) { // 没有保存过评论
|
|
|
$close.click(function() {
|
|
|
if (processInfo.manual && !processInfo.savedEval) { // 没有保存过评论
|
|
|
showEvalModal();
|
|
|
} else {
|
|
|
window.close();
|
...
|
...
|
@@ -1023,8 +1048,8 @@ $msgList.on('click', '.msg-bubble .img-msg', function(e) { |
|
|
msgZoomIn.fadeIn();
|
|
|
});
|
|
|
|
|
|
$('.img-zoom-in').on('click', function(e) {
|
|
|
$(e.currentTarget).fadeOut();
|
|
|
$document.on('click', '.img-zoom-in', function() {
|
|
|
$(this).fadeOut();
|
|
|
});
|
|
|
|
|
|
// 显示历史记录
|
...
|
...
|
@@ -1038,13 +1063,44 @@ $panelMainBody.scroll(function() { |
|
|
});
|
|
|
|
|
|
|
|
|
// 用户信息获取并初始化socket连接
|
|
|
(function() {
|
|
|
var param = {
|
|
|
return_type: 'jsonp',
|
|
|
method: 'open.passport.get'
|
|
|
};
|
|
|
|
|
|
$.getJSON('//www.yohobuy.com/common/passport/?callback=?', param, function(jsonData) {
|
|
|
if (jsonData && jsonData.data && jsonData.data.result !== -1) {
|
|
|
|
|
|
socketConf.conversationMessage.userHead = jsonData.data.headIco || socketConf.config.defaultUserHead;
|
|
|
socketConf.conversationMessage.userName = window.getUser()[0];
|
|
|
|
|
|
// 原始配置信息用于重新连线
|
|
|
originConf = JSON.parse(JSON.stringify(socketConf));
|
|
|
|
|
|
socketChat.init(Object.assign(socketConf, {
|
|
|
|
|
|
onOpen: function() {
|
|
|
console.log('websocket opened!');
|
|
|
},
|
|
|
|
|
|
onMessage: function(e) {
|
|
|
var received = JSON.parse(e.data);
|
|
|
|
|
|
cmEntity.conversationId = received.newConversationId !== 0 ?
|
|
|
received.newConversationId :
|
|
|
received.conversationId;
|
|
|
|
|
|
// 保存过程中信息
|
|
|
getMessage(received);
|
|
|
},
|
|
|
|
|
|
onClose: function() {
|
|
|
console.log('websocket closed!');
|
|
|
}
|
|
|
|
|
|
}));
|
|
|
}
|
|
|
});
|
|
|
}()); |
...
|
...
|
|