Add useCursorPagination hook and update multiple screens and services to use cursor-based pagination for better performance and consistency. - Add useCursorPagination hook with deduplication and caching support - Add cursor pagination types to infrastructure layer - Refactor HomeScreen, PostDetailScreen, SearchScreen for posts/comments - Refactor GroupMembersScreen, JoinGroupScreen for groups/members - Refactor MessageListScreen, NotificationsScreen for messages - Update post, message, group, comment, notification services with cursor endpoints - Add CursorPaginationRequest/Response DTOs - Remove deprecated OPTIMIZATION_DESIGN.md documentation
375 lines
9.4 KiB
TypeScript
375 lines
9.4 KiB
TypeScript
/**
|
||
* 帖子服务
|
||
* 处理帖子的增删改查、点赞、收藏等功能
|
||
*/
|
||
|
||
import { api, PaginatedData } from './api';
|
||
import { Post, CreatePostInput } from '../types';
|
||
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto';
|
||
|
||
// 帖子列表响应
|
||
interface PostListResponse {
|
||
list: Post[];
|
||
total: number;
|
||
page: number;
|
||
page_size: number;
|
||
total_pages: number;
|
||
}
|
||
|
||
// 帖子响应 - API直接返回Post对象
|
||
type PostResponse = Post;
|
||
|
||
// 创建帖子请求
|
||
interface CreatePostRequest {
|
||
title: string;
|
||
content: string;
|
||
images?: string[];
|
||
}
|
||
|
||
// 更新帖子请求
|
||
interface UpdatePostRequest {
|
||
title?: string;
|
||
content?: string;
|
||
images?: string[];
|
||
}
|
||
|
||
// 帖子服务类
|
||
class PostService {
|
||
// 获取帖子列表
|
||
async getPosts(
|
||
page = 1,
|
||
pageSize = 20,
|
||
tab?: string,
|
||
communityId?: string
|
||
): Promise<PaginatedData<Post>> {
|
||
const params: Record<string, any> = {
|
||
page,
|
||
page_size: pageSize,
|
||
};
|
||
|
||
if (tab) {
|
||
params.tab = tab;
|
||
}
|
||
if (communityId) {
|
||
params.community_id = communityId;
|
||
}
|
||
|
||
const response = await api.get<PostListResponse>('/posts', params);
|
||
return response.data;
|
||
}
|
||
|
||
// 获取推荐帖子
|
||
async getRecommendedPosts(page = 1, pageSize = 20): Promise<PaginatedData<Post>> {
|
||
return this.getPosts(page, pageSize, 'recommend');
|
||
}
|
||
|
||
// 获取关注帖子
|
||
async getFollowingPosts(page = 1, pageSize = 20): Promise<PaginatedData<Post>> {
|
||
return this.getPosts(page, pageSize, 'follow');
|
||
}
|
||
|
||
// 获取热门帖子
|
||
async getHotPosts(page = 1, pageSize = 20): Promise<PaginatedData<Post>> {
|
||
return this.getPosts(page, pageSize, 'hot');
|
||
}
|
||
|
||
// 获取最新帖子
|
||
async getLatestPosts(page = 1, pageSize = 20): Promise<PaginatedData<Post>> {
|
||
return this.getPosts(page, pageSize, 'latest');
|
||
}
|
||
|
||
// 获取帖子详情(不增加浏览量)
|
||
async getPost(postId: string): Promise<Post | null> {
|
||
try {
|
||
const response = await api.get<PostResponse>(`/posts/${postId}`);
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('获取帖子详情失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 记录帖子浏览(增加浏览量)
|
||
async recordView(postId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.post(`/posts/${postId}/view`);
|
||
return response.code === 0;
|
||
} catch (error) {
|
||
console.error('记录浏览失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 创建帖子
|
||
async createPost(data: CreatePostRequest): Promise<Post | null> {
|
||
const response = await api.post<PostResponse>('/posts', data);
|
||
return response.data;
|
||
}
|
||
|
||
// 更新帖子
|
||
async updatePost(postId: string, data: UpdatePostRequest): Promise<Post | null> {
|
||
try {
|
||
const response = await api.put<PostResponse>(`/posts/${postId}`, data);
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('更新帖子失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 删除帖子
|
||
async deletePost(postId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.delete(`/posts/${postId}`);
|
||
return response.code === 0;
|
||
} catch (error) {
|
||
console.error('删除帖子失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 点赞帖子
|
||
async likePost(postId: string): Promise<Post | null> {
|
||
try {
|
||
const response = await api.post<Post>(`/posts/${postId}/like`);
|
||
if (response.code === 0) {
|
||
return response.data;
|
||
}
|
||
console.warn('[postService] likePost failed, code:', response.code);
|
||
return null;
|
||
} catch (error) {
|
||
console.error('[postService] likePost error:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 取消点赞帖子
|
||
async unlikePost(postId: string): Promise<Post | null> {
|
||
try {
|
||
const response = await api.delete<Post>(`/posts/${postId}/like`);
|
||
if (response.code === 0) {
|
||
return response.data;
|
||
}
|
||
console.warn('[postService] unlikePost failed, code:', response.code);
|
||
return null;
|
||
} catch (error) {
|
||
console.error('[postService] unlikePost error:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 收藏帖子
|
||
async favoritePost(postId: string): Promise<Post | null> {
|
||
try {
|
||
const response = await api.post<Post>(`/posts/${postId}/favorite`);
|
||
if (response.code === 0) {
|
||
return response.data;
|
||
}
|
||
console.warn('[postService] favoritePost failed, code:', response.code);
|
||
return null;
|
||
} catch (error) {
|
||
console.error('[postService] favoritePost error:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 取消收藏帖子
|
||
async unfavoritePost(postId: string): Promise<Post | null> {
|
||
try {
|
||
const response = await api.delete<Post>(`/posts/${postId}/favorite`);
|
||
if (response.code === 0) {
|
||
return response.data;
|
||
}
|
||
console.warn('[postService] unfavoritePost failed, code:', response.code);
|
||
return null;
|
||
} catch (error) {
|
||
console.error('[postService] unfavoritePost error:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 获取用户帖子列表
|
||
async getUserPosts(
|
||
userId: string,
|
||
page = 1,
|
||
pageSize = 20
|
||
): Promise<PaginatedData<Post>> {
|
||
try {
|
||
const response = await api.get<PostListResponse>(`/users/${userId}/posts`, {
|
||
page,
|
||
page_size: pageSize,
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('获取用户帖子列表失败:', error);
|
||
return {
|
||
list: [],
|
||
total: 0,
|
||
page: 1,
|
||
page_size: pageSize,
|
||
total_pages: 0,
|
||
};
|
||
}
|
||
}
|
||
|
||
// 获取用户收藏列表
|
||
async getUserFavorites(
|
||
userId: string,
|
||
page = 1,
|
||
pageSize = 20
|
||
): Promise<PaginatedData<Post>> {
|
||
try {
|
||
const response = await api.get<PostListResponse>(`/users/${userId}/favorites`, {
|
||
page,
|
||
page_size: pageSize,
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('获取用户收藏列表失败:', error);
|
||
return {
|
||
list: [],
|
||
total: 0,
|
||
page: 1,
|
||
page_size: pageSize,
|
||
total_pages: 0,
|
||
};
|
||
}
|
||
}
|
||
|
||
// 搜索帖子
|
||
async searchPosts(
|
||
keyword: string,
|
||
page = 1,
|
||
pageSize = 20
|
||
): Promise<PaginatedData<Post>> {
|
||
try {
|
||
const response = await api.get<PostListResponse>('/posts/search', {
|
||
keyword,
|
||
page,
|
||
page_size: pageSize,
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('搜索帖子失败:', error);
|
||
return {
|
||
list: [],
|
||
total: 0,
|
||
page: 1,
|
||
page_size: pageSize,
|
||
total_pages: 0,
|
||
};
|
||
}
|
||
}
|
||
|
||
// 分享帖子
|
||
async sharePost(postId: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.post(`/posts/${postId}/share`);
|
||
return response.code === 0;
|
||
} catch (error) {
|
||
console.error('分享帖子失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 举报帖子
|
||
async reportPost(postId: string, reason: string): Promise<boolean> {
|
||
try {
|
||
const response = await api.post(`/posts/${postId}/report`, { reason });
|
||
return response.code === 0;
|
||
} catch (error) {
|
||
console.error('举报帖子失败:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// ==================== 游标分页方法 ====================
|
||
|
||
/**
|
||
* 获取帖子列表(游标分页)
|
||
* GET /api/v1/posts/cursor
|
||
* @param params 游标分页请求参数(包含 post_type 可选:recommend, follow, hot, latest)
|
||
*/
|
||
async getPostsCursor(
|
||
params: CursorPaginationRequest = {}
|
||
): Promise<CursorPaginationResponse<Post>> {
|
||
try {
|
||
const response = await api.get<CursorPaginationResponse<Post>>('/posts/cursor', {
|
||
params: {
|
||
cursor: params.cursor,
|
||
page_size: params.page_size,
|
||
post_type: params.post_type,
|
||
},
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('获取帖子列表失败:', error);
|
||
return {
|
||
items: [],
|
||
next_cursor: null,
|
||
prev_cursor: null,
|
||
has_more: false,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 搜索帖子(游标分页)
|
||
* GET /api/v1/posts/search/cursor
|
||
* @param query 搜索关键词
|
||
* @param params 游标分页请求参数
|
||
*/
|
||
async searchPostsCursor(
|
||
query: string,
|
||
params: CursorPaginationRequest = {}
|
||
): Promise<CursorPaginationResponse<Post>> {
|
||
try {
|
||
const response = await api.get<CursorPaginationResponse<Post>>('/posts/search/cursor', {
|
||
params: {
|
||
...params,
|
||
keyword: query,
|
||
},
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('搜索帖子失败:', error);
|
||
return {
|
||
items: [],
|
||
next_cursor: null,
|
||
prev_cursor: null,
|
||
has_more: false,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户帖子列表(游标分页)
|
||
* GET /api/v1/users/:id/posts/cursor
|
||
* @param userId 用户ID
|
||
* @param params 游标分页请求参数
|
||
*/
|
||
async getUserPostsCursor(
|
||
userId: string,
|
||
params: CursorPaginationRequest = {}
|
||
): Promise<CursorPaginationResponse<Post>> {
|
||
try {
|
||
const response = await api.get<CursorPaginationResponse<Post>>(
|
||
`/users/${userId}/posts/cursor`,
|
||
{ params }
|
||
);
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('获取用户帖子列表失败:', error);
|
||
return {
|
||
items: [],
|
||
next_cursor: null,
|
||
prev_cursor: null,
|
||
has_more: false,
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
// 导出帖子服务实例
|
||
export const postService = new PostService();
|