feat: 帖子收藏与用户关注
- 新增收藏功能:favorite 服务与 handler、FavoriteButton 组件 - 新增关注功能:follow 服务与 handler、FollowButton 组件 - 用户主页适配关注/粉丝与收藏展示 - flash 消息工具、广告与侧边栏组件微调
This commit is contained in:
@@ -270,16 +270,31 @@ func (s *PostService) List(q PostListQuery) ([]PostListItem, int64, error) {
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
// normalizeUserPostSort 用户主页帖子排序口径(非法值回落 new)
|
||||
func normalizeUserPostSort(sort string) string {
|
||||
switch sort {
|
||||
case "hot", "essence":
|
||||
return sort
|
||||
default:
|
||||
return "new"
|
||||
}
|
||||
}
|
||||
|
||||
// ListByUser 获取指定用户发布的帖子。
|
||||
// viewer 为本人或全站可审者时并入 pending;板块管理员仅并入其授权板的 pending。
|
||||
func (s *PostService) ListByUser(userID, viewerID uint, actor *Actor, page, size int) ([]PostListItem, int64, error) {
|
||||
// sort: new=最新(默认,置顶优先)、hot=热门(点赞+评论加权)、essence=精华(仅 recommended)。
|
||||
func (s *PostService) ListByUser(userID, viewerID uint, actor *Actor, page, size int, sort string) ([]PostListItem, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if size < 1 || size > 50 {
|
||||
size = 20
|
||||
}
|
||||
sort = normalizeUserPostSort(sort)
|
||||
query := s.db.Model(&model.Post{}).Where("user_id = ?", userID)
|
||||
if sort == "essence" {
|
||||
query = query.Where("recommended = ?", true)
|
||||
}
|
||||
if viewerID == userID || (actor != nil && model.RoleLevel(actor.Role) >= model.RoleLevel(model.RoleAdmin)) {
|
||||
query = query.Where("status IN ?", []string{model.ContentStatusPublished, model.ContentStatusPending})
|
||||
} else if actor != nil && actor.Role == model.RoleBoardAdmin && len(actor.BoardIDs) > 0 {
|
||||
@@ -296,7 +311,11 @@ func (s *PostService) ListByUser(userID, viewerID uint, actor *Actor, page, size
|
||||
}
|
||||
var posts []model.Post
|
||||
offset := (page - 1) * size
|
||||
if err := query.Order("pinned DESC, created_at DESC").Offset(offset).Limit(size).
|
||||
order := "pinned DESC, created_at DESC"
|
||||
if sort == "hot" {
|
||||
order = "like_count + comment_count DESC, view_count DESC, created_at DESC"
|
||||
}
|
||||
if err := query.Order(order).Offset(offset).Limit(size).
|
||||
Preload("Board").Preload("User").Preload("User.Badges.Badge").Find(&posts).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -457,7 +476,8 @@ type PostDetail struct {
|
||||
ViewCount int `json:"view_count"`
|
||||
CommentCount int `json:"comment_count"`
|
||||
Liked bool `json:"liked"`
|
||||
Edited bool `json:"edited"` // 是否存在编辑历史快照(决定"更新于/编辑历史"入口展示)
|
||||
Favorited bool `json:"favorited"` // 当前查看者是否已收藏(详情接口实时填充)
|
||||
Edited bool `json:"edited"` // 是否存在编辑历史快照(决定"更新于/编辑历史"入口展示)
|
||||
// 最后一条已发布评论时间;null=无回复(旧帖判定回落 created_at)
|
||||
LastReplyAt *time.Time `json:"last_reply_at,omitempty"`
|
||||
// 旧帖回复确认提示:按查看者实时计算,命中才返回;前端存在即弹确认框
|
||||
|
||||
Reference in New Issue
Block a user