package model import ( "database/sql/driver" "time" "github.com/bytedance/sonic" ) // H5PopupConfiguration 是 H5 运营弹窗全局配置的 PostgreSQL 持久化事实。 // 配置只决定后续投放:启停与有效期不删除行,停用走 Enabled 置 0; // Version 是配置版本而非乐观锁,更新事务内递增并参与频率去重键,旧版本通知保留原快照不被改写。 // 范围四维统一用 JSONB 字符串数组:空数组表示该维度未配置即全量,已配置而资产该维度无值时不命中。 type H5PopupConfiguration struct { ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` Title string `gorm:"column:title;type:varchar(100);not null" json:"title"` Content string `gorm:"column:content;type:varchar(2000);not null" json:"content"` Pages StringJSONBArray `gorm:"column:pages;type:jsonb;not null;default:'[]'" json:"pages"` ShopIDs StringJSONBArray `gorm:"column:shop_ids;type:jsonb;not null;default:'[]'" json:"shop_ids"` DeviceTypes StringJSONBArray `gorm:"column:device_types;type:jsonb;not null;default:'[]'" json:"device_types"` CardTypes StringJSONBArray `gorm:"column:card_types;type:jsonb;not null;default:'[]'" json:"card_types"` Priority int `gorm:"column:priority;type:integer;not null;default:0" json:"priority"` Frequency string `gorm:"column:frequency;type:varchar(20);not null;default:'once'" json:"frequency"` ActionType string `gorm:"column:action_type;type:varchar(40);not null;default:''" json:"action_type"` Enabled int `gorm:"column:enabled;type:smallint;not null;default:0" json:"enabled"` StartsAt time.Time `gorm:"column:starts_at;type:timestamptz;not null" json:"starts_at"` EndsAt time.Time `gorm:"column:ends_at;type:timestamptz;not null" json:"ends_at"` Version int64 `gorm:"column:version;type:bigint;not null;default:1" json:"version"` BaseModel `gorm:"embedded"` CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"` UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"` } // TableName 返回 H5 运营弹窗配置表名。 func (H5PopupConfiguration) TableName() string { return "tb_h5_popup_configuration" } // NotificationPopupSnapshot 是弹窗投放通知冻结的投放快照,作为可空 JSONB 写入 tb_notification。 // 只承载配置标识与受控动作,不含任何 URL 或前端路由;风险换卡弹窗没有配置,ConfigID 与 ConfigVersion 为 0。 type NotificationPopupSnapshot struct { ConfigID uint `json:"config_id"` ConfigVersion int64 `json:"config_version"` AssetType string `json:"asset_type"` AssetID uint `json:"asset_id"` ActionType string `json:"action_type"` } // Value 将弹窗快照序列化为 JSONB;nil 接收者写入 NULL,供非弹窗通知保持该列为空。 func (s *NotificationPopupSnapshot) Value() (driver.Value, error) { if s == nil { return nil, nil } return sonic.Marshal(s) } // Scan 从 JSONB 读取弹窗快照;数据库 NULL 时清空快照。 func (s *NotificationPopupSnapshot) Scan(value any) error { if value == nil { *s = NotificationPopupSnapshot{} return nil } data, ok := value.([]byte) if !ok { *s = NotificationPopupSnapshot{} return nil } return sonic.Unmarshal(data, s) }