package database import ( "database/sql/driver" "encoding/json" "fmt" "time" ) // StringSlice 表示以 JSON 序列化形式存入 MySQL TEXT/JSON 列的字符串切片。 type StringSlice []string func (s StringSlice) Value() (driver.Value, error) { if s == nil { return "[]", nil } b, err := json.Marshal(s) return string(b), err } func (s *StringSlice) Scan(src any) error { var raw []byte switch v := src.(type) { case string: raw = []byte(v) case []byte: raw = v default: return fmt.Errorf("StringSlice: unsupported type %T", src) } return json.Unmarshal(raw, s) } // ─── 商品 ───────────────────────────────────────────────────────────────────── // ProductRow 为 `products` 表的 GORM 模型。 type ProductRow struct { ID string `gorm:"primaryKey;size:36"` Name string `gorm:"size:255;not null"` Price float64 `gorm:"not null;default:0"` DiscountPrice float64 `gorm:"default:0"` Tags StringSlice `gorm:"type:json"` CoverURL string `gorm:"size:500"` ScreenshotURLs StringSlice `gorm:"type:json"` VerificationURL string `gorm:"size:500;default:''"` Description string `gorm:"type:text"` Active bool `gorm:"default:true;index"` RequireLogin bool `gorm:"default:false"` MaxPerAccount int `gorm:"default:0"` TotalSold int `gorm:"default:0"` ViewCount int `gorm:"default:0"` DeliveryMode string `gorm:"size:20;default:'auto'"` // FulfillmentType: card=卡密库存 / fixed=固定内容(不限库存,内容见 FixedContent) FulfillmentType string `gorm:"size:16;default:card;index"` FixedContent string `gorm:"type:text"` ShowNote bool `gorm:"default:true"` ShowContact bool `gorm:"default:true"` // PaymentQrURLs JSON:萌芽支付等多张收款码图片链接。 PaymentQrURLs StringSlice `gorm:"column:payment_qr_urls;type:json"` CreatedAt time.Time `gorm:"index"` } func (ProductRow) TableName() string { return "products" } // ProductCodeRow 单条卡密一行,按商品维度存储。 type ProductCodeRow struct { ID uint `gorm:"primaryKey;autoIncrement"` ProductID string `gorm:"size:36;not null;index"` Code string `gorm:"type:text;not null"` } func (ProductCodeRow) TableName() string { return "product_codes" } // ─── 订单 ───────────────────────────────────────────────────────────────────── type OrderRow struct { ID string `gorm:"primaryKey;size:36"` ProductID string `gorm:"size:36;not null;index"` ProductName string `gorm:"size:255;not null"` UserAccount string `gorm:"size:255;index"` UserName string `gorm:"size:255"` Quantity int `gorm:"not null;default:1"` DeliveredCodes StringSlice `gorm:"type:json"` Status string `gorm:"size:20;not null;default:'pending';index"` DeliveryMode string `gorm:"size:20;default:'auto'"` Note string `gorm:"type:text"` ContactPhone string `gorm:"size:50"` ContactEmail string `gorm:"size:255"` NotifyEmail string `gorm:"size:255"` // PaymentMethod 如 mengya;历史订单或免费单可能为空。 PaymentMethod string `gorm:"size:32;default:'';index"` // PaymentExpectedTotal 待支付时应付快照(元),用于 Webhook 金额核对。 PaymentExpectedTotal float64 `gorm:"default:0"` // PaymentExpiresAt 待支付截止时间;非待支付订单为 NULL。 PaymentExpiresAt *time.Time `gorm:"index"` CreatedAt time.Time } func (OrderRow) TableName() string { return "orders" } // ─── 站点设置 ───────────────────────────────────────────────────────────────── // SiteSettingRow 站点级键值配置。 type SiteSettingRow struct { Key string `gorm:"primaryKey;size:64"` Value string `gorm:"type:text"` } func (SiteSettingRow) TableName() string { return "site_settings" } // ─── 收藏夹 ─────────────────────────────────────────────────────────────────── type WishlistRow struct { ID uint `gorm:"primaryKey;autoIncrement"` AccountID string `gorm:"size:255;not null;index:idx_wishlist,unique"` ProductID string `gorm:"size:36;not null;index:idx_wishlist,unique"` } func (WishlistRow) TableName() string { return "wishlists" } // ─── 聊天消息 ───────────────────────────────────────────────────────────────── type ChatMessageRow struct { ID string `gorm:"primaryKey;size:36"` AccountID string `gorm:"size:255;not null;index"` AccountName string `gorm:"size:255"` Content string `gorm:"type:text;not null"` SentAt time.Time `gorm:"not null"` FromAdmin bool `gorm:"default:false"` } func (ChatMessageRow) TableName() string { return "chat_messages" }