feat: @搜索优先展示已关注用户,结果限制最多5条
- SearchUsersByLevel SQL新增LEFT JOIN user_follows,按已关注优先+exp降序 - SearchUsers/followerUID参数贯穿repo→service→controller - 继续输入时前端自动重新搜索新关键词
This commit is contained in:
@ -41,7 +41,7 @@ func (ctrl *CommentController) Delete(c *gin.Context) {
|
|||||||
|
|
||||||
// SearchUsers GET /api/users/search?q=keyword
|
// SearchUsers GET /api/users/search?q=keyword
|
||||||
func (ctrl *CommentController) SearchUsers(c *gin.Context) {
|
func (ctrl *CommentController) SearchUsers(c *gin.Context) {
|
||||||
_, _, ok := common.GetGinUser(c)
|
uid, _, ok := common.GetGinUser(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
common.Error(c, http.StatusUnauthorized, "请先登录")
|
common.Error(c, http.StatusUnauthorized, "请先登录")
|
||||||
return
|
return
|
||||||
@ -53,7 +53,7 @@ func (ctrl *CommentController) SearchUsers(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := ctrl.commentService.SearchUsers(q)
|
users, err := ctrl.commentService.SearchUsers(q, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Error(c, http.StatusInternalServerError, "搜索用户失败")
|
common.Error(c, http.StatusInternalServerError, "搜索用户失败")
|
||||||
return
|
return
|
||||||
|
|||||||
@ -115,7 +115,7 @@ type commentUseCase interface {
|
|||||||
Delete(commentID uint, requesterID uint, isAdmin bool) error
|
Delete(commentID uint, requesterID uint, isAdmin bool) error
|
||||||
ListRootComments(postID uint, page, pageSize int) ([]model.Comment, int64, error)
|
ListRootComments(postID uint, page, pageSize int) ([]model.Comment, int64, error)
|
||||||
ListReplies(rootID uint) ([]model.Comment, error)
|
ListReplies(rootID uint) ([]model.Comment, error)
|
||||||
SearchUsers(keyword string) ([]model.UserSearchResult, error)
|
SearchUsers(keyword string, followerUID uint) ([]model.UserSearchResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reactionUseCase ReactionController 对 ReactionService 的最小依赖(ISP:4 个方法)
|
// reactionUseCase ReactionController 对 ReactionService 的最小依赖(ISP:4 个方法)
|
||||||
|
|||||||
@ -67,7 +67,8 @@ func (r *CommentRepo) LoadMentionsForComments(comments []model.Comment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchUsersByLevel 搜索指定等级及以上用户(用于@艾特),返回 uid/username/avatar/exp
|
// 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
|
UID uint
|
||||||
Username string
|
Username string
|
||||||
Avatar string
|
Avatar string
|
||||||
@ -83,12 +84,17 @@ func (r *CommentRepo) SearchUsersByLevel(keyword string, minLevel int, limit int
|
|||||||
|
|
||||||
threshold := model.LevelThresholds[minLevel]
|
threshold := model.LevelThresholds[minLevel]
|
||||||
|
|
||||||
err := r.db.Table("users").
|
q := r.db.Table("users AS u").
|
||||||
Select("id AS uid, username, avatar, exp").
|
Select("u.id AS uid, u.username, u.avatar, u.exp").
|
||||||
Where("username LIKE ? AND exp >= ? AND deleted_at IS NULL", "%"+keyword+"%", threshold).
|
Where("u.username LIKE ? AND u.exp >= ? AND u.deleted_at IS NULL", "%"+keyword+"%", threshold).
|
||||||
Order("exp DESC").
|
Order("u.exp DESC")
|
||||||
Limit(limit).
|
|
||||||
Find(&list).Error
|
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 {
|
var res []struct {
|
||||||
UID uint
|
UID uint
|
||||||
|
|||||||
@ -190,9 +190,9 @@ func (s *CommentService) ListAllComments(keyword string, showDeleted bool, page,
|
|||||||
return rows, total, err
|
return rows, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUsers 搜索LV2+用户(用于@艾特悬浮窗)
|
// SearchUsers 搜索LV2+用户(用于@艾特悬浮窗),已关注优先,最多5条
|
||||||
func (s *CommentService) SearchUsers(keyword string) ([]model.UserSearchResult, error) {
|
func (s *CommentService) SearchUsers(keyword string, followerUID uint) ([]model.UserSearchResult, error) {
|
||||||
rows, err := s.repo.SearchUsersByLevel(keyword, 2, 10)
|
rows, err := s.repo.SearchUsersByLevel(keyword, 2, 5, followerUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("搜索用户失败: %w", err)
|
return nil, fmt.Errorf("搜索用户失败: %w", err)
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ func (s *CommentService) parseMentions(commentID uint, body string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen[username] = true
|
seen[username] = true
|
||||||
rows, _ := s.repo.SearchUsersByLevel(username, 2, 1)
|
rows, _ := s.repo.SearchUsersByLevel(username, 2, 1, 0)
|
||||||
if len(rows) > 0 {
|
if len(rows) > 0 {
|
||||||
_ = s.repo.CreateMention(&model.CommentMention{
|
_ = s.repo.CreateMention(&model.CommentMention{
|
||||||
CommentID: commentID,
|
CommentID: commentID,
|
||||||
|
|||||||
@ -155,7 +155,7 @@ type commentStore interface {
|
|||||||
CreateMention(mention *model.CommentMention) error
|
CreateMention(mention *model.CommentMention) error
|
||||||
FindPostIDByComment(commentID uint) (uint, error)
|
FindPostIDByComment(commentID uint) (uint, error)
|
||||||
FindPostAuthorID(postID 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
|
UID uint
|
||||||
Username string
|
Username string
|
||||||
Avatar string
|
Avatar string
|
||||||
|
|||||||
Reference in New Issue
Block a user