├── public ├── images │ ├── client.png │ ├── server.png │ ├── client │ │ ├── emoji.png │ │ └── picture.png │ └── server │ │ ├── tabpage.png │ │ ├── mine_fill.png │ │ └── mine_fill_blue.png ├── layui │ ├── font │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ ├── images │ │ └── face │ │ │ ├── 0.gif │ │ │ ├── 1.gif │ │ │ ├── 2.gif │ │ │ ├── 3.gif │ │ │ ├── 4.gif │ │ │ ├── 5.gif │ │ │ ├── 6.gif │ │ │ ├── 7.gif │ │ │ ├── 8.gif │ │ │ ├── 9.gif │ │ │ ├── 10.gif │ │ │ ├── 11.gif │ │ │ ├── 12.gif │ │ │ ├── 13.gif │ │ │ ├── 14.gif │ │ │ ├── 15.gif │ │ │ ├── 16.gif │ │ │ ├── 17.gif │ │ │ ├── 18.gif │ │ │ ├── 19.gif │ │ │ ├── 20.gif │ │ │ ├── 21.gif │ │ │ ├── 22.gif │ │ │ ├── 23.gif │ │ │ ├── 24.gif │ │ │ ├── 25.gif │ │ │ ├── 26.gif │ │ │ ├── 27.gif │ │ │ ├── 28.gif │ │ │ ├── 29.gif │ │ │ ├── 30.gif │ │ │ ├── 31.gif │ │ │ ├── 32.gif │ │ │ ├── 33.gif │ │ │ ├── 34.gif │ │ │ ├── 35.gif │ │ │ ├── 36.gif │ │ │ ├── 37.gif │ │ │ ├── 38.gif │ │ │ ├── 39.gif │ │ │ ├── 40.gif │ │ │ ├── 41.gif │ │ │ ├── 42.gif │ │ │ ├── 43.gif │ │ │ ├── 44.gif │ │ │ ├── 45.gif │ │ │ ├── 46.gif │ │ │ ├── 47.gif │ │ │ ├── 48.gif │ │ │ ├── 49.gif │ │ │ ├── 50.gif │ │ │ ├── 51.gif │ │ │ ├── 52.gif │ │ │ ├── 53.gif │ │ │ ├── 54.gif │ │ │ ├── 55.gif │ │ │ ├── 56.gif │ │ │ ├── 57.gif │ │ │ ├── 58.gif │ │ │ ├── 59.gif │ │ │ ├── 60.gif │ │ │ ├── 61.gif │ │ │ ├── 62.gif │ │ │ ├── 63.gif │ │ │ ├── 64.gif │ │ │ ├── 65.gif │ │ │ ├── 66.gif │ │ │ ├── 67.gif │ │ │ ├── 68.gif │ │ │ ├── 69.gif │ │ │ ├── 70.gif │ │ │ └── 71.gif │ ├── css │ │ ├── modules │ │ │ ├── layer │ │ │ │ └── default │ │ │ │ │ ├── icon.png │ │ │ │ │ ├── icon-ext.png │ │ │ │ │ ├── loading-0.gif │ │ │ │ │ ├── loading-1.gif │ │ │ │ │ ├── loading-2.gif │ │ │ │ │ └── layer.css │ │ │ ├── code.css │ │ │ └── laydate │ │ │ │ └── default │ │ │ │ └── laydate.css │ │ └── layui.mobile.css │ ├── lay │ │ └── modules │ │ │ ├── code.js │ │ │ ├── laytpl.js │ │ │ ├── util.js │ │ │ ├── flow.js │ │ │ ├── tree.js │ │ │ ├── carousel.js │ │ │ ├── laypage.js │ │ │ ├── upload.js │ │ │ ├── element.js │ │ │ ├── form.js │ │ │ ├── layedit.js │ │ │ ├── table.js │ │ │ └── layer.js │ └── layui.js ├── js │ ├── common.js │ ├── client │ │ └── client.js │ ├── fingerprint.js │ └── server │ │ └── index.js └── css │ ├── server.css │ └── client.css ├── .gitignore ├── views ├── client │ ├── error.ejs │ └── index.ejs └── server │ ├── users.ejs │ ├── setup.ejs │ ├── footer.ejs │ ├── header.ejs │ └── index.ejs ├── io ├── messageTpye.js ├── ioHelper.js └── io.js ├── config.js ├── package.json ├── utils ├── mongoose.js ├── common.js └── redis.js ├── routes ├── users.js ├── message.js └── index.js ├── README.md ├── model ├── message.js └── users.js ├── app.js └── bin └── www /public/images/client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/client.png -------------------------------------------------------------------------------- /public/images/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/server.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .gitignore 3 | .idea/ 4 | node_modules -------------------------------------------------------------------------------- /public/images/client/emoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/client/emoji.png -------------------------------------------------------------------------------- /public/layui/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/font/iconfont.eot -------------------------------------------------------------------------------- /public/layui/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/font/iconfont.ttf -------------------------------------------------------------------------------- /public/layui/images/face/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/0.gif -------------------------------------------------------------------------------- /public/layui/images/face/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/1.gif -------------------------------------------------------------------------------- /public/layui/images/face/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/2.gif -------------------------------------------------------------------------------- /public/layui/images/face/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/3.gif -------------------------------------------------------------------------------- /public/layui/images/face/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/4.gif -------------------------------------------------------------------------------- /public/layui/images/face/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/5.gif -------------------------------------------------------------------------------- /public/layui/images/face/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/6.gif -------------------------------------------------------------------------------- /public/layui/images/face/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/7.gif -------------------------------------------------------------------------------- /public/layui/images/face/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/8.gif -------------------------------------------------------------------------------- /public/layui/images/face/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/9.gif -------------------------------------------------------------------------------- /public/images/client/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/client/picture.png -------------------------------------------------------------------------------- /public/images/server/tabpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/server/tabpage.png -------------------------------------------------------------------------------- /public/layui/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/font/iconfont.woff -------------------------------------------------------------------------------- /public/layui/images/face/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/10.gif -------------------------------------------------------------------------------- /public/layui/images/face/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/11.gif -------------------------------------------------------------------------------- /public/layui/images/face/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/12.gif -------------------------------------------------------------------------------- /public/layui/images/face/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/13.gif -------------------------------------------------------------------------------- /public/layui/images/face/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/14.gif -------------------------------------------------------------------------------- /public/layui/images/face/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/15.gif -------------------------------------------------------------------------------- /public/layui/images/face/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/16.gif -------------------------------------------------------------------------------- /public/layui/images/face/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/17.gif -------------------------------------------------------------------------------- /public/layui/images/face/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/18.gif -------------------------------------------------------------------------------- /public/layui/images/face/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/19.gif -------------------------------------------------------------------------------- /public/layui/images/face/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/20.gif -------------------------------------------------------------------------------- /public/layui/images/face/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/21.gif -------------------------------------------------------------------------------- /public/layui/images/face/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/22.gif -------------------------------------------------------------------------------- /public/layui/images/face/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/23.gif -------------------------------------------------------------------------------- /public/layui/images/face/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/24.gif -------------------------------------------------------------------------------- /public/layui/images/face/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/25.gif -------------------------------------------------------------------------------- /public/layui/images/face/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/26.gif -------------------------------------------------------------------------------- /public/layui/images/face/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/27.gif -------------------------------------------------------------------------------- /public/layui/images/face/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/28.gif -------------------------------------------------------------------------------- /public/layui/images/face/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/29.gif -------------------------------------------------------------------------------- /public/layui/images/face/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/30.gif -------------------------------------------------------------------------------- /public/layui/images/face/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/31.gif -------------------------------------------------------------------------------- /public/layui/images/face/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/32.gif -------------------------------------------------------------------------------- /public/layui/images/face/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/33.gif -------------------------------------------------------------------------------- /public/layui/images/face/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/34.gif -------------------------------------------------------------------------------- /public/layui/images/face/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/35.gif -------------------------------------------------------------------------------- /public/layui/images/face/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/36.gif -------------------------------------------------------------------------------- /public/layui/images/face/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/37.gif -------------------------------------------------------------------------------- /public/layui/images/face/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/38.gif -------------------------------------------------------------------------------- /public/layui/images/face/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/39.gif -------------------------------------------------------------------------------- /public/layui/images/face/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/40.gif -------------------------------------------------------------------------------- /public/layui/images/face/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/41.gif -------------------------------------------------------------------------------- /public/layui/images/face/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/42.gif -------------------------------------------------------------------------------- /public/layui/images/face/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/43.gif -------------------------------------------------------------------------------- /public/layui/images/face/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/44.gif -------------------------------------------------------------------------------- /public/layui/images/face/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/45.gif -------------------------------------------------------------------------------- /public/layui/images/face/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/46.gif -------------------------------------------------------------------------------- /public/layui/images/face/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/47.gif -------------------------------------------------------------------------------- /public/layui/images/face/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/48.gif -------------------------------------------------------------------------------- /public/layui/images/face/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/49.gif -------------------------------------------------------------------------------- /public/layui/images/face/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/50.gif -------------------------------------------------------------------------------- /public/layui/images/face/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/51.gif -------------------------------------------------------------------------------- /public/layui/images/face/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/52.gif -------------------------------------------------------------------------------- /public/layui/images/face/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/53.gif -------------------------------------------------------------------------------- /public/layui/images/face/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/54.gif -------------------------------------------------------------------------------- /public/layui/images/face/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/55.gif -------------------------------------------------------------------------------- /public/layui/images/face/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/56.gif -------------------------------------------------------------------------------- /public/layui/images/face/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/57.gif -------------------------------------------------------------------------------- /public/layui/images/face/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/58.gif -------------------------------------------------------------------------------- /public/layui/images/face/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/59.gif -------------------------------------------------------------------------------- /public/layui/images/face/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/60.gif -------------------------------------------------------------------------------- /public/layui/images/face/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/61.gif -------------------------------------------------------------------------------- /public/layui/images/face/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/62.gif -------------------------------------------------------------------------------- /public/layui/images/face/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/63.gif -------------------------------------------------------------------------------- /public/layui/images/face/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/64.gif -------------------------------------------------------------------------------- /public/layui/images/face/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/65.gif -------------------------------------------------------------------------------- /public/layui/images/face/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/66.gif -------------------------------------------------------------------------------- /public/layui/images/face/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/67.gif -------------------------------------------------------------------------------- /public/layui/images/face/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/68.gif -------------------------------------------------------------------------------- /public/layui/images/face/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/69.gif -------------------------------------------------------------------------------- /public/layui/images/face/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/70.gif -------------------------------------------------------------------------------- /public/layui/images/face/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/images/face/71.gif -------------------------------------------------------------------------------- /public/images/server/mine_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/server/mine_fill.png -------------------------------------------------------------------------------- /views/client/error.ejs: -------------------------------------------------------------------------------- 1 |

<%= message %>

2 |

<%= error.status %>

