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.

752 lines
23 KiB

4 weeks ago
import { MESSAGE_TYPE, MESSAGE_STATUS } from "@/common/enums.js"
import localForage from 'localforage'
import {myCache} from "../utils/utils";
// 全局缓存变量(用于延迟渲染)
let cacheChats = []
// =================== Vuex 模块 ===================
const chatModule = {
namespaced: true,
state: () => ({
activeChat: null,
privateMsgMaxId: 0,
groupMsgMaxId: 0,
loadingPrivateMsg: false,
loadingGroupMsg: false,
chats: [] // 实际渲染的会话列表(仅前 N 个)
}),
getters: {
// 是否正在加载离线消息
isLoading: (state) => () => {
return state.loadingPrivateMsg || state.loadingGroupMsg
},
// 返回当前应显示的会话列表(加载中返回缓存列表,否则返回真实列表)
curChats: (state, getters) => () => {
if (cacheChats && getters.isLoading()) {
return cacheChats
}
return state.chats
},
// 查找会话索引
findChatIdx: (state, getters) => (chat) => {
const chats = getters.curChats()
for (let idx in chats) {
if (chats[idx].type === chat.type && chats[idx].targetId === chat.targetId) {
return parseInt(idx)
}
}
return -1
},
// 查找会话对象
findChat: (state, getters) => (chat) => {
const idx = getters.findChatIdx(chat)
return idx >= 0 ? getters.curChats()[idx] : null
},
findChatByFriend: (state, getters) => (fid) => {
const chats = getters.curChats()
return chats.find(c => c.type === 'PRIVATE' && c.targetId === fid)
},
findChatByGroup: (state, getters) => (gid) => {
const chats = getters.curChats()
return chats.find(c => c.type === 'GROUP' && c.targetId === gid)
},
// 在指定 chat 中查找消息
findMessage: (state, getters) => (chat, msgInfo) => {
if (!chat) return null
for (let idx in chat.messages) {
const m = chat.messages[idx]
if (msgInfo.id && m.id === msgInfo.id) return m
if (msgInfo.tmpId && m.tmpId && m.tmpId === msgInfo.tmpId) return m
}
return null
}
},
mutations: {
// ---------- 基础 mutations ----------
SET_CHATS(state, chats) {
state.chats = chats
},
SET_PRIVATE_MSG_MAX_ID(state, id) {
state.privateMsgMaxId = id
},
SET_GROUP_MSG_MAX_ID(state, id) {
state.groupMsgMaxId = id
},
SET_LOADING_PRIVATE(state, loading) {
state.loadingPrivateMsg = loading
},
SET_LOADING_GROUP(state, loading) {
state.loadingGroupMsg = loading
},
SET_ACTIVE_CHAT(state, chat) {
state.activeChat = chat
},
// ---------- 会话操作 ----------
ADD_CHAT(state, newChat) {
// 插入到列表头部
state.chats.unshift(newChat)
},
REMOVE_CHAT(state, idx) {
if (idx >= 0 && idx < state.chats.length) {
state.chats.splice(idx, 1)
}
},
MOVE_CHAT_TO_TOP(state, idx) {
if (idx > 0 && idx < state.chats.length) {
const chat = state.chats[idx]
state.chats.splice(idx, 1)
state.chats.unshift(chat)
chat.lastSendTime = new Date().getTime()
chat.stored = false
}
},
UPDATE_CHAT(state, { idx, chat }) {
if (idx >= 0 && idx < state.chats.length) {
state.chats[idx] = chat
}
},
RESET_UNREAD_COUNT(state, { type, targetId }) {
for (let c of state.chats) {
if (c.type === type && c.targetId === targetId) {
c.unreadCount = 0
c.atMe = false
c.atAll = false
c.stored = false
break
}
}
},
// ---------- 消息操作 ----------
UPDATE_MESSAGE(state, { chatIdx, msgInfo }) {
const chat = state.chats[chatIdx]
if (!chat) return
const msg = chat.messages.find(m => (m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId))
if (msg) {
Object.assign(msg, msgInfo)
chat.stored = false
}
},
DELETE_MESSAGE(state, { chatIdx, msgInfo }) {
const chat = state.chats[chatIdx]
if (!chat) return
const idx = chat.messages.findIndex(m => (m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId))
if (idx !== -1) {
chat.messages.splice(idx, 1)
chat.stored = false
}
},
// 更新会话的头像/名称
UPDATE_CHAT_INFO(state, { targetId, type, headImage, showName }) {
for (let c of state.chats) {
if (c.type === type && c.targetId === targetId) {
if (headImage) c.headImage = headImage
if (showName) c.showName = showName
c.stored = false
break
}
}
},
// 更新 chat 的基本信息lastContent, lastSendTime, sendNickName, unreadCount, atMe, atAll
UPDATE_CHAT_SUMMARY(state, { idx, lastContent, lastSendTime, sendNickName, unreadCount, atMe, atAll }) {
const chat = state.chats[idx];
if (!chat) return;
if (lastContent !== undefined) chat.lastContent = lastContent;
if (lastSendTime !== undefined) chat.lastSendTime = lastSendTime;
if (sendNickName !== undefined) chat.sendNickName = sendNickName;
if (unreadCount !== undefined) chat.unreadCount = unreadCount;
if (atMe !== undefined) chat.atMe = atMe;
if (atAll !== undefined) chat.atAll = atAll;
chat.stored = false;
},
// 插入时间戳消息
PUSH_TIME_TIP(state, { idx, sendTime }) {
const chat = state.chats[idx];
if (!chat) return;
chat.messages.push({ sendTime, type: MESSAGE_TYPE.TIP_TIME });
chat.lastTimeTip = sendTime;
chat.stored = false;
},
// 插入消息(支持指定位置)
INSERT_MESSAGE(state, { idx, msg, insertPos }) {
const chat = state.chats[idx];
if (!chat) return;
if (insertPos === undefined || insertPos === chat.messages.length) {
chat.messages.push(msg);
} else {
chat.messages.splice(insertPos, 0, msg);
}
chat.stored = false;
},
// 更新已有的消息(合并属性)
UPDATE_EXISTING_MESSAGE(state, { idx, msgInfo }) {
const chat = state.chats[idx];
if (!chat) return;
const msg = chat.messages.find(m => (m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId));
if (msg) Object.assign(msg, msgInfo);
chat.stored = false;
},
// 删除消息
DELETE_MESSAGE_BY_ID(state, { idx, msgInfo }) {
const chat = state.chats[idx];
if (!chat) return;
const pos = chat.messages.findIndex(m => (m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId));
if (pos !== -1) {
chat.messages.splice(pos, 1);
chat.stored = false;
}
},
// 撤回消息
RECALL_MESSAGE(state, { idx, targetId, recallContent, sendTime, selfSend }) {
const chat = state.chats[idx];
if (!chat) return;
for (let m of chat.messages) {
if (m.id === targetId) {
m.status = MESSAGE_STATUS.RECALL;
m.content = recallContent;
m.type = MESSAGE_TYPE.TIP_TEXT;
// 更新会话最后一条(如果撤回的是最后一条)
if (chat.messages[chat.messages.length - 1] === m) {
chat.lastContent = recallContent;
chat.lastSendTime = sendTime;
chat.sendNickName = '';
}
break;
}
}
// 处理引用消息
for (let m of chat.messages) {
if (m.quoteMessage && m.quoteMessage.id === targetId) {
m.quoteMessage.content = "引用内容已撤回";
m.quoteMessage.status = MESSAGE_STATUS.RECALL;
m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT;
}
}
chat.stored = false;
},
// 更新会话头像和名称
UPDATE_CHAT_AVATAR_NAME(state, { type, targetId, headImage, showName }) {
for (let chat of state.chats) {
if (chat.type === type && chat.targetId === targetId) {
if (headImage !== undefined) chat.headImage = headImage;
if (showName !== undefined) chat.showName = showName;
chat.stored = false;
break;
}
}
},
// 一次性替换所有会话(用于 refreshChats
REPLACE_CHATS(state, chats) {
state.chats = chats;
// 清空缓存(全局变量)
cacheChats = null;
},
// 更新单个 chat 的 hotMinIdx 和 stored 等
UPDATE_CHAT_META(state, { idx, hotMinIdx, stored }) {
const chat = state.chats[idx];
if (!chat) return;
if (hotMinIdx !== undefined) chat.hotMinIdx = hotMinIdx;
if (stored !== undefined) chat.stored = stored;
},
CLEAR_UNREAD_COUNT(state, idx) {
const chats = state.chats; // 或者通过 getter 获取当前列表
if (idx >= 0 && idx < chats.length) {
const chat = chats[idx];
if (chat) {
chat.unreadCount = 0;
chat.atMe = false;
chat.atAll = false;
chat.stored = false; // 标记需持久化
}
}
}
},
actions: {
// ========== 初始化 ==========
initChats({ commit, state }, chatsData) {
cacheChats = []
commit('SET_CHATS', [])
commit('SET_PRIVATE_MSG_MAX_ID', chatsData.privateMsgMaxId || 0)
commit('SET_GROUP_MSG_MAX_ID', chatsData.groupMsgMaxId || 0)
const allChats = chatsData.chats || []
for (let chat of allChats) {
chat.stored = false
// 深拷贝存入缓存,用于延迟渲染
cacheChats.push(JSON.parse(JSON.stringify(chat)))
// 仅渲染前 15 个会话(可调)
if (state.chats.length < 15) {
// 直接 push 新对象,避免引用缓存
state.chats.push({ ...chat })
}
}
// 防止图片一直处在加载中状态
cacheChats.forEach((chat) => {
chat.messages.forEach((msg) => {
if (msg.loadStatus == "loading") {
msg.loadStatus = "fail"
}
})
})
},
// ========== 打开会话 ==========
openChat({ state, getters, commit, dispatch }, chatInfo) {
// 加载中直接返回(原逻辑)
// if (getters.isLoading()) return
const chats = getters.curChats()
let existingIdx = -1
for (let idx in chats) {
if (chats[idx].type === chatInfo.type && chats[idx].targetId === chatInfo.targetId) {
existingIdx = parseInt(idx)
break
}
}
if (existingIdx !== -1) {
// 已存在 → 移到顶部
dispatch('moveTop', existingIdx)
} else {
// 新建会话
const newChat = {
targetId: chatInfo.targetId,
type: chatInfo.type,
showName: chatInfo.showName,
headImage: chatInfo.headImage,
lastContent: "",
lastSendTime: new Date().getTime(),
unreadCount: 0,
hotMinIdx: 0,
messages: [],
atMe: false,
atAll: false,
stored: false,
delete: false
}
commit('ADD_CHAT', newChat)
// 原逻辑未立即保存,等待后续消息触发保存
dispatch('saveToStorage', { withColdMessage: false })
}
},
activeChat({ commit, getters }, idx) {
const chats = getters.curChats(); // 使用 getter 获取当前列表(支持加载状态)
if (idx >= 0 && idx < chats.length) {
commit('CLEAR_UNREAD_COUNT', idx);
}
},
// ========== 移动会话到顶部 ==========
moveTop({ state, getters, commit, dispatch }, idx) {
if (getters.isLoading()) return
if (idx > 0 && idx < state.chats.length) {
commit('MOVE_CHAT_TO_TOP', idx)
// 移动后保存(原逻辑在 moveTop 最后调用了 saveToStorage
dispatch('saveToStorage', { withColdMessage: false })
}
},
removeChat({ state, getters, commit, dispatch }, idx) {
const chats = getters.curChats()
chats[idx].delete = true
chats[idx].stored = false
dispatch('saveToStorage', { withColdMessage: false })
},
resetUnreadCount({ state, getters, dispatch }, chatInfo) {
const chats = getters.curChats()
for (let idx in chats) {
if (chats[idx].type === chatInfo.type && chats[idx].targetId === chatInfo.targetId) {
chats[idx].unreadCount = 0
chats[idx].atMe = false
chats[idx].atAll = false
chats[idx].stored = false
dispatch('saveToStorage', { withColdMessage: false })
break
}
}
},
readedMessage({ state, getters, dispatch }, pos) {
const chat = getters.findChatByFriend(pos.friendId)
if (!chat) return
chat.messages.forEach((m) => {
let status=Number(m.status)
if (m.id && m.selfSend && status < MESSAGE_STATUS.RECALL) {
// pos.maxId为空表示整个会话已读
if (!pos.maxId || m.id <= pos.maxId) {
m.status = MESSAGE_STATUS.READED
chat.stored = false
}
}
})
dispatch('saveToStorage', { withColdMessage: false })
},
/**
* 删除私聊会话
* @param {Object} context - Vuex action 上下文
* @param {Number|String} userId - 对方用户ID
*/
removePrivateChat({ getters, dispatch }, userId) {
const chats = getters.curChats()
for (let idx in chats) {
if (chats[idx].type === 'PRIVATE' && chats[idx].targetId === userId) {
// 将索引转为数字(因为 for...in 返回字符串)
dispatch('removeChat', parseInt(idx))
break // 一个用户只有一个私聊会话,找到后退出
}
}
},
/**
* 删除群聊会话
* @param {Object} context - Vuex action 上下文
* @param {Number|String} groupId - 群ID
*/
removeGroupChat({ getters, dispatch }, groupId) {
const chats = getters.curChats()
for (let idx in chats) {
if (chats[idx].type === 'GROUP' && chats[idx].targetId === groupId) {
dispatch('removeChat', parseInt(idx))
break
}
}
},
insertMessage({ state, getters, commit, dispatch, rootState }, { msgInfo, chatInfo }) {
const type = chatInfo.type;
// 更新最大消息 ID
if (msgInfo.id && type === "PRIVATE" && msgInfo.id > state.privateMsgMaxId) {
commit('SET_PRIVATE_MSG_MAX_ID', msgInfo.id);
}
if (msgInfo.id && type === "GROUP" && msgInfo.id > state.groupMsgMaxId) {
commit('SET_GROUP_MSG_MAX_ID', msgInfo.id);
}
// 查找会话
const idx = getters.findChatIdx(chatInfo);
if (idx === -1) return;
const chat = state.chats[idx]; // 直接引用
// 检查是否已存在该消息(重发或更新)
const existingMsg = getters.findMessage(chat, msgInfo);
if (existingMsg) {
commit('UPDATE_EXISTING_MESSAGE', { idx, msgInfo });
dispatch('saveToStorage', { withColdMessage: false });
return;
}
let msgInfoType=Number(msgInfo.type)
let msgInfoStatus=Number(msgInfo.status)
// 准备要更新的字段
let lastContent = chat.lastContent;
if (msgInfoType === MESSAGE_TYPE.IMAGE) lastContent = "[图片]";
else if (msgInfoType === MESSAGE_TYPE.FILE) lastContent = "[文件]";
else if (msgInfoType === MESSAGE_TYPE.AUDIO) lastContent = "[语音]";
else if (msgInfoType === MESSAGE_TYPE.ACT_RT_VOICE) lastContent = "[语音通话]";
else if (msgInfoType === MESSAGE_TYPE.ACT_RT_VIDEO) lastContent = "[视频通话]";
else if (msgInfoType === MESSAGE_TYPE.TEXT || msgInfoType === MESSAGE_TYPE.RECALL || msgInfoType === MESSAGE_TYPE.TIP_TEXT) {
lastContent = msgInfo.content;
}
// 更新最后消息摘要
let unreadCount = chat.unreadCount || 0;
let atMe = chat.atMe || false;
let atAll = chat.atAll || false;
// 未读计数
if (!msgInfo.selfSend && msgInfoStatus !== MESSAGE_STATUS.READED &&
msgInfoStatus !== MESSAGE_STATUS.RECALL && msgInfoType !== MESSAGE_TYPE.TIP_TEXT) {
unreadCount++;
}
// @ 处理
if (!msgInfo.selfSend && chat.type === "GROUP" && msgInfo.atUserIds && msgInfoStatus !== MESSAGE_STATUS.READED) {
const userInfo = rootState.user?.userInfo;
if (userInfo) {
if (msgInfo.atUserIds.includes(userInfo.id)) atMe = true;
if (msgInfo.atUserIds.includes(-1)) atAll = true;
}
}
// 更新会话摘要(通过 mutation
commit('UPDATE_CHAT_SUMMARY', {
idx,
lastContent,
lastSendTime: msgInfo.sendTime,
sendNickName: msgInfo.sendNickName,
unreadCount,
atMe,
atAll
});
// 时间戳提示间隔10分钟
if (!chat.lastTimeTip || (chat.lastTimeTip < msgInfo.sendTime - 600 * 1000)) {
commit('PUSH_TIME_TIP', { idx, sendTime: msgInfo.sendTime });
}
// 计算插入位置(防止乱序)
let insertPos = chat.messages.length;
if (msgInfo.id && msgInfo.id > 0) {
for (let i = 0; i < chat.messages.length; i++) {
const m = chat.messages[i];
if (m.id && msgInfo.id < m.id) {
insertPos = i;
console.log(`消息乱序修正: ${chat.messages.length} -> ${insertPos}`);
break;
}
}
}
// 插入消息
commit('INSERT_MESSAGE', { idx, msg: msgInfo, insertPos });
// 标记已存储为 false已在 mutation 中完成)
// 保存到本地
dispatch('saveToStorage', { withColdMessage: false });
},
// ========== 更新消息 ==========
updateMessage({ getters, commit, dispatch }, { msgInfo, chatInfo }) {
const idx = getters.findChatIdx(chatInfo);
if (idx === -1) return;
commit('UPDATE_EXISTING_MESSAGE', { idx, msgInfo });
dispatch('saveToStorage', { withColdMessage: false });
},
// ========== 删除消息 ==========
deleteMessage({ getters, commit, dispatch }, { msgInfo, chatInfo }) {
const idx = getters.findChatIdx(chatInfo);
if (idx === -1) return;
const chat = getters.findChat(chatInfo);
// 找到消息位置,判断是否为冷消息(仅用于记录,不影响存储)
let isCold = false;
for (let i = 0; i < chat.messages.length; i++) {
const m = chat.messages[i];
if ((m.id && m.id === msgInfo.id) || (m.tmpId && m.tmpId === msgInfo.tmpId)) {
isCold = i < chat.hotMinIdx;
break;
}
}
commit('DELETE_MESSAGE_BY_ID', { idx, msgInfo });
dispatch('saveToStorage', { withColdMessage: isCold });
},
// ========== 撤回消息 ==========
recallMessage({ getters, commit, dispatch, rootState }, { msgInfo, chatInfo }) {
const idx = getters.findChatIdx(chatInfo);
if (idx === -1) return;
const chat = getters.findChat(chatInfo);
const targetId = msgInfo.content; // 被撤回的消息ID
// 构建撤回提示内容
const name = msgInfo.selfSend ? '你' : (chat.type === 'PRIVATE' ? '对方' : msgInfo.sendNickName);
const recallContent = name + "撤回了一条消息";
// 判断是否为冷消息
let isCold = false;
for (let i = 0; i < chat.messages.length; i++) {
if (chat.messages[i].id === targetId) {
isCold = i < chat.hotMinIdx;
break;
}
}
commit('RECALL_MESSAGE', { idx, targetId, recallContent, sendTime: msgInfo.sendTime, selfSend: msgInfo.selfSend });
// 更新未读计数(如果撤回的是对方消息且未读)
if (!msgInfo.selfSend && Number(msgInfo.status) !== MESSAGE_STATUS.READED) {
// 需要在 mutation 中增加未读计数?但原逻辑是 chat.unreadCount++,我们可以在 mutation 中处理
// 但为了复用,我们在 action 中手动增加(通过 UPDATE_CHAT_SUMMARY
const chatRef = state.chats[idx];
if (chatRef) {
commit('UPDATE_CHAT_SUMMARY', { idx, unreadCount: (chatRef.unreadCount || 0) + 1 });
}
}
dispatch('saveToStorage', { withColdMessage: isCold });
},
// ========== 更新会话信息(好友) ==========
updateChatFromFriend({ commit, dispatch }, friend) {
commit('UPDATE_CHAT_AVATAR_NAME', {
type: 'PRIVATE',
targetId: friend.id,
headImage: friend.headImage,
showName: friend.nickName
});
// 存储(会影响多个会话,但只更新了头像名称,可延迟保存)
dispatch('saveToStorage', { withColdMessage: false });
},
// ========== 更新会话信息(用户自身) ==========
updateChatFromUser({ commit, dispatch }, user) {
commit('UPDATE_CHAT_AVATAR_NAME', {
type: 'PRIVATE',
targetId: user.id,
headImage: user.headImageThumb,
showName: user.nickName
});
dispatch('saveToStorage', { withColdMessage: false });
},
// ========== 更新会话信息(群组) ==========
updateChatFromGroup({ commit, dispatch }, group) {
commit('UPDATE_CHAT_AVATAR_NAME', {
type: 'GROUP',
targetId: group.id,
headImage: group.headImageThumb,
showName: group.name
});
dispatch('saveToStorage', { withColdMessage: false });
},
setLoadingPrivateMsg({ commit, dispatch, getters }, loading) {
commit('SET_LOADING_PRIVATE', loading);
if (!getters.isLoading()) { // 使用 context.getters模块内局部 getters
dispatch('refreshChats');
}
},
setLoadingGroupMsg({ commit, dispatch, getters }, loading) {
commit('SET_LOADING_GROUP', loading);
if (!getters.isLoading()) { // 同上
dispatch('refreshChats');
}
},
// ========== 刷新会话列表(将缓存数据一次性渲染) ==========
refreshChats({ commit, dispatch }) {
if (!cacheChats) return;
// 排序(按最后消息时间倒序)
cacheChats.sort((a, b) => b.lastSendTime - a.lastSendTime);
// 非 App 端容量限制每个会话最多保留1000条消息
// #ifndef APP-PLUS
cacheChats.forEach(chat => {
if (chat.messages.length > 1000) {
chat.messages = chat.messages.slice(-1000);
}
});
// #endif
// 记录热数据索引(所有消息都视为热数据)
cacheChats.forEach(chat => chat.hotMinIdx = chat.messages.length);
// 一次性替换 state.chats
commit('REPLACE_CHATS', cacheChats);
// 清空缓存变量(已在 mutation 中处理)
// 持久化
dispatch('saveToStorage', { withColdMessage: true });
},
// ========== 保存到本地 ==========
saveToStorage({ state, getters, rootState }, { withColdMessage = false } = {}) {
if (getters.isLoading()) return
const userId = myCache('user').userid;
if (!userId) return
const key = `chats-app-${userId}`
const chatKeys = []
// 按会话为单位存储,
state.chats.forEach(chat => {
// 只存储有改动的会话
const chatKey = `${key}-${chat.type}-${chat.targetId}`
if (!chat.stored) {
if (chat.delete) {
uni.removeStorageSync(chatKey);
} else {
// 存储冷数据
if (withColdMessage) {
const coldChat = { ...chat, messages: chat.messages.slice(0, chat.hotMinIdx) }
uni.setStorageSync(chatKey, coldChat)
}
// 存储热消息
const hotKey = chatKey + '-hot'
const hotChat = { ...chat, messages: chat.messages.slice(chat.hotMinIdx) }
uni.setStorageSync(hotKey, hotChat);
}
chat.stored = true
}
if (!chat.delete) {
chatKeys.push(chatKey)
}
})
const chatsData = {
privateMsgMaxId: state.privateMsgMaxId,
groupMsgMaxId: state.groupMsgMaxId,
chatKeys
}
uni.setStorageSync(key, chatsData)
// 移除已删除的会话
state.chats = state.chats.filter(c => !c.delete)
},
// ========== 加载离线消息 ==========
loadChat({ commit, dispatch, rootState }) {
return new Promise((resolve, reject) => {
var userId = myCache('user').userid;
if (!userId) return resolve()
const key = `chats-app-${userId}`
const chatsData = uni.getStorageSync(`chats-app-${userId}`);
if (chatsData) {
if (chatsData.chatKeys) {
chatsData.chats = [];
chatsData.chatKeys.forEach(key => {
const coldChat = uni.getStorageSync(key);
const hotChat = uni.getStorageSync(key + '-hot');
if (!coldChat && !hotChat) {
return;
}
// 合并冷热消息
const chat = Object.assign({}, coldChat, hotChat);
if (hotChat && coldChat) {
chat.messages = coldChat.messages.concat(hotChat.messages);
}
chatsData.chats.push(chat);
});
}
// 调用 initChats action 初始化数据
dispatch('initChats', chatsData);
}
resolve();
})
},
clear(state){
},
// ... 其他 actions 类似迁移
}
}
export default chatModule