import { defineStore } from 'pinia'; import { MESSAGE_TYPE, MESSAGE_STATUS } from '@/common/enums.js'; import useFriendStore from './friendStore.js'; import useGroupStore from './groupStore.js'; import useUserStore from './userStore'; let cacheChats = []; export default defineStore('chatStore', { state: () => ({ chats: [], privateMsgMaxId: 0, groupMsgMaxId: 0, loading: false }), actions: { initChats(chatsData) { cacheChats = []; this.chats = []; for (let chat of chatsData.chats) { chat.stored = false; cacheChats.push(JSON.parse(JSON.stringify(chat))); if (this.chats.length < 15) { this.chats.push(chat); } } this.privateMsgMaxId = chatsData.privateMsgMaxId || 0; this.groupMsgMaxId = chatsData.groupMsgMaxId || 0; }, openChat(chatInfo) { let chats = this.chats; let chat = null; for (let idx in chats) { if (chats[idx].type == chatInfo.type && chats[idx].targetId === chatInfo.targetId) { chat = chats[idx]; this.moveTop(idx); break; } } if (chat == null) { chat = { targetId: chatInfo.targetId, type: chatInfo.type, showName: chatInfo.showName, headImage: chatInfo.headImage, isDnd: chatInfo.isDnd, lastContent: "", lastSendTime: new Date().getTime(), unreadCount: 0, hotMinIdx: 0, readedMessageIdx: 0, messages: [], atMe: false, atAll: false, stored: false }; chats.unshift(chat); this.saveToStorage(); } }, activeChat(idx) { if (idx >= 0) { this.chats[idx] = { ...this.chats[idx], unreadCount: 0 }; } }, resetUnreadCount(chatInfo) { this.chats = this.chats.map(chat => { if (chat.type == chatInfo.type && chat.targetId == chatInfo.targetId) { return { ...chat, unreadCount: 0, atMe: false, atAll: false, stored: false }; } return chat; }); this.saveToStorage(); }, readedMessage(pos) { let chat = this.findChatByFriend(pos.friendId); if (!chat) return; let messages = [...chat.messages]; 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 (!pos.maxId || m.id <= pos.maxId) { messages[idx] = { ...m, status: MESSAGE_STATUS.READED }; chat.readedMessageIdx = idx; changed = true; } } } if (changed) { chat.messages = messages; chat.stored = false; this.saveToStorage(); } }, cleanMessage(idx) { let chat = { ...this.chats[idx] }; chat.lastContent = ''; chat.hotMinIdx = 0; chat.unreadCount = 0; chat.atMe = false; chat.atAll = false; chat.stored = false; chat.messages = []; this.chats[idx] = chat; this.saveToStorage(true); }, removeChat(idx) { this.chats[idx] = { ...this.chats[idx], delete: true, stored: false }; this.saveToStorage(); }, removePrivateChat(userId) { this.chats = this.chats.map(chat => { if (chat.type == 'PRIVATE' && chat.targetId == userId) { return { ...chat, delete: true, stored: false }; } return chat; }); this.saveToStorage(); }, removeGroupChat(groupId) { this.chats = this.chats.map(chat => { if (chat.type == 'GROUP' && chat.targetId == groupId) { return { ...chat, delete: true, stored: false }; } return chat; }); this.saveToStorage(); }, moveTop(idx) { if (this.loading) return; if (idx > 0) { let chats = [...this.chats]; let chat = chats.splice(idx, 1)[0]; chat = { ...chat, lastSendTime: new Date().getTime(), stored: false }; chats.unshift(chat); this.chats = chats; this.saveToStorage(); } }, insertMessage(msgInfo, chatInfo) { let type = chatInfo.type; if (msgInfo.id && type == "PRIVATE" && msgInfo.id > this.privateMsgMaxId) { this.privateMsgMaxId = msgInfo.id; } if (msgInfo.id && type == "GROUP" && msgInfo.id > this.groupMsgMaxId) { this.groupMsgMaxId = msgInfo.id; } let chat = this.findChat(chatInfo); if (!chat) return; let message = this.findMessage(chat, msgInfo); if (message) { chat.messages = chat.messages.map(m => (m.id === msgInfo.id || m.tmpId === msgInfo.tmpId) ? { ...m, ...msgInfo } : m ); chat.stored = false; this.saveToStorage(); return; } chat = { ...chat }; 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 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; if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { chat.unreadCount++; } if (!msgInfo.selfSend && chat.type == "GROUP" && msgInfo.atUserIds && msgInfo.status != MESSAGE_STATUS.READED) { const userStore = useUserStore(); let userId = userStore.userInfo.id; if (msgInfo.atUserIds.indexOf(userId) >= 0) chat.atMe = true; if (msgInfo.atUserIds.indexOf(-1) >= 0) chat.atAll = true; } let messages = [...chat.messages]; if (!chat.lastTimeTip || chat.lastTimeTip < msgInfo.sendTime - 600 * 1000) { messages.push({ sendTime: msgInfo.sendTime, type: MESSAGE_TYPE.TIP_TIME }); chat.lastTimeTip = msgInfo.sendTime; } messages.push(msgInfo); chat.messages = messages; chat.stored = false; this.chats = this.chats.map(c => c.type === chat.type && c.targetId === chat.targetId ? chat : c); this.saveToStorage(); }, updateMessage(msgInfo, chatInfo) { let chat = this.findChat(chatInfo); if (!chat) return; this.chats = this.chats.map(c => { if (c.type === chat.type && c.targetId === chat.targetId) { return { ...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) { let chat = this.findChat(chatInfo); if (!chat) return; this.chats = this.chats.map(c => { if (c.type === chat.type && c.targetId === chat.targetId) { let messages = c.messages.filter(m => !(m.id && m.id === msgInfo.id) && !(m.tmpId && m.tmpId === msgInfo.tmpId) ); return { ...c, messages, stored: false }; } return c; }); this.saveToStorage(); }, recallMessage(msgInfo, chatInfo) { let chat = this.findChat(chatInfo); if (!chat) return; let id = msgInfo.content; let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName; this.chats = this.chats.map(c => { if (c.type === chat.type && c.targetId === chat.targetId) { let messages = c.messages.map(m => { if (m.id && m.id == id) { return { ...m, status: MESSAGE_STATUS.RECALL, content: name + "撤回了一条消息", type: MESSAGE_TYPE.TIP_TEXT }; } if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { return { ...m, quoteMessage: { ...m.quoteMessage, content: "引用内容已撤回", status: MESSAGE_STATUS.RECALL, type: MESSAGE_TYPE.TIP_TEXT } }; } return m; }); return { ...c, messages, stored: false }; } return c; }); this.saveToStorage(); }, updateChatFromFriend(friend) { this.chats = this.chats.map(chat => { if (chat.type === 'PRIVATE' && chat.targetId === friend.id) { return { ...chat, headImage: friend.headImage, showName: friend.nickName, stored: false }; } return chat; }); this.saveToStorage(); }, updateChatFromUser(user) { this.chats = this.chats.map(chat => { if (chat.type === 'PRIVATE' && chat.targetId === user.id) { return { ...chat, headImage: user.headImageThumb, showName: user.nickName, stored: false }; } return chat; }); this.saveToStorage(); }, updateChatFromGroup(group) { this.chats = this.chats.map(chat => { if (chat.type === 'GROUP' && chat.targetId === group.id) { return { ...chat, headImage: group.headImageThumb, showName: group.showGroupName, stored: false }; } return chat; }); this.saveToStorage(); }, setLoading(loading) { this.loading = loading; }, setDnd(chatInfo, isDnd) { this.chats = this.chats.map(chat => { if (chat.type === chatInfo.type && chat.targetId === chatInfo.targetId) { return { ...chat, isDnd }; } return chat; }); }, refreshChats() { let chats = cacheChats || this.chats; const friendStore = useFriendStore(); const groupStore = useGroupStore(); chats.forEach(chat => { if (chat.type == 'PRIVATE') { let friend = friendStore.findFriend(chat.targetId); if (friend) chat.isDnd = friend.isDnd; } else if (chat.type == 'GROUP') { let group = groupStore.findGroup(chat.targetId); if (group) chat.isDnd = group.isDnd; } }); chats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime); this.chats = chats; cacheChats = null; this.saveToStorage(true); }, fliterMessage(chats, maxTotalSize, maxPerChatSize) { let remainTotalSize = 0; chats.forEach(chat => { if (chat.messages.length > maxPerChatSize) { let idx = chat.messages.length - maxPerChatSize; chat.messages = chat.messages.slice(idx); } remainTotalSize += chat.messages.length; }); if (remainTotalSize > maxTotalSize) { this.fliterMessage(chats, maxTotalSize, maxPerChatSize / 2); } }, cleanOtherUserCache() { const userStore = useUserStore(); const userId = userStore.userInfo.id; const prefix = "chats-app-" + userId; const res = uni.getStorageInfoSync(); res.keys.forEach(key => { if (key.startsWith("chats-app") && !key.startsWith(prefix)) { uni.removeStorageSync(key); } }); }, saveToStorage(withColdMessage) { if (this.loading) return; const userStore = useUserStore(); let userId = userStore.userInfo.id; let key = "chats-app-" + userId; let chatKeys = []; this.chats.forEach((chat) => { let chatKey = `${key}-${chat.type}-${chat.targetId}`; if (!chat.stored) { if (chat.delete) { uni.removeStorageSync(chatKey); } else { if (withColdMessage) { let coldChat = { ...chat }; coldChat.messages = chat.messages.slice(0, chat.hotMinIdx); uni.setStorageSync(chatKey, coldChat); } let hotKey = chatKey + '-hot'; let hotChat = { ...chat }; hotChat.messages = chat.messages.slice(chat.hotMinIdx); uni.setStorageSync(hotKey, hotChat); } chat.stored = true; } if (!chat.delete) chatKeys.push(chatKey); }); let chatsData = { privateMsgMaxId: this.privateMsgMaxId, groupMsgMaxId: this.groupMsgMaxId, chatKeys: chatKeys }; uni.setStorageSync(key, chatsData); this.chats = this.chats.filter(chat => !chat.delete); }, clear() { cacheChats = []; this.chats = []; this.privateMsgMaxId = 0; this.groupMsgMaxId = 0; }, loadChat() { return new Promise((resolve) => { let userStore = useUserStore(); let userId = userStore.userInfo.id; let chatsData = uni.getStorageSync("chats-app-" + userId); if (chatsData && chatsData.chatKeys) { chatsData.chats = []; chatsData.chatKeys.forEach(key => { let coldChat = uni.getStorageSync(key); let hotChat = uni.getStorageSync(key + '-hot'); if (!coldChat && !hotChat) return; if (hotChat) { hotChat.messages.forEach(msg => { if (msg.status == MESSAGE_STATUS.SENDING) msg.status = MESSAGE_STATUS.FAILED; }); } let chat = { ...coldChat, ...hotChat }; if (hotChat && coldChat) { chat.messages = [...(coldChat.messages || []), ...(hotChat.messages || [])]; } chat.readedMessageIdx = chat.readedMessageIdx || 0; chatsData.chats.push(chat); }); this.initChats(chatsData); } resolve(); }); } }, getters: { curChats: (state) => state.chats, // ✅ 修复 findChatIdx: (state) => (chat) => { return state.chats.findIndex(c => c.type == chat.type && c.targetId === chat.targetId); }, findChat: (state) => (chat) => { return state.chats.find(c => c.type == chat.type && c.targetId === chat.targetId); }, findChatByFriend: (state) => (fid) => { return state.chats.find(c => c.type == 'PRIVATE' && c.targetId == fid); }, findChatByGroup: (state) => (gid) => { return state.chats.find(c => c.type == 'GROUP' && c.targetId == gid); }, findMessage: (state) => (chat, msgInfo) => { if (!chat) return null; if (msgInfo.id) { return chat.messages.find(m => m.id === msgInfo.id); } if (msgInfo.selfSend && msgInfo.tmpId) { return chat.messages.find(m => m.tmpId === msgInfo.tmpId); } return null; } } });