Authored by 李奇

客户端修改

/**
* 登录注册密码加密,uid加密
* @author: wsl<shuiling.wang@yoho.cn>
* @date: 2016/07/07
*/
'use strict';
const crypto = global.yoho.crypto;
/**
* 密码加密
**/
const aesPwd = (pwd) => {
return crypto.encryption('yoho9646yoho9646', pwd);
};
/**
* uid加密
**/
const encryptionUid = (uid) => {
return crypto.encryption('yoho9646abcdefgh', uid + '');
};
module.exports = {
aesPwd,
encryptionUid
};
... ...
... ... @@ -6,6 +6,7 @@
*/
'use strict';
const aes = require('./aes-pwd');
const clientService = require('../models/client-service');
/**
... ... @@ -13,15 +14,15 @@ const clientService = require('../models/client-service');
*/
const index = (req, res) => {
let type = 2; // 2: YOHO在线客服设置
// let uid = req.user.uid || '';
let uid = 8040155; // TODO 假数据
// let encryptionUid = aes.encryptionUid(req.user.uid);
let encryptionUid = req.user.uid;
let imgSize = '400x400'; // todo
let data = {
layout: false,
uid: uid
uid: encryptionUid
};
clientService.getClientData(type, uid, imgSize)
clientService.getClientData(type, encryptionUid, imgSize)
.then(result => {
res.render('client', Object.assign(data, result));
});
... ...
... ... @@ -18,9 +18,9 @@ let api = new global.yoho.ApiBase(config.domains.bjIm, {
// api urls
let urls = {
lastTen: '/api/cs/queryUserLastTenOrdersNgoodsInfo',
msgHistory: '/api/conversationMessage/pageList',
csSetting: '/api/cs/queryByType',
msgHistory: '/api/cs/queryByType', // TODO 历史消息接口未提供
qas: '' // TODO 接口未提供
qas: '' // TODO 没有接口功能暂缓
};
/**
... ... @@ -70,14 +70,14 @@ const getCsSetting = (type) => {
* @return { Array } 历史聊天记录
*/
const getMsgHistory = (uid) => {
let endTime = new Date().getTime() * 1000;
return api.get(urls.msgHistory, {
method: '',
uid
uid,
endTime,
method: ''
});
};
module.exports = {
getQas,
getCsSetting,
... ...
... ... @@ -15,10 +15,10 @@ const clientAPI = require('./client-api');
*/
const getClientData = (type, uid, imgSize) => {
let apiMethod = [
// clientAPI.getQas(), // TODO 常见问题
clientAPI.getCsSetting(type),
clientAPI.getMsgHistory(uid),
clientAPI.getLastTenOrders(uid, imgSize),
clientAPI.getLastTenOrders(uid, imgSize)
// clientAPI.getQas(), // TODO 常见问题
];
return Promise.all(apiMethod)
... ... @@ -27,16 +27,7 @@ const getClientData = (type, uid, imgSize) => {
csSetting: res[0].data.config,
msgHistory: res[1].data,
orders: res[2].data,
qas: [
{
question: '测试问题',
answer: '测试回答'
},
{
question: '测试问题',
answer: '测试回答'
},
] // TODO 接口待提供
qas: []
}
})
};
... ...
... ... @@ -42,7 +42,6 @@
{{> img-zoom-in}}
<input name="uid" type="text" type="hidden" value={{uid}}>
{{#if devEnv}}
<script src="//localhost:5002/libs.js"></script>
<script src="//localhost:5002/{{module}}.{{page}}.js"></script>
... ...
<div class="qa-list">
{{#each qas}}
<div class="item">
<div class="q">{{question}}</div>
<div class="a">{{answer}}</div>
{{#if qas}}
{{#each qas}}
<div class="item">
<div class="q">{{question}}</div>
<div class="a">{{answer}}</div>
</div>
{{/each}}
{{else}}
<div class="list-tip">
<span class="tip">暂无问题</span>
</div>
{{/each}}
{{/if}}
</div>
... ...
... ... @@ -23,29 +23,34 @@ require('blueimp-file-upload/js/jquery.fileupload');
var uid,
cursorPo;
var $sendOrder = $('.send-order'),
$rightHeadTab = $('.right-head .tab'),
$panelMainBody = $('.panel-main .main-body'),
$msgList = $('.msg-list'),
var $msgList = $('.msg-list'),
$leaveMsg = $('#leaveMsg'),
$sendImgInput = $('#sendImg');
$sendOrder = $('.send-order'),
$sendImgInput = $('#sendImg'),
$uidInput = $('input[name=uid]'),
$msgArea = $('.msg-edit .msg-area'),
$makeEvalModal = $('#makeEvaluation'),
$rightHeadTab = $('.right-head .tab'),
$panelMainBody = $('.panel-main .main-body');
var operation = {
savedEval: false
var processInfo = {
savedEval: false, // 是否保存过评论
csId: 0, // 客服Id
promoter: 1 // 评论发起者 1:客户自己 2:客服
};
uid = $('input[name=uid]').val();
uid = $uidInput.val();
socketConf.conversationMessage.userId = uid;
var cM = socketConf.conversationMessage;
var cM = socketConf.conversationMessage,
originConf = JSON.parse(JSON.stringify(socketConf)); // 原始配置信息用于重新连线
var urls = {
makeEval: '/evalute/saveEvalute',
leaveMsg: '/leavemessage/saveLeavemessage',
evalReason: '/evalute/queryEvaluteReason',
makeEval: '/evalute/saveEvalute'
evalReason: '/evalute/queryEvaluteReason'
};
for (var key in urls) {
... ... @@ -116,7 +121,6 @@ function setCursorPosition(textDom, pos) {
/**
* enter提交
* enter+ctrl换行
* @param e
*/
function msgEnterAction(e) {
var code = e.keyCode,
... ... @@ -125,8 +129,10 @@ function msgEnterAction(e) {
if (code !== 13) return;
if (!ctrlLike) {
e.preventDefault();
_sendMessage(e);
sendMessage();
} else {
var tag = $(e.target),
pos = tag.getCursorPosition(),
... ... @@ -143,7 +149,6 @@ function msgEnterAction(e) {
/**
* 常见问题
* @param e
*/
function toggleAnswer(e) {
var cTag = $(e.currentTarget),
... ... @@ -156,13 +161,6 @@ function toggleAnswer(e) {
}
/**
* 发送订单
*/
function sendOrderInfo(e) {
}
/**
* 连线客服
*/
function connectService() {
... ... @@ -173,9 +171,8 @@ function connectService() {
/**
* 处理收到消息
* @private
*/
function _getMessage(rec) {
function getMessage(rec) {
console.log('客户收到消息!', rec);
var recType = rec.type,
... ... @@ -223,7 +220,8 @@ function _getMessage(rec) {
case allTypes.EVAL_INVITE:
$('input[name=promoter]').val(2);
// 客服发起
processInfo.promoter = 2;
showEvalModal();
... ... @@ -235,7 +233,10 @@ function _getMessage(rec) {
tipTpl =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}<a class="red-tip reconnect">连线客服</a></span>
<span class="tip">
${message.content}
<a class="red-tip reconnect">连线客服</a>
</span>
</p>
</div>`;
break;
... ... @@ -252,9 +253,8 @@ function _getMessage(rec) {
/**
* 处理发送消息
* @private
*/
function _sendMessage(e, msgType, msgContent) {
function sendMessage(msgType, msgContent) {
if (!msgContent) {
var tag = $('.msg-area'),
... ... @@ -294,6 +294,224 @@ function leaveMsg() {
}
/**
* 链接建立
* @param msgType 内部消息类型
* @param message 内部消息对象
* @private
*/
function _linkSuccess(msgType, message) {
var OUT_SERVICE = 0,
LINE_UP = 1,
MANUAL_SERVICE = 2;
var liHtml;
var $msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
switch(msgType) {
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;
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;
case MANUAL_SERVICE: // 2是接入人工成功
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}</span>
</p>
<p class="push-tip">
<span class="tip">${message.content}</span>
</p>
</div>`;
break;
default:
break;
}
// 添加消息
liHtml && $msgList.append(liHtml);
liHtml && $mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 处理客户消息
* @private
*/
function _handleCusMsg(rec, msgType, message) {
var liHtml,
$msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
message.newContent = _emojiPrefix(message.newContent);
// 图片添加标签
if(msgType === 2) {
message.newContent =
`<img class="img-msg" src="${message.content}">`;
}
liHtml = `<div class="list-item host">
<img src="${rec.userHead}" class="avatar">
<div class="item-detail">
<span class="time">${rec.userName} ${rec.sendTimeShort}</span>
<div class="msg-bubble">
<div>${message.newContent}</div>
</div>
</div>
</div>`;
$msgList.append(liHtml);
$mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 处理客服消息
* @private
*/
function _handleCsMsg(rec, msgType, message) {
var liHtml,
$msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
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>
<div class="msg-bubble">
<div>${message.newContent}</div>
</div>
</div>
</div>`;
$msgList.append(liHtml);
$mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 返回表情路径处理
* @param text 文本
* @private
*/
function _emojiPrefix(text) {
if(typeof text === "string") {
return text.replace(/src="(\d{3}).gif"/g, 'src="/img/service/emoji/$1.gif"');
}
return text;
}
/**
* 显示评价弹框
*/
function showEvalModal() {
var $evalModal = $('#makeEvaluation');
// 没有客服不可以评价
if(!processInfo.csId) return;
// 评价原因
function discontentHtml(len, data) {
var html = '',
ceilRows = Math.ceil(len / 2),
floorRows = Math.floor(len / 2);
if(ceilRows === floorRows) {
for(var r = 1, i = 0; r <= ceilRows; r++) {
html +=
`<div class="dis-row">
<span class="type" data-id="${data[i].id}">
${data[i].content}
</span>
<span class="type" data-id="${data[i+1].id}">
${data[i+1].content}
</span>
</div>`;
i += 2;
}
} else {
for(r = 1, i = 0; r <= ceilRows - 1; r++) {
html +=
`<div class="dis-row">
<span class="type" data-id="${data[i].id}">
${data[i].content}
</span>
<span class="type" data-id="${data[i+1].id}">
${data[i+1].content}
</span>
</div>`;
i += 2;
}
html +=
`<div class="dis-row">
<span class="type" data-id="${data[len-1].id}">
${data[len-1].content}
</span>
</div>`;
}
$evalModal.find('.discontent').empty().append(html);
}
$.ajax({
type: 'GET',
url: urls.evalReason,
data: {
customerSettingId: 0 // TODO 写死,带接口返回
},
success: function(res) {
if (res && res.code === 200) {
var data = res.data,
len = data.length;
// 评价原因
len && discontentHtml(len, data);
}
$evalModal.modal('show');
}
});
}
// 初始化socket连接
socketChat.init(Object.assign(socketConf, {
... ... @@ -302,14 +520,16 @@ socketChat.init(Object.assign(socketConf, {
},
onMessage: function(e) {
var jsonString = e.data;
var received = JSON.parse(jsonString);
var received = JSON.parse(e.data);
cM.conversationId = received.newConversationId != 0 ?
received.newConversationId :
received.conversationId;
_getMessage(received);
// 保存过程中信息
processInfo.csId = received.csId;
getMessage(received);
},
onClose: function() {
... ... @@ -342,13 +562,10 @@ $leaveMsg.find('.submit').click(function() {
});
});
// 提交评价
$('#makeEvaluation .submit').click(function() {
$makeEvalModal.find('.submit').click(function() {
var mEval = $('#makeEvaluation'),
proInput = $('input[name=promoter]'),
promoter = proInput.val() || 1,
reason = mEval.find('textarea').val().trim(),
star = mEval.find('.star.positive').length,
reasonTypes = mEval.find('.dis-row .type.chosen');
... ... @@ -367,23 +584,21 @@ $('#makeEvaluation .submit').click(function() {
url: urls.makeEval,
data: {
conversationId: cM.conversationId,
csId: cM.csId,
csId: processInfo.csId,
pid: cM.platId,
promoter: promoter,
promoter: processInfo.promoter,
reasonIds: reasonIds || '',
reasonMsgs: reason,
stars: star,
uid: uid
},
success: function(res) {
if (res && res.code === 200) {
proInput.val('1');
processInfo.promoter = 1;
mEval.modal('hide');
operation.savedEval = true;
processInfo.savedEval = true;
}
},
error: function() {
mEval.modal('hide');
}
... ... @@ -391,7 +606,6 @@ $('#makeEvaluation .submit').click(function() {
});
// 调整窗口位置
$(window).on('resize', function() {
var vh = $(this).height(),
... ... @@ -422,7 +636,7 @@ $.fn.getCursorPosition = function() {
};
// enter提交 ctrl+enter换行
$('.msg-edit .msg-area').on('keydown', msgEnterAction);
$msgArea.on('keydown', msgEnterAction);
// 常见问题
$('.qa-list .q').on('click', toggleAnswer);
... ... @@ -440,7 +654,7 @@ $sendOrder.on('click', function(e) {
'下单时间:', time,
'状态:', status];
_sendMessage(e, 10, msgContent);
sendMessage(10, msgContent);
});
// 发送图片
... ... @@ -560,7 +774,7 @@ $('.emoji-component .emoji').on('click', setEmoji);
// 重新连线
$msgList.on('click', '.reconnect', function() {
socketChat.init(Object.assign(socketConf, {
socketChat.init(Object.assign(originConf, {
onOpen: function(e) {
console.log('websocket opened!');
... ... @@ -570,8 +784,11 @@ $msgList.on('click', '.reconnect', function() {
var jsonString = e.data;
var received = JSON.parse(jsonString);
cM.conversationId = received.newConversationId != 0 ? received.newConversationId : received.conversationId;
_getMessage(received);
cM.conversationId = received.newConversationId != 0 ?
received.newConversationId :
received.conversationId;
getMessage(received);
},
onClose: function() {
... ... @@ -582,11 +799,11 @@ $msgList.on('click', '.reconnect', function() {
});
// 发送
$('.msg-edit .send').on('click', _sendMessage);
$('.msg-edit .send').on('click', sendMessage);
// 关闭聊天窗口
$('.header .close').click(function() {
if (!operation.savedEval) { // 没有保存过评论
if (!processInfo.savedEval) { // 没有保存过评论
showEvalModal();
} else {
window.close();
... ... @@ -594,11 +811,10 @@ $('.header .close').click(function() {
});
// 失去焦点更新鼠标位置
$('.msg-area').on('blur', function() {
$msgArea.on('blur', function() {
cursorPo = $(this).getCursorPosition();
});
// 消息图片放大显示
$msgList.on('click', '.msg-bubble .img-msg', function(e) {
var msgZoomIn = $('.img-zoom-in');
... ... @@ -619,240 +835,6 @@ $('.about-his.has-his').click(function(e) {
});
/**
* 链接建立
* @param msgType 内部消息类型
* @param message 内部消息对象
* @private
*/
function _linkSuccess(msgType, message) {
var OUT_SERVICE = 0,
LINE_UP = 1,
MANUAL_SERVICE = 2;
var liHtml;
var $msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
switch(msgType) {
case OUT_SERVICE: // 0是没上班
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}</span>
</p>
</div>`;
break;
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;
case MANUAL_SERVICE: // 2是接入人工成功
liHtml =
`<div class="list-item">
<p class="push-tip">
<span class="tip">${message.content}</span>
</p>
</div>`;
break;
default:
break;
}
// 添加消息
liHtml && $msgList.append(liHtml);
liHtml && $mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 处理客户消息
* @private
*/
function _handleCusMsg(rec, msgType, message) {
var liHtml,
$msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
message.newContent = _emojiPrefix(message.newContent);
// 图片添加标签
if(msgType === 2) {
message.newContent =
'<img class="img-msg" src="${message.newContent}">'
}
liHtml = `<div class="list-item host">
<img src="${rec.userHead}" class="avatar">
<div class="item-detail">
<span class="time">${rec.userName} ${rec.sendTimeShort}</span>
<div class="msg-bubble">
<div>${message.newContent}</div>
</div>
</div>
</div>`;
$msgList.append(liHtml);
$mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 处理客服消息
* @private
*/
function _handleCsMsg(rec, msgType, message) {
var liHtml,
$msgList = $('.msg-list'),
$mainBody = $('.panel-main .main-body');
message.newContent = _emojiPrefix(message.newContent);
if(msgType === 2) {
message.content =
'<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>
<div class="msg-bubble">
<div>${message.newContent}</div>
</div>
</div>
</div>`;
$msgList.append(liHtml);
$mainBody.scrollTop($mainBody[0].scrollHeight);
}
/**
* 返回表情路径处理
* @param text 文本
* @private
*/
function _emojiPrefix(text) {
if(typeof text === "string") {
return text.replace(/src="(\d{3}).gif"/g, 'src="/img/service/emoji/$1.gif"');
}
return text;
}
/**
* 显示评价弹框
*/
function showEvalModal() {
var $evalModal = $('#makeEvaluation');
$.ajax({
type: 'GET',
url: urls.evalReason,
data: {
customerSettingId: 0 // todo
},
success: function(res) {
if (res && res.code === 200) {
var data = res.data,
len = data.length;
data = [
{
createTime: 1477657047,
customerSettingId: 40,
id: 26,
content: 123451,
status: 2
},
{
createTime: 1477657047,
customerSettingId: 40,
id: 28,
content: 123551,
status: 2
},
{
createTime: 1477657047,
customerSettingId: 40,
id: 28,
content: 123551,
status: 2
}
];
len = data.length;
if(len) {
var html = '',
ceilRows = Math.ceil(len / 2),
floorRows = Math.floor(len / 2);
if(ceilRows === floorRows) {
for(var r = 1, i = 0; r <= ceilRows; r++) {
html =
`<div class="dis-row">
<span class="type"data-id="${data[i].id}">
${data[i].content}
</span>
<span class="type"data-id="${data[i+1].id}">
${data[i+1].content}
</span>
</div>`;
i += 2;
}
} else {
for(var r = 1, i = 0; r <= ceilRows - 1; r++) {
html +=
`<div class="dis-row">
<span class="type"data-id="${data[i].id}">
${data[i].content}
</span>
<span class="type"data-id="${data[i+1].id}">
${data[i+1].content}
</span>
</div>`;
i += 2;
}
html +=
`<div class="dis-row">
<span class="type" data-id="${data[len-1].id}">
${data[len-1].content}
</span>
</div>`;
}
}
$evalModal.find('.discontent').empty().append(html);
}
$evalModal.modal('show');
}
});
}
... ...
... ... @@ -33,7 +33,7 @@ var config = {
conversationId: 0,
sessionId: '',
userId: 0,
userHead: 'http://img03.static.yohobuy.com/thumb/2016/10/28/20/01250f1e320b9941719635176db6205664-0050x0050-2-goodsimg.jpg', // 用户头像
userHead: '//img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif', // 用户头像
userName: '18551982891', // 用户昵称
csId: 0,
type: 1,
... ...
... ... @@ -216,7 +216,7 @@ $color-3a3a3a: #3a3a3a;
background-image: url('/img/service/tip.png');
}
a {
.leave-msg {
color: #d0021b;
text-decoration: none;
cursor: pointer;
... ... @@ -787,6 +787,25 @@ $color-3a3a3a: #3a3a3a;
background-color: #f0f0f0;
}
}
.list-tip {
text-align: center;
margin-bottom: 12px;
.tip {
color: #b6b6b6;
&:before,
&:after {
content: '';
display: inline-block;
width: 35px;
height: 1px;
margin: 0 3px 2px 3px;
background-color: #e0e0e0;
}
}
}
}
}
}
... ...