296 lines
7.2 KiB
Go
296 lines
7.2 KiB
Go
package hotelwelcome
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
"unicode/utf8"
|
||
|
||
"hunliji-api/models"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
var (
|
||
db *gorm.DB
|
||
requireAdmin func(*gin.Context) bool
|
||
)
|
||
|
||
var allowedTemplates = map[string]bool{
|
||
"banner-bottom": true,
|
||
"banner-top": true,
|
||
"banner-center": true,
|
||
"banner-names": true,
|
||
"banner-lower-third": true,
|
||
"banner-split-names": true,
|
||
"banner-frame-bottom": true,
|
||
"banner-minimal": true,
|
||
"art-welcome-brush": true,
|
||
"art-love-life": true,
|
||
"art-gaobai": true,
|
||
"art-married": true,
|
||
"art-hand-love": true,
|
||
"art-like-you": true,
|
||
"art-give-home": true,
|
||
"art-xi-welcome": true,
|
||
"art-wujia": true,
|
||
"art-tianci": true,
|
||
"art-tianzuo": true,
|
||
"art-welcome-v": true,
|
||
"art-longest": true,
|
||
"art-just-love": true,
|
||
"custom": true,
|
||
// 旧 key 兼容
|
||
"banner-zh": true,
|
||
"banner-upper-third": true,
|
||
"banner-mid-band": true,
|
||
"banner-left-stack": true,
|
||
"banner-right-stack": true,
|
||
"banner-vertical-left": true,
|
||
"banner-vertical-right": true,
|
||
"banner-hero-name": true,
|
||
"banner-date-focus": true,
|
||
"banner-welcome-en": true,
|
||
"banner-xi-corner": true,
|
||
"banner-top-bottom": true,
|
||
"welcome-bottom": true,
|
||
"welcome-top": true,
|
||
"welcome-left": true,
|
||
"welcome-right": true,
|
||
"welcome-center": true,
|
||
}
|
||
|
||
// Register 酒店迎宾海报 CRUD(均需管理员)
|
||
func Register(api *gin.RouterGroup, database *gorm.DB, adminGuard func(*gin.Context) bool) {
|
||
db = database
|
||
requireAdmin = adminGuard
|
||
api.GET("/hotel-welcome/list", handleList)
|
||
api.GET("/hotel-welcome/:id", handleDetail)
|
||
api.POST("/hotel-welcome", handleCreate)
|
||
api.PUT("/hotel-welcome/:id", handleUpdate)
|
||
api.DELETE("/hotel-welcome/:id", handleDelete)
|
||
}
|
||
|
||
func emptyConfigJSON() string {
|
||
return `{"texts":[]}`
|
||
}
|
||
|
||
func normalizeConfig(raw string) string {
|
||
raw = strings.TrimSpace(raw)
|
||
if raw == "" {
|
||
return emptyConfigJSON()
|
||
}
|
||
var m map[string]interface{}
|
||
if err := json.Unmarshal([]byte(raw), &m); err != nil {
|
||
return emptyConfigJSON()
|
||
}
|
||
if _, ok := m["texts"]; !ok {
|
||
m["texts"] = []interface{}{}
|
||
}
|
||
b, err := json.Marshal(m)
|
||
if err != nil {
|
||
return emptyConfigJSON()
|
||
}
|
||
return string(b)
|
||
}
|
||
|
||
func normalizeTemplate(raw string) string {
|
||
t := strings.TrimSpace(raw)
|
||
if allowedTemplates[t] {
|
||
return t
|
||
}
|
||
return "banner-bottom"
|
||
}
|
||
|
||
func parseID(c *gin.Context) (uint64, bool) {
|
||
id, err := strconv.ParseUint(strings.TrimSpace(c.Param("id")), 10, 64)
|
||
if err != nil || id == 0 {
|
||
c.JSON(400, gin.H{"error": "无效 ID"})
|
||
return 0, false
|
||
}
|
||
return id, true
|
||
}
|
||
|
||
// listItem 列表不返回原图 URL,减轻压力
|
||
type listItem struct {
|
||
ID uint `json:"id"`
|
||
Name string `json:"name"`
|
||
Template string `json:"template"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
func handleList(c *gin.Context) {
|
||
if !requireAdmin(c) {
|
||
return
|
||
}
|
||
var rows []models.HotelWelcomePoster
|
||
if err := db.Select("id", "name", "template", "created_at", "updated_at").
|
||
Order("updated_at desc, id desc").
|
||
Find(&rows).Error; err != nil {
|
||
c.JSON(500, gin.H{"error": "查询失败"})
|
||
return
|
||
}
|
||
list := make([]listItem, 0, len(rows))
|
||
for _, r := range rows {
|
||
list = append(list, listItem{
|
||
ID: r.ID,
|
||
Name: r.Name,
|
||
Template: r.Template,
|
||
CreatedAt: r.CreatedAt,
|
||
UpdatedAt: r.UpdatedAt,
|
||
})
|
||
}
|
||
c.JSON(200, gin.H{"code": 200, "data": gin.H{"list": list, "count": len(list)}})
|
||
}
|
||
|
||
func handleDetail(c *gin.Context) {
|
||
if !requireAdmin(c) {
|
||
return
|
||
}
|
||
id, ok := parseID(c)
|
||
if !ok {
|
||
return
|
||
}
|
||
var item models.HotelWelcomePoster
|
||
if err := db.First(&item, id).Error; err != nil {
|
||
c.JSON(404, gin.H{"error": "记录不存在"})
|
||
return
|
||
}
|
||
item.ConfigData = normalizeConfig(item.ConfigData)
|
||
item.Template = normalizeTemplate(item.Template)
|
||
c.JSON(200, gin.H{"code": 200, "data": item})
|
||
}
|
||
|
||
func handleCreate(c *gin.Context) {
|
||
if !requireAdmin(c) {
|
||
return
|
||
}
|
||
var body struct {
|
||
Name string `json:"name"`
|
||
ImageURL string `json:"image_url"`
|
||
Template string `json:"template"`
|
||
ConfigData json.RawMessage `json:"config_data"`
|
||
}
|
||
if err := c.ShouldBindJSON(&body); err != nil {
|
||
c.JSON(400, gin.H{"error": "参数错误"})
|
||
return
|
||
}
|
||
name := strings.TrimSpace(body.Name)
|
||
imageURL := strings.TrimSpace(body.ImageURL)
|
||
if name == "" {
|
||
c.JSON(400, gin.H{"error": "请填写图片名称"})
|
||
return
|
||
}
|
||
if utf8.RuneCountInString(name) > 100 {
|
||
c.JSON(400, gin.H{"error": "图片名称过长"})
|
||
return
|
||
}
|
||
if imageURL == "" {
|
||
c.JSON(400, gin.H{"error": "请上传原图"})
|
||
return
|
||
}
|
||
if utf8.RuneCountInString(imageURL) > 768 {
|
||
c.JSON(400, gin.H{"error": "图片地址过长"})
|
||
return
|
||
}
|
||
cfg := emptyConfigJSON()
|
||
if len(body.ConfigData) > 0 {
|
||
cfg = normalizeConfig(string(body.ConfigData))
|
||
}
|
||
item := models.HotelWelcomePoster{
|
||
Name: name,
|
||
ImageURL: imageURL,
|
||
Template: normalizeTemplate(body.Template),
|
||
ConfigData: cfg,
|
||
}
|
||
if err := db.Create(&item).Error; err != nil {
|
||
c.JSON(500, gin.H{"error": "创建失败"})
|
||
return
|
||
}
|
||
c.JSON(200, gin.H{"code": 200, "msg": "已创建", "data": item})
|
||
}
|
||
|
||
func handleUpdate(c *gin.Context) {
|
||
if !requireAdmin(c) {
|
||
return
|
||
}
|
||
id, ok := parseID(c)
|
||
if !ok {
|
||
return
|
||
}
|
||
var body struct {
|
||
Name *string `json:"name"`
|
||
ImageURL *string `json:"image_url"`
|
||
Template *string `json:"template"`
|
||
ConfigData json.RawMessage `json:"config_data"`
|
||
}
|
||
if err := c.ShouldBindJSON(&body); err != nil {
|
||
c.JSON(400, gin.H{"error": "参数错误"})
|
||
return
|
||
}
|
||
var item models.HotelWelcomePoster
|
||
if err := db.First(&item, id).Error; err != nil {
|
||
c.JSON(404, gin.H{"error": "记录不存在"})
|
||
return
|
||
}
|
||
if body.Name != nil {
|
||
name := strings.TrimSpace(*body.Name)
|
||
if name == "" {
|
||
c.JSON(400, gin.H{"error": "请填写图片名称"})
|
||
return
|
||
}
|
||
if utf8.RuneCountInString(name) > 100 {
|
||
c.JSON(400, gin.H{"error": "图片名称过长"})
|
||
return
|
||
}
|
||
item.Name = name
|
||
}
|
||
if body.ImageURL != nil {
|
||
imageURL := strings.TrimSpace(*body.ImageURL)
|
||
if imageURL == "" {
|
||
c.JSON(400, gin.H{"error": "请上传原图"})
|
||
return
|
||
}
|
||
if utf8.RuneCountInString(imageURL) > 768 {
|
||
c.JSON(400, gin.H{"error": "图片地址过长"})
|
||
return
|
||
}
|
||
item.ImageURL = imageURL
|
||
}
|
||
if body.Template != nil {
|
||
item.Template = normalizeTemplate(*body.Template)
|
||
}
|
||
if len(body.ConfigData) > 0 {
|
||
item.ConfigData = normalizeConfig(string(body.ConfigData))
|
||
}
|
||
if err := db.Save(&item).Error; err != nil {
|
||
c.JSON(500, gin.H{"error": "保存失败"})
|
||
return
|
||
}
|
||
item.ConfigData = normalizeConfig(item.ConfigData)
|
||
c.JSON(200, gin.H{"code": 200, "msg": "已保存", "data": item})
|
||
}
|
||
|
||
func handleDelete(c *gin.Context) {
|
||
if !requireAdmin(c) {
|
||
return
|
||
}
|
||
id, ok := parseID(c)
|
||
if !ok {
|
||
return
|
||
}
|
||
res := db.Delete(&models.HotelWelcomePoster{}, id)
|
||
if res.Error != nil {
|
||
c.JSON(500, gin.H{"error": "删除失败"})
|
||
return
|
||
}
|
||
if res.RowsAffected == 0 {
|
||
c.JSON(404, gin.H{"error": "记录不存在"})
|
||
return
|
||
}
|
||
c.JSON(200, gin.H{"code": 200, "msg": "已删除"})
|
||
}
|