feat: 补齐前端主流程并收紧工作台布局

统一工作台紧凑头部与形态图库间距,修复主体身份布局,并接入正式严格视频质量流水线。
This commit is contained in:
GouJ
2026-09-08 09:25:14 +08:00
committed by GitHub
parent 0f8b2074e4
commit 4edb0ff6cc
25 changed files with 355 additions and 233 deletions
+11 -15
View File
@@ -43,21 +43,13 @@ describe('后端 API 契约', () => {
})
expect(fetcher.mock.calls[4]![1]!.body).toBeUndefined()
})
it('分镜单集显式持久化,批量保持 force 和零次修复参数', async () => {
it('分镜只调用正式项目接口,并保持 force 和零次修复参数', async () => {
const fetcher = vi.fn<typeof fetch>().mockImplementation(async () => new Response('{"data":{}}'))
vi.stubGlobal('fetch', fetcher)
await storyboardApi.generateDirection('a/b', 2)
await storyboardApi.generateDirections('p', { concurrency: 2, force: false })
await storyboardApi.generateVisualState('p', 2, 0)
await storyboardApi.generateDirections('a/b', { concurrency: 2, force: false })
await storyboardApi.generateVisualStates('p', { concurrency: 3, force: true, maxRepairAttempts: 0 })
expect(fetcher.mock.calls.map(([url, init]) => [url, init?.method, JSON.parse(init!.body as string)])).toEqual([
['/api/projects/a%2Fb/storyboard-directions/generate-test', 'POST', { episodeNo: 2, persist: true }],
['/api/projects/p/storyboard-directions/generate', 'POST', { concurrency: 2, force: false }],
[
'/api/projects/p/storyboard-visual-states/generate-test',
'POST',
{ episodeNo: 2, persist: true, maxRepairAttempts: 0 }
],
['/api/projects/a%2Fb/storyboard-directions/generate', 'POST', { concurrency: 2, force: false }],
[
'/api/projects/p/storyboard-visual-states/generate',
'POST',
@@ -86,7 +78,7 @@ describe('后端 API 契约', () => {
expect(JSON.parse(fetcher.mock.calls[4]![1]!.body as string)).toEqual({ force: false })
})
it('分镜生成保留 200 中的校验失败和持久化标志,长请求不自动超时或重试', async () => {
it('分镜正式批量生成保留部分失败回执,长请求不自动超时或重试', async () => {
vi.useFakeTimers()
let finish!: (response: Response) => void
const fetcher = vi.fn<typeof fetch>().mockImplementation(
@@ -96,12 +88,16 @@ describe('后端 API 契约', () => {
})
)
vi.stubGlobal('fetch', fetcher)
const pending = storyboardApi.generateVisualState('p', 1, 2)
const pending = storyboardApi.generateVisualStates('p', {
concurrency: 1,
force: false,
maxRepairAttempts: 2
})
await vi.advanceTimersByTimeAsync(120_000)
expect(fetcher).toHaveBeenCalledOnce()
expect(fetcher.mock.calls[0]?.[1]?.signal?.aborted).toBe(false)
finish(new Response('{"data":{"validation":{"valid":false,"issues":[]},"persisted":false}}'))
await expect(pending).resolves.toMatchObject({ validation: { valid: false }, persisted: false })
finish(new Response('{"data":{"failedEpisodes":1,"episodes":[{"episodeNo":1,"status":"failed"}]}}'))
await expect(pending).resolves.toMatchObject({ failedEpisodes: 1, episodes: [{ status: 'failed' }] })
})
it('解包 data,同时保留创建项目的顶层 202 结构', async () => {
const fetcher = vi