Files
jiang13-bbs/backend/handler/setting.go
freefire 2b27703e6c feat(settings): 站点界面动画总开关与子开关
管理后台可关全站动画,并细调代码折叠、平滑滚动、装饰入场;统一 lib/motion,尊重系统减少动态效果。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 06:59:26 +08:00

179 lines
6.1 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 handler
import (
"errors"
"net/http"
"github.com/freefire/jiang13-bbs/realtime"
"github.com/freefire/jiang13-bbs/service"
"github.com/gin-gonic/gin"
)
// GET /api/settings
func (h *Handlers) PublicSettings(c *gin.Context) {
s, err := h.Setting.Public()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取站点设置失败"})
return
}
c.JSON(http.StatusOK, s)
}
// updateSettingsRequest 字段均为可选指针:只更新请求里出现的项,避免外观页覆盖其它设置
type updateSettingsRequest struct {
Accent *string `json:"accent"`
TrustReviewedPublish *bool `json:"trust_reviewed_publish"`
SiteName *string `json:"site_name"`
SiteDescription *string `json:"site_description"`
AllowRegister *bool `json:"allow_register"`
PostCooldownHours *int `json:"post_cooldown_hours"`
CodeBlockAutoFold *bool `json:"code_block_auto_fold"`
CodeBlockFoldLines *int `json:"code_block_fold_lines"`
UIAnimations *bool `json:"ui_animations"`
AnimCodeFold *bool `json:"anim_code_fold"`
AnimSmoothScroll *bool `json:"anim_smooth_scroll"`
AnimChrome *bool `json:"anim_chrome"`
}
func settingsPayload(saved service.PublicSiteSettings) gin.H {
return gin.H{
"accent": saved.Accent,
"trust_reviewed_publish": saved.TrustReviewedPublish,
"site_name": saved.SiteName,
"site_description": saved.SiteDescription,
"allow_register": saved.AllowRegister,
"post_cooldown_hours": saved.PostCooldownHours,
"code_block_auto_fold": saved.CodeBlockAutoFold,
"code_block_fold_lines": saved.CodeBlockFoldLines,
"ui_animations": saved.UIAnimations,
"anim_code_fold": saved.AnimCodeFold,
"anim_smooth_scroll": saved.AnimSmoothScroll,
"anim_chrome": saved.AnimChrome,
}
}
// PUT /api/admin/settings
func (h *Handlers) UpdateSettings(c *gin.Context) {
var req updateSettingsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
return
}
if req.Accent == nil && req.TrustReviewedPublish == nil && req.SiteName == nil &&
req.SiteDescription == nil && req.AllowRegister == nil &&
req.PostCooldownHours == nil && req.CodeBlockAutoFold == nil && req.CodeBlockFoldLines == nil &&
req.UIAnimations == nil && req.AnimCodeFold == nil && req.AnimSmoothScroll == nil &&
req.AnimChrome == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供任何可更新的设置项"})
return
}
if req.Accent != nil {
if err := h.Setting.SetAccent(*req.Accent); err != nil {
if errors.Is(err, service.ErrInvalidAccent) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.TrustReviewedPublish != nil {
if err := h.Setting.SetTrustReviewedPublish(*req.TrustReviewedPublish); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.SiteName != nil {
if err := h.Setting.SetSiteName(*req.SiteName); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": "站点名称过长或无效"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.SiteDescription != nil {
if err := h.Setting.SetSiteDescription(*req.SiteDescription); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": "站点简介过长"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.AllowRegister != nil {
if err := h.Setting.SetAllowRegister(*req.AllowRegister); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.PostCooldownHours != nil {
if err := h.Setting.SetPostCooldownHours(*req.PostCooldownHours); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": "冷静期须为 0–168 小时"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.CodeBlockAutoFold != nil {
if err := h.Setting.SetCodeBlockAutoFold(*req.CodeBlockAutoFold); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.CodeBlockFoldLines != nil {
if err := h.Setting.SetCodeBlockFoldLines(*req.CodeBlockFoldLines); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": "折叠行数须为 0–100"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.UIAnimations != nil {
if err := h.Setting.SetUIAnimations(*req.UIAnimations); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.AnimCodeFold != nil {
if err := h.Setting.SetAnimCodeFold(*req.AnimCodeFold); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.AnimSmoothScroll != nil {
if err := h.Setting.SetAnimSmoothScroll(*req.AnimSmoothScroll); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.AnimChrome != nil {
if err := h.Setting.SetAnimChrome(*req.AnimChrome); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
saved, err := h.Setting.Public()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取站点设置失败"})
return
}
payload := settingsPayload(saved)
h.Hub.BroadcastAll(realtime.Envelope{
Type: realtime.EventSettingsChanged,
Data: payload,
})
out := settingsPayload(saved)
out["ok"] = true
c.JSON(http.StatusOK, out)
}