This repository has been archived on 2026-06-21. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MetaLab/internal/repository/comment_mention_repo.go
Victor_Jay ae15025b1d feat: @提及支持改名后链接跟随UID + 显示名自动更新
- comment_mentions新增original_username列,创建时记录原始@用户名
- Mentions map改为{original_username: {uid, name}}结构,name为当前显示名
- 用户改名后:旧@文本仍能匹配original_username,链接跟随uid不变,显示名自动更新
- 前端renderMentions适配新结构
2026-06-03 01:00:44 +08:00

179 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"metazone.cc/metalab/internal/model"
"metazone.cc/metalab/internal/service"
)
// CreateMention 创建@提及记录
func (r *CommentRepo) CreateMention(mention *model.CommentMention) error {
return r.db.Create(mention).Error
}
// FindMentionsByComment 查询某条评论的@提及列表
func (r *CommentRepo) FindMentionsByComment(commentID uint) ([]model.CommentMention, error) {
var list []model.CommentMention
err := r.db.Where("comment_id = ?", commentID).Find(&list).Error
return list, err
}
// LoadMentionsForComments 批量加载多条评论的有效@提及映射
// key=创建时的原始@用户名, value={uid, 用户当前显示名}
// 用户改名后原始名匹配body中的旧@文本显示名随users表更新
func (r *CommentRepo) LoadMentionsForComments(comments []model.Comment) error {
if len(comments) == 0 {
return nil
}
commentIDs := make([]uint, len(comments))
for i, c := range comments {
commentIDs[i] = c.ID
}
type mentionRow struct {
CommentID uint
UID uint
OriginalUsername string
CurrentName string
}
var rows []mentionRow
err := r.db.Table("comment_mentions").
Select("comment_mentions.comment_id, comment_mentions.uid, comment_mentions.original_username, users.username AS current_name").
Joins("LEFT JOIN users ON users.id = comment_mentions.uid").
Where("comment_mentions.comment_id IN ?", commentIDs).
Find(&rows).Error
if err != nil {
return err
}
// 按 comment_id 分组key = original_username, value = MentionInfo
mentionMap := make(map[uint]map[string]model.MentionInfo)
for _, row := range rows {
if mentionMap[row.CommentID] == nil {
mentionMap[row.CommentID] = make(map[string]model.MentionInfo)
}
mentionMap[row.CommentID][row.OriginalUsername] = model.MentionInfo{
UID: row.UID,
Name: row.CurrentName,
}
}
for i := range comments {
if m, ok := mentionMap[comments[i].ID]; ok {
comments[i].Mentions = m
}
}
return nil
}
// SearchUsersByLevel 搜索指定等级及以上用户(用于@艾特),返回 uid/username/avatar/exp
func (r *CommentRepo) SearchUsersByLevel(keyword string, minLevel int, limit int) ([]struct {
UID uint
Username string
Avatar string
Exp int
}, error) {
type result struct {
UID uint
Username string
Avatar string
Exp int
}
var list []result
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
var res []struct {
UID uint
Username string
Avatar string
Exp int
}
for _, u := range list {
res = append(res, struct {
UID uint
Username string
Avatar string
Exp int
}{UID: u.UID, Username: u.Username, Avatar: u.Avatar, Exp: u.Exp})
}
return res, err
}
// GetUsernameByID 通过 userID 获取用户名(用于通知内容)
func (r *CommentRepo) GetUsernameByID(userID uint) (string, error) {
var username string
err := r.db.Table("users").Select("username").Where("id = ?", userID).Scan(&username).Error
return username, err
}
// FindPostIDByComment 查询评论所属的文章ID
func (r *CommentRepo) FindPostIDByComment(commentID uint) (uint, error) {
var postID uint
err := r.db.Table("comments").Select("post_id").Where("id = ?", commentID).Scan(&postID).Error
return postID, err
}
// UpdateRootID 更新评论的 root_id 字段(顶级评论创建后回填)
func (r *CommentRepo) UpdateRootID(id, rootID uint) error {
return r.db.Model(&model.Comment{}).Where("id = ?", id).Update("root_id", rootID).Error
}
// FindPostAuthorID 查询文章的作者 user_id
func (r *CommentRepo) FindPostAuthorID(postID uint) (uint, error) {
var authorID uint
err := r.db.Table("posts").Select("user_id").Where("id = ?", postID).Scan(&authorID).Error
return authorID, err
}
// AggregateCommentsByAuthor 按日期聚合评论量(作者所有文章在时间段内的评论)
func (r *CommentRepo) AggregateCommentsByAuthor(userID uint, since string) ([]service.TrendPoint, error) {
var results []service.TrendPoint
err := r.db.Table("comments").
Select("TO_CHAR(comments.created_at, 'YYYY-MM-DD') AS date, COUNT(*) AS value").
Joins("JOIN posts ON posts.id = comments.post_id").
Where("posts.user_id = ? AND comments.created_at >= ?", userID, since).
Group("TO_CHAR(comments.created_at, 'YYYY-MM-DD')").
Order("date ASC").
Scan(&results).Error
if results == nil {
results = []service.TrendPoint{}
}
return results, err
}
// ListAllComments 后台评论列表(支持关键词搜索、分页)
func (r *CommentRepo) ListAllComments(keyword string, showDeleted bool, offset, limit int) ([]model.AdminCommentRow, int64, error) {
var total int64
q := r.db.Table("comments").
Joins("LEFT JOIN users ON users.id = comments.user_id").
Joins("LEFT JOIN posts ON posts.id = comments.post_id")
if !showDeleted {
q = q.Where("comments.is_deleted = false")
}
if keyword != "" {
like := "%" + keyword + "%"
q = q.Where("comments.body LIKE ? OR users.username LIKE ? OR posts.title LIKE ?", like, like, like)
}
if err := q.Count(&total).Error; err != nil {
return nil, 0, err
}
var rows []model.AdminCommentRow
err := q.
Select("comments.id, comments.post_id, posts.title as post_title, comments.body, users.username as author_name, comments.is_deleted, comments.created_at, comments.updated_at").
Order("comments.created_at DESC").
Offset(offset).Limit(limit).
Scan(&rows).Error
return rows, total, err
}