feat: @搜索优先展示已关注用户,结果限制最多5条

- SearchUsersByLevel SQL新增LEFT JOIN user_follows,按已关注优先+exp降序
- SearchUsers/followerUID参数贯穿repo→service→controller
- 继续输入时前端自动重新搜索新关键词
This commit is contained in:
2026-06-03 01:15:38 +08:00
parent fb9724faed
commit 864a488ee0
5 changed files with 21 additions and 15 deletions

View File

@ -41,7 +41,7 @@ func (ctrl *CommentController) Delete(c *gin.Context) {
// SearchUsers GET /api/users/search?q=keyword
func (ctrl *CommentController) SearchUsers(c *gin.Context) {
_, _, ok := common.GetGinUser(c)
uid, _, ok := common.GetGinUser(c)
if !ok {
common.Error(c, http.StatusUnauthorized, "请先登录")
return
@ -53,7 +53,7 @@ func (ctrl *CommentController) SearchUsers(c *gin.Context) {
return
}
users, err := ctrl.commentService.SearchUsers(q)
users, err := ctrl.commentService.SearchUsers(q, uid)
if err != nil {
common.Error(c, http.StatusInternalServerError, "搜索用户失败")
return

View File

@ -115,7 +115,7 @@ type commentUseCase interface {
Delete(commentID uint, requesterID uint, isAdmin bool) error
ListRootComments(postID uint, page, pageSize int) ([]model.Comment, int64, error)
ListReplies(rootID uint) ([]model.Comment, error)
SearchUsers(keyword string) ([]model.UserSearchResult, error)
SearchUsers(keyword string, followerUID uint) ([]model.UserSearchResult, error)
}
// reactionUseCase ReactionController 对 ReactionService 的最小依赖ISP4 个方法)

View File

@ -67,7 +67,8 @@ func (r *CommentRepo) LoadMentionsForComments(comments []model.Comment) error {
}
// SearchUsersByLevel 搜索指定等级及以上用户(用于@艾特),返回 uid/username/avatar/exp
func (r *CommentRepo) SearchUsersByLevel(keyword string, minLevel int, limit int) ([]struct {
// followerUID > 0 时按已关注优先排序其次按exp降序
func (r *CommentRepo) SearchUsersByLevel(keyword string, minLevel, limit int, followerUID uint) ([]struct {
UID uint
Username string
Avatar string
@ -83,12 +84,17 @@ func (r *CommentRepo) SearchUsersByLevel(keyword string, minLevel int, limit int
threshold := model.LevelThresholds[minLevel]
err := r.db.Table("users").
Select("id AS uid, username, avatar, exp").
Where("username LIKE ? AND exp >= ? AND deleted_at IS NULL", "%"+keyword+"%", threshold).
Order("exp DESC").
Limit(limit).
Find(&list).Error
q := r.db.Table("users AS u").
Select("u.id AS uid, u.username, u.avatar, u.exp").
Where("u.username LIKE ? AND u.exp >= ? AND u.deleted_at IS NULL", "%"+keyword+"%", threshold).
Order("u.exp DESC")
if followerUID > 0 {
q = q.Joins("LEFT JOIN user_follows f ON f.followee_id = u.id AND f.follower_id = ?", followerUID).
Order("(f.follower_id IS NOT NULL) DESC, u.exp DESC")
}
err := q.Limit(limit).Find(&list).Error
var res []struct {
UID uint

View File

@ -190,9 +190,9 @@ func (s *CommentService) ListAllComments(keyword string, showDeleted bool, page,
return rows, total, err
}
// SearchUsers 搜索LV2+用户(用于@艾特悬浮窗)
func (s *CommentService) SearchUsers(keyword string) ([]model.UserSearchResult, error) {
rows, err := s.repo.SearchUsersByLevel(keyword, 2, 10)
// SearchUsers 搜索LV2+用户(用于@艾特悬浮窗)已关注优先最多5条
func (s *CommentService) SearchUsers(keyword string, followerUID uint) ([]model.UserSearchResult, error) {
rows, err := s.repo.SearchUsersByLevel(keyword, 2, 5, followerUID)
if err != nil {
return nil, fmt.Errorf("搜索用户失败: %w", err)
}
@ -219,7 +219,7 @@ func (s *CommentService) parseMentions(commentID uint, body string) {
continue
}
seen[username] = true
rows, _ := s.repo.SearchUsersByLevel(username, 2, 1)
rows, _ := s.repo.SearchUsersByLevel(username, 2, 1, 0)
if len(rows) > 0 {
_ = s.repo.CreateMention(&model.CommentMention{
CommentID: commentID,

View File

@ -155,7 +155,7 @@ type commentStore interface {
CreateMention(mention *model.CommentMention) error
FindPostIDByComment(commentID uint) (uint, error)
FindPostAuthorID(postID uint) (uint, error)
SearchUsersByLevel(keyword string, minLevel, limit int) ([]struct {
SearchUsersByLevel(keyword string, minLevel, limit int, followerUID uint) ([]struct {
UID uint
Username string
Avatar string