You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

437 lines
13 KiB

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;
}
}
});