From 2eea0ea72e58b79b0d2439928689b4404a157760 Mon Sep 17 00:00:00 2001 From: GJ Date: Thu, 10 Sep 2026 22:30:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8C=E6=AD=A5=E7=B2=BE=E7=AE=80?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=B9=B6=E7=BB=9F=E4=B8=80=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- docs/api-contract-sync.md | 32 +++ docs/backend-coverage.md | 8 +- docs/frontend-simplification.md | 12 +- src/components/ui/AppForm.vue | 119 ++++++++ src/components/ui/DetailDisclosure.vue | 5 + src/composables/useTheme.ts | 9 + src/features/breakdown/BreakdownPage.vue | 138 +++++---- src/features/create-drama/CreateDramaPage.vue | 25 +- src/features/production/ProductionPage.vue | 130 ++++++--- .../production/components/KeyframeDialog.vue | 89 +++--- .../components/ProductionReceipt.vue | 3 +- .../production/components/QualityDialog.vue | 270 ++++++++++-------- .../production/components/QualityResult.vue | 18 ++ .../components/ShotProductionAssets.vue | 73 ++--- src/features/production/model.ts | 6 +- src/features/production/quality.ts | 55 +--- src/features/production/quality.types.ts | 14 +- src/features/production/testing/fixtures.ts | 5 - src/features/production/types.ts | 38 ++- .../production/useAdvancedProduction.ts | 14 +- src/features/production/useQuality.ts | 23 +- .../components/CreateProjectDialog.vue | 44 +-- src/features/projects/types.ts | 10 - src/features/storyboard/StoryboardPage.vue | 77 ++--- .../storyboard/components/ShotTools.vue | 2 +- src/features/storyboard/types.ts | 3 +- .../subject-identity/SubjectIdentityPage.vue | 128 +++++---- .../components/CastingCandidateDialog.vue | 40 ++- .../components/IdentityEditor.vue | 24 +- .../components/IdentityGallery.vue | 26 +- .../components/IdentityImageDialog.vue | 64 +++-- src/features/subject-identity/index.ts | 2 +- src/features/subject-identity/model.ts | 23 +- .../subject-identity/testing/fixtures.ts | 3 - src/features/subject-identity/types.ts | 12 +- .../subject-identity/useSubjectIdentity.ts | 14 +- .../subject-images/SubjectImagesPage.vue | 177 ++++-------- .../components/FormPromptBatch.vue | 59 ++-- .../components/GenerateImageDialog.vue | 37 ++- .../components/ImageGalleryDialog.vue | 22 +- src/features/subject-images/model.ts | 24 +- .../subject-images/testing/fixtures.ts | 1 - src/features/subject-images/types.ts | 14 +- .../subject-images/useSubjectImages.ts | 82 +----- .../visual-style/components/StyleEditor.vue | 72 ++--- .../visual-style/components/StyleImages.vue | 46 ++- src/features/visual-style/testing/fixtures.ts | 1 - src/features/visual-style/types.ts | 1 - src/features/workflows/selectors.ts | 7 + src/lib/form-rules.ts | 52 ++++ src/testing/project-context.ts | 4 +- tests/components/ui/ActionMenu.test.ts | 1 + tests/components/ui/form.test.ts | 165 +++++++++++ tests/components/ui/layout.test.ts | 4 +- .../features/breakdown/BreakdownPage.test.ts | 17 +- tests/features/production/production.test.ts | 3 + .../features/production/public-assets.test.ts | 168 +++++++++++ tests/features/production/quality.test.ts | 40 +-- tests/features/projects/access.test.ts | 4 +- .../subject-identity/identity.test.ts | 56 ++-- .../subject-identity/thumbnail.test.ts | 2 +- .../subject-images/asset-impact.test.ts | 21 +- tests/features/subject-images/images.test.ts | 2 +- tests/features/subject-images/prompts.test.ts | 12 +- tests/features/workflows/pages.test.ts | 51 ++-- 66 files changed, 1611 insertions(+), 1100 deletions(-) create mode 100644 docs/api-contract-sync.md create mode 100644 src/components/ui/AppForm.vue create mode 100644 src/lib/form-rules.ts create mode 100644 tests/components/ui/form.test.ts create mode 100644 tests/features/production/public-assets.test.ts diff --git a/README.md b/README.md index 495548d..0d0d25b 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Oxfmt 不负责代码质量,Oxlint 不负责 Vue 的完整类型推导;Vue S 布局样式集中在 `src/styles/admin.css`,业务排版保留在 `src/styles/styles.css`。新增页面应使用 `WorkspacePage`(内容优先页开启 `compact`),低频操作使用 `WorkspaceTools`;避免通过 `body` 或 `window.scrollTo` 管理滚动。 -本次 UI 重构保留前端 `dev@5551653` 的业务更新,包括过期形态图、主首帧和主视频的提示与更新入口。首帧默认只补当前剧集;存在过期主首帧时优先更新全项目过期项。非覆盖模式下的过期主视频重建完成后,会接替旧主视频;普通新增候选不自动替换主资产。 +本次 UI 重构保留前端 `dev@5551653` 的业务更新,包括主首帧和主视频的过期提示与更新入口。2026-09-10 已适配精简公开 DTO,见 [接口数据同步说明](docs/api-contract-sync.md)。首帧默认只补当前剧集;存在过期主首帧时优先更新全项目过期项。非覆盖模式下的过期主视频重建完成后,会接替旧主视频;普通新增候选不自动替换主资产。 本地验收建议使用 1920×1080、1280×720 和窄屏视口:打开长剧本、长项目标题和多镜头项目,确认顶栏不移动、目录与正文能分别滚到底;切换暗黑模式后检查弹窗、下拉菜单、图片失败占位,刷新后主题应保持。 @@ -223,7 +223,7 @@ API 层也提供 `state` 与 `breakdown/latest` 方法。页面通过共享 chec ### 形态图片约定 1. 入口为 `/projects/:projectId/subject-images`;项目导航、拆解主体列表和分镜参考图缺失提示均可进入。图库自动读取后端已生成图片,不需要重新生图才能显示。 -2. 生图使用正式数据库 `SubjectForm.id`。Checkpoint 的领域 `formId` 不是数据库 ID,不能直接调用图片接口。项目列表包含 Identity Anchor 及图片的 `rawJson` 追溯字段,用于识别母版过期;完整实际 Prompt 在历史弹窗读取。 +2. 生图使用正式数据库 `SubjectForm.id`。Checkpoint 的领域 `formId` 不是数据库 ID,不能直接调用图片接口。图库通过 `identity.anchorImageId` 返回当前母版,不再返回图片 `rawJson` 或实际生成 Prompt;不能据此推断形态图历史母版是否过期。正式可编辑提示词保留在形态上。 3. 单图明确发送 `provider: 'seedream'`,避免后端单图入口默认使用 mock。模型和凭证仅配置在后端,前端不保存 API Key。自定义 Prompt 优先,其次正式 `generationPrompt`;缺少时后端先调用文本模型生成并保存。`appearancePrompt` 仅为原始素材,不能直接充当最终 Prompt。可在形态卡片“提示词与生成”先生成、检查与导出正式提示词;后端尚无手工编辑保存接口。 4. 单图宽高同时留空使用后端默认 2K,自定义时必须同时提供正整数,具体尺寸限制仍由模型校验。当前 后端图片模型 Provider 没有使用 negativePrompt,所以页面不提供无效的负向提示词输入。 5. 单图生成新增历史记录,不删除旧图。无主图时默认勾选“生成成功后设为主图”;已有主图时默认不替换。候选图可以在历史弹窗二次确认后通过 PUT 设为主图,只允许已完成图片。 @@ -231,7 +231,7 @@ API 层也提供 `state` 与 `breakdown/latest` 方法。页面通过共享 chec 7. 图库、镜头影响检查、关联素材和图片历史均不定时刷新;首次进入、切换查询目标、手动刷新及本次写操作完成后按需读取。“刷新图库”同时更新项目状态。数据库存在 pending / generating 时暂停再次生图;网络错误不自动重试有费用的请求。HTTP 200 中的批量部分失败单独展示。当前形态列表接口返回完整数组,无分页参数或游标,因此不显示分页或触底加载入口。筛选栏与有值的关联素材行共用一个不透明背景的吸顶容器,内部无 margin 断层;关联素材保持单行横向滚动、上下居中,图片区域沿正文向下滚动。 8. 图片使用持久化后的 `/storage/...` 地址,开发代理已配置。生产环境也必须代理 `/storage/`,不能让 SPA 回退返回 index.html。无效 URL、加载失败、无图和后端生成失败有各自提示;不会自动使用可能过期的 Provider 临时地址。 9. 设为主图后,回到分镜点击“刷新参考图”读取最新绑定。已有视频提示词不会自动重生成,需要按需覆盖。本页面不会调用 `/production/start` 或实际视频生成。 -10. 人物、场景、道具均仅继承已锁定身份的当前母版;无母版或未锁定不继承。刷新过期形态只生成候选,验图后手动切换主图。批量图片可限制本次数量,回执独立展示因上限未执行数,不把它算作已有结果的跳过数。 +10. 人物、场景、道具均仅继承已锁定身份的当前母版;无母版或未锁定不继承。母版变更后需人工核对形态,按需生成候选、验图后手动切换主图。批量图片可限制本次数量,回执独立展示因上限未执行数,不把它算作已有结果的跳过数。 11. 提示词批量入口有独立并发、覆盖和回执;默认补缺,覆盖会重写已有正式文本,但不改变历史图片、实际 Prompt 或主图。未完成剧本、运行中的任务及查询错误均阻止生成。 12. 生产页过期提示可点击直达镜头实际使用的形态;图库支持 `sourceShotId`/`subjectFormId` 定位、高亮和返回原镜头。顶部独立显示身份主图过期与下游首帧影响,检查失败不当作“没有过期”。两种后端就绪检查结果冲突时提示“状态待核对”,不建议据此重复生图;已知后端原因见 [覆盖说明](docs/backend-coverage.md#过期首帧与素材定位)。 @@ -253,7 +253,7 @@ API 层也提供 `state` 与 `breakdown/latest` 方法。页面通过共享 chec 2. 身份 AI 生成需要已创建 VisualStyle;身份图生成还需要已保存的非空 `generationPrompt`。不存在身份时不调用会报错的图片 GET。404 或网络失败不会被当作“尚未创建”。 3. 前端以正式 `subject-forms` 目录为基础,并合并 Character Casting readiness,因此尚无形态的角色也可先完成 Identity 和选角。Scene / Prop 若还没有 Form,仍不会凭 checkpoint 伪造正式 Subject ID。 4. 身份文本批量分为 Character 专用入口和全部主体高级入口。选角候选批量只处理 `missing_anchor`,受本批上限控制;`candidate_pending` 必须人工确认,不会由批量任务静默决定演员。 -5. 身份图片的 `isAnchor` 来自专用 GET。Character primary 通过 Casting Candidate 接口生成且默认停用;点击确认演员后才成为 Anchor 并锁定 Identity。辅助视图不能直接成为母版。Scene / Prop 保留普通母版切换接口。 +5. 身份图片的 `isAnchor` 来自专用 GET。Character primary 通过 Casting Candidate 接口生成,候选的 `isAnchor` 为 false;点击确认演员后才成为 Anchor 并锁定 Identity。辅助视图不能直接成为母版。Scene / Prop 保留普通母版切换接口。 6. 普通身份生图不传 `referenceImageId` 时,由后端自动选择当前母版;无母版时按文本生成。指定时只能选择当前身份已完成的图片;候选图即使停用也可作为显式参考。Character Casting Candidate 是独立选角入口,即使已有 Anchor 也不会复用旧母版,避免旧演员身份污染新候选。尺寸成对留空或提供正整数。自定义 Prompt 会替换后端编译的完整文本,建议保留默认。 7. 目前**人物与场景形态生图**会自动注入当前身份母版,分别固定人物身份和空间骨架;道具暂不自动引用。没有身份或母版时,原形态生图流程仍可使用。已有母版但缺少 Provider 可访问远程地址时,后端会报错;本地 `/storage/` 能显示并不证明原始 Provider URL 仍可访问。前端显示后端错误,不自动重试消耗额度。 8. 修改风格或身份文本不会自动重生成旧图。更换已锁定母版后,形态图库会根据 `identityAnchorImageId` 标记旧主图过期;主动生成候选、验图并切换主图,再更新下游首帧。Keyframe 就绪检查也会比对母版与形态主图引用,不应绕过过期提示继续生产。旧记录无追溯字段时不推断它已匹配当前母版。 diff --git a/docs/api-contract-sync.md b/docs/api-contract-sync.md new file mode 100644 index 0000000..18472be --- /dev/null +++ b/docs/api-contract-sync.md @@ -0,0 +1,32 @@ +# 接口数据同步说明 + +核对日期:2026-09-10。依据同级后端仓库 `short-drama-agent` 的 `HEAD=f0321c2`、`src/api/routes` 及实际资产 DTO/service 实现。本轮仅修改前端,沿用已完成页面和正式路由。 + +| 接口范围 | 精简后的公开数据 | 前端处理 | +| --- | --- | --- | +| 项目列表/详情 | 项目业务字段、characters、world、episodes;不含 reviews、tasks | 删除旧类型依赖;审核读取共享 checkpoint 的明确 reviewPassed,不伪造审核记录;生产预检从每条工作流最新 checkpoint 检查运行状态 | +| 视觉风格及参考图 | 风格保留可编辑 Prompt、hardConstraints 和 images;图片去除生成 Prompt | 保留编辑、锁定、图片登记和启停;移除图片内部提示词展示 | +| 主体身份查询/保存/生成 | id、subjectId、description、generationPrompt、isLocked、时间 | 图片继续通过独立 GET 查询,不从身份对象读取 images | +| 身份图片查询/生成/切母版 | 明确 isAnchor,不含 enabled、prompt、rawJson | 母版识别和切换结果校验统一使用 isAnchor;辅助视角仍不可设母版 | +| 角色选角确认 | identityId、subjectId、isLocked、anchor | 验证主体、身份、图片归属和母版标记,不再访问嵌套 identity | +| 形态图库/图片/主图 | identity.anchorImageId;图片仅含资产字段 | 正常预览、生成和切主图;移除依赖历史 rawJson 的身份过期推断及批量重生,保留下游 readiness 过期定位 | +| 形态正式 Prompt | 正式形态业务字段和时间,不含 subject、images 关联 | 单独声明回执类型;生成后重读图库,避免将单体回执当作图库记录 | +| 视频 Prompt | shotId、status、videoPrompt、negativePrompt、updatedAt | 两个页面均按 shotId 校验回执;保留正文展示与导出 | +| 首帧资产 | source、状态、图片、主图标记、模型与时间;无内部 Prompt/任务信息 | 保留候选和主图;source=provider_variant 的模型输入变体不可设业务主首帧 | +| 视频资产/单任务刷新 | 状态、地址、时长、isPrimary、模型和时间;无 rawJson/Provider Task/Prompt | 播放与状态使用公开字段;未知质量不显示通过或自动校验中 | +| 视频就绪/项目状态 | stale_prompt、provider_input_recovery;公开失败分类、retryable 和输入恢复状态 | 补齐类型和中文原因,显示不可普通重试提示;不解析内部失败快照 | +| 视频生成规格 | 业务 keyframe 和实际 providerInputKeyframe | 类型区分两种用途,规格面板展示实际输入 ID;尺寸允许后端 null | +| 失败视频重试 | totalFailed、retryable、skipped、retried、failed、failures | 显示可重试和跳过数,保留部分失败,不将 HTTP 成功当作全部重试成功 | +| 拆解、导演设计、即时状态、质量 POST、串联生产、诊断 | 已核对现有页面使用的正式路由与返回业务切片 | 保留原入口、参数、费用确认与失败处理;不增加测试/探针生成入口 | + +视频校验的新增运动、空间交互、道具结构及连接检查回执也已同步;专项未执行不显示通过,完整证据随结果导出。视频校验费用提示按一次请求可能调用多个模型说明。 + +## 质量数据边界 + +公开视频 DTO 不再带质量候选类型、历史校验和修复次数。后端自动质量链仍负责通过后晋升,前端以刷新后的 `isPrimary` 为准。普通手动设主入口要求本会话对此资产收到 PASS;修复要求本会话收到 FAIL。回执按项目、镜头、资产隔离,切页仍可查看,刷新浏览器后不伪造历史。重新校验会清除旧通过资格;失败的修复请求保留其依据的失败校验。次数上限由后端检查,错误原样呈现,不自动重试。 + +项目详情不再提供内部任务列表。公开 checkpoint 只能证明已记录工作流的状态,不能证明所有外部生成任务均已停止;保留现有的资产状态检查和操作确认。 + +## 回归验证范围 + +测试使用不包含旧内部字段的公开 DTO,覆盖页面加载、身份保存/选角、图片主图、Prompt 正式 ID、质量会话隔离、输入变体禁用、失败重试和缺失历史不误报过期。全部 API 使用模拟响应,不触发真实模型。此次不以自动化 DOM 测试代替浏览器视觉验收或真实后端联调。 diff --git a/docs/backend-coverage.md b/docs/backend-coverage.md index 7578498..94ea608 100644 --- a/docs/backend-coverage.md +++ b/docs/backend-coverage.md @@ -1,6 +1,6 @@ # 后端功能覆盖说明 -核对日期:2026-09-07。后端:`qianlanse/short-drama-agent`,`dev@697cf864e1e8d6f66e3ad7beeebdfd0ae0d6c16c`。以 API 路由和实际 service/workflow 实现为依据,不只根据接口名称推断功能。本轮不修改后端。 +核对日期:2026-09-10。后端:`qianlanse/short-drama-agent`,本地 `HEAD=f0321c2`。精简返回结构的适配详情见 [接口数据同步说明](api-contract-sync.md)。以 API 路由和实际 service/workflow 实现为依据,不只根据接口名称推断功能。本轮不修改后端。 ## 页面与接口能力 @@ -17,7 +17,7 @@ | 角色选角 | 主体身份角色模块 | `character-casting/readiness`、批量/单个 candidates、图片 `casting` | 保留候选、检查、确认母版并原子锁定 | | 身份参考图 | 主体身份图库 | `identity/images`、图片 `anchor` | 保留完整预览、历史、辅助视角与母版切换;修正道具继承说明 | | 正式形态提示词 | 形态卡片 → 提示词与生成;批量工具 | POST `subject-forms/:id/generation-prompt`、项目 `subject-forms/generation-prompts` | 新增单个生成/重生成、原始素材与正式文本对照、导出、批量补齐/覆盖及失败回执 | -| 形态图片 | 形态图片及图库 | 项目 `subject-forms`、形态 `images`、主图 PUT、项目 `subject-images/generate` | 增加本批数量上限;支持后端自动补正式 Prompt;人物/场景/道具已锁定母版继承;过期刷新只生成候选 | +| 形态图片 | 形态图片及图库 | 项目 `subject-forms`、形态 `images`、主图 PUT、项目 `subject-images/generate` | 增加本批数量上限;支持后端自动补正式 Prompt;人物/场景/道具已锁定母版继承;按需生成候选,历史母版信息不公开时不推断过期 | | 导演设计与即时状态 | 分镜设计 | directions/visual-states 查询、项目 `generate` | 只保留正式项目批量、覆盖、校验修复次数和逐集回执;不暴露 `generate-test` | | 参考图与规格 | 分镜参考图/生产单镜头 | `references`、`generation-spec`、`keyframe-spec`、`video-generation-spec` | 保留按需只读检查与缺失原因,查询不调用生成模型 | | 视频提示词 | 分镜设计/镜头生产 | 单镜头 `video-prompt`、项目 `video-prompts/readiness` 与 `generate` | 保留单镜头/项目生成,重写需确认 | @@ -27,7 +27,7 @@ ## 新增质量检查与修复 -已接入:首帧 `validate`、`repair`,项目 `keyframes/generate-quality`,视频 `validate`/`repair`,以及单镜头和项目级 `videos/generate-quality`。严格视频候选由后端 Poller 自动执行 Validator,失败时按上限创建 Repair Candidate,只有 PASS 才晋升 Primary;前端识别 `rawJson.qualityCandidate`,禁止未通过候选绕过校验手动设为主视频。生成请求不再传固定 Provider。质量接口的详细参数、默认一镜范围、费用确认、主图晋升、三点视频抽样和会话回执限制见 [前端简化与质量功能同步](frontend-simplification.md)。首帧校验历史尚无 GET,不虚构读取接口;视频已有结果从 `rawJson.videoValidation` 读取。 +已接入:首帧 `validate`、`repair`,项目 `keyframes/generate-quality`,视频 `validate`/`repair`,以及单镜头和项目级 `videos/generate-quality`。严格视频候选由后端 Poller 自动执行 Validator,失败时按上限创建 Repair Candidate,只有 PASS 才晋升 Primary;公开视频列表不再提供质量标记;前端只有在本会话收到 PASS 校验回执后才显示候选的手动设主入口。生成请求不再传固定 Provider。质量接口的详细参数、默认一镜范围、费用确认、主图晋升、视频抽样与专项检查和会话回执限制见 [前端简化与质量功能同步](frontend-simplification.md)。首帧和视频均不虚构质量历史 GET;校验回执按项目、镜头和资产 ID 保存在当前会话。 ## 高级串联生产边界 @@ -51,7 +51,7 @@ - 生产页将结构化 `stale_keyframe.missingSubjects` 映射到当前镜头 `/references` 返回的正式 `subjectFormId`,点击可定位图库中实际使用的形态;不按主体名称猜默认形态。缺少关联时退回主体引用检索并明确提示待核对。 - 图库始终读取 keyframes 与 videos 的 readiness,显示下游过期镜头数量;选择来源镜头后才查询其参考图,避免遍历全部镜头的 N+1 请求。只允许定位当前项目列表中的镜头。 - 图库深链接支持 `sourceShotId`、`subjectFormId` 和 `subjectRef`;精确形态优先,切换定位清除旧筛选,丢失的形态不自动回退其他形态。返回生产页携带 `episodeNo` 与正式 `shotId`。 -- “身份主图过期”与“下游首帧过期”独立展示。素材有效而首帧过期时,只需核对后重建首帧;定位、刷新、筛选不触发生成或切换主资产。 +- 形态图库不再有历史母版引用,已移除前端推导的“身份主图过期”筛选和批量重生入口。“下游首帧过期”仍读取后端 readiness;核对素材无误后可重建首帧;定位、刷新、筛选不触发生成或切换主资产。 - 本次后端基线已修复视频 readiness/compiler 缺少当前身份母版参数引起的过期误报。前端保留异常时的两种检查结果对照和“状态待核对”提示,不绕过后端阻塞或自动重复生图。 ## 不添加无效或重复入口 diff --git a/docs/frontend-simplification.md b/docs/frontend-simplification.md index 127c87d..dece738 100644 --- a/docs/frontend-simplification.md +++ b/docs/frontend-simplification.md @@ -1,6 +1,6 @@ # 前端简化与质量功能同步 -核对日期:2026-09-03。后端 dev 基线:`05bb9e8b7e0a0e85303b16eb3a2ac634e01dd7eb`。本次只改前端,不更改数据库、后端配置或生成资产。 +核对日期:2026-09-10。后端本地基线:`f0321c2`。精简返回结构见 [接口数据同步说明](api-contract-sync.md)。本次只改前端,不更改数据库、后端配置或生成资产。 ## 页面保留什么、收起什么 @@ -37,7 +37,7 @@ | 生产工具栏 → 首帧质量生成 | POST `/projects/:projectId/keyframes/generate-quality` | 当前集、默认最多一镜、并发 1、最多修复 1 次;每镜候选通过后才设主图 | | 单镜头 → 提交视频质量任务 | POST `/storyboard-shots/:shotId/videos/generate-quality` | 创建严格质量候选;生成完成后由后端自动校验,失败时最多自动修复 2 次,通过后才晋升主视频 | | 批量生产 → 视频成片 | POST `/projects/:projectId/videos/generate-quality` | 显式限制本批镜头数和每镜修复次数;只提交 ready 镜头,后续 Validator/Repair 由 Poller 推进 | -| 已完成视频 → 质量检查 | POST `/storyboard-shots/:shotId/videos/:videoId/validate` | 三点抽帧视觉检查,不检测音频/口型/完整连续运动;普通候选不切换主视频,修复候选通过后自动晋升 | +| 已完成视频 → 质量检查 | POST `/storyboard-shots/:shotId/videos/:videoId/validate` | 抽样视觉与按需运动/道具专项检查,不检测音频/口型;普通候选不切换主视频,修复候选通过后自动晋升 | 批量质量配置与普通批量面板独立。后端非 force 先根据全项目是否有过期项决定筛选,再筛当前集;因此其他集存在过期项而当前集无过期项时,本集不会先补缺失首帧。前端明确提示切换剧集,不悄悄扩大范围。 @@ -45,19 +45,19 @@ ### 视频自动质量链与手工复检 -生产页的单镜和批量视频主入口使用 `generate-quality`。HTTP 回执只表示初始 Candidate 已创建;后台 Poller 会在 Provider 完成后自动执行 Validator,失败时按 `maxRepairAttempts` 创建下一代 Repair Candidate,只有通过校验的版本才会晋升 Primary。前端读取 `rawJson.qualityCandidate` 和 `qualityPipeline` 标记质量候选,并禁止未通过候选使用普通“设为主视频”绕过校验。 +生产页的单镜和批量视频主入口使用 `generate-quality`。HTTP 回执只表示初始 Candidate 已创建;后台 Poller 会在 Provider 完成后自动执行 Validator,失败时按 `maxRepairAttempts` 创建下一代 Repair Candidate,只有通过校验的版本才会晋升 Primary。公开视频列表不再提供 `rawJson`。前端以资产 `isPrimary` 展示晋升结果;只有本会话收到 PASS 校验的候选才可使用手动“设为主视频”。不会将缺少历史质量数据标为自动校验中或通过。 视频质量面板新增“生成修复候选”,使用 POST `/storyboard-shots/:shotId/videos/:videoId/repair`,只接受 `maxRepairAttempts`(默认 2,正整数)。该参数是修复链的上限,不是本次自动生成次数。本次只提交一个视频候选,不自动等待、复检或循环重试;修复约束和允许文字沿用已保存的失败校验。 -确认后重新读取视频,未校验、校验已通过、链路到达上限或镜头有活动视频时不提交。候选完成后仍不是主视频,需要对新候选显式执行视觉校验;后端通过后自动晋升,界面在付费确认前说明后果,并显示实际晋升结果。未通过复检的修复候选不提供普通“设为主视频”按钮,不能绕过验收。 +确认后重新读取视频;本会话没有失败校验或镜头有活动视频时不提交。修复链次数不再由内部 JSON 推断,交由后端校验并显示其失败原因。候选完成后仍不是主视频,需要对新候选显式执行视觉校验;后端通过后自动晋升,界面在付费确认前说明后果,并显示实际晋升结果。未通过复检的修复候选不提供普通“设为主视频”按钮,不能绕过验收。 ### 状态与风险控制 - 打开页面、菜单、结果和模型能力不会自动调用生成/视觉模型。质量 POST 只在确认后发生,不自动超时重试。 -- 确认后再次 GET 项目完成状态、活动任务、项目镜头列表与目标资产归属。视频必须有完成状态、地址和有效时长;首帧必须完成且有图片。修复和小批量质量生成先检查模型参考图能力,批次检查当前镜头是否仍在生图。 +- 确认后再次 GET 项目完成状态、工作流 checkpoint、项目镜头列表与目标资产归属。项目详情已无内部任务数组,只检查公开工作流执行状态和资产活动状态。视频必须有完成状态、地址和有效时长;首帧必须完成且有图片。修复和小批量质量生成先检查模型参考图能力,批次检查当前镜头是否仍在生图。 - 预检期间关闭面板或换目标不发送 POST。已提交请求继续运行,回执按原项目/镜头/资产保存,不能写入新项目。当前浏览器项目互斥不能代替后端跨客户端锁;仍需确认外部任务停止。 - 结果分别显示视觉通过、修复未通过、调用失败、未执行;不会把 HTTP 200 当质量通过。批量回执提供定位镜头,完整主体检查/逐轮耗时/原始回执可展开和导出。 -- 视频历史结果直接从 `rawJson.videoValidation` 读取,不为“查看结果”重新调用视觉模型。它是历史抽样结论,不保证当前引用仍一致。 +- 视频列表不再返回质量历史;查看本会话校验回执不会重新调用模型。浏览器刷新后不保留通过结论;修复请求失败保留其所依据的失败校验。 - 后端持久化首帧校验,但尚无历史读取 GET。前端只显示当前会话确实收到的首帧回执并支持导出,不虚构历史接口。 - 后端已修复视频校验漏传身份母版导致的过期误报。前端保留两种就绪结果冲突时的防御性提示,不绕过后端阻塞、不自动重复生成。 diff --git a/src/components/ui/AppForm.vue b/src/components/ui/AppForm.vue new file mode 100644 index 0000000..9959962 --- /dev/null +++ b/src/components/ui/AppForm.vue @@ -0,0 +1,119 @@ + + + + diff --git a/src/components/ui/DetailDisclosure.vue b/src/components/ui/DetailDisclosure.vue index 7395495..bfeac00 100644 --- a/src/components/ui/DetailDisclosure.vue +++ b/src/components/ui/DetailDisclosure.vue @@ -9,6 +9,11 @@ const expanded = ref([]) function toggle() { expanded.value = expanded.value.length ? [] : ['details'] } +defineExpose({ + expand: () => { + expanded.value = ['details'] + } +})