diff --git a/app.js b/app.js index eff163b..5e703ab 100644 --- a/app.js +++ b/app.js @@ -18,7 +18,7 @@ app.set('view engine', 'ejs'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); // 日志 -app.use(logger('dev')); +// app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // cookie diff --git a/config.js b/config.js index 570b289..9740898 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,5 @@ const APP = { - "KF_PREFIX":'chat-admin-', + "KF_PREFIX":'', "QINIU":{ "accessKey":"your access key", "secretKey":"your secret key" diff --git a/io/io.js b/io/io.js index dbba9c4..76b723a 100644 --- a/io/io.js +++ b/io/io.js @@ -20,11 +20,11 @@ function ioServer(io) { var __uuids = []; //初始化连接人数 - redis.set('online_count', 0, null, function (err, ret) { - if (err) { - console.error(err); - } - }); + // redis.set('online_count', 0, null, function (err, ret) { + // if (err) { + // console.error(err); + // } + // }); Array.prototype.remove = function (val) { var index = this.indexOf(val); @@ -45,31 +45,37 @@ function ioServer(io) { //如果不是客服登录 if (type != 'kefu') { - let gongHao = msg.gongHao; - console.log('new customer login process gongHao=>', gongHao) + let gongHao = msg.kefu_id; + let location = Common.getIpLocation(msg.ip); + console.log('来自', location, '的客户连接并登录了处理客服gongHao=>', gongHao) // 获取管理员的socket try { //获取管理员 socket let kefuData = await sessoionModel.find(gongHao); if (kefuData) { // 找到客服数据 - let location = Common.getIpLocation(msg.ip); // let socket = socket.id; // let type = 'customer'; // let kefu_id = gongHao; let clientInfo = { "uid": uid, - "name": location + ' 客户', - "type": 'online' + "nickname": location + ' 客户', + "type": 'online', + status: 1, }; // 添加客户到 对应的客服 - await sessoionModel.createOrUpdate({uid}, { - uid, - socket: socket.id, - type: 'customer', - kefu_id: gongHao, - status: 1, - nickname: clientInfo.name, + await sessoionModel.createOrUpdate({uid}, (isCreate) => { + let data = { + uid, + socket: socket.id, + kefu_id: gongHao, + status: 1 + }; + if (isCreate) { + data['type'] = 'customer'; + data['nickname'] = clientInfo.name; + } + return data; }) // 给管理员发送通知 io.to(kefuData.socket).emit('update-users', clientInfo); @@ -98,22 +104,22 @@ function ioServer(io) { //断开事件 socket.on('disconnect', async function () { - console.log("与服务其断开"); - // _self.updateOnlineCount(false); let user = socket['_user']; if (user) { + console.log("与服务其断开",user); // 更新用户状态 await sessoionModel.update(user.uid, {status: 0}); - if (user.type == 'customer') { + if (user.type == 'customer' && user.kefu_id) { // 查找对应kf通知下线操作 let kf_data = await sessoionModel.find(user.kefu_id); - if (kf_data && kf_data.status == 1) { // 客服在线才通知哟 - var info = { - "uid": user.uid, - "name": '客户下线', - "type": 'offline' + if (kf_data && kf_data.status == 1) { // 客服在线才通知哟 + let info = { + "uid":user.uid, + "type": 'offline', + "nickname":"", + status: 0 }; io.to(kf_data.socket).emit('update-users', info); } @@ -167,7 +173,8 @@ function ioServer(io) { }); this.updateOnlineCount = function (isConnect) { - //记录在线客户连接数 + return; + // 更新在线客户连接数 redis.get('online_count', function (err, val) { if (err) { console.error(err); diff --git a/model/session.js b/model/session.js index a72a96b..e1e32bc 100644 --- a/model/session.js +++ b/model/session.js @@ -37,11 +37,17 @@ module.exports = { } try{ if(session){ + if(typeof(data) == "function"){ + data = data.call(this,false) + } sessionModel.update(condition,data, (err, doc) => { if (err) fail(err); else success(doc); }) }else{//新增 + if(typeof(data) == "function"){ + data = data.call(this,true) + } let model = new sessionModel(data); model.save(data, (err, doc) => { if (err) fail(err); diff --git a/public/css/client.css b/public/css/client.css index 3df7cf8..d20ee45 100644 --- a/public/css/client.css +++ b/public/css/client.css @@ -97,7 +97,8 @@ a { .msg-agent .bubble,.msg-bot .bubble { color: #000; background-color: #fff; - border-left: 1px solid #f0f0f0; + display: inline-block; + border: 1px solid #f0f0f0; } .msg-agent .agent-avatar, .msg-bot .agent-avatar { diff --git a/public/css/server.css b/public/css/server.css index 19127dc..8e03f62 100644 --- a/public/css/server.css +++ b/public/css/server.css @@ -66,13 +66,13 @@ .message-agent-content{ position: relative; float: right; - background-color: #f0f1f3; - color: #161e26; + background-color: #6d92bb; + color: #fff; } .message-client-content{ position: relative; float: left ; - background-color: #e7f4ff; + background-color: #efefef; color: #161e26; } @@ -110,14 +110,21 @@ } .user-info{ - height: 60px; + /*height: 60px;*/ + /*line-height: 60px;*/ background: #ffffff; - line-height: 60px; font-size: 16px; color: #767d85; + cursor: pointer; border-bottom: 1px solid #e9e9e9; + position: relative; +} +.user-info .user-status{ + background-color: #999; + margin-left:5px; + color: #fff; + display: none; } - .chat-user{ overflow: auto; } @@ -132,6 +139,7 @@ .user-info .user-name{ font-size: 12px; + padding:14px 0; } .empty-status{ diff --git a/public/images/client.png b/public/images/client.png index 78d1068..4407e47 100644 Binary files a/public/images/client.png and b/public/images/client.png differ diff --git a/public/images/server.png b/public/images/server.png index 7f13db7..2cfb160 100644 Binary files a/public/images/server.png and b/public/images/server.png differ diff --git a/public/js/client/client.js b/public/js/client/client.js index 1113e0a..5598f9d 100644 --- a/public/js/client/client.js +++ b/public/js/client/client.js @@ -55,7 +55,7 @@ $(function(){ tpl += '
'+ ''+ ''+ - '
' + msg.content + '
'+ + '
'+ '
'; }else if(msg.chat_type == "image"){ tpl += '
' + @@ -66,7 +66,7 @@ $(function(){ } tpl += '
'+ ''; - $(".msg-container").append(tpl); + $(tpl).appendTo(".msg-container").find('.text').html(msg.content.replace(/\n/g,"
")); } //聊天窗口自动滚到底 @@ -111,74 +111,6 @@ $(function(){ } }); - $(".picture-upload").click(function () { - var uploader = Qiniu.uploader({ - runtimes: 'html5,flash,html4', // 上传模式,依次退化 - browse_button: 'pickfiles', // 上传选择的点选按钮,必需 - uptoken_url: '/uptoken', // Ajax请求uptoken的Url,强烈建议设置(服务端提供) - get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的uptoken - domain: 'http://kefuimg.chinameyer.com/', // bucket域名,下载资源时用到,必需 - container: 'btn-uploader', // 上传区域DOM ID,默认是browser_button的父元素 - max_file_size: '10mb', // 最大文件体积限制 - flash_swf_url: 'path/of/plupload/Moxie.swf', //引入flash,相对路径 - max_retries: 3, // 上传失败最大重试次数 - dragdrop: false, // 开启可拖曳上传 - drop_element: 'btn-uploader', // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传 - chunk_size: '4mb', // 分块上传时,每块的体积 - auto_start: true, // 选择文件后自动上传,若关闭需要自己绑定事件触发上传 - unique_names: true, - filters : { - max_file_size : '10mb', - prevent_duplicates: true, - // Specify what files to browse for - mime_types: [ - {title : "Image files", extensions : "jpg,gif,png,bmp"}, // 限定jpg,gif,png后缀上传 - ] - }, - init: { - 'FilesAdded': function(up, files) { - plupload.each(files, function(file) { - // 文件添加进队列后,处理相关的事情 - }); - }, - 'BeforeUpload': function(up, file) { - // 每个文件上传前,处理相关的事情 - }, - 'UploadProgress': function(up, file) { - // 每个文件上传时,处理相关的事情 - }, - 'FileUploaded': function(up, file, info) { - // 查看简单反馈 - var domain = up.getOption('domain'); - var res = JSON.parse(info); - var sourceLink = domain +"/"+ res.key; - - var msg_sender = { - "type":'private', - "uid":'chat-kefu-admin', - "content":'图片消息', - "from_uid":uuid, - "chat_type":'image', - "image":sourceLink - }; - socket.emit('message', msg_sender); - insert_client_html(msg_sender); - scrollToBottom(); - - - }, - 'Error': function(up, err, errTip) { - //上传出错时,处理相关的事情 - $.toast("上传失败"); - }, - 'UploadComplete': function() { - //队列文件处理完毕后,处理相关的事情 - } - } - }); - - }); - $(".emoji-list li").click(function () { var content = $("#textarea").val(); $("#textarea").val(content + " " +$(this).html()+ " " ); @@ -204,8 +136,8 @@ $(function(){ var msg = { "uid" : uuid, "ip" : ip, - "gongHao":gongHao, - type:'c' + kefu_id:gongHao, + type:'customer' }; socket.emit('login', msg); get_message(uuid); diff --git a/public/js/server/index.js b/public/js/server/index.js index 57d081d..3aca85b 100644 --- a/public/js/server/index.js +++ b/public/js/server/index.js @@ -69,7 +69,7 @@ layui.use(['layer', 'form', 'jquery'], function () { if (msg.chat_type == "text") { html += '
\n' + - '
' + msg.content + '
\n' + + '
\n' + '
\n'; } else if (msg.chat_type == "image") { html += '
' + @@ -80,7 +80,8 @@ layui.use(['layer', 'form', 'jquery'], function () { } html += '
'; - $('#section-' + msg.uid).append(html); + $(html).appendTo('#section-' + msg.uid).find('.message-content-wrapper').html(msg.content.replace(/\n/g,"
")); + // $().append(html); } // 添加客户端消息 @@ -114,19 +115,23 @@ layui.use(['layer', 'form', 'jquery'], function () { } - function insert_user_html(id, name) { - var html = '
\n' + + function insert_user_html(id, name, u) { + + var html = '
\n' + '
\n' + - ' \n' + + ' \n' + '
\n' + - '
' + name + '-' + id + '
\n' + + '
' + + ' ' + name + '' + + ' 已离线
\n' + ' ' + '
'; $('.chat-user').append(html); } //设置消息状态 - function msg_sender_status(status) { + function msg_sender_status() { + let status = $('.user-info.selected').length != 0 if (status) { $(".btnMsgSend").removeClass("layui-btn-disabled"); $("#msg-send-textarea").removeAttr("disabled"); @@ -186,17 +191,17 @@ layui.use(['layer', 'form', 'jquery'], function () { var data = data.data; data.forEach(function (user) { - insert_user_html(user.uid, user.name + '#' + (uuids.length + 1)); + insert_user_html(user.uid, user.nickname, user); //创建聊天section - insert_section(user.uid); + insert_section(user.uid, user); uuids.push(user.uid); }); if (data.length > 0 && !currentUUID) { - currentUUID = data[0].uid; + currentUUID = data[0].uid; // 设置当前对话 客户为第一个 } $(".user-info").css("background", "#ffffff"); - $("#" + currentUUID).css("background", "#f2f3f5"); + $("#" + currentUUID).css("background", "#f2f3f5").addClass('selected'); $(".user-section").hide(); msg_sender_status(true); $("#section-" + currentUUID).show(); @@ -247,7 +252,7 @@ layui.use(['layer', 'form', 'jquery'], function () { var msg = { "uid": data.username, "ip": ip, - type:'kefu' + type: 'kefu' }; socket.emit('login', msg); }); @@ -261,36 +266,37 @@ layui.use(['layer', 'form', 'jquery'], function () { //后端推送来消息时,更新用户 socket.on('update-users', function (msg) { - if (msg.type == 'offline') { - //arrayRemove(uuids,msg.uid); + if (msg.type == 'offline') { // 用户离线 $(".chat-user #" + msg.uid + " .user-avatar img").attr("src", "/images/server/mine_fill.png"); - $("#section-" + msg.uid).hide(); - //$(".chat-user").find("#"+msg.uid).remove(); + // $("#section-" + msg.uid).hide(); + $(".chat-user").find(`[data-uid=${msg.uid}]`).find('.user-status').show(); msg_sender_status(false); } else if (msg.type == 'online') { + // 设置 当前用户 if (!currentUUID) { currentUUID = msg.uid; } - if (currentUUID == uuid) { return false; } - var index = uuids.indexOf(msg.uid); - if (index == -1) { + // 获取上线的用户 + if (uuids.indexOf(msg.uid) == -1) { uuids.push(msg.uid); - insert_user_html(msg.uid, msg.name + '#' + (uuids.length + 1)); - //创建聊天section - insert_section(msg.uid); - } else { - if ($(".chat-user").find("#" + msg.uid).length == 0) { - insert_user_html(msg.uid, msg.name + '#' + (uuids.length + 1)); - //创建聊天section - insert_section(msg.uid); - } } - - $(".chat-user #" + msg.uid + " .user-avatar img").attr("src", "/images/server/mine_fill_blue.png"); + //没有新的用户 + let userInfoEle = $(".chat-user").find(`[data-uid=${msg.uid}]`); + if (userInfoEle.length == 0) { + insert_user_html(msg.uid, msg.nickname, msg); + // 创建聊天section + insert_section(msg.uid); + userInfoEle = $(".chat-user").find(`[data-uid=${msg.uid}]`); + // insert_user_html(msg.uid, msg.name + '#' + (uuids.length + 1)); + // //创建聊天section + // insert_section(msg.uid); + } + userInfoEle.find(".user-avatar img").attr("src", "/images/server/mine_fill_blue.png"); + userInfoEle.find('.user-status').hide(); } update_online_status(); }); @@ -305,7 +311,8 @@ layui.use(['layer', 'form', 'jquery'], function () { $(document).on('click', '.user-info', function () { var uid = $(this).attr("id"); currentUUID = uid; - $(".user-info").css("background", "#ffffff"); + $(".user-info").css("background", "#ffffff").removeClass('selected'); + $(this).addClass('selected'); $("#" + uid).css("background", "#f2f3f5"); $(".user-section").hide(); $("#section-" + uid).show(); @@ -320,10 +327,10 @@ layui.use(['layer', 'form', 'jquery'], function () { btnAlign: 'c', btn: [' 登录 '], closeBtn: 0, - shade :0.7, + shade: 0.7, value: '' }, function (username, index, elem) { - if(!username){ + if (!username) { showLoginView(); return; } @@ -341,6 +348,7 @@ layui.use(['layer', 'form', 'jquery'], function () { }) }); } + window.getUserData = get_users; if (!data.username) { showLoginView(); } else { @@ -348,4 +356,5 @@ layui.use(['layer', 'form', 'jquery'], function () { init(); get_users(); } + }); \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index 144bd20..92f594a 100644 --- a/routes/users.js +++ b/routes/users.js @@ -8,7 +8,7 @@ const model = require('./../model/session'); /* GET users listing. */ router.get('/', async function (req, res, next) { try { - let data = await model.findByCondition({type: 'customer', kefu_id: req.cookies.username}); + let data = await model.findByCondition({type: 'customer',status:1, kefu_id: req.cookies.username}); return res.send({code: 200, msg: '获取成功', data: data ? data : []}); } catch (e) { return res.send({code: 400, msg: '获取失败'});