/** * 群组状态 Zustand Store */ import { create } from 'zustand'; import type { GroupResponse, GroupMemberResponse, } from '../../types/dto'; import { CacheEntry, createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache'; // ==================== 状态接口 ==================== export interface GroupManagerState { // 群组列表缓存 groupsListEntry: CacheEntry | null; // 群组详情缓存 groupsMap: Map>; // 群组成员缓存 (key: members:groupId:page:pageSize) membersMap: Map>; // 加载状态 isLoadingGroups: boolean; loadingGroupIds: Set; loadingMemberKeys: Set; // 待处理请求(去重) pendingRequests: Map>; } export interface GroupManagerActions { // 获取状态 getGroupsList: () => GroupResponse[] | null; getGroup: (groupId: string) => GroupResponse | null; getMembers: (groupId: string, page?: number, pageSize?: number) => GroupMemberResponse[] | null; isGroupsListExpired: () => boolean; isGroupExpired: (groupId: string) => boolean; isMembersExpired: (groupId: string, page?: number, pageSize?: number) => boolean; isLoadingGroup: (groupId: string) => boolean; isLoadingMembers: (groupId: string, page?: number, pageSize?: number) => boolean; // 设置状态 setGroupsList: (groups: GroupResponse[]) => void; setGroupsListEntry: (entry: CacheEntry) => void; setGroup: (groupId: string, group: GroupResponse) => void; setMembers: (groupId: string, members: GroupMemberResponse[], page?: number, pageSize?: number) => void; setLoadingGroups: (loading: boolean) => void; setLoadingGroup: (groupId: string, loading: boolean) => void; setLoadingMembers: (groupId: string, loading: boolean, page?: number, pageSize?: number) => void; // 缓存管理 invalidateGroupsList: () => void; invalidateGroup: (groupId: string) => void; invalidateMembers: (groupId: string) => void; invalidateAll: () => void; // 请求去重 getPendingRequest: (key: string) => Promise | undefined; setPendingRequest: (key: string, request: Promise) => void; deletePendingRequest: (key: string) => void; clearPendingRequests: () => void; // 重置 reset: () => void; } // ==================== 辅助函数 ==================== function buildMembersKey(groupId: string, page: number = 1, pageSize: number = 20): string { return `members:${groupId}:${page}:${pageSize}`; } // ==================== 初始状态 ==================== const initialState: GroupManagerState = { groupsListEntry: null, groupsMap: new Map(), membersMap: new Map(), isLoadingGroups: false, loadingGroupIds: new Set(), loadingMemberKeys: new Set(), pendingRequests: new Map(), }; // ==================== Store 创建 ==================== export type GroupManagerStore = GroupManagerState & GroupManagerActions; export const useGroupManagerStore = create((set, get) => ({ // ==================== 初始状态 ==================== ...initialState, // ==================== 获取状态 ==================== getGroupsList: () => { const entry = get().groupsListEntry; if (!entry) return null; if (isCacheExpired(entry)) return null; return entry.data; }, getGroup: (groupId: string) => { const entry = get().groupsMap.get(groupId); if (!entry) return null; if (isCacheExpired(entry)) return null; return entry.data; }, getMembers: (groupId: string, page = 1, pageSize = 20) => { const key = buildMembersKey(groupId, page, pageSize); const entry = get().membersMap.get(key); if (!entry) return null; if (isCacheExpired(entry)) return null; return entry.data; }, isGroupsListExpired: () => { const entry = get().groupsListEntry; if (!entry) return true; return isCacheExpired(entry); }, isGroupExpired: (groupId: string) => { const entry = get().groupsMap.get(groupId); if (!entry) return true; return isCacheExpired(entry); }, isMembersExpired: (groupId: string, page = 1, pageSize = 20) => { const key = buildMembersKey(groupId, page, pageSize); const entry = get().membersMap.get(key); if (!entry) return true; return isCacheExpired(entry); }, isLoadingGroup: (groupId: string) => { return get().loadingGroupIds.has(groupId); }, isLoadingMembers: (groupId: string, page = 1, pageSize = 20) => { const key = buildMembersKey(groupId, page, pageSize); return get().loadingMemberKeys.has(key); }, // ==================== 设置状态 ==================== setGroupsList: (groups: GroupResponse[]) => { set({ groupsListEntry: createCacheEntry(groups, DEFAULT_TTL.GROUP), }); }, setGroupsListEntry: (entry: CacheEntry) => { set({ groupsListEntry: entry }); }, setGroup: (groupId: string, group: GroupResponse) => { set(state => { const newGroupsMap = new Map(state.groupsMap); newGroupsMap.set(groupId, createCacheEntry(group, DEFAULT_TTL.GROUP)); return { groupsMap: newGroupsMap }; }); }, setMembers: (groupId: string, members: GroupMemberResponse[], page = 1, pageSize = 20) => { const key = buildMembersKey(groupId, page, pageSize); set(state => { const newMembersMap = new Map(state.membersMap); newMembersMap.set(key, createCacheEntry(members, DEFAULT_TTL.GROUP_MEMBERS)); return { membersMap: newMembersMap }; }); }, setLoadingGroups: (loading: boolean) => { set({ isLoadingGroups: loading }); }, setLoadingGroup: (groupId: string, loading: boolean) => { set(state => { const newLoadingGroupIds = new Set(state.loadingGroupIds); if (loading) { newLoadingGroupIds.add(groupId); } else { newLoadingGroupIds.delete(groupId); } return { loadingGroupIds: newLoadingGroupIds }; }); }, setLoadingMembers: (groupId: string, loading: boolean, page = 1, pageSize = 20) => { const key = buildMembersKey(groupId, page, pageSize); set(state => { const newLoadingMemberKeys = new Set(state.loadingMemberKeys); if (loading) { newLoadingMemberKeys.add(key); } else { newLoadingMemberKeys.delete(key); } return { loadingMemberKeys: newLoadingMemberKeys }; }); }, // ==================== 缓存管理 ==================== invalidateGroupsList: () => { set({ groupsListEntry: null }); }, invalidateGroup: (groupId: string) => { set(state => { const newGroupsMap = new Map(state.groupsMap); newGroupsMap.delete(groupId); // 删除相关的成员缓存 const newMembersMap = new Map(state.membersMap); for (const key of newMembersMap.keys()) { if (key.startsWith(`members:${groupId}:`)) { newMembersMap.delete(key); } } return { groupsMap: newGroupsMap, membersMap: newMembersMap }; }); }, invalidateMembers: (groupId: string) => { set(state => { const newMembersMap = new Map(state.membersMap); for (const key of newMembersMap.keys()) { if (key.startsWith(`members:${groupId}:`)) { newMembersMap.delete(key); } } return { membersMap: newMembersMap }; }); }, invalidateAll: () => { set({ groupsListEntry: null, groupsMap: new Map(), membersMap: new Map(), pendingRequests: new Map(), }); }, // ==================== 请求去重 ==================== getPendingRequest: (key: string) => { return get().pendingRequests.get(key) as Promise | undefined; }, setPendingRequest: (key: string, request: Promise) => { set(state => { const newPendingRequests = new Map(state.pendingRequests); newPendingRequests.set(key, request); return { pendingRequests: newPendingRequests }; }); }, deletePendingRequest: (key: string) => { set(state => { const newPendingRequests = new Map(state.pendingRequests); newPendingRequests.delete(key); return { pendingRequests: newPendingRequests }; }); }, clearPendingRequests: () => { set({ pendingRequests: new Map() }); }, // ==================== 重置 ==================== reset: () => { set({ ...initialState, groupsMap: new Map(), membersMap: new Map(), loadingGroupIds: new Set(), loadingMemberKeys: new Set(), pendingRequests: new Map(), }); }, }));