diff --git a/src/features/storyboard/StoryboardPage.vue b/src/features/storyboard/StoryboardPage.vue index e0fdb1a..aa10e6b 100644 --- a/src/features/storyboard/StoryboardPage.vue +++ b/src/features/storyboard/StoryboardPage.vue @@ -50,6 +50,7 @@ const { repairsValid, blocked, directionComplete, + hasCurrentEpisodeShots, run } = useStoryboard() const coverage = computed(() => [ @@ -217,6 +218,31 @@ watch(
+
+
+

+ 00本集镜头拆解 +

+

+ 只重新拆解当前选择的第 + {{ episodeNo }} + 集,其它剧集不受影响。新镜头会替换旧镜头,并清空本集已有的导演设计、即时状态、首帧与视频结果。 +

+
+
+ +
+
+

+ 当前集尚无正式 Storyboard Shot,不能执行单集重生成;请先完成拆解流程。 +

diff --git a/src/features/storyboard/api.ts b/src/features/storyboard/api.ts index fd8a673..2777099 100644 --- a/src/features/storyboard/api.ts +++ b/src/features/storyboard/api.ts @@ -7,6 +7,7 @@ import type { ShotReferences, StoryboardBatchInput, StoryboardBatchResult, + StoryboardShotRegenerationResult, VisualStateBatchInput } from './types' import type { ShotGenerationSpec } from './generation-spec.types' @@ -23,6 +24,13 @@ function shotPath(id: string) { /** Storyboard 正式路由契约;测试路由不暴露为前端生产入口。 */ export const storyboardApi = { + /** 强制重生成指定单集的镜头拆解;后端校验通过后才覆盖正式 Storyboard。 */ + regenerateEpisodeShots: (id: string, episodeNo: number) => + request(`${projectPath(id)}/storyboard-shots/regenerate`, { + method: 'POST', + body: { episodeNo }, + timeoutMs: 0 + }), directions: (id: string, episodeNo: number, signal?: AbortSignal) => request(`${projectPath(id)}/storyboard-directions?episodeNo=${episodeNo}`, { signal }), visualStates: (id: string, episodeNo: number, signal?: AbortSignal) => diff --git a/src/features/storyboard/components/GenerationReceipt.vue b/src/features/storyboard/components/GenerationReceipt.vue index 45195a8..45563ae 100644 --- a/src/features/storyboard/components/GenerationReceipt.vue +++ b/src/features/storyboard/components/GenerationReceipt.vue @@ -7,9 +7,11 @@ import type { StoryboardReceipt } from '../types' /** 独立展示提交结果,不能将 HTTP 成功或局部成功显示为整批完成。 */ const props = defineProps<{ receipt: StoryboardReceipt }>() -const failed = computed(() => - props.receipt.kind === 'batch' ? props.receipt.result.failedEpisodes > 0 : props.receipt.result.failed > 0 -) +const failed = computed(() => { + if (props.receipt.kind === 'shots') return !props.receipt.result.storyboardShotValidation.valid + if (props.receipt.kind === 'batch') return props.receipt.result.failedEpisodes > 0 + return props.receipt.result.failed > 0 +}) /** 导出原始回执,保留后端提供的完整失败诊断。 */ function exportReceipt() { @@ -26,7 +28,23 @@ function exportReceipt() { 本次存在失败、校验未通过或未保存项。关闭“批量覆盖已有结果”后再补齐,可跳过已完整保存项。 -