Sfoglia il codice sorgente

✨ feat(posts): 实现帖子推荐功能

- 当用户未关注任何人时,自动展示推荐用户的帖子
- 添加getRecommendedPosts方法,用于获取推荐用户的帖子
- 在UserService中添加getRecommendedUsers方法,获取未关注的活跃用户
- 添加getPostsByUserIds方法,支持根据用户ID列表批量获取帖子

🐛 fix(posts): 优化帖子查询逻辑

- 为posts变量添加明确的类型定义
- 初始化total变量为0,避免可能的undefined问题
yourname 5 mesi fa
parent
commit
67726ee8f8

+ 15 - 4
src/server/api/posts/get.ts

@@ -2,10 +2,11 @@ import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
 import { z } from '@hono/zod-openapi';
 import { AppDataSource } from '@/server/data-source';
 import { PostService } from '@/server/modules/posts/post.service';
-import { PostSchema } from '@/server/modules/posts/post.entity';
+import { PostSchema, PostEntity } from '@/server/modules/posts/post.entity';
 import { AuthContext } from '@/server/types/context';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
 import { ErrorSchema } from '@/server/utils/errorHandler';
+import { FollowService } from '@/server/modules/follows/follow.service';
 
 // 查询参数Schema
 const QuerySchema = z.object({
@@ -62,16 +63,26 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
   try {
     const { page, pageSize, userId } = c.req.valid('query');
     const postService = new PostService(AppDataSource);
+    const followService = new FollowService(AppDataSource);
     
-    let posts, total;
+    let posts: PostEntity[] = [];
+    let total = 0;
     
     if (userId) {
       // 获取特定用户的帖子
       [posts, total] = await postService.getUserPosts(userId, page, pageSize);
     } else {
-      // 获取当前用户关注的人的帖子流
       const user = c.get('user');
-      [posts, total] = await postService.getFollowingFeed(user.id, page, pageSize);
+      // 检查用户关注数量
+      const followingCount = await followService.getFollowingCount(user.id);
+      
+      if (followingCount === 0) {
+        // 用户未关注任何人,获取推荐用户的帖子
+        [posts, total] = await postService.getRecommendedPosts(user.id, page, pageSize);
+      } else {
+        // 获取当前用户关注的人的帖子流
+        [posts, total] = await postService.getFollowingFeed(user.id, page, pageSize);
+      }
     }
     
     return c.json({

+ 39 - 1
src/server/modules/posts/post.service.ts

@@ -1,9 +1,10 @@
-import { DataSource, Repository } from 'typeorm';
+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';
@@ -13,10 +14,12 @@ const logger = debug('backend:posts:service');
 export class PostService {
   private postRepository: Repository<Post>;
   private userRepository: Repository<User>;
+  private userService: UserService;
 
   constructor(dataSource: DataSource) {
     this.postRepository = dataSource.getRepository(Post);
     this.userRepository = dataSource.getRepository(User);
+    this.userService = new UserService(dataSource);
   }
 
   /**
@@ -179,4 +182,39 @@ export class PostService {
 
     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];
+  }
 }

+ 21 - 0
src/server/modules/users/user.service.ts

@@ -163,4 +163,25 @@ export class UserService {
       throw new Error('Failed to get user by account');
     }
   }
+
+  /**
+   * 获取推荐用户列表
+   */
+  async getRecommendedUsers(currentUserId: number, limit: number = 5): Promise<User[]> {
+    try {
+      // 查询当前用户未关注的活跃用户
+      const query = this.userRepository
+        .createQueryBuilder('user')
+        .leftJoin('follows', 'f', 'f.following_id = user.id AND f.follower_id = :currentUserId', { currentUserId })
+        .where('user.id != :currentUserId', { currentUserId })
+        .andWhere('f.id IS NULL') // 排除已关注用户
+        .orderBy('user.created_at', 'DESC') // 按注册时间倒序,优先推荐新用户
+        .take(limit);
+
+      return await query.getMany();
+    } catch (error) {
+      console.error('Error getting recommended users:', error);
+      throw new Error(`Failed to get recommended users: ${error instanceof Error ? error.message : String(error)}`)
+    }
+  }
 }