From 76d59d06fe0cb1c85ff55ee37a364ed9bdf32384 Mon Sep 17 00:00:00 2001 From: zyc <1439655764@qq.com> Date: Tue, 30 Jun 2026 11:47:07 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E6=AD=A5=E5=A4=8D=E7=94=A8=E5=95=86=E5=93=81?= =?UTF-8?q?=E5=BA=93=E5=B7=B2=E7=94=9F=E6=88=90=E7=9A=84=E4=B8=89=E8=A7=86?= =?UTF-8?q?=E5=9B=BE,=E4=B8=8D=E5=86=8D=E3=80=8C=E7=BC=BA=E4=B8=89?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=E3=80=8D(ZWQ#5=20=E7=BB=AD2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 商品库三视图走 standalone Asset、视频项目走项目级 BaseAssetGroup,两套存储不互通 → 商品库生成/采用的商品三视图,进视频项目第二步基础资产读不到、显示「缺三视图」。 修:项目详情 retrieve 时惰性单向同步(幂等,沿用 settle_video_completion 同款自愈模式)—— 若商品已有 standalone 三视图(metadata.view=three_view + product_id)但项目商品组尚无采用资产, 就 seed 进项目商品 BaseAssetGroup(candidate+adopted)。已在项目内生成过的不覆盖。 依赖上一commit给商品库三视图打的 view=three_view 标记。 projects 测试:基线已有 4 失败 2 错误(环境 provider 未配),本改动无新增回归。需部署生效。 Co-Authored-By: Claude Opus 4.8 --- core/backend/apps/projects/views.py | 35 ++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) 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: