Files
frontend/src/core/usecases/ProcessPostUseCase.ts

863 lines
21 KiB
TypeScript
Raw Normal View History

/**
* ProcessPostUseCase -
* Repository
* UI依赖
*/
import { postRepository } from '../../data/repositories/PostRepository';
import type { Post } from '../entities/Post';
import type {
GetPostsParams,
CreatePostData,
UpdatePostData,
PostsResult,
SearchPostsParams,
} from '../../data/repositories/interfaces/IPostRepository';
import { PaginationStateManager } from '../../infrastructure/pagination/PaginationStateManager';
import type { PaginationState } from '../../infrastructure/pagination/types';
// ==================== 事件类型定义 ====================
/**
*
*/
export type PostUseCaseEventType =
| 'posts_loaded'
| 'post_created'
| 'post_updated'
| 'post_deleted'
| 'post_liked'
| 'post_unliked'
| 'post_favorited'
| 'post_unfavorited'
| 'loading_changed'
| 'error_occurred'
| 'state_changed';
/**
*
*/
export interface PostUseCaseEvent {
type: PostUseCaseEventType;
payload: any;
timestamp: number;
}
/**
*
*/
export type PostUseCaseSubscriber = (event: PostUseCaseEvent) => void;
// ==================== 状态类型定义 ====================
/**
*
*/
export interface PostsState {
/** 帖子列表 */
posts: Post[];
/** 是否正在加载 */
isLoading: boolean;
/** 是否正在刷新 */
isRefreshing: boolean;
/** 是否有更多数据 */
hasMore: boolean;
/** 错误信息 */
error: string | null;
/** 当前游标 */
cursor: string | null;
/** 最后加载时间 */
lastLoadTime: number | null;
}
/**
*
*/
export interface PostDetailState {
/** 帖子详情 */
post: Post | null;
/** 是否正在加载 */
isLoading: boolean;
/** 错误信息 */
error: string | null;
}
// ==================== 默认配置 ====================
const DEFAULT_PAGE_SIZE = 20;
// ==================== ProcessPostUseCase 类 ====================
class ProcessPostUseCase {
// 单例实例
private static instance: ProcessPostUseCase;
// 订阅者管理
private subscribers: Set<PostUseCaseSubscriber> = new Set();
// 状态管理
private postsState: Map<string, PostsState> = new Map();
private postDetailState: Map<string, PostDetailState> = new Map();
// 分页状态管理器
private paginationManager: PaginationStateManager;
// 当前用户ID
private currentUserId: string | null = null;
// 私有构造函数
private constructor() {
this.paginationManager = new PaginationStateManager();
}
/**
*
*/
static getInstance(): ProcessPostUseCase {
if (!ProcessPostUseCase.instance) {
ProcessPostUseCase.instance = new ProcessPostUseCase();
}
return ProcessPostUseCase.instance;
}
// ==================== 初始化和销毁 ====================
/**
*
* @param currentUserId ID
*/
initialize(currentUserId: string | null = null): void {
this.currentUserId = currentUserId;
}
/**
*
*/
destroy(): void {
this.subscribers.clear();
this.postsState.clear();
this.postDetailState.clear();
this.paginationManager.clear();
this.currentUserId = null;
}
// ==================== 订阅机制 ====================
/**
*
* @param subscriber
* @returns
*/
subscribe(subscriber: PostUseCaseSubscriber): () => void {
this.subscribers.add(subscriber);
return () => {
this.subscribers.delete(subscriber);
};
}
/**
*
* @param event
*/
private notifySubscribers(event: PostUseCaseEvent): void {
this.subscribers.forEach((subscriber) => {
try {
subscriber(event);
} catch (error) {
console.error('[ProcessPostUseCase] 订阅者执行失败:', error);
}
});
}
/**
*
* @param key
*/
private notifyStateChanged(key: string): void {
const state = this.getPostsState(key);
this.notifySubscribers({
type: 'state_changed',
payload: { key, state },
timestamp: Date.now(),
});
}
// ==================== 状态管理 ====================
/**
*
* @param key 'default'
*/
getPostsState(key: string = 'default'): PostsState {
let state = this.postsState.get(key);
if (!state) {
state = {
posts: [],
isLoading: false,
isRefreshing: false,
hasMore: true,
error: null,
cursor: null,
lastLoadTime: null,
};
this.postsState.set(key, state);
}
return state;
}
/**
*
* @param postId ID
*/
getPostDetailState(postId: string): PostDetailState {
let state = this.postDetailState.get(postId);
if (!state) {
state = {
post: null,
isLoading: false,
error: null,
};
this.postDetailState.set(postId, state);
}
return state;
}
/**
*
* @param key
* @param partialState
*/
private updatePostsState(key: string, partialState: Partial<PostsState>): void {
const currentState = this.getPostsState(key);
this.postsState.set(key, {
...currentState,
...partialState,
});
this.notifyStateChanged(key);
}
/**
*
* @param postId ID
* @param partialState
*/
private updatePostDetailState(postId: string, partialState: Partial<PostDetailState>): void {
const currentState = this.getPostDetailState(postId);
this.postDetailState.set(postId, {
...currentState,
...partialState,
});
}
// ==================== 帖子列表操作 ====================
/**
*
* @param params
* @param key
*/
async fetchPosts(params?: GetPostsParams, key: string = 'default'): Promise<PostsResult> {
const state = this.getPostsState(key);
// 更新加载状态
this.updatePostsState(key, { isLoading: true, error: null });
try {
// 合并分页参数
const queryParams: GetPostsParams = {
page: params?.page || 1,
pageSize: params?.pageSize || DEFAULT_PAGE_SIZE,
cursor: params?.cursor || state.cursor || undefined,
...params,
};
const result = await postRepository.getPosts(queryParams);
// 更新状态
this.updatePostsState(key, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
isLoading: false,
lastLoadTime: Date.now(),
});
// 通知订阅者
this.notifySubscribers({
type: 'posts_loaded',
payload: { key, posts: result.posts, hasMore: result.hasMore },
timestamp: Date.now(),
});
return result;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取帖子列表失败';
this.updatePostsState(key, {
isLoading: false,
error: errorMessage,
});
this.notifySubscribers({
type: 'error_occurred',
payload: { key, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param key
*/
async refreshPosts(key: string = 'default'): Promise<PostsResult> {
// 更新刷新状态
this.updatePostsState(key, { isRefreshing: true, error: null });
try {
const result = await postRepository.getPosts({
page: 1,
pageSize: DEFAULT_PAGE_SIZE,
});
// 更新状态
this.updatePostsState(key, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
isRefreshing: false,
lastLoadTime: Date.now(),
});
// 重置分页状态
this.paginationManager.reset(key);
return result;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '刷新帖子列表失败';
this.updatePostsState(key, {
isRefreshing: false,
error: errorMessage,
});
throw error;
}
}
/**
*
* @param key
*/
async loadMorePosts(key: string = 'default'): Promise<PostsResult> {
const state = this.getPostsState(key);
// 检查是否还有更多数据
if (!state.hasMore) {
return {
posts: [],
hasMore: false,
};
}
// 检查是否正在加载
if (state.isLoading) {
return {
posts: [],
hasMore: state.hasMore,
};
}
// 更新加载状态
this.updatePostsState(key, { isLoading: true, error: null });
try {
const queryParams: GetPostsParams = {
pageSize: DEFAULT_PAGE_SIZE,
cursor: state.cursor || undefined,
};
const result = await postRepository.getPosts(queryParams);
// 合并新数据
const newPosts = [...state.posts, ...result.posts];
// 更新状态
this.updatePostsState(key, {
posts: newPosts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
isLoading: false,
lastLoadTime: Date.now(),
});
return {
posts: result.posts,
hasMore: result.hasMore,
nextCursor: result.nextCursor,
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '加载更多帖子失败';
this.updatePostsState(key, {
isLoading: false,
error: errorMessage,
});
throw error;
}
}
// ==================== 帖子详情操作 ====================
/**
*
* @param id ID
*/
async fetchPostById(id: string): Promise<Post | null> {
// 更新加载状态
this.updatePostDetailState(id, { isLoading: true, error: null });
try {
const post = await postRepository.getPostById(id);
// 更新状态
this.updatePostDetailState(id, {
post,
isLoading: false,
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取帖子详情失败';
this.updatePostDetailState(id, {
isLoading: false,
error: errorMessage,
});
throw error;
}
}
// ==================== 帖子CRUD操作 ====================
/**
*
* @param data
*/
async createPost(data: CreatePostData): Promise<Post> {
try {
const post = await postRepository.createPost(data);
// 通知订阅者
this.notifySubscribers({
type: 'post_created',
payload: { post },
timestamp: Date.now(),
});
// 更新所有列表(新帖子应该出现在列表顶部)
this.postsState.forEach((state, key) => {
this.updatePostsState(key, {
posts: [post, ...state.posts],
});
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '创建帖子失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'create', error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param id ID
* @param data
*/
async updatePost(id: string, data: UpdatePostData): Promise<Post> {
try {
const post = await postRepository.updatePost(id, data);
// 更新详情状态
this.updatePostDetailState(id, { post });
// 更新列表中的帖子
this.updatePostInLists(id, post);
// 通知订阅者
this.notifySubscribers({
type: 'post_updated',
payload: { postId: id, post },
timestamp: Date.now(),
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '更新帖子失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'update', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param id ID
*/
async deletePost(id: string): Promise<void> {
try {
await postRepository.deletePost(id);
// 从详情状态中移除
this.postDetailState.delete(id);
// 从所有列表中移除
this.postsState.forEach((state, key) => {
const filteredPosts = state.posts.filter((post) => post.id !== id);
this.updatePostsState(key, {
posts: filteredPosts,
});
});
// 通知订阅者
this.notifySubscribers({
type: 'post_deleted',
payload: { postId: id },
timestamp: Date.now(),
});
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '删除帖子失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'delete', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
// ==================== 互动操作 ====================
/**
*
* @param id ID
*/
async likePost(id: string): Promise<Post> {
try {
const post = await postRepository.likePost(id);
// 更新详情状态
this.updatePostDetailState(id, { post });
// 更新列表中的帖子
this.updatePostInLists(id, post);
// 通知订阅者
this.notifySubscribers({
type: 'post_liked',
payload: { postId: id, post },
timestamp: Date.now(),
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '点赞失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'like', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param id ID
*/
async unlikePost(id: string): Promise<Post> {
try {
const post = await postRepository.unlikePost(id);
// 更新详情状态
this.updatePostDetailState(id, { post });
// 更新列表中的帖子
this.updatePostInLists(id, post);
// 通知订阅者
this.notifySubscribers({
type: 'post_unliked',
payload: { postId: id, post },
timestamp: Date.now(),
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '取消点赞失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'unlike', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param id ID
*/
async favoritePost(id: string): Promise<Post> {
try {
const post = await postRepository.favoritePost(id);
// 更新详情状态
this.updatePostDetailState(id, { post });
// 更新列表中的帖子
this.updatePostInLists(id, post);
// 通知订阅者
this.notifySubscribers({
type: 'post_favorited',
payload: { postId: id, post },
timestamp: Date.now(),
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '收藏失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'favorite', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
/**
*
* @param id ID
*/
async unfavoritePost(id: string): Promise<Post> {
try {
const post = await postRepository.unfavoritePost(id);
// 更新详情状态
this.updatePostDetailState(id, { post });
// 更新列表中的帖子
this.updatePostInLists(id, post);
// 通知订阅者
this.notifySubscribers({
type: 'post_unfavorited',
payload: { postId: id, post },
timestamp: Date.now(),
});
return post;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '取消收藏失败';
this.notifySubscribers({
type: 'error_occurred',
payload: { operation: 'unfavorite', postId: id, error: errorMessage },
timestamp: Date.now(),
});
throw error;
}
}
// ==================== 搜索操作 ====================
/**
*
* @param params
* @param key
*/
async searchPosts(params: SearchPostsParams, key: string = 'search'): Promise<PostsResult> {
// 更新加载状态
this.updatePostsState(key, { isLoading: true, error: null });
try {
const result = await postRepository.searchPosts(params);
// 更新状态
this.updatePostsState(key, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
isLoading: false,
lastLoadTime: Date.now(),
});
return result;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '搜索帖子失败';
this.updatePostsState(key, {
isLoading: false,
error: errorMessage,
});
throw error;
}
}
// ==================== 用户帖子操作 ====================
/**
*
* @param userId ID
* @param params
* @param key
*/
async fetchPostsByUser(
userId: string,
params?: GetPostsParams,
key?: string
): Promise<PostsResult> {
const listKey = key || `user_${userId}`;
// 更新加载状态
this.updatePostsState(listKey, { isLoading: true, error: null });
try {
const result = await postRepository.getPostsByUser(userId, params);
// 更新状态
this.updatePostsState(listKey, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
isLoading: false,
lastLoadTime: Date.now(),
});
return result;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取用户帖子失败';
this.updatePostsState(listKey, {
isLoading: false,
error: errorMessage,
});
throw error;
}
}
// ==================== 辅助方法 ====================
/**
*
* @param postId ID
* @param updatedPost
*/
private updatePostInLists(postId: string, updatedPost: Post): void {
this.postsState.forEach((state, key) => {
const index = state.posts.findIndex((post) => post.id === postId);
if (index !== -1) {
const newPosts = [...state.posts];
newPosts[index] = updatedPost;
this.updatePostsState(key, { posts: newPosts });
}
});
}
/**
*
* @param key
*/
clearPostsState(key: string = 'default'): void {
this.postsState.delete(key);
this.paginationManager.reset(key);
}
/**
*
* @param postId ID
*/
clearPostDetailState(postId: string): void {
this.postDetailState.delete(postId);
}
/**
*
*/
clearAllStates(): void {
this.postsState.clear();
this.postDetailState.clear();
this.paginationManager.clear();
}
/**
* ID
*/
getCurrentUserId(): string | null {
return this.currentUserId;
}
/**
* ID
*/
setCurrentUserId(userId: string | null): void {
this.currentUserId = userId;
}
// ==================== 分页状态管理集成 ====================
/**
*
* @param key
*/
getPaginationState(key: string): PaginationState {
return this.paginationManager.getState(key);
}
/**
*
* @param key
*/
resetPagination(key: string): void {
this.paginationManager.reset(key);
}
/**
*
* @param key
*/
isLoading(key: string = 'default'): boolean {
return this.getPostsState(key).isLoading;
}
/**
*
* @param key
*/
hasError(key: string = 'default'): boolean {
return this.getPostsState(key).error !== null;
}
/**
*
* @param key
*/
getError(key: string = 'default'): string | null {
return this.getPostsState(key).error;
}
}
// ==================== 导出 ====================
// 导出单例实例
export const processPostUseCase = ProcessPostUseCase.getInstance();
export default processPostUseCase;