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
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
import { api, PaginatedData } from './api';
|
||||
import { Comment, CreateCommentInput } from '../types';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse, CommentDTO } from '../types/dto';
|
||||
|
||||
// 评论列表响应
|
||||
interface CommentListResponse {
|
||||
@@ -240,6 +241,62 @@ class CommentService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 游标分页方法 ====================
|
||||
|
||||
/**
|
||||
* 获取帖子评论列表(游标分页)
|
||||
* GET /api/v1/comments/post/:id/cursor
|
||||
* @param postId 帖子ID
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getPostCommentsCursor(
|
||||
postId: string,
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<Comment>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<Comment>>(
|
||||
`/comments/post/${postId}/cursor`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取帖子评论列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评论回复列表(游标分页)
|
||||
* GET /api/v1/comments/:id/replies/cursor
|
||||
* @param commentId 评论ID
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getCommentRepliesCursor(
|
||||
commentId: string,
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<Comment>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<Comment>>(
|
||||
`/comments/${commentId}/replies/cursor`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取评论回复列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出评论服务实例
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
MyMemberInfoResponse,
|
||||
SetGroupAvatarRequest,
|
||||
HandleGroupRequestAction,
|
||||
CursorPaginationRequest,
|
||||
CursorPaginationResponse,
|
||||
} from '../types/dto';
|
||||
|
||||
// 群组服务类(纯 API 层)
|
||||
@@ -321,6 +323,86 @@ class GroupService {
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== 游标分页方法 ====================
|
||||
|
||||
/**
|
||||
* 获取群组列表(游标分页)
|
||||
* GET /api/v1/groups/cursor
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getGroupsCursor(
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<GroupResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<GroupResponse>>('/groups/cursor', {
|
||||
params,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取群组列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组成员列表(游标分页)
|
||||
* GET /api/v1/groups/:id/members/cursor
|
||||
* @param groupId 群组ID
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getGroupMembersCursor(
|
||||
groupId: number | string,
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<GroupMemberResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<GroupMemberResponse>>(
|
||||
`/groups/${encodeURIComponent(String(groupId))}/members/cursor`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取群组成员列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群公告列表(游标分页)
|
||||
* GET /api/v1/groups/:id/announcements/cursor
|
||||
* @param groupId 群组ID
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getGroupAnnouncementsCursor(
|
||||
groupId: number | string,
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<GroupAnnouncementResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<GroupAnnouncementResponse>>(
|
||||
`/groups/${encodeURIComponent(String(groupId))}/announcements/cursor`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取群公告列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 兼容旧API的方法(将逐步废弃) ====================
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,11 @@ import {
|
||||
UnreadCountResponse,
|
||||
ConversationUnreadCountResponse,
|
||||
SystemMessageListResponse,
|
||||
SystemMessageResponse,
|
||||
SystemUnreadCountResponse,
|
||||
MessageSegment,
|
||||
CursorPaginationRequest,
|
||||
CursorPaginationResponse,
|
||||
} from '../types/dto';
|
||||
import {
|
||||
getConversationCache,
|
||||
@@ -555,6 +558,85 @@ class MessageService {
|
||||
await api.put('/messages/system/read-all');
|
||||
}
|
||||
|
||||
// ==================== 游标分页方法 ====================
|
||||
|
||||
/**
|
||||
* 获取会话列表(游标分页)
|
||||
* GET /api/v1/conversations/cursor
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getConversationsCursor(
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<ConversationResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<ConversationResponse>>(
|
||||
'/conversations/cursor',
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取会话列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息列表(游标分页)
|
||||
* GET /api/v1/conversations/:id/messages/cursor
|
||||
* @param conversationId 会话ID
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getMessagesCursor(
|
||||
conversationId: string,
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<MessageResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<MessageResponse>>(
|
||||
`/conversations/${encodeURIComponent(conversationId)}/messages/cursor`,
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取消息列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统消息列表(游标分页)
|
||||
* GET /api/v1/messages/system/cursor
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getSystemMessagesCursor(
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<SystemMessageResponse>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<SystemMessageResponse>>(
|
||||
'/messages/system/cursor',
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取系统消息列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 兼容旧API的方法(将逐步废弃) ====================
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { api, PaginatedData } from './api';
|
||||
import { Notification, NotificationBadge, NotificationType } from '../types';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto';
|
||||
|
||||
// 通知列表响应
|
||||
interface NotificationListResponse {
|
||||
@@ -151,6 +152,33 @@ class NotificationService {
|
||||
async getMentionNotifications(page = 1, pageSize = 20): Promise<PaginatedData<Notification>> {
|
||||
return this.getNotifications(page, pageSize, 'mention');
|
||||
}
|
||||
|
||||
// ==================== 游标分页方法 ====================
|
||||
|
||||
/**
|
||||
* 获取通知列表(游标分页)
|
||||
* GET /api/v1/notifications/cursor
|
||||
* @param params 游标分页请求参数
|
||||
*/
|
||||
async getNotificationsCursor(
|
||||
params: CursorPaginationRequest = {}
|
||||
): Promise<CursorPaginationResponse<Notification>> {
|
||||
try {
|
||||
const response = await api.get<CursorPaginationResponse<Notification>>(
|
||||
'/notifications/cursor',
|
||||
{ params }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取通知列表失败:', error);
|
||||
return {
|
||||
items: [],
|
||||
next_cursor: null,
|
||||
prev_cursor: null,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出通知服务实例
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { api, PaginatedData } from './api';
|
||||
import { Post, CreatePostInput } from '../types';
|
||||
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto';
|
||||
|
||||
// 帖子列表响应
|
||||
interface PostListResponse {
|
||||
@@ -281,6 +282,92 @@ class PostService {
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出帖子服务实例
|
||||
|
||||
Reference in New Issue
Block a user