支持公开用户主页、帖子图缩略图与编辑器图组排版。
新增用户签名与活动统计、图片灯箱;正文按需生成缩略图;TipTap 支持多图分组与环绕排版,并注入站点标题避免刷新闪烁。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -662,10 +662,12 @@ func (h *Handlers) APIPosts(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", strconv.Itoa(h.Settings.PageSizeDefault())))
|
||||
boardID, _ := strconv.ParseUint(c.Query("board_id"), 10, 64)
|
||||
userID, _ := strconv.ParseUint(c.Query("user_id"), 10, 64)
|
||||
keyword := c.Query("keyword")
|
||||
|
||||
q := service.PostListQuery{
|
||||
BoardID: uint(boardID),
|
||||
UserID: uint(userID),
|
||||
Page: page,
|
||||
Size: size,
|
||||
Keyword: keyword,
|
||||
|
||||
@@ -279,6 +279,44 @@ func (h *Handlers) APILogout(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "已退出"})
|
||||
}
|
||||
|
||||
// APIProfileStats 当前用户活动统计(发帖 / 评论 / 收藏 / 获赞)
|
||||
func (h *Handlers) APIProfileStats(c *gin.Context) {
|
||||
st, err := h.User.ActivityStats(h.currentUserID(c))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"stats": st})
|
||||
}
|
||||
|
||||
// APIUserPublic 公开用户主页(资料 + 公开统计)
|
||||
func (h *Handlers) APIUserPublic(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效用户"})
|
||||
return
|
||||
}
|
||||
user, err := h.User.GetByID(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
|
||||
return
|
||||
}
|
||||
st, err := h.User.ActivityStats(user.ID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// 收藏数仅本人可见
|
||||
viewerID := h.currentUserID(c)
|
||||
if viewerID != user.ID {
|
||||
st.FavoriteCount = 0
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"user": user.ToPublic(),
|
||||
"stats": st,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handlers) APIUpdateProfile(c *gin.Context) {
|
||||
nickname := c.PostForm("nickname")
|
||||
if err := h.User.UpdateNickname(h.currentUserID(c), nickname); err != nil {
|
||||
@@ -293,6 +331,20 @@ func (h *Handlers) APIUpdateProfile(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "昵称已更新", "user": userView})
|
||||
}
|
||||
|
||||
func (h *Handlers) APIUpdateSignature(c *gin.Context) {
|
||||
signature := c.PostForm("signature")
|
||||
if err := h.User.UpdateSignature(h.currentUserID(c), signature); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
user, _ := h.User.GetByID(h.currentUserID(c))
|
||||
var userView any
|
||||
if user != nil {
|
||||
userView = user.ToSelf()
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "签名已更新", "user": userView})
|
||||
}
|
||||
|
||||
func (h *Handlers) APIUpdatePassword(c *gin.Context) {
|
||||
oldPass := c.PostForm("old_password")
|
||||
newPass := c.PostForm("new_password")
|
||||
|
||||
32
handler/thumb.go
Normal file
32
handler/thumb.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"git.iioio.com/freefire/jiang13-forum/service"
|
||||
)
|
||||
|
||||
// ServeImageThumb 帖子图片缩略图(按需生成并缓存)
|
||||
// GET /media/thumb/posts/xxx.jpg → 最长边 1280 的 JPEG 预览
|
||||
func (h *Handlers) ServeImageThumb(c *gin.Context) {
|
||||
rel := strings.TrimPrefix(c.Param("filepath"), "/")
|
||||
uploadsRoot := filepath.Join(h.Cfg.DataDir, "uploads")
|
||||
thumbPath, err := service.EnsureUploadThumb(uploadsRoot, rel)
|
||||
if err != nil {
|
||||
// 生成失败时回退原图,避免正文裂图
|
||||
orig := filepath.Join(uploadsRoot, filepath.FromSlash(rel))
|
||||
if st, e := os.Stat(orig); e == nil && !st.IsDir() {
|
||||
c.Header("Cache-Control", "public, max-age=3600")
|
||||
c.File(orig)
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
c.Header("Cache-Control", "public, max-age=604800, immutable")
|
||||
c.File(thumbPath)
|
||||
}
|
||||
Reference in New Issue
Block a user