Files
hunli/hunliji-api/posterconfig/poster.go
2026-08-03 16:00:13 +08:00

221 lines
5.2 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 posterconfig
import (
"encoding/json"
"strings"
"hunliji-api/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
var (
db *gorm.DB
requireAdmin func(*gin.Context) bool
)
// Register 挂载海报配置路由GET 公开POST 需管理员
func Register(api *gin.RouterGroup, database *gorm.DB, adminGuard func(*gin.Context) bool) {
db = database
requireAdmin = adminGuard
api.GET("/poster/config", handleGetPosterConfig)
api.POST("/poster/config", handleSavePosterConfig)
}
// resolveSide 返回 "1"(男方)、"2"(女方)或 "3"(回门宴);无法识别返回空
func resolveSide(raw string) string {
v := strings.ToLower(strings.TrimSpace(raw))
switch v {
case "1", "male", "n", "m", "groom":
return "1"
case "2", "female", "nv", "f", "bride":
return "2"
case "3", "hm", "hmy", "return", "huimen":
return "3"
default:
return ""
}
}
// resolveLayout 返回 "1"(竖版)或 "2"(横版);无法识别返回空
func resolveLayout(raw string) string {
v := strings.ToLower(strings.TrimSpace(raw))
switch v {
case "1", "portrait", "v", "shu", "竖版":
return "1"
case "2", "landscape", "h", "heng", "横版":
return "2"
default:
return ""
}
}
func emptyObj() map[string]interface{} {
return map[string]interface{}{}
}
func asObject(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok {
return m
}
return emptyObj()
}
func takeSide(raw map[string]interface{}, keys ...string) map[string]interface{} {
for _, k := range keys {
if m := asObject(raw[k]); len(m) > 0 {
return m
}
}
return emptyObj()
}
func isLegacyFlat(m map[string]interface{}) bool {
if m == nil {
return false
}
for _, k := range []string{"1", "2", "3", "male", "female", "hm"} {
if _, ok := m[k]; ok {
return false
}
}
for _, k := range []string{"title", "lines", "heroImg", "sonName", "template"} {
if _, ok := m[k]; ok {
return true
}
}
return false
}
func isFlatPosterConfig(m map[string]interface{}) bool {
if m == nil || len(m) == 0 {
return false
}
// 已有嵌套 layout
for _, k := range []string{"1", "2"} {
if child := asObject(m[k]); len(child) > 0 {
for _, fk := range []string{"title", "lines", "heroImg", "sonName", "template", "groomName"} {
if _, ok := child[fk]; ok {
return false
}
}
}
}
for _, k := range []string{"title", "lines", "heroImg", "sonName", "template", "groomName", "mobileLayout", "pageTitle"} {
if _, ok := m[k]; ok {
return true
}
}
return false
}
func emptyLayouts() map[string]interface{} {
return map[string]interface{}{
"1": emptyObj(),
"2": emptyObj(),
}
}
// normalizeSideLayouts 将单侧归一为 { "1": 竖版, "2": 横版 }
func normalizeSideLayouts(raw map[string]interface{}) map[string]interface{} {
out := emptyLayouts()
if raw == nil {
return out
}
if isFlatPosterConfig(raw) {
out["1"] = raw
return out
}
if m := asObject(raw["1"]); len(m) > 0 {
out["1"] = m
}
if m := asObject(raw["2"]); len(m) > 0 {
out["2"] = m
}
return out
}
// normalizeBundle 统一为 { "1"|"2"|"3": { "1"|"2": cfg } }
func normalizeBundle(raw map[string]interface{}) map[string]interface{} {
if raw == nil {
raw = emptyObj()
}
out := map[string]interface{}{
"1": emptyLayouts(),
"2": emptyLayouts(),
"3": emptyLayouts(),
}
if isLegacyFlat(raw) {
out["1"] = normalizeSideLayouts(raw)
return out
}
if m := takeSide(raw, "1", "male"); len(m) > 0 {
out["1"] = normalizeSideLayouts(m)
}
if f := takeSide(raw, "2", "female"); len(f) > 0 {
out["2"] = normalizeSideLayouts(f)
}
if h := takeSide(raw, "3", "hm", "hmy"); len(h) > 0 {
out["3"] = normalizeSideLayouts(h)
}
return out
}
func loadBundle() map[string]interface{} {
var config models.PosterConfig
if err := db.First(&config, 1).Error; err != nil {
return normalizeBundle(nil)
}
raw := strings.TrimSpace(config.ConfigData)
if raw == "" {
raw = "{}"
}
var parsed map[string]interface{}
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return normalizeBundle(nil)
}
return normalizeBundle(parsed)
}
func handleGetPosterConfig(c *gin.Context) {
bundle := loadBundle()
side := resolveSide(c.Query("side"))
layout := resolveLayout(c.Query("layout"))
if side != "" && layout != "" {
sideObj := asObject(bundle[side])
c.JSON(200, gin.H{"code": 200, "data": asObject(sideObj[layout])})
return
}
if side != "" {
c.JSON(200, gin.H{"code": 200, "data": bundle[side]})
return
}
c.JSON(200, gin.H{"code": 200, "data": bundle})
}
func handleSavePosterConfig(c *gin.Context) {
if !requireAdmin(c) {
return
}
var rawBody map[string]interface{}
if err := c.BindJSON(&rawBody); err != nil {
c.JSON(400, gin.H{"error": "无效的JSON数据"})
return
}
bundle := normalizeBundle(rawBody)
jsonBytes, err := json.Marshal(bundle)
if err != nil {
c.JSON(400, gin.H{"error": "无效的JSON数据"})
return
}
var config models.PosterConfig
db.Attrs(models.PosterConfig{ConfigData: "{}"}).FirstOrCreate(&config, models.PosterConfig{ID: 1})
config.ConfigData = string(jsonBytes)
if err := db.Save(&config).Error; err != nil {
c.JSON(500, gin.H{"error": "海报配置保存失败"})
return
}
c.JSON(200, gin.H{"code": 200, "msg": "海报配置保存成功", "data": bundle})
}