Authored by 李奇

fixed:配置信息修改

... ... @@ -7,6 +7,7 @@
'use strict';
const aes = require('./aes-pwd');
const common = require('../../../config/common');
const clientService = require('../models/client-service');
/**
... ... @@ -27,7 +28,16 @@ const index = (req, res) => {
});
};
/**
* 在线客服客户端
*/
const domains = (req, res) => {
// 返回当前环境的配置信息
res.json(common.domains);
};
module.exports = {
index
index,
domains
};
... ...
... ... @@ -14,5 +14,6 @@ const client = require(`${cRoot}/client`);
// 在线客服
router.get('/client', auth, client.index); // 在线客服
router.get('/domains', auth, client.domains); // 域名配置
module.exports = router;
... ...
... ... @@ -11,8 +11,7 @@ var $ = require('yoho-jquery'),
countdown = require('./countdown'),
tab = require('./tab-hidden'),
socketChat = require('./socket-chat'),
socketConf = require('./socket-config'),
common = require('../../../config/common');
socketConf = require('./socket-config');
var allRTs,
endTime,
... ... @@ -21,6 +20,7 @@ var allRTs,
socketConfCM,
assetsPrefix,
cursorPosition,
configDomains,
hasMore = true,
titleInterval,
$html = $('html'),
... ... @@ -68,352 +68,348 @@ assetsPrefix = $assetsPrefix.val();
socketConfCM = socketConf.conversationMessage;
socketConfCM.encryptedUid = encryptedUid;
// 原始配置信息用于重新连线
originConf = JSON.parse(JSON.stringify(socketConf));
// url前缀添加
for (key in urls) {
if (urls.hasOwnProperty(key)) {
urls[key] = common.domains.imCs + urls[key];
// 页面初始化
function pageInit() {
// 原始配置信息用于重新连线
originConf = JSON.parse(JSON.stringify(socketConf));
/**
* 设置光标位置
* @param el
* @param pos
*/
function setCurPos(el, pos) {
var range;
if (el.setSelectionRange) {
// chrome and firefox support
el.setSelectionRange(pos, pos);
el.focus();
} else if (el.createTextRange) {
// IE support
range = el.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
}
/**
* 设置光标位置
* @param el
* @param pos
*/
function setCurPos(el, pos) {
var range;
if (el.setSelectionRange) {
// chrome and firefox support
el.setSelectionRange(pos, pos);
el.focus();
} else if (el.createTextRange) {
// IE support
range = el.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
/**
* 表情设置
* @param e
*/
function setEmoji(e) {
var i,
len,
pos,
start,
end,
newVal,
emojiText,
textDom,
tag = $(e.target),
area = $('.msg-area'),
val = area.val(),
emojiId = tag.data('id'),
comp = $('.emoji-component');
for (i = 0, len = emojiMap.length; i < len; i++) {
if (emojiMap[i].file === emojiId.toString()) {
emojiText = emojiMap[i].text;
}
}
/**
* 表情设置
* @param e
*/
function setEmoji(e) {
var i,
len,
pos,
start,
end,
newVal,
emojiText,
textDom,
tag = $(e.target),
area = $('.msg-area'),
val = area.val(),
emojiId = tag.data('id'),
comp = $('.emoji-component');
for (i = 0, len = emojiMap.length; i < len; i++) {
if (emojiMap[i].file === emojiId.toString()) {
emojiText = emojiMap[i].text;
if (cursorPosition) {
start = val.substring(0, cursorPosition);
end = val.substring(cursorPosition);
newVal = [start, emojiText, end].join('');
} else {
newVal = [val, emojiText].join('');
}
}
if (cursorPosition) {
start = val.substring(0, cursorPosition);
end = val.substring(cursorPosition);
newVal = [start, emojiText, end].join('');
} else {
newVal = [val, emojiText].join('');
}
comp.hide();
area.val(newVal);
cursorPosition += emojiText.length;
comp.hide();
area.val(newVal);
cursorPosition += emojiText.length;
textDom = area[0];
pos = cursorPosition ? cursorPosition : newVal.length;
setCurPos(textDom, pos);
}
textDom = area[0];
pos = cursorPosition ? cursorPosition : newVal.length;
setCurPos(textDom, pos);
}
/**
* 系统通知
* @param type 通知类型
* @param msg 具体消息
*/
function systemTip(type, msg) {
var tip,
liHtml;
/**
* 系统通知
* @param type 通知类型
* @param msg 具体消息
*/
function systemTip(type, msg) {
var tip,
liHtml;
var tipMap = {
var tipMap = {
};
};
if (type) {
tip = tipMap[type];
} else {
tip = msg;
}
if (type) {
tip = tipMap[type];
} else {
tip = msg;
}
liHtml =
`<div class="list-item">
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${tip}</span>
</p>
</div>`;
// 添加消息
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
// 添加消息
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
/**
* 发送消息前的共通处理
*/
function beforeSendMsg() {
var $countdown = $('.countdown');
/**
* 发送消息前的共通处理
*/
function beforeSendMsg() {
var $countdown = $('.countdown');
$countdown.parents('.list-item').remove();
if (titleInterval) {
clearInterval(titleInterval);
document.title = docTitle;
$countdown.parents('.list-item').remove();
if (titleInterval) {
clearInterval(titleInterval);
document.title = docTitle;
}
}
}
/**
* 处理发送消息
* @param e
* @param msgType
* @param msgContent
*/
function sendMessage(e, msgType, msgContent) {
var $area = $('.msg-area'),
msg = $area.val().trim();
/**
* 处理发送消息
* @param e
* @param msgType
* @param msgContent
*/
function sendMessage(e, msgType, msgContent) {
var $area = $('.msg-area'),
msg = $area.val().trim();
// 发送前共通处理清除计时器和title提示
beforeSendMsg();
if (!msgContent) {
if (!msg) {
return;
}
socketConfCM.type = allRTs.CU_SEND;
socketConfCM.uuid = uuid.v4();
socketConfCM.message.content = msg;
socketConfCM.message.type = msgType || 1;
socketChat.send(socketConfCM);
$area.val('');
// 发送前共通处理清除计时器和title提示
beforeSendMsg();
} else {
socketConfCM.type = allRTs.CU_SEND;
socketConfCM.uuid = uuid.v4();
socketConfCM.message.type = msgType || 1;
socketConfCM.message.content = msgContent;
socketChat.send(socketConfCM);
}
}
if (!msgContent) {
if (!msg) {
/**
* enter提交
* enter+ctrl换行
*/
function msgEnterAction(e) {
var code = e.keyCode,
tag = $(e.target),
val = tag.val(),
pos = tag.getCursorPosition(),
start = val.substring(0, pos),
end = val.substring(pos),
newVal = [start, '\n', end].join(''),
ctrlLike = e.ctrlKey || e.metaKey;
if (code !== 13) {
return;
}
socketConfCM.type = allRTs.CU_SEND;
socketConfCM.uuid = uuid.v4();
socketConfCM.message.content = msg;
socketConfCM.message.type = msgType || 1;
socketChat.send(socketConfCM);
$area.val('');
} else {
socketConfCM.type = allRTs.CU_SEND;
socketConfCM.uuid = uuid.v4();
socketConfCM.message.type = msgType || 1;
socketConfCM.message.content = msgContent;
socketChat.send(socketConfCM);
if (!ctrlLike) {
e.preventDefault();
sendMessage(e);
} else {
tag.val(newVal);
setCurPos(tag[0], pos + 1);
}
}
}
/**
* enter提交
* enter+ctrl换行
*/
function msgEnterAction(e) {
var code = e.keyCode,
tag = $(e.target),
val = tag.val(),
pos = tag.getCursorPosition(),
start = val.substring(0, pos),
end = val.substring(pos),
newVal = [start, '\n', end].join(''),
ctrlLike = e.ctrlKey || e.metaKey;
if (code !== 13) {
return;
}
/**
* 常见问题
*/
function toggleAnswer(e) {
var cTag = $(e.currentTarget),
parent = cTag.parent(),
next = cTag.next();
if (!ctrlLike) {
e.preventDefault();
sendMessage(e);
} else {
tag.val(newVal);
setCurPos(tag[0], pos + 1);
next.length && next.toggle();
next.length && parent.toggleClass('has-a');
}
}
/**
* 常见问题
*/
function toggleAnswer(e) {
var cTag = $(e.currentTarget),
parent = cTag.parent(),
next = cTag.next();
next.length && next.toggle();
next.length && parent.toggleClass('has-a');
}
/**
* 人工客服 s
*/
function manualService() {
socketConfCM.type = allRTs.MANUAL_SERVICE;
socketChat.send(socketConfCM);
}
/**
* 人工客服 s
*/
function manualService() {
socketConfCM.type = allRTs.MANUAL_SERVICE;
socketChat.send(socketConfCM);
}
/**
* 正在进行人工会话
*/
function csChatting(message) {
// 系统通知
systemTip('', message.newContent);
}
/**
* 正在进行人工会话
*/
function csChatting(message) {
// 系统通知
systemTip('', message.newContent);
}
/**
* 留言
*/
function leaveMsg() {
var lMsg = $('#leaveMsg'),
txt = lMsg.find('textarea');
/**
* 留言
*/
function leaveMsg() {
var lMsg = $('#leaveMsg'),
txt = lMsg.find('textarea');
txt.val('');
lMsg.modal({
show: true
});
}
txt.val('');
lMsg.modal({
show: true
});
}
/**
* 成功进入在线客服
*/
function enterSuccess(message) {
var $iconMs = $('.icon.manual-service');
/**
* 成功进入在线客服
*/
function enterSuccess(message) {
var $iconMs = $('.icon.manual-service');
// 系统通知
systemTip('', message.content);
// 系统通知
systemTip('', message.content);
// 进入成功显示人工客服
$iconMs.show();
}
// 进入成功显示人工客服
$iconMs.show();
}
/**
* 人工链接
* @param msgType 内部消息类型
* @param message 内部消息对象
* @private
*/
function linkSuccess(msgType, message) {
/**
* 人工链接
* @param msgType 内部消息类型
* @param message 内部消息对象
* @private
*/
function linkSuccess(msgType, message) {
var OUT_SERVICE = 0,
LINE_UP = 1,
MANUAL_SERVICE = 2,
ADMIN_MANUAL_SERVICE = 3;
var OUT_SERVICE = 0,
LINE_UP = 1,
MANUAL_SERVICE = 2,
ADMIN_MANUAL_SERVICE = 3;
var liHtml,
$iconEval = $('.icon.evaluate'),
$iconMs = $('.icon.manual-service');
var liHtml,
$iconEval = $('.icon.evaluate'),
$iconMs = $('.icon.manual-service');
switch (msgType) {
switch (msgType) {
case OUT_SERVICE: // 0是没上班
liHtml =
`<div class="list-item">
case OUT_SERVICE: // 0是没上班
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}<a class="leave-msg">留言</a></span>
</p>
</div>`;
break;
break;
case LINE_UP: // 1是需要排队
liHtml =
`<div class="list-item">
case LINE_UP: // 1是需要排队
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">
${message.content}您也可以选择<a class="leave-msg">留言</a>
</span>
</p>
</div>`;
break;
break;
case MANUAL_SERVICE: // 2是接入人工成功
liHtml =
`<div class="list-item">
case MANUAL_SERVICE: // 2是接入人工成功
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}</span>
</p>
</div>`;
// 接入人工客服需要评价
processInfo.manual = true;
// 接入人工客服需要评价
processInfo.manual = true;
// 显示评价&隐藏人工
$iconEval.show();
$iconMs.hide();
break;
// 显示评价&隐藏人工
$iconEval.show();
$iconMs.hide();
break;
case ADMIN_MANUAL_SERVICE: // 3是管理员分配客服成功
liHtml =
`<div class="list-item">
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;
// 接入人工客服需要评价
processInfo.manual = true;
// 显示评价&隐藏人工
$iconEval.show();
$iconMs.hide();
break;
// 显示评价&隐藏人工
$iconEval.show();
$iconMs.hide();
break;
default:
break;
default:
break;
}
// 添加消息
liHtml && $msgList.append(liHtml);
liHtml && $panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
// 添加消息
liHtml && $msgList.append(liHtml);
liHtml && $panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
/**
* 返回表情路径处理
* @param text 文本
* @private
*/
function emojiPrefix(text) {
if (typeof text === 'string') {
return text.replace(/src="(\d{3}).gif"/g, 'src="' + assetsPrefix + '/img/service/emoji/$1.gif"');
}
/**
* 返回表情路径处理
* @param text 文本
* @private
*/
function emojiPrefix(text) {
if (typeof text === 'string') {
return text.replace(/src="(\d{3}).gif"/g, 'src="' + assetsPrefix + '/img/service/emoji/$1.gif"');
return text;
}
return text;
}
/**
* 处理客户消息
* @private
*/
function handleCusMsg(rec, msgType, message) {
var liHtml;
/**
* 处理客户消息
* @private
*/
function handleCusMsg(rec, msgType, message) {
var liHtml;
message.newContent = emojiPrefix(message.newContent);
message.newContent = emojiPrefix(message.newContent);
// 用户头像处理
if (!rec.userHead) {
rec.userHead = assetsPrefix + socketConf.defaultUserHead;
}
// 用户头像处理
if (!rec.userHead) {
rec.userHead = assetsPrefix + socketConf.defaultUserHead;
}
// 图片添加标签
if (msgType === 2) {
message.newContent =
`<img class="img-msg" src="${message.content}">`;
}
// 图片添加标签
if (msgType === 2) {
message.newContent =
`<img class="img-msg" src="${message.content}">`;
}
liHtml = `<div class="list-item host">
liHtml = `<div class="list-item host">
<img src="${rec.userHead}" class="avatar">
<div class="item-detail">
<span class="time">${rec.userName} ${rec.sendTimeShort}</span>
... ... @@ -423,20 +419,20 @@ function handleCusMsg(rec, msgType, message) {
</div>
</div>`;
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
}
/**
* 链接终端倒计时
* @private
*/
function breakCountdown(message) {
var liHtml;
/**
* 链接终端倒计时
* @private
*/
function breakCountdown(message) {
var liHtml;
liHtml =
`<div class="list-item">
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">
${message.content}
... ... @@ -445,27 +441,27 @@ function breakCountdown(message) {
</p>
</div>`;
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
// 倒计时信息
countdown(message.newContent, $('.tip .countdown'));
}
// 倒计时信息
countdown(message.newContent, $('.tip .countdown'));
}
/**
* 处理客服消息
* @private
*/
function handleCsMsg(rec, msgType, message) {
/**
* 处理客服消息
* @private
*/
function handleCsMsg(rec, msgType, message) {
var liHtml;
var liHtml;
message.newContent = emojiPrefix(message.newContent);
if (msgType === 2) {
message.newContent =
`<img class="img-msg" src="${message.content}">`;
}
liHtml = `<div class="list-item guest">
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">
<span class="time">${rec.csName} ${rec.sendTimeShort}</span>
... ... @@ -475,33 +471,33 @@ function handleCsMsg(rec, msgType, message) {
</div>
</div>`;
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
$msgList.append(liHtml);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
/**
* 显示评价弹框
*/
function showEvalModal() {
var $evalModal = $('#makeEvaluation');
/**
* 显示评价弹框
*/
function showEvalModal() {
var $evalModal = $('#makeEvaluation');
// 没有接入人工
if (!processInfo.manual) {
return;
}
// 没有接入人工
if (!processInfo.manual) {
return;
}
// 评价原因
function discontentHtml(len, data) {
var i, r,
html = '',
ceilRows = Math.ceil(len / 2),
floorRows = Math.floor(len / 2);
// 评价原因
function discontentHtml(len, data) {
var i, r,
html = '',
ceilRows = Math.ceil(len / 2),
floorRows = Math.floor(len / 2);
if (ceilRows === floorRows) {
for (r = 1, i = 0; r <= ceilRows; r++) {
if (ceilRows === floorRows) {
for (r = 1, i = 0; r <= ceilRows; r++) {
html +=
`<div class="dis-row">
html +=
`<div class="dis-row">
<span class="type" data-id="${data[i].id}" data-content="${data[i].content}">
${data[i].content}
</span>
... ... @@ -510,13 +506,13 @@ function showEvalModal() {
</span>
</div>`;
i += 2;
}
i += 2;
}
} else {
for (r = 1, i = 0; r <= ceilRows - 1; r++) {
html +=
`<div class="dis-row">
} else {
for (r = 1, i = 0; r <= ceilRows - 1; r++) {
html +=
`<div class="dis-row">
<span class="type" data-id="${data[i].id}" data-content="${data[i].content}">
${data[i].content}
</span>
... ... @@ -524,81 +520,81 @@ function showEvalModal() {
${data[i + 1].content}
</span>
</div>`;
i += 2;
}
html +=
`<div class="dis-row">
i += 2;
}
html +=
`<div class="dis-row">
<span class="type" data-id="${data[len - 1].id}" data-content="${data[i].content}">
${data[len - 1].content}
</span>
</div>`;
}
$evalModal.find('.discontent').empty().append(html);
}
$evalModal.find('.discontent').empty().append(html);
// 拉取评价原因
$.ajax({
type: 'GET',
url: urls.evalReason,
data: {
conversationId: socketConfCM.conversationId
},
success: function(res) {
var data = res.data,
len = data.length;
if (res && res.code === 200) {
// 评价原因
len && discontentHtml(len, data);
}
$evalModal.modal('show');
}
});
}
// 拉取评价原因
$.ajax({
type: 'GET',
url: urls.evalReason,
data: {
conversationId: socketConfCM.conversationId
},
success: function(res) {
var data = res.data,
len = data.length;
if (res && res.code === 200) {
// 评价原因
len && discontentHtml(len, data);
}
$evalModal.modal('show');
/**
* 处理收到消息
*/
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);
}
});
}
/**
* 处理收到消息
*/
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:
enterSuccess(message);
break;
switch (recType) {
case allTypes.ENTER:
enterSuccess(message);
break;
case allTypes.LINK_SUCCESS:
linkSuccess(msgType, message);
break;
case allTypes.LINK_SUCCESS:
linkSuccess(msgType, message);
break;
case allTypes.CU_SEND:
handleCusMsg(rec, msgType, message);
break;
case allTypes.CU_SEND:
handleCusMsg(rec, msgType, message);
break;
case allTypes.BREAK_TIME:
breakCountdown(message);
break;
case allTypes.BREAK_TIME:
breakCountdown(message);
break;
case allTypes.ROBOT_SEND:
rec.csName = rec.csName || '客服机器人';
tipTpl = `<div class="list-item guest">
case allTypes.ROBOT_SEND:
rec.csName = rec.csName || '客服机器人';
tipTpl = `<div class="list-item guest">
<img src="${assetsPrefix}/img/service/robot-avatar.png" class="avatar">
<div class="item-detail">
<span class="time">${rec.csName} ${rec.sendTimeShort}</span>
... ... @@ -607,29 +603,29 @@ function getMessage(rec) {
</div>
</div>
</div>`;
break;
break;
case allTypes.CS_SEND:
// 处理客服消息
handleCsMsg(rec, msgType, message);
break;
case allTypes.CS_SEND:
// 处理客服消息
handleCsMsg(rec, msgType, message);
break;
case allTypes.EVAL_INVITE:
// 客服发起
if (!processInfo.savedEval) {
processInfo.promoter = 2;
showEvalModal();
}
break;
case allTypes.EVAL_INVITE:
// 客服发起
if (!processInfo.savedEval) {
processInfo.promoter = 2;
showEvalModal();
}
break;
case allTypes.CS_CHATTING:
// 正在人工会话
csChatting(message);
break;
case allTypes.CS_CHATTING:
// 正在人工会话
csChatting(message);
break;
case allTypes.OFFLINE:
tipTpl =
`<div class="list-item">
case allTypes.OFFLINE:
tipTpl =
`<div class="list-item">
<p class="push-tip">
<span class="tip">
${message.content}
... ... @@ -637,53 +633,53 @@ function getMessage(rec) {
</span>
</p>
</div>`;
break;
break;
default:
break;
default:
break;
}
$msgList.append(tipTpl);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
$msgList.append(tipTpl);
$panelMainBody.scrollTop($panelMainBody[0].scrollHeight);
}
/**
* 消息解析
* @param msgList
*/
function msgResolve(msgList) {
var item,
heightBefore,
heightAfter,
msgTpl = '';
/**
* 消息解析
* @param msgList
*/
function msgResolve(msgList) {
var item,
heightBefore,
heightAfter,
msgTpl = '';
msgList = msgList.reverse();
msgList = msgList.reverse();
if (endTime === msgList[0].sendTime) {
hasMore = false;
}
if (endTime === msgList[0].sendTime) {
hasMore = false;
}
endTime = msgList[0].sendTime;
endTime = msgList[0].sendTime;
if (hasMore) {
for (item of msgList) {
item.message.newContent = emojiPrefix(item.message.newContent);
if (item.message.type === 2) {
item.message.newContent =
['<img class="img-msg" src="', item.message.newContent, '">'].join('');
}
if (hasMore) {
for (item of msgList) {
item.message.newContent = emojiPrefix(item.message.newContent);
if (item.message.type === 2) {
item.message.newContent =
['<img class="img-msg" src="', item.message.newContent, '">'].join('');
}
// 客户自己的消息
if (item.type === 3) {
// 客户自己的消息
if (item.type === 3) {
// 用户头像处理
if (!item.userHead) {
item.userHead = assetsPrefix + socketConf.defaultUserHead;
}
// 用户头像处理
if (!item.userHead) {
item.userHead = assetsPrefix + socketConf.defaultUserHead;
}
msgTpl +=
`<div class="list-item host">
msgTpl +=
`<div class="list-item host">
<img src="${item.userHead}" class="avatar">
<div class="item-detail">
<span class="time">${item.userName} ${item.sendTimeShort}</span>
... ... @@ -693,10 +689,10 @@ function msgResolve(msgList) {
</div>
</div>`;
// 客服消息
} else {
msgTpl +=
`<div class="list-item guest">
// 客服消息
} else {
msgTpl +=
`<div class="list-item guest">
<img src="${item.csHead}" class="avatar">
<div class="item-detail">
<span class="time">${item.csName} ${item.sendTimeShort}</span>
... ... @@ -705,441 +701,461 @@ function msgResolve(msgList) {
</div>
</div>
</div>`;
}
}
}
heightBefore = $msgList.height();
$msgList.prepend(msgTpl);
heightAfter = $msgList.height();
$panelMainBody.scrollTop(heightAfter - heightBefore);
heightBefore = $msgList.height();
$msgList.prepend(msgTpl);
heightAfter = $msgList.height();
$panelMainBody.scrollTop(heightAfter - heightBefore);
}
}
}
/**
* 获取历史聊天记录
*/
function fetchHistoryMsg() {
var data = {
encryptedUid: encryptedUid
};
/**
* 获取历史聊天记录
*/
function fetchHistoryMsg() {
var data = {
encryptedUid: encryptedUid
};
if (endTime) {
data.endTime = endTime;
}
$.ajax({
type: 'GET',
url: urls.msgHistory,
data: data,
success: function(res) {
if (res && res.code === 200) {
hasMore && msgResolve(res.data);
$history.hide();
processInfo.scrollLoad = true;
}
if (endTime) {
data.endTime = endTime;
}
});
}
$.ajax({
type: 'GET',
url: urls.msgHistory,
data: data,
success: function(res) {
if (res && res.code === 200) {
hasMore && msgResolve(res.data);
$history.hide();
processInfo.scrollLoad = true;
}
}
});
}
// 用户信息获取并初始化socket连接
(function() {
var param = {
return_type: 'jsonp',
method: 'open.passport.get'
};
// 用户信息获取并初始化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) {
$.getJSON('//www.yohobuy.com/common/passport/?callback=?', param, function(jsonData) {
if (jsonData && jsonData.data && jsonData.data.result !== -1) {
socketConfCM.userHead = jsonData.data.headIco || '';
socketConfCM.userName = window.getUser()[0];
socketConfCM.userHead = jsonData.data.headIco || '';
socketConfCM.userName = window.getUser()[0];
// 原始配置信息用于重新连线
originConf = JSON.parse(JSON.stringify(socketConf));
// 原始配置信息用于重新连线
originConf = JSON.parse(JSON.stringify(socketConf));
socketChat.init(Object.assign(socketConf, {
onMessage: function(e) {
var received = JSON.parse(e.data);
socketChat.init(Object.assign(socketConf, {
onMessage: function(e) {
var received = JSON.parse(e.data);
socketConfCM.conversationId = received.newConversationId > 0 ?
received.newConversationId :
received.conversationId;
// 保存过程中信息
getMessage(received);
}
}));
}
});
}());
socketConfCM.conversationId = received.newConversationId > 0 ?
received.newConversationId :
received.conversationId;
// tab页title重置
tab.tabVisible(function() {
document.title = docTitle;
clearInterval(titleInterval);
});
// 保存过程中信息
getMessage(received);
// 提交留言
$leaveMsg.find('.submit').click(function() {
var lMsg = $('#leaveMsg'),
val = lMsg.find('textarea').val().trim();
$.ajax({
type: 'POST',
url: urls.leaveMsg,
data: {
content: val,
encryptedUid: encryptedUid,
conversationId: socketConfCM.newConversationId || socketConfCM.conversationId
},
success: function(res) {
if (res && res.code === 200) {
lMsg.modal('hide');
}
}));
}
},
error: function() {
lMsg.modal('hide');
}
});
});
}());
// tab页title重置
tab.tabVisible(function() {
document.title = docTitle;
clearInterval(titleInterval);
});
// 提交评价
$makeEvalModal.find('.submit').click(function() {
// 提交留言
$leaveMsg.find('.submit').click(function() {
var lMsg = $('#leaveMsg'),
val = lMsg.find('textarea').val().trim();
var $btnEval = $('.icon.evaluate'),
mEval = $('#makeEvaluation'),
reason = mEval.find('textarea').val().trim(),
star = mEval.find('.star.positive').length,
reasonTypes = mEval.find('.dis-row .type.chosen');
$.ajax({
type: 'POST',
url: urls.leaveMsg,
data: {
content: val,
var data = {
conversationId: socketConfCM.conversationId,
encryptedUid: encryptedUid,
conversationId: socketConfCM.newConversationId || socketConfCM.conversationId
},
success: function(res) {
if (res && res.code === 200) {
lMsg.modal('hide');
}
},
error: function() {
lMsg.modal('hide');
promoter: processInfo.promoter,
stars: star
};
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: data,
success: function(res) {
if (res && res.code === 200) {
processInfo.promoter = 1;
mEval.modal('hide');
$btnEval.hide();
processInfo.savedEval = true;
socketConfCM.type = 10; // 评价后通知客服
socketConfCM.uuid = uuid.v4();
socketChat.send(socketConfCM);
}
},
error: function() {
mEval.modal('hide');
}
});
});
});
// 提交评价
$makeEvalModal.find('.submit').click(function() {
var $btnEval = $('.icon.evaluate'),
mEval = $('#makeEvaluation'),
reason = mEval.find('textarea').val().trim(),
star = mEval.find('.star.positive').length,
reasonTypes = mEval.find('.dis-row .type.chosen');
var data = {
conversationId: socketConfCM.conversationId,
encryptedUid: encryptedUid,
promoter: processInfo.promoter,
stars: star
// 根节点高度设置
$html.css({
height: '100%'
});
// 获取鼠标位置
$.fn.getCursorPosition = function() {
var sel,
pos = 0,
selLength,
el = $(this).get(0);
if ('selectionStart' in el) {
pos = el.selectionStart;
} else if ('selection' in document) {
sel = document.selection.createRange();
selLength = document.selection.createRange().text.length;
el.focus();
sel.moveStart('character', -el.value.length);
pos = sel.text.length - selLength;
}
return pos;
};
var contents,
reasonIds,
idArray = [],
contentArray = [];
// enter提交 ctrl+enter换行
$msgArea.on('keydown', msgEnterAction);
if (star < 4) {
$.each(reasonTypes, function(index, item) {
idArray.push($(item).data('id'));
contentArray.push($(item).data('content'));
});
// 常见问题
$('.qa-list .q').on('click', toggleAnswer);
reasonIds = idArray.join(':');
contents = contentArray.join(':');
data.reasonIds = reasonIds;
data.reasonMsgs = contents;
data.reasonMsg = reason;
}
// 发送订单信息
$sendOrder.on('click', function(e) {
var tag = $(this),
no = tag.data('no'),
nm = tag.data('nm'),
time = tag.data('time'),
status = tag.data('status');
$.ajax({
type: 'POST',
url: urls.makeEval,
data: data,
success: function(res) {
if (res && res.code === 200) {
processInfo.promoter = 1;
mEval.modal('hide');
$btnEval.hide();
processInfo.savedEval = true;
var msgContent = ['单号:', no,
'金额:', '¥' + nm,
'下单时间:', time,
'状态:', status];
socketConfCM.type = 10; // 评价后通知客服
sendMessage(e, 10, msgContent);
});
// 发送图片
$sendImgInput.fileupload({
dataType: 'json',
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxFileSize: 5000000, // 5M
url: configDomains.imServer + '/fileManage/uploadFile',
progressall: function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress-bar').css('width', progress + '%');
},
done: function(e, res) {
res = res.result;
if (res && res.code === 200) {
// 上传成功后发送图片消息
socketConfCM.type = 3;
socketConfCM.message.content = res.data.filePath;
socketConfCM.message.type = 2;
socketConfCM.uuid = uuid.v4();
socketChat.send(socketConfCM);
}
setTimeout(function() {
$('.progress-bar').fadeOut();
}, 500);
},
error: function() {
mEval.modal('hide');
$('.progress-bar').css('width', 0);
$('.upload-tip').text('上传失败,请稍后重试').fadeIn();
setTimeout(function() {
$('.upload-tip').fadeOut().text('');
}, 2000);
}
}).on('fileuploadprocessalways', function(e, data) {
var $tip = $('.upload-tip'),
currentFile = data.files[data.index];
if (data.files.error && currentFile.error) {
switch (currentFile.error) {
case 'File type not allowed':
$tip.text('您上传的图片格式不正确').fadeIn();
break;
case 'File is too large':
$tip.text('请上传5M以内的图片').fadeIn();
break;
default:
break;
}
setTimeout(function() {
$tip.fadeOut().text('');
}, 2000);
}
});
});
// 根节点高度设置
$html.css({
height: '100%'
});
// 获取鼠标位置
$.fn.getCursorPosition = function() {
var sel,
pos = 0,
selLength,
el = $(this).get(0);
if ('selectionStart' in el) {
pos = el.selectionStart;
} else if ('selection' in document) {
sel = document.selection.createRange();
selLength = document.selection.createRange().text.length;
el.focus();
sel.moveStart('character', -el.value.length);
pos = sel.text.length - selLength;
}
return pos;
};
// 订单信息、常见问题
$rightHeadTab.on('click', function() {
var $el = $(this),
$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;
}
// enter提交 ctrl+enter换行
$msgArea.on('keydown', msgEnterAction);
// 常见问题
$('.qa-list .q').on('click', toggleAnswer);
// 发送订单信息
$sendOrder.on('click', function(e) {
var tag = $(this),
no = tag.data('no'),
nm = tag.data('nm'),
time = tag.data('time'),
status = tag.data('status');
var msgContent = ['单号:', no,
'金额:', '¥' + nm,
'下单时间:', time,
'状态:', status];
sendMessage(e, 10, msgContent);
});
// 发送图片
$sendImgInput.fileupload({
dataType: 'json',
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxFileSize: 5000000, // 5M
url: common.domains.imServer + '/fileManage/uploadFile',
progressall: function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress-bar').css('width', progress + '%');
},
done: function(e, res) {
res = res.result;
if (res && res.code === 200) {
// 上传成功后发送图片消息
socketConfCM.type = 3;
socketConfCM.message.content = res.data.filePath;
socketConfCM.message.type = 2;
socketConfCM.uuid = uuid.v4();
socketChat.send(socketConfCM);
$el.addClass('active');
$siblings.removeClass('active');
if (order) {
$qaUse.hide();
$orderUse.show();
} else {
$qaUse.show();
$orderUse.hide();
}
setTimeout(function() {
$('.progress-bar').fadeOut();
}, 500);
},
error: function() {
$('.progress-bar').css('width', 0);
$('.upload-tip').text('上传失败,请稍后重试').fadeIn();
setTimeout(function() {
$('.upload-tip').fadeOut().text('');
}, 2000);
}
}).on('fileuploadprocessalways', function(e, data) {
var $tip = $('.upload-tip'),
currentFile = data.files[data.index];
if (data.files.error && currentFile.error) {
switch (currentFile.error) {
case 'File type not allowed':
$tip.text('您上传的图片格式不正确').fadeIn();
break;
});
case 'File is too large':
$tip.text('请上传5M以内的图片').fadeIn();
break;
default:
break;
// 星评
$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');
var starText = {
0: '非常不满意',
1: '不满意',
2: '一般',
3: '满意',
4: '非常满意'
};
for (i = 0, len = startList.length; i < len; i++) {
el = $(startList[i]);
el.index() <= index && el.addClass('positive');
el.index() > index && el.removeClass('positive');
}
setTimeout(function() {
$tip.fadeOut().text('');
}, 2000);
}
});
// 订单信息、常见问题
$rightHeadTab.on('click', function() {
var $el = $(this),
$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;
}
$el.addClass('active');
$siblings.removeClass('active');
index < 3 && $detailReason.show();
index >= 3 && $detailReason.hide();
textEl.text(starText[index]);
});
if (order) {
$qaUse.hide();
$orderUse.show();
} else {
$qaUse.show();
$orderUse.hide();
}
});
// 星评
$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');
var starText = {
0: '非常不满意',
1: '不满意',
2: '一般',
3: '满意',
4: '非常满意'
};
// 选择不满意类型
$document.on('click', '.dis-row .type', function(e) {
$(e.target).toggleClass('chosen');
});
for (i = 0, len = startList.length; i < len; i++) {
el = $(startList[i]);
el.index() <= index && el.addClass('positive');
el.index() > index && el.removeClass('positive');
}
// 留言
$msgList.on('click', '.leave-msg', leaveMsg);
// 消息编辑框功能区
$msgEdit.find('.util .icon').on('click', function(e) {
var cTa = $(this),
index = cTa.index(),
comp = $('.emoji-component');
var utilMap = {
0: function() {
var isNone,
compHeight,
topPo = cTa.offset().top,
leftPo = cTa.offset().left,
cTaHeight = cTa.height();
isNone = comp.css('display') === 'none';
comp.css({display: 'inline-block'});
compHeight = comp.height();
isNone && comp.css({
top: topPo - cTaHeight - compHeight - 5,
left: leftPo
});
!isNone && comp.hide();
},
2: function() {
showEvalModal();
},
index < 3 && $detailReason.show();
index >= 3 && $detailReason.hide();
textEl.text(starText[index]);
});
// 选择不满意类型
$document.on('click', '.dis-row .type', function(e) {
$(e.target).toggleClass('chosen');
});
// 留言
$msgList.on('click', '.leave-msg', leaveMsg);
// 消息编辑框功能区
$msgEdit.find('.util .icon').on('click', function(e) {
var cTa = $(this),
index = cTa.index(),
comp = $('.emoji-component');
var utilMap = {
0: function() {
var isNone,
compHeight,
topPo = cTa.offset().top,
leftPo = cTa.offset().left,
cTaHeight = cTa.height();
isNone = comp.css('display') === 'none';
comp.css({display: 'inline-block'});
compHeight = comp.height();
isNone && comp.css({
top: topPo - cTaHeight - compHeight - 5,
left: leftPo
});
3: function() {
manualService();
}
};
!isNone && comp.hide();
},
if (index === 1) {
return;
}
utilMap[index](e);
});
2: function() {
showEvalModal();
},
// 设置表情
$document.on('click', '.emoji-component .emoji', setEmoji);
// 表情组件隐藏
$document.on('click', function(e) {
var $t = $(e.target),
comp = $('.emoji-component');
3: function() {
manualService();
if (!$t.hasClass('emoji') && !$t.hasClass('emoji-component')) {
comp.hide();
}
};
});
if (index === 1) {
return;
}
utilMap[index](e);
});
// 重新连线
$msgList.on('click', '.reconnect', function() {
// 共通处理
beforeSendMsg();
socketChat.init(Object.assign(originConf, {
onOpen: function() {
console.log('websocket opened!');
},
// 设置表情
$document.on('click', '.emoji-component .emoji', setEmoji);
onMessage: function(e) {
var jsonString = e.data;
var received = JSON.parse(jsonString);
// 表情组件隐藏
$document.on('click', function(e) {
var $t = $(e.target),
comp = $('.emoji-component');
socketConfCM.conversationId = received.newConversationId !== 0 ?
received.newConversationId :
received.conversationId;
if (!$t.hasClass('emoji') && !$t.hasClass('emoji-component')) {
comp.hide();
}
});
// 重新连线
$msgList.on('click', '.reconnect', function() {
// 共通处理
beforeSendMsg();
socketChat.init(Object.assign(originConf, {
onOpen: function() {
console.log('websocket opened!');
},
getMessage(received);
},
onMessage: function(e) {
var jsonString = e.data;
var received = JSON.parse(jsonString);
onClose: function() {
console.log('websocket closed!');
}
}));
socketConfCM.conversationId = received.newConversationId !== 0 ?
received.newConversationId :
received.conversationId;
});
getMessage(received);
},
// 发送
$msgEdit.find('.send').on('click', sendMessage);
onClose: function() {
console.log('websocket closed!');
// 关闭聊天窗口
$close.click(function() {
if (processInfo.manual && !processInfo.savedEval) { // 没有保存过评论
showEvalModal();
} else {
window.close();
}
}));
});
// 发送
$msgEdit.find('.send').on('click', sendMessage);
});
// 关闭聊天窗口
$close.click(function() {
if (processInfo.manual && !processInfo.savedEval) { // 没有保存过评论
showEvalModal();
} else {
window.close();
}
});
// 失去焦点更新鼠标位置
$msgArea.on('blur', function() {
cursorPosition = $(this).getCursorPosition();
});
// 失去焦点更新鼠标位置
$msgArea.on('blur', function() {
cursorPosition = $(this).getCursorPosition();
});
// 消息图片放大显示
$msgList.on('click', '.msg-bubble .img-msg', function(e) {
var msgZoomIn = $('.img-zoom-in');
// 消息图片放大显示
$msgList.on('click', '.msg-bubble .img-msg', function(e) {
var msgZoomIn = $('.img-zoom-in');
msgZoomIn.find('img').attr('src', $(e.target).attr('src'));
msgZoomIn.fadeIn();
});
msgZoomIn.find('img').attr('src', $(e.target).attr('src'));
msgZoomIn.fadeIn();
});
$document.on('click', '.img-zoom-in', function() {
$(this).fadeOut();
});
$document.on('click', '.img-zoom-in', function() {
$(this).fadeOut();
});
// 显示历史记录
$history.click(fetchHistoryMsg);
// 显示历史记录
$history.click(fetchHistoryMsg);
// 滚动加载更多
$panelMainBody.scroll(function() {
var loading = $panelMainBody.scrollTop() === 0;
// 滚动加载更多
$panelMainBody.scroll(function() {
var loading = $panelMainBody.scrollTop() === 0;
processInfo.scrollLoad && loading && hasMore && fetchHistoryMsg();
});
}
processInfo.scrollLoad && loading && hasMore && fetchHistoryMsg();
});
// 拉取域名信息
(function () {
$.ajax({
type: 'GET',
url: '/service/domains',
success: function(domains) {
configDomains = domains;
// url前缀添加
for (key in urls) {
if (urls.hasOwnProperty(key)) {
urls[key] = configDomains.imCs + urls[key];
}
}
socketConf.servers.push(configDomains.imSocket);
pageInit();
}
});
}());
... ...
... ... @@ -5,10 +5,8 @@
* @date: 2016/11/8
*/
var common = require('../../../config/common');
var config = {
servers: [common.domains.imSocket],
servers: [],
defaultUserHead: '/img/service/default-thumb.png',
recType: {
ENTER: 1, // 用户进入
... ...