import {defineStore} from 'pinia' import type Chat from '@/mode/Chat' import type Message from '@/mode/Message' import ChatType from '@/utils/ChatType' import GroupApi from '@/api/GroupApi' import UserApi from '../api/UserApi' import MessageType from '@/utils/MessageType' import FetchRequest from '@/api/FetchRequest' import {useSettingStore} from '@/store/settingStore' import DictUtils from '@/utils/DictUtils' import {useUserStore} from '@/store/userStore' import {useImmunityStore} from '@/store/immunityStore' import type Extend from '@/mode/Extend' import {useSysStore} from "@/store/sysStore"; import type Receipt from "@/mode/Receipt"; import {useWsStore} from "@/store/WsStore"; import ChatApi from "@/api/ChatApi"; import VimConfig from "@/config/VimConfig"; import {decryptLong2 } from '@/store/cryptoAES'; import dbApi from '@/api/DBactApi'; export interface IState { chats: Array; openChatId: string | null; last: number; quoteMessage: Message | undefined chatMessage: Map; chatLastTime: Map; chatLastMessage: Map; //未读消息id chatUnreadId: Map> } export const useChatStore = defineStore({ id: 'chat_store', state: (): IState => ({ chats: new Array(), //当前打开的聊天室id openChatId: null, //消息声音提醒时间(限流作用) last: 0, //引用消息的id quoteMessage: undefined, chatMessage: new Map(), chatLastTime: new Map(), chatLastMessage: new Map(), chatUnreadId: new Map() }), // // 开启数据缓存 persist: { enabled: true, strategies: [ { key: 'chat', storage: localStorage, paths: ['chatLastTime','chatLastMessage','chatUnreadId'] } ] }, getters: { allUnReadCount(): number { //console.log('allUnReadCount',this.chats) return this.chats.reduce((accumulator, currentValue) => accumulator + currentValue.unreadCount, 0) } }, actions: { /** * 去重 * @param chatArr 聊天室数组 */ removeDuplicateChats(chatArr: Chat[]) { return chatArr.reduce((prev: Chat[], cur: Chat) => { const has = prev.some((item) => item.id === cur.id) return has ? prev : [...prev, cur] }, []) }, /** * 插入数据库 * @param chatArr 聊天室数组 */ insertChats(chatArr: Chat[]){ chatArr.forEach((item) => { dbApi.insertchat(item); }) }, /** * 重新加载聊历史记录 */ reloadChats() { var locatList=[]; dbApi.selectchats().then((sres:any)=>{ if(sres){ //console.log('selectchats',sres); locatList=sres; } }); return Promise.all([ChatApi.topList(), ChatApi.list()]) .then((res) => { //console.log('reloadChats',res) this.chats = [] const topChats = res[0].data topChats.forEach((item) => { item.top = true }) const list = topChats.concat(res[1].data) list.forEach((item) => { item.unreadCount = (this.chatUnreadId[item.id]??[]).length }) const rlist=list.concat(locatList); //console.log(rlist); //去重 this.chats = this.removeDuplicateChats(rlist); //插入数据库 this.insertChats(this.chats); return Promise.resolve() }) }, setQuoteMessage(quoteMessage: Message | undefined) { this.quoteMessage = quoteMessage }, /** * 把一个消息推送到对应的聊天记录里面 * @param message 消息 */ pushMessage(message: Message) { //console.log('pushMessage',message); const hideIndex = 10 const chat = this.getChat(message.chatId) //所在的位置 const chatIndex = this.getChatIndex(message.chatId) //消息是在队列的后面,用户可能看不到,需要把消息移到队列的前面 if (chatIndex > hideIndex) { const topList = this.chats.filter((item) => !!item.top) // 查找已置顶元素的位置 const topIndex = topList.length if (topIndex < hideIndex) { const temp = this.chats.splice(chatIndex, 1)[0]; this.chats.splice(topIndex, 0, temp) //把消息列表更新到服务端 ChatApi.move(message.chatId) } } //说明该聊天对话框已经存在 if (chat) { this.addToMessageList(message, chat, true) } else { this.createChatRoom(message) const chat = this.getChat(message.chatId); if (chat) { this.addToMessageList(message, chat, true) } } if (message.chatId === this.openChatId && !message.mine) { const user = useUserStore().getUser(); if (chat && user) { const receipt: Receipt = { chatId: chat.id, userId: user?.id, timestamp: new Date().getTime(), type: chat.type } useWsStore().sendRead(receipt) } } }, /** * 收到后端返回的用户自己发送数据,删除本地临时数据 * @param message 消息 * @param chat 聊天室 * @param addTips 仅仅添加,不做其他操作(true:提醒 false:不提醒) */ delLocalMessageList(message: Message) { const chat = this.getChat(message.chatId) if (chat) { const messageList = this.getChatMessage(chat.id) //执行清除操作 const len = messageList.findIndex((n:Message) => { // @ts-ignore return n.localtime > message.localtime }) messageList.splice(len,1); this.chatMessage.set(chat.id, messageList) } }, /** * 把数据插入到消息的列表,有序插入 * @param list list * @param message 消息 * @param chat 聊天室 * @param addTips 仅仅添加,不做其他操作(true:提醒 false:不提醒) */ insertMessage(list: Message[], message: Message, chat: Chat, addTips: boolean = true): void { //重复数据,不予处理 const repeat = list.findIndex((item) => { return item.id === message.id }) if (repeat > -1) { return } //console.log('insertMessage',message) var content=decryptLong2(message.content); if(content){ message.content=content; } var extend=message.extend; if((typeof extend)=='string'){ //console.log('typeof extend==string'); try { message.extend=JSON.parse(extend); } catch (e) { message.extend=undefined; // 如果 jsonString 不是有效的 JSON,会进入这里 } } else{ //console.log('typeof extend!=string'); } //console.log('insertMessage1',message) if (addTips && !message.mine && this.openChatId !== chat.id && ((message.fromId != useUserStore().getUser()?.id && useImmunityStore().immunityList.indexOf(message.chatId) === -1) || (message.type === ChatType.GROUP && this.isAtMine(message.extend)))) { // @ts-ignore this.chatLastMessage[chat.id] = message.content // @ts-ignore this.chatLastTime[chat.id] = message.timestamp if (!this.chatUnreadId[chat.id]) { this.chatUnreadId[chat.id] = [] } if(!this.chatUnreadId[chat.id].includes(message.id)){ this.chatUnreadId[chat.id].push(message.id) } chat.unreadCount = this.chatUnreadId[chat.id].length //console.log('chat.unreadCount',chat.unreadCount) this.messageTips(message) } else if (message.fromId == useUserStore().getUser()?.id) { // @ts-ignore this.chatLastMessage[chat.id] = message.content // @ts-ignore this.chatLastTime[chat.id] = message.timestamp } //如果新消息的时间比历史数据的时间小 const len = list.findIndex((n) => { // @ts-ignore return n.timestamp > message.timestamp }) //消息是在队列的中间,不在最后 if (len > -1) { list.splice(len, 0, message) } else { list.push(message) } }, /** * 当前用户是否被@ * @param extend 扩展信息 */ isAtMine(extend: Extend | undefined): boolean { const user = useUserStore().getUser() //@所有人 if (extend && extend.atAll && user) { return true } //@指定用户 if (extend && extend.atUserIds && user) { return extend.atUserIds.indexOf(user.id) > -1 } return false }, /** * 创建一个新聊天室 * @param message message * @private 私有方法 */ createChatRoom(message: Message) { //先占位,后加载 const chat: Chat = { id: message.chatId, name: '加载中...', avatar: '', type: message.type, unreadCount: 0, isLoading: false, loaded: true } // @ts-ignore this.chatLastMessage[chat.id] = message.content // @ts-ignore this.chatLastTime[chat.id] = message.timestamp this.newChat(chat) if (message.type === ChatType.GROUP) { GroupApi.get(message.chatId).then((res) => { this.updateChat(chat.id, res.data.name, res.data.avatar, false) }) } else { UserApi.getUser(message.mine ? message.chatId : message.fromId).then((res) => { this.updateChat(chat.id, res.data.name, res.data.avatar, false) }) } }, /** * 重置未读消息计数 */ reset() { this.chats.forEach((item: Chat) => { item.unreadCount = 0 this.chatUnreadId[item.id] = [] }) }, /** * 打开一个聊天对话框 * @param chat chat */ openChat(chat: Chat) { let hasChat = false this.chats.forEach((item: Chat) => { //聊天对话框已经存在 if (item.id === chat.id) { item.unreadCount = 0 this.chatUnreadId[item.id] = [] hasChat = true } }) //新增一个新聊天对话框 if (!hasChat) { chat.unreadCount = 0 this.chatUnreadId[chat.id] = [] //添加到聊天列表第一个 this.newChat(chat) } }, /** * 根据聊天室的ID 获取他的index * @param id 聊天室的ID */ getChatIndex(id: string) { let i = -1 this.chats.forEach((item: Chat, index: number) => { if (item.id === id) { i = index } }) return i }, /** * 根据聊天室的ID 获取聊天室 * @param id 聊天室的ID */ getChat(id: string): null | Chat { let chat: null | Chat = null this.chats.forEach((item: Chat) => { if (item.id === id) { chat = item } }) return chat }, /** * 退出清除chatMessage */ clearMessage(): void { this.chatMessage = new Map() }, /** * 设置打开的chatId */ setOpenChatId(id: string | null) { this.openChatId = id }, /** * 限制聊天记录的数组的长度 * @param message 新增的聊天消息 * @param chat 聊天室 * @param addTips 是否提醒 */ addToMessageList(message: Message, chat: Chat, addTips: boolean = true) { const messageList = this.getChatMessage(chat.id) this.insertMessage(messageList, message, chat, addTips) this.chatMessage.set(chat.id, messageList) }, /** * 获取聊天消息 */ getChatMessage(chatId: string) { return this.chatMessage.get(chatId) ?? [] }, /** * 删除聊天 * @param id 聊天室的ID */ delChat(id: string) { this.chats.splice(this.getChatIndex(id), 1) ChatApi.delete(id) }, /** * 更新聊天室信息 * @param id 聊天室id * @param name 名称 * @param avatar 头像 * @param updateUnreadCount 是否更新未读消息数 * @param updateServer 是否更新服务器 */ updateChat(id: string, name: string, avatar: string, updateUnreadCount: boolean = true, updateServer: boolean = true) { this.chats.forEach((item: Chat) => { if (item.id === id) { item.name = name item.avatar = avatar if (updateUnreadCount) { item.unreadCount = 0 this.chatUnreadId[item.id] = [] } if (updateServer) { ChatApi.update(item) } } }) }, /** * 新增聊天室 * @param chat 聊天室 */ newChat(chat: Chat) { const items = this.chats const topList = items.filter((item) => item.top) // 查找已置顶元素的位置 const topIndex = topList.length if (this.chats.findIndex((item) => item.id === chat.id) === -1) { items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的后面 ChatApi.add(chat) } }, /** * 撤回消息 * @param message 消息 */ backMessage(message: Message) { this.chatMessage.get(message.chatId)?.forEach((item) => { if (item.id === message.id) { item.content = '该消息已被撤回' item.messageType = MessageType.event } }) }, /** * 撤回消息 * @param message 消息 */ deMessage(message: Message) { let dechatId=''; if(message.mine){ dechatId = message.chatId } else{ dechatId = message.fromId } const messages = this.chatMessage.get(dechatId) console.log('deMessage',message) messages?.forEach((item) => { //删除id 一样的消息 if (item.id === message.id) { console.log(item) messages?.splice(messages?.indexOf(item), 1); dbApi.deleteLocalmsg(message); if(this.chatLastTime[message.chatId]==message.timestamp){ this.chatLastMessage[message.chatId]=''; } } }) }, /** * 置顶聊天室 * @param id 聊天室的ID */ topChat(id: string) { const items = this.chats const itemIndex = this.getChatIndex(id) // 查找对应元素的索引 const chat = JSON.parse(JSON.stringify(this.chats[itemIndex])) if (itemIndex !== -1) { items.splice(itemIndex, 1) // 先从原数组中删除该元素 const topIndex = items.findIndex((item) => !!item.top) // 查找已置顶元素的位置 if (topIndex !== -1) { items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的前面 } else { items.unshift(chat) // 如果不存在已置顶元素,则将该元素插入数组最前面 } chat.top = true // 标记该元素已置顶 } ChatApi.top(id) }, /** * 实现取消置顶功能 * @param id 聊天室的ID */ cancelTop(id: string) { const items = this.chats const itemIndex = this.getChatIndex(id) // 查找对应元素的索引 const chat = JSON.parse(JSON.stringify(this.chats[itemIndex])) if (itemIndex !== -1 && chat.top) { chat.top = false // 标记该元素已取消置顶 const topList = items.filter((item) => !!item.top) // 查找已置顶元素的位置 const topIndex = topList.length if (topIndex !== 0) { items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的后面 } else { items.push(chat) // 如果不存在已置顶元素,则将该元素插入数组末尾 } items.splice(itemIndex, 1) // 最后从原位置删除该元素 } ChatApi.cancelTop(id) }, /** * 消息提醒,限流2秒 */ messageTips: function (message: Message) { const now = Date.now() if (now - this.last >= 1000) { this.last = now if (useSettingStore().setting?.canSoundRemind === DictUtils.YES) { // 创建音频对象并播放 // const innerAudioContext = uni.createInnerAudioContext(); // innerAudioContext.src = `${FetchRequest.getHost()}${VimConfig.soundPath}`; // innerAudioContext.play() //#ifdef APP-PLUS //只提醒友聊,如果想提示群聊,去掉 && message.type === ChatType.FRIEND if (VimConfig.openUniPush && !useSysStore().show && message.type === ChatType.FRIEND) { let content = MessageType.text === message.messageType ? message.content : '' uni.createPushMessage({ title: '您有一条新消息', content: content, sound: 'system', fail: fail => { console.log(fail); } }) } // #endif } } }, /** * 设置已读读消息时间 */ setLastReadTime(receipt: Receipt) { this.chats.forEach((item: Chat) => { if (receipt.userId === item.id) { item.lastReadTime = receipt.timestamp } }) }, /** * 设置当前聊天室的对方 已读时间 */ setCurrentChatLastReadTime(time: number) { if (this.openChatId && this.getChat(this.openChatId)) { const chat = this.getChat(this.openChatId); //console.log('setCurrentChatLastReadTime',chat); if (chat) { chat.lastReadTime = time } } }, } })