图标
This commit is contained in:
@@ -1,43 +0,0 @@
|
|||||||
//构建联系人列表标签
|
|
||||||
import { weChatGroupService, contractService } from "@/utils/db";
|
|
||||||
import { request } from "@/api/request2";
|
|
||||||
import { ContactGroupByLabel } from "@/pages/pc/ckbox/data";
|
|
||||||
|
|
||||||
export function WechatGroup(params) {
|
|
||||||
return request("/api/WechatGroup/list", params, "GET");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createContractList = async (
|
|
||||||
kfSelected: number,
|
|
||||||
countLables: ContactGroupByLabel[],
|
|
||||||
) => {
|
|
||||||
// 根据 groupType 决定查询不同的服务
|
|
||||||
const dataByLabels = [];
|
|
||||||
for (const label of countLables) {
|
|
||||||
let data;
|
|
||||||
if (label.groupType === 1) {
|
|
||||||
// groupType: 1, 查询 contractService
|
|
||||||
data = await contractService.findWhere("groupId", label.id);
|
|
||||||
// 过滤出 kfSelected 对应的联系人
|
|
||||||
if (kfSelected && kfSelected != 0) {
|
|
||||||
data = data.filter(contact => contact.wechatAccountId === kfSelected);
|
|
||||||
}
|
|
||||||
// console.log(`标签 ${label.groupName} 对应的联系人数据:`, data);
|
|
||||||
} else if (label.groupType === 2) {
|
|
||||||
// groupType: 2, 查询 weChatGroupService
|
|
||||||
data = await weChatGroupService.findWhere("groupId", label.id);
|
|
||||||
if (kfSelected && kfSelected != 0) {
|
|
||||||
data = data.filter(contact => contact.wechatAccountId === kfSelected);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn(`未知的 groupType: ${label.groupType}`);
|
|
||||||
data = [];
|
|
||||||
}
|
|
||||||
dataByLabels.push({
|
|
||||||
...label,
|
|
||||||
contacts: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataByLabels;
|
|
||||||
};
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import {
|
|
||||||
ContractData,
|
|
||||||
KfUserListData,
|
|
||||||
CkAccount,
|
|
||||||
ContactGroupByLabel,
|
|
||||||
weChatGroup,
|
|
||||||
} from "@/pages/pc/ckbox/data";
|
|
||||||
|
|
||||||
// 权限片段接口
|
|
||||||
export interface PrivilegeFrag {
|
|
||||||
// 根据实际数据结构补充
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 租户信息接口
|
|
||||||
export interface CkTenant {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
guid: string;
|
|
||||||
thirdParty: string | null;
|
|
||||||
tenantType: number;
|
|
||||||
deployName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触客宝用户信息接口
|
|
||||||
export interface CkUserInfo {
|
|
||||||
account: CkAccount;
|
|
||||||
privilegeFrags: PrivilegeFrag[];
|
|
||||||
tenant: CkTenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态接口
|
|
||||||
export interface CkChatState {
|
|
||||||
userInfo: CkUserInfo | null;
|
|
||||||
isLoggedIn: boolean;
|
|
||||||
searchKeyword: string;
|
|
||||||
contractList: ContractData[];
|
|
||||||
chatSessions: any[];
|
|
||||||
kfUserList: KfUserListData[];
|
|
||||||
kfSelected: number;
|
|
||||||
getKfSelectedUser: () => KfUserListData | undefined;
|
|
||||||
countLables: ContactGroupByLabel[];
|
|
||||||
newContractList: ContactGroupByLabel[];
|
|
||||||
getContractList: () => ContractData[];
|
|
||||||
getSomeContractList: (kfSelected: number) => ContractData[];
|
|
||||||
getNewContractList: () => ContactGroupByLabel[];
|
|
||||||
setSearchKeyword: (keyword: string) => void;
|
|
||||||
clearSearchKeyword: () => void;
|
|
||||||
asyncKfSelected: (data: number) => void;
|
|
||||||
asyncWeChatGroup: (data: weChatGroup[]) => void;
|
|
||||||
asyncCountLables: (data: ContactGroupByLabel[]) => void;
|
|
||||||
getkfUserList: () => KfUserListData[];
|
|
||||||
asyncKfUserList: (data: KfUserListData[]) => void;
|
|
||||||
getKfUserInfo: (wechatAccountId: number) => KfUserListData | undefined;
|
|
||||||
asyncContractList: (data: ContractData[]) => void;
|
|
||||||
getChatSessions: () => any[];
|
|
||||||
asyncChatSessions: (data: any[]) => void;
|
|
||||||
updateChatSession: (session: ContractData | weChatGroup) => void;
|
|
||||||
deleteCtrlUser: (userId: number) => void;
|
|
||||||
updateCtrlUser: (user: KfUserListData) => void;
|
|
||||||
clearkfUserList: () => void;
|
|
||||||
addChatSession: (session: any) => void;
|
|
||||||
deleteChatSession: (sessionId: number) => void;
|
|
||||||
setUserInfo: (userInfo: CkUserInfo) => void;
|
|
||||||
clearUserInfo: () => void;
|
|
||||||
updateAccount: (account: Partial<CkAccount>) => void;
|
|
||||||
updateTenant: (tenant: Partial<CkTenant>) => void;
|
|
||||||
getAccountId: () => number | null;
|
|
||||||
getTenantId: () => number | null;
|
|
||||||
getAccountName: () => string | null;
|
|
||||||
getTenantName: () => string | null;
|
|
||||||
}
|
|
||||||
@@ -1,527 +0,0 @@
|
|||||||
import { createPersistStore } from "@/store/createPersistStore";
|
|
||||||
import { CkChatState, CkUserInfo, CkTenant } from "./ckchat.data";
|
|
||||||
import {
|
|
||||||
ContractData,
|
|
||||||
weChatGroup,
|
|
||||||
CkAccount,
|
|
||||||
KfUserListData,
|
|
||||||
ContactGroupByLabel,
|
|
||||||
} from "@/pages/pc/ckbox/data";
|
|
||||||
import { weChatGroupService, contractService } from "@/utils/db";
|
|
||||||
import { createContractList } from "@/store/module/ckchat/api";
|
|
||||||
import { useWeChatStore } from "@/store/module/weChat/weChat";
|
|
||||||
// 从weChat store获取clearCurrentContact方法
|
|
||||||
const getClearCurrentContact = () =>
|
|
||||||
useWeChatStore.getState().clearCurrentContact;
|
|
||||||
export const useCkChatStore = createPersistStore<CkChatState>(
|
|
||||||
set => ({
|
|
||||||
userInfo: null,
|
|
||||||
isLoggedIn: false,
|
|
||||||
contractList: [], //联系人列表
|
|
||||||
chatSessions: [], //聊天会话
|
|
||||||
kfUserList: [], //客服列表
|
|
||||||
countLables: [], //标签列表
|
|
||||||
newContractList: [], //联系人分组
|
|
||||||
kfSelected: 0, //选中的客服
|
|
||||||
searchKeyword: "", //搜索关键词
|
|
||||||
//客服列表
|
|
||||||
asyncKfUserList: async data => {
|
|
||||||
set({ kfUserList: data });
|
|
||||||
// await kfUserService.createManyWithServerId(data);
|
|
||||||
},
|
|
||||||
// 获取客服列表
|
|
||||||
getkfUserList: async () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.kfUserList;
|
|
||||||
// return await kfUserService.findAll();
|
|
||||||
},
|
|
||||||
// 异步设置标签列表
|
|
||||||
asyncCountLables: async (data: ContactGroupByLabel[]) => {
|
|
||||||
set({ countLables: data });
|
|
||||||
// 清除getNewContractList缓存
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
if (
|
|
||||||
state.getNewContractList &&
|
|
||||||
typeof state.getNewContractList === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
await state.getNewContractList();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 设置搜索关键词
|
|
||||||
setSearchKeyword: (keyword: string) => {
|
|
||||||
set({ searchKeyword: keyword });
|
|
||||||
},
|
|
||||||
// 清除搜索关键词
|
|
||||||
clearSearchKeyword: () => {
|
|
||||||
set({ searchKeyword: "" });
|
|
||||||
},
|
|
||||||
asyncKfSelected: async (data: number) => {
|
|
||||||
set({ kfSelected: data });
|
|
||||||
// 清除getChatSessions、getContractList和getNewContractList缓存
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
if (
|
|
||||||
state.getChatSessions &&
|
|
||||||
typeof state.getChatSessions === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
state.getChatSessions();
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.getContractList &&
|
|
||||||
typeof state.getContractList === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
state.getContractList();
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.getNewContractList &&
|
|
||||||
typeof state.getNewContractList === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
await state.getNewContractList();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取联系人分组列表 - 使用缓存避免无限循环
|
|
||||||
getNewContractList: (() => {
|
|
||||||
let cachedResult: any = null;
|
|
||||||
let lastKfSelected: number | null = null;
|
|
||||||
let lastCountLablesLength: number = 0;
|
|
||||||
let lastSearchKeyword: string = "";
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
|
|
||||||
// 检查是否需要重新计算缓存
|
|
||||||
const shouldRecalculate =
|
|
||||||
cachedResult === null ||
|
|
||||||
lastKfSelected !== state.kfSelected ||
|
|
||||||
lastCountLablesLength !== (state.countLables?.length || 0) ||
|
|
||||||
lastSearchKeyword !== state.searchKeyword;
|
|
||||||
|
|
||||||
if (shouldRecalculate) {
|
|
||||||
// 使用createContractList构建联系人分组数据
|
|
||||||
let contractList = await createContractList(
|
|
||||||
state.kfSelected,
|
|
||||||
state.countLables,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 根据搜索关键词筛选联系人分组
|
|
||||||
if (state.searchKeyword.trim()) {
|
|
||||||
const keyword = state.searchKeyword.toLowerCase();
|
|
||||||
contractList = contractList
|
|
||||||
.map(group => ({
|
|
||||||
...group,
|
|
||||||
contracts:
|
|
||||||
group.contracts?.filter(item => {
|
|
||||||
const nickname = (item.nickname || "").toLowerCase();
|
|
||||||
const conRemark = (item.conRemark || "").toLowerCase();
|
|
||||||
return (
|
|
||||||
nickname.includes(keyword) || conRemark.includes(keyword)
|
|
||||||
);
|
|
||||||
}) || [],
|
|
||||||
}))
|
|
||||||
.filter(group => group.contracts.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedResult = contractList;
|
|
||||||
lastKfSelected = state.kfSelected;
|
|
||||||
lastCountLablesLength = state.countLables?.length || 0;
|
|
||||||
lastSearchKeyword = state.searchKeyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedResult;
|
|
||||||
};
|
|
||||||
})(),
|
|
||||||
// 搜索好友和群组的新方法 - 从本地数据库查询并返回扁平化的搜索结果
|
|
||||||
searchContactsAndGroups: (() => {
|
|
||||||
let cachedResult: (ContractData | weChatGroup)[] = [];
|
|
||||||
let lastKfSelected: number | null = null;
|
|
||||||
let lastSearchKeyword: string = "";
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
|
|
||||||
// 检查是否需要重新计算缓存
|
|
||||||
const shouldRecalculate =
|
|
||||||
lastKfSelected !== state.kfSelected ||
|
|
||||||
lastSearchKeyword !== state.searchKeyword;
|
|
||||||
|
|
||||||
if (shouldRecalculate) {
|
|
||||||
if (state.searchKeyword.trim()) {
|
|
||||||
const keyword = state.searchKeyword.toLowerCase();
|
|
||||||
|
|
||||||
// 从本地数据库查询联系人数据
|
|
||||||
let allContacts: any[] = await contractService.findAll();
|
|
||||||
|
|
||||||
// 从本地数据库查询群组数据
|
|
||||||
let allGroups: any[] = await weChatGroupService.findAll();
|
|
||||||
|
|
||||||
// 根据选中的客服筛选联系人
|
|
||||||
if (state.kfSelected !== 0) {
|
|
||||||
allContacts = allContacts.filter(
|
|
||||||
item => item.wechatAccountId === state.kfSelected,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据选中的客服筛选群组
|
|
||||||
if (state.kfSelected !== 0) {
|
|
||||||
allGroups = allGroups.filter(
|
|
||||||
item => item.wechatAccountId === state.kfSelected,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索匹配的联系人
|
|
||||||
const matchedContacts = allContacts.filter(item => {
|
|
||||||
const nickname = (item.nickname || "").toLowerCase();
|
|
||||||
const conRemark = (item.conRemark || "").toLowerCase();
|
|
||||||
return nickname.includes(keyword) || conRemark.includes(keyword);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 搜索匹配的群组
|
|
||||||
const matchedGroups = allGroups.filter(item => {
|
|
||||||
const nickname = (item.nickname || "").toLowerCase();
|
|
||||||
const conRemark = (item.conRemark || "").toLowerCase();
|
|
||||||
return nickname.includes(keyword) || conRemark.includes(keyword);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 合并搜索结果
|
|
||||||
cachedResult = [...matchedContacts, ...matchedGroups];
|
|
||||||
} else {
|
|
||||||
cachedResult = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
lastKfSelected = state.kfSelected;
|
|
||||||
lastSearchKeyword = state.searchKeyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedResult;
|
|
||||||
};
|
|
||||||
})(),
|
|
||||||
// 异步设置联系人分组列表
|
|
||||||
asyncNewContractList: async (data: any[]) => {
|
|
||||||
set({ newContractList: data });
|
|
||||||
// 清除getNewContractList缓存
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
if (
|
|
||||||
state.getNewContractList &&
|
|
||||||
typeof state.getNewContractList === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
await state.getNewContractList();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 异步设置会话列表
|
|
||||||
asyncChatSessions: data => {
|
|
||||||
set({ chatSessions: data });
|
|
||||||
// 清除getChatSessions缓存
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
if (
|
|
||||||
state.getChatSessions &&
|
|
||||||
typeof state.getChatSessions === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
state.getChatSessions();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 异步设置联系人列表
|
|
||||||
asyncContractList: async (data: ContractData[]) => {
|
|
||||||
set({ contractList: data });
|
|
||||||
await contractService.createManyWithServerId(data);
|
|
||||||
// 清除getContractList缓存
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
if (
|
|
||||||
state.getContractList &&
|
|
||||||
typeof state.getContractList === "function"
|
|
||||||
) {
|
|
||||||
// 触发缓存重新计算
|
|
||||||
state.getContractList();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//获取特定联系人
|
|
||||||
getSomeContractList: (kfSelected: number) => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.contractList.filter(
|
|
||||||
item => item.wechatAccountId === kfSelected,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// 获取联系人列表 - 使用缓存避免无限循环
|
|
||||||
getContractList: (() => {
|
|
||||||
let cachedResult: any = null;
|
|
||||||
let lastKfSelected: number | null = null;
|
|
||||||
let lastContractListLength: number = 0;
|
|
||||||
let lastSearchKeyword: string = "";
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
|
|
||||||
// 检查是否需要重新计算缓存
|
|
||||||
const shouldRecalculate =
|
|
||||||
cachedResult === null ||
|
|
||||||
lastKfSelected !== state.kfSelected ||
|
|
||||||
lastContractListLength !== state.contractList.length ||
|
|
||||||
lastSearchKeyword !== state.searchKeyword;
|
|
||||||
|
|
||||||
if (shouldRecalculate) {
|
|
||||||
let filteredContracts = state.contractList;
|
|
||||||
|
|
||||||
// 根据客服筛选
|
|
||||||
if (state.kfSelected !== 0) {
|
|
||||||
filteredContracts = filteredContracts.filter(
|
|
||||||
item => item.wechatAccountId === state.kfSelected,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据搜索关键词筛选
|
|
||||||
if (state.searchKeyword.trim()) {
|
|
||||||
const keyword = state.searchKeyword.toLowerCase();
|
|
||||||
filteredContracts = filteredContracts.filter(item => {
|
|
||||||
const nickname = (item.nickname || "").toLowerCase();
|
|
||||||
const conRemark = (item.conRemark || "").toLowerCase();
|
|
||||||
return nickname.includes(keyword) || conRemark.includes(keyword);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedResult = filteredContracts;
|
|
||||||
lastKfSelected = state.kfSelected;
|
|
||||||
lastContractListLength = state.contractList.length;
|
|
||||||
lastSearchKeyword = state.searchKeyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedResult;
|
|
||||||
};
|
|
||||||
})(),
|
|
||||||
//异步设置联系人分组
|
|
||||||
asyncWeChatGroup: async (data: weChatGroup[]) => {
|
|
||||||
await weChatGroupService.createManyWithServerId(data);
|
|
||||||
},
|
|
||||||
//获取选中的客服信息
|
|
||||||
getKfSelectedUser: () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.kfUserList.find(item => item.id === state.kfSelected);
|
|
||||||
},
|
|
||||||
getKfUserInfo: (wechatAccountId: number) => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.kfUserList.find(item => item.id === wechatAccountId);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除控制终端用户
|
|
||||||
deleteCtrlUser: (userId: number) => {
|
|
||||||
set(state => ({
|
|
||||||
kfUserList: state.kfUserList.filter(item => item.id !== userId),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
// 更新控制终端用户
|
|
||||||
updateCtrlUser: (user: KfUserListData) => {
|
|
||||||
set(state => ({
|
|
||||||
kfUserList: state.kfUserList.map(item =>
|
|
||||||
item.id === user.id ? user : item,
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
// 清空控制终端用户列表
|
|
||||||
clearkfUserList: () => {
|
|
||||||
set({ kfUserList: [] });
|
|
||||||
},
|
|
||||||
// 获取聊天会话 - 使用缓存避免无限循环
|
|
||||||
getChatSessions: (() => {
|
|
||||||
let cachedResult: any = null;
|
|
||||||
let lastKfSelected: number | null = null;
|
|
||||||
let lastChatSessionsLength: number = 0;
|
|
||||||
let lastSearchKeyword: string = "";
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
|
|
||||||
// 检查是否需要重新计算缓存
|
|
||||||
const shouldRecalculate =
|
|
||||||
cachedResult === null ||
|
|
||||||
lastKfSelected !== state.kfSelected ||
|
|
||||||
lastChatSessionsLength !== state.chatSessions.length ||
|
|
||||||
lastSearchKeyword !== state.searchKeyword;
|
|
||||||
|
|
||||||
if (shouldRecalculate) {
|
|
||||||
let filteredSessions = state.chatSessions;
|
|
||||||
|
|
||||||
// 根据客服筛选
|
|
||||||
if (state.kfSelected !== 0) {
|
|
||||||
filteredSessions = filteredSessions.filter(
|
|
||||||
item => item.wechatAccountId === state.kfSelected,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据搜索关键词筛选
|
|
||||||
if (state.searchKeyword.trim()) {
|
|
||||||
const keyword = state.searchKeyword.toLowerCase();
|
|
||||||
filteredSessions = filteredSessions.filter(item => {
|
|
||||||
const nickname = (item.nickname || "").toLowerCase();
|
|
||||||
const conRemark = (item.conRemark || "").toLowerCase();
|
|
||||||
return nickname.includes(keyword) || conRemark.includes(keyword);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedResult = filteredSessions;
|
|
||||||
lastKfSelected = state.kfSelected;
|
|
||||||
lastChatSessionsLength = state.chatSessions.length;
|
|
||||||
lastSearchKeyword = state.searchKeyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cachedResult;
|
|
||||||
};
|
|
||||||
})(),
|
|
||||||
// 添加聊天会话
|
|
||||||
addChatSession: (session: ContractData | weChatGroup) => {
|
|
||||||
set(state => {
|
|
||||||
// 检查是否已存在相同id的会话
|
|
||||||
const exists = state.chatSessions.some(item => item.id === session.id);
|
|
||||||
// 如果已存在则不添加,否则添加到列表中
|
|
||||||
return {
|
|
||||||
chatSessions: exists
|
|
||||||
? state.chatSessions
|
|
||||||
: [...state.chatSessions, session as ContractData | weChatGroup],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 更新聊天会话
|
|
||||||
updateChatSession: (session: ContractData | weChatGroup) => {
|
|
||||||
set(state => ({
|
|
||||||
chatSessions: state.chatSessions.map(item =>
|
|
||||||
item.id === session.id ? { ...item, ...session } : item,
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
// 删除聊天会话
|
|
||||||
deleteChatSession: (sessionId: number) => {
|
|
||||||
set(state => ({
|
|
||||||
chatSessions: state.chatSessions.filter(item => item.id !== sessionId),
|
|
||||||
}));
|
|
||||||
//当前选中的客户清空
|
|
||||||
getClearCurrentContact();
|
|
||||||
},
|
|
||||||
// 设置用户信息
|
|
||||||
setUserInfo: (userInfo: CkUserInfo) => {
|
|
||||||
set({ userInfo, isLoggedIn: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 清除用户信息
|
|
||||||
clearUserInfo: () => {
|
|
||||||
set({ userInfo: null, isLoggedIn: false });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新账户信息
|
|
||||||
updateAccount: (account: Partial<CkAccount>) => {
|
|
||||||
set(state => ({
|
|
||||||
userInfo: state.userInfo
|
|
||||||
? {
|
|
||||||
...state.userInfo,
|
|
||||||
account: { ...state.userInfo.account, ...account },
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新租户信息
|
|
||||||
updateTenant: (tenant: Partial<CkTenant>) => {
|
|
||||||
set(state => ({
|
|
||||||
userInfo: state.userInfo
|
|
||||||
? {
|
|
||||||
...state.userInfo,
|
|
||||||
tenant: { ...state.userInfo.tenant, ...tenant },
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取账户ID
|
|
||||||
getAccountId: () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return Number(state.userInfo?.account?.id) || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取租户ID
|
|
||||||
getTenantId: () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.userInfo?.tenant?.id || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取账户名称
|
|
||||||
getAccountName: () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return (
|
|
||||||
state.userInfo?.account?.realName ||
|
|
||||||
state.userInfo?.account?.userName ||
|
|
||||||
null
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取租户名称
|
|
||||||
getTenantName: () => {
|
|
||||||
const state = useCkChatStore.getState();
|
|
||||||
return state.userInfo?.tenant?.name || null;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "ckchat-store",
|
|
||||||
partialize: state => ({
|
|
||||||
userInfo: state.userInfo,
|
|
||||||
isLoggedIn: state.isLoggedIn,
|
|
||||||
kfUserList: state.kfUserList,
|
|
||||||
}),
|
|
||||||
onRehydrateStorage: () => state => {
|
|
||||||
// console.log("CkChat store hydrated:", state);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// 导出便捷的获取方法
|
|
||||||
export const getCkAccountId = () => useCkChatStore.getState().getAccountId();
|
|
||||||
export const getCkTenantId = () => useCkChatStore.getState().getTenantId();
|
|
||||||
export const getCkAccountName = () =>
|
|
||||||
useCkChatStore.getState().getAccountName();
|
|
||||||
export const getCkTenantName = () => useCkChatStore.getState().getTenantName();
|
|
||||||
export const getChatSessions = () =>
|
|
||||||
useCkChatStore.getState().getChatSessions();
|
|
||||||
export const addChatSession = (session: ContractData | weChatGroup) =>
|
|
||||||
useCkChatStore.getState().addChatSession(session);
|
|
||||||
export const updateChatSession = (session: ContractData | weChatGroup) =>
|
|
||||||
useCkChatStore.getState().updateChatSession(session);
|
|
||||||
export const deleteChatSession = (sessionId: string) =>
|
|
||||||
useCkChatStore.getState().deleteChatSession(sessionId);
|
|
||||||
export const getkfUserList = () => useCkChatStore.getState().kfUserList;
|
|
||||||
export const addCtrlUser = (user: KfUserListData) =>
|
|
||||||
useCkChatStore.getState().addCtrlUser(user);
|
|
||||||
export const deleteCtrlUser = (userId: number) =>
|
|
||||||
useCkChatStore.getState().deleteCtrlUser(userId);
|
|
||||||
export const updateCtrlUser = (user: KfUserListData) =>
|
|
||||||
useCkChatStore.getState().updateCtrlUser(user);
|
|
||||||
export const asyncKfUserList = (data: KfUserListData[]) =>
|
|
||||||
useCkChatStore.getState().asyncKfUserList(data);
|
|
||||||
export const asyncContractList = (data: ContractData[]) =>
|
|
||||||
useCkChatStore.getState().asyncContractList(data);
|
|
||||||
export const asyncChatSessions = (data: ContractData[]) =>
|
|
||||||
useCkChatStore.getState().asyncChatSessions(data);
|
|
||||||
export const asyncKfSelected = (data: number) =>
|
|
||||||
useCkChatStore.getState().asyncKfSelected(data);
|
|
||||||
export const asyncWeChatGroup = (data: weChatGroup[]) =>
|
|
||||||
useCkChatStore.getState().asyncWeChatGroup(data);
|
|
||||||
export const getKfSelectedUser = () =>
|
|
||||||
useCkChatStore.getState().getKfSelectedUser();
|
|
||||||
export const getKfUserInfo = (wechatAccountId: number) =>
|
|
||||||
useCkChatStore.getState().getKfUserInfo(wechatAccountId);
|
|
||||||
export const getContractList = () =>
|
|
||||||
useCkChatStore.getState().getContractList();
|
|
||||||
export const getNewContractList = () =>
|
|
||||||
useCkChatStore.getState().getNewContractList();
|
|
||||||
export const asyncCountLables = (data: ContactGroupByLabel[]) =>
|
|
||||||
useCkChatStore.getState().asyncCountLables(data);
|
|
||||||
export const asyncNewContractList = (data: any[]) =>
|
|
||||||
useCkChatStore.getState().asyncNewContractList(data);
|
|
||||||
export const getCountLables = () => useCkChatStore.getState().countLables;
|
|
||||||
export const setSearchKeyword = (keyword: string) =>
|
|
||||||
useCkChatStore.getState().setSearchKeyword(keyword);
|
|
||||||
export const clearSearchKeyword = () =>
|
|
||||||
useCkChatStore.getState().clearSearchKeyword();
|
|
||||||
export const searchContactsAndGroups = () =>
|
|
||||||
useCkChatStore.getState().searchContactsAndGroups();
|
|
||||||
useCkChatStore.getState().getKfSelectedUser();
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
|
||||||
// 微信聊天相关的类型定义
|
|
||||||
export interface WeChatState {
|
|
||||||
// 当前选中的联系人/群组
|
|
||||||
currentContract: ContractData | weChatGroup | null;
|
|
||||||
|
|
||||||
// 当前聊天用户的消息列表(只存储当前聊天用户的消息)
|
|
||||||
currentMessages: ChatRecord[];
|
|
||||||
// 清空当前联系人
|
|
||||||
clearCurrentContact: () => void;
|
|
||||||
// 消息加载状态
|
|
||||||
messagesLoading: boolean;
|
|
||||||
isLoadingData: boolean;
|
|
||||||
currentGroupMembers: any[];
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
setCurrentContact: (
|
|
||||||
contract: ContractData | weChatGroup,
|
|
||||||
isExist?: boolean,
|
|
||||||
) => void;
|
|
||||||
loadChatMessages: (Init: boolean, To?: number) => Promise<void>;
|
|
||||||
SearchMessage: (params: {
|
|
||||||
From: number;
|
|
||||||
To: number;
|
|
||||||
keyword: string;
|
|
||||||
Count?: number;
|
|
||||||
}) => Promise<void>;
|
|
||||||
// 视频消息处理方法
|
|
||||||
setVideoLoading: (messageId: number, isLoading: boolean) => void;
|
|
||||||
setVideoUrl: (messageId: number, videoUrl: string) => void;
|
|
||||||
addMessage: (message: ChatRecord) => void;
|
|
||||||
receivedMsg: (message: ChatRecord) => void;
|
|
||||||
}
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
import { persist } from "zustand/middleware";
|
|
||||||
import {
|
|
||||||
getChatMessages,
|
|
||||||
getChatroomMessages,
|
|
||||||
getGroupMembers,
|
|
||||||
} from "@/pages/pc/ckbox/api";
|
|
||||||
import { WeChatState } from "./weChat.data";
|
|
||||||
import { clearUnreadCount, updateConfig } from "@/pages/pc/ckbox/api";
|
|
||||||
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
|
||||||
import { weChatGroupService, contractService } from "@/utils/db";
|
|
||||||
import {
|
|
||||||
addChatSession,
|
|
||||||
updateChatSession,
|
|
||||||
useCkChatStore,
|
|
||||||
} from "@/store/module/ckchat/ckchat";
|
|
||||||
|
|
||||||
export const useWeChatStore = create<WeChatState>()(
|
|
||||||
persist(
|
|
||||||
(set, get) => ({
|
|
||||||
// 初始状态
|
|
||||||
currentContract: null,
|
|
||||||
currentMessages: [],
|
|
||||||
messagesLoading: false,
|
|
||||||
isLoadingData: false,
|
|
||||||
currentGroupMembers: [],
|
|
||||||
//清空当前联系人
|
|
||||||
clearCurrentContact: () => {
|
|
||||||
set({ currentContract: null, currentMessages: [] });
|
|
||||||
},
|
|
||||||
// Actions
|
|
||||||
setCurrentContact: (
|
|
||||||
contract: ContractData | weChatGroup,
|
|
||||||
isExist?: boolean,
|
|
||||||
) => {
|
|
||||||
const state = useWeChatStore.getState();
|
|
||||||
// 切换联系人时清空当前消息,等待重新加载
|
|
||||||
set({ currentMessages: [] });
|
|
||||||
clearUnreadCount([contract.id]).then(() => {
|
|
||||||
if (isExist) {
|
|
||||||
updateChatSession({ ...contract, unreadCount: 0 });
|
|
||||||
} else {
|
|
||||||
addChatSession(contract);
|
|
||||||
}
|
|
||||||
set({ currentContract: contract });
|
|
||||||
updateConfig({
|
|
||||||
id: contract.id,
|
|
||||||
config: { chat: true },
|
|
||||||
});
|
|
||||||
state.loadChatMessages(true, 4704624000000);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadChatMessages: async (Init: boolean, To?: number) => {
|
|
||||||
const state = useWeChatStore.getState();
|
|
||||||
const contact = state.currentContract;
|
|
||||||
set({ messagesLoading: true });
|
|
||||||
set({ isLoadingData: Init });
|
|
||||||
try {
|
|
||||||
const params: any = {
|
|
||||||
wechatAccountId: contact.wechatAccountId,
|
|
||||||
From: 1,
|
|
||||||
To: To || +new Date(),
|
|
||||||
Count: 5,
|
|
||||||
olderData: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ("chatroomId" in contact && contact.chatroomId) {
|
|
||||||
params.wechatChatroomId = contact.id;
|
|
||||||
const messages = await getChatroomMessages(params);
|
|
||||||
const currentGroupMembers = await getGroupMembers({
|
|
||||||
id: contact.id,
|
|
||||||
});
|
|
||||||
if (Init) {
|
|
||||||
set({ currentMessages: messages || [], currentGroupMembers });
|
|
||||||
} else {
|
|
||||||
set({
|
|
||||||
currentMessages: [
|
|
||||||
...(messages || []),
|
|
||||||
...state.currentMessages,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
params.wechatFriendId = contact.id;
|
|
||||||
const messages = await getChatMessages(params);
|
|
||||||
if (Init) {
|
|
||||||
set({ currentMessages: messages || [] });
|
|
||||||
} else {
|
|
||||||
set({
|
|
||||||
currentMessages: [
|
|
||||||
...(messages || []),
|
|
||||||
...state.currentMessages,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set({ messagesLoading: false });
|
|
||||||
} catch (error) {
|
|
||||||
console.error("获取聊天消息失败:", error);
|
|
||||||
} finally {
|
|
||||||
set({ messagesLoading: false });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SearchMessage: async ({
|
|
||||||
From = 1,
|
|
||||||
To = 4704624000000,
|
|
||||||
keyword = "",
|
|
||||||
Count = 20,
|
|
||||||
}: {
|
|
||||||
From: number;
|
|
||||||
To: number;
|
|
||||||
keyword: string;
|
|
||||||
Count?: number;
|
|
||||||
}) => {
|
|
||||||
const state = useWeChatStore.getState();
|
|
||||||
const contact = state.currentContract;
|
|
||||||
set({ messagesLoading: true });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const params: any = {
|
|
||||||
wechatAccountId: contact.wechatAccountId,
|
|
||||||
From,
|
|
||||||
To,
|
|
||||||
keyword,
|
|
||||||
Count,
|
|
||||||
olderData: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ("chatroomId" in contact && contact.chatroomId) {
|
|
||||||
params.wechatChatroomId = contact.id;
|
|
||||||
const messages = await getChatroomMessages(params);
|
|
||||||
const currentGroupMembers = await getGroupMembers({
|
|
||||||
id: contact.id,
|
|
||||||
});
|
|
||||||
set({ currentMessages: messages || [], currentGroupMembers });
|
|
||||||
} else {
|
|
||||||
params.wechatFriendId = contact.id;
|
|
||||||
const messages = await getChatMessages(params);
|
|
||||||
set({ currentMessages: messages || [] });
|
|
||||||
}
|
|
||||||
set({ messagesLoading: false });
|
|
||||||
} catch (error) {
|
|
||||||
console.error("获取聊天消息失败:", error);
|
|
||||||
} finally {
|
|
||||||
set({ messagesLoading: false });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setMessageLoading: loading => {
|
|
||||||
set({ messagesLoading: Boolean(loading) });
|
|
||||||
},
|
|
||||||
|
|
||||||
addMessage: message => {
|
|
||||||
set(state => ({
|
|
||||||
currentMessages: [...state.currentMessages, message],
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
receivedMsg: async message => {
|
|
||||||
const currentContract = useWeChatStore.getState().currentContract;
|
|
||||||
//判断群还是好友
|
|
||||||
const getMessageId =
|
|
||||||
message?.wechatChatroomId || message.wechatFriendId;
|
|
||||||
const isWechatGroup = message?.wechatChatroomId;
|
|
||||||
//当前选中聊天的群或好友
|
|
||||||
if (currentContract && currentContract.id == getMessageId) {
|
|
||||||
set(state => ({
|
|
||||||
currentMessages: [...state.currentMessages, message],
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
//更新消息列表unread数值,根据接收的++1 这样
|
|
||||||
const chatSessions = useCkChatStore.getState().chatSessions;
|
|
||||||
const session = chatSessions.find(item => item.id == getMessageId);
|
|
||||||
if (session) {
|
|
||||||
session.unreadCount = Number(session.unreadCount) + 1;
|
|
||||||
updateChatSession(session);
|
|
||||||
} else {
|
|
||||||
if (isWechatGroup) {
|
|
||||||
const [group] = await weChatGroupService.findByIds(getMessageId);
|
|
||||||
if (group) {
|
|
||||||
addChatSession({
|
|
||||||
...group,
|
|
||||||
unreadCount: 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const [user] = await contractService.findByIds(getMessageId);
|
|
||||||
addChatSession({
|
|
||||||
...user,
|
|
||||||
unreadCount: 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateMessage: (messageId, updates) => {
|
|
||||||
set(state => ({
|
|
||||||
currentMessages: state.currentMessages.map(msg =>
|
|
||||||
msg.id === messageId ? { ...msg, ...updates } : msg,
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
// 便捷选择器
|
|
||||||
getCurrentContact: () => get().currentContract,
|
|
||||||
getCurrentMessages: () => get().currentMessages,
|
|
||||||
getMessagesLoading: () => get().messagesLoading,
|
|
||||||
|
|
||||||
// 视频消息处理方法
|
|
||||||
setVideoLoading: (messageId: number, isLoading: boolean) => {
|
|
||||||
set(state => ({
|
|
||||||
currentMessages: state.currentMessages.map(msg => {
|
|
||||||
if (msg.id === messageId) {
|
|
||||||
try {
|
|
||||||
const content = JSON.parse(msg.content);
|
|
||||||
// 更新加载状态
|
|
||||||
const updatedContent = { ...content, isLoading };
|
|
||||||
return {
|
|
||||||
...msg,
|
|
||||||
content: JSON.stringify(updatedContent),
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
console.error("更新视频加载状态失败:", e);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
setVideoUrl: (messageId: number, videoUrl: string) => {
|
|
||||||
set(state => ({
|
|
||||||
currentMessages: state.currentMessages.map(msg => {
|
|
||||||
if (msg.id === messageId) {
|
|
||||||
try {
|
|
||||||
const content = JSON.parse(msg.content);
|
|
||||||
// 检查视频是否已经下载完毕,避免重复更新
|
|
||||||
if (content.videoUrl && content.videoUrl === videoUrl) {
|
|
||||||
console.log("视频已下载,跳过重复更新:", messageId);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置视频URL并清除加载状态
|
|
||||||
const updatedContent = {
|
|
||||||
...content,
|
|
||||||
videoUrl,
|
|
||||||
isLoading: false,
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
...msg,
|
|
||||||
content: JSON.stringify(updatedContent),
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
console.error("更新视频URL失败:", e);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
clearAllData: () => {
|
|
||||||
set({
|
|
||||||
currentContract: null,
|
|
||||||
currentMessages: [],
|
|
||||||
messagesLoading: false,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "wechat-storage",
|
|
||||||
partialize: state => ({
|
|
||||||
// currentContract 不做持久化,登录和页面刷新时直接清空
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 导出便捷的选择器函数
|
|
||||||
export const useCurrentContact = () =>
|
|
||||||
useWeChatStore(state => state.currentContract);
|
|
||||||
export const useCurrentMessages = () =>
|
|
||||||
useWeChatStore(state => state.currentMessages);
|
|
||||||
export const useMessagesLoading = () =>
|
|
||||||
useWeChatStore(state => state.messagesLoading);
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { ChatRecord } from "@/pages/pc/ckbox/data";
|
|
||||||
export interface Messages {
|
|
||||||
friendMessage?: ChatRecord | null;
|
|
||||||
chatroomMessage?: ChatRecord | null;
|
|
||||||
seq: number;
|
|
||||||
cmdType: string;
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
//消息管理器
|
|
||||||
import { deepCopy } from "@/utils/common";
|
|
||||||
import { WebSocketMessage } from "./websocket";
|
|
||||||
import { getkfUserList, asyncKfUserList } from "@/store/module/ckchat/ckchat";
|
|
||||||
import { Messages } from "./msg.data";
|
|
||||||
|
|
||||||
import { useWeChatStore } from "@/store/module/weChat/weChat";
|
|
||||||
// 消息处理器类型定义
|
|
||||||
type MessageHandler = (message: WebSocketMessage) => void;
|
|
||||||
const setVideoUrl = useWeChatStore.getState().setVideoUrl;
|
|
||||||
const addMessage = useWeChatStore.getState().addMessage;
|
|
||||||
const receivedMsg = useWeChatStore.getState().receivedMsg;
|
|
||||||
|
|
||||||
// 消息处理器映射
|
|
||||||
const messageHandlers: Record<string, MessageHandler> = {
|
|
||||||
// 微信账号存活状态响应
|
|
||||||
CmdRequestWechatAccountsAliveStatusResp: message => {
|
|
||||||
// console.log("微信账号存活状态响应", message);
|
|
||||||
// 获取客服列表
|
|
||||||
const kfUserList = deepCopy(getkfUserList());
|
|
||||||
const wechatAccountsAliveStatus = message.wechatAccountsAliveStatus || {};
|
|
||||||
// 遍历客服列表,更新存活状态
|
|
||||||
kfUserList.forEach(kfUser => {
|
|
||||||
kfUser.isOnline = wechatAccountsAliveStatus[kfUser.id];
|
|
||||||
});
|
|
||||||
asyncKfUserList(kfUserList);
|
|
||||||
},
|
|
||||||
// 发送消息响应
|
|
||||||
CmdSendMessageResp: message => {
|
|
||||||
console.log("发送消息响应", message);
|
|
||||||
addMessage(message.friendMessage || message.chatroomMessage);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
},
|
|
||||||
CmdSendMessageResult: message => {
|
|
||||||
console.log("发送消息结果", message);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
},
|
|
||||||
// 接收消息响应
|
|
||||||
CmdReceiveMessageResp: message => {
|
|
||||||
console.log("接收消息响应", message);
|
|
||||||
addMessage(message.friendMessage || message.chatroomMessage);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
},
|
|
||||||
//收到消息
|
|
||||||
CmdNewMessage: (message: Messages) => {
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
receivedMsg(message.friendMessage || message.chatroomMessage);
|
|
||||||
},
|
|
||||||
CmdFriendInfoChanged: message => {
|
|
||||||
// console.log("好友信息变更", message);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
},
|
|
||||||
|
|
||||||
// 登录响应
|
|
||||||
CmdSignInResp: message => {
|
|
||||||
console.log("登录响应", message);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通知消息
|
|
||||||
CmdNotify: message => {
|
|
||||||
console.log("通知消息", message);
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
if (message.notify == "Kicked out") {
|
|
||||||
// 被踢出时直接跳转到登录页面
|
|
||||||
window.location.href = "/login";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
CmdDownloadVideoResult: message => {
|
|
||||||
// 在这里添加具体的处理逻辑
|
|
||||||
setVideoUrl(message.friendMessageId, message.url);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 可以继续添加更多处理器...
|
|
||||||
};
|
|
||||||
|
|
||||||
// 默认处理器
|
|
||||||
const defaultHandler: MessageHandler = message => {
|
|
||||||
console.log("未知消息类型", message.cmdType, message);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 注册新的消息处理器
|
|
||||||
export const registerMessageHandler = (
|
|
||||||
cmdType: string,
|
|
||||||
handler: MessageHandler,
|
|
||||||
) => {
|
|
||||||
messageHandlers[cmdType] = handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 移除消息处理器
|
|
||||||
export const unregisterMessageHandler = (cmdType: string) => {
|
|
||||||
delete messageHandlers[cmdType];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取所有已注册的消息类型
|
|
||||||
export const getRegisteredMessageTypes = (): string[] => {
|
|
||||||
return Object.keys(messageHandlers);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 消息管理核心函数
|
|
||||||
export const msgManageCore = (message: WebSocketMessage) => {
|
|
||||||
const cmdType = message.cmdType;
|
|
||||||
if (!cmdType) {
|
|
||||||
console.warn("消息缺少cmdType字段", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取对应的处理器,如果没有则使用默认处理器
|
|
||||||
const handler = messageHandlers[cmdType] || defaultHandler;
|
|
||||||
|
|
||||||
try {
|
|
||||||
handler(message);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`处理消息类型 ${cmdType} 时发生错误:`, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,586 +0,0 @@
|
|||||||
import { createPersistStore } from "@/store/createPersistStore";
|
|
||||||
import { Toast } from "antd-mobile";
|
|
||||||
import { useUserStore } from "../user";
|
|
||||||
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
|
||||||
const { getAccountId } = useCkChatStore.getState();
|
|
||||||
import { msgManageCore } from "./msgManage";
|
|
||||||
// WebSocket消息类型
|
|
||||||
export interface WebSocketMessage {
|
|
||||||
cmdType?: string;
|
|
||||||
seq?: number;
|
|
||||||
wechatAccountIds?: string[];
|
|
||||||
content?: any;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebSocket连接状态
|
|
||||||
export enum WebSocketStatus {
|
|
||||||
DISCONNECTED = "disconnected",
|
|
||||||
CONNECTING = "connecting",
|
|
||||||
CONNECTED = "connected",
|
|
||||||
RECONNECTING = "reconnecting",
|
|
||||||
ERROR = "error",
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebSocket配置
|
|
||||||
interface WebSocketConfig {
|
|
||||||
url: string;
|
|
||||||
client: string;
|
|
||||||
accountId: number;
|
|
||||||
accessToken: string;
|
|
||||||
autoReconnect: boolean;
|
|
||||||
cmdType: string;
|
|
||||||
seq: number;
|
|
||||||
reconnectInterval: number;
|
|
||||||
maxReconnectAttempts: number;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WebSocketState {
|
|
||||||
// 连接状态
|
|
||||||
status: WebSocketStatus;
|
|
||||||
ws: WebSocket | null;
|
|
||||||
|
|
||||||
// 配置信息
|
|
||||||
config: WebSocketConfig | null;
|
|
||||||
|
|
||||||
// 消息相关
|
|
||||||
messages: WebSocketMessage[];
|
|
||||||
unreadCount: number;
|
|
||||||
|
|
||||||
// 重连相关
|
|
||||||
reconnectAttempts: number;
|
|
||||||
reconnectTimer: NodeJS.Timeout | null;
|
|
||||||
aliveStatusTimer: NodeJS.Timeout | null; // 客服用户状态查询定时器
|
|
||||||
|
|
||||||
// 方法
|
|
||||||
connect: (config: Partial<WebSocketConfig>) => void;
|
|
||||||
disconnect: () => void;
|
|
||||||
sendMessage: (message: Omit<WebSocketMessage, "id" | "timestamp">) => void;
|
|
||||||
sendCommand: (cmdType: string, data?: any) => void;
|
|
||||||
clearMessages: () => void;
|
|
||||||
markAsRead: () => void;
|
|
||||||
reconnect: () => void;
|
|
||||||
clearConnectionState: () => void; // 清空连接状态
|
|
||||||
|
|
||||||
// 内部方法
|
|
||||||
_handleOpen: () => void;
|
|
||||||
_handleMessage: (event: MessageEvent) => void;
|
|
||||||
_handleClose: (event: CloseEvent) => void;
|
|
||||||
_handleError: (event: Event) => void;
|
|
||||||
_startReconnectTimer: () => void;
|
|
||||||
_stopReconnectTimer: () => void;
|
|
||||||
_startAliveStatusTimer: () => void; // 启动客服状态查询定时器
|
|
||||||
_stopAliveStatusTimer: () => void; // 停止客服状态查询定时器
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认配置
|
|
||||||
const DEFAULT_CONFIG: WebSocketConfig = {
|
|
||||||
url: "wss://kf.quwanzhi.com:9993",
|
|
||||||
client: "kefu-client",
|
|
||||||
accountId: 0,
|
|
||||||
accessToken: "",
|
|
||||||
autoReconnect: true,
|
|
||||||
cmdType: "", // 添加默认的命令类型
|
|
||||||
seq: +new Date(), // 添加默认的序列号
|
|
||||||
reconnectInterval: 3000,
|
|
||||||
maxReconnectAttempts: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useWebSocketStore = createPersistStore<WebSocketState>(
|
|
||||||
(set, get) => ({
|
|
||||||
status: WebSocketStatus.DISCONNECTED,
|
|
||||||
ws: null,
|
|
||||||
config: null,
|
|
||||||
messages: [],
|
|
||||||
unreadCount: 0,
|
|
||||||
reconnectAttempts: 0,
|
|
||||||
reconnectTimer: null,
|
|
||||||
aliveStatusTimer: null,
|
|
||||||
|
|
||||||
// 连接WebSocket
|
|
||||||
connect: (config: Partial<WebSocketConfig>) => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
// 检查当前连接状态,避免重复连接
|
|
||||||
if (
|
|
||||||
currentState.status === WebSocketStatus.CONNECTED ||
|
|
||||||
currentState.status === WebSocketStatus.CONNECTING
|
|
||||||
) {
|
|
||||||
// console.log("WebSocket已连接或正在连接,跳过重复连接", {
|
|
||||||
// currentStatus: currentState.status,
|
|
||||||
// hasWebSocket: !!currentState.ws,
|
|
||||||
// });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果已经有WebSocket实例,先断开
|
|
||||||
if (currentState.ws) {
|
|
||||||
// console.log("断开现有WebSocket连接");
|
|
||||||
currentState.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并配置
|
|
||||||
const fullConfig: WebSocketConfig = {
|
|
||||||
...DEFAULT_CONFIG,
|
|
||||||
...config,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
const { token2 } = useUserStore.getState();
|
|
||||||
|
|
||||||
if (!token2) {
|
|
||||||
Toast.show({ content: "未找到有效的访问令牌", position: "top" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建WebSocket URL
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
client: fullConfig.client.toString(),
|
|
||||||
accountId: getAccountId().toString(),
|
|
||||||
accessToken: token2,
|
|
||||||
t: Date.now().toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const wsUrl = fullConfig.url + "?" + params;
|
|
||||||
|
|
||||||
// 检查URL是否为localhost,如果是则不连接
|
|
||||||
if (wsUrl.includes("localhost") || wsUrl.includes("127.0.0.1")) {
|
|
||||||
// console.error("WebSocket连接被拦截:不允许连接到本地地址", wsUrl);
|
|
||||||
Toast.show({
|
|
||||||
content: "WebSocket连接被拦截:不允许连接到本地地址",
|
|
||||||
position: "top",
|
|
||||||
});
|
|
||||||
set({ status: WebSocketStatus.ERROR });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.CONNECTING,
|
|
||||||
config: fullConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const ws = new WebSocket(wsUrl);
|
|
||||||
|
|
||||||
// 绑定事件处理器
|
|
||||||
ws.onopen = () => get()._handleOpen();
|
|
||||||
ws.onmessage = event => get()._handleMessage(event);
|
|
||||||
ws.onclose = event => get()._handleClose(event);
|
|
||||||
ws.onerror = event => get()._handleError(event);
|
|
||||||
|
|
||||||
set({ ws });
|
|
||||||
|
|
||||||
// console.log("WebSocket连接创建成功", wsUrl);
|
|
||||||
} catch (error) {
|
|
||||||
// console.error("WebSocket连接失败:", error);
|
|
||||||
set({ status: WebSocketStatus.ERROR });
|
|
||||||
Toast.show({ content: "WebSocket连接失败", position: "top" });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 断开连接
|
|
||||||
disconnect: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (currentState.ws) {
|
|
||||||
currentState.ws.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
currentState._stopReconnectTimer();
|
|
||||||
currentState._stopAliveStatusTimer();
|
|
||||||
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.DISCONNECTED,
|
|
||||||
ws: null,
|
|
||||||
reconnectAttempts: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log("WebSocket连接已断开");
|
|
||||||
},
|
|
||||||
|
|
||||||
// 发送消息
|
|
||||||
sendMessage: message => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (
|
|
||||||
currentState.status !== WebSocketStatus.CONNECTED ||
|
|
||||||
!currentState.ws
|
|
||||||
) {
|
|
||||||
Toast.show({ content: "WebSocket未连接", position: "top" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullMessage: WebSocketMessage = {
|
|
||||||
...message,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
currentState.ws.send(JSON.stringify(fullMessage));
|
|
||||||
// console.log("消息发送成功:", fullMessage);
|
|
||||||
} catch (error) {
|
|
||||||
// console.error("消息发送失败:", error);
|
|
||||||
Toast.show({ content: "消息发送失败", position: "top" });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 发送命令
|
|
||||||
sendCommand: (cmdType: string, data?: any) => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (
|
|
||||||
currentState.status !== WebSocketStatus.CONNECTED ||
|
|
||||||
!currentState.ws
|
|
||||||
) {
|
|
||||||
Toast.show({
|
|
||||||
content: "WebSocket未连接,正在重新连接...",
|
|
||||||
position: "top",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 重置连接状态并发起重新连接
|
|
||||||
set({ status: WebSocketStatus.DISCONNECTED });
|
|
||||||
if (currentState.config) {
|
|
||||||
currentState.connect(currentState.config);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const command = {
|
|
||||||
cmdType,
|
|
||||||
...data,
|
|
||||||
seq: +new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
currentState.ws.send(JSON.stringify(command));
|
|
||||||
// console.log("命令发送成功:", command);
|
|
||||||
} catch (error) {
|
|
||||||
// console.error("命令发送失败:", error);
|
|
||||||
Toast.show({ content: "命令发送失败", position: "top" });
|
|
||||||
|
|
||||||
// 发送失败时也尝试重新连接
|
|
||||||
set({ status: WebSocketStatus.DISCONNECTED });
|
|
||||||
if (currentState.config) {
|
|
||||||
currentState.connect(currentState.config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 清除消息
|
|
||||||
clearMessages: () => {
|
|
||||||
set({ messages: [], unreadCount: 0 });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 标记为已读
|
|
||||||
markAsRead: () => {
|
|
||||||
set({ unreadCount: 0 });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 重连
|
|
||||||
reconnect: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (currentState.config) {
|
|
||||||
// 检查是否允许重连
|
|
||||||
if (!currentState.config.autoReconnect) {
|
|
||||||
// console.log("自动重连已禁用,不再尝试重连");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentState.connect(currentState.config);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 清空连接状态(用于退出登录时)
|
|
||||||
clearConnectionState: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
// 断开现有连接
|
|
||||||
if (currentState.ws) {
|
|
||||||
currentState.ws.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 停止所有定时器
|
|
||||||
currentState._stopReconnectTimer();
|
|
||||||
currentState._stopAliveStatusTimer();
|
|
||||||
|
|
||||||
// 重置所有状态
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.DISCONNECTED,
|
|
||||||
ws: null,
|
|
||||||
config: null,
|
|
||||||
messages: [],
|
|
||||||
unreadCount: 0,
|
|
||||||
reconnectAttempts: 0,
|
|
||||||
reconnectTimer: null,
|
|
||||||
aliveStatusTimer: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log("WebSocket连接状态已清空");
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:处理连接打开
|
|
||||||
_handleOpen: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.CONNECTED,
|
|
||||||
reconnectAttempts: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log("WebSocket连接成功");
|
|
||||||
const { token2 } = useUserStore.getState();
|
|
||||||
// 发送登录命令
|
|
||||||
if (currentState.config) {
|
|
||||||
currentState.sendCommand("CmdSignIn", {
|
|
||||||
accessToken: token2,
|
|
||||||
accountId: Number(getAccountId()),
|
|
||||||
client: currentState.config?.client || "kefu-client",
|
|
||||||
seq: +new Date(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Toast.show({ content: "WebSocket连接成功", position: "top" });
|
|
||||||
|
|
||||||
// 启动客服状态查询定时器
|
|
||||||
currentState._startAliveStatusTimer();
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:处理消息接收
|
|
||||||
_handleMessage: (event: MessageEvent) => {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
// console.log("收到WebSocket消息:", data);
|
|
||||||
|
|
||||||
// 处理特定的通知消息
|
|
||||||
if (data.cmdType === "CmdNotify") {
|
|
||||||
// 处理Auth failed通知
|
|
||||||
if (data.notify === "Auth failed" || data.notify === "Kicked out") {
|
|
||||||
// console.error(`WebSocket ${data.notify},断开连接`);
|
|
||||||
Toast.show({
|
|
||||||
content: `WebSocket ${data.notify},断开连接`,
|
|
||||||
position: "top",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 禁用自动重连
|
|
||||||
if (get().config) {
|
|
||||||
set({
|
|
||||||
config: {
|
|
||||||
...get().config!,
|
|
||||||
autoReconnect: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 停止客服状态查询定时器
|
|
||||||
get()._stopAliveStatusTimer();
|
|
||||||
|
|
||||||
// 断开连接
|
|
||||||
get().disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentState = get();
|
|
||||||
const newMessage: WebSocketMessage = {
|
|
||||||
id: Date.now().toString(),
|
|
||||||
type: data.type || "message",
|
|
||||||
content: data,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
sender: data.sender,
|
|
||||||
receiver: data.receiver,
|
|
||||||
};
|
|
||||||
|
|
||||||
set({
|
|
||||||
messages: [...currentState.messages, newMessage],
|
|
||||||
unreadCount: currentState.unreadCount + 1,
|
|
||||||
});
|
|
||||||
//消息处理器
|
|
||||||
msgManageCore(data);
|
|
||||||
|
|
||||||
// 可以在这里添加消息处理逻辑
|
|
||||||
// 比如播放提示音、显示通知等
|
|
||||||
} catch (error) {
|
|
||||||
// console.error("解析WebSocket消息失败:", error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:处理连接关闭
|
|
||||||
_handleClose: (event: CloseEvent) => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
// console.log("WebSocket连接关闭:", event.code, event.reason);
|
|
||||||
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.DISCONNECTED,
|
|
||||||
ws: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 自动重连逻辑
|
|
||||||
if (
|
|
||||||
currentState.config?.autoReconnect &&
|
|
||||||
currentState.reconnectAttempts <
|
|
||||||
(currentState.config?.maxReconnectAttempts || 5)
|
|
||||||
) {
|
|
||||||
// console.log("尝试自动重连...");
|
|
||||||
currentState._startReconnectTimer();
|
|
||||||
} else if (!currentState.config?.autoReconnect) {
|
|
||||||
// console.log("自动重连已禁用,不再尝试重连");
|
|
||||||
// 重置重连计数
|
|
||||||
set({ reconnectAttempts: 0 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:处理连接错误
|
|
||||||
_handleError: (event: Event) => {
|
|
||||||
// console.error("WebSocket连接错误:", event);
|
|
||||||
|
|
||||||
set({ status: WebSocketStatus.ERROR });
|
|
||||||
|
|
||||||
Toast.show({ content: "WebSocket连接错误", position: "top" });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:启动重连定时器
|
|
||||||
_startReconnectTimer: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
currentState._stopReconnectTimer();
|
|
||||||
|
|
||||||
set({
|
|
||||||
status: WebSocketStatus.RECONNECTING,
|
|
||||||
reconnectAttempts: currentState.reconnectAttempts + 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
// console.log(
|
|
||||||
// `尝试重连 (${currentState.reconnectAttempts + 1}/${currentState.config?.maxReconnectAttempts})`,
|
|
||||||
// );
|
|
||||||
currentState.reconnect();
|
|
||||||
}, currentState.config?.reconnectInterval || 3000);
|
|
||||||
|
|
||||||
set({ reconnectTimer: timer });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:停止重连定时器
|
|
||||||
_stopReconnectTimer: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (currentState.reconnectTimer) {
|
|
||||||
clearTimeout(currentState.reconnectTimer);
|
|
||||||
set({ reconnectTimer: null });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:启动客服状态查询定时器
|
|
||||||
_startAliveStatusTimer: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
// 先停止现有定时器
|
|
||||||
currentState._stopAliveStatusTimer();
|
|
||||||
|
|
||||||
// 获取客服用户列表
|
|
||||||
const { kfUserList } = useCkChatStore.getState();
|
|
||||||
|
|
||||||
// 如果没有客服用户,不启动定时器
|
|
||||||
if (!kfUserList || kfUserList.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 启动定时器,每5秒查询一次
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
const state = get();
|
|
||||||
// 检查连接状态
|
|
||||||
if (state.status === WebSocketStatus.CONNECTED) {
|
|
||||||
const { kfUserList: currentKfUserList } = useCkChatStore.getState();
|
|
||||||
if (currentKfUserList && currentKfUserList.length > 0) {
|
|
||||||
state.sendCommand("CmdRequestWechatAccountsAliveStatus", {
|
|
||||||
wechatAccountIds: currentKfUserList.map(v => v.id),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 如果连接断开,停止定时器
|
|
||||||
state._stopAliveStatusTimer();
|
|
||||||
}
|
|
||||||
}, 5 * 1000);
|
|
||||||
|
|
||||||
set({ aliveStatusTimer: timer });
|
|
||||||
},
|
|
||||||
|
|
||||||
// 内部方法:停止客服状态查询定时器
|
|
||||||
_stopAliveStatusTimer: () => {
|
|
||||||
const currentState = get();
|
|
||||||
|
|
||||||
if (currentState.aliveStatusTimer) {
|
|
||||||
clearInterval(currentState.aliveStatusTimer);
|
|
||||||
set({ aliveStatusTimer: null });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "websocket-store",
|
|
||||||
partialize: state => ({
|
|
||||||
// 只持久化必要的状态,不持久化WebSocket实例
|
|
||||||
status: state.status,
|
|
||||||
config: state.config,
|
|
||||||
messages: state.messages.slice(-100), // 只保留最近100条消息
|
|
||||||
unreadCount: state.unreadCount,
|
|
||||||
reconnectAttempts: state.reconnectAttempts,
|
|
||||||
// 注意:定时器不需要持久化,重新连接时会重新创建
|
|
||||||
}),
|
|
||||||
onRehydrateStorage: () => state => {
|
|
||||||
// 页面刷新后,如果之前是连接状态,尝试重新连接
|
|
||||||
if (state && state.status === WebSocketStatus.CONNECTED && state.config) {
|
|
||||||
// console.log("页面刷新后恢复WebSocket连接", {
|
|
||||||
// persistedConfig: state.config,
|
|
||||||
// currentDefaultConfig: DEFAULT_CONFIG,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 使用最新的默认配置,而不是持久化的配置
|
|
||||||
const freshConfig = {
|
|
||||||
...DEFAULT_CONFIG,
|
|
||||||
client: state.config.client,
|
|
||||||
accountId: state.config.accountId,
|
|
||||||
accessToken: state.config.accessToken,
|
|
||||||
autoReconnect: state.config.autoReconnect,
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log("使用刷新后的配置重连:", freshConfig);
|
|
||||||
|
|
||||||
// 延迟一下再重连,确保页面完全加载
|
|
||||||
// 同时检查当前状态,避免重复连接
|
|
||||||
setTimeout(() => {
|
|
||||||
// 重新获取最新的状态,而不是使用闭包中的state
|
|
||||||
const currentState = useWebSocketStore.getState();
|
|
||||||
// console.log("页面刷新后检查状态", {
|
|
||||||
// status: currentState.status,
|
|
||||||
// hasWs: !!currentState.ws,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 强制重置状态为disconnected,因为页面刷新后WebSocket实例已失效
|
|
||||||
if (
|
|
||||||
currentState.status === WebSocketStatus.CONNECTED &&
|
|
||||||
!currentState.ws
|
|
||||||
) {
|
|
||||||
// console.log("检测到状态不一致,重置为disconnected");
|
|
||||||
useWebSocketStore.setState({
|
|
||||||
status: WebSocketStatus.DISCONNECTED,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新获取状态进行连接
|
|
||||||
const latestState = useWebSocketStore.getState();
|
|
||||||
if (
|
|
||||||
latestState.status === WebSocketStatus.DISCONNECTED ||
|
|
||||||
latestState.status === WebSocketStatus.ERROR
|
|
||||||
) {
|
|
||||||
// console.log("页面刷新后开始重连");
|
|
||||||
latestState.connect(freshConfig);
|
|
||||||
} else {
|
|
||||||
// console.log("WebSocket已连接或正在连接,跳过页面刷新重连", {
|
|
||||||
// status: latestState.status,
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user