feat: @提及功能优化 + 默认头像改用SVG图标

- 评论区有效@提及渲染为蓝色链接跳转/space/{uid},无效@保持纯文本
- 输入@触发悬浮窗,根据输入实时搜索用户(含头像+等级)
- 无匹配时显示未搜索到用户,选中后插入为@用户名 格式(尾部空格)
- 悬浮窗定位于输入光标上方,不遮挡输入内容
- 后端Comment新增Mentions字段,批量加载提及映射供前端判断
- SearchUsers/parseMentions 统一限制LV2+用户
- 所有默认头像由首字符文字改为统一SVG人形图标(nav/home/space/mention等7处)
This commit is contained in:
2026-06-03 00:49:24 +08:00
parent 2d05da6709
commit 4ac4f64f33
12 changed files with 249 additions and 57 deletions

View File

@ -152,7 +152,15 @@ func (s *CommentService) Delete(commentID uint, requesterID uint, isAdmin bool)
func (s *CommentService) ListRootComments(postID uint, page, pageSize int) ([]model.Comment, int64, error) {
p := common.Pagination{Page: page, PageSize: pageSize}
p.DefaultPagination()
return s.repo.FindRootComments(postID, p.Offset(), p.PageSize)
comments, total, err := s.repo.FindRootComments(postID, p.Offset(), p.PageSize)
if err != nil {
return nil, 0, err
}
// 批量加载有效@提及映射,前端据此决定是否为链接
if len(comments) > 0 {
_ = s.repo.LoadMentionsForComments(comments)
}
return comments, total, nil
}
// ListReplies 获取某条顶级评论的全部回复
@ -164,6 +172,10 @@ func (s *CommentService) ListReplies(rootID uint) ([]model.Comment, error) {
if list == nil {
list = []model.Comment{}
}
// 批量加载有效@提及映射
if len(list) > 0 {
_ = s.repo.LoadMentionsForComments(list)
}
return list, nil
}
@ -178,9 +190,9 @@ func (s *CommentService) ListAllComments(keyword string, showDeleted bool, page,
return rows, total, err
}
// SearchUsers 搜索LV3+用户(用于@艾特)
// SearchUsers 搜索LV2+用户(用于@艾特悬浮窗
func (s *CommentService) SearchUsers(keyword string) ([]model.UserSearchResult, error) {
rows, err := s.repo.SearchUsersByLevel(keyword, 3, 10)
rows, err := s.repo.SearchUsersByLevel(keyword, 2, 10)
if err != nil {
return nil, fmt.Errorf("搜索用户失败: %w", err)
}
@ -191,6 +203,7 @@ func (s *CommentService) SearchUsers(keyword string) ([]model.UserSearchResult,
UID: row.UID,
Username: row.Username,
Level: model.GetLevelByExp(row.Exp),
Avatar: row.Avatar,
}
}
return users, nil
@ -206,7 +219,7 @@ func (s *CommentService) parseMentions(commentID uint, body string) {
continue
}
seen[username] = true
rows, _ := s.repo.SearchUsersByLevel(username, 0, 1)
rows, _ := s.repo.SearchUsersByLevel(username, 2, 1)
if len(rows) > 0 {
_ = s.repo.CreateMention(&model.CommentMention{
CommentID: commentID,

View File

@ -158,9 +158,11 @@ type commentStore interface {
SearchUsersByLevel(keyword string, minLevel, limit int) ([]struct {
UID uint
Username string
Avatar string
Exp int
}, error)
GetUsernameByID(userID uint) (string, error)
LoadMentionsForComments(comments []model.Comment) error
ListAllComments(keyword string, showDeleted bool, offset, limit int) ([]model.AdminCommentRow, int64, error)
}