本次提交实现了完整的社区首页功能: 1. 新增首页聚合接口与服务,包含社区统计、热门帖、活跃用户与板块数据 2. 实现帖子推荐排序、SSR缓存与点赞态同步逻辑 3. 重构导航与布局系统,新增工作台侧边栏与移动端适配 4. 优化主题色与UI样式,统一设计系统风格 5. 修复登录注册页自动跳转与组件状态同步问题
182 lines
5.1 KiB
Go
182 lines
5.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/freefire/jiang13-bbs/middleware"
|
|
"github.com/freefire/jiang13-bbs/service"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// Posts 获取帖子列表
|
|
func (h *Handlers) Posts(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
|
boardID, _ := strconv.ParseUint(c.Query("board_id"), 10, 64)
|
|
sort := c.DefaultQuery("sort", "latest")
|
|
keyword := c.Query("keyword")
|
|
recommended := c.Query("recommended") == "true"
|
|
|
|
items, total, err := h.Post.List(service.PostListQuery{
|
|
BoardID: uint(boardID),
|
|
Page: page,
|
|
Size: size,
|
|
Sort: sort,
|
|
Keyword: keyword,
|
|
Recommended: recommended,
|
|
})
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
// 填充点赞状态(仅登录用户)
|
|
if claims := middleware.CurrentUser(c); claims != nil {
|
|
ids := make([]uint, 0, len(items))
|
|
for _, p := range items {
|
|
ids = append(ids, p.ID)
|
|
}
|
|
likedMap := h.Like.BatchHasLiked(ids, claims.ID)
|
|
for i := range items {
|
|
items[i].Liked = likedMap[items[i].ID]
|
|
}
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"posts": items,
|
|
"total": total,
|
|
"page": page,
|
|
"size": size,
|
|
})
|
|
}
|
|
|
|
// PostDetail 获取帖子详情
|
|
func (h *Handlers) PostDetail(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
|
return
|
|
}
|
|
post, err := h.Post.GetByID(uint(id))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "帖子不存在"})
|
|
return
|
|
}
|
|
// 填充点赞状态(仅登录用户)
|
|
if claims := middleware.CurrentUser(c); claims != nil {
|
|
post.Liked = h.Like.HasLiked(post.ID, claims.ID)
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"post": post})
|
|
}
|
|
|
|
// CreatePostRequest 发帖请求
|
|
type CreatePostRequest struct {
|
|
BoardID uint `json:"board_id" binding:"required"`
|
|
Title string `json:"title" binding:"required,min=1,max=256"`
|
|
Content string `json:"content" binding:"required,min=1"`
|
|
Tags string `json:"tags"`
|
|
PostType string `json:"post_type"`
|
|
}
|
|
|
|
// CreatePost 创建帖子
|
|
func (h *Handlers) CreatePost(c *gin.Context) {
|
|
claims := middleware.CurrentUser(c)
|
|
var req CreatePostRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
postType := req.PostType
|
|
if postType == "" {
|
|
postType = "normal"
|
|
}
|
|
post, err := h.Post.Create(claims.ID, req.BoardID, req.Title, req.Content, req.Tags, postType)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"post": post})
|
|
}
|
|
|
|
// UpdatePostRequest 更新帖子请求
|
|
type UpdatePostRequest struct {
|
|
Title string `json:"title" binding:"omitempty,min=1,max=256"`
|
|
Content string `json:"content" binding:"omitempty,min=1"`
|
|
Tags string `json:"tags"`
|
|
}
|
|
|
|
// UpdatePost 编辑帖子
|
|
func (h *Handlers) UpdatePost(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 UpdatePostRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
post, err := h.Post.Update(uint(id), claims.ID, claims.Role, req.Title, req.Content, req.Tags)
|
|
if err != nil {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"post": post})
|
|
}
|
|
|
|
// DeletePost 删除帖子
|
|
func (h *Handlers) DeletePost(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
|
|
}
|
|
if err := h.Post.Delete(uint(id), claims.ID, claims.Role); err != nil {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "已删除"})
|
|
}
|
|
|
|
// TogglePin 切换帖子置顶(仅管理员)
|
|
func (h *Handlers) TogglePin(c *gin.Context) {
|
|
claims := middleware.CurrentUser(c)
|
|
if claims.Role != "admin" {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "仅管理员可操作"})
|
|
return
|
|
}
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
|
return
|
|
}
|
|
pinned, err := h.Post.TogglePin(uint(id))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"pinned": pinned})
|
|
}
|
|
|
|
// ToggleRecommend 切换帖子推荐(仅管理员)
|
|
func (h *Handlers) ToggleRecommend(c *gin.Context) {
|
|
claims := middleware.CurrentUser(c)
|
|
if claims.Role != "admin" {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "仅管理员可操作"})
|
|
return
|
|
}
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的帖子 ID"})
|
|
return
|
|
}
|
|
recommended, err := h.Post.ToggleRecommend(uint(id))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"recommended": recommended})
|
|
}
|