import Vue from "vue"; import { Module } from "vuex"; import { dbController } from "../database"; import { ChatMember, ServiceType, MessageHandled, RawChatItem, BaseChatItemBusinessData, MessageType, } from "../model"; import { isAccessibleUrl } from "../service/tools"; import { unique } from "../utils"; import { getChatModelInfo } from "../utils/chat-info"; import { getUserInfo } from "../utils/user-info"; import Chat from "../xim"; import { Chat as ChatType, Message } from "../xim/models/chat"; import xim, { ChatNotifyListener } from "../xim/xim"; import { decodeJwt } from "uniplat-sdk"; import { ChatStatus, ChatStore, ChatStoreState } from "./model"; import { RootStoreState } from "@/store/model"; export const ns = ChatStore.ns; const UniplatChatModelName = "UniplatChat"; const model = () => Chat.getSdk().model(UniplatChatModelName); const orgId = () => Chat.getOrgId() as string; function uniqueMessages( messages: NonNullable<ChatStore.STATE_CHAT_MSG_HISTORY> ) { const arr = [...messages]; return unique(arr, function (item, all) { return all.findIndex((k) => k.id === item.id); }); } function filterMessages( messages: NonNullable<ChatStore.STATE_CHAT_MSG_HISTORY>, chatid: number ) { return uniqueMessages(Array.from(messages)).filter( (k) => k.chat_id === chatid ); } let removeRegisterChatEvents: (() => void)[] = []; async function preCacheImgs(msgs?: any[]) { if (!msgs) { return Promise.resolve(); } await Promise.all( msgs .filter((i) => i.id > 0) .map((k) => { return new Promise((resolve: (p: void) => void) => { if (k.type === "image") { const msg = JSON.parse(k.msg); const url = msg.url; if (!isAccessibleUrl(url)) { return resolve(); } if ( url && isAccessibleUrl(url) && typeof Image !== "undefined" ) { const preCache = new Image(); preCache.src = url; preCache.onload = () => resolve(); setTimeout(resolve, 2000); } else { resolve(); } } else { resolve(); } }); }) ); } function buildChatItem(chat: RawChatItem) { if ((!chat.model_name || !chat.obj_id) && chat.business_data) { const b = JSON.parse(chat.business_data) as BaseChatItemBusinessData; chat.model_name = b.model_name; b.obj_id && (chat.obj_id = b.obj_id); } if (!chat.detail_name && chat.business_data) { const b = JSON.parse(chat.business_data) as BaseChatItemBusinessData; b.detail_name && (chat.detail_name = b.detail_name); } return { ...chat, chat_id: chat.id } as ChatType; } const chatType = "group"; const allowedChatTypes = [chatType, "notify"]; export const filterActiveChats = (items: RawChatItem[]) => { return items.filter( (i) => !i.is_finish && !i.is_exited && !i.is_remove && !i.is_deleted && allowedChatTypes.includes(i.type) ); }; export function getLastMessageId(msgs: Message[] | any) { if (msgs && msgs.length) { const last = msgs[msgs.length - 1]; let id = last.id; if (id < 0) { id = Math.max(...msgs.map((i: any) => i.id)); } return id; } return 0; } let loadingChatList = false; let cachedLoadingChatListAction: ((value: ChatType[]) => void)[] = []; function clearAction(value: ChatType[]) { for (const item of cachedLoadingChatListAction) { item(value); } cachedLoadingChatListAction = []; return value; } export default { namespaced: true, state: () => ({ [ChatStore.STATE_CHAT_DIALOG_VISIBLE]: false, [ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: false, [ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]: false, [ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR]: null, [ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID]: null, [ChatStore.STATE_CHAT_CURRENT_USER_UID]: null, [ChatStore.STATE_CHAT_MSG_HISTORY]: null, [ChatStore.STATE_CHAT_SENDING_MESSAGES]: [], [ChatStore.STATE_MY_CHAT_ROOM_LIST]: [], [ChatStore.STATE_SINGLE_CHAT]: null, [ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION]: null, [ChatStore.STATE_CHAT_CURRENT_CHAT_ID]: null, [ChatStore.STATE_CHAT_MY_ID]: null, [ChatStore.STATE_CHAT_MY_UID]: null, [ChatStore.STATE_CHAT_SOURCE]: ServiceType.Frontend, [ChatStore.STATE_CURRENT_CHAT_MEMBERS]: null, [ChatStore.STATE_CURRENT_CHAT_TITLE]: "", [ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM]: () => true, [ChatStore.STATE_FUNC_ON_NEW_MSG]: () => true, [ChatStore.STATE_CURRENT_CHAT_INPUTING]: [], [ChatStore.STATE_CURRENT_CHAT_INITING]: false, [ChatStore.STATE_CHAT_CURRENT_USER_TYPE]: null, [ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE]: null, [ChatStore.STATE_CHAT_USERNAME]: {}, [ChatStore.STATE_CURRENT_UNREAD_MESSAGE_COUNT]: 0, }), mutations: { [ChatStore.MUTATION_SHOW_CHAT](state, isSingle?: boolean) { state[ChatStore.STATE_CHAT_DIALOG_VISIBLE] = true; isSingle ? (state[ChatStore.STATE_CHAT_DIALOG_IS_SINGLE] = true) : (state[ChatStore.STATE_CHAT_DIALOG_IS_SINGLE] = false); }, [ChatStore.MUTATION_HIDE_CHAT](state) { state[ChatStore.STATE_CHAT_DIALOG_VISIBLE] = false; }, [ChatStore.MUTATION_SAVE_CHAT_LIST]( state, data: ChatStore.STATE_MY_CHAT_ROOM_LIST ) { state[ChatStore.STATE_MY_CHAT_ROOM_LIST] = data; }, [ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY](state) { state[ChatStore.STATE_CHAT_MSG_HISTORY] = null; }, [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_ID](state) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID] = null; }, [ChatStore.MUTATION_SAVE_CURRENT_CHAT_ID]( state, id: ChatStore.STATE_CHAT_CURRENT_CHAT_ID ) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID] = id; }, [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_VERSION](state) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION] = null; }, [ChatStore.MUTATION_SAVE_CURRENT_CHAT_VERSION]( state, v: ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION ) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION] = v; }, [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_UNIPLAT_ID](state) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID] = null; }, [ChatStore.MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID]( state, id: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID ) { state[ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID] = id; }, [ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY]( state, data: ChatStore.STATE_CHAT_MSG_HISTORY ) { const old = state[ChatStore.STATE_CHAT_MSG_HISTORY] || []; const chatid = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatid) { // 移除撤回的消息 const newItems = data || []; const withdraw = newItems .filter((i) => i.type === MessageType.Withdraw) .map((i) => +i.msg); const filterout = newItems.filter( (i) => !withdraw.includes(i.id) ); state[ChatStore.STATE_CHAT_MSG_HISTORY] = Object.freeze( filterMessages([...old, ...filterout], chatid) ); } }, [ChatStore.MUTATION_SAVE_MYSELF_ID](state) { if (!state[ChatStore.STATE_CHAT_MY_ID]) { Chat.getToken().then((token) => { if (token) { const eid = decodeJwt<{ user_id: string; sub: string }>(token); state[ChatStore.STATE_CHAT_MY_ID] = String(eid.user_id); state[ChatStore.STATE_CHAT_MY_UID] = eid.sub; } }); } }, [ChatStore.MUTATION_CLEAR_MYSELF_ID](state) { state[ChatStore.STATE_CHAT_MY_ID] = null; state[ChatStore.STATE_CHAT_MY_UID] = null; }, [ChatStore.MUTATION_SAVE_SEND_FAIL_MESSAGE](state, param: string) { state[ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE] = param; }, [ChatStore.MUTATION_SET_CHAT_SOURCE]( state, data: ChatStore.STATE_CHAT_SOURCE ) { state[ChatStore.STATE_CHAT_SOURCE] = data; }, [ChatStore.MUTATION_UNSHIFT_CHAT_MSG_HISTORY]( state, data: ChatStore.STATE_CHAT_MSG_HISTORY ) { const old = state[ChatStore.STATE_CHAT_MSG_HISTORY] || []; const chatid = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatid == null) return; state[ChatStore.STATE_CHAT_MSG_HISTORY] = Object.freeze( filterMessages([...(data || []), ...old], chatid) ); }, [ChatStore.MUTATION_SAVE_CURRENT_CHAT_MEMBERS]( state, data: ChatStore.STATE_CURRENT_CHAT_MEMBERS ) { state[ChatStore.STATE_CURRENT_CHAT_MEMBERS] = Object.freeze(data); }, [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS](state) { state[ChatStore.STATE_CURRENT_CHAT_MEMBERS] = null; }, [ChatStore.MUTATION_SAVE_CHAT_TITLE]( state, data: ChatStore.STATE_CURRENT_CHAT_TITLE ) { state[ChatStore.STATE_CURRENT_CHAT_TITLE] = data; }, [ChatStore.MUTATION_CLEAR_CHAT_TITLE](state) { state[ChatStore.STATE_CURRENT_CHAT_TITLE] = ""; }, [ChatStore.MUTATION_SAVE_SINGLE_CHAT](state, v: ChatType) { state[ChatStore.STATE_SINGLE_CHAT] = v; }, [ChatStore.MUTATION_CLEAR_SINGLE_CHAT](state) { state[ChatStore.STATE_SINGLE_CHAT] = null; }, [ChatStore.MUTATION_SCROLL_TO_BOTTOM](state) { state[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM](); }, [ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM]( state, data: ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM ) { state[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM] = data; }, [ChatStore.MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM](state) { state[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM] = () => true; }, [ChatStore.MUTATION_SAVE_FUNC_ON_NEW_MSG]( state, data: ChatStore.STATE_FUNC_ON_NEW_MSG ) { state[ChatStore.STATE_FUNC_ON_NEW_MSG] = data; }, [ChatStore.MUTATION_CLEAR_FUNC_ON_NEW_MSG](state) { state[ChatStore.STATE_FUNC_ON_NEW_MSG] = () => true; }, [ChatStore.MUTATION_APPEND_SENDING_MESSAGE]: ( state, payload: ChatStore.STATE_CHAT_SENDING_MESSAGE ) => { const current = state[ ChatStore.STATE_CHAT_SENDING_MESSAGES ] as ChatStore.STATE_CHAT_SENDING_MESSAGE[]; if (current) { current.push(payload); const chat = state[ ChatStore.STATE_CHAT_CURRENT_CHAT_ID ] as number; dbController.appendMessages(chat, [payload]); } preCacheImgs([payload]).then(() => { setTimeout( () => state[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM](), 100 ); }); }, [ChatStore.MUTATION_REMOVE_SENDING_MESSAGE]: ( state, payload: number ) => { const current = state[ ChatStore.STATE_CHAT_SENDING_MESSAGES ] as ChatStore.STATE_CHAT_SENDING_MESSAGE[]; if (current) { const target = current.find((i) => i.id === payload); if (target) { const index = current.indexOf(target); current.splice(index, 1); } } }, [ChatStore.MUTATION_FAILED_SENDING_MESSAGE]: ( state, payload: number ) => { const current = state[ ChatStore.STATE_CHAT_SENDING_MESSAGES ] as ChatStore.STATE_CHAT_SENDING_MESSAGE[]; if (current) { const target = current.find((i) => i.id === payload); if (target) { target.status = -1; } state[ChatStore.STATE_CHAT_SENDING_MESSAGES] = [...current]; } }, [ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING]: (function () { const setTimeoutId: { [key: string]: number } = {}; return ( state: ChatStoreState, payload: Parameters<ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING>[0] ) => { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatId == null) return; if (payload.chat_id !== chatId) return; const arr = state[ChatStore.STATE_CURRENT_CHAT_INPUTING]; const eid = payload.eid; if (eid === state[ChatStore.STATE_CHAT_MY_ID]) return; if (arr.includes(eid)) { clearTimeout(setTimeoutId[eid]); } else { arr.push(eid); } setTimeoutId[eid] = setTimeout( () => arr.splice(arr.indexOf(eid), 1), 4000 ); }; })(), [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_INPUTING]: (state) => { state[ChatStore.STATE_CURRENT_CHAT_INPUTING] = []; }, [ChatStore.MUTATION_INITING_CHAT]: (state) => { state[ChatStore.STATE_CURRENT_CHAT_INITING] = true; }, [ChatStore.MUTATION_INITING_CHAT_DONE]: (state) => { state[ChatStore.STATE_CURRENT_CHAT_INITING] = false; }, [ChatStore.MUTATION_CHAT_UPDATE_IS_MEMBER]: (state, v: boolean) => { state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER] = v; }, [ChatStore.MUTATION_SET_CURRENT_USER_UID]: (state, v: number) => { state[ChatStore.STATE_CHAT_CURRENT_USER_UID] = v; }, [ChatStore.MUTATION_CHAT_UPDATE_USER_TYPE]: (state, v: string) => { state[ChatStore.STATE_CHAT_CURRENT_USER_TYPE] = v; }, [ChatStore.MUTATION_SAVE_USERNAME]: ( state, param: { id: string; name: string } ) => { Vue.set(state[ChatStore.STATE_CHAT_USERNAME], param.id, param.name); }, [ChatStore.MUTATION_WITHDRAW]: (state, id: number) => { const old = state[ChatStore.STATE_CHAT_MSG_HISTORY] || []; const chatid = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatid == null) return; state[ChatStore.STATE_CHAT_MSG_HISTORY] = old.filter( (i) => i.id !== id ); }, }, actions: { async [ChatStore.ACTION_GET_MY_CHAT_LIST]({ commit, state }) { commit(ChatStore.MUTATION_SAVE_MYSELF_ID); if (loadingChatList) { return new Promise<ChatType[]>((resolve) => cachedLoadingChatListAction.push(resolve) ); } loadingChatList = true; let cache = await dbController.getChatList(); cache.sort((x, y) => (x.last_msg_ts < y.last_msg_ts ? 1 : -1)); for (const item of cache) { if (item.business_data && !item.detail_name) { const d = JSON.parse( item.business_data ) as BaseChatItemBusinessData; if (d) { if (d.detail_name) { item.detail_name = d.detail_name; } if (!item.obj_id && d.obj_id) { item.obj_id = d.obj_id; } if (!item.model_name && d.model_name) { item.model_name = d.model_name; } } } } const buildUnreadMessage = (items: ChatType[]) => { let sum = 0; items.forEach((i) => (sum += i.unread_msg_count)); state[ChatStore.STATE_CURRENT_UNREAD_MESSAGE_COUNT] = sum; return items.sort((x, y) => x.last_msg_ts < y.last_msg_ts ? 1 : -1 ); }; if (cache && cache.length) { commit(ChatStore.MUTATION_SAVE_CHAT_LIST, cache); const ts = cache .map((i) => Math.max(i.last_msg_ts, i.update_time)) .sort(); const last = ts[ts.length - 1]; const execute = () => new Promise<ChatType[]>((resolve) => { Chat.onReady(() => { xim.fetchChatListAfter(last)!.then((r) => { const list = filterActiveChats( r.args[0] as RawChatItem[] ); const items = list.map((i) => buildChatItem(i)); if (items && items.length) { cache = dbController.mergeChatList( cache, items ); } resolve(buildUnreadMessage(cache)); }); }); }).finally(() => (loadingChatList = false)); return await execute().then((d) => clearAction(d)); } const execute = () => new Promise<ChatType[]>((resolve) => { Chat.onReady(() => { xim.fetchChatList().then((data) => { if (!data) { return resolve([]); } const chatList = filterActiveChats( data.args[0] as RawChatItem[] ); const items = chatList.map((chat) => buildChatItem(chat) ); dbController.saveChatList(items); commit(ChatStore.MUTATION_SAVE_CHAT_LIST, items); resolve(buildUnreadMessage(items)); }); }); }).finally(() => (loadingChatList = false)); return await execute().then((d) => clearAction(d)); }, async [ChatStore.ACTION_FORCE_RELOAD_CHAT_LIST]({ commit }) { return new Promise<ChatType[]>((resolve) => { Chat.onReady(() => { xim.fetchChatList().then((data) => { if (!data) { return resolve([]); } const chatList = filterActiveChats( data.args[0] as RawChatItem[] ); const items = chatList.map((chat) => buildChatItem(chat) ); dbController.saveChatList(items); commit(ChatStore.MUTATION_SAVE_CHAT_LIST, items); resolve(items); }); }); }); }, async [ChatStore.ACTION_REBUILD_UNREAD_MESSAGE_COUNT]({ state }) { let items = await dbController.getChatList(); let sum = 0; items.forEach((i) => (sum += i.unread_msg_count)); state[ChatStore.STATE_CURRENT_UNREAD_MESSAGE_COUNT] = sum; }, async [ChatStore.ACTION_UPDATE_CHAT_UNREAD_MESSAGE_COUNT]( { dispatch }, p: { chat: number; unread: number } ) { dbController .updateChat4UnreadCount(p.chat, p.unread) .then(() => dispatch(ChatStore.ACTION_REBUILD_UNREAD_MESSAGE_COUNT) ); }, async [ChatStore.ACTION_GET_CHAT_MESSAGES]({ state, commit, getters }) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; const isMember = state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]; if (chatId == null) return; let data: Message[] = []; const getMessages = async () => { const o = { model: chat.model_name, obj: chat.obj_id, isMember, }; data = await xim.queryLastPageMsg(chatType, chatId, 20, o); }; if (isMember) { const cache = await dbController.getChatMessages(chatId); if (cache && cache.length) { data = cache; } else { await getMessages(); } } else { await getMessages(); } try { commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data); dbController.saveChatMessages(chatId, data); await preCacheImgs(data); commit(ChatStore.MUTATION_SCROLL_TO_BOTTOM); return data; } catch (error) { // eslint-disable-next-line no-console console.error(error); } }, async [ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID]( { state, commit, getters }, msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID>[0] ) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatId == null) return; const chat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; const o = { model: chat.model_name, obj: chat.obj_id, isMember: state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER], }; const data = await xim.queryPrevPageMsg( chatType, chatId, msgId, 10, o ); commit(ChatStore.MUTATION_UNSHIFT_CHAT_MSG_HISTORY, data); dbController.appendMessages(chatId, data); return data; }, async [ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID]( { state, commit, getters }, msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID>[0] ) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (chatId == null) return; const chat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; const o = { model: chat.model_name, obj: chat.obj_id, isMember: state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER], }; const data = await xim.queryNextPageMsg( chatType, chatId, msgId, 10, o ); commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data); dbController.appendMessages(chatId, data); return data; }, async [ChatStore.ACTION_SEND_MESSAGE]( { state, dispatch, getters, commit }, params: Parameters<ChatStore.ACTION_SEND_MESSAGE>[0] ) { if (Chat.getServiceType() === ServiceType.Backend) { if (!state[ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID]) { return Promise.reject(`No Uniplat Id Found`); } } try { const chat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; const data = await Chat.getSdk() .model(chat.model_name) .chat(chat.obj_id, orgId()) .sendMsg(params.msgType, params.msg); await dispatch(ChatStore.ACTION_GET_FRESH_MESSAGE); return data; } catch (error) { // eslint-disable-next-line no-console commit( ChatStore.MUTATION_SAVE_SEND_FAIL_MESSAGE, JSON.stringify(params) ); return Promise.reject(error); } }, async [ChatStore.ACTION_GET_FRESH_MESSAGE]({ state, dispatch, commit, }) { const msgs = state[ChatStore.STATE_CHAT_MSG_HISTORY]; let newMsgsArr; if (msgs == null || msgs.length === 0) { newMsgsArr = await dispatch(ChatStore.ACTION_GET_CHAT_MESSAGES); } else { const id = getLastMessageId(msgs); newMsgsArr = await dispatch( ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID, id ); } // const lastMsg = newMsgsArr[newMsgsArr.length - 1]; await preCacheImgs(newMsgsArr); commit(ChatStore.MUTATION_SCROLL_TO_BOTTOM); }, async [ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN]( { commit, dispatch }, params: Parameters<ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN>[0] ) { const { imChatId, catalog } = await Chat.getSdk() .model(params.modelName) .chat(params.selectedListId, orgId()) .createChat(); const chatId = +imChatId; await dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST); commit(ChatStore.MUTATION_SHOW_CHAT, !params.showByPage); await dispatch( ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION, chatId ); return { chatId, catalog }; }, async [ChatStore.ACTION_CREATE_NEW_CHAT_BY_CLIENT]( { commit, dispatch }, params: Parameters<ChatStore.ACTION_CREATE_NEW_CHAT_BY_CLIENT>[0] ) { const { imChatId } = await Chat.getSdk() .model(params.modelName) .chat(params.selectedListId, orgId()) .createChat(true, params.title); const chatId = +imChatId; await commit(ChatStore.MUTATION_SHOW_CHAT, true); await dispatch( ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION, chatId ); // 打开会话后获取一下会话列表,刷新未读消息 dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST); return chatId; }, async [ChatStore.ACTION_REGISTER_EVENT]({ dispatch, commit, state, getters, }) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const onNewMsg = (e: Message) => { const thenAction = () => { if (e.type === MessageType.Withdraw) { commit(ChatStore.MUTATION_WITHDRAW, +e.msg); } const scroll = () => state[ChatStore.STATE_FUNC_ON_NEW_MSG](e); if (e.chat_id === chatId) { dispatch(ChatStore.ACTION_GET_FRESH_MESSAGE).finally( () => scroll() ); } else { scroll(); } }; if (e.type === MessageType.Withdraw) { dbController .removeMessage(e.chat_id, +e.msg) .finally(() => thenAction()); } else { thenAction(); } }; if (!chatId) { xim.off("msg", onNewMsg); xim.on("msg", onNewMsg); return; } const onMsgRead: ChatNotifyListener = async (e) => { if (chatId !== e.chat_id) return; const msgs = state[ChatStore.STATE_CHAT_MSG_HISTORY]; if (msgs == null) return; const oldestMsgId = msgs[0].id - 1; const lastMsgId = msgs[msgs.length - 1].id + 1; const chat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; const o = { model: chat.model_name, obj: chat.obj_id, isMember: state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER], }; const start = oldestMsgId < 1 ? 1 : oldestMsgId; const freshMsgs = await xim.queryMsgs( chatType, chatId, start, lastMsgId, 20, true, o ); dbController.setMessageReaded(chatId, { start, end: lastMsgId, }); commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY); commit( ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, msgs.map((msg) => { msg = { ...msg }; const newMsg = freshMsgs.find( (freshMsg) => freshMsg.id === msg.id ); if (newMsg != null) { msg.read_count = newMsg.read_count; } return msg; }) ); }; const onInputing: ChatNotifyListener = (e) => { commit(ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING, e); }; removeRegisterChatEvents.push(() => { xim.off("msg", onNewMsg); xim.off("chat_notify", "read", onMsgRead); xim.off("chat_notify", "user.input", onInputing); }); xim.on("msg", onNewMsg); xim.on("chat_notify", "read", onMsgRead); xim.on("chat_notify", "user.input", onInputing); }, async [ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION]( { state, commit, dispatch }, chatId: ChatStore.STATE_CHAT_CURRENT_CHAT_ID ) { if (!chatId) { return; } const chatList = state[ ChatStore.STATE_MY_CHAT_ROOM_LIST ] as ChatType[]; let wantedChatRoom = chatList.find((k) => k.chat_id === chatId); if (!wantedChatRoom) { const data = await xim.fetchChat(chatId); if (!data) { return; } const chat = data.args[0] as RawChatItem; commit( ChatStore.MUTATION_SAVE_SINGLE_CHAT, (wantedChatRoom = buildChatItem(chat)) ); } else { commit(ChatStore.MUTATION_CLEAR_SINGLE_CHAT); } if (!state[ChatStore.STATE_CHAT_CURRENT_USER_UID]) { const userInfo = await Chat.getSdk().getUserInfo(); commit(ChatStore.MUTATION_SET_CURRENT_USER_UID, userInfo.id); } commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY); commit(ChatStore.MUTATION_SAVE_CURRENT_CHAT_ID, chatId); await getChatModelInfo( wantedChatRoom.model_name, wantedChatRoom.obj_id, wantedChatRoom.detail_name ) .then((info) => { commit( ChatStore.MUTATION_SAVE_CURRENT_CHAT_VERSION, info.uniplat_version ); commit( ChatStore.MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID, info.uniplatId ); }) .catch(console.error); commit(ChatStore.MUTATION_INITING_CHAT); removeRegisterChatEvents.forEach((k) => k()); removeRegisterChatEvents = []; await dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS); await Promise.all([ dispatch(ChatStore.ACTION_REGISTER_EVENT), dispatch(ChatStore.ACTION_GET_CHAT_MESSAGES), ]); commit( ChatStore.MUTATION_SAVE_CHAT_TITLE, wantedChatRoom.title || `会话${chatId}` ); commit(ChatStore.MUTATION_INITING_CHAT_DONE); commit(ChatStore.MUTATION_SCROLL_TO_BOTTOM); (<any>state)[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = null; }, async [ChatStore.ACTION_CLEAR_CURRENT_CHAT_DATA]({ commit, state }) { commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_ID); commit(ChatStore.MUTATION_CLEAR_MYSELF_ID); commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY); commit(ChatStore.MUTATION_CLEAR_CHAT_TITLE); commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS); (<any>state)[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = null; }, async [ChatStore.ACTION_GET_CHAT_MEMBERS]({ commit, state }) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; if (!chatId) return; const getChatMembersResult = await xim.fetchChatMembers(chatId); if (!getChatMembersResult) return; const chatMembers = getChatMembersResult.args[0] as ChatMember[]; let newChatMembers = await Promise.all( chatMembers.map(async (member) => { let result: NonNullable<ChatStore.STATE_CURRENT_CHAT_MEMBERS>[number]; try { const data = await getUserInfo(member.eid); result = { ...member, ...data, }; } catch (error) { // eslint-disable-next-line no-console console.error(error); result = member; } return result; }) ); newChatMembers = newChatMembers.filter((it) => !it.is_exited); const member = newChatMembers.find( (it) => it.eid === String(state[ChatStore.STATE_CHAT_CURRENT_USER_UID]) ); if (member) { commit(ChatStore.MUTATION_CHAT_UPDATE_IS_MEMBER, true); commit(ChatStore.MUTATION_CHAT_UPDATE_USER_TYPE, member.type); } else { commit(ChatStore.MUTATION_CHAT_UPDATE_IS_MEMBER, false); commit(ChatStore.MUTATION_CHAT_UPDATE_USER_TYPE, "0"); } commit( ChatStore.MUTATION_SAVE_CURRENT_CHAT_MEMBERS, unique(newChatMembers, function (item, all) { return all.findIndex((k) => k.eid === item.eid); }) ); }, async [ChatStore.ACTION_TERINATE_CHAT]({ state, dispatch }) { const v = state[ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION]; if (v == null) return; const id = Number( state[ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID] ); await model() .action("update") .updateInitialParams({ selected_list: [{ v, id }], }) .addInputs_parameter({ Status: ChatStatus.terminated, }) .execute(); await dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST); const firstChat = state[ChatStore.STATE_MY_CHAT_ROOM_LIST][0]; if (firstChat == null) return; await getChatModelInfo( firstChat.model_name, firstChat.obj_id, firstChat.detail_name ); await dispatch( ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION, firstChat.chat_id ); }, async [ChatStore.ACTION_CHAT_START_RECEPTION]({ getters, dispatch }) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return new Promise<void>((resolve, reject) => { Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .startChat() .catch(reject) .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS) .then(resolve) .catch(reject) ); }); }, async [ChatStore.ACTION_CHAT_FINISH_RECEPTION]({ getters, dispatch }) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .finishChat() .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_USER_EXIT]({ getters, dispatch }) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } await dbController.removeChatFromList(currentChat.id); return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .userExitChat() .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_CS_EXIT]({ getters, dispatch }) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } await dbController.removeChatFromList(currentChat.id); return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .csExitChat() .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_ADD_MEMBERS]( { getters, dispatch }, uids: Parameters<ChatStore.ACTION_CHAT_ADD_MEMBERS>[0] ) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .addMember(uids.map((id) => +id)) .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_REMOVE_MEMBER]( { getters, dispatch }, uids: Parameters<ChatStore.ACTION_CHAT_REMOVE_MEMBER>[0] ) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, currentChat.org_id) .removeMember(uids.map((id) => +id)) .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_ADD_CS]( { getters, dispatch }, uids: Parameters<ChatStore.ACTION_CHAT_ADD_CS>[0] ) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .addCs(uids.map((id) => Number(id))) .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, async [ChatStore.ACTION_CHAT_REMOVE_CS]( { getters, dispatch }, uids: Parameters<ChatStore.ACTION_CHAT_REMOVE_CS>[0] ) { const currentChat = getters[ ChatStore.GETTER_CURRENT_CURRENT_CHAT ] as ChatType; if ( !currentChat || !currentChat.model_name || !currentChat.obj_id ) { return Promise.reject(); } return await Chat.getSdk() .model(currentChat.model_name) .chat(currentChat.obj_id, orgId()) .removeCs(uids.map((id) => Number(id))) .finally(() => dispatch(ChatStore.ACTION_GET_CHAT_MEMBERS)); }, [ChatStore.ACTION_SET_HANDLED]( { state }, p: { id: number; value: MessageHandled; } ) { const msgs = state[ChatStore.STATE_CHAT_MSG_HISTORY]; if (msgs) { const t = msgs.find((i) => i.id === p.id); if (t) { t.handled = p.value; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; chatId && dbController.updateMessageStatus(chatId, p.id, p.value); } } }, [ChatStore.ACTION_UPDATE_CHAT]: ( { dispatch }, p: ChatStore.ChatUpdateParameter ) => { dbController .updateChat(p) .finally(() => dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST)); }, [ChatStore.ACTION_SET_CHAT_ERROR]: ({ state }, chat: number) => { (<any>state)[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = chat; }, [ChatStore.ACTION_GET_USERINFO]: ({ state }, id: string) => { const cache = state[ChatStore.STATE_CHAT_USERNAME] || {}; if (cache[id]) { return Promise.resolve({ id, name: cache[id] }); } return new Promise<{ id: string; name: string }>( (resolve, reject) => getUserInfo(id) .then((d) => { Vue.set( state[ChatStore.STATE_CHAT_USERNAME], id, d.name ); resolve({ id, name: d.name }); }) .catch(reject) ); }, [ChatStore.ACTION_UPDATE_MESSAGE_READ_STATUS]: ( { state }, option: { chat: number; start: number; end?: number; all?: boolean; readed?: number; } ) => { const items = state[ChatStore.STATE_CHAT_MSG_HISTORY] as Message[]; if (items) { if (option.end && option.end > option.start) { for (let i = option.start; i <= option.end; i++) { const p = items.find((m) => m.id === i); if (p) { p.read_count = option.all ? p.total_read_count : option.readed ? option.readed : p.read_count + 1; } } } else { const p = items.find((i) => i.id === option.start); if (p) { p.read_count = option.all ? p.total_read_count : option.readed ? option.readed : p.read_count + 1; } } } return dbController .setMessageReaded(option.chat, { start: option.start, end: option.end, allRead: option.all, }) .then(() => (state[ChatStore.STATE_CHAT_MSG_HISTORY] = items)); }, }, getters: { [ChatStore.STATE_CHAT_MSG_HISTORY](state) { return state[ChatStore.STATE_CHAT_MSG_HISTORY] ?? []; }, [ChatStore.STATE_CHAT_SENDING_MESSAGES](state) { return state[ChatStore.STATE_CHAT_SENDING_MESSAGES] || []; }, [ChatStore.STATE_CURRENT_CHAT_MEMBERS](state) { return state[ChatStore.STATE_CURRENT_CHAT_MEMBERS] ?? []; }, [ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS](state) { return (state[ChatStore.STATE_CURRENT_CHAT_MEMBERS] ?? []).filter( (member) => !member.is_exited ); }, [ChatStore.STATE_CURRENT_CHAT_TITLE](state) { return state[ChatStore.STATE_CURRENT_CHAT_TITLE] || ""; }, [ChatStore.STATE_CHAT_SOURCE](state) { return state[ChatStore.STATE_CHAT_SOURCE] || 0; }, [ChatStore.GETTER_CURRENT_CURRENT_CHAT](state) { const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const singleChat = state[ChatStore.STATE_SINGLE_CHAT]; if (singleChat && singleChat.chat_id === chatId) { return singleChat; } const chatList = state[ChatStore.STATE_MY_CHAT_ROOM_LIST]; return chatList.find((chat) => chat.chat_id === chatId); }, }, } as Module<ChatStoreState, RootStoreState>;