服务器端:
app.js let express = require('express'); |
websocket.js const md5=require('md5');
const db=require('./../utils/db');
module.exports=function (io,app) {
//设置聊天名字,返回聊天记录
app.post("/qingwakuaiche/setName",function (req,res) {
let data=req.body.fromName;
let _toName=req.body.toName;
let fromName=new Promise(function (resolve, reject) {
db.find('chatList',{$or:[{fromName:data},{toName:data}]}).then(function (arr) {
if(arr.length){
resolve(arr)
}else {
reject([{
sayID:sort(_toName+data),
toName:_toName,
arr:[
{
toName:_toName,
msg:'',
fromName:data,
sayID:sort(_toName+data),
time:new Date().getTime(),
}
]
}])
}
})
});
Promise.all([fromName]).then(function ([fromName]) {
let result=fromName;
result.sort(function (a,b) {
return a.time-b.time
});
//整理toName
let toNameArr=result.map(function (value, index, array) {
if(value.fromName!==data){
return JSON.stringify({
name:value.fromName,
sayID:value.sayID,
})
} else if(value.toName!==data){
return JSON.stringify({
name: value.toName,
sayID:value.sayID,
})
}
});
//toName去重
toNameArr=Array.from(new Set(toNameArr));
//整合后的result数组 和 toName再次整合
result=toNameArr.map(function (val,index) {
let nameObj=JSON.parse(val);
return {
sayID:nameObj.sayID,
toName:nameObj.name,
arr:result.filter(function (value, index, array) {
return nameObj.sayID===value.sayID
})
}
});
res.json(result)
}).catch(function (err) {
res.json(err)
})
});
io.on('connection', function(socket){
//用户想聊天对象发起聊天
socket.on('sayTo',function (data) {
let toName = data.toName;
db.insertOne('chatList',{
sayID:sort(toName+data.fromName),
toName,
msg:data.msg,
fromName:data.fromName,
time:new Date().getTime()
});
//发送信息给指定的用户
io.emit('frog'+sort(toName+data.fromName),{
msg:data.msg,
fromName:data.fromName,
toName,
time:new Date().getTime()
});
});
});
//字符串排序
function sort(str) {
let a=(str.toString()).split("");
let b=a.sort();
return b.join("");
}
};
//判断是否参数缺失
function isNot(req,res,arr) {
return new Promise(function (resolve, reject) {
let obj=req.body;
for(let i in arr){
if(obj[arr[i]]){
resolve(true)
}else {
res.send('缺少参数');
}
}
})
} |
客户端:(基于vue开发)
基于的包
"axios": "^0.18.0", "babel-polyfill": "^6.26.0", "jquery": "^3.3.1", "js-cookie": "^2.2.0", "jsencrypt": "^3.0.0-beta.1", "vue": "^2.5.2", "vue-axios": "^2.1.1", "vue-router": "^3.0.1", "vue-socket-io": "^0.3.2", "vue-socket.io": "^2.1.1-b", "vuex": "^3.0.1"
<template> <div v-show="chatBool"> <div class="min-box clearfix" v-show="min==='true'" @click="maximize('false')"> <div class="fl"> <span class="icon"><i></i><sub></sub></span> <span class="news">有42条新消息</span> </div> <div class="fr"></div> </div> <div class="chat" v-if="min==='false'"> <p class="operate"> <span class="min" @click="maximize('true')"></span> <span class="close" @click="closeFn"></span> </p> <div class="fl"> <h3>消息(1)</h3> <ul v-show="chatList.length"> <li class="clearfix" :class="{active:chatIndex===index}" v-for="(item,index) in chatList" @click="chooseChat(index)"> <div class="img fl active"> <img src="../assets/images/userImg-circle.png" > <div class="line" v-if="item.isReader"></div> </div> <div class="name fl"> <h3>{{item.toName}}</h3> <p>{{item.arr[item.arr.length-1].msg}}</p> </div> <div class="news fl">...</div> </li> </ul> </div> <div class="fr"> <h3>{{toName}}</h3> <div class="text"> <div v-if="item.msg" class="clearfix" :class="[((index+1)%2)===0 && index!==0?'active':'', tel===item.fromName?'hover':'']" v-for="(item,index) in chooseChatData"> <div class="img fl"> <img src="../assets/images/userImg-circle.png" ></div> <div class="text fl"> <div class="sjx"></div> <div class="content">{{item.msg}}</div> </div> </div> </div> <div class="sendMes"> <textarea v-model="sendMes" @keyup.enter="sendMesFn(toName)" placeholder="输入消息文本" maxlength="50"></textarea> <div><button @click="sendMesFn(toName)">发送</button></div> </div> </div> </div> </div> </template> <script> export default { name: "chat", data(){ return{ chatIndex:'',//默认聊天的数组 min:sessionStorage.getItem('chatMin') || 'false',//聊天窗口是否最小化 sendMes:'',//发送的数据 chatList:[],//关于我的聊天数据 chooseChatData:[],//选择与那个用户的聊天记录 chatId:'',//聊天id toName:'',//对谁聊天 sameSayArr:[],//相同的聊天id tel:this.getCookie('tel'), init:1,//聊天初始化 } }, created(){ }, computed:{ chatBool(){ let toName=this.$store.state.common.chatBool; if(toName){ this.getChatList(this.$store.state.common.chatBool); this.getMsg(this.getCookie('tel'),this.toName); } return this.$store.state.common.chatBool } }, mounted(){ }, updated(){ }, watch:{ chooseChatData(){ let talk=$('.chat > div.fr > .text'); talk.scrollTop(talk[0].scrollHeight); } }, methods:{ //获取聊天历史记录 getChatList(toName){ let tel=this.getCookie('tel'); this.axios.post(this.hostUrl+'/setName', {fromName:tel,toName}).then((obj) => { let arr=obj.data; this.chatList=arr; /*if(arr[0].msg){ this.chatList=arr; }*/ }); }, //选择聊天的人 chooseChat(index){ this.chatIndex=index; if(this.chatList.length){ this.toName=(this.chatList)[index].toName; this.chooseChatData=(this.chatList)[index].arr; let talk=$('.chat > div.fr > .text'); talk.scrollTop(talk[0].scrollHeight); } }, //发送消息 sendMesFn(toName){ let tel=this.getCookie('tel'); if(!tel){ return false } if(!toName){ alert("请选择聊天对象"); return false } this.$socket.emit('sayTo',{ toName, fromName:tel, msg:this.sendMes }); }, //获取聊天消息 getMsg(tel,toName){ this.$socket.on('frog'+this.sort(tel+toName), (data)=> { this.sendMes=''; console.log(data) if(this.chatList.length){ this.chatList=this.chatList.map(val=>{ if(val.toName===toName){ let arr=val.arr; arr.push(data); return{ sayID:val.sayID, toName:val.toName, arr } } }); } this.chooseChatData.push(data); }); }, maximize(bool){ this.min=bool; sessionStorage.setItem('chatMin',bool); }, closeFn(){ this.$store.commit('chatFn',false) }, } } </script> <style scoped> @import "../assets/less/chat.css"; </style> |