Browse Source

优化:web端缓存存储以会话为单位

master
xsx 2 years ago
parent
commit
f28571a6f8
  1. 4
      im-uniapp/App.vue
  2. 15
      im-uniapp/components/chat-item/chat-item.vue
  3. 2
      im-uniapp/pages/common/user-info.vue
  4. 30
      im-uniapp/store/chatStore.js
  5. 170
      im-web/src/store/chatStore.js
  6. 2
      im-web/src/view/Chat.vue
  7. 2
      im-web/src/view/Friend.vue
  8. 6
      im-web/src/view/Group.vue

4
im-uniapp/App.vue

@ -356,6 +356,10 @@
url: "/pages/chat/chat"
})
} else {
uni.showToast({
title: '您的登陆信息已失效,请重新登陆',
icon: 'none'
})
//
// #ifdef H5
uni.navigateTo({

15
im-uniapp/components/chat-item/chat-item.vue

@ -17,7 +17,7 @@
</view>
<view class="chat-content">
<view class="chat-at-text">{{atText}}</view>
<view class="chat-send-name" v-show="chat.sendNickName">{{chat.sendNickName+':&nbsp;'}}</view>
<view class="chat-send-name" v-if="isShowSendName">{{chat.sendNickName+':&nbsp;'}}</view>
<rich-text class="chat-content-text" :nodes="$emo.transform(chat.lastContent)"></rich-text>
<uni-badge v-if="chat.unreadCount>0" size="small" :max-num="99" :text="chat.unreadCount" />
</view>
@ -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 "[有人@我]"

2
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;

30
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)
},

170
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;

2
im-web/src/view/Chat.vue

@ -12,7 +12,7 @@
</div>
<el-scrollbar class="chat-list-items">
<div v-for="(chat,index) in chatStore.chats" :key="index">
<chat-item v-show="chat.showName.includes(searchText)" :chat="chat" :index="index"
<chat-item v-show="!chat.delete&&chat.showName.includes(searchText)" :chat="chat" :index="index"
@click.native="onActiveItem(index)" @delete="onDelItem(index)" @top="onTop(index)"
:active="chat === chatStore.activeChat"></chat-item>
</div>

2
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'

6
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();

Loading…
Cancel
Save