feat: 生产页展示过期首帧状态
This commit is contained in:
@@ -52,7 +52,7 @@ const stages = computed(() => {
|
|||||||
icon: Image,
|
icon: Image,
|
||||||
data: data?.keyframes,
|
data: data?.keyframes,
|
||||||
done: data?.keyframes.skipped ?? 0,
|
done: data?.keyframes.skipped ?? 0,
|
||||||
action: force.value ? '为全部镜头新增首帧' : '补齐主首帧'
|
action: force.value ? '为全部镜头新增首帧' : '补齐 / 更新主首帧'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'videos' as const,
|
key: 'videos' as const,
|
||||||
@@ -81,6 +81,7 @@ const identityBlocked = computed(
|
|||||||
(query.data.value?.keyframes.missingIdentityAnchor ?? 0) +
|
(query.data.value?.keyframes.missingIdentityAnchor ?? 0) +
|
||||||
(query.data.value?.keyframes.identityUnlocked ?? 0)
|
(query.data.value?.keyframes.identityUnlocked ?? 0)
|
||||||
)
|
)
|
||||||
|
const staleKeyframes = computed(() => query.data.value?.keyframes.stalePrimaryKeyframe ?? 0)
|
||||||
|
|
||||||
/** 父页查询包含整个项目的就绪统计,单镜头变更后立即刷新。 */
|
/** 父页查询包含整个项目的就绪统计,单镜头变更后立即刷新。 */
|
||||||
function refreshProject() {
|
function refreshProject() {
|
||||||
@@ -100,7 +101,7 @@ function refreshProject() {
|
|||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
<p class="alert mt-5 text-xs">
|
<p class="alert mt-5 text-xs">
|
||||||
每一步都按后端就绪检查执行。覆盖只会新增首帧/视频候选,不会替换当前主资产;重新生成上游内容后,也不会自动更新已有下游结果。
|
每一步都按后端就绪检查执行。覆盖只会新增首帧/视频候选,不会替换当前主资产;上游参考资产变化后,下游过期结果会被标记并阻止继续使用,需要重新生成后才能恢复就绪。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<section class="panel mt-5 p-5" aria-label="项目生产配置">
|
<section class="panel mt-5 p-5" aria-label="项目生产配置">
|
||||||
@@ -160,6 +161,9 @@ function refreshProject() {
|
|||||||
Identity、确认演员母版并锁定后,首帧才能就绪。
|
Identity、确认演员母版并锁定后,首帧才能就绪。
|
||||||
<RouterLink :to="`/projects/${id}/subject-identity`" class="text-button ml-2">前往角色选角 →</RouterLink>
|
<RouterLink :to="`/projects/${id}/subject-identity`" class="text-button ml-2">前往角色选角 →</RouterLink>
|
||||||
</p>
|
</p>
|
||||||
|
<p v-if="staleKeyframes" class="alert mt-4" role="status">
|
||||||
|
当前有 {{ staleKeyframes }} 个主首帧已过期。它们使用的主体参考资产已经变化,视频阶段会被阻止;可在下方逐镜重新生成,或使用“补齐 / 更新主首帧”批量处理。
|
||||||
|
</p>
|
||||||
<ProductionReceipt v-if="session.receipt" :receipt="session.receipt" />
|
<ProductionReceipt v-if="session.receipt" :receipt="session.receipt" />
|
||||||
|
|
||||||
<div v-if="query.data.value" class="production-pipeline mt-5">
|
<div v-if="query.data.value" class="production-pipeline mt-5">
|
||||||
@@ -202,6 +206,9 @@ function refreshProject() {
|
|||||||
<dd>{{ stage.data?.blocked ?? 0 }}</dd>
|
<dd>{{ stage.data?.blocked ?? 0 }}</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
|
<p v-if="stage.key === 'keyframes' && staleKeyframes" class="mt-3 text-[11px] leading-5">
|
||||||
|
已过期 {{ staleKeyframes }} · 会按当前主体参考资产重新生成
|
||||||
|
</p>
|
||||||
<p v-if="stage.key === 'keyframes' && identityBlocked" class="mt-3 text-[11px] leading-5 text-danger">
|
<p v-if="stage.key === 'keyframes' && identityBlocked" class="mt-3 text-[11px] leading-5 text-danger">
|
||||||
身份缺失 {{ query.data.value?.keyframes.missingIdentity ?? 0 }} · 母版缺失
|
身份缺失 {{ query.data.value?.keyframes.missingIdentity ?? 0 }} · 母版缺失
|
||||||
{{ query.data.value?.keyframes.missingIdentityAnchor ?? 0 }} · 未锁定
|
{{ query.data.value?.keyframes.missingIdentityAnchor ?? 0 }} · 未锁定
|
||||||
@@ -216,7 +223,7 @@ function refreshProject() {
|
|||||||
stage.key === 'videos'
|
stage.key === 'videos'
|
||||||
? '只为当前就绪镜头创建 Seedance 异步任务。创建成功不代表视频已经完成,任务会在后台继续运行。'
|
? '只为当前就绪镜头创建 Seedance 异步任务。创建成功不代表视频已经完成,任务会在后台继续运行。'
|
||||||
: stage.key === 'keyframes'
|
: stage.key === 'keyframes'
|
||||||
? '只为当前就绪镜头调用 Seedream。覆盖模式会新增候选,不替换已有主首帧。'
|
? '处理缺失主首帧和参考资产已变化的过期主首帧。过期镜头会按当前主体参考资产重新生成并恢复为可用于视频的主首帧;覆盖模式只新增候选。'
|
||||||
: '只处理通过视频提示词就绪检查的镜头;覆盖模式会重写已有提示词。'
|
: '只处理通过视频提示词就绪检查的镜头;覆盖模式会重写已有提示词。'
|
||||||
"
|
"
|
||||||
:primary="stage.key === 'videos'"
|
:primary="stage.key === 'videos'"
|
||||||
@@ -281,7 +288,13 @@ function refreshProject() {
|
|||||||
>
|
>
|
||||||
<span class="font-mono text-[10px] text-muted">B{{ item.beatNo }} / S{{ item.shotNo }}</span>
|
<span class="font-mono text-[10px] text-muted">B{{ item.beatNo }} / S{{ item.shotNo }}</span>
|
||||||
<span class="mt-1 block truncate text-xs font-medium">{{ item.title }}</span>
|
<span class="mt-1 block truncate text-xs font-medium">{{ item.title }}</span>
|
||||||
<span class="mt-2 flex items-center gap-2 text-[10px] text-muted">
|
<span
|
||||||
|
v-if="query.data.value?.keyframes.items.find(row => row.shotId === item.shotId)?.primaryKeyframeStale"
|
||||||
|
class="mt-2 flex items-center gap-2 text-[10px]"
|
||||||
|
>
|
||||||
|
<CircleAlert :size="12" />主首帧已过期
|
||||||
|
</span>
|
||||||
|
<span v-else class="mt-2 flex items-center gap-2 text-[10px] text-muted">
|
||||||
<CheckCircle2
|
<CheckCircle2
|
||||||
v-if="
|
v-if="
|
||||||
query.data.value?.videos.items.find(row => row.shotId === item.shotId)?.status ===
|
query.data.value?.videos.items.find(row => row.shotId === item.shotId)?.status ===
|
||||||
@@ -320,6 +333,9 @@ function refreshProject() {
|
|||||||
</div>
|
</div>
|
||||||
<p v-if="shot.description" class="mt-3 text-sm leading-7">{{ shot.description }}</p>
|
<p v-if="shot.description" class="mt-3 text-sm leading-7">{{ shot.description }}</p>
|
||||||
<p class="mt-3 break-all font-mono text-[10px] text-muted">Shot ID · {{ shot.shotId }}</p>
|
<p class="mt-3 break-all font-mono text-[10px] text-muted">Shot ID · {{ shot.shotId }}</p>
|
||||||
|
<p v-if="keyframeItem?.primaryKeyframeStale" class="alert mt-4 text-xs" role="status">
|
||||||
|
主首帧已过期:当前主体参考资产与生成该首帧时不一致。旧首帧会保留,但不能继续用于视频生成。
|
||||||
|
</p>
|
||||||
<ul v-if="selectedIssues.length" class="alert alert-error mt-4 space-y-1" role="alert">
|
<ul v-if="selectedIssues.length" class="alert alert-error mt-4 space-y-1" role="alert">
|
||||||
<li v-for="(issue, index) in selectedIssues" :key="`${issue.code}-${index}`">
|
<li v-for="(issue, index) in selectedIssues" :key="`${issue.code}-${index}`">
|
||||||
{{ issueLabel(issue.code) }}:{{ issue.reason }}
|
{{ issueLabel(issue.code) }}:{{ issue.reason }}
|
||||||
|
|||||||
Reference in New Issue
Block a user