Files
frontend/src/services/postService.ts
lafay 8a0aea1c59 feat(pagination): implement cursor-based pagination across the app
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
2026-03-20 23:00:27 +08:00

375 lines
9.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 帖子服务
* 处理帖子的增删改查、点赞、收藏等功能
*/
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();