topfans/backend/pkg/models/laser_card.go
2026-06-03 22:19:22 +08:00

231 lines
9.5 KiB
Go

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"
)