基础功能上传
This commit is contained in:
parent
3dba4147ea
commit
3c78c7f4c2
5
config.js
Normal file
5
config.js
Normal file
@ -0,0 +1,5 @@
|
||||
const APP = {
|
||||
"KEFUUUID":'chat-kefu-admin'
|
||||
};
|
||||
|
||||
module.exports = APP;
|
111
io/io.js
111
io/io.js
@ -6,6 +6,7 @@
|
||||
var redis = require('../utils/redis');
|
||||
var msgType = require('./messageTpye');
|
||||
var ioSvc = require('./ioHelper').ioSvc;
|
||||
var AppConfig = require('../config');
|
||||
|
||||
//服务端连接
|
||||
function ioServer(io) {
|
||||
@ -20,6 +21,13 @@ function ioServer(io) {
|
||||
}
|
||||
});
|
||||
|
||||
Array.prototype.remove = function(val) {
|
||||
var index = this.indexOf(val);
|
||||
if (index > -1) {
|
||||
this.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
io.on('connection', function (socket) {
|
||||
console.log('SocketIO有新的连接!');
|
||||
|
||||
@ -28,22 +36,76 @@ function ioServer(io) {
|
||||
//用户与Socket进行绑定
|
||||
socket.on('login', function (uid) {
|
||||
console.log(uid+'登录成功');
|
||||
|
||||
//通知用户上线
|
||||
if(uid != AppConfig.KEFUUUID){
|
||||
redis.get(AppConfig.KEFUUUID,function (err,sid) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
if(sid){
|
||||
redis.get('online_count',function (err,val) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
if(!val){
|
||||
val = 0;
|
||||
}
|
||||
if(typeof val == 'string'){
|
||||
val = parseInt(val);
|
||||
}
|
||||
var info = {
|
||||
"uid":uid,
|
||||
"name":'客户'+val,
|
||||
"type":'online'
|
||||
};
|
||||
io.to(sid).emit('update-users',info);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
redis.get('user-uuids',function (err,uuids) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
if(uuids){
|
||||
uuids =JSON.parse(uuids);
|
||||
}else{
|
||||
uuids = [];
|
||||
}
|
||||
if(uuids.indexOf(uid) == -1){
|
||||
uuids.push(uid);
|
||||
uuids = JSON.stringify(uuids);
|
||||
redis.set('user-uuids',uuids,null,function (err,ret) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
redis.set(uid,socket.id,null,function (err,ret) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
redis.set(socket.id,uid,null,function (err,ret) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//断开事件
|
||||
socket.on('disconnect', function() {
|
||||
console.log("与服务其断开");
|
||||
|
||||
_self.updateOnlieCount(false);
|
||||
|
||||
redis.get(socket.id,function (err,val) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
@ -59,6 +121,43 @@ function ioServer(io) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
//通知用户下线
|
||||
if(val != AppConfig.KEFUUUID){
|
||||
redis.get(AppConfig.KEFUUUID,function (err,sid) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
if(sid){
|
||||
var info = {
|
||||
"uid":val,
|
||||
"name":'客户下线',
|
||||
"type":'offline'
|
||||
};
|
||||
io.to(sid).emit('update-users',info);
|
||||
}
|
||||
});
|
||||
|
||||
redis.get('user-uuids',function (err,uuids) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
if(uuids){
|
||||
uuids =JSON.parse(uuids);
|
||||
}else{
|
||||
uuids = [];
|
||||
}
|
||||
|
||||
if(uuids.indexOf(val) != -1){
|
||||
uuids.remove(val);
|
||||
uuids = JSON.stringify(uuids);
|
||||
redis.set('user-uuids',uuids,null,function (err,ret) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -70,7 +169,11 @@ function ioServer(io) {
|
||||
//监听客户端发送的信息,实现消息转发到各个其他客户端
|
||||
socket.on('message',function(msg){
|
||||
if(msg.type == msgType.messageType.public){
|
||||
socket.broadcast.emit("message",msg.content);
|
||||
var mg = {
|
||||
"uid" : msg.from_uid ,
|
||||
"content": msg.content
|
||||
};
|
||||
socket.broadcast.emit("message",mg);
|
||||
}else if(msg.type == msgType.messageType.private){
|
||||
var uid = msg.uid;
|
||||
redis.get(uid,function (err,sid) {
|
||||
@ -79,7 +182,11 @@ function ioServer(io) {
|
||||
}
|
||||
if(sid){
|
||||
//给指定的客户端发送消息
|
||||
io.sockets.socket(sid).emit('message', msg.content);
|
||||
var mg = {
|
||||
"uid" : msg.from_uid,
|
||||
"content": msg.content
|
||||
};
|
||||
io.to(sid).emit('message',mg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -193,4 +193,5 @@ a {
|
||||
line-height: 44px;
|
||||
font-size: 14px;
|
||||
color: #858e99;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
BIN
public/images/server/mine_fill.png
Normal file
BIN
public/images/server/mine_fill.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
@ -1,6 +1,7 @@
|
||||
$(function(){
|
||||
//Socket.IO 连接
|
||||
var socket = io.connect('http://'+document.domain+':9010');
|
||||
var uuid = '';
|
||||
|
||||
function insert_client_html(time,content){
|
||||
var tpl = '<div class="msg-box">'+
|
||||
@ -33,17 +34,36 @@ $(function(){
|
||||
$(".msg-container").append(tpl);
|
||||
}
|
||||
|
||||
//聊天窗口自动滚到底
|
||||
function scrollToBottom() {
|
||||
var div = document.getElementById('msg-container');
|
||||
div.scrollTop = div.scrollHeight;
|
||||
}
|
||||
|
||||
|
||||
$("#btnSend").click(function(){
|
||||
var date = dateFormat();
|
||||
var msg = $("#textarea").val();
|
||||
if(msg){
|
||||
var msg_sender = {
|
||||
"type":'private',
|
||||
"uid":'chat-kefu-admin',
|
||||
"content":msg,
|
||||
"from_uid":uuid
|
||||
};
|
||||
socket.emit('message', msg_sender);
|
||||
insert_client_html(date,msg);
|
||||
scrollToBottom();
|
||||
$("#textarea").val('');
|
||||
}
|
||||
});
|
||||
|
||||
//连接服务器
|
||||
socket.on('connect', function () {
|
||||
console.log('连接成功...');
|
||||
var uuid = 'chat'+ guid();
|
||||
//uuid = 'chat'+ guid();
|
||||
var fp1 = new Fingerprint();
|
||||
uuid = fp1.get();
|
||||
console.log('连接成功...'+uuid);
|
||||
socket.emit('login', uuid);
|
||||
});
|
||||
|
||||
@ -54,6 +74,7 @@ $(function(){
|
||||
// */
|
||||
socket.on('message', function(msg){
|
||||
insert_agent_html(dateFormat(),msg.content);
|
||||
scrollToBottom();
|
||||
});
|
||||
|
||||
});
|
293
public/js/fingerprint.js
Executable file
293
public/js/fingerprint.js
Executable file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* fingerprintJS 0.5.5 - Fast browser fingerprint library
|
||||
* https://github.com/Valve/fingerprintjs
|
||||
* Copyright (c) 2013 Valentin Vasilyev (valentin.vasilyev@outlook.com)
|
||||
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
;(function (name, context, definition) {
|
||||
if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); }
|
||||
else if (typeof define === 'function' && define.amd) { define(definition); }
|
||||
else { context[name] = definition(); }
|
||||
})('Fingerprint', this, function () {
|
||||
'use strict';
|
||||
|
||||
var Fingerprint = function (options) {
|
||||
var nativeForEach, nativeMap;
|
||||
nativeForEach = Array.prototype.forEach;
|
||||
nativeMap = Array.prototype.map;
|
||||
|
||||
this.each = function (obj, iterator, context) {
|
||||
if (obj === null) {
|
||||
return;
|
||||
}
|
||||
if (nativeForEach && obj.forEach === nativeForEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (obj.length === +obj.length) {
|
||||
for (var i = 0, l = obj.length; i < l; i++) {
|
||||
if (iterator.call(context, obj[i], i, obj) === {}) return;
|
||||
}
|
||||
} else {
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (iterator.call(context, obj[key], key, obj) === {}) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.map = function(obj, iterator, context) {
|
||||
var results = [];
|
||||
// Not using strict equality so that this acts as a
|
||||
// shortcut to checking for `null` and `undefined`.
|
||||
if (obj == null) return results;
|
||||
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
||||
this.each(obj, function(value, index, list) {
|
||||
results[results.length] = iterator.call(context, value, index, list);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
if (typeof options == 'object'){
|
||||
this.hasher = options.hasher;
|
||||
this.screen_resolution = options.screen_resolution;
|
||||
this.screen_orientation = options.screen_orientation;
|
||||
this.canvas = options.canvas;
|
||||
this.ie_activex = options.ie_activex;
|
||||
} else if(typeof options == 'function'){
|
||||
this.hasher = options;
|
||||
}
|
||||
};
|
||||
|
||||
Fingerprint.prototype = {
|
||||
get: function(){
|
||||
var keys = [];
|
||||
keys.push(navigator.userAgent);
|
||||
keys.push(navigator.language);
|
||||
keys.push(screen.colorDepth);
|
||||
if (this.screen_resolution) {
|
||||
var resolution = this.getScreenResolution();
|
||||
if (typeof resolution !== 'undefined'){ // headless browsers, such as phantomjs
|
||||
keys.push(resolution.join('x'));
|
||||
}
|
||||
}
|
||||
keys.push(new Date().getTimezoneOffset());
|
||||
keys.push(this.hasSessionStorage());
|
||||
keys.push(this.hasLocalStorage());
|
||||
keys.push(this.hasIndexDb());
|
||||
//body might not be defined at this point or removed programmatically
|
||||
if(document.body){
|
||||
keys.push(typeof(document.body.addBehavior));
|
||||
} else {
|
||||
keys.push(typeof undefined);
|
||||
}
|
||||
keys.push(typeof(window.openDatabase));
|
||||
keys.push(navigator.cpuClass);
|
||||
keys.push(navigator.platform);
|
||||
keys.push(navigator.doNotTrack);
|
||||
keys.push(this.getPluginsString());
|
||||
if(this.canvas && this.isCanvasSupported()){
|
||||
keys.push(this.getCanvasFingerprint());
|
||||
}
|
||||
if(this.hasher){
|
||||
return this.hasher(keys.join('###'), 31);
|
||||
} else {
|
||||
return this.murmurhash3_32_gc(keys.join('###'), 31);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
|
||||
*
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @see http://github.com/garycourt/murmurhash-js
|
||||
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
|
||||
* @see http://sites.google.com/site/murmurhash/
|
||||
*
|
||||
* @param {string} key ASCII only
|
||||
* @param {number} seed Positive integer only
|
||||
* @return {number} 32-bit positive integer hash
|
||||
*/
|
||||
|
||||
murmurhash3_32_gc: function(key, seed) {
|
||||
var remainder, bytes, h1, h1b, c1, c2, k1, i;
|
||||
|
||||
remainder = key.length & 3; // key.length % 4
|
||||
bytes = key.length - remainder;
|
||||
h1 = seed;
|
||||
c1 = 0xcc9e2d51;
|
||||
c2 = 0x1b873593;
|
||||
i = 0;
|
||||
|
||||
while (i < bytes) {
|
||||
k1 =
|
||||
((key.charCodeAt(i) & 0xff)) |
|
||||
((key.charCodeAt(++i) & 0xff) << 8) |
|
||||
((key.charCodeAt(++i) & 0xff) << 16) |
|
||||
((key.charCodeAt(++i) & 0xff) << 24);
|
||||
++i;
|
||||
|
||||
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = (h1 << 13) | (h1 >>> 19);
|
||||
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
|
||||
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
|
||||
}
|
||||
|
||||
k1 = 0;
|
||||
|
||||
switch (remainder) {
|
||||
case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
|
||||
case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
|
||||
case 1: k1 ^= (key.charCodeAt(i) & 0xff);
|
||||
|
||||
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
h1 ^= key.length;
|
||||
|
||||
h1 ^= h1 >>> 16;
|
||||
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
|
||||
h1 ^= h1 >>> 13;
|
||||
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
|
||||
h1 ^= h1 >>> 16;
|
||||
|
||||
return h1 >>> 0;
|
||||
},
|
||||
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=781447
|
||||
hasLocalStorage: function () {
|
||||
try{
|
||||
return !!window.localStorage;
|
||||
} catch(e) {
|
||||
return true; // SecurityError when referencing it means it exists
|
||||
}
|
||||
},
|
||||
|
||||
hasSessionStorage: function () {
|
||||
try{
|
||||
return !!window.sessionStorage;
|
||||
} catch(e) {
|
||||
return true; // SecurityError when referencing it means it exists
|
||||
}
|
||||
},
|
||||
|
||||
hasIndexDb: function () {
|
||||
try{
|
||||
return !!window.indexedDB;
|
||||
} catch(e) {
|
||||
return true; // SecurityError when referencing it means it exists
|
||||
}
|
||||
},
|
||||
|
||||
isCanvasSupported: function () {
|
||||
var elem = document.createElement('canvas');
|
||||
return !!(elem.getContext && elem.getContext('2d'));
|
||||
},
|
||||
|
||||
isIE: function () {
|
||||
if(navigator.appName === 'Microsoft Internet Explorer') {
|
||||
return true;
|
||||
} else if(navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)){// IE 11
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
getPluginsString: function () {
|
||||
if(this.isIE() && this.ie_activex){
|
||||
return this.getIEPluginsString();
|
||||
} else {
|
||||
return this.getRegularPluginsString();
|
||||
}
|
||||
},
|
||||
|
||||
getRegularPluginsString: function () {
|
||||
return this.map(navigator.plugins, function (p) {
|
||||
var mimeTypes = this.map(p, function(mt){
|
||||
return [mt.type, mt.suffixes].join('~');
|
||||
}).join(',');
|
||||
return [p.name, p.description, mimeTypes].join('::');
|
||||
}, this).join(';');
|
||||
},
|
||||
|
||||
getIEPluginsString: function () {
|
||||
if(window.ActiveXObject){
|
||||
var names = ['ShockwaveFlash.ShockwaveFlash',//flash plugin
|
||||
'AcroPDF.PDF', // Adobe PDF reader 7+
|
||||
'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr
|
||||
'QuickTime.QuickTime', // QuickTime
|
||||
// 5 versions of real players
|
||||
'rmocx.RealPlayer G2 Control',
|
||||
'rmocx.RealPlayer G2 Control.1',
|
||||
'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)',
|
||||
'RealVideo.RealVideo(tm) ActiveX Control (32-bit)',
|
||||
'RealPlayer',
|
||||
'SWCtl.SWCtl', // ShockWave player
|
||||
'WMPlayer.OCX', // Windows media player
|
||||
'AgControl.AgControl', // Silverlight
|
||||
'Skype.Detection'];
|
||||
|
||||
// starting to detect plugins in IE
|
||||
return this.map(names, function(name){
|
||||
try{
|
||||
new ActiveXObject(name);
|
||||
return name;
|
||||
} catch(e){
|
||||
return null;
|
||||
}
|
||||
}).join(';');
|
||||
} else {
|
||||
return ""; // behavior prior version 0.5.0, not breaking backwards compat.
|
||||
}
|
||||
},
|
||||
|
||||
getScreenResolution: function () {
|
||||
var resolution;
|
||||
if(this.screen_orientation){
|
||||
resolution = (screen.height > screen.width) ? [screen.height, screen.width] : [screen.width, screen.height];
|
||||
}else{
|
||||
resolution = [screen.height, screen.width];
|
||||
}
|
||||
return resolution;
|
||||
},
|
||||
|
||||
getCanvasFingerprint: function () {
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
// https://www.browserleaks.com/canvas#how-does-it-work
|
||||
var txt = 'http://valve.github.io';
|
||||
ctx.textBaseline = "top";
|
||||
ctx.font = "14px 'Arial'";
|
||||
ctx.textBaseline = "alphabetic";
|
||||
ctx.fillStyle = "#f60";
|
||||
ctx.fillRect(125,1,62,20);
|
||||
ctx.fillStyle = "#069";
|
||||
ctx.fillText(txt, 2, 15);
|
||||
ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
|
||||
ctx.fillText(txt, 4, 17);
|
||||
return canvas.toDataURL();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return Fingerprint;
|
||||
|
||||
});
|
173
public/js/server/index.js
Normal file
173
public/js/server/index.js
Normal file
@ -0,0 +1,173 @@
|
||||
//一般直接写在一个js文件中
|
||||
layui.use(['layer', 'form', 'jquery'], function () {
|
||||
var layer = layui.layer
|
||||
, form = layui.form
|
||||
, $ = layui.jquery;
|
||||
|
||||
var currentUUID = '';
|
||||
var uuid = '';
|
||||
var socket = io.connect('http://'+document.domain+':9010');
|
||||
|
||||
var uuids = [];
|
||||
|
||||
Array.prototype.remove = function(val) {
|
||||
var index = this.indexOf(val);
|
||||
if (index > -1) {
|
||||
this.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//页面初始化函数
|
||||
function init() {
|
||||
$(".admin-index").addClass("layui-this");
|
||||
|
||||
var height = document.body.clientHeight - 262;
|
||||
$(".message-container").css("height", height);
|
||||
|
||||
window.onresize = function(){
|
||||
var height = document.body.clientHeight - 262;
|
||||
$(".message-container").css("height", height);
|
||||
}
|
||||
}
|
||||
|
||||
//聊天窗口自动滚到底
|
||||
function scrollToBottom() {
|
||||
var div = document.getElementById('message-container');
|
||||
div.scrollTop = div.scrollHeight;
|
||||
}
|
||||
|
||||
function insert_section(uid) {
|
||||
var html = '<section class="user-section" id="section-'+ uid +'"></section>';
|
||||
$(".message-container").append(html);
|
||||
}
|
||||
|
||||
function insert_agent_html(content){
|
||||
var date = dateFormat();
|
||||
var html = ' <div class="message-agent">\n' +
|
||||
' <div class="message-agent-time-sender message-time-sender">\n' +
|
||||
' <span class="message-agent-time">' + date + '</span>\n' +
|
||||
' <span class="">我</span>\n' +
|
||||
' </div>\n' +
|
||||
' <div class="message-agent-content message-content">\n' +
|
||||
' <div>' + content + '</div>\n' +
|
||||
' </div>\n' +
|
||||
' </div>';
|
||||
$('#section-'+currentUUID).append(html);
|
||||
}
|
||||
|
||||
|
||||
function insert_client_html(uid,content){
|
||||
var date = dateFormat();
|
||||
var html = '<div class="message-client">\n' +
|
||||
' <div class="message-time-sender">\n' +
|
||||
' <span class="message-client-time">' + date + '</span>\n' +
|
||||
' <span class="">客户</span>\n' +
|
||||
' </div>\n' +
|
||||
' <div class="message-client-content message-content">\n' +
|
||||
' <div>' + content + '</div>\n' +
|
||||
' </div>\n' +
|
||||
' </div>';
|
||||
$('#section-'+uid).append(html);
|
||||
}
|
||||
|
||||
function insert_user_html(id,name) {
|
||||
var html = '<div class="user-info layui-row" id="' + id + '">\n' +
|
||||
' <div class="layui-col-xs3 user-avatar">\n' +
|
||||
' <img src="/images/server/mine_fill.png">\n' +
|
||||
' </div>\n' +
|
||||
' <div class="layui-col-xs9">' + name + '</div>\n' +
|
||||
' </div>';
|
||||
$('.chat-user').append(html);
|
||||
}
|
||||
|
||||
function getUsers() {
|
||||
$.get('/users',function (data) {
|
||||
if(data.code == 200){
|
||||
$('.chat-user').html('');
|
||||
|
||||
var data = data.data;
|
||||
var count = 1;
|
||||
data.forEach(function (uid) {
|
||||
insert_user_html(uid,'客户' + count++);
|
||||
//创建聊天section
|
||||
insert_section(uid);
|
||||
});
|
||||
if(data.length > 0 && !currentUUID){
|
||||
currentUUID = data[0];
|
||||
}
|
||||
|
||||
$(".user-info").css("background","#ffffff");
|
||||
$("#"+currentUUID).css("background","#f2f3f5");
|
||||
$(".user-section").hide();
|
||||
$("#section-"+currentUUID).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(".btnMsgSend").click(function(){
|
||||
var msg = $("#msg-send-textarea").val();
|
||||
if(msg){
|
||||
var msg_sender = {
|
||||
"type":'private',
|
||||
"uid":currentUUID,
|
||||
"content":msg,
|
||||
"from_uid":uuid
|
||||
};
|
||||
socket.emit('message', msg_sender);
|
||||
insert_agent_html(msg);
|
||||
scrollToBottom();
|
||||
$("#msg-send-textarea").val('');
|
||||
}
|
||||
});
|
||||
|
||||
//连接服务器
|
||||
socket.on('connect', function () {
|
||||
console.log('连接成功...');
|
||||
uuid = 'chat-kefu-admin';
|
||||
socket.emit('login', uuid);
|
||||
});
|
||||
|
||||
//后端推送来消息时
|
||||
socket.on('message', function(msg){
|
||||
insert_client_html(msg.uid,msg.content);
|
||||
scrollToBottom();
|
||||
});
|
||||
|
||||
//后端推送来消息时
|
||||
socket.on('update-users', function(msg){
|
||||
if(msg.type == 'offline'){
|
||||
$("#"+msg.uid).remove();
|
||||
uuids.remove(msg.uid);
|
||||
}else if(msg.type == 'online'){
|
||||
if(!currentUUID){
|
||||
currentUUID = msg.uid;
|
||||
}
|
||||
if(uuids.indexOf(msg.uid) == -1){
|
||||
uuids.push(msg.uid);
|
||||
insert_user_html(msg.uid,msg.name);
|
||||
//创建聊天section
|
||||
insert_section(msg.uid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//更新用户在线数
|
||||
socket.on('update_online_count', function(msg){
|
||||
$(".friend-head-right").html( (msg.online_count - 1) + '人' );
|
||||
});
|
||||
|
||||
//切换用户
|
||||
$(document).on('click','.user-info',function(){
|
||||
var uid = $(this).attr("id");
|
||||
currentUUID = uid;
|
||||
$(".user-info").css("background","#ffffff");
|
||||
$("#"+uid).css("background","#f2f3f5");
|
||||
$(".user-section").hide();
|
||||
$("#section-"+uid).show();
|
||||
});
|
||||
|
||||
|
||||
init();
|
||||
getUsers();
|
||||
});
|
@ -1,9 +1,22 @@
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
var redis = require('../utils/redis');
|
||||
|
||||
/* GET users listing. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.send('respond with a resource');
|
||||
redis.get('user-uuids',function (err,uuids) {
|
||||
if(err){
|
||||
console.error(err);
|
||||
return res.send({code:400,msg:'获取失败'});
|
||||
}
|
||||
if(uuids){
|
||||
uuids =JSON.parse(uuids);
|
||||
}else{
|
||||
uuids = [];
|
||||
}
|
||||
|
||||
return res.send({code:200,msg:'获取成功',data:uuids});
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
@ -25,7 +25,7 @@
|
||||
</header>
|
||||
<!-- 这里是页面内容区 -->
|
||||
<div class="content">
|
||||
<div class="content-block msg-container">
|
||||
<div class="content-block msg-container" id="msg-container">
|
||||
|
||||
|
||||
</div>
|
||||
@ -44,6 +44,7 @@
|
||||
<script type='text/javascript' src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script>
|
||||
<script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script>
|
||||
<script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script>
|
||||
<script src="/js/fingerprint.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script type='text/javascript' src='js/common.js' charset='utf-8'></script>
|
||||
<script type='text/javascript' src='js/client/client.js' charset='utf-8'></script>
|
||||
|
@ -8,12 +8,14 @@
|
||||
background: #fbfcfe;
|
||||
border-right: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.chat {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: calc(100% - 301px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.friend-head {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
@ -26,32 +28,137 @@
|
||||
border-top: 1px solid #e9e9e9;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.friend-head-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.message-agent,.message-client{
|
||||
overflow: auto;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.message-container{
|
||||
padding: 0 20px 0 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.message-time-sender{
|
||||
line-height: 1;
|
||||
margin-bottom: 5px;
|
||||
font-size: 12px;
|
||||
color: #adb2bb;
|
||||
}
|
||||
|
||||
.message-agent-time-sender{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-content{
|
||||
border-radius: 3px;
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
border: 1px dashed transparent;
|
||||
}
|
||||
|
||||
.message-agent-content{
|
||||
position: relative;
|
||||
float: right;
|
||||
background-color: #f0f1f3;
|
||||
color: #161e26;
|
||||
}
|
||||
.message-client-content{
|
||||
position: relative;
|
||||
float: left ;
|
||||
background-color: #e7f4ff;
|
||||
color: #161e26;
|
||||
}
|
||||
|
||||
.message-sender{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 150px;
|
||||
border-top: 1px solid #e9e9e9;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.sender-editor{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.message-sender textarea{
|
||||
resize: none;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
color: #161e26;
|
||||
line-height: 22px;
|
||||
background-color: #fff;
|
||||
height: calc(100% - 40px);
|
||||
padding: 20px;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.btnMsgSend{
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.user-info{
|
||||
height: 60px;
|
||||
background: #ffffff;
|
||||
line-height: 60px;
|
||||
font-size: 16px;
|
||||
color: #767d85;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.chat-user{
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.user-info img{
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.user-info .user-avatar{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="layui-fluid">
|
||||
<div class="friend">
|
||||
<div class="friend-head">
|
||||
<span class="friend-head-right">0 / 2</span>
|
||||
<span class="friend-head-right">0人</span>
|
||||
<span class="help-my-chat">我的对话</span>
|
||||
</div>
|
||||
<div class="chat-user">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat">
|
||||
1111
|
||||
<div class="message-container" id="message-container">
|
||||
|
||||
</div>
|
||||
<div class="message-sender">
|
||||
<div class="sender-editor">
|
||||
<textarea placeholder="请输入" id="msg-send-textarea"></textarea>
|
||||
<div class="layui-btn layui-btn-normal btnMsgSend">发送</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script>
|
||||
//一般直接写在一个js文件中
|
||||
layui.use(['layer', 'form','jquery'], function(){
|
||||
var layer = layui.layer
|
||||
,form = layui.form
|
||||
,$ = layui.jquery;
|
||||
|
||||
$(".admin-index").addClass("layui-this");
|
||||
});
|
||||
</script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script type='text/javascript' src='js/common.js' charset='utf-8'></script>
|
||||
<script src="/js/server/index.js"> </script>
|
||||
|
||||
<% include footer.ejs %>
|
Loading…
x
Reference in New Issue
Block a user