vue和springboot使用websocket实现聊天
分类: springboot vue 专栏: springboot vue 常用功能 标签: 实现聊天
2025-02-19 21:47:58 254浏览
用2张表实现vue和springboot使用websocket实现聊天,可以是好朋友聊,也可以是固定客服人员聊天
旅游web——vue项目
DROP TABLE IF EXISTS `lv_chatroom`; CREATE TABLE `lv_chatroom` ( `cno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `cts` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `cnos` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, PRIMARY KEY (`cno`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1; DROP TABLE IF EXISTS `lv_chat`; CREATE TABLE `lv_chat` ( `id` int(0) NOT NULL AUTO_INCREMENT, `uid` int(0) DEFAULT NULL, `cont` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `cts` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `cno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 473 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
后台xml chat.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jf.s.dao.LvChatMapper">
<select id="getlistByJoin" resultType="com.jf.s.bean.LvChat" parameterType="com.jf.s.bean.LvChat">
select
c.*,u.nickname,u.faceimg
from lv_chat c
left join lv_users u on u.id=c.uid
where 1=1
<if test="cno != null and cno!='' ">
and c.cno=#{cno}
</if>
</select>
<select id="getByIdJoin" resultType="com.jf.s.bean.LvChat"
parameterType="java.lang.Integer">
select
c.*,u.nickname,u.faceimg
from lv_chat c
left join lv_users u on u.id=c.uid
where c.id=#{0}
</select>
</mapper>dao
package com.jf.s.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jf.s.bean.LvChat;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Mapper
public interface LvChatMapper extends BaseMapper<LvChat> {
List<LvChat> getlistByJoin(LvChat o);
LvChat getByIdJoin(Integer id);
}
package com.jf.s.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jf.s.bean.LvChat;
import com.jf.s.bean.LvChatroom;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Mapper
public interface LvChatroomMapper extends BaseMapper<LvChatroom> {
}
service
package com.jf.s.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jf.s.bean.LvChat;
import com.jf.s.dao.LvChatMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LvChatService extends ServiceImpl<LvChatMapper, LvChat> {
@Autowired
LvChatMapper chatMapper;
public List<LvChat> getlistByJoin(LvChat o) {
return chatMapper.getlistByJoin(o);
}
public LvChat getByIdJoin(Integer id){
return chatMapper.getByIdJoin(id);
}
}
package com.jf.s.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jf.s.bean.LvChatroom;
import com.jf.s.bean.LvChatroom;
import com.jf.s.dao.LvChatroomMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LvChatroomService extends ServiceImpl<LvChatroomMapper, LvChatroom> {
@Autowired
LvChatroomMapper chatroomMapper;
public List<LvChatroom> getChatRooms(String cnos) {
LambdaQueryWrapper<LvChatroom> lambdaQueryWrapper = Wrappers.lambdaQuery();
//条件查询
lambdaQueryWrapper.like(LvChatroom::getCnos, cnos);
List<LvChatroom> li = chatroomMapper.selectList(lambdaQueryWrapper);
return li;
}
}
bean
package com.jf.s.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("lv_chat")
public class LvChat {
@TableId(type = IdType.AUTO)
private Integer id;
private Integer uid;
private String cont;
private String cts;
private String cno;
@TableField(exist = false)
private String keywords;
@TableField(exist = false)
private String nickname;
@TableField(exist = false)
private String faceimg;
}
package com.jf.s.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("lv_chatroom")
public class LvChatroom {
@TableId(type = IdType.INPUT)
private String cno;
private String cts;
private String cnos;
}
controller
package com.jf.s.control; import com.jf.s.bean.LvChat; import com.jf.s.bean.LvChatroom; import com.jf.s.bean.LvUsers; import com.jf.s.service.LvChatService; import com.jf.s.service.LvChatroomService; import com.jf.s.service.LvUsersService; import com.jf.s.util.DateUtil; import com.jf.s.util.MessUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @CrossOrigin @RestController @RequestMapping("/chat") public class LvChatController { @Resource LvChatService chatService; @Resource LvChatroomService chatroomService; @Autowired LvUsersService usersService; @RequestMapping("/getChatRooms") public MessUtil getChatRooms(Integer uid ,String cno) { MessUtil mess=new MessUtil(); if(cno!=null&&cno.trim().length()>0){ LvChatroom r=chatroomService.getById(cno); if(r==null){ r=new LvChatroom(); r.setCno(cno); r.setCts(DateUtil.getNowTime()); Integer uid1=Integer.parseInt(r.getCno().split("_")[0]); Integer uid2=Integer.parseInt(r.getCno().split("_")[1]); r.setCnos("["+uid1+"]["+uid2+"]"); chatroomService.save(r); } } List<LvChatroom> li=chatroomService.getChatRooms("["+uid+"]"); List<LvChat> cli=new ArrayList<>(); for(LvChatroom r:li){ Integer uid1=Integer.parseInt(r.getCno().split("_")[0]); Integer uid2=Integer.parseInt(r.getCno().split("_")[1]); LvUsers u=null; if(uid.equals(uid1)){ u=usersService.getById(uid2); }else{ u=usersService.getById(uid1); } LvChat c=new LvChat(); c.setUid(u.getId()); c.setFaceimg(u.getFaceimg()); c.setNickname(u.getNickname()); c.setCno(r.getCno()); cli.add(c); } //对cli去重 String cnos=""; List<LvChat> cli2=new ArrayList<>(); for( LvChat c:cli){ if(cnos.indexOf("["+c.getCno()+"]")==-1 ){ cli2.add(c); cnos+="["+c.getCno()+"]"; } } return mess.succ(cli2); } @RequestMapping("/list") public MessUtil list( LvChat o) { MessUtil mess=new MessUtil(); LvChatroom r=chatroomService.getById(o.getCno()); if(r==null){ r=new LvChatroom(); r.setCno(o.getCno()); r.setCts(DateUtil.getNowTime()); Integer uid1=Integer.parseInt(r.getCno().split("_")[0]); Integer uid2=Integer.parseInt(r.getCno().split("_")[1]); r.setCnos("["+uid1+"]["+uid2+"]"); chatroomService.save(r); } List<LvChat> li=chatService.getlistByJoin(o); return mess.succ(li); } @RequestMapping("/save") public MessUtil save(LvChat o ) { MessUtil mess=new MessUtil(); if(o.getId()==null){ o.setCts(DateUtil.getNowTime()); chatService.save(o); }else{ chatService.updateById(o); } return mess.succ(o); } @RequestMapping("/info") public MessUtil info(Integer id ) { MessUtil mess=new MessUtil(); LvChat o=chatService.getByIdJoin(id); return mess.succ(o); } }
配置websocket,和application启动类同一目录
package com.jff.xinli;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
websocket
package com.jff.xinli.websocket;
import com.alibaba.fastjson.JSONObject;
import com.jff.xinli.bean.XlChat;
import com.jff.xinli.service.XlChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint(value = "/websocket/message/{cno}")
@Component
public class MessageWebSocket {
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static CopyOnWriteArraySet<Map<String, MessageWebSocket>> webSocketSet = new CopyOnWriteArraySet<Map<String, MessageWebSocket>>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
* @throws EncodeException
* @throws IOException
*/
@OnOpen
public void onOpen(@PathParam(value = "cno") String param, Session session) throws EncodeException, IOException{
this.session = session;
Map<String, MessageWebSocket> map = new HashMap<String, MessageWebSocket>();
String name = param ;
Map<String, List<String>> listMap = session.getRequestParameterMap();
map.put(name,this);
addSocket(map, name);
}
// 添加map 到 webSocketSet,
public void addSocket(Map<String, MessageWebSocket> map, String name) {
// 删除重复的连接
for(Map<String, MessageWebSocket> item: webSocketSet){
for(String key : item.keySet()){
if (key.toString().equals(name)) {
webSocketSet.remove(item);
}
}
}
webSocketSet.add(map); //加入set中
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(){
for (Map<String, MessageWebSocket> item : webSocketSet) {
for(String key : item.keySet()){
if(item.get(key) == this){
// 删除关闭的连接
webSocketSet.remove(item);
}
}
}
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* @param session 可选的参数
* @throws EncodeException
*/
@OnMessage
public void onMessage(String message, Session session) throws EncodeException {
Map<String,Object> map = (Map<String, Object>) JSONObject.parse(message);
System.out.println("socket=message=="+message );
String cno= (String) map.get("cno");
for(Map<String, MessageWebSocket> item: webSocketSet){
for(String key : item.keySet()){
System.out.println(key +"============key");
if(key.equals(cno)){
MessageWebSocket webSocket = item.get(key);
try {
webSocket.sendMessage( message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
}
}
/**
* 发生错误时调用
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
error.printStackTrace();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException{
synchronized (this.session) {
this.session.getBasicRemote().sendText(message);
}
}
}
vue
api/common.js配置路径
export const messageSocketUrl='ws://127.0.0.1:8099/websocket/message/'
api/messageSocket.js
export default {
ws: {},
setWs: function(newWs) {
this.ws = newWs
}
}
main.js配置全局
import Vue from 'vue'
import * as echarts from 'echarts'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import messageSocket from './api/messageSocket'
Vue.prototype.$messageSocket = messageSocket
Vue.prototype.$echarts = echarts
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
import messageSocket from './api/messageSocket' Vue.prototype.$messageSocket = messageSocket
关键的是上面2行
chat.vue可代入房间号cno或者不带
<template>
<div class="about ">
<v-header />
<v-sidebar />
<div class="content-box " >
<br>
<div style="width: 95%">
<el-row >
<el-col :span="4" class=" bkk" >
<div class="kfdiv">
<table v-for="(t,i) in uli" :class="'bgg ' +(t.uid==chatuid?'selxian':'')">
<tr @click="chooseuser(t,i)">
<td class="kfw" valign="top"><img class="kffaceimg" :src="FILE_URL+t.faceimg"></td>
<td class="dibuxian"> <span class="kfname">{{t.nickname}}</span> </td>
</tr>
</table>
</div>
</el-col>
<el-col :span="20" class=" bkk">
<div class="chatdiv" id="chatgf">
<div v-for="(t,i) in cli">
<table v-if="lander.id!=t.uid" class="bgg">
<tr>
<td class="ltr" valign="top"><img :src="FILE_URL+t.faceimg" class="faceimg"></td>
<td class="lnr">
<span class="huizi">{{t.nickname}} {{t.cts}}</span><br>
<p class="lcnr">{{t.cont}}</p>
</td>
</tr>
</table>
<table v-if="lander.id==t.uid" class="bgg">
<tr>
<td class="rnr">
<span class="huizi">{{t.nickname}} {{t.cts}}</span><br>
<p class="rcnr">{{t.cont}}</p>
</td>
<td class="rtr" valign="top"><img :src="FILE_URL+t.faceimg" class="faceimg"></td>
</tr>
</table>
</div>
</div>
<el-row class="chatnr " >
<el-col :span="22" >
<el-input v-model="context" placeholder="请输入您的内容"></el-input>
</el-col>
<el-col :span="2" >
<el-button :disabled=" chatuid?false:true" @click="saveC" type="success">提交</el-button>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</div>
</div>
</template>
<script>
import vHeader from "./Header.vue";
import vSidebar from "./Sidebar.vue";
import { messageSocketUrl } from '../../api/common'
import { chat_save, chat_list, chat_getChatRooms ,chat_info,users_list} from '../../api';
export default {
name: "NoticeDetail",
components: {
vHeader,vSidebar
},
data() {
return {
cno:'',
FILE_URL:'',
context:'',
chatuid:'',
lander:{},
islogin:'',
uli:[],
cli:[],
isfirst:true,
}
},
methods:{
getInfo(chatid){
chat_info({id:chatid}).then((res) => {
if(res.data.status==1){
this.cli.push(res.data.obj);
this.gobottom();
}else{
this.$message.info('消息发送失败')
}
})
},
sendMessage(msg) {
let that = this;
console.log(that.$messageSocket.ws);
console.log("发送信息", msg);
that.$messageSocket.ws.send(msg);
// if (that.$messageSocket.ws && that.$messageSocket.ws.readyState == 1) {
// console.log("发送信息", msg);
// that.$messageSocket.ws.send(msg);
// } else {
// that.ws = new WebSocket(messageSocketUrl + this.cno);
// that.$messageSocket.setWs(that.ws);
// setTimeout(() => {
// console.log("setTimeout发送信息", msg);
// that.$messageSocket.ws.send(msg);
// }, 2000)
// }
},
saveC() {
if ( this.context.trim().length==0) {
this.$message.error('请输入内容');
return ;
}
chat_save({uid:this.lander.id, cont: this.context ,cno:this.cno}).then((res) => {
if(res.data.status==1){
this.context='';
this.sendMessage( JSON.stringify(res.data.obj));
}else{
this.$message.info(res.data.msg);
}
})
},
gobottom(){
setTimeout(()=>{
let scrollTarget = document.getElementById("chatgf");
scrollTarget.scrollTop=scrollTarget.scrollHeight;
},500)
},
getcli(){
chat_list({cno: this.cno}).then((res) => {
if(res.data.status==1){
this.cli=res.data.obj;
if(this.isfirst){
this.gobottom();
this.isfirst=false;
}
}else{
this.$message.info(res.data.msg);
}
})
},
getuli(){
chat_getChatRooms({ uid:this.lander.id,cno:this.cno}).then((res) => {
if(res.data.status==1){
this.uli=res.data.obj;
let index = ( this.uli || []).findIndex((item) => item.cno === this.cno);
if(index>-1){
this.chooseuser(this.uli[index],index);
}
}else{
this.$message.info(res.data.msg);
}
})
},
chooseuser(t,i){
this.chatuid=t.uid;
this.cno=t.cno;
let that=this;
that.ws = new WebSocket(messageSocketUrl + this.cno);
that.$messageSocket.setWs(that.ws);
that.$messageSocket.ws.onmessage = function(msg) {
console.log(msg.data,"socket接收到的消息")
let m=JSON.parse(msg.data);
that.getInfo(m.id)
};
this. getcli();
},
getkfli(){
users_list({role:'admin',state:1}).then((res) => {
this.uli=[];
if(res.data.status==1){
let li=res.data.obj;
for(let i=0;i<li.length;i++){
let o=li[i];
let cno=this.lander.id+'_'+o.id;
if(parseInt(this.lander.id)>parseInt(o.id))cno=o.id+'_'+this.lander.id;
o.uid=o.id;
o.cno=cno;
this.uli.push(o)
}
console.log(this.uli)
}else{
this.$message.info(res.data.msg);
}
})
},
},mounted() {
this.FILE_URL=process.env.VUE_APP_API_ROOT;
this.lander=JSON.parse(localStorage.loginUser);
if( this.$route.query.cno) {
this.cno = this.$route.query.cno;
this.getuli();
}
if(this.$route.query.seltype=='qt'){
this.getkfli();
}
if(this.$route.query.seltype=='kf'){
this.getuli();
}
},
watch:{
$route:function(value){
//已建立回话的前提,直接跳转回话
if(value.query.cno){
this.cno =value.query.cno;
this.getuli();
}
//固定客服,前台咨询,查客服表
if(value.query.seltype=='qt'){
this.getkfli();
}
//客服后台
if(value.query.seltype=='kf'){
this.getuli();
}
//如果就是好盆友聊天请直接调用this.getuli();
}
},
deactivated() {
},destroyed() {
}
}
</script>
<style scoped>
.bgg{width: 100%;margin-bottom: 10px;}
.bkk{border: 1px solid #888;border-radius:10px;height:500px;}
.chatdiv{height: 440px; overflow-y: auto;padding: 10px;}
.chatnr{height: 50px;}
.faceimg{width: 50px;height: 50px;border-radius: 50%; }
.lnr{ text-align: left; }
.huizi{color: #666;font-size: 13px;}
.lcnr{background-color: #dddddd;padding: 10px;max-width: 80%;display: inline-block;border-radius: 10px;}
.ltr{width: 60px}
.rtr{width: 60px;text-align: right;}
.rnr{text-align: right;}
.rcnr{background-color: #2f7bbf;padding: 10px;max-width: 80%;color: #fff;display: inline-block;text-align: left;border-radius: 10px;}
.kfdiv{overflow-y: auto;padding: 10px 0px;height: 100%;}
.kffaceimg{width: 40px;height: 40px;border-radius: 50%; }
.kfw{width: 50px;}
.kfname{font-size: 13px;color:#333;}
.dibuxian{border-bottom: 1px solid #8888;}
.selxian{background-color:#ddd;}
</style>
谷歌部分功能受限,可以用国内两个浏览器测试
可以上传图片的vue
<template>
<div class=" ">
<div class=" " >
<br>
<div style="width: 100%">
<el-row >
<el-col :span="4" class=" bkk" >
<div class="kfdiv">
<table v-for="(t,i) in uli" :class="'bgg ' +(t.uid==chatuid?'selxian':'')">
<tr >
<td class="kfw" valign="top"><img @click="chooseuser(t,i)" class="kffaceimg" :src="FILE_URL+t.faceimg"></td>
<td class="dibuxian"> <span class="kfname" @click="chooseuser(t,i)">{{t.nickname}}</span><el-tag type="danger" size="mini" v-if="ctype=='hy' " @click="delhandle(t)" >删除</el-tag> </td>
</tr>
</table>
</div>
</el-col>
<el-col :span="20" class=" bkk">
<div class="chatdiv" id="chatgf">
<div v-for="(t,i) in cli">
<table v-if="lander.id!=t.uid" class="bgg">
<tr>
<td class="ltr" valign="top"><img :src="FILE_URL+t.faceimg" class="faceimg"></td>
<td class="lnr">
<span class="huizi">{{t.nickname}} {{t.cts}}</span><br>
<p class="lcnr" v-if="t.cctype=='text'">{{t.cont}}</p>
<p class="lcnr" v-if="t.cctype=='img'"> <img :src="FILE_URL+t.cont" style="max-width: 100%;"></p>
</td>
</tr>
</table>
<table v-if="lander.id==t.uid" class="bgg">
<tr>
<td class="rnr">
<span class="huizi">{{t.nickname}} {{t.cts}}</span><br>
<p class="rcnr" v-if="t.cctype=='text'">{{t.cont}}</p>
<p class="rcnr" v-if="t.cctype=='img'"> <img :src="FILE_URL+t.cont" style="max-width: 100%;"></p>
</td>
<td class="rtr" valign="top"><img :src="FILE_URL+t.faceimg" class="faceimg"></td>
</tr>
</table>
</div>
</div>
<el-upload
v-show="false"
ref="uploadRef"
drag
:before-upload="beforeUploadFile"
:show-file-list="false"
:action=FILE_ACTION
:on-success="handleFileSuccess"
accept="image/*"
:multiple="true">
</el-upload>
<el-row class="chatnr " >
<el-col :span="20" >
<el-input v-model="context" placeholder="请输入您的内容"></el-input>
</el-col>
<el-col :span="4" >
<el-button :disabled=" chatuid?false:true" @click="uploadC" icon="el-icon-upload" type="info"></el-button>
<el-button :disabled=" chatuid?false:true" @click="saveC" type="success">提交</el-button>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</div>
</div>
</template>
<script>
import PubSub from 'pubsub-js'
import { messageSocketUrl } from '../../api/common'
import {chat_save, chat_list, chat_getChatRooms, chat_info, chat_del} from '../../api';
export default {
name: "Chat",
props:{
cno:{
type:String,
default:'',
},
ctype:{
type:String,
default:'',
},
},
components: {
},
data() {
return {
inv:null,
context:'',
chatuid:'',
FILE_ACTION:'',
FILE_URL:'',
lander:{},
islogin:'',
uli:[],
cli:[],
isfirst:true,
}
},
methods:{
delhandle(row){
this.$confirm('确定删除该好友?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
chat_del({cno: row.cno}).then((res) => {
let data = res.data;
if(data.status==1){
this.getuli();
}else{
this.$message.error(data.msg);
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
uploadC(){
// 通过 ref 获取 el-upload 组件实例
const uploadInstance = this.$refs.uploadRef;
if (uploadInstance) {
// 找到 el-upload 中的 input 元素
const inputElement = uploadInstance.$el.querySelector('input[type="file"]');
if (inputElement) {
// 触发 input 元素的点击事件
inputElement.click();
}
}
},
beforeUploadFile(){
this.loading = this.$loading({
lock: true,
text: "上传中,请稍等,,,,",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.5)",
});
},
handleFileSuccess(res) {
this.loading.close();
console.log(res)
if( res.status==1){
let img=res.obj ;
let o={uid:this.lander.id, cont: img ,cno:this.cno,cctype:'img'};
chat_save(o).then((res) => {
if(res.data.status==1){
this.isfirst=true;
this.sendMessage( JSON.stringify(res.data.obj));
}else{
this.$message.info(res.data.msg);
}
})
}else{
this. $message.error( '上传失败' );
}
},
getInfo(chatid){
chat_info({id:chatid}).then((res) => {
if(res.data.status==1){
this.cli.push(res.data.obj);
this.gobottom();
}else{
this.$message.info('消息发送失败')
}
})
},
sendMessage(msg) {
let that = this;
console.log(that.$messageSocket.ws);
console.log("发送信息", msg);
that.$messageSocket.ws.send(msg);
// if (that.$messageSocket.ws && that.$messageSocket.ws.readyState == 1) {
// console.log("发送信息", msg);
// that.$messageSocket.ws.send(msg);
// } else {
// that.ws = new WebSocket(messageSocketUrl + this.cno);
// that.$messageSocket.setWs(that.ws);
// setTimeout(() => {
// console.log("setTimeout发送信息", msg);
// that.$messageSocket.ws.send(msg);
// }, 2000)
// }
},
saveC() {
if ( this.context.trim().length==0) {
this.$message.error('请输入内容');
return ;
}
let o={uid:this.lander.id, cont: this.context ,cno:this.cno,cctype:'text'};
chat_save(o).then((res) => {
if(res.data.status==1){
this.context='';
this.isfirst=true;
this.sendMessage( JSON.stringify(res.data.obj));
}else{
this.$message.info(res.data.msg);
}
})
},
gobottom(){
setTimeout(()=>{
let scrollTarget = document.getElementById("chatgf");
scrollTarget.scrollTop=scrollTarget.scrollHeight;
},500)
},
getcli(){
chat_list({cno: this.cno}).then((res) => {
if(res.data.status==1){
this.cli=res.data.obj;
if(this.isfirst){
this.gobottom();
this.isfirst=false;
}
}else{
this.$message.info(res.data.msg);
}
})
},
getuli(){
let o={ uid:this.lander.id,cno:this.cno};
if(this.ctype=='hy'){
o.isfriends=1;
}
chat_getChatRooms(o).then((res) => {
if(res.data.status==1){
this.uli=res.data.obj;
let index = ( this.uli || []).findIndex((item) => item.cno === this.cno);
if(index>-1){
this.chooseuser(this.uli[index],index);
}
if(this.ctype=='one'){
let u=this.uli[index];
this.uli=[];
this.uli.push(u);
}
}else{
this.$message.info(res.data.msg);
}
})
},
chooseuser(t,i){
this.chatuid=t.uid;
this.cno=t.cno;
let that=this;
that.ws = new WebSocket(messageSocketUrl + this.cno);
that.$messageSocket.setWs(that.ws);
that.$messageSocket.ws.onmessage = function(msg) {
console.log(msg.data,"socket接收到的消息")
let m=JSON.parse(msg.data);
that.getInfo(m.id)
};
this. getcli();
},
},mounted() {
this.FILE_URL=process.env.VUE_APP_API_ROOT
this.FILE_ACTION=process.env.VUE_APP_API_ROOT+'/common/upimg?type=chat' ;
this.lander=JSON.parse(localStorage.loginUser);
PubSub.subscribe('chat_cno_ctype',(msg,index)=>{
if(index){
let arr=index.split('@#@')
this.cno=arr[0];
this.ctype=arr[1];
this.getuli();
}
});
this.getuli();
this.inv=setInterval(()=>{
this. getcli();
},1000*5 )
},
deactivated() {
if(this.inv !=null) clearInterval(this.inv)
},destroyed() {
if(this.inv !=null) clearInterval(this.inv)
}
}
</script>
<style scoped>
.bgg{width: 100%;margin-bottom: 10px;}
.bkk{border: 1px solid #888;border-radius:10px;height:500px;}
.chatdiv{height: 440px; overflow-y: auto;padding: 10px;}
.chatnr{height: 50px;}
.faceimg{width: 50px;height: 50px;border-radius: 50%; }
.lnr{ text-align: left; }
.huizi{color: #666;font-size: 13px;}
.lcnr{background-color: #dddddd;padding: 10px;max-width: 80%;display: inline-block;border-radius: 10px;}
.ltr{width: 60px}
.rtr{width: 60px;text-align: right;}
.rnr{text-align: right;}
.rcnr{background-color: #2f7bbf;padding: 10px;max-width: 80%;color: #fff;display: inline-block;text-align: left;border-radius: 10px;}
.kfdiv{overflow-y: auto;padding: 10px 0px;height: 100%;}
.kffaceimg{width: 40px;height: 40px;border-radius: 50%; }
.kfw{width: 50px;}
.kfname{font-size: 13px;color:#333;}
.dibuxian{border-bottom: 1px solid #8888;}
.selxian{background-color:#ddd;}
</style>
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
暂无评论,快来写一下吧
展开评论
他的专栏
他感兴趣的技术


java
vue
springboot
Mysql
ssm
小程序
uniapp
js和jquery