From 735d9e6deb55aa5a124809c0814f7880e86b9d6e Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Sun, 5 Nov 2023 20:11:34 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E7=A7=BB=E9=99=A4uniap=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-platform/src/main/resources/application.yml | 12 ++++++------ im-server/src/main/resources/application.yml | 2 +- im-ui/src/store/index.js | 1 - im-uniapp/package.json | 8 ++++---- im-uniapp/pages/login/login.vue | 9 +++++++-- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/im-platform/src/main/resources/application.yml b/im-platform/src/main/resources/application.yml index 07678d0..a700272 100644 --- a/im-platform/src/main/resources/application.yml +++ b/im-platform/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/box-im?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true username: root - password: root + password: root123456 redis: host: 127.0.0.1 @@ -29,11 +29,11 @@ mybatis-plus: # *.xml的具体路径 - classpath*:mapper/*.xml minio: - endpoint: http://127.0.0.1:9001 #内网地址 - public: http://127.0.0.1:9001 #外网访问地址 + endpoint: http://42.194.187.243:9001 #内网地址 + public: http://42.194.187.243:9001 #外网访问地址 accessKey: admin - secretKey: 12345678 - bucketName: box-im + secretKey: admin123456 + bucketName: box-im2 imagePath: image filePath: file @@ -43,7 +43,7 @@ webrtc: jwt: accessToken: - expireIn: 1800 #半个小时 + expireIn: 1800 #半个小时 secret: MIIBIjANBgkq refreshToken: expireIn: 604800 #7天 diff --git a/im-server/src/main/resources/application.yml b/im-server/src/main/resources/application.yml index e3110a4..3ab53c4 100644 --- a/im-server/src/main/resources/application.yml +++ b/im-server/src/main/resources/application.yml @@ -12,7 +12,7 @@ websocket: port: 8878 tcpsocket: - enable: false # 暂时不开启 + enable: true # 暂时不开启 port: 8879 jwt: diff --git a/im-ui/src/store/index.js b/im-ui/src/store/index.js index 997c3d0..ba185be 100644 --- a/im-ui/src/store/index.js +++ b/im-ui/src/store/index.js @@ -25,7 +25,6 @@ export default new Vuex.Store({ this.commit("initGroupStore"); this.commit("initChatStore"); } - }, strict: process.env.NODE_ENV !== 'production' }) diff --git a/im-uniapp/package.json b/im-uniapp/package.json index da18df0..440479f 100644 --- a/im-uniapp/package.json +++ b/im-uniapp/package.json @@ -6,16 +6,16 @@ "browser":"chrome", "env": { "UNI_PLATFORM": "h5", - "BASE_URL": "http://192.168.1.5:8888", - "WS_URL": "ws://192.168.1.5:8878/im" + "BASE_URL": "http://192.168.43.6:8888", + "WS_URL": "ws://192.168.43.6:8878/im" } }, "dev-wx-mini": { "title": "开发环境-微信小程序", "env": { "UNI_PLATFORM": "mp-weixin", - "BASE_URL": "http://192.168.1.5:8888", - "WS_URL": "ws://192.168.1.5:8878/im" + "BASE_URL": "http://192.168.43.6:8888", + "WS_URL": "ws://192.168.43.6:8878/im" } }, "prod-h5": { diff --git a/im-uniapp/pages/login/login.vue b/im-uniapp/pages/login/login.vue index 65c535b..ed9dc99 100644 --- a/im-uniapp/pages/login/login.vue +++ b/im-uniapp/pages/login/login.vue @@ -20,8 +20,8 @@ return { loginForm: { terminal: 1, // APP终端 - userName: 'blue', - password: '123456' + userName: '', + password: '' }, rules: { userName: { @@ -48,6 +48,9 @@ }).then(data => { console.log("登录成功,自动跳转到聊天页面...") uni.setStorageSync("loginInfo", data); + uni.setStorageSync("userName", this.loginForm.userName); + uni.setStorageSync("password", this.loginForm.password); + // 调用App.vue的初始化方法 getApp().init() // 跳转到聊天页面 @@ -58,6 +61,8 @@ } }, onLoad() { + this.loginForm.userName = uni.getStorageSync("userName"); + this.loginForm.password = uni.getStorageSync("password"); let loginInfo = uni.getStorageSync("loginInfo"); if (loginInfo) { // 跳转到聊天页面 From 9a4fcd8e22148777095b1fda658aaaff9b926a73 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Mon, 6 Nov 2023 12:37:19 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E8=BF=98=E5=8E=9F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-platform/src/main/resources/application.yml | 2 +- im-server/src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-platform/src/main/resources/application.yml b/im-platform/src/main/resources/application.yml index a700272..6c77e0b 100644 --- a/im-platform/src/main/resources/application.yml +++ b/im-platform/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/box-im?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true username: root - password: root123456 + password: root redis: host: 127.0.0.1 diff --git a/im-server/src/main/resources/application.yml b/im-server/src/main/resources/application.yml index 3ab53c4..e3110a4 100644 --- a/im-server/src/main/resources/application.yml +++ b/im-server/src/main/resources/application.yml @@ -12,7 +12,7 @@ websocket: port: 8878 tcpsocket: - enable: true # 暂时不开启 + enable: false # 暂时不开启 port: 8879 jwt: From bf37e191cb18b00b282ed981823911887a92da95 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Mon, 6 Nov 2023 13:24:23 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=8D=A1=E9=A1=BF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-uniapp/store/chatStore.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index 0cc1a6a..3358b23 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -35,9 +35,11 @@ export default { if (state.chats[i].type == chatInfo.type && state.chats[i].targetId === chatInfo.targetId) { chat = state.chats[i]; - // 放置头部 - state.chats.splice(i, 1); - state.chats.unshift(chat); + // 放置头部(这个操作非常耗资源,正在加载消息时不执行) + if(!state.loadingPrivateMsg && !state.loadingPrivateMsg){ + state.chats.splice(i, 1); + state.chats.unshift(chat); + } break; } } From 410e4597618c7903d801117977055bb1c3e6c53f Mon Sep 17 00:00:00 2001 From: "xie.bx" Date: Mon, 6 Nov 2023 23:22:13 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=95=88=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-ui/src/view/Chat.vue | 5 ++++ im-uniapp/App.vue | 10 +++++-- im-uniapp/store/chatStore.js | 55 ++++++++++++++++++++++++---------- im-uniapp/store/friendStore.js | 1 - 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/im-ui/src/view/Chat.vue b/im-ui/src/view/Chat.vue index 68a34b0..ecd9599 100644 --- a/im-ui/src/view/Chat.vue +++ b/im-ui/src/view/Chat.vue @@ -8,6 +8,7 @@
+
@@ -96,6 +97,10 @@ .l-chat-loadding{ height: 50px; background-color: #eee; + + .chat-loading-box{ + height: 100%; + } } .l-friend-ist { diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index f7a4b71..2dddb5e 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -58,6 +58,10 @@ this.exit(); } else if (res.code != 3000) { // 重新连接 + uni.showToast({ + title: '连接已断开,尝试重新连接...', + icon: 'none', + }) wsApi.connect(); } }) @@ -66,7 +70,7 @@ store.commit("loadingPrivateMsg", true) http({ url: "/message/private/loadMessage?minId=" + minId, - method: 'get' + method: 'GET' }).then((msgInfos) => { msgInfos.forEach((msgInfo) => { msgInfo.selfSend = msgInfo.sendId == store.state.userStore.userInfo.id; @@ -76,6 +80,7 @@ this.insertPrivateMessage(friend,msgInfo); } }) + store.commit("refreshChats"); if (msgInfos.length == 100) { // 继续拉取 this.loadPrivateMessage(msgInfos[99].id); @@ -88,7 +93,7 @@ store.commit("loadingGroupMsg", true) http({ url: "/message/group/loadMessage?minId=" + minId, - method: 'get' + method: 'GET' }).then((msgInfos) => { msgInfos.forEach((msgInfo) => { msgInfo.selfSend = msgInfo.sendId == store.state.userStore.userInfo.id; @@ -98,6 +103,7 @@ this.insertGroupMessage(group,msgInfo); } }) + store.commit("refreshChats"); if (msgInfos.length == 100) { // 继续拉取 this.loadGroupMessage(msgInfos[99].id); diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index 3358b23..c961c26 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -79,7 +79,6 @@ export default { if (state.chats[idx].type == 'PRIVATE' && state.chats[idx].targetId == friendId) { state.chats[idx].messages.forEach((m) => { - console.log("readedMessage") if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) { m.status = MESSAGE_STATUS.READED } @@ -128,17 +127,20 @@ export default { break; } } - // 插入新的数据 - if (msgInfo.type == MESSAGE_TYPE.IMAGE) { - chat.lastContent = "[图片]"; - } else if (msgInfo.type == MESSAGE_TYPE.FILE) { - chat.lastContent = "[文件]"; - } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { - chat.lastContent = "[语音]"; - } else { - chat.lastContent = msgInfo.content; + + // 会话列表内容 + if(!state.loadingPrivateMsg && !state.loadingPrivateMsg){ + if (msgInfo.type == MESSAGE_TYPE.IMAGE) { + chat.lastContent = "[图片]"; + } else if (msgInfo.type == MESSAGE_TYPE.FILE) { + chat.lastContent = "[文件]"; + } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { + chat.lastContent = "[语音]"; + } else { + chat.lastContent = msgInfo.content; + } + chat.lastSendTime = msgInfo.sendTime; } - chat.lastSendTime = msgInfo.sendTime; // 未读加1 if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { chat.unreadCount++; @@ -234,6 +236,29 @@ export default { loadingGroupMsg(state, loadding) { state.loadingGroupMsg = loadding; }, + refreshChats(state){ + state.chats.forEach((chat)=>{ + if(chat.messages.length>0){ + let msgInfo = chat.messages[chat.messages.length-1]; + if (msgInfo.type == MESSAGE_TYPE.IMAGE) { + chat.lastContent = "[图片]"; + } else if (msgInfo.type == MESSAGE_TYPE.FILE) { + chat.lastContent = "[文件]"; + } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { + chat.lastContent = "[语音]"; + } else { + chat.lastContent = msgInfo.content; + } + chat.lastSendTime = msgInfo.sendTime; + }else{ + chat.lastContent = ""; + chat.lastSendTime = new Date() + } + }) + state.chats.sort((chat1, chat2) => { + return chat2.lastSendTime-chat1.lastSendTime; + }); + }, saveToStorage(state) { let userId = userStore.state.userInfo.id; let key = "chats-" + userId; @@ -242,10 +267,10 @@ export default { groupMsgMaxId: state.groupMsgMaxId, chats: state.chats } - uni.setStorage({ - key: key, - data: chatsData - }) + // uni.setStorage({ + // key: key, + // data: chatsData + // }) }, clear(state) { state.chats = []; diff --git a/im-uniapp/store/friendStore.js b/im-uniapp/store/friendStore.js index 539e99d..b13c08d 100644 --- a/im-uniapp/store/friendStore.js +++ b/im-uniapp/store/friendStore.js @@ -36,7 +36,6 @@ export default { state.friends.forEach((f) => { let userTerminal = onlineTerminals.find((o) => f.id == o.userId); if (userTerminal) { - console.log(userTerminal) f.online = true; f.onlineTerminals = userTerminal.terminals; f.onlineWeb = userTerminal.terminals.indexOf(TERMINAL_TYPE.WEB) >= 0 From 5dedc178b1e482505b02fe296b23dbfad218a691 Mon Sep 17 00:00:00 2001 From: "xie.bx" Date: Thu, 9 Nov 2023 22:40:51 +0800 Subject: [PATCH 05/14] =?UTF-8?q?ws=E9=87=8D=E8=BF=9E=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/GroupMessageServiceImpl.java | 24 ++++--- im-ui/src/api/wssocket.js | 33 +++------- im-ui/src/components/chat/ChatBox.vue | 5 +- im-ui/src/view/Home.vue | 63 ++++++++++--------- im-uniapp/App.vue | 19 ++---- im-uniapp/common/wssocket.js | 38 +++++------ 6 files changed, 86 insertions(+), 96 deletions(-) diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index 5be6caf..d13bf57 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -1,8 +1,10 @@ package com.bx.implatform.service.impl; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; @@ -198,6 +200,9 @@ public class GroupMessageServiceImpl extends ServiceImpl members = groupMemberService.findByUserId(session.getUserId()); List ids = members.stream().map(GroupMember::getGroupId).collect(Collectors.toList()); + if(CollectionUtil.isEmpty(ids)){ + return Collections.EMPTY_LIST; + } // 只能拉取最近1个月的 Date minDate = DateTimeUtils.addMonths(new Date(), -1); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); @@ -242,6 +247,16 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GroupMessage::getGroupId, groupId) + .orderByDesc(GroupMessage::getId) + .last("limit 1") + .select(GroupMessage::getId); + GroupMessage message = this.getOne(wrapper); + if(Objects.isNull(message)){ + return; + } // 推送消息给自己的其他终端 GroupMessageVO msgInfo = new GroupMessageVO(); msgInfo.setType(MessageType.READED.code()); @@ -254,14 +269,7 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); - wrapper.eq(GroupMessage::getGroupId, groupId) - .orderByDesc(GroupMessage::getId) - .last("limit 1") - .select(GroupMessage::getId); - GroupMessage message = this.getOne(wrapper); + // 记录已读消息位置 String key = StrUtil.join(":",RedisKey.IM_GROUP_READED_POSITION,groupId,session.getUserId()); redisTemplate.opsForValue().set(key, message.getId()); diff --git a/im-ui/src/api/wssocket.js b/im-ui/src/api/wssocket.js index e014edd..ef2a237 100644 --- a/im-ui/src/api/wssocket.js +++ b/im-ui/src/api/wssocket.js @@ -1,19 +1,11 @@ var websock = null; let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码 let isConnect = false; //连接标识 避免重复连接 -let wsurl = ""; -let accessToken = ""; let messageCallBack = null; -let openCallBack = null; let closeCallBack = null -let init = (url,token) => { - wsurl = url; - accessToken = token; -}; - -let connect = () => { +let connect = (wsurl,accessToken) => { try { if (isConnect) { return; @@ -25,8 +17,6 @@ let connect = () => { if (sendInfo.cmd == 0) { heartCheck.start() console.log('WebSocket登录成功') - // 登录成功才算连接完成 - openCallBack && openCallBack(); } else if (sendInfo.cmd == 1) { // 重新开启心跳定时 heartCheck.reset(); @@ -59,16 +49,16 @@ let connect = () => { websock.onerror = function() { console.log('WebSocket连接发生错误') isConnect = false; //连接断开修改标识 - reConnect(); + reconnect(wsurl,accessToken); } } catch (e) { console.log("尝试创建连接失败"); - reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接 + reconnect(wsurl,accessToken); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接 } }; //定义重连函数 -let reConnect = () => { +let reconnect = (wsurl,accessToken) => { console.log("尝试重新连接"); if (isConnect){ //如果已经连上就不在重连了 @@ -76,12 +66,12 @@ let reConnect = () => { } rec && clearTimeout(rec); rec = setTimeout(function() { // 延迟5秒重连 避免过多次过频繁请求重连 - connect(); - }, 5000); + connect(wsurl,accessToken); + }, 15000); }; //设置关闭连接 -let close = () => { - websock && websock.close(); +let close = (code) => { + websock && websock.close(code); }; @@ -136,20 +126,15 @@ let onMessage = (callback) => { } -let onOpen = (callback) => { - openCallBack = callback; -} - let onClose = (callback) => { closeCallBack = callback; } // 将方法暴露出去 export { - init, connect, + reconnect, close, sendMessage, - onOpen, onMessage, onClose } diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue index e4f06b4..5fd5e1e 100644 --- a/im-ui/src/components/chat/ChatBox.vue +++ b/im-ui/src/components/chat/ChatBox.vue @@ -512,11 +512,13 @@ // 滚到底部 this.scrollToBottom(); this.sendText = ""; + this.showSide = false; // 消息已读 this.readedMessage() // 初始状态只显示30条消息 let size = this.chat.messages.length; this.showMinIdx = size > 30 ? size - 30 : 0; + // 保持输入框焦点 this.$nextTick(() => { this.$refs.sendBox.focus(); @@ -573,7 +575,7 @@ .im-chat-box { >ul { - padding: 20px; + padding: 0 20px; li { list-style-type: none; @@ -612,6 +614,7 @@ } .send-content-area { + position: relative; display: flex; flex-direction: column; height: 100%; diff --git a/im-ui/src/view/Home.vue b/im-ui/src/view/Home.vue index d70cdbb..20b4d01 100644 --- a/im-ui/src/view/Home.vue +++ b/im-ui/src/view/Home.vue @@ -74,7 +74,7 @@ data() { return { showSettingDialog: false, - lastPlayAudioTime: new Date()-1000 + lastPlayAudioTime: new Date() - 1000 } }, methods: { @@ -84,16 +84,19 @@ this.loadPrivateMessage(this.$store.state.chatStore.privateMsgMaxId); this.loadGroupMessage(this.$store.state.chatStore.groupMsgMaxId); // ws初始化 - this.$wsApi.init(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); - this.$wsApi.connect(); - this.$wsApi.onOpen(); + this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); this.$wsApi.onMessage((cmd, msgInfo) => { if (cmd == 2) { + // 关闭ws + this.$wsApi.close(3000) // 异地登录,强制下线 - this.$message.error("您已在其他地方登陆,将被强制下线"); - setTimeout(() => { - location.href = "/"; - }, 1000) + this.$alert("您已在其他地方登陆,将被强制下线", "强制下线通知", { + confirmButtonText: '确定', + callback: action => { + location.href = "/"; + } + }); + } else if (cmd == 3) { // 插入私聊消息 this.handlePrivateMessage(msgInfo); @@ -104,20 +107,18 @@ }) this.$wsApi.onClose((e) => { console.log(e); - if (e.code == 1006) { - // 服务器主动断开 - this.$message.error("连接已断开,请重新登录"); - location.href = "/"; - } else { - this.$wsApi.connect(); + if (e.code != 3000) { + // 断线重连 + this.$message.error("连接断开,正在尝试重新连接..."); + this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); } }); }).catch((e) => { - console.log("初始化失败",e); + console.log("初始化失败", e); }) }, loadPrivateMessage(minId) { - this.$store.commit("loadingPrivateMsg",true) + this.$store.commit("loadingPrivateMsg", true) this.$http({ url: "/message/private/loadMessage?minId=" + minId, method: 'get' @@ -126,20 +127,20 @@ msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id; let friendId = msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId; let friend = this.$store.state.friendStore.friends.find((f) => f.id == friendId); - if(friend){ - this.insertPrivateMessage(friend,msgInfo); - } + if (friend) { + this.insertPrivateMessage(friend, msgInfo); + } }) if (msgInfos.length == 100) { // 继续拉取 this.loadPrivateMessage(msgInfos[99].id); - }else{ - this.$store.commit("loadingPrivateMsg",false) + } else { + this.$store.commit("loadingPrivateMsg", false) } }) }, loadGroupMessage(minId) { - this.$store.commit("loadingGroupMsg",true) + this.$store.commit("loadingGroupMsg", true) this.$http({ url: "/message/group/loadMessage?minId=" + minId, method: 'get' @@ -148,15 +149,15 @@ msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id; let groupId = msgInfo.groupId; let group = this.$store.state.groupStore.groups.find((g) => g.id == groupId); - if(group){ - this.insertGroupMessage(group,msgInfo); + if (group) { + this.insertGroupMessage(group, msgInfo); } }) if (msgInfos.length == 100) { // 继续拉取 this.loadGroupMessage(msgInfos[99].id); - }else{ - this.$store.commit("loadingGroupMsg",false) + } else { + this.$store.commit("loadingGroupMsg", false) } }) }, @@ -212,7 +213,7 @@ // 插入消息 this.$store.commit("insertMessage", msg); // 播放提示音 - if(!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED){ + if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) { this.playAudioTip(); } }, @@ -247,7 +248,7 @@ // 插入消息 this.$store.commit("insertMessage", msg); // 播放提示音 - if(!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED){ + if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) { this.playAudioTip(); } }, @@ -257,14 +258,14 @@ location.href = "/"; }, playAudioTip() { - if(new Date() - this.lastPlayAudioTime > 1000){ + if (new Date() - this.lastPlayAudioTime > 1000) { this.lastPlayAudioTime = new Date(); let audio = new Audio(); let url = require(`@/assets/audio/tip.wav`); audio.src = url; audio.play(); - } - + } + }, showSetting() { this.showSettingDialog = true; diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index 2dddb5e..715f6ac 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -28,10 +28,8 @@ }, initWebSocket() { let loginInfo = uni.getStorageSync("loginInfo") - let userId = store.state.userStore.userInfo.id; - wsApi.init(process.env.WS_URL, loginInfo.accessToken); - wsApi.connect(); - wsApi.onOpen() + wsApi.init(); + wsApi.connect(process.env.WS_URL, loginInfo.accessToken); wsApi.onMessage((cmd, msgInfo) => { if (cmd == 2) { // 异地登录,强制下线 @@ -49,20 +47,15 @@ } }); wsApi.onClose((res) => { - // 1006是服务器主动断开,3000是APP主动关闭 - if (res.code == 1006) { - uni.showToast({ - title: '连接已断开,请重新登录', - icon: 'none', - }) - this.exit(); - } else if (res.code != 3000) { + // 3000是客户端主动关闭 + if (res.code != 3000) { // 重新连接 uni.showToast({ title: '连接已断开,尝试重新连接...', icon: 'none', }) - wsApi.connect(); + let loginInfo = uni.getStorageSync("loginInfo") + wsApi.reconnect(process.env.WS_URL, loginInfo.accessToken); } }) }, diff --git a/im-uniapp/common/wssocket.js b/im-uniapp/common/wssocket.js index a724820..1f3a04a 100644 --- a/im-uniapp/common/wssocket.js +++ b/im-uniapp/common/wssocket.js @@ -1,20 +1,12 @@ let wsurl = ""; let accessToken = ""; -let openCallBack = null; let messageCallBack = null; let closeCallBack = null; let isConnect = false; //连接标识 避免重复连接 -let hasInit = false; +let rec = null; + +let init = () => { -let init = (url, token) => { - wsurl = url; - accessToken = token; - // 防止重新注册事件 - if(hasInit){ - return; - } - hasInit = true; - uni.onSocketOpen((res) => { console.log("WebSocket连接已打开"); isConnect = true; @@ -35,8 +27,6 @@ let init = (url, token) => { if (sendInfo.cmd == 0) { heartCheck.start() console.log('WebSocket登录成功') - // 登录成功才算连接完成 - openCallBack && openCallBack(); } else if (sendInfo.cmd == 1) { // 重新开启心跳定时 heartCheck.reset(); @@ -48,7 +38,6 @@ let init = (url, token) => { }) uni.onSocketClose((res) => { - console.log(res) console.log('WebSocket连接关闭') isConnect = false; //断开后修改标识 closeCallBack && closeCallBack(res); @@ -64,7 +53,9 @@ let init = (url, token) => { }) }; -let connect = ()=>{ +let connect = (url, token)=>{ + wsurl = url; + accessToken = token; if (isConnect) { return; } @@ -83,6 +74,18 @@ let connect = ()=>{ }); } +//定义重连函数 +let reconnect = (wsurl,accessToken) => { + console.log("尝试重新连接"); + if (isConnect){ + //如果已经连上就不在重连了 + return; + } + rec && clearTimeout(rec); + rec = setTimeout(function() { // 延迟15秒重连 避免过多次过频繁请求重连 + connect(wsurl,accessToken); + }, 15000); +}; //设置关闭连接 let close = () => { @@ -142,9 +145,6 @@ function onMessage(callback) { messageCallBack = callback; } -function onOpen(callback) { - openCallBack = callback; -} function onClose(callback) { closeCallBack = callback; @@ -155,9 +155,9 @@ function onClose(callback) { export { init, connect, + reconnect, close, sendMessage, onMessage, - onOpen, onClose } \ No newline at end of file From 594737af3a2eccf7892134f2c4162c5a4749c5af Mon Sep 17 00:00:00 2001 From: "xie.bx" Date: Thu, 9 Nov 2023 22:49:36 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=83=85?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-ui/src/api/emotion.js | 3 ++- im-uniapp/common/emotion.js | 2 +- im-uniapp/components/chat-item/chat-item.vue | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/im-ui/src/api/emotion.js b/im-ui/src/api/emotion.js index 86af031..c14c015 100644 --- a/im-ui/src/api/emotion.js +++ b/im-ui/src/api/emotion.js @@ -16,8 +16,9 @@ let textToImg = (emoText) => { let word = emoText.replace(/\#|\;/gi, ''); let idx = emoTextList.indexOf(word); if(idx==-1){ - return ""; + return emoText; } + return emoText; let url = require(`@/assets/emoji/${idx}.gif`); return `` } diff --git a/im-uniapp/common/emotion.js b/im-uniapp/common/emotion.js index 178909a..06b509a 100644 --- a/im-uniapp/common/emotion.js +++ b/im-uniapp/common/emotion.js @@ -18,7 +18,7 @@ let textToImg = (emoText) => { let word = emoText.replace(/\#|\;/gi, ''); let idx = emoTextList.indexOf(word); if (idx == -1) { - return ""; + return emoText; } let path = textToPath(emoText); // #ifdef MP diff --git a/im-uniapp/components/chat-item/chat-item.vue b/im-uniapp/components/chat-item/chat-item.vue index 8e0deee..19f2e6b 100644 --- a/im-uniapp/components/chat-item/chat-item.vue +++ b/im-uniapp/components/chat-item/chat-item.vue @@ -9,7 +9,7 @@ {{ chat.showName}} - + {{$date.toTimeText(chat.lastSendTime)}} From e931f24db790e74d55f0d56350b4b0b69a915e3b Mon Sep 17 00:00:00 2001 From: "xie.bx" Date: Thu, 9 Nov 2023 22:52:10 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=83=85?= =?UTF-8?q?=E6=98=BE=E7=A4=BAbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-ui/src/api/emotion.js | 1 - 1 file changed, 1 deletion(-) diff --git a/im-ui/src/api/emotion.js b/im-ui/src/api/emotion.js index c14c015..1588729 100644 --- a/im-ui/src/api/emotion.js +++ b/im-ui/src/api/emotion.js @@ -18,7 +18,6 @@ let textToImg = (emoText) => { if(idx==-1){ return emoText; } - return emoText; let url = require(`@/assets/emoji/${idx}.gif`); return `` } From 4cc8c1d0f3ff43eaefd3770d7c4fc311a20c22f1 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Sat, 11 Nov 2023 20:46:23 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E7=BE=A4=E8=81=8A@=E5=8A=9F=E8=83=BD(?= =?UTF-8?q?=E5=BC=80=E5=8F=91=E4=B8=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-ui/src/api/emotion.js | 14 +- im-ui/src/api/wssocket.js | 1 - im-ui/src/components/chat/ChatAtBox.vue | 162 ++++++++++ im-ui/src/components/chat/ChatBox.vue | 402 ++++++++++++++++-------- im-ui/src/components/common/Emotion.vue | 62 ++-- 5 files changed, 482 insertions(+), 159 deletions(-) create mode 100644 im-ui/src/components/chat/ChatAtBox.vue diff --git a/im-ui/src/api/emotion.js b/im-ui/src/api/emotion.js index 1588729..c391496 100644 --- a/im-ui/src/api/emotion.js +++ b/im-ui/src/api/emotion.js @@ -19,12 +19,22 @@ let textToImg = (emoText) => { return emoText; } let url = require(`@/assets/emoji/${idx}.gif`); - return `` + return `` } +let textToUrl = (emoText) => { + let word = emoText.replace(/\#|\;/gi, ''); + let idx = emoTextList.indexOf(word); + if(idx==-1){ + return ""; + } + let url = require(`@/assets/emoji/${idx}.gif`); + return url; +} export default { emoTextList, transform, - textToImg + textToImg, + textToUrl } diff --git a/im-ui/src/api/wssocket.js b/im-ui/src/api/wssocket.js index ef2a237..e89988d 100644 --- a/im-ui/src/api/wssocket.js +++ b/im-ui/src/api/wssocket.js @@ -20,7 +20,6 @@ let connect = (wsurl,accessToken) => { } else if (sendInfo.cmd == 1) { // 重新开启心跳定时 heartCheck.reset(); - console.log("") } else { // 其他消息转发出去 console.log("收到消息:",sendInfo); diff --git a/im-ui/src/components/chat/ChatAtBox.vue b/im-ui/src/components/chat/ChatAtBox.vue new file mode 100644 index 0000000..858cbbf --- /dev/null +++ b/im-ui/src/components/chat/ChatAtBox.vue @@ -0,0 +1,162 @@ + + + + + \ No newline at end of file diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue index 5fd5e1e..57e6b69 100644 --- a/im-ui/src/components/chat/ChatBox.vue +++ b/im-ui/src/components/chat/ChatBox.vue @@ -1,79 +1,88 @@ + \ No newline at end of file From 4a8933961157f025c3381c68926bb1ebd3168c3a Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Sun, 12 Nov 2023 12:24:45 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E7=BE=A4=E8=81=8A@=E5=8A=9F=E8=83=BD(?= =?UTF-8?q?=E5=BC=80=E5=8F=91=E4=B8=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bx/implatform/dto/GroupMessageDTO.java | 9 +- .../bx/implatform/entity/GroupMessage.java | 11 ++ .../service/IGroupMemberService.java | 1 - .../service/impl/GroupMessageServiceImpl.java | 38 +++--- .../com/bx/implatform/vo/GroupMessageVO.java | 7 ++ im-platform/src/main/resources/db/db.sql | 2 + im-ui/src/components/chat/ChatAtBox.vue | 44 ++++--- im-ui/src/components/chat/ChatBox.vue | 50 ++++---- im-ui/src/components/chat/ChatItem.vue | 81 +++++++++---- im-ui/src/store/chatStore.js | 13 +++ im-ui/src/store/friendStore.js | 1 + im-ui/src/view/Chat.vue | 30 ++--- im-ui/src/view/Friend.vue | 109 +++++++++++------- im-ui/src/view/Group.vue | 94 +++++++-------- im-ui/src/view/Home.vue | 9 +- 15 files changed, 314 insertions(+), 185 deletions(-) diff --git a/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java index 2535784..2b0ce80 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java @@ -7,6 +7,8 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; @Data @ApiModel("群聊消息DTO") @@ -16,8 +18,7 @@ public class GroupMessageDTO { @ApiModelProperty(value = "群聊id") private Long groupId; - - @Length(max=1024,message = "内容长度不得大于1024") + @Length(max=1024,message = "发送内容长度不得大于1024") @NotEmpty(message="发送内容不可为空") @ApiModelProperty(value = "发送内容") private String content; @@ -25,4 +26,8 @@ public class GroupMessageDTO { @NotNull(message="消息类型不可为空") @ApiModelProperty(value = "消息类型") private Integer type; + + @Size(max = 20,message = "一次最多只能@20个小伙伴哦") + @ApiModelProperty(value = "被@用户列表") + private List atUserIds; } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java b/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java index a94bec1..fa5fb28 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java @@ -44,6 +44,17 @@ public class GroupMessage extends Model { @TableField("send_id") private Long sendId; + /** + * 发送用户昵称 + */ + @TableField("send_nick_name") + private String sendNickName; + + /** + * @用户列表 + */ + @TableField("at_user_ids") + private String atUserIds; /** * 发送内容 */ diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java b/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java index 3611045..a4966c0 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java @@ -18,7 +18,6 @@ public interface IGroupMemberService extends IService { List findUserIdsByGroupId(Long groupId); - boolean saveOrUpdateBatch(Long groupId,List members); void removeByGroupId(Long groupId); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index d13bf57..3bab80d 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -4,12 +4,10 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; import com.bx.imcommon.contant.IMConstant; -import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.util.DateTimeUtils; import com.bx.implatform.vo.GroupMessageVO; import com.bx.imcommon.model.IMGroupMessage; @@ -30,16 +28,13 @@ import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; import com.bx.implatform.dto.GroupMessageDTO; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -64,26 +59,33 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(group.getId()); - if (!userIds.contains(session.getUserId())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法发送消息"); + // 是否在群聊里面 + GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getUserId()); + if (Objects.isNull(member)) { + throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法撤回消息"); } + // 群聊成员列表 + List userIds = groupMemberService.findUserIdsByGroupId(group.getId()); + // 不用发给自己 + userIds = userIds.stream().filter(id -> !session.getUserId().equals(id)).collect(Collectors.toList()); // 保存消息 GroupMessage msg = BeanUtils.copyProperties(dto, GroupMessage.class); msg.setSendId(session.getUserId()); msg.setSendTime(new Date()); + msg.setSendNickName(member.getAliasName()); + if(CollectionUtil.isNotEmpty(dto.getAtUserIds())){ + msg.setAtUserIds(StrUtil.join(",",dto.getAtUserIds())); + } this.save(msg); - // 不用发给自己 - userIds = userIds.stream().filter(id -> !session.getUserId().equals(id)).collect(Collectors.toList()); // 群发 GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); + msgInfo.setAtUserIds(dto.getAtUserIds()); IMGroupMessage sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); sendMessage.setRecvIds(userIds); @@ -215,7 +217,13 @@ public class GroupMessageServiceImpl extends ServiceImpl messages = this.list(wrapper); // 转成vo - List vos = messages.stream().map(m -> BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList()); + List vos = messages.stream().map(m -> { + GroupMessageVO vo = BeanUtils.copyProperties(m, GroupMessageVO.class); + // 被@用户列表 + List atIds = Arrays.asList(StrUtil.split(m.getAtUserIds(),",")); + vo.setAtUserIds(atIds.stream().map(id->Long.parseLong(id)).collect(Collectors.toList())); + return vo; + }).collect(Collectors.toList()); // 消息状态,数据库没有存群聊的消息状态,需要从redis取 List keys = ids.stream() .map(id -> String.join(":", RedisKey.IM_GROUP_READED_POSITION, id.toString(), session.getUserId().toString())) diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java index f00cccc..1f5beae 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java @@ -6,6 +6,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; +import java.util.List; @Data public class GroupMessageVO { @@ -19,12 +20,18 @@ public class GroupMessageVO { @ApiModelProperty(value = " 发送者id") private Long sendId; + @ApiModelProperty(value = " 发送者昵称") + private String sendNickName; + @ApiModelProperty(value = "消息内容") private String content; @ApiModelProperty(value = "消息内容类型 具体枚举值由应用层定义") private Integer type; + @ApiModelProperty(value = "@用户列表") + private List atUserIds; + @ApiModelProperty(value = " 状态") private Integer status; diff --git a/im-platform/src/main/resources/db/db.sql b/im-platform/src/main/resources/db/db.sql index 9cca837..2469150 100644 --- a/im-platform/src/main/resources/db/db.sql +++ b/im-platform/src/main/resources/db/db.sql @@ -67,7 +67,9 @@ create table `im_group_message`( `id` bigint not null auto_increment primary key comment 'id', `group_id` bigint not null comment '群id', `send_id` bigint not null comment '发送用户id', + `send_nick_name` varchar(255) DEFAULT '' comment '发送用户昵称', `content` text comment '发送内容', + `at_user_ids` varchar(1024) comment '@的用户id列表', `type` tinyint(1) NOT NULL comment '消息类型 0:文字 1:图片 2:文件 3:语音 10:系统提示' , `status` tinyint(1) DEFAULT 0 comment '状态 0:正常 2:撤回', `send_time` datetime DEFAULT CURRENT_TIMESTAMP comment '发送时间', diff --git a/im-ui/src/components/chat/ChatAtBox.vue b/im-ui/src/components/chat/ChatAtBox.vue index 858cbbf..0616a99 100644 --- a/im-ui/src/components/chat/ChatAtBox.vue +++ b/im-ui/src/components/chat/ChatAtBox.vue @@ -2,8 +2,7 @@
-
+
@@ -28,6 +27,9 @@ type: String, default: "" }, + ownerId: { + type: Number, + }, members: { type: Array } @@ -40,19 +42,27 @@ y: 0 }, activeIdx: 0, - showMembers:[] + showMembers: [] }; }, methods: { - init(){ - this.activeIdx = 0; + init() { this.$refs.scrollBox.wrap.scrollTop = 0; - this.showMembers=[]; - this.members.forEach((m)=>{ - if(m.aliasName.startsWith(this.searchText)){ + this.showMembers = []; + let userId = this.$store.state.userStore.userInfo.id; + let name = "全体成员"; + if (this.ownerId == userId && name.startsWith(this.searchText)) { + this.showMembers.push({ + userId: -1, + aliasName: name + }) + } + this.members.forEach((m) => { + if (m.userId != userId && m.aliasName.startsWith(this.searchText)) { this.showMembers.push(m); } }) + this.activeIdx = this.showMembers.length > 0 ? 0: -1; }, open(pos) { this.show = true; @@ -69,38 +79,41 @@ } }, moveDown() { - console.log(this.activeIdx) if (this.activeIdx < this.showMembers.length - 1) { this.activeIdx++; this.scrollToActive() } }, select() { - this.onSelectMember(this.showMembers[this.activeIdx]) + if (this.activeIdx >= 0) { + this.onSelectMember(this.showMembers[this.activeIdx]) + } + this.close(); }, scrollToActive() { - console.log(this.$refs.scrollBox.wrap) if (this.activeIdx * 35 - this.$refs.scrollBox.wrap.clientHeight > this.$refs.scrollBox.wrap.scrollTop) { this.$refs.scrollBox.wrap.scrollTop += 140; if (this.$refs.scrollBox.wrap.scrollTop > this.$refs.scrollBox.wrap.scrollHeight) { this.$refs.scrollBox.wrap.scrollTop = this.$refs.scrollBox.wrap.scrollHeight } } - if (this.activeIdx * 35 < this.$refs.scrollBox.wrap.scrollTop) { this.$refs.scrollBox.wrap.scrollTop -= 140; if (this.$refs.scrollBox.wrap.scrollTop < 0) { this.$refs.scrollBox.wrap.scrollTop = 0; } } - - }, onSelectMember(member) { this.$emit("select", member); this.show = false; } }, + computed: { + isOwner() { + return this.$store.state.userStore.userInfo.id == this.ownerId; + } + }, watch: { searchText: { handler(newText, oldText) { @@ -132,6 +145,7 @@ padding-right: 5px; background-color: #fafafa; white-space: nowrap; + box-sizing: border-box; &:hover { background-color: #eeeeee; @@ -151,7 +165,7 @@ padding-left: 10px; height: 100%; text-align: left; - line-height: 35px; + line-height: 40px; white-space: nowrap; overflow: hidden; font-size: 14px; diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue index 57e6b69..01849c8 100644 --- a/im-ui/src/components/chat/ChatBox.vue +++ b/im-ui/src/components/chat/ChatBox.vue @@ -1,5 +1,5 @@