package service import ( "errors" "github.com/topfans/backend/pkg/models" "github.com/topfans/backend/services/assetService/repository" "gorm.io/gorm" ) // MaterialService 素材业务逻辑层 type MaterialService struct { materialRepo *repository.MaterialRepository relationRepo *repository.AssetMaterialRelationRepository } // NewMaterialService 创建素材 Service func NewMaterialService(materialRepo *repository.MaterialRepository, relationRepo *repository.AssetMaterialRelationRepository) *MaterialService { return &MaterialService{ materialRepo: materialRepo, relationRepo: relationRepo, } } // UploadMaterial 上传素材(含 hash + oss_key 双重去重) func (s *MaterialService) UploadMaterial(m *models.Material) (*models.Material, error) { // 先按 hash + oss_key 双重判断,避免同一张图被错误复用 existing, err := s.materialRepo.FindByHashAndOssKey(m.Hash, m.OssKey, m.StarID) if err == nil && existing != nil { return existing, nil } if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err } // 如果没找到,再按单纯 hash 查找(兼容旧数据) existing, err = s.materialRepo.FindByHash(m.Hash, m.StarID) if err == nil && existing != nil { // 找到旧记录但 oss_key 不同,说明是不同文件但 hash 巧合相同,需要创建新记录 if existing.OssKey != m.OssKey { if err := s.materialRepo.Create(m); err != nil { return nil, err } return m, nil } return existing, nil } if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err } if err := s.materialRepo.Create(m); err != nil { return nil, err } return m, nil } // BindMaterials 绑定资产素材关联 func (s *MaterialService) BindMaterials(assetID int64, items []BindMaterialItem) ([]*models.AssetMaterialRelation, error) { if len(items) == 0 { return nil, errors.New("素材列表不能为空") } relations := make([]*models.AssetMaterialRelation, 0, len(items)) for _, item := range items { rel := &models.AssetMaterialRelation{ AssetID: assetID, MaterialID: item.MaterialID, MaterialType: item.MaterialType, LayerOrder: int(item.LayerOrder), PosX: item.PosX, PosY: item.PosY, Opacity: item.Opacity, Rotation: item.Rotation, ScaleX: item.ScaleX, ScaleY: item.ScaleY, } relations = append(relations, rel) } if err := s.relationRepo.BatchCreate(relations); err != nil { return nil, err } return relations, nil } // GetAssetMaterials 获取资产素材列表 func (s *MaterialService) GetAssetMaterials(assetID int64) ([]*models.AssetMaterialRelation, error) { return s.relationRepo.FindByAssetID(assetID) } // UpdateLayerOrder 更新图层顺序 func (s *MaterialService) UpdateLayerOrder(assetID int64, orders map[int64]int) error { return s.relationRepo.UpdateLayerOrder(assetID, orders) } // UnbindMaterial 解绑素材 func (s *MaterialService) UnbindMaterial(relationID int64) error { return s.relationRepo.SoftDelete(relationID) } // BindMaterialItem 绑定素材项 type BindMaterialItem struct { MaterialID int64 MaterialType string LayerOrder int32 PosX *float64 PosY *float64 Opacity *float64 Rotation *float64 ScaleX *float64 ScaleY *float64 }