221 lines
5.2 KiB
Go
221 lines
5.2 KiB
Go
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})
|
||
}
|