fix(web): 修复生成页 API 调用适配新模板编辑器架构 #671
@@ -219,16 +219,14 @@ test.describe("Core generation flow", () => {
|
||||
// Step 7: confirm and generate
|
||||
await expect(page.getByRole("heading", { name: /确认生成/ })).toBeVisible()
|
||||
|
||||
// Wait for plan creation API to be called
|
||||
// 精确匹配 POST /template-editors(创建接口),排除所有子路径(/generate, /clips, /ai-recommend 等)
|
||||
const createPlanPromise = page.waitForResponse(
|
||||
// Wait for generation API to be called
|
||||
// 新架构:GET 草稿自动创建 → PUT 更新内容 → POST /generate 触发生成
|
||||
// 等 generate 接口返回,确认生成流程启动
|
||||
const generatePromise = page.waitForResponse(
|
||||
(response) => {
|
||||
const url = response.url()
|
||||
const path = new URL(url).pathname
|
||||
return (
|
||||
response.request().method() === "POST" &&
|
||||
(path.endsWith("/templates/drafts") || path.endsWith("/templates/drafts/"))
|
||||
)
|
||||
return response.request().method() === "POST" && path.endsWith("/editor/generate")
|
||||
},
|
||||
{ timeout: 30_000 },
|
||||
)
|
||||
@@ -236,17 +234,18 @@ test.describe("Core generation flow", () => {
|
||||
// Click generate button
|
||||
await page.locator(".xx-btn-primary").filter({ hasText: "确认生成" }).first().click()
|
||||
|
||||
// Verify plan was created successfully
|
||||
const planResp = await createPlanPromise
|
||||
if (!planResp.ok()) {
|
||||
const body = await planResp.text()
|
||||
// Verify generation was triggered successfully
|
||||
const genResp = await generatePromise
|
||||
if (!genResp.ok()) {
|
||||
const body = await genResp.text()
|
||||
console.error(
|
||||
`[E2E DEBUG] 创建计划接口失败: status=${planResp.status()} url=${planResp.url()} body=${body.slice(0, 500)}`,
|
||||
`[E2E DEBUG] 触发生成接口失败: status=${genResp.status()} url=${genResp.url()} body=${body.slice(0, 500)}`,
|
||||
)
|
||||
}
|
||||
expect(planResp.ok()).toBeTruthy()
|
||||
const planData = (await planResp.json()) as { id: string }
|
||||
expect(planData.id).toBeTruthy()
|
||||
expect(genResp.ok()).toBeTruthy()
|
||||
const genData = (await genResp.json()) as { plan_id: string; generation_task_id: string }
|
||||
expect(genData.plan_id).toBeTruthy()
|
||||
expect(genData.generation_task_id).toBeTruthy()
|
||||
|
||||
// Generation may fail in test env (no worker), that's OK
|
||||
// Just verify the flow started - check page shows generation-related UI
|
||||
|
||||
Executable → Regular
+11
-13
@@ -25,11 +25,11 @@ import {
|
||||
import type { AssetItem } from "@/api/assets"
|
||||
import { getAssets, getAssetLibraries } from "@/api/assets"
|
||||
import {
|
||||
createEditPlan,
|
||||
generateEditPlan,
|
||||
updateEditPlan,
|
||||
getGenerationTaskResults,
|
||||
getGenerationStatus,
|
||||
getEditPlan,
|
||||
} from "@/api/templateEditor"
|
||||
import type { GeneratedVideo, EditPlanConfig, TitleConfig } from "@/api/templateEditor"
|
||||
import type { CoverConfig } from "../editing-planner/types"
|
||||
@@ -44,7 +44,6 @@ import { synthesizeSpeech, getTTSJobStatus, saveTtsToLibrary } from "@/api/tts"
|
||||
import { getTags, createTag } from "@/api/tags"
|
||||
import { useCloneProgress } from "@/hooks/useCloneProgress"
|
||||
import { useSearchParams, useNavigate } from "react-router-dom"
|
||||
import { getEditPlan } from "@/api/templateEditor"
|
||||
import "./generate.css"
|
||||
|
||||
const { Text } = Typography
|
||||
@@ -994,8 +993,11 @@ const GeneratePage: React.FC = () => {
|
||||
if (customVoiceText.trim()) voiceConfig.custom_text = customVoiceText.trim()
|
||||
}
|
||||
|
||||
const plan = await createEditPlan({
|
||||
template_id: selectedTemplate,
|
||||
// 获取或创建草稿(新架构:GET /templates/{templateId}/editor 自动创建)
|
||||
await getEditPlan(selectedTemplate)
|
||||
|
||||
// 更新草稿内容 + 切换到 editing 状态
|
||||
await updateEditPlan(selectedTemplate, {
|
||||
name: titleSettings.title.trim(),
|
||||
config: {
|
||||
asset_ids: materialMode === "auto" ? smartSelectedIds : selectedMaterials,
|
||||
@@ -1018,17 +1020,14 @@ const GeneratePage: React.FC = () => {
|
||||
material_mode: materialMode,
|
||||
},
|
||||
total_duration: duration,
|
||||
source_edit_plan_id: editPlanId || undefined,
|
||||
status: "editing",
|
||||
})
|
||||
|
||||
// 后端要求计划处于 editing 状态才能触发渲染,自动转换状态
|
||||
await updateEditPlan(plan.id, { status: "editing" })
|
||||
|
||||
await generateEditPlan(plan.id)
|
||||
await generateEditPlan(selectedTemplate)
|
||||
|
||||
const poll = async () => {
|
||||
try {
|
||||
const data = await getGenerationStatus(plan.id)
|
||||
const data = await getGenerationStatus(selectedTemplate)
|
||||
|
||||
if (data.plan_status === "completed") {
|
||||
setProgress(100)
|
||||
@@ -1075,7 +1074,7 @@ const GeneratePage: React.FC = () => {
|
||||
return String(val ?? "")
|
||||
}
|
||||
const errorMsg = safeExtract(rawMsg)
|
||||
console.error("[生成失败] planId:", plan.id, "响应:", data)
|
||||
console.error("[生成失败] templateId:", selectedTemplate, "响应:", data)
|
||||
setGenerateError(errorMsg)
|
||||
message.error(errorMsg)
|
||||
return
|
||||
@@ -1091,7 +1090,7 @@ const GeneratePage: React.FC = () => {
|
||||
>
|
||||
} catch (pollErr) {
|
||||
// 轮询接口本身出错(网络/鉴权等),记录并继续轮询一次
|
||||
console.error("[轮询出错] planId:", plan.id, pollErr)
|
||||
console.error("[轮询出错] templateId:", selectedTemplate, pollErr)
|
||||
progressTimer.current = setTimeout(poll, 3000) as unknown as ReturnType<
|
||||
typeof setInterval
|
||||
>
|
||||
@@ -1198,7 +1197,6 @@ const GeneratePage: React.FC = () => {
|
||||
duration,
|
||||
autoSubtitles,
|
||||
bgm,
|
||||
editPlanId,
|
||||
selectedTemplate,
|
||||
generateCount,
|
||||
materialMode,
|
||||
|
||||
Executable → Regular
@@ -214,10 +214,23 @@ vi.mock("@/api/titles", () => ({
|
||||
}))
|
||||
|
||||
vi.mock("@/api/templateEditor", () => ({
|
||||
createEditPlan: vi.fn().mockResolvedValue({ id: "test-plan" }),
|
||||
generateEditPlan: vi.fn().mockResolvedValue({ task_id: "test-task" }),
|
||||
updateEditPlan: vi.fn().mockResolvedValue({}),
|
||||
getEditPlan: vi.fn().mockResolvedValue({}),
|
||||
generateEditPlan: vi.fn().mockResolvedValue({
|
||||
plan_id: "test-plan",
|
||||
generation_task_id: "test-task",
|
||||
plan_status: "processing",
|
||||
clip_count: 5,
|
||||
}),
|
||||
updateEditPlan: vi.fn().mockResolvedValue({ plan_id: "test-plan", template_id: "test-template" }),
|
||||
getEditPlan: vi.fn().mockResolvedValue({
|
||||
plan_id: "test-plan",
|
||||
template_id: "test-template",
|
||||
name: "",
|
||||
config: {},
|
||||
status: "draft",
|
||||
}),
|
||||
getGenerationStatus: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ plan_status: "completed", generation_task_id: "test-task", clips: [] }),
|
||||
getGenerationTaskResults: vi.fn().mockResolvedValue({ items: [] }),
|
||||
}))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user