Files
frontend/src/services/postService.ts

476 lines
13 KiB
TypeScript
Raw Normal View History

/**
*
*
*
* @deprecated 使 ProcessPostUseCase
* processPostUseCase
*/
import { api, PaginatedData } from './api';
import { Post, CreatePostInput } from '../types';
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto';
import { processPostUseCase } from '../core/usecases/ProcessPostUseCase';
import type { Post as PostEntity } from '../core/entities/Post';
// 帖子列表响应
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[];
channel_id?: string;
}
// 更新帖子请求
interface UpdatePostRequest {
title?: string;
content?: string;
images?: string[];
}
// 帖子服务类
class PostService {
// 获取帖子列表
async getPosts(
page = 1,
pageSize = 20,
tab?: string,
channelId?: string
): Promise<PaginatedData<Post>> {
const params: Record<string, any> = {
page,
page_size: pageSize,
};
if (tab) {
params.tab = tab;
}
if (channelId) {
params.channel_id = channelId;
}
const response = await api.get<PostListResponse>('/posts', params);
return response.data;
}
// 获取关注帖子
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;
}
}
// 点赞帖子
// @deprecated 请使用 processPostUseCase.likePost() 代替
async likePost(postId: string): Promise<Post | null> {
try {
const post = await processPostUseCase.likePost(postId);
// 转换为旧版 Post 类型以保持向后兼容
return post as unknown as Post;
} catch (error) {
console.error('[postService] likePost error:', error);
return null;
}
}
// 取消点赞帖子
// @deprecated 请使用 processPostUseCase.unlikePost() 代替
async unlikePost(postId: string): Promise<Post | null> {
try {
const post = await processPostUseCase.unlikePost(postId);
return post as unknown as Post;
} catch (error) {
console.error('[postService] unlikePost error:', error);
return null;
}
}
// 收藏帖子
// @deprecated 请使用 processPostUseCase.favoritePost() 代替
async favoritePost(postId: string): Promise<Post | null> {
try {
const post = await processPostUseCase.favoritePost(postId);
return post as unknown as Post;
} catch (error) {
console.error('[postService] favoritePost error:', error);
return null;
}
}
// 取消收藏帖子
// @deprecated 请使用 processPostUseCase.unfavoritePost() 代替
async unfavoritePost(postId: string): Promise<Post | null> {
try {
const post = await processPostUseCase.unfavoritePost(postId);
return post as unknown as Post;
} 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,
};
}
}
/** 上报分享成功;返回服务端最新 shares_count 供界面同步 */
async sharePost(
postId: string,
body?: { channel?: string }
): Promise<{ ok: boolean; shares_count?: number }> {
try {
const response = await api.post<{ success: boolean; shares_count: number }>(
`/posts/${postId}/share`,
body && body.channel ? { channel: body.channel } : undefined
);
if (response.code !== 0) {
return { ok: false };
}
const n = response.data?.shares_count;
return { ok: true, shares_count: typeof n === 'number' ? n : undefined };
} catch (error) {
console.error('分享帖子失败:', error);
return { ok: 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
* @param params post_type follow, hot, latest
*/
async getPostsCursor(
params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<Post>> {
try {
// 构建请求参数
// 后端使用 `tab` 参数区分帖子类型,使用 `cursor` 参数启用游标分页
// 始终传递 cursor 参数(空字符串表示首次请求),确保使用游标分页
const requestParams: Record<string, any> = {
cursor: params.cursor || '', // 空字符串表示首次请求
page_size: params.page_size,
};
// 将 post_type 映射为后端的 tab 参数
if (params.post_type) {
requestParams.tab = params.post_type;
}
const response = await api.get<any>('/posts', requestParams);
const data = response.data;
if (data && typeof data === 'object' && Array.isArray(data.list)) {
const isPageShape =
typeof data.page === 'number' &&
typeof data.total_pages === 'number' &&
data.next_cursor === undefined &&
data.prev_cursor === undefined;
if (isPageShape) {
const currentPage = data.page || 1;
const totalPages = data.total_pages || 1;
return {
list: data.list,
next_cursor: currentPage < totalPages ? String(currentPage + 1) : null,
prev_cursor: currentPage > 1 ? String(currentPage - 1) : null,
has_more: currentPage < totalPages,
};
}
return {
list: data.list,
next_cursor: data.next_cursor ?? null,
prev_cursor: data.prev_cursor ?? null,
has_more: data.has_more ?? false,
};
}
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
} catch (error) {
console.error('获取帖子列表失败:', error);
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
}
}
/**
*
* GET /api/v1/posts/search
* @param query
* @param params
*/
async searchPostsCursor(
query: string,
params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<Post>> {
try {
const response = await api.get<any>('/posts/search', {
...params,
keyword: query,
});
const data = response.data;
if (data && typeof data === 'object' && Array.isArray(data.list)) {
const isPageShape =
typeof data.page === 'number' &&
typeof data.total_pages === 'number' &&
data.next_cursor === undefined &&
data.prev_cursor === undefined;
if (isPageShape) {
const currentPage = data.page || 1;
const totalPages = data.total_pages || 1;
return {
list: data.list,
next_cursor: currentPage < totalPages ? String(currentPage + 1) : null,
prev_cursor: currentPage > 1 ? String(currentPage - 1) : null,
has_more: currentPage < totalPages,
};
}
return {
list: data.list,
next_cursor: data.next_cursor ?? null,
prev_cursor: data.prev_cursor ?? null,
has_more: data.has_more ?? false,
};
}
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
} catch (error) {
console.error('搜索帖子失败:', error);
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
}
}
/**
*
* GET /api/v1/users/:id/posts
* @param userId ID
* @param params
*/
async getUserPostsCursor(
userId: string,
params: CursorPaginationRequest = {}
): Promise<CursorPaginationResponse<Post>> {
try {
const response = await api.get<any>(
`/users/${userId}/posts`,
params
);
const data = response.data;
if (data && typeof data === 'object' && Array.isArray(data.list)) {
const isPageShape =
typeof data.page === 'number' &&
typeof data.total_pages === 'number' &&
data.next_cursor === undefined &&
data.prev_cursor === undefined;
if (isPageShape) {
const currentPage = data.page || 1;
const totalPages = data.total_pages || 1;
return {
list: data.list,
next_cursor: currentPage < totalPages ? String(currentPage + 1) : null,
prev_cursor: currentPage > 1 ? String(currentPage - 1) : null,
has_more: currentPage < totalPages,
};
}
return {
list: data.list,
next_cursor: data.next_cursor ?? null,
prev_cursor: data.prev_cursor ?? null,
has_more: data.has_more ?? false,
};
}
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
} catch (error) {
console.error('获取用户帖子列表失败:', error);
return {
list: [],
next_cursor: null,
prev_cursor: null,
has_more: false,
};
}
}
}
// 导出帖子服务实例
export const postService = new PostService();