fix(web): 修复生成页 API 调用适配新模板编辑器架构 #671

Merged
auto-approve-bot merged 5 commits from fix/generate-page-api-migration into develop 2026-07-21 10:33:47 +08:00
4 changed files with 42 additions and 32 deletions
+14 -15
View File
@@ -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
+11 -13
View File
@@ -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,
View File
+17 -4
View File
@@ -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: [] }),
}))