import { DataSource, Repository, In } from 'typeorm'; import debug from 'debug'; import { z } from '@hono/zod-openapi'; import { PostEntity as Post } from './post.entity'; import { FollowEntity } from '../follows/follow.entity'; import { UserEntity as User } from '../users/user.entity'; import { UserService } from '../users/user.service'; import type { CreatePostDto, UpdatePostDto } from './post.entity'; import { HTTPException } from 'hono/http-exception'; import { DeleteStatus } from '@/share/types'; const logger = debug('backend:posts:service'); export class PostService { private postRepository: Repository; private userRepository: Repository; private userService: UserService; constructor(dataSource: DataSource) { this.postRepository = dataSource.getRepository(Post); this.userRepository = dataSource.getRepository(User); this.userService = new UserService(dataSource); } /** * 创建帖子 */ async createPost(userId: number, data: z.infer): Promise { // 验证用户是否存在 const user = await this.userRepository.findOneBy({ id: userId }); if (!user) { throw new Error('用户不存在'); } const post = this.postRepository.create({ userId, ...data, likesCount: 0, commentsCount: 0 }); const savedPost = await this.postRepository.save(post); return savedPost as unknown as Post; } /** * 获取帖子详情 */ async getPostById(id: number): Promise { const post = await this.postRepository.findOne({ where: { id, isDeleted: DeleteStatus.NOT_DELETED }, relations: ['user'] }); return post; } /** * 更新帖子 */ async updatePost(postId: number, userId: number, data: z.infer): Promise { // 验证帖子是否存在且属于当前用户 const post = await this.postRepository.findOneBy({ id: postId, userId, isDeleted: DeleteStatus.NOT_DELETED }); if (!post) { throw new Error('帖子不存在或没有权限'); } Object.assign(post, data); return this.postRepository.save(post); } /** * 删除帖子(软删除) */ async deletePost(postId: number, userId: number): Promise { const result = await this.postRepository.update( { id: postId, userId, isDeleted: DeleteStatus.NOT_DELETED }, { isDeleted: DeleteStatus.DELETED } ); return (result.affected || 0) > 0; } /** * 获取用户帖子列表 */ async getUserPosts(userId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> { const skip = (page - 1) * pageSize; const [posts, total] = await this.postRepository.findAndCount({ where: { userId, isDeleted: DeleteStatus.NOT_DELETED }, relations: ['user'], skip, take: pageSize, order: { createdAt: 'DESC' } }); return [posts, total]; } /** * 获取关注用户的帖子流 */ async getFollowingFeed(followerId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> { const skip = (page - 1) * pageSize; // 直接查询关注用户的帖子,假设follow表存在且有关联 logger('Building following feed query for followerId: %d, page: %d, pageSize: %d', followerId, page, pageSize); // 创建主查询用于获取分页数据 const query = this.postRepository .createQueryBuilder('post') .leftJoin('follows', 'f', 'f.following_id = post.user_id') .where('f.follower_id = :followerId', { followerId }) .andWhere('post.is_deleted = :notDeleted', { notDeleted: DeleteStatus.NOT_DELETED }) .leftJoinAndSelect('post.user', 'user') .orderBy('post.created_at', 'DESC') .skip(skip) .take(pageSize); // 创建计数查询 const countQuery = this.postRepository .createQueryBuilder('post') .leftJoin('follows', 'f', 'f.following_id = post.user_id') .where('f.follower_id = :followerId', { followerId }) .andWhere('post.is_deleted = :notDeleted', { notDeleted: DeleteStatus.NOT_DELETED }); // 记录生成的SQL和参数 const sql = query.getSql(); const parameters = query.getParameters(); logger('Following feed query: %s', sql); logger('Query parameters: %o', parameters); const [posts, total] = await Promise.all([ query.getRawMany(), countQuery.getCount() ]); logger('Following feed results: %d posts, total: %d', posts.length, total); return [posts, total]; } /** * 点赞帖子 */ async likePost(postId: number): Promise { const post = await this.postRepository.findOneBy({ id: postId, isDeleted: DeleteStatus.NOT_DELETED }); if (!post) { throw new Error('帖子不存在'); } post.likesCount += 1; return this.postRepository.save(post); } /** * 取消点赞帖子 */ async unlikePost(postId: number): Promise { const post = await this.postRepository.findOneBy({ id: postId, isDeleted: DeleteStatus.NOT_DELETED }); if (!post) { throw new Error('帖子不存在'); } if (post.likesCount > 0) { post.likesCount -= 1; return this.postRepository.save(post); } return post; } /** * 根据用户ID列表获取帖子 */ async getPostsByUserIds(userIds: number[], page: number = 1, pageSize: number = 10): Promise<[Post[], number]> { const skip = (page - 1) * pageSize; const [posts, total] = await this.postRepository.findAndCount({ where: { userId: In(userIds), isDeleted: DeleteStatus.NOT_DELETED }, relations: ['user'], skip, take: pageSize, order: { createdAt: 'DESC' } }); return [posts, total]; } /** * 获取推荐用户的帖子 */ async getRecommendedPosts(currentUserId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> { // 获取推荐用户 const recommendedUsers = await this.userService.getRecommendedUsers(currentUserId); const recommendedUserIds = recommendedUsers.map(u => u.id); if (recommendedUserIds.length > 0) { return this.getPostsByUserIds(recommendedUserIds, page, pageSize); } return [[], 0]; } /** * 获取热门帖子(按点赞数和创建时间排序) */ async getPopularPosts(page: number = 1, pageSize: number = 10): Promise<[Post[], number]> { const skip = (page - 1) * pageSize; const [posts, total] = await this.postRepository.findAndCount({ where: { isDeleted: DeleteStatus.NOT_DELETED }, relations: ['user'], skip, take: pageSize, order: { likesCount: 'DESC', createdAt: 'DESC' } }); return [posts, total]; } }