diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index a30cd85..c103597 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -356,6 +356,10 @@ url: "/pages/chat/chat" }) } else { + uni.showToast({ + title: '您的登陆信息已失效,请重新登陆', + icon: 'none' + }) // 跳转到登录页 // #ifdef H5 uni.navigateTo({ diff --git a/im-uniapp/components/chat-item/chat-item.vue b/im-uniapp/components/chat-item/chat-item.vue index db6f955..21b3e06 100644 --- a/im-uniapp/components/chat-item/chat-item.vue +++ b/im-uniapp/components/chat-item/chat-item.vue @@ -17,7 +17,7 @@ {{atText}} - {{chat.sendNickName+': '}} + {{chat.sendNickName+': '}} @@ -44,6 +44,7 @@ } }, methods: { + showChatBox() { uni.navigateTo({ url: "/pages/chat/chat-box?chatIdx=" + this.index @@ -51,6 +52,18 @@ } }, computed: { + isShowSendName() { + if (!this.chat.sendNickName) { + return false; + } + let size = this.chat.messages.length; + if (size == 0) { + return false; + } + // 只有群聊的普通消息需要显示名称 + let lastMsg = this.chat.messages[size - 1]; + return this.$msgType.isNormal(lastMsg.type) + }, atText() { if (this.chat.atMe) { return "[有人@我]" diff --git a/im-uniapp/pages/common/user-info.vue b/im-uniapp/pages/common/user-info.vue index 366a034..4c6c25c 100644 --- a/im-uniapp/pages/common/user-info.vue +++ b/im-uniapp/pages/common/user-info.vue @@ -81,7 +81,7 @@ onDelFriend(){ uni.showModal({ title: "确认删除", - content: `确认要删除与 '${this.userInfo.nickName}'的好友关系吗?`, + content: `确认删除 '${this.userInfo.nickName}',并删除聊天记录吗?`, success: (res)=> { if(res.cancel) return; diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index 7a4faa0..6ae6eef 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -92,11 +92,11 @@ export default defineStore('chatStore', { readedMessage(pos) { let chat = this.findChatByFriend(pos.friendId); chat.messages.forEach((m) => { - if (m.selfSend && m.status < MESSAGE_STATUS.RECALL) { + if (m.id && m.selfSend && m.status < MESSAGE_STATUS.RECALL) { // pos.maxId为空表示整个会话已读 if (!pos.maxId || m.id <= pos.maxId) { m.status = MESSAGE_STATUS.READED - chats.stored = false; + chat.stored = false; } } }) @@ -137,9 +137,10 @@ export default defineStore('chatStore', { let chat = chats[idx]; chats.splice(idx, 1); chats.unshift(chat); + chat.lastSendTime = new Date().getTime(); + chat.stored = false; this.saveToStorage(); } - }, insertMessage(msgInfo) { // 获取对方id或群id @@ -171,12 +172,14 @@ export default defineStore('chatStore', { chat.lastContent = "[文件]"; } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { chat.lastContent = "[语音]"; - } else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) { - chat.lastContent = msgInfo.content; } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) { chat.lastContent = "[语音通话]"; } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) { chat.lastContent = "[视频通话]"; + } else if (msgInfo.type == MESSAGE_TYPE.TEXT || + msgInfo.type == MESSAGE_TYPE.RECALL || + msgInfo.type == MESSAGE_TYPE.TIP_TEXT) { + chat.lastContent = msgInfo.content; } chat.lastSendTime = msgInfo.sendTime; chat.sendNickName = msgInfo.sendNickName; @@ -313,22 +316,23 @@ export default defineStore('chatStore', { // 按会话为单位存储,只存储有改动的会话 this.chats.forEach((chat)=>{ let chatKey = `${key}-${chat.type}-${chat.targetId}` - if(chat.delete){ - uni.removeStorageSync(chatKey); - return; - } if(!chat.stored){ - uni.setStorageSync(chatKey,chat); + if(chat.delete){ + uni.removeStorageSync(chatKey); + }else{ + uni.setStorageSync(chatKey,chat); + } + chat.stored = true; + } + if(!chat.delete){ + chatKeys.push(chatKey); } - chat.stored = true; - chatKeys.push(chatKey); }) // 会话核心信息 let chatsData = { privateMsgMaxId: this.privateMsgMaxId, groupMsgMaxId: this.groupMsgMaxId, chatKeys: chatKeys - //chats: this.chats } uni.setStorageSync(key, chatsData) }, diff --git a/im-web/src/store/chatStore.js b/im-web/src/store/chatStore.js index 826c2db..f9ff092 100644 --- a/im-web/src/store/chatStore.js +++ b/im-web/src/store/chatStore.js @@ -21,7 +21,7 @@ export default { state.chats = []; state.privateMsgMaxId = chatsData.privateMsgMaxId || 0; state.groupMsgMaxId = chatsData.groupMsgMaxId || 0; - cacheChats = chatsData.chats||[]; + cacheChats = chatsData.chats || []; // 防止图片一直处在加载中状态 cacheChats.forEach((chat) => { chat.messages.forEach((msg) => { @@ -55,7 +55,9 @@ export default { unreadCount: 0, messages: [], atMe: false, - atAll: false + atAll: false, + stored: false, + delete: false }; chats.unshift(chat); } @@ -72,26 +74,23 @@ export default { chats[idx].unreadCount = 0; chats[idx].atMe = false; chats[idx].atAll = false; + chats[idx].stored = false; + this.commit("saveToStorage"); + break; } } - this.commit("saveToStorage"); }, readedMessage(state, pos) { - let chats = this.getters.findChats(); - for (let idx in chats) { - if (chats[idx].type == 'PRIVATE' && - chats[idx].targetId == pos.friendId) { - chats[idx].messages.forEach((m) => { - if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) { - // pos.maxId为空表示整个会话已读 - if (!pos.maxId || m.id <= pos.maxId) { - m.status = MESSAGE_STATUS.READED - } - - } - }) + let chat = this.getters.findChatByFriend(pos.friendId); + chat.messages.forEach((m) => { + if (m.id && m.selfSend && m.status != MESSAGE_STATUS.RECALL) { + // pos.maxId为空表示整个会话已读 + if (!pos.maxId || m.id <= pos.maxId) { + m.status = MESSAGE_STATUS.READED + chat.stored = false; + } } - } + }) this.commit("saveToStorage"); }, removeChat(state, idx) { @@ -99,9 +98,30 @@ export default { if (chats[idx] == state.activeChat) { state.activeChat = null; } - chats.splice(idx, 1); + chats[idx].delete = true; + chats[idx].stored = false; this.commit("saveToStorage"); }, + removePrivateChat(state,friendId){ + let chats = this.getters.findChats(); + for (let idx in chats) { + if (chats[idx].type == 'PRIVATE' && + chats[idx].targetId === friendId) { + this.commit("removeChat",idx) + break; + } + } + }, + removeGroupChat(state,groupId){ + let chats = this.getters.findChats(); + for (let idx in chats) { + if (chats[idx].type == 'GROUP' && + chats[idx].targetId === groupId) { + this.commit("removeChat",idx) + break; + } + } + }, moveTop(state, idx) { // 加载中不移动,很耗性能 if (this.getters.isLoading()) { @@ -112,18 +132,11 @@ export default { let chat = chats[idx]; chats.splice(idx, 1); chats.unshift(chat); + chat.lastSendTime = new Date().getTime(); + chat.stored = false; this.commit("saveToStorage"); } }, - removePrivateChat(state, friendId) { - let chats = this.getters.findChats(); - for (let idx in chats) { - if (chats[idx].type == 'PRIVATE' && - chats[idx].targetId == friendId) { - this.commit("removeChat", idx); - } - } - }, insertMessage(state, msgInfo) { let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE'; // 记录消息的最大id @@ -142,6 +155,7 @@ export default { if (msgInfo.type == MESSAGE_TYPE.RECALL) { chat.lastContent = msgInfo.content; } + chat.stored = false; this.commit("saveToStorage"); return; } @@ -152,14 +166,14 @@ export default { chat.lastContent = "[文件]"; } else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { chat.lastContent = "[语音]"; - } else if (msgInfo.type == MESSAGE_TYPE.TEXT || - msgInfo.type == MESSAGE_TYPE.RECALL || - msgInfo.type == MESSAGE_TYPE.TIP_TEXT) { - chat.lastContent = msgInfo.content; } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) { chat.lastContent = "[语音通话]"; } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) { chat.lastContent = "[视频通话]"; + } else if (msgInfo.type == MESSAGE_TYPE.TEXT || + msgInfo.type == MESSAGE_TYPE.RECALL || + msgInfo.type == MESSAGE_TYPE.TIP_TEXT) { + chat.lastContent = msgInfo.content; } chat.lastSendTime = msgInfo.sendTime; chat.sendNickName = msgInfo.sendNickName; @@ -199,6 +213,7 @@ export default { } } chat.messages.splice(insertPos, 0, msgInfo); + chat.stored = false; this.commit("saveToStorage"); }, updateMessage(state, msgInfo) { @@ -208,6 +223,7 @@ export default { if (message) { // 属性拷贝 Object.assign(message, msgInfo); + chat.stored = false; this.commit("saveToStorage"); } }, @@ -226,31 +242,30 @@ export default { break; } } + chat.stored = false; this.commit("saveToStorage"); }, updateChatFromFriend(state, friend) { - let chats = this.getters.findChats(); - for (let i in chats) { - let chat = chats[i]; - if (chat.type == 'PRIVATE' && chat.targetId == friend.id) { - chat.headImage = friend.headImageThumb; - chat.showName = friend.nickName; - break; - } + let chat = this.getters.findChatByFriend(friend.id); + // 更新会话中的群名和头像 + if (chat && (chat.headImage != friend.headImageThumb || + chat.showName != friend.nickName)) { + chat.headImage = friend.headImageThumb; + chat.showName = friend.nickName; + chat.stored = false; + this.commit("saveToStorage") } - this.commit("saveToStorage"); }, updateChatFromGroup(state, group) { - let chats = this.getters.findChats(); - for (let i in chats) { - let chat = chats[i]; - if (chat.type == 'GROUP' && chat.targetId == group.id) { - chat.headImage = group.headImageThumb; - chat.showName = group.showGroupName; - break; - } + let chat = this.getters.findChatByGroup(group.id); + if (chat && (chat.headImage != group.headImageThumb || + chat.showName != group.showGroupName)) { + // 更新会话中的群名称和头像 + chat.headImage = group.headImageThumb; + chat.showName = group.showGroupName; + chat.stored = false; + this.commit("saveToStorage") } - this.commit("saveToStorage"); }, loadingPrivateMsg(state, loading) { state.loadingPrivateMsg = loading; @@ -282,10 +297,28 @@ export default { } let userId = userStore.state.userInfo.id; let key = "chats-" + userId; + let chatKeys = []; + // 按会话为单位存储, + state.chats.forEach((chat) => { + // 只存储有改动的会话 + let chatKey = `${key}-${chat.type}-${chat.targetId}` + if (!chat.stored) { + if (chat.delete) { + localForage.removeItem(chatKey); + } else { + localForage.setItem(chatKey, chat); + } + chat.stored = true; + } + if (!chat.delete) { + chatKeys.push(chatKey); + } + }) + // 会话核心信息 let chatsData = { privateMsgMaxId: state.privateMsgMaxId, groupMsgMaxId: state.groupMsgMaxId, - chats: state.chats + chatKeys: chatKeys } localForage.setItem(key, chatsData) }, @@ -293,7 +326,6 @@ export default { cacheChats = [] state.chats = []; state.activeChat = null; - } }, actions: { @@ -301,17 +333,27 @@ export default { return new Promise((resolve, reject) => { let userId = userStore.state.userInfo.id; let key = "chats-" + userId; - localForage.getItem(key).then((item)=>{ - let chatsData = item; - // 兼容历史数据,以后要删除 - if(!chatsData){ - chatsData = JSON.parse(localStorage.getItem(key)); + localForage.getItem(key).then((chatsData) => { + if (!chatsData) { + resolve(); } - if (chatsData) { + else if(chatsData.chats){ + // 兼容旧版本 context.commit("initChats", chatsData); + resolve(); + }else if (chatsData.chatKeys) { + const promises = []; + chatsData.chatKeys.forEach(key => { + promises.push(localForage.getItem(key)) + }) + Promise.all(promises).then(chats => { + chatsData.chats = chats.filter(o => o); + context.commit("initChats", chatsData); + resolve(); + }) } - resolve(); - }).catch(()=>{ + }).catch((e) => { + console.log("加载消息失败") reject(); }) }) @@ -349,6 +391,16 @@ export default { } return chat; }, + findChatByFriend: (state, getters) => (fid) => { + let chats = getters.findChats(); + return chats.find(chat => chat.type == 'PRIVATE' && + chat.targetId == fid) + }, + findChatByGroup: (state, getters) => (gid) => { + let chats = getters.findChats(); + return chats.find(chat => chat.type == 'GROUP' && + chat.targetId == gid) + }, findMessage: (state) => (chat, msgInfo) => { if (!chat) { return null; diff --git a/im-web/src/view/Chat.vue b/im-web/src/view/Chat.vue index bb107aa..be1be02 100644 --- a/im-web/src/view/Chat.vue +++ b/im-web/src/view/Chat.vue @@ -12,7 +12,7 @@
-
diff --git a/im-web/src/view/Friend.vue b/im-web/src/view/Friend.vue index 24f29df..c904fd3 100644 --- a/im-web/src/view/Friend.vue +++ b/im-web/src/view/Friend.vue @@ -89,7 +89,7 @@ this.loadUserInfo(friend, idx); }, onDelItem(friend, idx) { - this.$confirm(`确认要解除与 '${friend.nickName}'的好友关系吗?`, '确认解除?', { + this.$confirm(`确认删除'${friend.nickName}',并清空聊天记录吗?`, '确认解除?', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' diff --git a/im-web/src/view/Group.vue b/im-web/src/view/Group.vue index cde4c0e..77dd34e 100644 --- a/im-web/src/view/Group.vue +++ b/im-web/src/view/Group.vue @@ -172,7 +172,7 @@ }); }, onDissolve() { - this.$confirm('确认要解散群聊吗?', '确认解散?', { + this.$confirm(`确认要解散'${this.activeGroup.name}'吗?`, '确认解散?', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' @@ -183,6 +183,7 @@ }).then(() => { this.$message.success(`群聊'${this.activeGroup.name}'已解散`); this.$store.commit("removeGroup", this.activeGroup.id); + this.$store.commit("removeGroupChat", this.activeGroup.id); this.reset(); }); }) @@ -208,7 +209,7 @@ }, onQuit() { - this.$confirm('退出群聊后将不再接受群里的消息,确认退出吗?', '确认退出?', { + this.$confirm(`确认退出'${this.activeGroup.showGroupName}',并清空聊天记录吗?`, '确认退出?', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' @@ -217,6 +218,7 @@ url: `/group/quit/${this.activeGroup.id}`, method: 'delete' }).then(() => { + this.$message.success(`您已退出'${this.activeGroup.name}'`); this.$store.commit("removeGroup", this.activeGroup.id); this.$store.commit("removeGroupChat", this.activeGroup.id); this.reset();