后台站点设计UIUX优化
This commit is contained in:
@@ -21,31 +21,41 @@ func (h *Handlers) PublicSettings(c *gin.Context) {
|
||||
|
||||
// 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"`
|
||||
AllowComments *bool `json:"allow_comments"`
|
||||
AllowMessages *bool `json:"allow_messages"`
|
||||
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"`
|
||||
PostLinkNewTab *bool `json:"post_link_new_tab"`
|
||||
AttachmentExtLimit *bool `json:"attachment_ext_limit"`
|
||||
AttachmentExts *[]string `json:"attachment_exts"`
|
||||
AttachmentMaxMB *int `json:"attachment_max_mb"`
|
||||
AttachmentMaxCount *int `json:"attachment_max_count"`
|
||||
ImageMaxMB *int `json:"image_max_mb"`
|
||||
BgSiteURL *string `json:"bg_site_url"`
|
||||
BgSiteMode *string `json:"bg_site_mode"`
|
||||
BgAdminURL *string `json:"bg_admin_url"`
|
||||
BgAdminMode *string `json:"bg_admin_mode"`
|
||||
TimelineGitImport *string `json:"timeline_git_import"` // 超管专用;不进公开 settings / WS 广播
|
||||
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"`
|
||||
AllowComments *bool `json:"allow_comments"`
|
||||
AllowMessages *bool `json:"allow_messages"`
|
||||
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"`
|
||||
PostLinkNewTab *bool `json:"post_link_new_tab"`
|
||||
AttachmentExtLimit *bool `json:"attachment_ext_limit"`
|
||||
AttachmentExts *[]string `json:"attachment_exts"`
|
||||
AttachmentMaxMB *int `json:"attachment_max_mb"`
|
||||
AttachmentMaxCount *int `json:"attachment_max_count"`
|
||||
ImageMaxMB *int `json:"image_max_mb"`
|
||||
BgSiteURL *string `json:"bg_site_url"`
|
||||
BgSiteMode *string `json:"bg_site_mode"`
|
||||
BgAdminURL *string `json:"bg_admin_url"`
|
||||
BgAdminMode *string `json:"bg_admin_mode"`
|
||||
SiteWordmark *string `json:"site_wordmark"`
|
||||
SiteSlogan *string `json:"site_slogan"`
|
||||
SiteKeywords *[]string `json:"site_keywords"`
|
||||
LogoLightURL *string `json:"logo_light_url"`
|
||||
LogoDarkURL *string `json:"logo_dark_url"`
|
||||
FaviconURL *string `json:"favicon_url"`
|
||||
BrandMark *string `json:"brand_mark"`
|
||||
BrandLogoSize *string `json:"brand_logo_size"`
|
||||
BrandLogoFit *string `json:"brand_logo_fit"`
|
||||
FooterLinks *[]service.FooterLink `json:"footer_links"`
|
||||
TimelineGitImport *string `json:"timeline_git_import"` // 超管专用;不进公开 settings / WS 广播
|
||||
}
|
||||
|
||||
func settingsPayload(saved service.PublicSiteSettings) gin.H {
|
||||
@@ -74,6 +84,16 @@ func settingsPayload(saved service.PublicSiteSettings) gin.H {
|
||||
"bg_site_mode": saved.BgSiteMode,
|
||||
"bg_admin_url": saved.BgAdminURL,
|
||||
"bg_admin_mode": saved.BgAdminMode,
|
||||
"site_wordmark": saved.SiteWordmark,
|
||||
"site_slogan": saved.SiteSlogan,
|
||||
"site_keywords": saved.SiteKeywords,
|
||||
"logo_light_url": saved.LogoLightURL,
|
||||
"logo_dark_url": saved.LogoDarkURL,
|
||||
"favicon_url": saved.FaviconURL,
|
||||
"brand_mark": saved.BrandMark,
|
||||
"brand_logo_size": saved.BrandLogoSize,
|
||||
"brand_logo_fit": saved.BrandLogoFit,
|
||||
"footer_links": saved.FooterLinks,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +106,11 @@ func (req *updateSettingsRequest) hasAny() bool {
|
||||
req.AttachmentExtLimit != nil || req.AttachmentExts != nil || req.AttachmentMaxMB != nil ||
|
||||
req.AttachmentMaxCount != nil || req.ImageMaxMB != nil ||
|
||||
req.BgSiteURL != nil || req.BgSiteMode != nil ||
|
||||
req.BgAdminURL != nil || req.BgAdminMode != nil || req.TimelineGitImport != nil
|
||||
req.BgAdminURL != nil || req.BgAdminMode != nil ||
|
||||
req.SiteWordmark != nil || req.SiteSlogan != nil || req.SiteKeywords != nil ||
|
||||
req.LogoLightURL != nil || req.LogoDarkURL != nil || req.FaviconURL != nil ||
|
||||
req.BrandMark != nil || req.BrandLogoSize != nil || req.BrandLogoFit != nil ||
|
||||
req.FooterLinks != nil || req.TimelineGitImport != nil
|
||||
}
|
||||
|
||||
// AdminGetSettings 超管读取站点设置(含 timeline_git_import,不进公开 /api/settings)
|
||||
@@ -306,6 +330,94 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.SiteWordmark != nil {
|
||||
if err := h.Setting.SetSiteWordmark(*req.SiteWordmark); err != nil {
|
||||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "字标过长(最多 16 字)"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.SiteSlogan != nil {
|
||||
if err := h.Setting.SetSiteSlogan(*req.SiteSlogan); err != nil {
|
||||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "标语过长(最多 32 字)"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.SiteKeywords != nil {
|
||||
if err := h.Setting.SetSiteKeywords(*req.SiteKeywords); err != nil {
|
||||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "关键词过多或单个过长(最多 16 个,每个 20 字)"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.LogoLightURL != nil {
|
||||
if err := h.applyBrandURL(service.BrandSlotLight, *req.LogoLightURL); err != nil {
|
||||
writeBrandSettingError(c, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.LogoDarkURL != nil {
|
||||
if err := h.applyBrandURL(service.BrandSlotDark, *req.LogoDarkURL); err != nil {
|
||||
writeBrandSettingError(c, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.FaviconURL != nil {
|
||||
if err := h.applyBrandURL(service.BrandSlotFavicon, *req.FaviconURL); err != nil {
|
||||
writeBrandSettingError(c, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.BrandMark != nil {
|
||||
if err := h.Setting.SetBrandMark(*req.BrandMark); 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.BrandLogoFit != nil {
|
||||
if err := h.Setting.SetBrandLogoFit(*req.BrandLogoFit); 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.BrandLogoSize != nil {
|
||||
if err := h.Setting.SetBrandLogoSize(*req.BrandLogoSize); 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.FooterLinks != nil {
|
||||
if err := h.Setting.SetFooterLinks(*req.FooterLinks); err != nil {
|
||||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "页脚链接无效(最多 8 条,文案 32 字,地址须为站内路径或 http(s))"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var savedAdapter string
|
||||
if req.TimelineGitImport != nil {
|
||||
@@ -378,3 +490,61 @@ func (h *Handlers) applyBgURL(surface, url string) error {
|
||||
h.Upload.RemoveBackgroundIfUnused(oldSite, u, oldAdmin)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBrandSettingError(c *gin.Context, err error) {
|
||||
if errors.Is(err, service.ErrInvalidSiteSetting) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "品牌图地址无效"})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, service.ErrBrandFileMissing) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
}
|
||||
|
||||
// applyBrandURL 写入对应槽位,并删除不再被引用的旧文件
|
||||
func (h *Handlers) applyBrandURL(slot, url string) error {
|
||||
u, ok := service.NormalizeBrandURL(slot, url)
|
||||
if !ok {
|
||||
return service.ErrInvalidSiteSetting
|
||||
}
|
||||
if u != "" && !h.Upload.BrandFileExists(u) {
|
||||
return service.ErrBrandFileMissing
|
||||
}
|
||||
oldLight, err := h.Setting.LogoLightURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldDark, err := h.Setting.LogoDarkURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldFav, err := h.Setting.FaviconURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var old string
|
||||
switch slot {
|
||||
case service.BrandSlotDark:
|
||||
old = oldDark
|
||||
if err := h.Setting.SetLogoDarkURL(u); err != nil {
|
||||
return err
|
||||
}
|
||||
oldDark = u
|
||||
case service.BrandSlotFavicon:
|
||||
old = oldFav
|
||||
if err := h.Setting.SetFaviconURL(u); err != nil {
|
||||
return err
|
||||
}
|
||||
oldFav = u
|
||||
default:
|
||||
old = oldLight
|
||||
if err := h.Setting.SetLogoLightURL(u); err != nil {
|
||||
return err
|
||||
}
|
||||
oldLight = u
|
||||
}
|
||||
h.Upload.RemoveBrandIfUnused(old, oldLight, oldDark, oldFav)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user