diff --git a/apps/api/app/api/routes/templates_editor/clips.py b/apps/api/app/api/routes/templates_editor/clips.py index 515e3eaa4..4343481a1 100755 --- a/apps/api/app/api/routes/templates_editor/clips.py +++ b/apps/api/app/api/routes/templates_editor/clips.py @@ -445,6 +445,8 @@ def create_clips_from_assets_editor( current_user.user.id, ) + # 新创建的片段已分配素材,立即标记为 ready,否则渲染管线找不到就绪片段 + plan_svc.mark_clips_ready(plan_id) return ClipsFromAssetsResponse( created_count=len(clips), plan_id=plan_id, diff --git a/tests/unit/test_editor_clips_random_start.py b/tests/unit/test_editor_clips_random_start.py index e2336ef72..fe782562d 100644 --- a/tests/unit/test_editor_clips_random_start.py +++ b/tests/unit/test_editor_clips_random_start.py @@ -394,3 +394,30 @@ class TestEditorClipsErrorHandling: assert exc_info.value.status_code == 400 assert "创建片段失败" in exc_info.value.detail + + +class TestMarkClipsReadyAfterCreation: + """验证 from-assets 创建片段后立即调用 mark_clips_ready,确保渲染管线能找到就绪片段。""" + + @patch("app.api.routes.templates_editor.clips.get_storage_service") + def test_mark_clips_ready_called_after_creation(self, _mock_storage): + """创建片段后必须调用 plan_svc.mark_clips_ready(plan_id)。""" + from app.api.routes.templates_editor.clips import create_clips_from_assets_editor + from app.api.routes.templates_editor.schemas import ClipsFromAssetsRequest + + mock_plan_svc = _make_plan_svc() + mock_asset_repo = MagicMock() + mock_asset_repo.get = MagicMock(side_effect=lambda aid: _make_mock_asset(aid, {"a1": 30.0}[aid])) + + body = ClipsFromAssetsRequest(asset_ids=["a1"], required_clips_count=2) + create_clips_from_assets_editor( + template_id="tmpl-1", + body=body, + plan_id="plan-xyz", + services=(MagicMock(), mock_plan_svc), + asset_repo=mock_asset_repo, + current_user=_make_auth_user(), + ) + + # 关键断言:mark_clips_ready 必须被调用,且传入正确的 plan_id + mock_plan_svc.mark_clips_ready.assert_called_once_with("plan-xyz")