Browse Source

客服转接

master
[yxf] 11 hours ago
parent
commit
5caf461a4c
  1. 209
      im-uniapp/pages/chat/chat-box.vue
  2. 530
      im-uniapp/store/chatStore.js

209
im-uniapp/pages/chat/chat-box.vue

@ -133,6 +133,10 @@ export default {
isReceipt: false, // isReceipt: false, //
scrollMsgIdx: 0, // scrollMsgIdx: 0, //
chatTabBox: 'none', chatTabBox: 'none',
currentTargetId: null, //
currentChatType: 'PRIVATE',
// activeChatIdx: 0,
_activeChatIdx: 0, //
showRecord: false, showRecord: false,
chatMainHeight: 800, // chatMainHeight: 800, //
keyboardHeight: 290, // keyboardHeight: 290, //
@ -181,6 +185,8 @@ export default {
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
// //
const chat = this.chat; const chat = this.chat;
// const chat = this.chatStore.chats[this.activeChatIdx];
if (!chat) return;
// //
let tmpMessage = this.buildTmpMessage(msgInfo); let tmpMessage = this.buildTmpMessage(msgInfo);
this.chatStore.insertMessage(tmpMessage, chat); this.chatStore.insertMessage(tmpMessage, chat);
@ -330,6 +336,8 @@ export default {
this.fillTargetId(msgInfo, this.chat.targetId); this.fillTargetId(msgInfo, this.chat.targetId);
// //
const chat = this.chat; const chat = this.chat;
// const chat = this.chatStore.chats[this.activeChatIdx];
if (!chat) return;
// //
let tmpMessage = this.buildTmpMessage(msgInfo); let tmpMessage = this.buildTmpMessage(msgInfo);
this.chatStore.insertMessage(tmpMessage, chat); this.chatStore.insertMessage(tmpMessage, chat);
@ -555,6 +563,8 @@ export default {
} }
// //
const chat = this.chat; const chat = this.chat;
// const chat = this.chatStore.chats[this.activeChatIdx];
if (!chat) return;
// //
this.chatStore.deleteMessage(msgInfo, chat); this.chatStore.deleteMessage(msgInfo, chat);
// //
@ -1002,22 +1012,26 @@ export default {
}, },
computed: { computed: {
chat() { chat() {
// store chat if (!this.currentTargetId) return null;
if (!this.chatStore.chats || this.chatStore.chats.length === 0) { return this.chatStore.chats.find(c =>
return null; c.targetId === this.currentTargetId &&
} c.type === this.currentChatType
const idx = this.activeChatIdx; ) || null;
return this.chatStore.chats[idx] || this.chatStore.chats[0]; },
},
activeChatIdx: { activeChatIdx: {
get() { get() { return this._activeChatIdx || 0; },
return this._activeChatIdx || 0; set(val) { this._activeChatIdx = val; }
}, },
set(val) {
this._activeChatIdx = val; // activeChatIdx: {
} // get() {
}, // return this._activeChatIdx || 0;
// },
// set(val) {
// this._activeChatIdx = val;
// }
// },
mine() { mine() {
return this.userStore.userInfo; return this.userStore.userInfo;
@ -1036,9 +1050,13 @@ export default {
} }
return title; return title;
}, },
messageAction() { // messageAction() {
return `/message/${this.chat.type.toLowerCase()}/send`; // return `/message/${this.chat.type.toLowerCase()}/send`;
}, // },
messageAction() {
if (!this.chat) return '';
return `/message/${this.chat.type.toLowerCase()}/send`;
},
messageSize() { messageSize() {
if (!this.chat || !this.chat.messages) { if (!this.chat || !this.chat.messages) {
return 0; return 0;
@ -1119,120 +1137,63 @@ export default {
} }
}, },
async onLoad(options) { async onLoad(options) {
const chatIdx = options.chatIdx !== undefined ? parseInt(options.chatIdx) : 0;
//
uni.showLoading({
title: '加载中...',
mask: true
});
try { try {
// uni.showLoading({ title: '加载中...', mask: true });
let retryCount = 0;
const maxRetry = 30; // 3 let targetId = null;
let type = 'PRIVATE';
// chats
while ((!this.chatStore.chats || this.chatStore.chats.length === 0) && retryCount < maxRetry) { //
await new Promise(resolve => setTimeout(resolve, 100)); if (options.targetId) {
retryCount++; targetId = Number(options.targetId);
} type = options.type || 'PRIVATE';
//
if (!this.chatStore.chats || this.chatStore.chats.length === 0) {
if (this.chatStore.loadChat) {
await this.chatStore.loadChat();
}
//
await new Promise(resolve => setTimeout(resolve, 500));
}
//
if (!this.chatStore.chats || this.chatStore.chats.length === 0) {
//
const cached = uni.getStorageSync('chat_chats');
if (cached && cached.length > 0) {
this.chatStore.chats = cached;
} else {
throw new Error('暂无聊天数据');
}
}
//
this.chat = this.chatStore.chats[chatIdx] || this.chatStore.chats[0];
if (!this.chat || !this.chat.targetId) {
// throw new Error('');
}
uni.hideLoading();
// ...
// 20
let size = this.messageSize;
this.showMinIdx = size > 20 ? size - 20 : 0;
//
this.readedMessage()
//
if (this.isGroup) {
this.loadGroup(this.chat.targetId);
} else { } else {
this.loadFriend(this.chat.targetId); //
this.loadReaded(this.chat.targetId) if (this.friendStore.friends.length === 0) await this.friendStore.loadFriend();
const first = this.friendStore.friends[0];
if (!first) return uni.showToast({ title: '暂无好友', icon: 'none' });
targetId = first.id;
}
await this.chatStore.loadChat();
await new Promise(r => setTimeout(r, 300));
//
let chat = this.chatStore.chats.find(c => c.type === type && c.targetId === targetId);
if (!chat) {
const friend = this.friendStore.findFriend(targetId) || this.friendStore.friends[0];
chat = {
targetId, type,
showName: friend?.nickName || '客服',
headImage: friend?.headImage || '',
isDnd: false, lastContent: '',
lastSendTime: Date.now(), unreadCount: 0, messages: []
};
this.chatStore.chats.unshift(chat);
} }
// // ID
this.chatStore.activeChat(chatIdx); this.currentTargetId = targetId;
this.currentChatType = type;
//
this.isReceipt = false; await this.$nextTick();
this.isInBottom = true;
this.newMessageSize = 0; //
this.maxTmpId = 0; this.readedMessage();
this.loadFriend(targetId);
// this.loadReaded(targetId);
this.listenKeyBoard(); this.listenKeyBoard();
//
this.windowHeight = uni.getSystemInfoSync().windowHeight; this.windowHeight = uni.getSystemInfoSync().windowHeight;
this.screenHeight = uni.getSystemInfoSync().screenHeight; this.screenHeight = uni.getSystemInfoSync().screenHeight;
this.reCalChatMainHeight(); this.reCalChatMainHeight();
this.$nextTick(() => { this.$nextTick(() => this.scrollToBottom());
this.windowHeight = uni.getSystemInfoSync().windowHeight;
this.reCalChatMainHeight(); } catch (err) {
this.scrollToBottom(); console.error('错误:', err);
// #ifdef H5 } finally {
this.initHeight = window.innerHeight;
const chatBox = document.getElementById('chatBox')
if (chatBox) {
chatBox.addEventListener('touchmove', e => {
e.preventDefault()
}, { passive: false });
}
// #endif
});
} catch (error) {
uni.hideLoading(); uni.hideLoading();
console.error('进入聊天页面失败:', error);
uni.showToast({
title: error.message || '加载失败,请稍后重试',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack({
delta: 1,
fail: () => {
uni.switchTab({
url: "/pages/chat/chat"
});
}
});
}, 1500);
} }
}, },
onUnload() { onUnload() {

530
im-uniapp/store/chatStore.js

@ -6,23 +6,19 @@ import useUserStore from './userStore';
let cacheChats = []; let cacheChats = [];
export default defineStore('chatStore', { export default defineStore('chatStore', {
state: () => { state: () => ({
return { chats: [],
chats: [], privateMsgMaxId: 0,
privateMsgMaxId: 0, groupMsgMaxId: 0,
groupMsgMaxId: 0, loading: false
loading: false }),
}
},
actions: { actions: {
initChats(chatsData) { initChats(chatsData) {
cacheChats = []; cacheChats = [];
this.chats = []; this.chats = [];
for (let chat of chatsData.chats) { for (let chat of chatsData.chats) {
chat.stored = false; chat.stored = false;
// 暂存至缓冲区
cacheChats.push(JSON.parse(JSON.stringify(chat))); cacheChats.push(JSON.parse(JSON.stringify(chat)));
// 加载期间显示只前15个会话做做样子,一切都为了加快初始化时间
if (this.chats.length < 15) { if (this.chats.length < 15) {
this.chats.push(chat); this.chats.push(chat);
} }
@ -31,18 +27,15 @@ export default defineStore('chatStore', {
this.groupMsgMaxId = chatsData.groupMsgMaxId || 0; this.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
}, },
openChat(chatInfo) { openChat(chatInfo) {
let chats = this.curChats; let chats = this.chats;
let chat = null; let chat = null;
for (let idx in chats) { for (let idx in chats) {
if (chats[idx].type == chatInfo.type && if (chats[idx].type == chatInfo.type && chats[idx].targetId === chatInfo.targetId) {
chats[idx].targetId === chatInfo.targetId) {
chat = chats[idx]; chat = chats[idx];
// 放置头部 this.moveTop(idx);
this.moveTop(idx)
break; break;
} }
} }
// 创建会话
if (chat == null) { if (chat == null) {
chat = { chat = {
targetId: chatInfo.targetId, targetId: chatInfo.targetId,
@ -65,323 +58,265 @@ export default defineStore('chatStore', {
} }
}, },
activeChat(idx) { activeChat(idx) {
let chats = this.curChats;
if (idx >= 0) { if (idx >= 0) {
chats[idx].unreadCount = 0; this.chats[idx] = { ...this.chats[idx], unreadCount: 0 };
} }
}, },
resetUnreadCount(chatInfo) { resetUnreadCount(chatInfo) {
let chats = this.curChats; this.chats = this.chats.map(chat => {
for (let idx in chats) { if (chat.type == chatInfo.type && chat.targetId == chatInfo.targetId) {
if (chats[idx].type == chatInfo.type && return { ...chat, unreadCount: 0, atMe: false, atAll: false, stored: false };
chats[idx].targetId == chatInfo.targetId) {
chats[idx].unreadCount = 0;
chats[idx].atMe = false;
chats[idx].atAll = false;
chats[idx].stored = false;
this.saveToStorage();
} }
} return chat;
});
this.saveToStorage();
}, },
readedMessage(pos) { readedMessage(pos) {
let chat = this.findChatByFriend(pos.friendId); let chat = this.findChatByFriend(pos.friendId);
if (!chat) return; if (!chat) return;
for (let idx = chat.readedMessageIdx; idx < chat.messages.length; idx++) { let messages = [...chat.messages];
let m = chat.messages[idx]; let changed = false;
for (let idx = chat.readedMessageIdx; idx < messages.length; idx++) {
let m = messages[idx];
if (m.id && 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) { if (!pos.maxId || m.id <= pos.maxId) {
m.status = MESSAGE_STATUS.READED messages[idx] = { ...m, status: MESSAGE_STATUS.READED };
chat.readedMessageIdx = idx; chat.readedMessageIdx = idx;
chat.stored = false; changed = true;
} }
} }
} }
if (!chat.stored) { if (changed) {
chat.messages = messages;
chat.stored = false;
this.saveToStorage(); this.saveToStorage();
} }
}, },
cleanMessage(idx) { cleanMessage(idx) {
let chat = this.curChats[idx]; let chat = { ...this.chats[idx] };
chat.lastContent = ''; chat.lastContent = '';
chat.hotMinIdx = 0; chat.hotMinIdx = 0;
chat.unreadCount = 0; chat.unreadCount = 0;
chat.atMe = false; chat.atMe = false;
chat.atAll = false; chat.atAll = false;
chat.stored = false chat.stored = false;
chat.messages = []; chat.messages = [];
this.chats[idx] = chat;
this.saveToStorage(true); this.saveToStorage(true);
}, },
removeChat(idx) { removeChat(idx) {
let chats = this.curChats; this.chats[idx] = { ...this.chats[idx], delete: true, stored: false };
chats[idx].delete = true;
chats[idx].stored = false;
this.saveToStorage(); this.saveToStorage();
}, },
removePrivateChat(userId) { removePrivateChat(userId) {
let chats = this.curChats; this.chats = this.chats.map(chat => {
for (let idx in chats) { if (chat.type == 'PRIVATE' && chat.targetId == userId) {
if (chats[idx].type == 'PRIVATE' && return { ...chat, delete: true, stored: false };
chats[idx].targetId == userId) {
this.removeChat(idx);
} }
} return chat;
});
this.saveToStorage();
}, },
removeGroupChat(groupId) { removeGroupChat(groupId) {
let chats = this.curChats; this.chats = this.chats.map(chat => {
for (let idx in chats) { if (chat.type == 'GROUP' && chat.targetId == groupId) {
if (chats[idx].type == 'GROUP' && return { ...chat, delete: true, stored: false };
chats[idx].targetId == groupId) {
this.removeChat(idx);
} }
} return chat;
});
this.saveToStorage();
}, },
moveTop(idx) { moveTop(idx) {
if (this.loading) { if (this.loading) return;
return;
}
let chats = this.curChats;
if (idx > 0) { if (idx > 0) {
let chat = chats[idx]; let chats = [...this.chats];
chats.splice(idx, 1); let chat = chats.splice(idx, 1)[0];
chat = { ...chat, lastSendTime: new Date().getTime(), stored: false };
chats.unshift(chat); chats.unshift(chat);
chat.lastSendTime = new Date().getTime(); this.chats = chats;
chat.stored = false;
this.saveToStorage(); this.saveToStorage();
} }
}, },
insertMessage(msgInfo, chatInfo) { insertMessage(msgInfo, chatInfo) {
// 获取对方id或群id
let type = chatInfo.type; let type = chatInfo.type;
// 记录消息的最大id
if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) { if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) {
this.privateMsgMaxId = msgInfo.id; this.privateMsgMaxId = msgInfo.id;
} }
if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) { if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) {
this.groupMsgMaxId = msgInfo.id; this.groupMsgMaxId = msgInfo.id;
} }
// 如果是已存在消息,则覆盖旧的消息数据
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return;
let message = this.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
console.log("message:", message) chat.messages = chat.messages.map(m =>
Object.assign(message, msgInfo); (m.id === msgInfo.id || m.tmpId === msgInfo.tmpId) ? { ...m, ...msgInfo } : m
);
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage();
return; return;
} }
// 会话列表内容
if (msgInfo.type == MESSAGE_TYPE.IMAGE) { chat = { ...chat };
chat.lastContent = "[图片]"; if (msgInfo.type == MESSAGE_TYPE.IMAGE) chat.lastContent = "[图片]";
} else if (msgInfo.type == MESSAGE_TYPE.FILE) { else if (msgInfo.type == MESSAGE_TYPE.FILE) chat.lastContent = "[文件]";
chat.lastContent = "[文件]"; else if (msgInfo.type == MESSAGE_TYPE.AUDIO) chat.lastContent = "[语音]";
} else if (msgInfo.type == MESSAGE_TYPE.AUDIO) { else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) chat.lastContent = "[语音通话]";
chat.lastContent = "[语音]"; else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) chat.lastContent = "[视频通话]";
} else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) { else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL || msgInfo.type == MESSAGE_TYPE.TIP_TEXT) {
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.lastContent = msgInfo.content;
} }
chat.lastSendTime = msgInfo.sendTime; chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = msgInfo.sendNickName; chat.sendNickName = msgInfo.sendNickName;
// 未读加1
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) {
chat.unreadCount++; chat.unreadCount++;
} }
// 是否有人@我
if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds && if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds && msgInfo.status != MESSAGE_STATUS.READED) {
msgInfo.status != MESSAGE_STATUS.READED) {
const userStore = useUserStore(); const userStore = useUserStore();
let userId = userStore.userInfo.id; let userId = userStore.userInfo.id;
if (msgInfo.atUserIds.indexOf(userId) >= 0) { if (msgInfo.atUserIds.indexOf(userId) >= 0) chat.atMe = true;
chat.atMe = true; if (msgInfo.atUserIds.indexOf(-1) >= 0) chat.atAll = true;
}
if (msgInfo.atUserIds.indexOf(-1) >= 0) {
chat.atAll = true;
}
} }
// 间隔大于10分钟插入时间显示
if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) { let messages = [...chat.messages];
chat.messages.push({ if (!chat.lastTimeTip || chat.lastTimeTip < msgInfo.sendTime - 600 * 1000) {
sendTime: msgInfo.sendTime, messages.push({ sendTime: msgInfo.sendTime, type: MESSAGE_TYPE.TIP_TIME });
type: MESSAGE_TYPE.TIP_TIME,
});
chat.lastTimeTip = msgInfo.sendTime; chat.lastTimeTip = msgInfo.sendTime;
} }
// 插入消息 messages.push(msgInfo);
chat.messages.push(msgInfo); chat.messages = messages;
chat.stored = false; chat.stored = false;
this.chats = this.chats.map(c => c.type === chat.type && c.targetId === chat.targetId ? chat : c);
this.saveToStorage(); this.saveToStorage();
}, },
updateMessage(msgInfo, chatInfo) { updateMessage(msgInfo, chatInfo) {
// 获取对方id或群id
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let message = this.findMessage(chat, msgInfo); if (!chat) return;
if (message) {
// 属性拷贝 this.chats = this.chats.map(c => {
Object.assign(message, msgInfo); if (c.type === chat.type && c.targetId === chat.targetId) {
chat.stored = false; return {
this.saveToStorage(); ...c,
} messages: c.messages.map(m =>
(m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId)
? { ...m, ...msgInfo }
: m
),
stored: false
};
}
return c;
});
this.saveToStorage();
}, },
deleteMessage(msgInfo, chatInfo) { deleteMessage(msgInfo, chatInfo) {
let isColdMessage = false;
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let delIdx = -1; if (!chat) return;
for (let idx in chat.messages) {
// 已经发送成功的,根据id删除 this.chats = this.chats.map(c => {
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) { if (c.type === chat.type && c.targetId === chat.targetId) {
delIdx = idx; let messages = c.messages.filter(m =>
break; !(m.id && m.id === msgInfo.id) && !(m.tmpId && m.tmpId === msgInfo.tmpId)
} );
// 正在发送中的消息可能没有id,只有临时id return { ...c, messages, stored: false };
if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
delIdx = idx;
break;
}
}
if (delIdx >= 0) {
chat.messages.splice(delIdx, 1);
if (delIdx < chat.hotMinIdx) {
isColdMessage = true;
chat.hotMinIdx--;
}
if (delIdx < chat.readedMessageIdx) {
chat.readedMessageIdx--;
} }
chat.stored = false; return c;
this.saveToStorage(isColdMessage); });
} this.saveToStorage();
}, },
recallMessage(msgInfo, chatInfo) { recallMessage(msgInfo, chatInfo) {
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return; if (!chat) return;
let isColdMessage = false;
// 要撤回的消息id
let id = msgInfo.content; let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName; let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
for (let idx in chat.messages) {
let m = chat.messages[idx]; this.chats = this.chats.map(c => {
if (m.id && m.id == id) { if (c.type === chat.type && c.targetId === chat.targetId) {
// 改造成一条提示消息 let messages = c.messages.map(m => {
m.status = MESSAGE_STATUS.RECALL; if (m.id && m.id == id) {
m.content = name + "撤回了一条消息"; return {
m.type = MESSAGE_TYPE.TIP_TEXT ...m,
// 会话列表 status: MESSAGE_STATUS.RECALL,
chat.lastContent = m.content; content: name + "撤回了一条消息",
chat.lastSendTime = msgInfo.sendTime; type: MESSAGE_TYPE.TIP_TEXT
chat.sendNickName = ''; };
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { }
chat.unreadCount++; if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
} return {
isColdMessage = idx < chat.hotMinIdx; ...m,
} quoteMessage: { ...m.quoteMessage, content: "引用内容已撤回", status: MESSAGE_STATUS.RECALL, type: MESSAGE_TYPE.TIP_TEXT }
// 被引用的消息也要撤回 };
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { }
m.quoteMessage.content = "引用内容已撤回"; return m;
m.quoteMessage.status = MESSAGE_STATUS.RECALL; });
m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT return { ...c, messages, stored: false };
} }
} return c;
chat.stored = false; });
this.saveToStorage(isColdMessage); this.saveToStorage();
}, },
updateChatFromFriend(friend) { updateChatFromFriend(friend) {
let chat = this.findChatByFriend(friend.id) this.chats = this.chats.map(chat => {
if (chat && (chat.headImage != friend.headImage || if (chat.type === 'PRIVATE' && chat.targetId === friend.id) {
chat.showName != friend.nickName)) { return { ...chat, headImage: friend.headImage, showName: friend.nickName, stored: false };
// 更新会话中的群名和头像 }
chat.headImage = friend.headImage; return chat;
chat.showName = friend.nickName; });
chat.stored = false; this.saveToStorage();
this.saveToStorage();
}
}, },
updateChatFromUser(user) { updateChatFromUser(user) {
let chat = this.findChatByFriend(user.id); this.chats = this.chats.map(chat => {
// 更新会话中的昵称和头像 if (chat.type === 'PRIVATE' && chat.targetId === user.id) {
if (chat && (chat.headImage != user.headImageThumb || return { ...chat, headImage: user.headImageThumb, showName: user.nickName, stored: false };
chat.showName != user.nickName)) { }
chat.headImage = user.headImageThumb; return chat;
chat.showName = user.nickName; });
chat.stored = false; this.saveToStorage();
this.saveToStorage();
}
}, },
updateChatFromGroup(group) { updateChatFromGroup(group) {
let chat = this.findChatByGroup(group.id); this.chats = this.chats.map(chat => {
if (chat && (chat.headImage != group.headImageThumb || if (chat.type === 'GROUP' && chat.targetId === group.id) {
chat.showName != group.showGroupName)) { return { ...chat, headImage: group.headImageThumb, showName: group.showGroupName, stored: false };
// 更新会话中的群名称和头像 }
chat.headImage = group.headImageThumb; return chat;
chat.showName = group.showGroupName; });
chat.stored = false; this.saveToStorage();
this.saveToStorage();
}
}, },
setLoading(loading) { setLoading(loading) {
this.loading = loading; this.loading = loading;
}, },
setDnd(chatInfo, isDnd) { setDnd(chatInfo, isDnd) {
let chat = this.findChat(chatInfo); this.chats = this.chats.map(chat => {
if (chat) { if (chat.type === chatInfo.type && chat.targetId === chatInfo.targetId) {
chat.isDnd = isDnd; return { ...chat, isDnd };
} }
return chat;
});
}, },
refreshChats() { refreshChats() {
let chats = cacheChats || this.chats; let chats = cacheChats || this.chats;
// 更新会话免打扰状态
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const groupStore = useGroupStore(); const groupStore = useGroupStore();
chats.forEach(chat => { chats.forEach(chat => {
if (chat.type == 'PRIVATE') { if (chat.type == 'PRIVATE') {
let friend = friendStore.findFriend(chat.targetId); let friend = friendStore.findFriend(chat.targetId);
if (friend) { if (friend) chat.isDnd = friend.isDnd;
chat.isDnd = friend.isDnd
}
} else if (chat.type == 'GROUP') { } else if (chat.type == 'GROUP') {
let group = groupStore.findGroup(chat.targetId); let group = groupStore.findGroup(chat.targetId);
if (group) { if (group) chat.isDnd = group.isDnd;
chat.isDnd = group.isDnd
}
}
})
// 排序
chats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
// #ifndef APP-PLUS
// h5和小程序的stroge一般只有5m,大约只能存储1w条消息,所以可能需要清理部分历史消息
const storageInfo = uni.getStorageInfoSync();
console.log(`storage缓存: ${storageInfo.currentSize} KB`)
// 空间不足(大于3mb)时,清理这个设备登录过其他账户的消息
if (storageInfo && storageInfo.currentSize > 3000) {
console.log("storage空间不足,清理其他用户缓存..")
this.cleanOtherUserCache();
}
// 保证消息总数量不超过3000条,每个会话不超过500条
this.fliterMessage(chats, 3000, 500);
// #endif
// 记录热数据索引位置
chats.forEach(chat => {
if (!chat.hotMinIdx || chat.hotMinIdx != chat.messages.length) {
chat.hotMinIdx = chat.messages.length;
chat.stored = false;
} }
}); });
// 将消息一次性装载回来 chats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
this.chats = chats; this.chats = chats;
// 清空缓存,不再使用
cacheChats = null; cacheChats = null;
// 消息持久化
this.saveToStorage(true); this.saveToStorage(true);
}, },
fliterMessage(chats, maxTotalSize, maxPerChatSize) { fliterMessage(chats, maxTotalSize, maxPerChatSize) {
// 每个会话只保留maxPerChatSize条消息
let remainTotalSize = 0; let remainTotalSize = 0;
chats.forEach(chat => { chats.forEach(chat => {
if (chat.messages.length > maxPerChatSize) { if (chat.messages.length > maxPerChatSize) {
@ -389,13 +324,10 @@ export default defineStore('chatStore', {
chat.messages = chat.messages.slice(idx); chat.messages = chat.messages.slice(idx);
} }
remainTotalSize += chat.messages.length; remainTotalSize += chat.messages.length;
}) });
// 保证消息总数不超过maxTotalSize条,否则继续清理
if (remainTotalSize > maxTotalSize) { if (remainTotalSize > maxTotalSize) {
this.fliterMessage(chats, maxTotalSize, maxPerChatSize / 2); this.fliterMessage(chats, maxTotalSize, maxPerChatSize / 2);
} }
console.log("消息留存总数量:", remainTotalSize)
console.log("单会话消息数量:", maxPerChatSize)
}, },
cleanOtherUserCache() { cleanOtherUserCache() {
const userStore = useUserStore(); const userStore = useUserStore();
@ -403,163 +335,101 @@ export default defineStore('chatStore', {
const prefix = "chats-app-" + userId; const prefix = "chats-app-" + userId;
const res = uni.getStorageInfoSync(); const res = uni.getStorageInfoSync();
res.keys.forEach(key => { res.keys.forEach(key => {
// 清理其他用户的消息
if (key.startsWith("chats-app") && !key.startsWith(prefix)) { if (key.startsWith("chats-app") && !key.startsWith(prefix)) {
uni.removeStorageSync(key); uni.removeStorageSync(key);
console.log("清理key:", key)
} }
}) });
}, },
saveToStorage(withColdMessage) { saveToStorage(withColdMessage) {
// 加载中不保存,防止卡顿 if (this.loading) return;
if (this.loading) {
return;
}
const userStore = useUserStore(); const userStore = useUserStore();
let userId = userStore.userInfo.id; let userId = userStore.userInfo.id;
let key = "chats-app-" + userId; let key = "chats-app-" + userId;
let chatKeys = []; let chatKeys = [];
// 按会话为单位存储,只存储有改动的会话
this.chats.forEach((chat) => { this.chats.forEach((chat) => {
let chatKey = `${key}-${chat.type}-${chat.targetId}` let chatKey = `${key}-${chat.type}-${chat.targetId}`;
if (!chat.stored) { if (!chat.stored) {
if (chat.delete) { if (chat.delete) {
uni.removeStorageSync(chatKey); uni.removeStorageSync(chatKey);
} else { } else {
// 存储冷数据
if (withColdMessage) { if (withColdMessage) {
let coldChat = Object.assign({}, chat); let coldChat = { ...chat };
coldChat.messages = chat.messages.slice(0, chat.hotMinIdx); coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
uni.setStorageSync(chatKey, coldChat) uni.setStorageSync(chatKey, coldChat);
} }
// 存储热消息
let hotKey = chatKey + '-hot'; let hotKey = chatKey + '-hot';
let hotChat = Object.assign({}, chat); let hotChat = { ...chat };
hotChat.messages = chat.messages.slice(chat.hotMinIdx) hotChat.messages = chat.messages.slice(chat.hotMinIdx);
uni.setStorageSync(hotKey, hotChat); uni.setStorageSync(hotKey, hotChat);
} }
chat.stored = true; chat.stored = true;
} }
if (!chat.delete) { if (!chat.delete) chatKeys.push(chatKey);
chatKeys.push(chatKey); });
}
})
// 会话核心信息
let chatsData = { let chatsData = {
privateMsgMaxId: this.privateMsgMaxId, privateMsgMaxId: this.privateMsgMaxId,
groupMsgMaxId: this.groupMsgMaxId, groupMsgMaxId: this.groupMsgMaxId,
chatKeys: chatKeys chatKeys: chatKeys
} };
uni.setStorageSync(key, chatsData) uni.setStorageSync(key, chatsData);
// 清理已删除的会话 this.chats = this.chats.filter(chat => !chat.delete);
this.chats = this.chats.filter(chat => !chat.delete)
}, },
clear(state) { clear() {
cacheChats = []; cacheChats = [];
this.chats = []; this.chats = [];
this.privateMsgMaxId = 0; this.privateMsgMaxId = 0;
this.groupMsgMaxId = 0; this.groupMsgMaxId = 0;
this.loadingPrivateMsg = false;
this.loadingGroupMsg = false;
}, },
loadChat() { loadChat() {
return new Promise((resolve, reject) => { return new Promise((resolve) => {
let userStore = useUserStore(); let userStore = useUserStore();
let userId = userStore.userInfo.id; let userId = userStore.userInfo.id;
let chatsData = uni.getStorageSync("chats-app-" + userId) let chatsData = uni.getStorageSync("chats-app-" + userId);
if (chatsData) { if (chatsData && chatsData.chatKeys) {
if (chatsData.chatKeys) { chatsData.chats = [];
chatsData.chats = []; chatsData.chatKeys.forEach(key => {
chatsData.chatKeys.forEach(key => { let coldChat = uni.getStorageSync(key);
let coldChat = uni.getStorageSync(key); let hotChat = uni.getStorageSync(key + '-hot');
let hotChat = uni.getStorageSync(key + '-hot'); if (!coldChat && !hotChat) return;
if (!coldChat && !hotChat) { if (hotChat) {
return; hotChat.messages.forEach(msg => {
} if (msg.status == MESSAGE_STATUS.SENDING) msg.status = MESSAGE_STATUS.FAILED;
// 防止消息一直处在发送中状态 });
hotChat && hotChat.messages.forEach(msg => { }
if (msg.status == MESSAGE_STATUS.SENDING) { let chat = { ...coldChat, ...hotChat };
msg.status = MESSAGE_STATUS.FAILED if (hotChat && coldChat) {
} chat.messages = [...(coldChat.messages || []), ...(hotChat.messages || [])];
}) }
// 冷热消息合并 chat.readedMessageIdx = chat.readedMessageIdx || 0;
let chat = Object.assign({}, coldChat, hotChat); chatsData.chats.push(chat);
if (hotChat && coldChat) { });
chat.messages = coldChat.messages.concat(hotChat.messages)
}
// 历史版本没有readedMessageIdx字段,做兼容一下
chat.readedMessageIdx = chat.readedMessageIdx || 0;
chatsData.chats.push(chat);
})
}
this.initChats(chatsData); this.initChats(chatsData);
} }
resolve() resolve();
}) });
} }
}, },
getters: { getters: {
curChats: (state) => { curChats: (state) => state.chats, // ✅ 修复
if (cacheChats && state.loading) {
return cacheChats;
}
return state.chats;
},
findChatIdx: (state) => (chat) => { findChatIdx: (state) => (chat) => {
let chats = state.curChats; return state.chats.findIndex(c => c.type == chat.type && c.targetId === chat.targetId);
for (let idx in chats) {
if (chats[idx].type == chat.type &&
chats[idx].targetId === chat.targetId) {
chat = state.chats[idx];
return idx;
}
}
}, },
findChat: (state) => (chat) => { findChat: (state) => (chat) => {
let chats = state.curChats; return state.chats.find(c => c.type == chat.type && c.targetId === chat.targetId);
let idx = state.findChatIdx(chat);
return chats[idx];
}, },
findChatByFriend: (state) => (fid) => { findChatByFriend: (state) => (fid) => {
return state.curChats.find(chat => chat.type == 'PRIVATE' && return state.chats.find(c => c.type == 'PRIVATE' && c.targetId == fid);
chat.targetId == fid)
}, },
findChatByGroup: (state) => (gid) => { findChatByGroup: (state) => (gid) => {
return state.curChats.find(chat => chat.type == 'GROUP' && return state.chats.find(c => c.type == 'GROUP' && c.targetId == gid);
chat.targetId == gid)
}, },
findMessage: (state) => (chat, msgInfo) => { findMessage: (state) => (chat, msgInfo) => {
if (!chat) { if (!chat) return null;
return null;
}
// 通过id判断
if (msgInfo.id) { if (msgInfo.id) {
for (let idx = chat.messages.length - 1; idx >= 0; idx--) { return chat.messages.find(m => m.id === msgInfo.id);
let m = chat.messages[idx];
if (m.id && msgInfo.id == m.id) {
return m;
}
// 如果id比要查询的消息小,说明没有这条消息
if (m.id && m.id < msgInfo.id) {
break;
}
}
} }
// 正在发送中的临时消息可能没有id,只有tmpId
if (msgInfo.selfSend && msgInfo.tmpId) { if (msgInfo.selfSend && msgInfo.tmpId) {
for (let idx = chat.messages.length - 1; idx >= 0; idx--) { return chat.messages.find(m => m.tmpId === msgInfo.tmpId);
let m = chat.messages[idx];
if (!m.selfSend || !m.tmpId) {
continue;
}
if (msgInfo.tmpId == m.tmpId) {
return m;
}
// 如果id比要查询的消息小,说明没有这条消息
if (m.tmpId && m.tmpId < msgInfo.tmpId) {
break;
}
}
} }
return null; return null;
} }

Loading…
Cancel
Save