此提交完成了以下核心功能与优化: 1. 新增站点公告全流程支持:包含公告模型、CRUD接口、管理后台页面、公告详情页与首页展示 2. 实现评论楼层化与回复嵌套:重构评论系统为树状结构,支持回复评论与层级限制 3. 添加用户在线状态追踪:异步更新用户最后活跃时间并做SQL限频 4. 优化用户体验:移动端浮动操作条、统一板块标签样式、用户页签到积分展示、注册即登录优化 5. 其他细节优化:SEO站点地图新增公告页、评论分页与统计、登录/注册表单增强等
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package handler
|
||
|
||
import (
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"github.com/freefire/jiang13-bbs/middleware"
|
||
"github.com/freefire/jiang13-bbs/model"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// PostComments 获取帖子评论树(楼层分页:主评论算楼层,每楼附带全部子回复,时间正序)
|
||
func (h *Handlers) PostComments(c *gin.Context) {
|
||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
||
return
|
||
}
|
||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
||
|
||
comments, floors, totalComments, err := h.Comment.ListFloorPaged(uint(id), page, size)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"comments": comments,
|
||
"total": floors, // 楼层数(主评论数)→ 前端分页与楼层号计算
|
||
"total_comments": totalComments, // 全部评论数(含回复)→ 展示徽标
|
||
"page": page,
|
||
"size": size,
|
||
})
|
||
}
|
||
|
||
// CreateCommentRequest 评论请求
|
||
type CreateCommentRequest struct {
|
||
Content string `json:"content" binding:"required,min=1"`
|
||
ParentID *uint `json:"parent_id"` // 非空 = 回复该评论(发为其子评论)
|
||
}
|
||
|
||
// CreateComment 创建评论(主评论或子回复)
|
||
func (h *Handlers) CreateComment(c *gin.Context) {
|
||
claims := middleware.CurrentUser(c)
|
||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
||
return
|
||
}
|
||
var req CreateCommentRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
comment, parent, err := h.Comment.Create(claims.ID, uint(id), req.Content, req.ParentID)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
if parent == nil {
|
||
// 主评论:通知帖子作者(排除自己评论自己的帖子)
|
||
if authorID, e := h.Post.GetAuthorID(uint(id)); e == nil {
|
||
h.Notification.Create(authorID, claims.ID, model.NotificationTypeComment, uint(id), comment.ID, req.Content)
|
||
}
|
||
} else {
|
||
// 子回复:通知父评论作者(Notification.Create 内部排除自我通知)
|
||
h.Notification.Create(parent.UserID, claims.ID, model.NotificationTypeReply, uint(id), comment.ID, req.Content)
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"comment": comment})
|
||
}
|
||
|
||
// DeleteComment 删除评论
|
||
func (h *Handlers) DeleteComment(c *gin.Context) {
|
||
claims := middleware.CurrentUser(c)
|
||
cid, err := strconv.ParseUint(c.Param("cid"), 10, 64)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的评论 ID"})
|
||
return
|
||
}
|
||
if err := h.Comment.Delete(uint(cid), claims.ID, claims.Role); err != nil {
|
||
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{"message": "已删除"})
|
||
}
|