3 |
<%= error.stack %>
4 | -------------------------------------------------------------------------------- /public/images/server/mine_fill_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/images/server/mine_fill_blue.png -------------------------------------------------------------------------------- /io/messageTpye.js: -------------------------------------------------------------------------------- 1 | const messageType= { 2 | 'public':'public', 3 | 'private':'private' 4 | }; 5 | 6 | exports.messageType = messageType; -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/css/modules/layer/default/icon.png -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/css/modules/layer/default/icon-ext.png -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/css/modules/layer/default/loading-0.gif -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/css/modules/layer/default/loading-1.gif -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/KeFu/master/public/layui/css/modules/layer/default/loading-2.gif -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const APP = { 2 | "KEFUUUID":'chat-kefu-admin', 3 | "QINIU":{ 4 | "accessKey":"your access key", 5 | "secretKey":"your secret key" 6 | } 7 | }; 8 | 9 | module.exports = APP; -------------------------------------------------------------------------------- /views/server/users.ejs: -------------------------------------------------------------------------------- 1 | <% include header.ejs %> 2 | 3 |
4 | 敬请期待 5 |
6 | 7 | 8 | 18 | 19 | <% include footer.ejs %> -------------------------------------------------------------------------------- /views/server/setup.ejs: -------------------------------------------------------------------------------- 1 | <% include header.ejs %> 2 | 3 |
4 | 敬请期待 5 |
6 | 7 | 8 | 19 | 20 | <% include footer.ejs %> -------------------------------------------------------------------------------- /views/server/footer.ejs: -------------------------------------------------------------------------------- 1 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kefu", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.17.1", 10 | "cookie-parser": "~1.4.3", 11 | "debug": "~2.6.3", 12 | "ejs": "~2.5.6", 13 | "express": "~4.15.2", 14 | "morgan": "~1.8.1", 15 | "serve-favicon": "~2.4.2", 16 | "socket.io":"~2.0.4", 17 | "socket.io-client":"^2.0.4", 18 | "redis":"^2.8.0", 19 | "mongoose":"^4.12.5", 20 | "qiniu":"^7.1.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /utils/mongoose.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | const DB_URL = 'mongodb://127.0.0.1:27017/kefu'; 3 | mongoose.connect(DB_URL); 4 | 5 | /** 6 | * 连接成功 7 | */ 8 | mongoose.connection.on('connected', function () { 9 | console.log('Mongoose connection open to ' + DB_URL); 10 | }); 11 | 12 | /** 13 | * 连接异常 14 | */ 15 | mongoose.connection.on('error',function (err) { 16 | console.log('Mongoose connection error: ' + err); 17 | }); 18 | 19 | /** 20 | * 连接断开 21 | */ 22 | mongoose.connection.on('disconnected', function () { 23 | console.log('Mongoose connection disconnected'); 24 | }); 25 | 26 | exports.mongoose = mongoose; -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var redis = require('../utils/redis'); 4 | 5 | /* GET users listing. */ 6 | router.get('/', function(req, res, next) { 7 | redis.get('user-uuids',function (err,uuids) { 8 | if(err){ 9 | console.error(err); 10 | return res.send({code:400,msg:'获取失败'}); 11 | } 12 | if(uuids){ 13 | uuids =JSON.parse(uuids); 14 | }else{ 15 | uuids = []; 16 | } 17 | 18 | return res.send({code:200,msg:'获取成功',data:uuids}); 19 | }); 20 | }); 21 | 22 | module.exports = router; 23 | -------------------------------------------------------------------------------- /routes/message.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var msgModel = require('../model/message'); 4 | 5 | router.get('/', function(req, res, next) { 6 | var page = req.query.page || 1; 7 | var size = req.query.size || 10; 8 | var uid = req.query.uid; 9 | 10 | if(!uid){ 11 | return res.send({code:500,msg:"参数不全"}); 12 | } 13 | 14 | msgModel.query(page,size,uid,function (err,data) { 15 | if(err){ 16 | console.error(err); 17 | return res.send({code:400,msg:"系统错误"}); 18 | } 19 | return res.send({code:200,msg:"获取成功",data:data}); 20 | }); 21 | }); 22 | 23 | module.exports = router; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeFu 2 | 在线客服系统,开发语言:NodeJS。通信库:Socket.IO。UI库:前端SUI,后端LayUI。 3 | 4 | # 缘起 5 | 公司商城里面想加个在线客服,但是第三方的的太贵,功能太多又又不上。所以闲暇时间写了这个,让公司能暂时用起来。 6 | 7 | # 安装 8 | git clone https://github.com/gytai/KeFu.git 9 | 10 | cd KeFu 11 | 12 | npm install 13 | 14 | pm2 start bin/www --name kefu 15 | 16 | # 使用 17 | 1,打开localhost:9010/client --客户端 18 | 19 | 2,打开localhost:9010 --服务端 20 | 21 | # 实例截图 22 | 客户端 23 | 24 | ![Alt text](https://github.com/gytai/KeFu/blob/master/public/images/client.png) 25 | 26 | 服务端 27 | 28 | ![Alt text](https://github.com/gytai/KeFu/blob/master/public/images/server.png) 29 | 30 | # 在线实例 31 | 客户端 32 | 33 | http://112.74.81.224:9010/client 34 | 35 | 客服端: 36 | 37 | http://112.74.81.224:9010/ 38 | -------------------------------------------------------------------------------- /io/ioHelper.js: -------------------------------------------------------------------------------- 1 | var redis = require('../utils/redis'); 2 | 3 | var ioSvc = {}; 4 | ioSvc.io = null; 5 | 6 | //初始化实例 7 | ioSvc.setInstance = function (io) { 8 | this.io = io; 9 | }; 10 | 11 | ioSvc.getInstance =function () { 12 | return this.io; 13 | }; 14 | 15 | //服务器给所有客户端广播消息 16 | ioSvc.serverBroadcastMsg = function (data) { 17 | console.log('发送广播消息'); 18 | console.log(data); 19 | this.io.sockets.emit('message',data); 20 | }; 21 | 22 | //服务端给指定用户发消息 23 | ioSvc.serverToPrivateMsg = function (uid,data) { 24 | console.log('发送私人消息'); 25 | console.log(data); 26 | redis.get(uid,function (err,sid) { 27 | if(err){ 28 | console.error(err); 29 | } 30 | if(sid){ 31 | //给指定的客户端发送消息 32 | this.io.sockets.socket(sid).emit('message',data); 33 | } 34 | }); 35 | }; 36 | 37 | exports.ioSvc = ioSvc; -------------------------------------------------------------------------------- /utils/common.js: -------------------------------------------------------------------------------- 1 | var http=require('http'); 2 | 3 | function getClientIp(req) { 4 | return req.headers['x-forwarded-for'] || 5 | req.connection.remoteAddress || 6 | req.socket.remoteAddress || 7 | req.connection.socket.remoteAddress; 8 | }; 9 | 10 | function getIpLocation(ip,callback) { 11 | http.get('http://ip.taobao.com/service/getIpInfo.php?ip='+ip,function(req,res){ 12 | var html=''; 13 | req.on('data',function(data){ 14 | html+=data; 15 | }); 16 | req.on('end',function(){ 17 | console.info(html); 18 | var json = JSON.parse(html); 19 | if(json.code == 0){ 20 | return callback(null,json.data.region + json.data.city); 21 | }else{ 22 | return callback(json.data,null); 23 | } 24 | 25 | }); 26 | }); 27 | } 28 | 29 | exports.getClientIp = getClientIp; 30 | exports.getIpLocation = getIpLocation; -------------------------------------------------------------------------------- /public/layui/css/modules/code.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none} -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var AppConfig = require('../config'); 4 | var qiniu = require('qiniu'); 5 | 6 | router.get('/', function(req, res, next) { 7 | res.render('./server/index'); 8 | }); 9 | 10 | router.get('/admin', function(req, res, next) { 11 | res.render('./server/index'); 12 | }); 13 | 14 | router.get('/client', function(req, res, next) { 15 | res.render('./client/index'); 16 | }); 17 | 18 | router.get('/admin/users', function(req, res, next) { 19 | res.render('./server/users'); 20 | }); 21 | 22 | router.get('/admin/setup', function(req, res, next) { 23 | res.render('./server/setup'); 24 | }); 25 | 26 | router.get('/uptoken', function(req, res, next) { 27 | var mac = new qiniu.auth.digest.Mac(AppConfig.QINIU.accessKey, AppConfig.QINIU.secretKey); 28 | var options = { 29 | scope: 'kefu', 30 | expires: 7200, 31 | mimeLimit:"image/*" 32 | }; 33 | var putPolicy = new qiniu.rs.PutPolicy(options); 34 | var uploadToken=putPolicy.uploadToken(mac); 35 | res.send({"uptoken":uploadToken}); 36 | }); 37 | 38 | module.exports = router; 39 | -------------------------------------------------------------------------------- /public/layui/lay/modules/code.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
  1. '+o.replace(/[\r\t\n]+/g,"
  2. ")+"
"),c.find(">.layui-code-h3")[0]||c.prepend('

'+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); -------------------------------------------------------------------------------- /public/js/common.js: -------------------------------------------------------------------------------- 1 | //用于生成uuid 2 | function S4() { 3 | return (((1+Math.random())*0x10000)|0).toString(16).substring(1); 4 | } 5 | 6 | function guid() { 7 | return (S4()+S4()+"-"+S4()+S4()+S4()); 8 | } 9 | 10 | function dateFormat(fmt,date) { 11 | if(!fmt){ 12 | fmt = "yyyy-MM-dd hh:mm:ss"; 13 | } 14 | if(!date){ 15 | date = new Date(); 16 | } 17 | var o = { 18 | "M+": date.getMonth() + 1, //月份 19 | "d+": date.getDate(), //日 20 | "h+": date.getHours(), //小时 21 | "m+": date.getMinutes(), //分 22 | "s+": date.getSeconds(), //秒 23 | "q+": Math.floor((date.getMonth() + 3) / 3), //季度 24 | "S": date.getMilliseconds() //毫秒 25 | }; 26 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); 27 | for (var k in o) 28 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 29 | return fmt; 30 | } 31 | 32 | function arrayRemove(array,val) { 33 | var index = array.indexOf(val); 34 | if (index > -1) { 35 | array.splice(index, 1); 36 | } 37 | }; -------------------------------------------------------------------------------- /model/message.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('../utils/mongoose').mongoose; 2 | 3 | var Schema = mongoose.Schema; 4 | 5 | var MessageSchema = new Schema({ 6 | from_uid : { type:String ,index: true}, 7 | to_uid : { type:String ,index: true}, 8 | content : { type:String }, 9 | chat_type : { type:String,default:'text'}, 10 | image : { type:String,default:''}, 11 | time : { type:Date, default:Date.now } 12 | }); 13 | 14 | var MessageModel = mongoose.model("message", MessageSchema); 15 | 16 | function add(from_uid,to_uid,content,chat_type,image,callback) { 17 | var info = { 18 | "from_uid" : from_uid, 19 | "to_uid" : to_uid, 20 | "content" : content, 21 | "chat_type" : chat_type, 22 | "image" : image, 23 | }; 24 | var msgModel = new MessageModel(info); 25 | msgModel.save(function(err, res){ 26 | return callback(err,res); 27 | }); 28 | } 29 | 30 | function query(page,size,uid,callback) { 31 | var query = MessageModel.find({}); 32 | var condition = []; 33 | if(uid){ 34 | condition.push({"from_uid":uid}); 35 | condition.push({"to_uid":uid}); 36 | } 37 | 38 | var skip = (page - 1) * size; 39 | query.or(condition).skip(skip).limit(size).sort({"time":-1}).exec(callback); 40 | } 41 | 42 | 43 | exports.add = add; 44 | exports.query = query; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var index = require('./routes/index'); 9 | var users = require('./routes/users'); 10 | var message = require('./routes/message'); 11 | 12 | var app = express(); 13 | 14 | // view engine setup 15 | app.set('views', path.join(__dirname, 'views')); 16 | app.set('view engine', 'ejs'); 17 | 18 | // uncomment after placing your favicon in /public 19 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 20 | app.use(logger('dev')); 21 | app.use(bodyParser.json()); 22 | app.use(bodyParser.urlencoded({ extended: false })); 23 | app.use(cookieParser()); 24 | app.use(express.static(path.join(__dirname, 'public'))); 25 | 26 | app.use('/', index); 27 | app.use('/users', users); 28 | app.use('/message', message); 29 | 30 | // catch 404 and forward to error handler 31 | app.use(function(req, res, next) { 32 | var err = new Error('Not Found'); 33 | err.status = 404; 34 | next(err); 35 | }); 36 | 37 | // error handler 38 | app.use(function(err, req, res, next) { 39 | // set locals, only providing error in development 40 | res.locals.message = err.message; 41 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 42 | 43 | // render the error page 44 | res.status(err.status || 500); 45 | res.render('error'); 46 | }); 47 | 48 | module.exports = app; 49 | -------------------------------------------------------------------------------- /model/users.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('../mongoose').mongoose; 2 | var crypto = require('crypto'); 3 | 4 | var Schema = mongoose.Schema; 5 | 6 | var UsersSchema = new Schema({ 7 | username : { type:String }, 8 | password : { type:String }, 9 | time : { type:Date, default:Date.now } 10 | }); 11 | 12 | var UsersModel = mongoose.model("users", UsersSchema); 13 | 14 | function login(username,password,callback) { 15 | var md5 = crypto.createHash('md5'); 16 | password = md5.update(password).digest('hex'); 17 | var condition = {'username' : username,'password':password}; 18 | 19 | UsersModel.findOne(condition, function(err, res){ 20 | var _err = null; 21 | if (err) { 22 | _err = err; 23 | } 24 | if(!res){ 25 | _err = '用户名密码不正确'; 26 | } 27 | return callback(_err,res); 28 | }) 29 | } 30 | 31 | function reset_psw(username,psw_old,psw_new,callback) { 32 | psw_old = crypto.createHash('md5').update(psw_old).digest('hex'); 33 | UsersModel.find({username:username,password:psw_old},function (err,info) { 34 | if (err) { 35 | return callback(err,null); 36 | } 37 | 38 | if(!info || info.length == 0){ 39 | return callback('原密码不正确',null); 40 | } 41 | psw_new = crypto.createHash('md5').update(psw_new).digest('hex'); 42 | UsersModel.findOneAndUpdate({username:username,password:psw_old}, {password:psw_new}, callback); 43 | }); 44 | } 45 | 46 | exports.login = login; 47 | exports.reset_psw = reset_psw; -------------------------------------------------------------------------------- /public/layui/lay/modules/laytpl.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},n={exp:function(e){return new RegExp(e,"g")},query:function(e,n,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return c((n||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var n="Laytpl Error:";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e}},c=n.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=c("^"+r.open+"#",""),l=c(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(c(r.open+"#"),r.open+"# ").replace(c(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(/(?="|')/g,"\\").replace(n.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(n.query(1),function(e){var n='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(c(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),n='"+_escape_('),n+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,n.escape)}catch(u){return delete o.cache,n.error(u,p)}},t.pt.render=function(e,r){var c,t=this;return e?(c=t.cache?t.cache(e,n.escape):t.parse(t.tpl,e),r?void r(c):c):n.error("no data")};var o=function(e){return"string"!=typeof e?n.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var n in e)r[n]=e[n]},o.v="1.2.0",e("laytpl",o)}); -------------------------------------------------------------------------------- /public/layui/lay/modules/util.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var o=layui.$,t={fixbar:function(e){var t,a,i="layui-fixbar",l="layui-fixbar-top",r=o(document),c=o("body");e=o.extend({showHeight:200},e),e.bar1=e.bar1===!0?"":e.bar1,e.bar2=e.bar2===!0?"":e.bar2,e.bgcolor=e.bgcolor?"background-color:"+e.bgcolor:"";var n=[e.bar1,e.bar2,""],u=o(['"].join("")),s=u.find("."+l),b=function(){var o=r.scrollTop();o>=e.showHeight?t||(s.show(),t=1):t&&(s.hide(),t=0)};o("."+i)[0]||("object"==typeof e.css&&u.css(e.css),c.append(u),b(),u.find("li").on("click",function(){var t=o(this),a=t.attr("lay-type");"top"===a&&o("html,body").animate({scrollTop:0},200),e.click&&e.click.call(this,a)}),r.on("scroll",function(){clearTimeout(a),a=setTimeout(function(){b()},100)}))},countdown:function(e,o,t){var a=this,i="function"==typeof o,l=new Date(e).getTime(),r=new Date(!o||i?(new Date).getTime():o).getTime(),c=l-r,n=[Math.floor(c/864e5),Math.floor(c/36e5)%24,Math.floor(c/6e4)%60,Math.floor(c/1e3)%60];i&&(t=o);var u=setTimeout(function(){a.countdown(e,r+1e3,t)},1e3);return t&&t(c>0?n:[0,0,0,0],o,u),c<=0&&clearTimeout(u),u},timeAgo:function(e,o){var t=(new Date).getTime()-new Date(e).getTime();return t>2592e6?(t=new Date(e).toLocaleString(),o&&(t=t.replace(/\s[\S]+$/g,"")),t):t>=864e5?(t/1e3/60/60/24|0)+"天前":t>=36e5?(t/1e3/60/60|0)+"小时前":t>=18e4?(t/1e3/60|0)+"分钟前":t<0?"未来":"刚刚"}};e("util",t)}); -------------------------------------------------------------------------------- /views/server/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 客服系统 7 | 8 | 59 | 60 | 61 | 66 | 67 | -------------------------------------------------------------------------------- /utils/redis.js: -------------------------------------------------------------------------------- 1 | var redisSvc = {}; 2 | var redis = require("redis"); 3 | 4 | if(!client){ 5 | var client = redis.createClient(); 6 | } 7 | 8 | client.on("error", function (err) { 9 | console.log("Redis Error :" , err); 10 | client = null; 11 | }); 12 | 13 | client.on('connect', function(){ 14 | console.log('Redis连接成功.'); 15 | }); 16 | 17 | /** 18 | * 添加string类型的数据 19 | * @param key 键 20 | * @params value 值 21 | * @params expire (过期时间,单位秒;可为空,为空表示不过期) 22 | * @param callBack(err,result) 23 | */ 24 | redisSvc.set = function(key, value, expire, callback){ 25 | 26 | client.set(key, value, function(err, result){ 27 | 28 | if (err) { 29 | console.log(err); 30 | callback(err,null); 31 | return; 32 | } 33 | 34 | if (!isNaN(expire) && expire > 0) { 35 | client.expire(key, parseInt(expire)); 36 | } 37 | 38 | callback(null,result) 39 | }) 40 | }; 41 | 42 | /** 43 | * 查询string类型的数据 44 | * @param key 键 45 | * @param callBack(err,result) 46 | */ 47 | redisSvc.get = function(key, callback){ 48 | 49 | client.get(key, function(err,result){ 50 | 51 | if (err) { 52 | console.log(err); 53 | callback(err,null); 54 | return; 55 | } 56 | 57 | callback(null,result); 58 | }); 59 | }; 60 | 61 | /* 62 | *删除String 类型的key 63 | * @param key 键 64 | * @param callBack(err,result) 65 | */ 66 | redisSvc.del = function(key, callback){ 67 | 68 | client.del(key, function(err,result){ 69 | 70 | if (err) { 71 | console.log(err); 72 | callback(err,null); 73 | return; 74 | } 75 | 76 | callback(null,result); 77 | }); 78 | }; 79 | 80 | 81 | module.exports = redisSvc; -------------------------------------------------------------------------------- /public/layui/lay/modules/flow.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('
'+d+"
");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)}); -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('kefu:server'); 9 | var http = require('http'); 10 | 11 | var ioSvc = require('../io/io'); 12 | /** 13 | * Get port from environment and store in Express. 14 | */ 15 | 16 | var port = normalizePort(process.env.PORT || '9010'); 17 | app.set('port', port); 18 | 19 | /** 20 | * Create HTTP server. 21 | */ 22 | 23 | var server = http.createServer(app); 24 | var io = require('socket.io')(server); 25 | ioSvc.ioServer(io); 26 | 27 | /** 28 | * Listen on provided port, on all network interfaces. 29 | */ 30 | 31 | server.listen(port); 32 | server.on('error', onError); 33 | server.on('listening', onListening); 34 | 35 | /** 36 | * Normalize a port into a number, string, or false. 37 | */ 38 | 39 | function normalizePort(val) { 40 | var port = parseInt(val, 10); 41 | 42 | if (isNaN(port)) { 43 | // named pipe 44 | return val; 45 | } 46 | 47 | if (port >= 0) { 48 | // port number 49 | return port; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | /** 56 | * Event listener for HTTP server "error" event. 57 | */ 58 | 59 | function onError(error) { 60 | if (error.syscall !== 'listen') { 61 | throw error; 62 | } 63 | 64 | var bind = typeof port === 'string' 65 | ? 'Pipe ' + port 66 | : 'Port ' + port; 67 | 68 | // handle specific listen errors with friendly messages 69 | switch (error.code) { 70 | case 'EACCES': 71 | console.error(bind + ' requires elevated privileges'); 72 | process.exit(1); 73 | break; 74 | case 'EADDRINUSE': 75 | console.error(bind + ' is already in use'); 76 | process.exit(1); 77 | break; 78 | default: 79 | throw error; 80 | } 81 | } 82 | 83 | /** 84 | * Event listener for HTTP server "listening" event. 85 | */ 86 | 87 | function onListening() { 88 | var addr = server.address(); 89 | var bind = typeof addr === 'string' 90 | ? 'pipe ' + addr 91 | : 'port ' + addr.port; 92 | debug('Listening on ' + bind); 93 | } 94 | -------------------------------------------------------------------------------- /views/server/index.ejs: -------------------------------------------------------------------------------- 1 | <% include header.ejs %> 2 | 3 |
4 |
5 |
6 | 0人 7 | 我的对话 8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 |
从左侧列表打开对话
18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 |
发送
28 |
29 |
30 |
31 |
    32 |
  • 😁
  • 33 |
  • 😂
  • 34 |
  • 😃
  • 35 |
  • 😄
  • 36 |
  • 😅
  • 37 |
  • 😆
  • 38 |
  • 😇
  • 39 |
  • 😈
  • 40 |
  • 😉
  • 41 |
  • 😊
  • 42 |
  • 😋
  • 43 |
  • 😌
  • 44 |
45 |
46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | <% include footer.ejs %> -------------------------------------------------------------------------------- /public/layui/lay/modules/tree.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var o=layui.$,a=layui.hint(),i="layui-tree-enter",r=function(e){this.options=e},t={arrow:["",""],checkbox:["",""],radio:["",""],branch:["",""],leaf:""};r.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},r.prototype.tree=function(e,a){var i=this,r=i.options,n=a||r.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o(''),s=o(["
  • ",function(){return l?''+(n.spread?t.arrow[1]:t.arrow[0])+"":""}(),function(){return r.check?''+("checkbox"===r.check?t.checkbox[0]:"radio"===r.check?t.radio[0]:"")+"":""}(),function(){return'"+(''+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"")+(""+(n.name||"未命名")+"")}(),"
  • "].join(""));l&&(s.append(c),i.tree(c,n.children)),e.append(s),"function"==typeof r.click&&i.click(s,n),i.spread(s,n),r.drag&&i.drag(s,n)})},r.prototype.click=function(e,o){var a=this,i=a.options;e.children("a").on("click",function(e){layui.stope(e),i.click(o)})},r.prototype.spread=function(e,o){var a=this,i=(a.options,e.children(".layui-tree-spread")),r=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),r.removeClass("layui-show"),i.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),r.addClass("layui-show"),i.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};r[0]&&(i.on("click",l),n.on("dblclick",l))},r.prototype.on=function(e){var a=this,r=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),r.drag&&o(document).on("mousemove",function(e){var i=a.move;if(i.from){var r=(i.to,o('
    '));e.preventDefault(),o("."+t)[0]||o("body").append(r);var n=o("."+t)[0]?o("."+t):r;n.addClass("layui-show").html(i.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(i),e.to&&e.to.elem.children("a").removeClass(i),a.move={},o("."+t).remove())})},r.prototype.move={},r.prototype.drag=function(e,a){var r=this,t=(r.options,e.children("a")),n=function(){var t=o(this),n=r.move;n.from&&(n.to={item:a,elem:e},t.addClass(i))};t.on("mousedown",function(){var o=r.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=r.move;a.from&&(delete a.to,e.removeClass(i))})},e("tree",function(e){var i=new r(e=e||{}),t=o(e.elem);return t[0]?void i.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})}); -------------------------------------------------------------------------------- /public/layui/lay/modules/carousel.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.indicator(),e.elemItem.length<=1||(e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['
    "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a 2 | 3 | 4 | 5 | 6 | 客服系统 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
    19 |
    20 | 21 |
    22 | 23 |

    客服系统

    24 |
    25 | 26 |
    27 |
    28 | 29 |
    30 | 31 |
    32 |
    33 |
    34 | 35 | 36 |
    37 |
    38 | 39 | 发送 40 |
    41 |
    42 |
    43 |
    44 |
      45 |
    • 😁
    • 46 |
    • 😂
    • 47 |
    • 😃
    • 48 |
    • 😄
    • 49 |
    • 😅
    • 50 |
    • 😆
    • 51 |
    • 😇
    • 52 |
    • 😈
    • 53 |
    • 😉
    • 54 |
    • 😊
    • 55 |
    • 😋
    • 56 |
    • 😌
    • 57 |
    58 |
    59 |
    60 |
    61 |
    62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /public/css/server.css: -------------------------------------------------------------------------------- 1 | .friend { 2 | position: relative; 3 | float: left; 4 | width: 300px; 5 | height: 100%; 6 | background: #fbfcfe; 7 | border-right: 1px solid #e9e9e9; 8 | } 9 | 10 | .chat { 11 | position: relative; 12 | float: left; 13 | width: calc(100% - 301px); 14 | height: 100%; 15 | } 16 | 17 | .friend-head { 18 | display: block; 19 | cursor: pointer; 20 | height: 51px; 21 | padding: 0 12px; 22 | font-size: 15px; 23 | line-height: 50px; 24 | color: #767d85; 25 | background-color: #fff; 26 | border-top: 1px solid #e9e9e9; 27 | border-bottom: 1px solid #e9e9e9; 28 | } 29 | 30 | .friend-head-right { 31 | float: right; 32 | } 33 | 34 | .message-agent,.message-client{ 35 | overflow: auto; 36 | margin-bottom: 10px; 37 | margin-top: 10px; 38 | } 39 | 40 | .message-container{ 41 | padding: 0 20px 0 20px; 42 | overflow: auto; 43 | } 44 | 45 | .message-time-sender{ 46 | line-height: 1; 47 | margin-bottom: 5px; 48 | font-size: 12px; 49 | color: #adb2bb; 50 | } 51 | 52 | .message-agent-time-sender{ 53 | text-align: right; 54 | } 55 | 56 | .message-content{ 57 | border-radius: 3px; 58 | padding: 8px 12px; 59 | font-size: 13px; 60 | line-height: 22px; 61 | word-wrap: break-word; 62 | word-break: break-all; 63 | border: 1px dashed transparent; 64 | } 65 | 66 | .message-agent-content{ 67 | position: relative; 68 | float: right; 69 | background-color: #f0f1f3; 70 | color: #161e26; 71 | } 72 | .message-client-content{ 73 | position: relative; 74 | float: left ; 75 | background-color: #e7f4ff; 76 | color: #161e26; 77 | } 78 | 79 | .message-sender{ 80 | position: absolute; 81 | bottom: 0; 82 | height: 180px; 83 | border-top: 1px solid #e9e9e9; 84 | width: 100%; 85 | 86 | } 87 | 88 | .sender-editor{ 89 | height: calc(100% - 40px); 90 | } 91 | 92 | .message-sender textarea{ 93 | resize: none; 94 | border: none; 95 | border-radius: 6px; 96 | font-size: 15px; 97 | color: #161e26; 98 | line-height: 22px; 99 | background-color: #fff; 100 | height: calc(100% - 40px); 101 | padding: 20px; 102 | width: calc(100% - 40px); 103 | } 104 | 105 | .btnMsgSend{ 106 | z-index: 1; 107 | position: absolute; 108 | right: 15px; 109 | bottom: 15px; 110 | } 111 | 112 | .user-info{ 113 | height: 60px; 114 | background: #ffffff; 115 | line-height: 60px; 116 | font-size: 16px; 117 | color: #767d85; 118 | border-bottom: 1px solid #e9e9e9; 119 | } 120 | 121 | .chat-user{ 122 | overflow: auto; 123 | } 124 | 125 | .user-info img{ 126 | width: 50px; 127 | } 128 | 129 | .user-info .user-avatar{ 130 | text-align: center; 131 | } 132 | 133 | .user-info .user-name{ 134 | font-size: 12px; 135 | } 136 | 137 | .empty-status{ 138 | width: 150px; 139 | margin: 0 auto; 140 | text-align: center; 141 | margin-top: 200px; 142 | } 143 | 144 | .empty-status img{ 145 | width: 100px; 146 | } 147 | 148 | .msg-tips{ 149 | margin-top: 25px; 150 | display: none; 151 | } 152 | 153 | .msg-client-img{ 154 | text-align: left; 155 | } 156 | 157 | .msg-client-img img{ 158 | width: 10rem; 159 | } 160 | 161 | .msg-agent-img{ 162 | text-align: right; 163 | } 164 | 165 | .msg-agent-img img{ 166 | width: 10rem; 167 | } 168 | 169 | .layui-icon{ 170 | cursor: pointer; 171 | } 172 | 173 | .message-emoji-picture{ 174 | height: 40px; 175 | line-height: 40px; 176 | padding-left: 20px; 177 | } 178 | 179 | .emoji-list{ 180 | display: none; 181 | position: fixed; 182 | left: 300px; 183 | bottom:230px; 184 | border: solid 1px #e9e9e9; 185 | border-radius: 3px; 186 | box-shadow: 0 15px 30px 0 rgba(52,63,75,.2); 187 | background: #fff; 188 | } 189 | 190 | .emoji-list ul{ 191 | overflow: auto; 192 | } 193 | 194 | .emoji-list li{ 195 | float: left; 196 | width: 30px; 197 | cursor: pointer; 198 | height: 30px; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /public/layui/lay/modules/laypage.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),skip:function(){return['到第','','页',""].join("")}()};return['
    ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
    "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)}); -------------------------------------------------------------------------------- /public/css/client.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | 10 | .page-current{ 11 | background: #ffffff; 12 | } 13 | 14 | .msg-box { 15 | margin-bottom: 10px; 16 | margin-top: 10px; 17 | } 18 | 19 | .msg-agent, .msg-bot, .msg-client { 20 | position: relative; 21 | width: 100%; 22 | padding-left: 50px; 23 | } 24 | 25 | .msg-agent .agent-avatar,.msg-bot .agent-avatar { 26 | position: absolute; 27 | top: 18px; 28 | left: 0; 29 | } 30 | 31 | .msg-client .date { 32 | margin-bottom: 2px; 33 | font-size: 12px; 34 | line-height: 14px; 35 | color: #b2b2b2; 36 | width: 100%; 37 | text-align: right; 38 | } 39 | 40 | .msg-client .bubble, .msg-client .photo { 41 | float: right; 42 | width: auto; 43 | max-width: 100%; 44 | margin-left: 35px; 45 | } 46 | 47 | .msg-agent .bubble, .msg-bot .bubble, .msg-client .bubble { 48 | position: relative; 49 | padding: 8px 12px; 50 | font-size: 13px; 51 | line-height: 20px; 52 | border-radius: 4px; 53 | word-wrap: break-word; 54 | } 55 | 56 | .msg-client .arrow { 57 | top: 14px; 58 | right: -6px; 59 | border-top: 5px solid transparent; 60 | border-bottom: 5px solid transparent; 61 | border-left: 6px solid #007aff; 62 | } 63 | 64 | .msg-agent .arrow, .msg-agent .arrow-bg, .msg-bot .arrow, .msg-bot .arrow-bg, .msg-client .arrow, .msg-client .arrow-bg { 65 | position: absolute; 66 | display: block; 67 | width: 0; 68 | height: 0; 69 | font-size: 0; 70 | } 71 | 72 | .msg-client .status { 73 | position: absolute; 74 | left: -25px; 75 | top: 8px; 76 | } 77 | 78 | .msg-agent:after, .msg-bot:after, .msg-client:after, .evaluation-body .evaluation-btn-group:after { 79 | display: block; 80 | clear: both; 81 | content: ''; 82 | } 83 | 84 | .msg-client .bubble { 85 | background-color: #007aff; 86 | color: #fff; 87 | } 88 | 89 | .msg-agent .date,.msg-bot .date { 90 | margin-bottom: 2px; 91 | font-size: 12px; 92 | line-height: 14px; 93 | color: #b2b2b2; 94 | text-align: left; 95 | } 96 | 97 | .msg-agent .bubble,.msg-bot .bubble { 98 | color: #000; 99 | background-color: #fff; 100 | border-left: 1px solid #f0f0f0; 101 | } 102 | 103 | .msg-agent .agent-avatar, .msg-bot .agent-avatar { 104 | position: absolute; 105 | top: 18px; 106 | left: 0; 107 | } 108 | 109 | .msg-agent .agent-avatar>img,.msg-bot .agent-avatar>img { 110 | width: 36px; 111 | height: 36px; 112 | margin-top: 1px; 113 | border-radius: 18px; 114 | } 115 | 116 | .msg-agent .arrow-bg,.msg-bot .arrow-bg { 117 | top: 13px; 118 | left: -7px; 119 | border-top: 6px solid transparent; 120 | border-bottom: 6px solid transparent; 121 | border-right: 7px solid #f0f0f0; 122 | } 123 | 124 | .msg-agent .arrow,.msg-bot .arrow { 125 | top: 14px; 126 | left: -6px; 127 | border-top: 5px solid transparent; 128 | border-bottom: 5px solid transparent; 129 | border-right: 6px solid #fff; 130 | } 131 | 132 | *, :after, :before { 133 | box-sizing: border-box; 134 | outline: none; 135 | } 136 | 137 | .footer { 138 | position: absolute; 139 | right: 0; 140 | bottom: 0; 141 | left: 0; 142 | z-index: 2; 143 | width: 100%; 144 | height: 2.5rem; 145 | background-color: #fff; 146 | box-shadow: 0 -1px 0 0 rgba(0,0,0,.04), 0 -2px 0 0 rgba(0,0,0,.01); 147 | } 148 | 149 | .input-holder { 150 | position: relative; 151 | height: 50px; 152 | } 153 | 154 | .footer .input-holder .feature-holder { 155 | float: left; 156 | padding-left: 4px; 157 | } 158 | 159 | .footer .input-holder .text-holder { 160 | float: left; 161 | width: calc(100% - 3rem); 162 | position: relative; 163 | padding-right: 50px; 164 | padding-left: 4px; 165 | overflow: hidden; 166 | zoom: 1; 167 | height: 100%; 168 | } 169 | 170 | .footer .input-holder .text-holder #textarea { 171 | display: block; 172 | width: 100%; 173 | height: 100%; 174 | padding: 15px; 175 | overflow-x: hidden; 176 | overflow-y: auto; 177 | resize: none; 178 | vertical-align: middle; 179 | outline: 0; 180 | border: 0; 181 | word-break: break-all; 182 | font-size: 14px; 183 | -webkit-appearance: none; 184 | -moz-appearance: none; 185 | appearance: none; 186 | } 187 | 188 | .footer .input-holder .text-holder #btnSend { 189 | position: absolute; 190 | top: 3px; 191 | right: 2px; 192 | width: 46px; 193 | height: 44px; 194 | text-align: center; 195 | line-height: 44px; 196 | font-size: 14px; 197 | color: #858e99; 198 | cursor: pointer; 199 | } 200 | 201 | .msg-container{ 202 | overflow: auto; 203 | height: calc(100% - 2.5rem); 204 | } 205 | .content-block { 206 | margin: 0; 207 | } 208 | 209 | .emoji-image{ 210 | float: left; 211 | width: 3rem; 212 | text-align: center; 213 | margin-top: 0.85rem; 214 | } 215 | 216 | .emoji-image .icon{ 217 | width: 1.2rem; 218 | height: 1.2rem; 219 | } 220 | 221 | .msg-client-img{ 222 | text-align: right; 223 | } 224 | 225 | .msg-client-img img{ 226 | width: 10rem; 227 | } 228 | 229 | .msg-agent-img{ 230 | text-align: left; 231 | } 232 | 233 | .msg-agent-img img{ 234 | width: 10rem; 235 | } 236 | 237 | .emoji-list{ 238 | display: none; 239 | position: fixed; 240 | border-top: solid 1px #e9e9e9; 241 | background: #fff; 242 | bottom: 50px; 243 | width: 100%; 244 | } 245 | 246 | .emoji-list ul{ 247 | overflow: auto; 248 | padding-left: 0.5rem; 249 | } 250 | 251 | .emoji-list li{ 252 | list-style-type:none; 253 | float: left; 254 | width: 30px; 255 | cursor: pointer; 256 | height: 30px; 257 | } 258 | 259 | -------------------------------------------------------------------------------- /public/layui/layui.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.1.5"},r=function(){var e=t.scripts,o=e[e.length-1].src;return o.substring(0,o.lastIndexOf("/")+1)}(),a=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},i="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",tree:"modules/tree",table:"modules/table",element:"modules/element",util:"modules/util",flow:"modules/flow",carousel:"modules/carousel",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,a=function(){return"function"==typeof t&&t(function(e,t){layui[e]=t,o.status[e]=!0}),this};return r&&(t=e,e=[]),layui["layui.all"]||!layui["layui.all"]&&layui["layui.mobile"]?a.call(n):(n.use(e,a),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?a(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?a(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":o.base||"")+(y.modules[f]||f)+".js";v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||i?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var i=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?i:(function p(){return++y>1e3*o.timeout/100?a(e+" timeout"):void(1989===parseInt(i.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),i)},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?a("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,"").replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o){if(t=t||"layui",e.JSON&&e.JSON.parse){if(null===o)return delete localStorage[t];o="object"==typeof o?o:{key:o};try{var n=JSON.parse(localStorage[t])}catch(r){var n={}}return o.value&&(n[o.key]=o.value),o.remove&&delete n[o.key],localStorage[t]=JSON.stringify(n),o.key?n[o.key]:n}},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:a}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oa?1:r"].join("")),o=t.elem.next();(o.hasClass(u)||o.hasClass(c))&&o.remove(),a.ie&&a.ie<10&&t.elem.wrap('
    '),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(n),a.ie&&a.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,t=e.config,n=i(''),a=i(['
    ',"
    "].join(""));i("#"+s)[0]||i("body").append(n),t.elem.next().hasClass(s)||(e.elemFile.wrap(a),t.elem.next("."+s).append(function(){var e=[];return layui.each(t.data,function(i,t){e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var i=this;window.FileReader&&layui.each(i.chooseFiles,function(i,t){var n=new FileReader;n.readAsDataURL(t),n.onload=function(){e&&e(i,t,this.result)}})},p.prototype.upload=function(e,t){var n,o=this,l=o.config,r=o.elemFile[0],u=function(){layui.each(e||o.files||o.chooseFiles||r.files,function(e,t){var n=new FormData;n.append(l.field,t),layui.each(l.data,function(e,i){n.append(e,i)}),i.ajax({url:l.url,type:l.method,data:n,contentType:!1,processData:!1,dataType:"json",success:function(i){d(e,i)},error:function(){o.msg("请求上传接口出现异常"),m(e)}})})},c=function(){var e=i("#"+s);o.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var i,t=e.contents().find("body");try{i=t.text()}catch(n){o.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}i&&(clearInterval(p.timer),t.html(""),d(0,i))},30)},d=function(e,i){if(o.elemFile.next("."+f).remove(),r.value="","object"!=typeof i)try{i=JSON.parse(i)}catch(t){return i={},o.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(i,e||0,function(e){o.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){o.upload(e)})},v=l.exts,h=function(){var i=[];return layui.each(e||o.chooseFiles,function(e,t){i.push(t.name)}),i}(),g={preview:function(e){o.preview(e)},upload:function(e,i){var t={};t[e]=i,o.upload(t)},pushFile:function(){return o.files=o.files||{},layui.each(o.chooseFiles,function(e,i){o.files[e]=i}),o.files}},y=function(){return"choose"===t?l.choose&&l.choose(g):(l.before&&l.before(g),a.ie?a.ie>9?u():c():void u())};switch(h=0===h.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":h,l.accept){case"file":if(v&&!RegExp("\\w\\.("+v+")$","i").test(escape(h)))return o.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(v||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(h)))return o.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(v||"mp3|wav|mid")+")$","i").test(escape(h)))return o.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(h,function(e,i){RegExp("\\w\\.("+(v||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(i))||(n=!0)}),n)return o.msg("选择的图片中包含不支持的格式"),r.value=""}if(l.size>0&&!(a.ie&&a.ie<10)){var F;if(layui.each(o.chooseFiles,function(e,i){if(i.size>1024*l.size){var t=l.size/1024;t=t>=1?Math.floor(t)+(t%1>0?t.toFixed(1):0)+"MB":l.size+"KB",r.value="",F=t}}),F)return o.msg("文件不能超过"+F)}y()},p.prototype.events=function(){var e=this,t=e.config,o=function(i){e.chooseFiles={},layui.each(i,function(i,t){var n=(new Date).getTime();e.chooseFiles[n+"-"+i]=t})},l=function(i,n){var a=e.elemFile,o=i.length>1?i.length+"个文件":(i[0]||{}).name||a[0].value.match(/[^\/\\]+\..+/g)||[]||"";a.next().hasClass(f)&&a.next().remove(),e.upload(null,"choose"),e.isFile()||t.choose||a.after(''+o+"")};t.elem.off("upload.start").on("upload.start",function(){var a=i(this),o=a.attr("lay-data");if(o)try{o=new Function("return "+o)(),e.config=i.extend({},t,o)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+o)}e.config.item=a,e.elemFile[0].click()}),a.ie&&a.ie<10||t.elem.off("upload.over").on("upload.over",function(){var e=i(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=i(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,a){var r=i(this),u=a.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),o(u),t.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var i=this.files||[];o(i),t.auto?e.upload():l(i)}),t.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),t.elem.data("haveEvents")||(e.elemFile.on("change",function(){i(this).trigger("upload.change")}),t.elem.on("click",function(){e.isFile()||i(this).trigger("upload.start")}),t.drag&&t.elem.on("dragover",function(e){e.preventDefault(),i(this).trigger("upload.over")}).on("dragleave",function(e){i(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),i(this).trigger("upload.drop",e)}),t.bindAction.on("click",function(){i(this).trigger("upload.action")}),t.elem.data("haveEvents",!0))},o.render=function(e){var i=new p(e);return l.call(i)},e(r,o)}); -------------------------------------------------------------------------------- /public/layui/lay/modules/element.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("jquery",function(i){"use strict";var a=layui.$,t=(layui.hint(),layui.device()),l="element",e="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(i){var t=this;return a.extend(!0,t.config,i),t},s.prototype.on=function(i,a){return layui.onevent.call(this,l,i,a)},s.prototype.tabAdd=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.children(".layui-tab-bar"),o=e.children(".layui-tab-content"),c='
  • '+(t.title||"unnaming")+"
  • ";return s[0]?s.before(c):n.append(c),o.append('
    '+(t.content||"")+"
    "),y.hideTabMore(!0),y.tabAuto(),this},s.prototype.tabDelete=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return y.tabDelete(null,s),this},s.prototype.tabChange=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return y.tabClick(null,null,s),this},s.prototype.progress=function(i,t){var l="layui-progress",e=a("."+l+"[lay-filter="+i+"]"),n=e.find("."+l+"-bar"),s=n.find("."+l+"-text");return n.css("width",t),s.text(t),this};var o=".layui-nav",c="layui-nav-item",r="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",h="layui-nav-more",f="layui-anim layui-anim-upbit",y={tabClick:function(i,t,s){var o=s||a(this),t=t||o.parent().children("li").index(o),c=o.parents(".layui-tab").eq(0),r=c.children(".layui-tab-content").children(".layui-tab-item"),u=o.find("a"),d=c.attr("lay-filter");"javascript:;"!==u.attr("href")&&"_blank"===u.attr("target")||(o.addClass(e).siblings().removeClass(e),r.eq(t).addClass(n).siblings().removeClass(n)),layui.event.call(this,l,"tab("+d+")",{elem:c,index:t})},tabDelete:function(i,t){var l=t||a(this).parent(),n=l.index(),s=l.parents(".layui-tab").eq(0),o=s.children(".layui-tab-content").children(".layui-tab-item");l.hasClass(e)&&(l.next()[0]?y.tabClick.call(l.next()[0],null,n+1):l.prev()[0]&&y.tabClick.call(l.prev()[0],null,n-1)),l.remove(),o.eq(n).remove(),setTimeout(function(){y.tabAuto()},50)},tabAuto:function(){var i="layui-tab-more",l="layui-tab-bar",e="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),c=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),r=a('');if(n===window&&8!=t.ie&&y.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var i=a(this);if(!i.find("."+e)[0]){var t=a('');t.on("click",y.tabDelete),i.append(t)}}),o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+l)[0])return;o.append(r),s.attr("overflow",""),r.on("click",function(a){o[this.title?"removeClass":"addClass"](i),this.title=this.title?"":"收缩"})}else o.find("."+l).remove(),s.removeAttr("overflow")})},hideTabMore:function(i){var t=a(".layui-tab-title");i!==!0&&"tabmore"===a(i.target).attr("lay-stope")||(t.removeClass("layui-tab-more"),t.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter"),s=i.find("a");i.find("."+d)[0]||("javascript:;"!==s.attr("href")&&"_blank"===s.attr("target")||(t.find("."+e).removeClass(e),i.addClass(e)),layui.event.call(this,l,"nav("+n+")",i))},clickChild:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter");t.find("."+e).removeClass(e),i.addClass(e),layui.event.call(this,l,"nav("+n+")",i)},showChild:function(){var i=a(this),t=i.parents(o),l=i.parent(),e=i.siblings("."+d);t.hasClass(u)&&(e.removeClass(f),l["none"===e.css("display")?"addClass":"removeClass"](c+"ed"))},collapse:function(){var i=a(this),t=i.find(".layui-colla-icon"),e=i.siblings(".layui-colla-content"),s=i.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),c="none"===e.css("display");if("string"==typeof s.attr("lay-accordion")){var r=s.children(".layui-colla-item").children("."+n);r.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),r.removeClass(n)}e[c?"addClass":"removeClass"](n),t.html(c?"":""),layui.event.call(this,l,"collapse("+o+")",{title:i,content:e,show:c})}};s.prototype.init=function(i){var l={tab:function(){y.tabAuto.call({})},nav:function(){var i=200,l={},e={},s={},p=function(o,c,r){var y=a(this),p=y.find("."+d);c.hasClass(u)?o.css({top:y.position().top,height:y.children("a").height(),opacity:1}):(p.addClass(f),o.css({left:y.position().left+parseFloat(y.css("marginLeft")),top:y.position().top+y.height()-5}),l[r]=setTimeout(function(){o.css({width:y.width(),opacity:1})},t.ie&&t.ie<10?0:i),clearTimeout(s[r]),"block"===p.css("display")&&clearTimeout(e[r]),e[r]=setTimeout(function(){p.addClass(n),y.find("."+h).addClass(h+"d")},300))};a(o).each(function(t){var o=a(this),f=a(''),v=o.find("."+c);o.find("."+r)[0]||(o.append(f),v.on("mouseenter",function(){p.call(this,f,o,t)}).on("mouseleave",function(){o.hasClass(u)||(clearTimeout(e[t]),e[t]=setTimeout(function(){o.find("."+d).removeClass(n),o.find("."+h).removeClass(h+"d")},300))}),o.on("mouseleave",function(){clearTimeout(l[t]),s[t]=setTimeout(function(){o.hasClass(u)?f.css({height:0,top:f.position().top+f.height()/2,opacity:0}):f.css({width:0,left:f.position().left+f.width()/2,opacity:0})},i)})),v.each(function(){var i=a(this),t=i.find("."+d);if(t[0]&&!i.find("."+h)[0]){var l=i.children("a");l.append('')}i.off("click",y.clickThis).on("click",y.clickThis),i.children("a").off("click",y.showChild).on("click",y.showChild),t.children("dd").off("click",y.clickChild).on("click",y.clickChild)})})},breadcrumb:function(){var i=".layui-breadcrumb";a(i).each(function(){var i=a(this),t=i.attr("lay-separator")||">",l=i.find("a");l.find(".layui-box")[0]||(l.each(function(i){i!==l.length-1&&a(this).append(''+t+"")}),i.css("visibility","visible"))})},progress:function(){var i="layui-progress";a("."+i).each(function(){var t=a(this),l=t.find(".layui-progress-bar"),e=l.attr("lay-percent");l.css("width",e),t.attr("lay-showPercent")&&setTimeout(function(){var a=Math.round(l.width()/t.width()*100);a>100&&(a=100),l.html(''+a+"%")},350)})},collapse:function(){var i="layui-collapse";a("."+i).each(function(){var i=a(this).find(".layui-colla-item");i.each(function(){var i=a(this),t=i.find(".layui-colla-title"),l=i.find(".layui-colla-content"),e="none"===l.css("display");t.find(".layui-colla-icon").remove(),t.append(''+(e?"":"")+""),t.off("click",y.collapse).on("click",y.collapse)})})}};return layui.each(l,function(i,a){a()})};var p=new s,v=a(document);p.init();var b=".layui-tab-title li";v.on("click",b,y.tabClick),v.on("click",y.hideTabMore),a(window).on("resize",y.tabAuto),i(l,p)}); -------------------------------------------------------------------------------- /public/layui/lay/modules/form.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define("layer",function(e){"use strict";var i=layui.$,t=layui.layer,a=layui.hint(),n=layui.device(),l="form",s=".layui-form",r="layui-this",u="layui-hide",c="layui-disabled",o=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:function(e){if(!e||isNaN(e))return"只能填写数字"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};o.prototype.set=function(e){var t=this;return i.extend(!0,t.config,e),t},o.prototype.verify=function(e){var t=this;return i.extend(!0,t.config.verify,e),t},o.prototype.on=function(e,i){return layui.onevent.call(this,l,e,i)},o.prototype.render=function(e,t){var n=this,o=i(s+function(){return t?'[lay-filter="'+t+'"]':""}()),d={select:function(){var e,t="请选择",a="layui-form-select",n="layui-select-title",s="layui-select-none",d="",f=o.find("select"),y=function(t,l){i(t.target).parent().hasClass(n)&&!l||(i("."+a).removeClass(a+"ed "+a+"up"),e&&d&&e.val(d)),e=null},h=function(t,o,f){var h=i(this),p=t.find("."+n),m=p.find("input"),k=t.find("dl"),g=k.children("dd");if(!o){var b=function(){var e=t.offset().top+t.outerHeight()+5-v.scrollTop(),i=k.outerHeight();t.addClass(a+"ed"),g.removeClass(u),e+i>v.height()&&e>=i&&t.addClass(a+"up")},x=function(e){t.removeClass(a+"ed "+a+"up"),m.blur(),e||C(m.val(),function(e){e&&(d=k.find("."+r).html(),m&&m.val(d))})};p.on("click",function(e){t.hasClass(a+"ed")?x():(y(e,!0),b()),k.find("."+s).remove()}),p.find(".layui-edge").on("click",function(){m.focus()}),m.on("keyup",function(e){var i=e.keyCode;9===i&&b()}).on("keydown",function(e){var i=e.keyCode;9===i?x():13===i&&e.preventDefault()});var C=function(e,t,a){var n=0;layui.each(g,function(){var t=i(this),l=t.text(),s=l.indexOf(e)===-1;(""===e||"blur"===a?e!==l:s)&&n++,"keyup"===a&&t[s?"addClass":"removeClass"](u)});var l=n===g.length;return t(l),l},w=function(e){var i=this.value,t=e.keyCode;return 9!==t&&13!==t&&37!==t&&38!==t&&39!==t&&40!==t&&(C(i,function(e){e?k.find("."+s)[0]||k.append('

    无匹配项

    '):k.find("."+s).remove()},"keyup"),void(""===i&&k.find("."+s).remove()))};f&&m.on("keyup",w).on("blur",function(i){e=m,d=k.find("."+r).html(),setTimeout(function(){C(m.val(),function(e){e&&!d&&m.val("")},"blur")},200)}),g.on("click",function(){var e=i(this),a=e.attr("lay-value"),n=h.attr("lay-filter");return!e.hasClass(c)&&(e.hasClass("layui-select-tips")?m.val(""):(m.val(e.text()),e.addClass(r)),e.siblings().removeClass(r),h.val(a).removeClass("layui-form-danger"),layui.event.call(this,l,"select("+n+")",{elem:h[0],value:a,othis:t}),x(!0),!1)}),t.find("dl>dt").on("click",function(e){return!1}),i(document).off("click",y).on("click",y)}};f.each(function(e,l){var s=i(this),u=s.next("."+a),o=this.disabled,d=l.value,f=i(l.options[l.selectedIndex]),y=l.options[0];if("string"==typeof s.attr("lay-ignore"))return s.show();var v="string"==typeof s.attr("lay-search"),p=y?y.value?t:y.innerHTML||t:t,m=i(['
    ','
    ','
    ','
    '+function(e){var i=[];return layui.each(e,function(e,a){0!==e||a.value?"optgroup"===a.tagName.toLowerCase()?i.push("
    "+a.label+"
    "):i.push('
    '+a.innerHTML+"
    "):i.push('
    '+(a.innerHTML||t)+"
    ")}),0===i.length&&i.push('
    没有选项
    '),i.join("")}(s.find("*"))+"
    ","
    "].join(""));u[0]&&u.remove(),s.after(m),h.call(this,m,o,v)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},t=o.find("input[type=checkbox]"),a=function(e,t){var a=i(this);e.on("click",function(){var i=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(t[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(t[1]).find("em").text(n[0])),layui.event.call(a[0],l,t[2]+"("+i+")",{elem:a[0],value:a[0].value,othis:e}))})};t.each(function(t,n){var l=i(this),s=l.attr("lay-skin"),r=(l.attr("lay-text")||"").split("|"),u=this.disabled;"switch"===s&&(s="_"+s);var o=e[s]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+o[0]),f=i(['
    ',{_switch:""+((n.checked?r[0]:r[1])||"")+""}[s]||(n.title.replace(/\s/g,"")?""+n.title+"":"")+''+(s?"":"")+"","
    "].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,o)})},radio:function(){var e="layui-form-radio",t=["",""],a=o.find("input[type=radio]"),n=function(a){var n=i(this),r="layui-anim-scaleSpring";a.on("click",function(){var u=n[0].name,c=n.parents(s),o=n.attr("lay-filter"),d=c.find("input[name="+u.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=i(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(r).html(t[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(r).html(t[0]),layui.event.call(n[0],l,"radio("+o+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var s=i(this),r=s.next("."+e),u=this.disabled;if("string"==typeof s.attr("lay-ignore"))return s.show();var o=i(['
    ',''+t[l.checked?0:1]+"",""+(l.title||"未命名")+"","
    "].join(""));r[0]&&r.remove(),s.after(o),n.call(this,o)})}};return e?d[e]?d[e]():a.error("不支持的"+e+"表单渲染"):layui.each(d,function(e,i){i()}),n};var d=function(){var e=i(this),a=f.config.verify,r=null,u="layui-form-danger",c={},o=e.parents(s),d=o.find("*[lay-verify]"),y=e.parents("form")[0],v=o.find("input,select,textarea"),h=e.attr("lay-filter");return layui.each(d,function(e,l){var s=i(this),c=s.attr("lay-verify").split("|"),o="",d=s.val();if(s.removeClass(u),layui.each(c,function(e,i){var c="function"==typeof a[i];if(a[i]&&(c?o=a[i](d,l):!a[i][0].test(d)))return t.msg(o||a[i][1],{icon:5,shift:6}),n.android||n.ios||l.focus(),s.addClass(u),r=!0}),r)return r}),!r&&(layui.each(v,function(e,i){i.name&&(/^checkbox|radio$/.test(i.type)&&!i.checked||(c[i.name]=i.value))}),layui.event.call(this,l,"submit("+h+")",{elem:this,form:y,field:c}))},f=new o,y=i(document),v=i(window);f.render(),y.on("reset",s,function(){var e=i(this).attr("lay-filter");setTimeout(function(){f.render(null,e)},50)}),y.on("submit",s,d).on("click","*[lay-submit]",d),e(l,f)}); -------------------------------------------------------------------------------- /public/layui/css/modules/laydate/default/laydate.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | .laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:laydate-upbit;animation-name:laydate-upbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@-webkit-keyframes laydate-upbit{from{-webkit-transform:translate3d(0,20px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes laydate-upbit{from{transform:translate3d(0,20px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-0 .laydate-next-m,.layui-laydate-range .laydate-main-list-0 .laydate-next-y,.layui-laydate-range .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#00F7DE}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eaeaea;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{color:#fff!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px} -------------------------------------------------------------------------------- /public/js/client/client.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | //Socket.IO 连接 3 | var socket = io.connect('http://'+document.domain+':9010',{ 4 | "transports":['websocket', 'polling'] 5 | }); 6 | var uuid = ''; 7 | 8 | function insert_client_html(msg){ 9 | var time = dateFormat(); 10 | if(msg.time){ 11 | time = dateFormat("yyyy-MM-dd hh:mm:ss",new Date(msg.time)); 12 | } 13 | if(!msg.chat_type){ 14 | msg.chat_type = 'text'; 15 | } 16 | var tpl = '
    '+ 17 | '
    '+ 18 | '
    ' + time + ' 我' + '
    '; 19 | 20 | if(msg.chat_type == "text"){ 21 | tpl += '
    '+ 22 | ''+ 23 | '
    ' + msg.content + '
    '+ 24 | ''+ 25 | '
    '; 26 | }else if(msg.chat_type == "image"){ 27 | tpl += '
    ' + 28 | ' ' + 29 | ' photo'+ 30 | ' ' + 31 | '
    '; 32 | } 33 | 34 | tpl += '
    '+ 35 | '
    '; 36 | $(".msg-container").append(tpl); 37 | } 38 | 39 | function insert_agent_html(msg){ 40 | var time = dateFormat(); 41 | if(msg.time){ 42 | time = dateFormat("yyyy-MM-dd hh:mm:ss",new Date(msg.time)); 43 | } 44 | if(!msg.chat_type){ 45 | msg.chat_type = 'text'; 46 | } 47 | var tpl = '
    '+ 48 | '
    '+ 49 | '
    '+ 50 | ''+ 51 | '
    '+ 52 | '
    ' + time + ' 客服' + '
    '; 53 | 54 | if(msg.chat_type == "text"){ 55 | tpl += '
    '+ 56 | ''+ 57 | ''+ 58 | '
    ' + msg.content + '
    '+ 59 | '
    '; 60 | }else if(msg.chat_type == "image"){ 61 | tpl += '
    ' + 62 | ' ' + 63 | ' photo'+ 64 | ' ' + 65 | '
    '; 66 | } 67 | tpl += '
    '+ 68 | '
    '; 69 | $(".msg-container").append(tpl); 70 | } 71 | 72 | //聊天窗口自动滚到底 73 | function scrollToBottom() { 74 | var div = document.getElementById('msg-container'); 75 | div.scrollTop = div.scrollHeight; 76 | } 77 | 78 | //获取最新的五条数据 79 | function get_message(uid) { 80 | $.get('/message?uid='+uid,function (data) { 81 | if(data.code == 200){ 82 | data.data.reverse().forEach(function (msg) { 83 | if(msg.from_uid == uid){ 84 | insert_client_html(msg); 85 | }else{ 86 | insert_agent_html(msg); 87 | } 88 | 89 | scrollToBottom(); 90 | }); 91 | } 92 | }); 93 | } 94 | 95 | 96 | $("#btnSend").click(function(){ 97 | var msg = $("#textarea").val(); 98 | if(msg){ 99 | var msg_sender = { 100 | "type":'private', 101 | "uid":'chat-kefu-admin', 102 | "content":msg, 103 | "from_uid":uuid, 104 | "chat_type":'text' 105 | }; 106 | socket.emit('message', msg_sender); 107 | insert_client_html(msg_sender); 108 | scrollToBottom(); 109 | $("#textarea").val(''); 110 | } 111 | }); 112 | 113 | $(".picture-upload").click(function () { 114 | var uploader = Qiniu.uploader({ 115 | runtimes: 'html5,flash,html4', // 上传模式,依次退化 116 | browse_button: 'pickfiles', // 上传选择的点选按钮,必需 117 | uptoken_url: '/uptoken', // Ajax请求uptoken的Url,强烈建议设置(服务端提供) 118 | get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的uptoken 119 | domain: 'http://kefuimg.chinameyer.com/', // bucket域名,下载资源时用到,必需 120 | container: 'btn-uploader', // 上传区域DOM ID,默认是browser_button的父元素 121 | max_file_size: '10mb', // 最大文件体积限制 122 | flash_swf_url: 'path/of/plupload/Moxie.swf', //引入flash,相对路径 123 | max_retries: 3, // 上传失败最大重试次数 124 | dragdrop: false, // 开启可拖曳上传 125 | drop_element: 'btn-uploader', // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传 126 | chunk_size: '4mb', // 分块上传时,每块的体积 127 | auto_start: true, // 选择文件后自动上传,若关闭需要自己绑定事件触发上传 128 | unique_names: true, 129 | filters : { 130 | max_file_size : '10mb', 131 | prevent_duplicates: true, 132 | // Specify what files to browse for 133 | mime_types: [ 134 | {title : "Image files", extensions : "jpg,gif,png,bmp"}, // 限定jpg,gif,png后缀上传 135 | ] 136 | }, 137 | init: { 138 | 'FilesAdded': function(up, files) { 139 | plupload.each(files, function(file) { 140 | // 文件添加进队列后,处理相关的事情 141 | }); 142 | }, 143 | 'BeforeUpload': function(up, file) { 144 | // 每个文件上传前,处理相关的事情 145 | }, 146 | 'UploadProgress': function(up, file) { 147 | // 每个文件上传时,处理相关的事情 148 | }, 149 | 'FileUploaded': function(up, file, info) { 150 | // 查看简单反馈 151 | var domain = up.getOption('domain'); 152 | var res = JSON.parse(info); 153 | var sourceLink = domain +"/"+ res.key; 154 | 155 | var msg_sender = { 156 | "type":'private', 157 | "uid":'chat-kefu-admin', 158 | "content":'图片消息', 159 | "from_uid":uuid, 160 | "chat_type":'image', 161 | "image":sourceLink 162 | }; 163 | socket.emit('message', msg_sender); 164 | insert_client_html(msg_sender); 165 | scrollToBottom(); 166 | 167 | 168 | }, 169 | 'Error': function(up, err, errTip) { 170 | //上传出错时,处理相关的事情 171 | $.toast("上传失败"); 172 | }, 173 | 'UploadComplete': function() { 174 | //队列文件处理完毕后,处理相关的事情 175 | } 176 | } 177 | }); 178 | 179 | }); 180 | 181 | $(".emoji-list li").click(function () { 182 | var content = $("#textarea").val(); 183 | $("#textarea").val(content + " " +$(this).html()+ " " ); 184 | $(".emoji-list").toggle(); 185 | }); 186 | 187 | $(".emoji-send").click(function () { 188 | $(".emoji-list").toggle(); 189 | }); 190 | 191 | //连接服务器 192 | socket.on('connect', function () { 193 | //uuid = 'chat'+ guid(); 194 | var fp1 = new Fingerprint(); 195 | uuid = fp1.get(); 196 | console.log('连接成功...'+uuid); 197 | 198 | var ip = $("#keleyivisitorip").html(); 199 | var msg = { 200 | "uid" : uuid, 201 | "ip" : ip 202 | }; 203 | socket.emit('login', msg); 204 | get_message(uuid); 205 | }); 206 | 207 | // /* 后端推送来消息时 208 | // msg: 209 | // type 消息类型 image,text 210 | // content 消息 211 | // */ 212 | socket.on('message', function(msg){ 213 | insert_agent_html(msg); 214 | scrollToBottom(); 215 | }); 216 | 217 | 218 | }); -------------------------------------------------------------------------------- /public/layui/css/layui.mobile.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,legend,li,ol,p,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}html{font:12px 'Helvetica Neue','PingFang SC',STHeitiSC-Light,Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0)}a{text-decoration:none;background:0 0}a:active,a:hover{outline:0}table{border-collapse:collapse;border-spacing:0}li{list-style:none}b,strong{font-weight:700}h1,h2,h3,h4,h5,h6{font-weight:500}address,cite,dfn,em,var{font-style:normal}dfn{font-style:italic}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}img{border:0;vertical-align:bottom}.layui-inline,input,label{vertical-align:middle}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;outline:0}button,select{text-transform:none}select{-webkit-appearance:none;border:none}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=1.0.7);src:url(../font/iconfont.eot?v=1.0.7#iefix) format('embedded-opentype'),url(../font/iconfont.woff?v=1.0.7) format('woff'),url(../font/iconfont.ttf?v=1.0.7) format('truetype'),url(../font/iconfont.svg?v=1.0.7#iconfont) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-box,.layui-box *{-webkit-box-sizing:content-box!important;-moz-box-sizing:content-box!important;box-sizing:content-box!important}.layui-border-box,.layui-border-box *{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1}.layui-edge,.layui-upload-iframe{position:absolute;width:0;height:0}.layui-edge{border-style:dashed;border-color:transparent;overflow:hidden}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:active{background-color:#d2d2d2!important;color:#fff!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-upload-iframe{border:0;visibility:hidden}.layui-upload-enter{border:1px solid #009E94;background-color:#009E94;color:#fff;-webkit-transform:scale(1.1);transform:scale(1.1)}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}@-webkit-keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-left{-webkit-animation-name:layui-m-anim-left;animation-name:layui-m-anim-left}@-webkit-keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-right{-webkit-animation-name:layui-m-anim-right;animation-name:layui-m-anim-right}@-webkit-keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.layui-m-anim-lout{-webkit-animation-name:layui-m-anim-lout;animation-name:layui-m-anim-lout}@-webkit-keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}.layui-m-anim-rout{-webkit-animation-name:layui-m-anim-rout;animation-name:layui-m-anim-rout}.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px} -------------------------------------------------------------------------------- /io/io.js: -------------------------------------------------------------------------------- 1 | /* 2 | *介绍:socket.io 功能封装 3 | *作者:TaiGuangYin 4 | *时间:2017-09-09 5 | * */ 6 | var redis = require('../utils/redis'); 7 | var msgType = require('./messageTpye'); 8 | var ioSvc = require('./ioHelper').ioSvc; 9 | var AppConfig = require('../config'); 10 | var Common = require('../utils/common'); 11 | var msgModel = require('../model/message'); 12 | 13 | //服务端连接 14 | function ioServer(io) { 15 | 16 | var _self = this; 17 | ioSvc.setInstance(io); 18 | 19 | var __uuids = []; 20 | 21 | //初始化连接人数 22 | redis.set('online_count',0,null,function (err,ret) { 23 | if(err){ 24 | console.error(err); 25 | } 26 | }); 27 | 28 | Array.prototype.remove = function(val) { 29 | var index = this.indexOf(val); 30 | if (index > -1) { 31 | this.splice(index, 1); 32 | } 33 | }; 34 | 35 | io.on('connection', function (socket) { 36 | console.log('SocketIO有新的连接!'); 37 | 38 | _self.updateOnlieCount(true); 39 | 40 | //用户与Socket进行绑定 41 | socket.on('login', function (msg) { 42 | var uid = msg.uid; 43 | console.log(uid+'登录成功'); 44 | 45 | //通知用户上线 46 | if(uid != AppConfig.KEFUUUID){ 47 | redis.get(AppConfig.KEFUUUID,function (err,sid) { 48 | if(err){ 49 | console.error(err); 50 | } 51 | if(sid){ 52 | redis.get('online_count',function (err,val) { 53 | if(err){ 54 | console.error(err); 55 | } 56 | if(!val){ 57 | val = 0; 58 | } 59 | if(typeof val == 'string'){ 60 | val = parseInt(val); 61 | } 62 | 63 | //var ip = socket.request.connection.remoteAddress; 64 | //此处获取IP可能会有延迟,建议改成自己的IP库 65 | Common.getIpLocation(msg.ip,function (err,location) { 66 | if(err){ 67 | location = ''; 68 | } 69 | var info = { 70 | "uid":uid, 71 | "name":location + ' 客户', 72 | "type":'online' 73 | }; 74 | 75 | redis.get('user-uuids',function (err,uuids) { 76 | if(err){ 77 | console.error(err); 78 | } 79 | if(uuids){ 80 | uuids =JSON.parse(uuids); 81 | }else{ 82 | uuids = []; 83 | } 84 | 85 | if(__uuids.indexOf(uid) == -1){ 86 | __uuids.push(uid); 87 | var d_user = {"uid":uid,"name":location + ' 客户'}; 88 | uuids.push(d_user); 89 | uuids = JSON.stringify(uuids); 90 | redis.set('user-uuids',uuids,null,function (err,ret) { 91 | if(err){ 92 | console.error(err); 93 | } 94 | }); 95 | } 96 | }); 97 | 98 | io.to(sid).emit('update-users',info); 99 | }); 100 | 101 | }); 102 | } 103 | }); 104 | } 105 | 106 | redis.set(uid,socket.id,null,function (err,ret) { 107 | if(err){ 108 | console.error(err); 109 | } 110 | }); 111 | 112 | redis.set(socket.id,uid,null,function (err,ret) { 113 | if(err){ 114 | console.error(err); 115 | } 116 | }); 117 | 118 | }); 119 | 120 | //断开事件 121 | socket.on('disconnect', function() { 122 | console.log("与服务其断开"); 123 | 124 | _self.updateOnlieCount(false); 125 | 126 | redis.get(socket.id,function (err,val) { 127 | if(err){ 128 | console.error(err); 129 | } 130 | redis.del(socket.id,function (err,ret) { 131 | if(err){ 132 | console.error(err); 133 | } 134 | 135 | }); 136 | redis.del(val,function (err,ret) { 137 | if(err){ 138 | console.error(err); 139 | } 140 | }); 141 | //通知用户下线 142 | if(val != AppConfig.KEFUUUID){ 143 | redis.get(AppConfig.KEFUUUID,function (err,sid) { 144 | if(err){ 145 | console.error(err); 146 | } 147 | if(sid){ 148 | var info = { 149 | "uid":val, 150 | "name":'客户下线', 151 | "type":'offline' 152 | }; 153 | io.to(sid).emit('update-users',info); 154 | } 155 | }); 156 | 157 | redis.get('user-uuids',function (err,uuids) { 158 | if(err){ 159 | console.error(err); 160 | } 161 | if(uuids){ 162 | uuids =JSON.parse(uuids); 163 | }else{ 164 | uuids = []; 165 | } 166 | val = parseInt(val); 167 | var idx = __uuids.indexOf(val); 168 | if( idx != -1){ 169 | __uuids.remove(val); 170 | //uuids.splice(idx,1); 171 | var tmp = []; 172 | uuids.forEach(function (user) { 173 | if(user.uid != val){ 174 | tmp.push(user); 175 | } 176 | }); 177 | uuids = JSON.stringify(tmp); 178 | redis.set('user-uuids',uuids,null,function (err,ret) { 179 | if(err){ 180 | console.error(err); 181 | } 182 | }); 183 | } 184 | }); 185 | } 186 | }); 187 | }); 188 | 189 | //重连事件 190 | socket.on('reconnect', function() { 191 | console.log("重新连接到服务器"); 192 | }); 193 | 194 | //监听客户端发送的信息,实现消息转发到各个其他客户端 195 | socket.on('message',function(msg){ 196 | msgModel.add(msg.from_uid,msg.uid,msg.content,msg.chat_type,msg.image,function (err) { 197 | if(err){ 198 | console.error(err); 199 | } 200 | }); 201 | if(msg.type == msgType.messageType.public){ 202 | var mg = { 203 | "uid" : msg.from_uid , 204 | "content": msg.content, 205 | "chat_type" : msg.chat_type?msg.chat_type:'text', 206 | "image":msg.image 207 | }; 208 | socket.broadcast.emit("message",mg); 209 | }else if(msg.type == msgType.messageType.private){ 210 | var uid = msg.uid; 211 | redis.get(uid,function (err,sid) { 212 | if(err){ 213 | console.error(err); 214 | } 215 | if(sid){ 216 | //给指定的客户端发送消息 217 | var mg = { 218 | "uid" : msg.from_uid, 219 | "content": msg.content, 220 | "chat_type" : msg.chat_type?msg.chat_type:'text', 221 | "image":msg.image 222 | }; 223 | io.to(sid).emit('message',mg); 224 | } 225 | }); 226 | } 227 | 228 | }); 229 | }); 230 | 231 | this.updateOnlieCount = function (isConnect) { 232 | //记录在线客户连接数 233 | redis.get('online_count',function (err,val) { 234 | if(err){ 235 | console.error(err); 236 | } 237 | if(!val){ 238 | val = 0; 239 | } 240 | if(typeof val == 'string'){ 241 | val = parseInt(val); 242 | } 243 | if(isConnect){ 244 | val += 1; 245 | }else{ 246 | val -= 1; 247 | if(val<=0){ 248 | val = 0; 249 | } 250 | } 251 | 252 | console.log('当前在线人数:'+val); 253 | io.sockets.emit('update_online_count', { online_count: val }); 254 | 255 | redis.set('online_count',val,null,function (err,ret) { 256 | if(err){ 257 | console.error(err); 258 | } 259 | }); 260 | }); 261 | }; 262 | 263 | } 264 | 265 | 266 | //模块导出 267 | exports.ioServer = ioServer; -------------------------------------------------------------------------------- /public/js/fingerprint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * fingerprintJS 0.5.5 - Fast browser fingerprint library 3 | * https://github.com/Valve/fingerprintjs 4 | * Copyright (c) 2013 Valentin Vasilyev (valentin.vasilyev@outlook.com) 5 | * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 8 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 11 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 12 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 13 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 14 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 15 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 16 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | */ 18 | 19 | ;(function (name, context, definition) { 20 | if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); } 21 | else if (typeof define === 'function' && define.amd) { define(definition); } 22 | else { context[name] = definition(); } 23 | })('Fingerprint', this, function () { 24 | 'use strict'; 25 | 26 | var Fingerprint = function (options) { 27 | var nativeForEach, nativeMap; 28 | nativeForEach = Array.prototype.forEach; 29 | nativeMap = Array.prototype.map; 30 | 31 | this.each = function (obj, iterator, context) { 32 | if (obj === null) { 33 | return; 34 | } 35 | if (nativeForEach && obj.forEach === nativeForEach) { 36 | obj.forEach(iterator, context); 37 | } else if (obj.length === +obj.length) { 38 | for (var i = 0, l = obj.length; i < l; i++) { 39 | if (iterator.call(context, obj[i], i, obj) === {}) return; 40 | } 41 | } else { 42 | for (var key in obj) { 43 | if (obj.hasOwnProperty(key)) { 44 | if (iterator.call(context, obj[key], key, obj) === {}) return; 45 | } 46 | } 47 | } 48 | }; 49 | 50 | this.map = function(obj, iterator, context) { 51 | var results = []; 52 | // Not using strict equality so that this acts as a 53 | // shortcut to checking for `null` and `undefined`. 54 | if (obj == null) return results; 55 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 56 | this.each(obj, function(value, index, list) { 57 | results[results.length] = iterator.call(context, value, index, list); 58 | }); 59 | return results; 60 | }; 61 | 62 | if (typeof options == 'object'){ 63 | this.hasher = options.hasher; 64 | this.screen_resolution = options.screen_resolution; 65 | this.screen_orientation = options.screen_orientation; 66 | this.canvas = options.canvas; 67 | this.ie_activex = options.ie_activex; 68 | } else if(typeof options == 'function'){ 69 | this.hasher = options; 70 | } 71 | }; 72 | 73 | Fingerprint.prototype = { 74 | get: function(){ 75 | var keys = []; 76 | keys.push(navigator.userAgent); 77 | keys.push(navigator.language); 78 | keys.push(screen.colorDepth); 79 | if (this.screen_resolution) { 80 | var resolution = this.getScreenResolution(); 81 | if (typeof resolution !== 'undefined'){ // headless browsers, such as phantomjs 82 | keys.push(resolution.join('x')); 83 | } 84 | } 85 | keys.push(new Date().getTimezoneOffset()); 86 | keys.push(this.hasSessionStorage()); 87 | keys.push(this.hasLocalStorage()); 88 | keys.push(this.hasIndexDb()); 89 | //body might not be defined at this point or removed programmatically 90 | if(document.body){ 91 | keys.push(typeof(document.body.addBehavior)); 92 | } else { 93 | keys.push(typeof undefined); 94 | } 95 | keys.push(typeof(window.openDatabase)); 96 | keys.push(navigator.cpuClass); 97 | keys.push(navigator.platform); 98 | keys.push(navigator.doNotTrack); 99 | keys.push(this.getPluginsString()); 100 | if(this.canvas && this.isCanvasSupported()){ 101 | keys.push(this.getCanvasFingerprint()); 102 | } 103 | if(this.hasher){ 104 | return this.hasher(keys.join('###'), 31); 105 | } else { 106 | return this.murmurhash3_32_gc(keys.join('###'), 31); 107 | } 108 | }, 109 | 110 | /** 111 | * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) 112 | * 113 | * @author Gary Court 114 | * @see http://github.com/garycourt/murmurhash-js 115 | * @author Austin Appleby 116 | * @see http://sites.google.com/site/murmurhash/ 117 | * 118 | * @param {string} key ASCII only 119 | * @param {number} seed Positive integer only 120 | * @return {number} 32-bit positive integer hash 121 | */ 122 | 123 | murmurhash3_32_gc: function(key, seed) { 124 | var remainder, bytes, h1, h1b, c1, c2, k1, i; 125 | 126 | remainder = key.length & 3; // key.length % 4 127 | bytes = key.length - remainder; 128 | h1 = seed; 129 | c1 = 0xcc9e2d51; 130 | c2 = 0x1b873593; 131 | i = 0; 132 | 133 | while (i < bytes) { 134 | k1 = 135 | ((key.charCodeAt(i) & 0xff)) | 136 | ((key.charCodeAt(++i) & 0xff) << 8) | 137 | ((key.charCodeAt(++i) & 0xff) << 16) | 138 | ((key.charCodeAt(++i) & 0xff) << 24); 139 | ++i; 140 | 141 | k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; 142 | k1 = (k1 << 15) | (k1 >>> 17); 143 | k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; 144 | 145 | h1 ^= k1; 146 | h1 = (h1 << 13) | (h1 >>> 19); 147 | h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; 148 | h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); 149 | } 150 | 151 | k1 = 0; 152 | 153 | switch (remainder) { 154 | case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; 155 | case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; 156 | case 1: k1 ^= (key.charCodeAt(i) & 0xff); 157 | 158 | k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; 159 | k1 = (k1 << 15) | (k1 >>> 17); 160 | k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; 161 | h1 ^= k1; 162 | } 163 | 164 | h1 ^= key.length; 165 | 166 | h1 ^= h1 >>> 16; 167 | h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; 168 | h1 ^= h1 >>> 13; 169 | h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; 170 | h1 ^= h1 >>> 16; 171 | 172 | return h1 >>> 0; 173 | }, 174 | 175 | // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 176 | hasLocalStorage: function () { 177 | try{ 178 | return !!window.localStorage; 179 | } catch(e) { 180 | return true; // SecurityError when referencing it means it exists 181 | } 182 | }, 183 | 184 | hasSessionStorage: function () { 185 | try{ 186 | return !!window.sessionStorage; 187 | } catch(e) { 188 | return true; // SecurityError when referencing it means it exists 189 | } 190 | }, 191 | 192 | hasIndexDb: function () { 193 | try{ 194 | return !!window.indexedDB; 195 | } catch(e) { 196 | return true; // SecurityError when referencing it means it exists 197 | } 198 | }, 199 | 200 | isCanvasSupported: function () { 201 | var elem = document.createElement('canvas'); 202 | return !!(elem.getContext && elem.getContext('2d')); 203 | }, 204 | 205 | isIE: function () { 206 | if(navigator.appName === 'Microsoft Internet Explorer') { 207 | return true; 208 | } else if(navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)){// IE 11 209 | return true; 210 | } 211 | return false; 212 | }, 213 | 214 | getPluginsString: function () { 215 | if(this.isIE() && this.ie_activex){ 216 | return this.getIEPluginsString(); 217 | } else { 218 | return this.getRegularPluginsString(); 219 | } 220 | }, 221 | 222 | getRegularPluginsString: function () { 223 | return this.map(navigator.plugins, function (p) { 224 | var mimeTypes = this.map(p, function(mt){ 225 | return [mt.type, mt.suffixes].join('~'); 226 | }).join(','); 227 | return [p.name, p.description, mimeTypes].join('::'); 228 | }, this).join(';'); 229 | }, 230 | 231 | getIEPluginsString: function () { 232 | if(window.ActiveXObject){ 233 | var names = ['ShockwaveFlash.ShockwaveFlash',//flash plugin 234 | 'AcroPDF.PDF', // Adobe PDF reader 7+ 235 | 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr 236 | 'QuickTime.QuickTime', // QuickTime 237 | // 5 versions of real players 238 | 'rmocx.RealPlayer G2 Control', 239 | 'rmocx.RealPlayer G2 Control.1', 240 | 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', 241 | 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', 242 | 'RealPlayer', 243 | 'SWCtl.SWCtl', // ShockWave player 244 | 'WMPlayer.OCX', // Windows media player 245 | 'AgControl.AgControl', // Silverlight 246 | 'Skype.Detection']; 247 | 248 | // starting to detect plugins in IE 249 | return this.map(names, function(name){ 250 | try{ 251 | new ActiveXObject(name); 252 | return name; 253 | } catch(e){ 254 | return null; 255 | } 256 | }).join(';'); 257 | } else { 258 | return ""; // behavior prior version 0.5.0, not breaking backwards compat. 259 | } 260 | }, 261 | 262 | getScreenResolution: function () { 263 | var resolution; 264 | if(this.screen_orientation){ 265 | resolution = (screen.height > screen.width) ? [screen.height, screen.width] : [screen.width, screen.height]; 266 | }else{ 267 | resolution = [screen.height, screen.width]; 268 | } 269 | return resolution; 270 | }, 271 | 272 | getCanvasFingerprint: function () { 273 | var canvas = document.createElement('canvas'); 274 | var ctx = canvas.getContext('2d'); 275 | // https://www.browserleaks.com/canvas#how-does-it-work 276 | var txt = 'http://valve.github.io'; 277 | ctx.textBaseline = "top"; 278 | ctx.font = "14px 'Arial'"; 279 | ctx.textBaseline = "alphabetic"; 280 | ctx.fillStyle = "#f60"; 281 | ctx.fillRect(125,1,62,20); 282 | ctx.fillStyle = "#069"; 283 | ctx.fillText(txt, 2, 15); 284 | ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; 285 | ctx.fillText(txt, 4, 17); 286 | return canvas.toDataURL(); 287 | } 288 | }; 289 | 290 | 291 | return Fingerprint; 292 | 293 | }); 294 | -------------------------------------------------------------------------------- /public/layui/lay/modules/layedit.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define(["layer","form"],function(t){"use strict";var e=layui.$,i=layui.layer,a=layui.form,l=(layui.hint(),layui.device()),n="layedit",o="layui-show",r="layui-disabled",c=function(){var t=this;t.index=0,t.config={tool:["strong","italic","underline","del","|","left","center","right","|","link","unlink","face","image"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r="layui-layedit",c=e("#"+t),u="LAY_layedit_"+ ++a.index,d=c.next("."+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join("")}(),m=e(['
    ','
    '+f+"
    ",'
    ','',"
    ","
    "].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

    ")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

    "),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find("input")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["http://www.layui.com/about/layedit/help.html","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

    "),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

      ','
    • ','','
      ','',"
      ","
    • ",'
    • ','','
      ','",'","
      ","
    • ",'
    • ','','',"
    • ","
    "].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
  • '+e+'
  • ')}),'
      '+t.join("")+"
    "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
      ','
    • ','','
      ','","
      ","
    • ",'
    • ','','
      ','',"
      ","
    • ",'
    • ','','',"
    • ","
    "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},w=new c;t(n,w)}); -------------------------------------------------------------------------------- /public/layui/css/modules/layer/default/layer.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | .layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} -------------------------------------------------------------------------------- /public/js/server/index.js: -------------------------------------------------------------------------------- 1 | //一般直接写在一个js文件中 2 | layui.use(['layer', 'form', 'jquery'], function () { 3 | var layer = layui.layer 4 | , form = layui.form 5 | , $ = layui.jquery; 6 | 7 | var currentUUID = ''; 8 | var uuid = ''; 9 | var socket = io.connect('http://'+document.domain+':9010',{ 10 | "transports":['websocket', 'polling'] 11 | }); 12 | 13 | var uuids = []; 14 | var online_num = 0; 15 | 16 | //页面初始化函数 17 | function init() { 18 | $(".admin-index").addClass("layui-this"); 19 | 20 | var height = document.body.clientHeight - 292; 21 | $(".message-container").css("height", height); 22 | 23 | window.onresize = function(){ 24 | var height = document.body.clientHeight - 292; 25 | $(".message-container").css("height", height); 26 | }; 27 | 28 | document.getElementById("msg-send-textarea").onkeydown=function(e){ 29 | if(e.keyCode == 13 && e.ctrlKey){ 30 | // 这里实现换行 31 | document.getElementById("msg-send-textarea").value += "\n"; 32 | }else if(e.keyCode == 13){ 33 | // 避免回车键换行 34 | e.preventDefault(); 35 | // 下面写你的发送消息的代码 36 | msg_send(); 37 | } 38 | }; 39 | } 40 | 41 | //聊天窗口自动滚到底 42 | function scrollToBottom() { 43 | var div = document.getElementById('message-container'); 44 | div.scrollTop = div.scrollHeight; 45 | } 46 | 47 | function insert_section(uid) { 48 | var html = ''; 49 | $(".message-container").append(html); 50 | get_message(uid); 51 | } 52 | 53 | function insert_agent_html(msg){ 54 | var time = dateFormat(); 55 | if(msg.time){ 56 | time = dateFormat("yyyy-MM-dd hh:mm:ss",new Date(msg.time)); 57 | } 58 | if(!msg.chat_type){ 59 | msg.chat_type = 'text'; 60 | } 61 | var html = '
    \n' + 62 | '
    \n' + 63 | ' ' + time + '\n' + 64 | ' \n' + 65 | '
    \n'; 66 | 67 | if(msg.chat_type == "text"){ 68 | html += '
    \n' + 69 | '
    ' + msg.content + '
    \n' + 70 | '
    \n' ; 71 | }else if(msg.chat_type == "image"){ 72 | html += '
    ' + 73 | ' ' + 74 | ' photo'+ 75 | ' ' + 76 | '
    '; 77 | } 78 | 79 | html += '
    '; 80 | $('#section-'+msg.uid).append(html); 81 | } 82 | 83 | 84 | function insert_client_html(msg){ 85 | var time = dateFormat(); 86 | if(msg.time){ 87 | time = dateFormat("yyyy-MM-dd hh:mm:ss",new Date(msg.time)); 88 | } 89 | if(!msg.chat_type){ 90 | msg.chat_type = 'text'; 91 | } 92 | var html = '
    \n' + 93 | '
    \n' + 94 | ' ' + time + '\n' + 95 | ' 客户\n' + 96 | '
    \n' ; 97 | if(msg.chat_type == "text"){ 98 | html += '
    \n' + 99 | '
    ' + msg.content + '
    \n' + 100 | '
    \n' ; 101 | }else if(msg.chat_type == "image"){ 102 | html += '
    ' + 103 | ' ' + 104 | ' photo'+ 105 | ' ' + 106 | '
    '; 107 | } 108 | 109 | html += '
    '; 110 | $('#section-'+msg.uid).append(html); 111 | } 112 | 113 | function insert_user_html(id,name) { 114 | var html = ''; 121 | $('.chat-user').append(html); 122 | } 123 | 124 | function msg_sender_status(status){ 125 | if(status){ 126 | $(".btnMsgSend").removeClass("layui-btn-disabled"); 127 | $("#msg-send-textarea").removeAttr("disabled"); 128 | $(".empty-status").hide(); 129 | }else{ 130 | $(".btnMsgSend").addClass("layui-btn-disabled"); 131 | $("#msg-send-textarea").attr("disabled","disabled"); 132 | $(".empty-status").show(); 133 | } 134 | } 135 | 136 | function msg_notification(msg) { 137 | $(".chat-user #"+msg.uid+" .msg-tips").show(); 138 | if(window.Notification && Notification.permission !== "denied") { 139 | Notification.requestPermission(function(status) { 140 | var n = new Notification('您有新的消息', { body: msg.content }); 141 | }); 142 | } 143 | } 144 | 145 | function update_online_status() { 146 | var num = uuids.length; 147 | if(online_num > num){ 148 | num = online_num; 149 | } 150 | $(".friend-head-right").html( online_num + ' / ' + num + ' 人' ); 151 | } 152 | 153 | //发送消息 154 | function msg_send() { 155 | var msg = $("#msg-send-textarea").val(); 156 | 157 | if(msg){ 158 | var msg_sender = { 159 | "type":'private', 160 | "uid":currentUUID, 161 | "content":msg, 162 | "from_uid":uuid, 163 | "chat_type":'text' 164 | }; 165 | socket.emit('message', msg_sender); 166 | insert_agent_html(msg_sender); 167 | scrollToBottom(); 168 | $("#msg-send-textarea").val(''); 169 | } 170 | } 171 | 172 | //获取在线用户 173 | function get_users() { 174 | $.get('/users',function (data) { 175 | if(data.code == 200){ 176 | $('.chat-user').html(''); 177 | 178 | var data = data.data; 179 | 180 | data.forEach(function (user) { 181 | insert_user_html(user.uid,user.name + '#'+ (uuids.length + 1)); 182 | //创建聊天section 183 | insert_section(user.uid); 184 | uuids.push(user.uid); 185 | }); 186 | if(data.length > 0 && !currentUUID){ 187 | currentUUID = data[0].uid; 188 | } 189 | 190 | $(".user-info").css("background","#ffffff"); 191 | $("#"+currentUUID).css("background","#f2f3f5"); 192 | $(".user-section").hide(); 193 | msg_sender_status(true); 194 | $("#section-"+currentUUID).show(); 195 | update_online_status(); 196 | } 197 | }); 198 | } 199 | 200 | //获取最新的五条数据 201 | function get_message(uid) { 202 | $.get('/message?uid='+uid,function (data) { 203 | if(data.code == 200){ 204 | data.data.reverse().forEach(function (msg) { 205 | if(msg.from_uid == uid){ 206 | msg.uid = msg.from_uid; 207 | insert_client_html(msg); 208 | }else{ 209 | msg.uid = msg.to_uid; 210 | insert_agent_html(msg); 211 | } 212 | 213 | scrollToBottom(); 214 | }); 215 | } 216 | }); 217 | } 218 | 219 | $(".btnMsgSend").click(function(){ 220 | msg_send(); 221 | }); 222 | 223 | $(".picture-upload").click(function () { 224 | var uploader = Qiniu.uploader({ 225 | runtimes: 'html5,flash,html4', // 上传模式,依次退化 226 | browse_button: 'pickfiles', // 上传选择的点选按钮,必需 227 | uptoken_url: '/uptoken', // Ajax请求uptoken的Url,强烈建议设置(服务端提供) 228 | get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的uptoken 229 | domain: 'http://kefuimg.chinameyer.com/', // bucket域名,下载资源时用到,必需 230 | container: 'btn-uploader', // 上传区域DOM ID,默认是browser_button的父元素 231 | max_file_size: '10mb', // 最大文件体积限制 232 | flash_swf_url: 'path/of/plupload/Moxie.swf', //引入flash,相对路径 233 | max_retries: 3, // 上传失败最大重试次数 234 | dragdrop: false, // 开启可拖曳上传 235 | drop_element: 'btn-uploader', // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传 236 | chunk_size: '4mb', // 分块上传时,每块的体积 237 | auto_start: true, // 选择文件后自动上传,若关闭需要自己绑定事件触发上传 238 | unique_names: true, 239 | filters : { 240 | max_file_size : '10mb', 241 | prevent_duplicates: true, 242 | // Specify what files to browse for 243 | mime_types: [ 244 | {title : "Image files", extensions : "jpg,gif,png,bmp"}, // 限定jpg,gif,png后缀上传 245 | ] 246 | }, 247 | init: { 248 | 'FilesAdded': function(up, files) { 249 | plupload.each(files, function(file) { 250 | // 文件添加进队列后,处理相关的事情 251 | }); 252 | }, 253 | 'BeforeUpload': function(up, file) { 254 | // 每个文件上传前,处理相关的事情 255 | }, 256 | 'UploadProgress': function(up, file) { 257 | // 每个文件上传时,处理相关的事情 258 | }, 259 | 'FileUploaded': function(up, file, info) { 260 | // 查看简单反馈 261 | var domain = up.getOption('domain'); 262 | var res = JSON.parse(info); 263 | var sourceLink = domain +"/"+ res.key; 264 | 265 | var msg_sender = { 266 | "type":'private', 267 | "uid":currentUUID, 268 | "content":'图片消息', 269 | "from_uid":uuid, 270 | "chat_type":'image', 271 | "image":sourceLink 272 | }; 273 | socket.emit('message', msg_sender); 274 | insert_agent_html(msg_sender); 275 | scrollToBottom(); 276 | }, 277 | 'Error': function(up, err, errTip) { 278 | //上传出错时,处理相关的事情 279 | $.toast("上传失败"); 280 | }, 281 | 'UploadComplete': function() { 282 | //队列文件处理完毕后,处理相关的事情 283 | } 284 | } 285 | }); 286 | 287 | }); 288 | 289 | $(".emoji-list li").click(function () { 290 | var content = $("#msg-send-textarea").val(); 291 | $("#msg-send-textarea").val(content + " " +$(this).html()+ " " ); 292 | $(".emoji-list").toggle(); 293 | }); 294 | 295 | $("#emojiBtn").click(function () { 296 | $(".emoji-list").toggle(); 297 | }); 298 | 299 | //连接服务器 300 | socket.on('connect', function () { 301 | console.log('连接成功...'); 302 | uuid = 'chat-kefu-admin'; 303 | var ip = $("#keleyivisitorip").html(); 304 | var msg = { 305 | "uid" : uuid, 306 | "ip" : ip 307 | }; 308 | socket.emit('login', msg); 309 | }); 310 | 311 | //后端推送来消息时 312 | socket.on('message', function(msg){ 313 | insert_client_html(msg); 314 | scrollToBottom(); 315 | msg_notification(msg); 316 | }); 317 | 318 | //后端推送来消息时 319 | socket.on('update-users', function(msg){ 320 | if(msg.type == 'offline'){ 321 | //arrayRemove(uuids,msg.uid); 322 | $(".chat-user #"+msg.uid+" .user-avatar img").attr("src","/images/server/mine_fill.png"); 323 | $("#section-" + msg.uid).hide(); 324 | //$(".chat-user").find("#"+msg.uid).remove(); 325 | msg_sender_status(false); 326 | }else if(msg.type == 'online'){ 327 | if(!currentUUID){ 328 | currentUUID = msg.uid; 329 | } 330 | 331 | if(currentUUID == uuid){ 332 | return false; 333 | } 334 | 335 | var index = uuids.indexOf(msg.uid); 336 | if( index == -1){ 337 | uuids.push(msg.uid); 338 | insert_user_html(msg.uid,msg.name + '#'+ (uuids.length + 1)); 339 | //创建聊天section 340 | insert_section(msg.uid); 341 | }else{ 342 | if($(".chat-user").find("#"+msg.uid).length == 0){ 343 | insert_user_html(msg.uid,msg.name + '#'+ (uuids.length + 1)); 344 | //创建聊天section 345 | insert_section(msg.uid); 346 | } 347 | } 348 | 349 | $(".chat-user #"+msg.uid+" .user-avatar img").attr("src","/images/server/mine_fill_blue.png"); 350 | } 351 | update_online_status(); 352 | }); 353 | 354 | //更新用户在线数 355 | socket.on('update_online_count', function(msg){ 356 | online_num = (msg.online_count - 1) >= 0 ? (msg.online_count - 1) : 0; 357 | update_online_status(); 358 | }); 359 | 360 | //切换用户 361 | $(document).on('click','.user-info',function(){ 362 | var uid = $(this).attr("id"); 363 | currentUUID = uid; 364 | $(".user-info").css("background","#ffffff"); 365 | $("#"+uid).css("background","#f2f3f5"); 366 | $(".user-section").hide(); 367 | $("#section-"+uid).show(); 368 | msg_sender_status(true); 369 | $(".chat-user #"+uid+" .msg-tips").hide(); 370 | }); 371 | 372 | init(); 373 | get_users(); 374 | }); -------------------------------------------------------------------------------- /public/layui/lay/modules/table.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;layui.define(["laytpl","laypage","layer","form"],function(e){"use strict";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=layui.hint(),r=layui.device(),d={config:{checkName:"LAY_CHECKED",indexName:"LAY_TABLE_INDEX"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,s,e,t)}},c=function(){var e=this,t=e.config,i=t.id;return i&&(c.config[i]=t),{reload:function(t){e.reload.call(e,t)},config:t}},s="table",u=".layui-table",f="layui-hide",h="layui-none",y="layui-table-view",p=".layui-table-header",m=".layui-table-body",v=".layui-table-main",g=".layui-table-fixed",x=".layui-table-fixed-l",b=".layui-table-fixed-r",k=".layui-table-tool",C=".layui-table-sort",w="layui-table-edit",N="layui-table-hover",z=function(e){return e=e||{},['',"","{{# layui.each(d.data.cols, function(i1, item1){ }}","","{{# layui.each(item1, function(i2, item2){ }}",'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}','{{# if(item2.fixed === "right"){ right = true; } }}',function(){return e.fixed&&"right"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== "right"){ }}':"right"===e.fixed?'{{# if(item2.fixed === "right"){ }}':""}(),"{{# if(item2.checkbox){ }}",'',"{{# } else if(item2.space){ }}",'',"{{# } else { }}",'","{{# }; }}",e.fixed?"{{# }; }}":"","{{# }); }}","","{{# }); }}","","
    ',"{{# if(item2.colspan > 1){ }}",'
    ','{{item2.title||""}}',"
    ","{{# } else { }}",'
    ','{{item2.title||""}}',"{{# if(item2.sort){ }}",'',"{{# } }}","
    ","{{# } }}","
    "].join("")},F=['',"","
    "].join(""),T=['
    ',"{{# var left, right; }}",'
    ',z(),"
    ",'
    ',F,"
    ","{{# if(left){ }}",'
    ','
    ',z({fixed:!0}),"
    ",'
    ',F,"
    ","
    ","{{# }; }}","{{# if(right){ }}",'
    ','
    ',z({fixed:"right"}),'
    ',"
    ",'
    ',F,"
    ","
    ","{{# }; }}","{{# if(d.data.page){ }}",'
    ','
    ',"
    ","{{# } }}","","
    "].join(""),L=t(window),S=t(document),H=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};H.prototype.config={limit:30,loading:!0},H.prototype.render=function(e){var a,l=this;if(e&&(l.config=e),a=l.config,a.elem=t(a.elem),a.where=a.where||{},a.request=t.extend({pageName:"page",limitName:"limit"},a.request),a.response=t.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",countName:"count"},a.response),!a.elem[0])return l;var n=a.elem,o=n.next("."+y);a.height&&/^full-\d+$/.test(a.height)&&(l.fullHeightGap=a.height.split("-")[1],a.height=L.height()-l.fullHeightGap);var r=l.elem=t(i(T).render({VIEW_CLASS:y,data:a,index:l.index}));if(a.index=l.index,o[0]&&o.remove(),n.after(r),l.layHeader=r.find(p),l.layMain=r.find(v),l.layBody=r.find(m),l.layFixed=r.find(g),l.layFixLeft=r.find(x),l.layFixRight=r.find(b),l.layTool=r.find(k),a.height&&l.fullSize(),a.cols.length>1){var d=l.layFixed.find(p).find("th");d.height(l.layHeader.height()-1-parseFloat(d.css("padding-top"))-parseFloat(d.css("padding-bottom")))}l.pullData(1),l.events()},H.prototype.reload=function(e){var i=this;i.config=t.extend({},i.config,e),i.render()},H.prototype.pullData=function(e,i){var a=this,n=a.config,o=n.request,r=n.response,d=function(){"object"==typeof n.initSort&&a.sort(n.initSort.field,n.initSort.type)};if(n.url){var c={};c[o.pageName]=e,c[o.limitName]=n.limit,t.ajax({type:n.method||"get",url:n.url,data:t.extend(c,n.where),dataType:"json",success:function(t){return t[r.statusName]!=r.statusCode?(a.renderForm(),a.layMain.html('
    '+(t[r.msgName]||"返回的数据状态异常")+"
    ")):(a.renderData(t,e,t[r.countName]),d(),i&&l.close(i),void("function"==typeof n.done&&n.done(t,e,t[r.countName])))},error:function(e,t){a.layMain.html('
    数据接口请求异常
    '),a.renderForm(),i&&l.close(i)}})}else if(n.data&&n.data.constructor===Array){var s={},u=e*n.limit-n.limit;s[r.dataName]=n.data.concat().splice(u,n.limit),s[r.countName]=n.data.length,a.renderData(s,e,n.data.length),d(),"function"==typeof n.done&&n.done(s,e,s[r.countName])}},H.prototype.page=1,H.prototype.eachCols=function(e){var i=t.extend(!0,[],this.config.cols),a=[],l=0;layui.each(i,function(e,t){layui.each(t,function(t,n){if(n.colspan>1){var o=0;l++,n.CHILD_COLS=[],layui.each(i[e+1],function(e,t){t.PARENT_COL||o==n.colspan||(t.PARENT_COL=l,n.CHILD_COLS.push(t),o+=t.colspan>1?t.colspan:1)})}n.PARENT_COL||a.push(n)})});var n=function(t){layui.each(t||a,function(t,i){return i.CHILD_COLS?n(i.CHILD_COLS):void e(t,i)})};n()},H.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,u=e[s.response.dataName]||[],f=[],y=[],p=[],m=function(){return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(u,function(e,a){var l=[],n=[],o=[];0!==a.length&&(r||(a[d.config.indexName]=e),c.eachCols(function(e,r){var c=a[r.field||e];if(void 0!==c&&null!==c||(c=""),!(r.colspan>1)){var u=['",'
    '+function(){return r.checkbox?'":r.toolbar?i(t(r.toolbar).html()||"").render(a):r.templet?i(t(r.templet).html()||String(c)).render(a):c}(),"
    "].join("");l.push(u),r.fixed&&"right"!==r.fixed&&n.push(u),"right"===r.fixed&&o.push(u)}}),f.push(''+l.join("")+""),y.push(''+n.join("")+""),p.push(''+o.join("")+""))}),c.layBody.scrollTop(0),c.layMain.find("."+h).remove(),c.layMain.find("tbody").html(f.join("")),c.layFixLeft.find("tbody").html(y.join("")),c.layFixRight.find("tbody").html(p.join("")),c.renderForm(),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,void l.close(c.tipsIndex))};return c.key=s.id||s.index,d.cache[c.key]=u,r?m():0===u.length?(c.renderForm(),c.layFixed.remove(),c.layMain.find("tbody").html(""),c.layMain.find("."+h).remove(),c.layMain.append('
    无数据
    ')):(m(),void(s.page&&(c.page=n,c.count=o,a.render({elem:"layui-table-page"+s.index,count:o,groups:3,limits:s.limits||[10,20,30,40,50,60,70,80,90],limit:s.limit,curr:n,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr,c.loading()))}}),c.layTool.find(".layui-table-count span").html(o))))},H.prototype.renderForm=function(e){n.render(e||"checkbox","LAY-table-"+this.index)},H.prototype.sort=function(e,i,a,n){var r,c,u=this,f={},h=u.config,y=h.elem.attr("lay-filter"),p=d.cache[u.key];"string"==typeof e&&u.layHeader.find("th").each(function(i,a){var l=t(this),n=l.data("field");if(n===e)return e=l,r=n,!1});try{var r=r||e.data("field");if(u.sortKey&&!a&&r===u.sortKey.field&&i===u.sortKey.sort)return;var m=u.layHeader.find("th .laytable-cell-"+h.index+"-"+r).find(C);u.layHeader.find("th").find(C).removeAttr("lay-sort"),m.attr("lay-sort",i||null),u.layFixed.find("th")}catch(v){return o.error("Table modules: Did not match to field")}u.sortKey={field:r,sort:i},"asc"===i?c=layui.sort(p,r):"desc"===i?c=layui.sort(p,r,!0):(c=layui.sort(p,d.config.indexName),delete u.sortKey),f[h.response.dataName]=c,u.renderData(f,u.page,u.count,!0),l.close(u.tipsIndex),n&&layui.event.call(e,s,"sort("+y+")",{field:r,type:i})},H.prototype.loading=function(){var e=this,t=e.config;if(t.loading&&t.url)return l.msg("数据请求中",{icon:16,offset:[e.elem.offset().top+e.elem.height()/2-35-L.scrollTop()+"px",e.elem.offset().left+e.elem.width()/2-90-L.scrollLeft()+"px"],anim:-1,fixed:!1})},H.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&(l[e][a.checkName]=t)},H.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(i){return e.eachCols(function(e,a){a.checkbox&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop("checked",!0),e.renderForm()),a(!0)):(i[0].checked&&(i.prop("checked",!1),e.renderForm()),a(!1)))},H.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find("style")[0],l=a.sheet||a.styleSheet,n=l.cssRules||l.rules;layui.each(n,function(a,l){if(l.selectorText===".laytable-cell-"+i.index+"-"+e)return t(l),!0})},H.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=L.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css("height",a)),e=parseFloat(a)-parseFloat(t.layHeader.height())-1,i.page&&(e-=parseFloat(t.layTool.outerHeight()+1)),t.layMain.css("height",e)},H.prototype.scrollPatch=function(){var e=this,i=e.layMain.children("table"),a=e.layMain.width()-e.layMain.prop("clientWidth"),l=e.layMain.height()-e.layMain.prop("clientHeight");if(a&&l){if(!e.elem.find(".layui-table-patch")[0]){var n=t('
    ');n.find("div").css({width:a}),e.layHeader.eq(0).find("thead tr").append(n)}}else e.layHeader.eq(0).find(".layui-table-patch").remove();var o=e.layMain.height(),r=o-l;e.layFixed.find(m).css("height",i.height()>r?r:"auto"),e.layFixRight[i.width()>e.layMain.width()?"removeClass":"addClass"](f),e.layFixRight.css("right",a-1)},H.prototype.events=function(){var e,a=this,n=a.config,o=t("body"),c={},u=a.layHeader.find("th"),f=".layui-table-cell",h=n.elem.attr("lay-filter");u.on("mousemove",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.attr("colspan")>1||i.attr("unresize")||c.resizeStart||(c.allowResize=i.width()-l<=10,o.css("cursor",c.allowResize?"col-resize":""))}).on("mouseleave",function(){t(this);c.resizeStart||o.css("cursor","")}).on("mousedown",function(e){if(c.allowResize){var i=t(this).data("field");e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],a.getCssRule(i,function(e){c.rule=e,c.ruleWidth=parseFloat(e.style.width)})}}),S.on("mousemove",function(t){if(c.resizeStart){if(t.preventDefault(),c.rule){var i=c.ruleWidth+t.clientX-c.offset[0];c.rule.style.width=i+"px",l.close(a.tipsIndex)}e=1}}).on("mouseup",function(t){c.resizeStart&&(c={},o.css("cursor",""),a.scrollPatch()),2===e&&(e=null)}),u.on("click",function(){var i,l=t(this),n=l.find(C),o=n.attr("lay-sort");return n[0]&&1!==e?(i="asc"===o?"desc":"desc"===o?null:"asc",void a.sort(l,i,null,!0)):e=2}).find(C+" .layui-edge ").on("click",function(e){var i=t(this),l=i.index(),n=i.parents("th").eq(0).data("field");layui.stope(e),0===l?a.sort(n,"asc",null,!0):a.sort(n,"desc",null,!0)}),a.elem.on("click",'input[name="layTableCheckbox"]+',function(){var e=t(this).prev(),i=a.layBody.find('input[name="layTableCheckbox"]'),l=e.parents("tr").eq(0).data("index"),n=e[0].checked,o="layTableAllChoose"===e.attr("lay-filter");o?(i.each(function(e,t){t.checked=n,a.setCheckData(e,n)}),a.syncCheckAll(),a.renderForm()):(a.setCheckData(l,n),a.syncCheckAll()),layui.event.call(this,s,"checkbox("+h+")",{checked:n,data:d.cache[a.key][l],type:o?"all":"one"})}),a.layBody.on("mouseenter","tr",function(){var e=t(this),i=e.index();a.layBody.find("tr:eq("+i+")").addClass(N)}).on("mouseleave","tr",function(){var e=t(this),i=e.index();a.layBody.find("tr:eq("+i+")").removeClass(N)}),a.layBody.on("change","."+w,function(){var e=t(this),i=this.value,l=e.parent().data("field"),n=e.parents("tr").eq(0).data("index"),o=d.cache[a.key][n];o[l]=i,layui.event.call(this,s,"edit("+h+")",{value:i,data:o,field:l})}).on("blur","."+w,function(){var e,l=t(this),n=l.parent().data("field"),o=l.parents("tr").eq(0).data("index"),r=d.cache[a.key][o];a.eachCols(function(t,i){i.field==n&&i.templet&&(e=i.templet)}),l.siblings(f).html(e?i(t(e).html()||this.value).render(r):this.value),l.parent().data("content",this.value),l.remove()}),a.layBody.on("click","td",function(){var e=t(this),i=(e.data("field"),e.children(f));if(!e.data("off")){if(e.data("edit")){var o=t('');return o[0].value=e.data("content")||i.text(),e.find("."+w)[0]||e.append(o),o.focus()}i.prop("scrollWidth")>i.outerWidth()&&(a.tipsIndex=l.tips(['
    ',i.html(),"
    ",''].join(""),i[0],{tips:[3,""],time:-1,anim:-1,maxWidth:r.ios||r.android?300:600,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){l.close(t)})}}))}}),a.layBody.on("click","*[lay-event]",function(){var e=t(this),l=e.parents("tr").eq(0).data("index"),n=a.layBody.find('tr[data-index="'+l+'"]'),o="layui-table-click",r=d.cache[a.key][l];layui.event.call(this,s,"tool("+h+")",{data:d.clearCacheKey(r),event:e.attr("lay-event"),tr:n,del:function(){d.cache[a.key][l]=[],n.remove(),a.scrollPatch()},update:function(e){e=e||{},layui.each(e,function(e,l){if(e in r){var o,d=n.children('td[data-field="'+e+'"]');r[e]=l,a.eachCols(function(t,i){i.field==e&&i.templet&&(o=i.templet)}),d.children(f).html(o?i(t(o).html()||l).render(r):l),d.data("content",l)}})}}),n.addClass(o).siblings("tr").removeClass(o)}),a.layMain.on("scroll",function(){var e=t(this),i=e.scrollLeft(),n=e.scrollTop();a.layHeader.scrollLeft(i),a.layFixed.find(m).scrollTop(n),l.close(a.tipsIndex)}),L.on("resize",function(){a.fullSize(),a.scrollPatch()})},d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter="'+e+'"]':u+"[lay-data]"),n="Table element property lay-data configuration item has a syntax error: ";return l.each(function(){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){o.error(n+l)}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr("lay-skin"),size:a.attr("lay-size"),even:"string"==typeof a.attr("lay-even")},d.config,i,l);e&&a.hide(),a.find("thead>tr").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr("colspan")||0,rowspan:a.attr("rowspan")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find("tbody>tr").each(function(e){var i=t(this),a={};i.children("td").each(function(e,i){var l=t(this),n=l.data("field");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children("td").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},d.checkStatus=function(e){var t=0,i=[],a=d.cache[e];return a?(layui.each(a,function(e,a){a[d.config.checkName]&&(t++,i.push(d.clearCacheKey(a)))}),{data:i,isAll:t===a.length}):{}},c.config={},d.reload=function(e,i){var a=c.config[e];return a?d.render(t.extend({},a,i)):o.error("The ID option was not found in the table instance")},d.render=function(e){var t=new H(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(s,d)}); -------------------------------------------------------------------------------- /public/layui/lay/modules/layer.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.1.5 MIT License By http://www.layui.com */ 2 | ;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.scripts,t=e[e.length-1],i=t.src;if(!t.getAttribute("merge"))return i.substring(0,i.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.0",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
    '+(f?r.title[0]:r.title)+"
    ":"";return r.zIndex=s,t([r.shade?'
    ':"",'
    '+(e&&2!=r.type?"":u)+'
    '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
    '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
    '+e+"
    "}():"")+(r.resize?'':"")+"
    "],u,i('
    ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
      '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
    • '+(t[0].content||"no content")+"
    • ";i'+(t[i].content||"no content")+"";return a}()+"
    ",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
    '+(u.length>1?'':"")+'
    '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
    ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
    是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window); --------------------------------------------------------------------------------