fix: 电商测试清单一轮 bug 修复(视频项目角色/场景 + 图片工作台 + 视频收口)

视频项目(ZWQ):
- 演员工作台保存后「我的演员」仍 0 个:保存时加入资产库(in_library=True)
- 资产详情「应用当前角色」自动送审(不再要手动点灰盾)
- 「我的演员」卡 + 待生成 seed 卡补删除入口(垃圾桶,两步确认)
- 新增场景未生成就刷新会丢:sceneDrafts 按项目持久化 localStorage
- 场景 AI 生成强制叠加「无真人」约束,避免出真人致视频被火山拒
- 进入项目默认落到当前阶段(不再恒显第 1 阶段)
- 视频已出但进度卡 3/4:submit/poll/adopt 幂等补推 current_stage→VIDEO,
  否则 settle_video_completion 因阶段守卫直接返回、永不收口 completed

图片工作台(PMC):
- 生图走 action 全局单飞锁致并发重跑/多平台套图被拒成「失败/少出图」:
  action 加 concurrent 选项,生图不占单飞锁
- 切模块再切回状态丢/数量少:每批各自落盘 pendingIds(onSubmitted 回传),
  切回时全部批次各自续轮询

附:含一处早前未提交的图片创作改动(选火山+传参考图强制切 gpt-image-2 + gen 气泡溢出 CSS)。
新增/通过测试:AttachOfficialModel、商品图删除、视频卡阶段收口、参考图强切模型。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-27 15:11:29 +08:00
co-authored by Claude Opus 4.8
parent ce7eaefe1d
commit 8f32ad69d3
9 changed files with 253 additions and 97 deletions
+24
View File
@@ -624,6 +624,30 @@ class ProjectApiTests(TestCase):
self.assertEqual(clip.trim_start_ms, 0)
self.assertIsNone(clip.trim_end_ms)
def test_video_done_settles_even_if_stage_stuck_at_storyboard(self):
"""ZWQ#15:项目 current_stage 还停在 storyboard,但视频段都出片并采用 → 必须收口成 completed,
而不是永远卡在「3/4 故事板」。修复前 settle_video_completion 因 current_stage != VIDEO 直接返回 → 卡死。"""
project = Project.objects.create(
team=self.team, created_by=self.user, product=self.product, name="P",
current_stage=ProjectStage.Stage.STORYBOARD, status=Project.Status.STORYBOARDING,
)
seg = VideoSegment.objects.create(project=project, sort_order=0, target_duration_seconds=15)
asset = Asset.objects.create(
team=self.team, created_by=self.user, name="clip",
asset_type=Asset.Type.VIDEO, source=Asset.Source.AI_GENERATED, category=Asset.Category.VIDEO_CLIP,
)
ver = VideoSegmentVersion.objects.create(video_segment=seg, asset=asset)
res = self.client.post(
f"/api/projects/{project.id}/adopt-video-version/",
{"video_segment_id": str(seg.id), "version_id": str(ver.id)},
format="json",
)
self.assertEqual(res.status_code, 200)
project.refresh_from_db()
self.assertEqual(project.current_stage, ProjectStage.Stage.VIDEO)
self.assertEqual(project.status, Project.Status.COMPLETED)
def _make_audio_model(self):
return ModelConfig.objects.create(
provider=self.provider, name="doubao-voice-bigtts", display_name="豆包语音合成",