diff --git a/backend/app/http/v1/dto/creator.go b/backend/app/http/v1/dto/creator.go index b364ca3..226170f 100644 --- a/backend/app/http/v1/dto/creator.go +++ b/backend/app/http/v1/dto/creator.go @@ -30,6 +30,7 @@ type ContentCreateForm struct { Genre string `json:"genre"` Key string `json:"key"` Price float64 `json:"price"` + CoverIDs []string `json:"cover_ids"` MediaIDs []string `json:"media_ids"` } @@ -38,6 +39,7 @@ type ContentUpdateForm struct { Genre string `json:"genre"` Key string `json:"key"` Price float64 `json:"price"` + CoverIDs []string `json:"cover_ids"` MediaIDs []string `json:"media_ids"` } diff --git a/backend/app/services/creator.go b/backend/app/services/creator.go index bc7ae1a..84a8128 100644 --- a/backend/app/services/creator.go +++ b/backend/app/services/creator.go @@ -173,18 +173,30 @@ func (s *creator) CreateContent(ctx context.Context, userID int64, form *creator } // 2. Link Assets - if len(form.MediaIDs) > 0 { - var assets []*models.ContentAsset - for i, mid := range form.MediaIDs { - assets = append(assets, &models.ContentAsset{ - TenantID: tid, - UserID: uid, - ContentID: content.ID, - AssetID: cast.ToInt64(mid), - Sort: int32(i), - Role: consts.ContentAssetRoleMain, - }) - } + var assets []*models.ContentAsset + // Covers + for i, mid := range form.CoverIDs { + assets = append(assets, &models.ContentAsset{ + TenantID: tid, + UserID: uid, + ContentID: content.ID, + AssetID: cast.ToInt64(mid), + Sort: int32(i), + Role: consts.ContentAssetRoleCover, + }) + } + // Main Media + for i, mid := range form.MediaIDs { + assets = append(assets, &models.ContentAsset{ + TenantID: tid, + UserID: uid, + ContentID: content.ID, + AssetID: cast.ToInt64(mid), + Sort: int32(i), + Role: consts.ContentAssetRoleMain, + }) + } + if len(assets) > 0 { if err := tx.ContentAsset.WithContext(ctx).Create(assets...); err != nil { return err } @@ -258,23 +270,35 @@ func (s *creator) UpdateContent( } // 4. Update Assets (Full replacement strategy) - if len(form.MediaIDs) > 0 { - _, err = tx.ContentAsset.WithContext(ctx).Where(tx.ContentAsset.ContentID.Eq(cid)).Delete() - if err != nil { - return err - } + _, err = tx.ContentAsset.WithContext(ctx).Where(tx.ContentAsset.ContentID.Eq(cid)).Delete() + if err != nil { + return err + } - var assets []*models.ContentAsset - for i, mid := range form.MediaIDs { - assets = append(assets, &models.ContentAsset{ - TenantID: tid, - UserID: uid, - ContentID: cid, - AssetID: cast.ToInt64(mid), - Sort: int32(i), - Role: consts.ContentAssetRoleMain, // Default to main - }) - } + var assets []*models.ContentAsset + // Covers + for i, mid := range form.CoverIDs { + assets = append(assets, &models.ContentAsset{ + TenantID: tid, + UserID: uid, + ContentID: cid, + AssetID: cast.ToInt64(mid), + Sort: int32(i), + Role: consts.ContentAssetRoleCover, + }) + } + // Main Media + for i, mid := range form.MediaIDs { + assets = append(assets, &models.ContentAsset{ + TenantID: tid, + UserID: uid, + ContentID: cid, + AssetID: cast.ToInt64(mid), + Sort: int32(i), + Role: consts.ContentAssetRoleMain, + }) + } + if len(assets) > 0 { if err := tx.ContentAsset.WithContext(ctx).Create(assets...); err != nil { return err } diff --git a/backend/config.toml b/backend/config.toml index b822342..de15d4b 100644 --- a/backend/config.toml +++ b/backend/config.toml @@ -138,4 +138,4 @@ LocalPath = "./storage" # 签名密钥 Secret = "your-storage-secret" # 公共访问URL前缀 -BaseURL = "http://localhost:8080/v1/storage" +BaseURL = "/v1/storage" diff --git a/frontend/portal/src/views/creator/ContentsEditView.vue b/frontend/portal/src/views/creator/ContentsEditView.vue index 33fd8a9..a04d6e0 100644 --- a/frontend/portal/src/views/creator/ContentsEditView.vue +++ b/frontend/portal/src/views/creator/ContentsEditView.vue @@ -338,44 +338,12 @@ const submit = async () => { visibility: 'public', preview_seconds: form.enableTrial ? form.trialTime : 0, price: form.priceType === 'paid' ? parseFloat(form.price) : 0, // API expects float price, service handles conversion - media_ids: [] // API expects media_ids list? Wait, update DTO `ContentUpdateForm` expects `media_ids` string array? - // Check `ContentCreateForm` and `ContentUpdateForm`. - // `ContentCreateForm`: `MediaIDs []string`. - // Backend logic in `CreateContent` iterates `MediaIDs` and sets `Role` to `main`. - // It does NOT handle Covers explicitly in `CreateContent` logic I read! - // `CreateContent` logic: `assets = append(assets, ... Role: Main)`. - // So Covers are ignored or treated as Main? - // Wait, `UpdateContent` also iterates `MediaIDs` and sets `Role` to `Main`. - // So current backend implementation treats ALL sent IDs as Main assets. - // And assumes `Cover` is handled via `toContentItemDTO` fallback or separate logic? - // Backend logic for `CreateContent`: - // `assets = append(assets, ... Role: Main)`. - // This is a limitation. I need to update backend to support Roles map or assume first image is cover? - // But `ContentsEditView` sends `assets` array with roles in my previous assumption? - // No, the `submit` function in `ContentsEditView` (previous version) constructed `payload.assets`. - // But `creatorApi.createContent` sends `ContentCreateForm` which has `media_ids []string`. - // `ContentCreateForm` does NOT have `assets` structure! - // So I need to update `ContentCreateForm` / `ContentUpdateForm` to support asset structure OR just send IDs and let backend guess. - // Given I can't easily change `ContentCreateForm` structure extensively without breaking other things? - // Actually, I just read `ContentCreateForm` has `MediaIDs []string`. - // If I want to support covers, I need to update Backend DTO and Service. - // Or I can send all IDs in `MediaIDs` and Backend sets them as `Main`. - // This means Covers won't be distinguished. - // I should fix Backend `ContentCreateForm` / `ContentUpdateForm` to accept `Assets []AssetForm`? - // Or just `CoverIDs` and `MediaIDs`. + cover_ids: [], + media_ids: [] }; - // Let's check `backend/app/http/v1/dto/creator.go` again. - // `ContentCreateForm` struct: `MediaIDs []string`. - // `ContentUpdateForm` struct: `MediaIDs []string`. - - // I will assume for now I pass ALL IDs. Backend sets Role=Main. - // To fix Cover, I should modify backend to accept `CoverIDs` or `Assets` structure. - // But for this task "Fix 404", I'll stick to passing IDs. - // I will update the logic to collect ALL IDs from covers, videos, audios, images. - - const allMedia = [...form.covers, ...form.videos, ...form.audios, ...form.images]; - payload.media_ids = allMedia.map(m => m.id); + payload.cover_ids = form.covers.map(m => m.id); + payload.media_ids = [...form.videos, ...form.audios, ...form.images].map(m => m.id); if (isEditMode.value) { await creatorApi.updateContent(contentId.value, payload);