feat: 增加操作步骤引导与错误修复入口

This commit is contained in:
GouJ
2026-09-22 21:40:58 +08:00
parent be06caaa9f
commit 1c5b1e448a
8 changed files with 374 additions and 122 deletions
+11 -20
View File
@@ -378,7 +378,7 @@ describe('视觉风格与主体身份工作区', () => {
const put = fetcher.mock.calls.find(([, init]) => init?.method === 'PUT')!
expect(put[0]).toBe('/api/subjects/subject-db-1/identity')
expect(JSON.parse(put[1]!.body as string)).toMatchObject({ description: '人工稳定身份', isLocked: true })
expect(button('AI 重新生成身份').disabled).toBe(true)
expect(button('生成选角候选').disabled).toBe(false)
await wrapper!.get('#identity-description').setValue('新的未保存草稿')
await wrapper!.findAll('.identity-subject-item')[1]!.trigger('click')
expect(wrapper!.text()).toContain('切换会丢弃草稿')
@@ -538,11 +538,10 @@ describe('视觉风格与主体身份工作区', () => {
expect(wrapper!.text()).toContain('2 个形态')
expect(fetcher.mock.calls.some(([url]) => String(url).endsWith('/subjects/subject-db-1/identity'))).toBe(true)
expect(fetcher.mock.calls.some(([url]) => String(url).endsWith('/identity/images'))).toBe(false)
expect(button('生成选角候选').disabled).toBe(true)
expect(button('AI 生成身份').disabled).toBe(false)
expect(button('配置生成模型').disabled).toBe(false)
})
it('锁定阻止身份 AI 覆盖但不阻止人工编辑和生图,生图默认省略 referenceImageId', async () => {
it('锁定阻止身份 AI 覆盖但不阻止人工编辑,并按步骤进入后续操作', async () => {
const fetcher = vi.fn<typeof fetch>().mockImplementation(async (url, init) => {
if (String(url).endsWith('/subject-forms')) return jsonResponse([formFixture()])
if (String(url).endsWith('/visual-style')) return jsonResponse(styleFixture({ isLocked: true }))
@@ -552,18 +551,9 @@ describe('视觉风格与主体身份工作区', () => {
})
vi.stubGlobal('fetch', fetcher)
await mountAssets('identity')
expect(button('AI 重新生成身份').disabled).toBe(true)
expect(wrapper!.text()).toContain('主体身份已完成')
expect(button('保存主体身份').disabled).toBe(false)
button('生成辅助身份图').click()
await flushPromises()
expect(button('确认生成身份图').disabled).toBe(true)
document.querySelector<HTMLInputElement>('#identity-image-cost')!.click()
await flushPromises()
button('确认生成身份图').click()
await flushPromises()
const post = fetcher.mock.calls.find(([, init]) => init?.method === 'POST')!
expect(post[0]).toBe('/api/subjects/subject-db-1/identity/images')
expect(JSON.parse(post[1]!.body as string)).toEqual({ viewType: 'front' })
expect(fetcher.mock.calls.some(([, init]) => init?.method === 'POST')).toBe(false)
})
it('无项目风格时禁止生成身份和图片,但仍可人工保存身份', async () => {
@@ -577,8 +567,7 @@ describe('视觉风格与主体身份工作区', () => {
})
)
await mountAssets('identity')
expect(button('AI 重新生成身份').disabled).toBe(true)
expect(button('生成选角候选').disabled).toBe(true)
expect(button('设置视觉风格').disabled).toBe(false)
expect(button('保存主体身份').disabled).toBe(false)
})
@@ -758,7 +747,7 @@ describe('视觉风格与主体身份工作区', () => {
const put = fetcher.mock.calls.find(([, init]) => init?.method === 'PUT')!
expect(put[0]).toBe('/api/subjects/subject-db-1/identity/images/casting-1/casting')
expect(fetcher.mock.calls.some(([url]) => String(url).endsWith('/anchor'))).toBe(false)
expect(wrapper!.text()).toContain('选角状态:选角已完成')
expect(wrapper!.text()).toContain('主体身份已完成')
expect(wrapper!.text()).toContain('演员身份已确认并锁定')
})
@@ -803,17 +792,19 @@ describe('视觉风格与主体身份工作区', () => {
if (String(url).endsWith('/visual-style')) return jsonResponse(styleFixture())
if (String(url).endsWith('/identity/images')) return jsonResponse([])
if (init?.method === 'POST') throw new Error('connection lost')
if (String(url).endsWith('/identity')) return jsonResponse(null)
return jsonResponse(identityFixture())
})
vi.stubGlobal('fetch', fetcher)
const provided = await mountAssets('identity')
await confirmGeneration('AI 重新生成身份')
button('生成身份文本').click()
await flushPromises()
expect(fetcher.mock.calls.filter(([, init]) => init?.method === 'POST')).toHaveLength(1)
expect(getOperation(fixture.id).error).toContain('无法连接后端')
provided.data.value!.project = { ...fixture, status: 'generating' }
await flushPromises()
expect(button('保存主体身份').disabled).toBe(true)
expect(button('生成选角候选').disabled).toBe(true)
expect(button('生成身份文本').disabled).toBe(true)
})
})