基础功能上传
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 redis = require('../utils/redis');
|
||||||
var msgType = require('./messageTpye');
|
var msgType = require('./messageTpye');
|
||||||
var ioSvc = require('./ioHelper').ioSvc;
|
var ioSvc = require('./ioHelper').ioSvc;
|
||||||
|
var AppConfig = require('../config');
|
||||||
|
|
||||||
//服务端连接
|
//服务端连接
|
||||||
function ioServer(io) {
|
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) {
|
io.on('connection', function (socket) {
|
||||||
console.log('SocketIO有新的连接!');
|
console.log('SocketIO有新的连接!');
|
||||||
|
|
||||||
@ -28,22 +36,76 @@ function ioServer(io) {
|
|||||||
//用户与Socket进行绑定
|
//用户与Socket进行绑定
|
||||||
socket.on('login', function (uid) {
|
socket.on('login', function (uid) {
|
||||||
console.log(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) {
|
redis.set(uid,socket.id,null,function (err,ret) {
|
||||||
if(err){
|
if(err){
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
redis.set(socket.id,uid,null,function (err,ret) {
|
redis.set(socket.id,uid,null,function (err,ret) {
|
||||||
if(err){
|
if(err){
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//断开事件
|
//断开事件
|
||||||
socket.on('disconnect', function() {
|
socket.on('disconnect', function() {
|
||||||
console.log("与服务其断开");
|
console.log("与服务其断开");
|
||||||
|
|
||||||
_self.updateOnlieCount(false);
|
_self.updateOnlieCount(false);
|
||||||
|
|
||||||
redis.get(socket.id,function (err,val) {
|
redis.get(socket.id,function (err,val) {
|
||||||
if(err){
|
if(err){
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -59,6 +121,43 @@ function ioServer(io) {
|
|||||||
console.error(err);
|
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){
|
socket.on('message',function(msg){
|
||||||
if(msg.type == msgType.messageType.public){
|
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){
|
}else if(msg.type == msgType.messageType.private){
|
||||||
var uid = msg.uid;
|
var uid = msg.uid;
|
||||||
redis.get(uid,function (err,sid) {
|
redis.get(uid,function (err,sid) {
|
||||||
@ -79,7 +182,11 @@ function ioServer(io) {
|
|||||||
}
|
}
|
||||||
if(sid){
|
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;
|
line-height: 44px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #858e99;
|
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(){
|
$(function(){
|
||||||
//Socket.IO 连接
|
//Socket.IO 连接
|
||||||
var socket = io.connect('http://'+document.domain+':9010');
|
var socket = io.connect('http://'+document.domain+':9010');
|
||||||
|
var uuid = '';
|
||||||
|
|
||||||
function insert_client_html(time,content){
|
function insert_client_html(time,content){
|
||||||
var tpl = '<div class="msg-box">'+
|
var tpl = '<div class="msg-box">'+
|
||||||
@ -33,17 +34,36 @@ $(function(){
|
|||||||
$(".msg-container").append(tpl);
|
$(".msg-container").append(tpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//聊天窗口自动滚到底
|
||||||
|
function scrollToBottom() {
|
||||||
|
var div = document.getElementById('msg-container');
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$("#btnSend").click(function(){
|
$("#btnSend").click(function(){
|
||||||
var date = dateFormat();
|
var date = dateFormat();
|
||||||
var msg = $("#textarea").val();
|
var msg = $("#textarea").val();
|
||||||
insert_client_html(date,msg);
|
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 () {
|
socket.on('connect', function () {
|
||||||
console.log('连接成功...');
|
//uuid = 'chat'+ guid();
|
||||||
var uuid = 'chat'+ guid();
|
var fp1 = new Fingerprint();
|
||||||
|
uuid = fp1.get();
|
||||||
|
console.log('连接成功...'+uuid);
|
||||||
socket.emit('login', uuid);
|
socket.emit('login', uuid);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,6 +74,7 @@ $(function(){
|
|||||||
// */
|
// */
|
||||||
socket.on('message', function(msg){
|
socket.on('message', function(msg){
|
||||||
insert_agent_html(dateFormat(),msg.content);
|
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 express = require('express');
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
var redis = require('../utils/redis');
|
||||||
|
|
||||||
/* GET users listing. */
|
/* GET users listing. */
|
||||||
router.get('/', function(req, res, next) {
|
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;
|
module.exports = router;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<!-- 这里是页面内容区 -->
|
<!-- 这里是页面内容区 -->
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="content-block msg-container">
|
<div class="content-block msg-container" id="msg-container">
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</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/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.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 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 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/common.js' charset='utf-8'></script>
|
||||||
<script type='text/javascript' src='js/client/client.js' charset='utf-8'></script>
|
<script type='text/javascript' src='js/client/client.js' charset='utf-8'></script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<% include header.ejs %>
|
<% include header.ejs %>
|
||||||
<style>
|
<style>
|
||||||
.friend{
|
.friend {
|
||||||
position: relative;
|
position: relative;
|
||||||
float: left;
|
float: left;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
@ -8,13 +8,15 @@
|
|||||||
background: #fbfcfe;
|
background: #fbfcfe;
|
||||||
border-right: 1px solid #e9e9e9;
|
border-right: 1px solid #e9e9e9;
|
||||||
}
|
}
|
||||||
.chat{
|
|
||||||
|
.chat {
|
||||||
position: relative;
|
position: relative;
|
||||||
float: left;
|
float: left;
|
||||||
width: calc(100% - 301px);
|
width: calc(100% - 301px);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.friend-head{
|
|
||||||
|
.friend-head {
|
||||||
display: block;
|
display: block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 51px;
|
height: 51px;
|
||||||
@ -26,32 +28,137 @@
|
|||||||
border-top: 1px solid #e9e9e9;
|
border-top: 1px solid #e9e9e9;
|
||||||
border-bottom: 1px solid #e9e9e9;
|
border-bottom: 1px solid #e9e9e9;
|
||||||
}
|
}
|
||||||
.friend-head-right{
|
|
||||||
|
.friend-head-right {
|
||||||
float: 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>
|
</style>
|
||||||
<div class="layui-fluid">
|
<div class="layui-fluid">
|
||||||
<div class="friend">
|
<div class="friend">
|
||||||
<div class="friend-head">
|
<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>
|
<span class="help-my-chat">我的对话</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="chat-user">
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat">
|
<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>
|
||||||
</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 src="/layui/layui.js"></script>
|
||||||
});
|
<script src="/socket.io/socket.io.js"></script>
|
||||||
</script>
|
<script type='text/javascript' src='js/common.js' charset='utf-8'></script>
|
||||||
|
<script src="/js/server/index.js"> </script>
|
||||||
|
|
||||||
<% include footer.ejs %>
|
<% include footer.ejs %>
|
Loading…
x
Reference in New Issue
Block a user