package models import ( "encoding/json" "fmt" "math/rand" "time" "database/sql/driver" "gorm.io/gorm" ) // ============================================================================= // LaserCardTemplate — 镭射卡预设模板表 // ============================================================================= // LaserCardTemplate 镭射卡预设模板 type LaserCardTemplate struct { ID int64 `gorm:"primaryKey;autoIncrement;column:id"` TemplateCode string `gorm:"type:varchar(64);not null;uniqueIndex:uk_lct_code_version;column:template_code"` Name string `gorm:"type:varchar(100);not null;column:name"` Description *string `gorm:"type:text;column:description"` Status string `gorm:"type:varchar(20);not null;default:'published';index:idx_lct_status_star;column:status"` Version int `gorm:"not null;default:1;uniqueIndex:uk_lct_code_version;column:version"` ThumbnailOssKey *string `gorm:"type:varchar(255);column:thumbnail_oss_key"` BackdropOptions LaserCardBackdropOptions `gorm:"type:jsonb;not null;default:'[]';column:backdrop_options"` RenderConfig json.RawMessage `gorm:"type:jsonb;not null;default:'{}';column:render_config"` EngineMinVersion string `gorm:"type:varchar(32);not null;default:'compositor-1.0.0';column:engine_min_version"` SortOrder int `gorm:"not null;default:0;column:sort_order"` StarID int64 `gorm:"not null;default:0;index:idx_lct_status_star;column:star_id"` CreatedBy int64 `gorm:"not null;default:0;column:created_by"` CreatedAt int64 `gorm:"not null;column:created_at"` UpdatedAt int64 `gorm:"not null;column:updated_at"` DeletedAt *int64 `gorm:"index;column:deleted_at"` } func (LaserCardTemplate) TableName() string { return "laser_card_templates" } func (t *LaserCardTemplate) BeforeCreate(tx *gorm.DB) error { now := time.Now().UnixMilli() t.CreatedAt = now t.UpdatedAt = now return nil } func (t *LaserCardTemplate) BeforeUpdate(tx *gorm.DB) error { t.UpdatedAt = time.Now().UnixMilli() return nil } // LaserCardBackdropOption 底纹选项 type LaserCardBackdropOption struct { ID string `json:"id"` Label string `json:"label"` OssKey string `json:"oss_key"` } // LaserCardBackdropOptions 底纹选项 JSON 数组 type LaserCardBackdropOptions []LaserCardBackdropOption // Scan 实现 sql.Scanner func (b *LaserCardBackdropOptions) Scan(value interface{}) error { if value == nil { *b = LaserCardBackdropOptions{} return nil } bytes, ok := value.([]byte) if !ok { return fmt.Errorf("failed to scan LaserCardBackdropOptions: %v", value) } return json.Unmarshal(bytes, b) } // Value 实现 driver.Valuer func (b LaserCardBackdropOptions) Value() (driver.Value, error) { if b == nil { return "[]", nil } return json.Marshal(b) } // 模板状态常量 const ( LaserCardTemplateStatusPublished = "published" LaserCardTemplateStatusArchived = "archived" ) // ============================================================================= // LaserCardInstance — 镭射卡业务实例表 // ============================================================================= // LaserCardInstance 镭射卡业务实例 type LaserCardInstance struct { ID int64 `gorm:"primaryKey;autoIncrement;column:id"` InstanceNo string `gorm:"type:varchar(32);not null;uniqueIndex:uk_lci_instance_no;column:instance_no"` InstanceUlid string `gorm:"type:varchar(40);not null;uniqueIndex:uk_lci_instance_ulid;column:instance_ulid"` TemplateID int64 `gorm:"not null;column:template_id"` TemplateCode string `gorm:"type:varchar(64);not null;column:template_code"` TemplateVersion int `gorm:"not null;column:template_version"` OwnerUserID int64 `gorm:"not null;index:idx_lci_owner_status;column:owner_user_id"` StarID int64 `gorm:"not null;index:idx_lci_star_created;column:star_id"` Status string `gorm:"type:varchar(20);not null;default:'rendered';index:idx_lci_owner_status;column:status"` ClientRequestID *string `gorm:"type:varchar(64);column:client_request_id"` RenderConfig json.RawMessage `gorm:"type:jsonb;column:render_config"` MaterialsSnapshot MaterialsSnapshot `gorm:"type:jsonb;not null;default:'[]';column:materials_snapshot"` CompositeOssKey *string `gorm:"type:varchar(255);column:composite_oss_key"` CompositeMaterialID *int64 `gorm:"column:composite_material_id"` AssetID *int64 `gorm:"index:idx_lci_asset;column:asset_id"` MintOrderID *string `gorm:"type:varchar(100);column:mint_order_id"` IdempotencyKey *string `gorm:"type:varchar(64);column:idempotency_key"` Version int `gorm:"not null;default:1;column:version"` CreatedAt int64 `gorm:"not null;column:created_at"` UpdatedAt int64 `gorm:"not null;column:updated_at"` DeletedAt *int64 `gorm:"index;column:deleted_at"` Template LaserCardTemplate `gorm:"foreignKey:TemplateID;references:ID;constraint:OnDelete:RESTRICT"` } func (LaserCardInstance) TableName() string { return "laser_card_instances" } func (i *LaserCardInstance) BeforeCreate(tx *gorm.DB) error { now := time.Now().UnixMilli() i.CreatedAt = now i.UpdatedAt = now if i.InstanceNo == "" { i.InstanceNo = generateInstanceNo(now) } if i.InstanceUlid == "" { i.InstanceUlid = "lc_inst_" + i.InstanceNo } if i.Status == "" { i.Status = LaserCardInstanceStatusRendered } return nil } func (i *LaserCardInstance) BeforeUpdate(tx *gorm.DB) error { i.UpdatedAt = time.Now().UnixMilli() return nil } // generateInstanceNo 生成 LC + yyyyMMddHHmmss + 6位随机的单号 func generateInstanceNo(now int64) string { t := time.UnixMilli(now) ts := t.Format("20060102150405") r := rand.Intn(900000) + 100000 return fmt.Sprintf("LC%s%d", ts, r) } // MaterialSnapshotItem 素材快照单项 type MaterialSnapshotItem struct { Role string `json:"role"` // source | cutout | backdrop | composite OssKey string `json:"oss_key"` Hash string `json:"hash,omitempty"` Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` MimeType string `json:"mime_type,omitempty"` FileSize int64 `json:"file_size,omitempty"` PresetID string `json:"preset_id,omitempty"` // 仅 composite 需要 } // MaterialsSnapshot 素材快照 JSON 数组 type MaterialsSnapshot []MaterialSnapshotItem func (m *MaterialsSnapshot) Scan(value interface{}) error { if value == nil { *m = MaterialsSnapshot{} return nil } bytes, ok := value.([]byte) if !ok { return fmt.Errorf("failed to scan MaterialsSnapshot: %v", value) } return json.Unmarshal(bytes, m) } func (m MaterialsSnapshot) Value() (driver.Value, error) { if m == nil { return "[]", nil } return json.Marshal(m) } // 实例状态常量 const ( LaserCardInstanceStatusRendered = "rendered" // 已选卡,未铸造 LaserCardInstanceStatusMinting = "minting" // 铸造中 LaserCardInstanceStatusMinted = "minted" // 铸造完成 ) // ============================================================================= // LaserCardOperationLog — 镭射卡操作日志表 // ============================================================================= // LaserCardOperationLog 镭射卡操作审计日志 type LaserCardOperationLog struct { ID int64 `gorm:"primaryKey;autoIncrement;column:id"` InstanceID int64 `gorm:"not null;index:idx_lclog_instance_time;column:instance_id"` InstanceNo string `gorm:"type:varchar(32);not null;column:instance_no"` OperatorUserID int64 `gorm:"not null;index:idx_lclog_operator_time;column:operator_user_id"` Action string `gorm:"type:varchar(50);not null;index:idx_lclog_action_time;column:action"` StatusBefore *string `gorm:"type:varchar(20);column:status_before"` StatusAfter *string `gorm:"type:varchar(20);column:status_after"` RequestID *string `gorm:"type:varchar(64);column:request_id"` PayloadJSON json.RawMessage `gorm:"type:jsonb;column:payload_json"` ResultJSON json.RawMessage `gorm:"type:jsonb;column:result_json"` IPAddress *string `gorm:"type:varchar(45);column:ip_address"` UserAgent *string `gorm:"type:varchar(255);column:user_agent"` LatencyMs *int `gorm:"column:latency_ms"` ErrCode *string `gorm:"type:varchar(32);column:err_code"` CreatedAt int64 `gorm:"not null;column:created_at"` } func (LaserCardOperationLog) TableName() string { return "laser_card_operation_logs" } func (l *LaserCardOperationLog) BeforeCreate(tx *gorm.DB) error { l.CreatedAt = time.Now().UnixMilli() return nil } // 操作动作常量 const ( LaserCardActionCreateInstance = "create_instance" LaserCardActionGenerateVariants = "generate_variants" LaserCardActionMintStart = "mint_start" LaserCardActionMintSuccess = "mint_success" LaserCardActionMintFail = "mint_fail" )