feat: 同步质量校验修复并精简工作台操作

This commit is contained in:
GouJ
2026-09-03 19:38:57 +08:00
parent 771b66cafc
commit 13bb6dc83b
47 changed files with 2244 additions and 260 deletions
+37 -25
View File
@@ -17,7 +17,7 @@ import { ArrowLeft, CheckCircle2, CircleAlert, Film, Image, MessageSquareText, R
import { EmptyState, StatusBadge } from '../../components/ui'
import BeatShotDirectory from '../storyboard/components/BeatShotDirectory.vue'
import ConfirmAction from '../workflows/ConfirmAction.vue'
import { issueLabel, productionStatusLabel } from './model'
import { productionStatusLabel } from './model'
import { useProduction } from './useProduction'
import ProductionReceipt from './components/ProductionReceipt.vue'
import ShotProductionAssets from './components/ShotProductionAssets.vue'
@@ -25,6 +25,9 @@ import AdvancedProduction from './components/AdvancedProduction.vue'
import StaleKeyframeNotice from './components/StaleKeyframeNotice.vue'
import { routeLocationKey } from 'vue-router'
import { queryText } from './asset-links'
import QualityDialog from './components/QualityDialog.vue'
import DetailDisclosure from '../../components/ui/DetailDisclosure.vue'
const qualityOpen = ref(false)
/** 镜头生产页将项目批处理与单镜头资产管理放在同一条可核验链路中。 */
const {
@@ -87,7 +90,7 @@ const stages = computed(() => {
key: 'keyframes' as const,
code: '02',
title: '镜头首帧',
description: '合并视觉风格、镜头规格和主体参考图,调用 Seedream 生成。',
description: '合并视觉风格、镜头规格和主体参考图,调用图片模型生成。',
icon: Image,
data: data?.keyframes,
done: data?.keyframes.skipped ?? 0,
@@ -97,7 +100,7 @@ const stages = computed(() => {
key: 'videos' as const,
code: '03',
title: '视频成片',
description: '以主首帧作为第一帧,连同提示词和主体参考图提交 Seedance。',
description: '以主首帧作为第一帧,连同提示词和主体参考图提交视频模型。',
icon: Film,
data: data?.videos,
done: data?.videoStatus.completed ?? 0,
@@ -112,7 +115,6 @@ const stages = computed(() => {
const selectedIssues = computed(() =>
[promptItem.value, keyframeItem.value, videoItem.value].flatMap(item => item?.issues ?? [])
)
const remainingIssues = computed(() => selectedIssues.value.filter(issue => issue.code !== 'stale_keyframe'))
const selectedKeyframeStale = computed(
() =>
!!keyframeItem.value?.primaryKeyframeStale ||
@@ -136,6 +138,11 @@ const staleKeyframes = computed(() => query.data.value?.keyframes.stalePrimaryKe
function refreshProject() {
void query.refresh()
}
/** 从质量回执定位本集正式镜头,关闭弹窗不会触发任何生成请求。 */
function locateQualityShot(shotId: string) {
selectedShot.value = shotId
qualityOpen.value = false
}
/** 新回执自动展开,避免折叠区隐藏部分失败诊断。 */
const toolsOpen = ref(false)
const overview = ref<string[]>(['overview'])
@@ -181,17 +188,20 @@ watch(
></span
>
<div class="toolbar-actions">
<NButton :disabled="blocked || !episodeNo" @click="qualityOpen = true">首帧质量生成</NButton>
<NButton
:disabled="query.loading.value"
@click="query.refresh"
text
size="small"
class="mb-2 ml-auto"
><RefreshCw :size="13" :class="{ 'animate-spin': query.loading.value }" />刷新就绪状态
quaternary
class="icon-button"
aria-label="刷新就绪状态"
title="刷新就绪状态"
><RefreshCw :size="16" :class="{ 'animate-spin': query.loading.value }" />
</NButton>
<WorkspaceTools
v-model:open="toolsOpen"
title="项目生产总览与批量操作"
label="批量生产"
:has-receipt="!!session.receipt || !!session.pipelineReceipt"
>
<div class="flex flex-wrap items-end justify-between gap-4">
@@ -225,18 +235,17 @@ watch(
>覆盖模式重写提示词新增图视频候选
</NCheckbox>
</div>
<p class="mt-3 text-[11px] leading-6 text-muted">
提示词与视频批量操作面向全项目首帧默认补当前剧集存在过期主首帧时优先更新全项目过期项覆盖模式处理全项目过期首帧成功后会自动接替旧主图其余新增候选Seedream
Seedance 均可能产生费用
</p>
<DetailDisclosure title="处理范围与覆盖规则" class="mt-3"
><p class="text-xs leading-6 text-muted">
提示词与视频批量操作面向全项目首帧默认补当前剧集存在过期主首帧时优先更新全项目过期项覆盖模式处理全项目过期首帧成功后会自动接替旧主图其余新增候选图片模型
与视频模型均可能产生费用
</p></DetailDisclosure
>
</section>
<div class="workspace-overview-panel">
<NCollapse v-model:expanded-names="overview"
><NCollapseItem name="overview" title="项目生产总览与批量操作"
><div class="overview-content">
<NAlert type="info" :show-icon="false" class="mt-5 text-xs">
每一步都按后端就绪检查执行覆盖会重写提示词图片和视频通常新增候选但过期首帧即使在覆盖模式也会更新为主图上游资产变化后请先更新过期结果再继续生产
</NAlert>
<NAlert
v-if="videoRunning"
role="status"
@@ -372,8 +381,8 @@ watch(
:description="
stage.key === 'videos'
? staleVideos && !force
? '当前存在过期主视频,非覆盖模式只会为这些镜头创建新的 Seedance 任务;新视频完成后会自动接替过期主视频。'
: '只为当前就绪镜头创建 Seedance 异步任务。创建成功不代表视频已经完成,任务会在后台继续运行。'
? '当前存在过期主视频,非覆盖模式只会为这些镜头创建新的视频模型任务;新视频完成后会自动接替过期主视频。'
: '只为当前就绪镜头创建视频模型异步任务。创建成功不代表视频已经完成,任务会在后台继续运行。'
: stage.key === 'keyframes'
? `处理缺失或过期主首帧。过期首帧成功后自动接替旧主图(覆盖模式也如此),其余已有主图只新增候选。本批上限:${keyframeLimit || '不限制'};尺寸:${keyframeWidth && keyframeHeight ? `${keyframeWidth} × ${keyframeHeight}` : '后端默认'}。`
: '只处理通过视频提示词就绪检查的镜头;覆盖模式会重写已有提示词。'
@@ -431,7 +440,7 @@ watch(
blocked || !batchValid || !query.data.value.videoStatus.failed
"
acknowledgement
description="为当前最近一次状态为失败的镜头重新创建 Seedance 任务。成功镜头和进行中的镜头不会处理。"
description="为当前最近一次状态为失败的镜头重新创建视频模型任务。成功镜头和进行中的镜头不会处理。"
@confirm="run('retry-videos')"
/>
</div>
@@ -576,11 +585,6 @@ watch(
>
主视频已过期:当前主首帧或主体参考图与生成该视频时不一致。旧视频仍保留,但需要重新生成后才能作为当前有效成片。
</NAlert>
<ul v-if="remainingIssues.length" class="alert alert-error mt-4 space-y-1" role="alert">
<li v-for="(issue, index) in remainingIssues" :key="`${issue.code}-${index}`">
{{ issueLabel(issue.code) }}{{ issue.reason }}
</li>
</ul>
</header>
<ShotProductionAssets
:key="shot.shotId"
@@ -604,6 +608,14 @@ watch(
</EmptyState>
<p v-else-if="query.loading.value" class="panel mt-5 p-8 text-sm text-muted" role="status">
正在检查全项目生产就绪状态……
</p></WorkspacePage
>
</p>
<QualityDialog
v-model:open="qualityOpen"
:project-id="id"
:target="episodeNo ? { kind: 'batch', episodeNo, title: `第 ${episodeNo} 集首帧` } : null"
:disabled="blocked"
@changed="refreshProject"
@locate="locateQualityShot"
/>
</WorkspacePage>
</template>