diff --git a/core/backend/apps/projects/views.py b/core/backend/apps/projects/views.py index c51bfff..facf643 100644 --- a/core/backend/apps/projects/views.py +++ b/core/backend/apps/projects/views.py @@ -231,6 +231,36 @@ class ProjectViewSet(TeamScopedViewSetMixin, ModelViewSet): # 列表用轻量序列化(只给列表/仪表盘/侧栏要的字段);详情/写操作用全量 ProjectSerializer return ProjectListSerializer if self.action == "list" else ProjectSerializer + def _seed_product_triview_group(self, *, project_id, product_id, team): + """惰性把商品库已有的商品三视图挂进本项目的商品 BaseAssetGroup(幂等)。 + 商品库走 standalone Asset、视频项目走项目级 BaseAssetGroup,是两套存储;此处做单向复用同步: + 进详情时若商品已有 standalone 三视图(metadata.view=three_view + product_id)但项目商品组尚无采用资产, + 就 seed 进去 → 第二步基础资产直接显示该三视图,不再「缺三视图」。已在项目内生成过的不覆盖。""" + if not product_id: + return + groups = [ + g for g in BaseAssetGroup.objects.filter(project_id=project_id, kind=BaseAssetGroup.Kind.PRODUCT) + if not (g.metadata or {}).get("triview_of") + ] + if any(g.adopted_asset_id for g in groups): + return # 项目内已有商品三视图,不覆盖 + tri = ( + Asset.objects.filter( + team=team, is_deleted=False, + metadata__product_id=str(product_id), metadata__view="three_view", + ) + .order_by("-created_at") + .first() + ) + if tri is None: + return + group = groups[0] if groups else BaseAssetGroup.objects.create( + project_id=project_id, kind=BaseAssetGroup.Kind.PRODUCT, metadata={} + ) + group.candidate_assets.add(tri) + group.adopted_asset = tri + group.save(update_fields=["adopted_asset", "updated_at"]) + def retrieve(self, request, *args, **kwargs): # 详情加载(=进入流水线页)时自愈视频片段数:历史项目在「采用前增删分镜」未同步, # 或项目创建固定铺的 4 段从未被收口,会让视频步骤的片段数与故事板/采用版分镜对不上。 @@ -238,10 +268,13 @@ class ProjectViewSet(TeamScopedViewSetMixin, ModelViewSet): # 用轻量查询判定 + 同步,再交给 super 做重 prefetch 序列化(避免重查询跑两遍)。 proj = ( Project.objects.filter(pk=kwargs.get("pk"), **{self.team_field: self.get_team()}) - .only("id", "current_stage", "status") + .only("id", "current_stage", "status", "product_id") .first() ) if proj is not None: + # 跨库同步:商品在「商品库」生成过三视图(standalone Asset, view=three_view + product_id), + # 但本项目还没商品三视图组 → seed 进项目商品组,让第二步「基础资产」复用、不再「缺三视图」。 + self._seed_product_triview_group(project_id=proj.id, product_id=proj.product_id, team=self.get_team()) if proj.current_stage == ProjectStage.Stage.VIDEO: adopted_script = proj.script_versions.filter(is_adopted=True).order_by("-created_at").first() if adopted_script is not None: