package service import ( "github.com/sundynix/pets-be/internal/model" ) // UserCard 用户公开资料。关注这件事之前只做了「点一下关注」, // 关注完既看不到对方主页、也看不到自己关注了谁——等于关注完就石沉大海。 type UserCard struct { ID string `json:"id"` Nickname string `json:"nickname"` AvatarURL string `json:"avatar_url"` IsBot bool `json:"is_bot"` IsSelf bool `json:"is_self"` Followed bool `json:"followed"` // 我有没有关注 TA Posts int64 `json:"post_count"` Following int64 `json:"following_count"` Followers int64 `json:"follower_count"` } // GetUserCard 取某人的公开资料 + 三个计数 + 我是否已关注 func (s *Service) GetUserCard(viewerID, userID string) (*UserCard, error) { var u model.User if err := s.db.First(&u, "id = ?", userID).Error; err != nil { return nil, ErrNotFound } card := &UserCard{ ID: u.ID, Nickname: u.Nickname, IsBot: u.IsBot, IsSelf: u.ID == viewerID, AvatarURL: s.fileURL(u.AvatarFileID), } if card.AvatarURL == "" { card.AvatarURL = u.Avatar } s.db.Model(&model.Post{}).Where("user_id = ? AND status = ?", userID, "published").Count(&card.Posts) s.db.Model(&model.Follow{}).Where("follower_id = ?", userID).Count(&card.Following) s.db.Model(&model.Follow{}).Where("followee_id = ?", userID).Count(&card.Followers) if !card.IsSelf { var n int64 s.db.Model(&model.Follow{}). Where("follower_id = ? AND followee_id = ?", viewerID, userID).Count(&n) card.Followed = n > 0 } return card, nil } // ListUserPosts 某人发布的帖子 func (s *Service) ListUserPosts(viewerID, userID string, offset, limit int) ([]model.Post, int64, error) { q := s.db.Model(&model.Post{}).Where("user_id = ? AND status = ?", userID, "published") var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, err } var posts []model.Post if err := q.Order("id desc").Offset(offset).Limit(limit).Find(&posts).Error; err != nil { return nil, 0, err } s.attachPostImages(posts) s.markFollowed(viewerID, posts) return posts, total, nil } // ListRelations 关注列表 / 粉丝列表。 // kind = "following" 我关注的人;"followers" 关注我的人 func (s *Service) ListRelations(viewerID, userID, kind string, offset, limit int) ([]UserCard, int64, error) { q := s.db.Model(&model.Follow{}) var idCol string if kind == "followers" { q = q.Where("followee_id = ?", userID) idCol = "follower_id" } else { q = q.Where("follower_id = ?", userID) idCol = "followee_id" } var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, err } var ids []string if err := q.Order("id desc").Offset(offset).Limit(limit).Pluck(idCol, &ids).Error; err != nil { return nil, 0, err } if len(ids) == 0 { return []UserCard{}, total, nil } var users []model.User s.db.Where("id IN ?", ids).Find(&users) byID := map[string]model.User{} for _, u := range users { byID[u.ID] = u } // 一次查出我关注了这批人里的哪些,不要每行一次查询 var mine []string s.db.Model(&model.Follow{}).Where("follower_id = ? AND followee_id IN ?", viewerID, ids). Pluck("followee_id", &mine) followed := map[string]bool{} for _, id := range mine { followed[id] = true } // 按 ids 的顺序输出,保持「最近关注的在前」 out := make([]UserCard, 0, len(ids)) for _, id := range ids { u, ok := byID[id] if !ok { continue } avatar := s.fileURL(u.AvatarFileID) if avatar == "" { avatar = u.Avatar } out = append(out, UserCard{ ID: u.ID, Nickname: u.Nickname, IsBot: u.IsBot, AvatarURL: avatar, IsSelf: u.ID == viewerID, Followed: followed[u.ID], }) } return out, total, nil }