fix(templates): real scene count on template pages (was always 0)
The card + detail read template.sceneCount, but the API never sent one — so the frontend mapper hardcoded sceneCount:0 for every DB-backed template. - content-svc: ContainerSummaryResponse + ContainerDetailResponse now carry SceneCount. The list computes it with one grouped query (scenes per aspect project, max across aspects); the detail loads scenes and counts them. - frontend: V2ContainerSummary.scene_count → AdminProject.sceneCount → the catalog card/detail (adminProjectToCatalogTemplate no longer hardcodes 0). Verified on the live local API: fr-instagram-promo → 5, single-scene templates → 1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,8 +51,18 @@ public class TemplateService(ContentDbContext db)
|
||||
var total = await q.LongCountAsync();
|
||||
var items = await q.Skip((req.Page - 1) * req.PageSize).Take(req.PageSize).ToListAsync();
|
||||
|
||||
// Scene count per template = scenes in a single aspect project (max across
|
||||
// projects). One grouped query, no scene entities loaded.
|
||||
var ids = items.Select(i => i.Id).ToList();
|
||||
var sceneCounts = (await db.Projects
|
||||
.Where(p => p.DeletedAt == null && ids.Contains(p.ContainerId))
|
||||
.Select(p => new { p.ContainerId, Cnt = p.Scenes.Count(s => s.DeletedAt == null) })
|
||||
.ToListAsync())
|
||||
.GroupBy(x => x.ContainerId)
|
||||
.ToDictionary(g => g.Key, g => g.Max(x => x.Cnt));
|
||||
|
||||
return new PagedResponse<ContainerSummaryResponse>(
|
||||
items.Select(MapContainerSummary),
|
||||
items.Select(c => MapContainerSummary(c, sceneCounts.GetValueOrDefault(c.Id, 0))),
|
||||
new PaginationMeta(req.Page, req.PageSize, total, (int)Math.Ceiling((double)total / req.PageSize))
|
||||
);
|
||||
}
|
||||
@@ -62,7 +72,7 @@ public class TemplateService(ContentDbContext db)
|
||||
var container = await db.ProjectContainers
|
||||
.Include(x => x.ContainerCategories).ThenInclude(x => x.Category)
|
||||
.Include(x => x.ContainerTags).ThenInclude(x => x.Tag)
|
||||
.Include(x => x.Projects.Where(p => p.DeletedAt == null))
|
||||
.Include(x => x.Projects.Where(p => p.DeletedAt == null)).ThenInclude(p => p.Scenes.Where(s => s.DeletedAt == null))
|
||||
.FirstOrDefaultAsync(x => x.Slug == slug)
|
||||
?? throw new KeyNotFoundException($"Container '{slug}' not found");
|
||||
|
||||
@@ -74,7 +84,7 @@ public class TemplateService(ContentDbContext db)
|
||||
var container = await db.ProjectContainers
|
||||
.Include(x => x.ContainerCategories).ThenInclude(x => x.Category)
|
||||
.Include(x => x.ContainerTags).ThenInclude(x => x.Tag)
|
||||
.Include(x => x.Projects.Where(p => p.DeletedAt == null))
|
||||
.Include(x => x.Projects.Where(p => p.DeletedAt == null)).ThenInclude(p => p.Scenes.Where(s => s.DeletedAt == null))
|
||||
.FirstOrDefaultAsync(x => x.Id == id)
|
||||
?? throw new KeyNotFoundException($"Container {id} not found");
|
||||
|
||||
@@ -450,12 +460,13 @@ public class TemplateService(ContentDbContext db)
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static ContainerSummaryResponse MapContainerSummary(ProjectContainer c) => new(
|
||||
private static ContainerSummaryResponse MapContainerSummary(ProjectContainer c, int sceneCount = 0) => new(
|
||||
c.Id, c.Slug, c.Name, c.Description, c.Image, c.Demo, c.MiniDemo,
|
||||
c.IsPublished, c.IsPremium, c.IsMockup, c.PrimaryMode.ToString(),
|
||||
c.RateAvg, c.RateCount, c.ViewCount, c.UseCount, c.Sort, c.SortDate,
|
||||
c.ContainerCategories.Select(cc => cc.Category.Slug).ToList(),
|
||||
c.ContainerTags.Select(ct => ct.Tag.Name).ToList()
|
||||
c.ContainerTags.Select(ct => ct.Tag.Name).ToList(),
|
||||
sceneCount
|
||||
);
|
||||
|
||||
private static ContainerDetailResponse MapContainerDetail(ProjectContainer c) => new(
|
||||
@@ -465,7 +476,8 @@ public class TemplateService(ContentDbContext db)
|
||||
c.RateAvg, c.RateCount, c.ViewCount, c.UseCount, c.Sort, c.SortDate,
|
||||
c.Projects.Select(MapProject).ToList(),
|
||||
c.ContainerCategories.Select(cc => MapCategoryFlat(cc.Category)).ToList(),
|
||||
c.ContainerTags.Select(ct => new TagResponse(ct.Tag.Id, ct.Tag.Name, ct.Tag.LatinName, ct.Tag.Slug, ct.Tag.AppliesToMode, ct.Tag.IsActive)).ToList()
|
||||
c.ContainerTags.Select(ct => new TagResponse(ct.Tag.Id, ct.Tag.Name, ct.Tag.LatinName, ct.Tag.Slug, ct.Tag.AppliesToMode, ct.Tag.IsActive)).ToList(),
|
||||
c.Projects.Count == 0 ? 0 : c.Projects.Max(p => p.Scenes.Count)
|
||||
);
|
||||
|
||||
private static CategoryResponse MapCategoryFlat(Category c) => new(
|
||||
|
||||
Reference in New Issue
Block a user