fix(*): 素材库与画布 - 修复批量删除刷新、选择布局及工具引用

This commit is contained in:
ddCat committed 2026-09-21 20:14:05 +08:00
1 parent 4e0b0a9256
commit 0146a232a7
27 files changed
+852 -109

No files matched your search

@@ -10,6 +10,7 @@ import (
"infinite-canvas/backend/internal/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// ResourceReferenceDocument 是资源删除校验使用的只读业务文档快照。
@@ -36,8 +37,12 @@ type ResourceReferenceSnapshot struct {
}
func (r *Repository) AssetResourceRecords(assetID string) ([]model.AssetVersion, []model.AssetRepresentation, error) {
return r.AssetsResourceRecords([]string{assetID})
}
func (r *Repository) AssetsResourceRecords(assetIDs []string) ([]model.AssetVersion, []model.AssetRepresentation, error) {
var versions []model.AssetVersion
if err := r.db.Where("asset_id = ?", assetID).Find(&versions).Error; err != nil {
if err := r.db.Where("asset_id IN ?", assetIDs).Find(&versions).Error; err != nil {
return nil, nil, err
}
if len(versions) == 0 {
@@ -54,6 +59,35 @@ func (r *Repository) AssetResourceRecords(assetID string) ([]model.AssetVersion,
return versions, representations, nil
}
// OtherAssetResourceReferences 只查询整批删除范围之外的素材,不扫描任务和画布。
func (r *Repository) OtherAssetResourceReferences(userID string, excludedAssetIDs []string) (ResourceReferenceSnapshot, error) {
snapshot := ResourceReferenceSnapshot{}
var assets []model.Asset
if err := r.db.Where("user_id = ? AND id NOT IN ?", userID, excludedAssetIDs).Find(&assets).Error; err != nil {
return snapshot, err
}
ids := make([]string, 0, len(assets))
for _, asset := range assets {
ids = append(ids, asset.ID)
snapshot.Documents = append(snapshot.Documents, ResourceReferenceDocument{Kind: "素材", ID: asset.ID, PrimaryJSON: asset.PayloadJSON})
}
if len(ids) == 0 {
return snapshot, nil
}
versions, representations, err := r.AssetsResourceRecords(ids)
if err != nil {
return snapshot, err
}
for _, version := range versions {
snapshot.Documents = append(snapshot.Documents, ResourceReferenceDocument{Kind: "素材", ID: version.ID, PrimaryJSON: version.DefinitionJSON})
}
for _, representation := range representations {
snapshot.Direct = append(snapshot.Direct, ResourceDirectReference{Kind: "素材", ID: representation.ID, ResourceID: representation.ResourceID})
snapshot.Documents = append(snapshot.Documents, ResourceReferenceDocument{Kind: "素材", ID: representation.ID, PrimaryJSON: representation.MetadataJSON})
}
return snapshot, nil
}
func (r *Repository) ResourcesForUserIDs(userID string, resourceIDs []string) ([]model.Resource, error) {
if len(resourceIDs) == 0 {
return []model.Resource{}, nil
@@ -352,12 +386,42 @@ func (r *Repository) AssetBusinessReferences(userID string, assetID string) ([]R
return result, nil
}
func (r *Repository) DeleteAssetAndResources(userID string, assetID string, resourceIDs []string, deletionJobs []model.ResourceDeletionJob) error {
func (r *Repository) DeleteAssetAndResources(userID string, assetID string, resourceIDs []string, deletionJobs []model.ResourceDeletionJob, deleteReferencedResources bool) error {
return r.DeleteAssetsAndResources(userID, []string{assetID}, resourceIDs, deletionJobs, deleteReferencedResources)
}
func (r *Repository) DeleteAssetsAndResources(userID string, assetIDs []string, resourceIDs []string, deletionJobs []model.ResourceDeletionJob, deleteReferencedResources bool) error {
return r.db.Transaction(func(tx *gorm.DB) error {
if err := New(tx).RequireNoCanvasHistoryReferences(resourceIDs); err != nil {
var ownedAssets []model.Asset
query := tx.Where("user_id = ? AND id IN ?", userID, assetIDs).Order("id")
if r.Dialect() == "postgres" {
query = query.Clauses(clause.Locking{Strength: "UPDATE"})
}
if err := query.Find(&ownedAssets).Error; err != nil {
return err
}
versionIDs := tx.Model(&model.AssetVersion{}).Select("id").Where("asset_id = ?", assetID)
if len(assetIDs) == 0 || len(ownedAssets) != len(assetIDs) {
return gorm.ErrRecordNotFound
}
if deleteReferencedResources {
if len(resourceIDs) > 0 {
// 与历史快照写入串行化,避免清除索引后又插入外键引用。
if r.Dialect() == "postgres" {
var resources []model.Resource
if err := tx.Select("id").Where("id IN ?", resourceIDs).Order("id").Clauses(clause.Locking{Strength: "UPDATE"}).Find(&resources).Error; err != nil {
return err
}
}
if err := tx.Where("resource_id IN ?", resourceIDs).Delete(&model.CanvasSnapshotResource{}).Error; err != nil {
return err
}
}
} else {
if err := New(tx).RequireNoCanvasHistoryReferences(resourceIDs); err != nil {
return err
}
}
versionIDs := tx.Model(&model.AssetVersion{}).Select("id").Where("asset_id IN ?", assetIDs)
if err := tx.Where("asset_version_id IN (?)", versionIDs).Delete(&model.ShotAssetReference{}).Error; err != nil {
return err
}
@@ -367,16 +431,16 @@ func (r *Repository) DeleteAssetAndResources(userID string, assetID string, reso
if err := tx.Where("asset_version_id IN (?)", versionIDs).Delete(&model.AssetRepresentation{}).Error; err != nil {
return err
}
if err := tx.Where("asset_id = ?", assetID).Delete(&model.ProjectAssetLink{}).Error; err != nil {
if err := tx.Where("asset_id IN ?", assetIDs).Delete(&model.ProjectAssetLink{}).Error; err != nil {
return err
}
if err := tx.Where("resolved_asset_id = ?", assetID).Delete(&model.ProjectAssetCandidate{}).Error; err != nil {
if err := tx.Where("resolved_asset_id IN ?", assetIDs).Delete(&model.ProjectAssetCandidate{}).Error; err != nil {
return err
}
if err := tx.Where("asset_id = ?", assetID).Delete(&model.AssetVersion{}).Error; err != nil {
if err := tx.Where("asset_id IN ?", assetIDs).Delete(&model.AssetVersion{}).Error; err != nil {
return err
}
if err := tx.Delete(&model.Asset{}, "id = ? AND user_id = ?", assetID, userID).Error; err != nil {
if err := tx.Delete(&model.Asset{}, "id IN ? AND user_id = ?", assetIDs, userID).Error; err != nil {
return err
}
if len(deletionJobs) > 0 {