feat: 同步精简接口并统一表单校验
This commit is contained in:
@@ -27,7 +27,7 @@ import ActionMenu from '../../../components/ui/ActionMenu.vue'
|
||||
import { AppDialog } from '../../../components/ui'
|
||||
import ModelCapabilities from './ModelCapabilities.vue'
|
||||
import type { QualityTarget } from '../quality.types'
|
||||
import { savedVideoValidation, videoQualityInfo, videoRepairInfo } from '../quality'
|
||||
import { sessionVideoValidation } from '../quality'
|
||||
|
||||
/** 单镜头生产面板只负责正式资产,不修改上游导演设计与即时状态。 */
|
||||
const props = defineProps<{
|
||||
@@ -64,10 +64,6 @@ const assetBlocked = computed(() => props.disabled || operation.value.pending ||
|
||||
const keyframeOpen = ref(false)
|
||||
const qualityOpen = ref(false)
|
||||
const qualityTarget = ref<QualityTarget | null>(null)
|
||||
const qualityRawJson = computed(() => {
|
||||
const target = qualityTarget.value
|
||||
return target?.kind === 'video' ? (videos.value.find(item => item.id === target.assetId)?.rawJson ?? null) : null
|
||||
})
|
||||
const specsOpen = ref(false)
|
||||
|
||||
/** 从实际候选打开质量面板,保留单镜头主操作,不默认展开全部校验参数。 */
|
||||
@@ -132,7 +128,7 @@ async function generatePrompt() {
|
||||
const overwrite = props.promptReadiness?.status === 'skipped'
|
||||
await runOperation(props.projectId, `生成镜头 ${props.shot.shotNo} 视频提示词`, async () => {
|
||||
const result = await storyboardApi.generatePrompt(shotId, overwrite)
|
||||
if (!result || result.id !== shotId || !result.videoPrompt) throw new Error('接口未返回有效视频提示词。')
|
||||
if (!result || result.shotId !== shotId || !result.videoPrompt) throw new Error('接口未返回有效视频提示词。')
|
||||
})
|
||||
await refreshAll()
|
||||
}
|
||||
@@ -151,7 +147,12 @@ async function generateKeyframe(input: GenerateKeyframeInput) {
|
||||
/** 切换主首帧不调用模型,但会改变后续视频生成输入。 */
|
||||
async function setPrimaryKeyframe() {
|
||||
const keyframeId = confirmingKeyframe.value
|
||||
if (assetBlocked.value || !keyframeId) return
|
||||
if (
|
||||
assetBlocked.value ||
|
||||
!keyframeId ||
|
||||
keyframes.value.find(item => item.id === keyframeId)?.source === 'provider_variant'
|
||||
)
|
||||
return
|
||||
const shotId = props.shot.shotId
|
||||
confirmingKeyframe.value = ''
|
||||
await runOperation(props.projectId, `设置镜头 ${props.shot.shotNo} 主首帧`, async () => {
|
||||
@@ -195,8 +196,9 @@ async function setPrimaryVideo() {
|
||||
const video = videos.value.find(item => item.id === videoId)
|
||||
if (
|
||||
!video ||
|
||||
((videoRepairInfo(video.rawJson) || videoQualityInfo(video.rawJson)) &&
|
||||
savedVideoValidation(video.rawJson)?.passed !== true)
|
||||
video.status !== 'completed' ||
|
||||
!video.videoUrl ||
|
||||
sessionVideoValidation(props.projectId, video.shotId, video.id)?.passed !== true
|
||||
)
|
||||
return
|
||||
const shotId = props.shot.shotId
|
||||
@@ -322,6 +324,9 @@ async function inspectSpecs() {
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<StatusBadge :status="item.status" :label="productionStatusLabel(item.status)" />
|
||||
<NTag v-if="item.isPrimary" size="small" :bordered="false">主首帧</NTag>
|
||||
<NTag v-if="item.source === 'provider_variant'" size="small" :bordered="false"
|
||||
>模型输入变体</NTag
|
||||
>
|
||||
<NTag v-if="item.isPrimary && keyframeStale" size="small" :bordered="false">已过期</NTag>
|
||||
<span class="text-[10px] text-muted"
|
||||
>{{ item.width || '—' }} × {{ item.height || '—' }}</span
|
||||
@@ -338,7 +343,12 @@ async function inspectSpecs() {
|
||||
>质量检查</NButton
|
||||
>
|
||||
<NButton
|
||||
v-if="item.status === 'completed' && item.imageUrl && !item.isPrimary"
|
||||
v-if="
|
||||
item.status === 'completed' &&
|
||||
item.imageUrl &&
|
||||
item.source !== 'provider_variant' &&
|
||||
!item.isPrimary
|
||||
"
|
||||
:disabled="assetBlocked"
|
||||
@click="confirmingKeyframe = item.id"
|
||||
text
|
||||
@@ -401,22 +411,7 @@ async function inspectSpecs() {
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<StatusBadge :status="item.status" :label="productionStatusLabel(item.status)" />
|
||||
<NTag v-if="item.isPrimary" size="small" :bordered="false">主视频</NTag>
|
||||
<NTag v-if="videoRepairInfo(item.rawJson) && !item.isPrimary" size="small" :bordered="false"
|
||||
>修复候选 · 待复检</NTag
|
||||
>
|
||||
<NTag
|
||||
v-else-if="videoQualityInfo(item.rawJson) && !item.isPrimary"
|
||||
size="small"
|
||||
:bordered="false"
|
||||
>质量候选 ·
|
||||
{{
|
||||
savedVideoValidation(item.rawJson)
|
||||
? savedVideoValidation(item.rawJson)?.passed
|
||||
? '已通过'
|
||||
: '未通过'
|
||||
: '自动校验中'
|
||||
}}</NTag
|
||||
>
|
||||
<NTag v-if="!item.isPrimary" size="small" :bordered="false">候选视频</NTag>
|
||||
<NTag v-if="item.isPrimary && videoStale" size="small" :bordered="false">已过期</NTag>
|
||||
<span class="text-[10px] text-muted"
|
||||
>{{ item.durationSeconds || shot.durationSeconds || '—' }}s</span
|
||||
@@ -434,8 +429,13 @@ async function inspectSpecs() {
|
||||
text
|
||||
size="small"
|
||||
@click="openQuality('video', item.id)"
|
||||
>质量检查<template v-if="savedVideoValidation(item.rawJson)">
|
||||
· {{ savedVideoValidation(item.rawJson)?.passed ? '曾通过' : '未通过' }}</template
|
||||
>质量检查<template v-if="sessionVideoValidation(projectId, item.shotId, item.id)">
|
||||
·
|
||||
{{
|
||||
sessionVideoValidation(projectId, item.shotId, item.id)?.passed
|
||||
? '曾通过'
|
||||
: '未通过'
|
||||
}}</template
|
||||
></NButton
|
||||
>
|
||||
<a
|
||||
@@ -451,8 +451,7 @@ async function inspectSpecs() {
|
||||
item.status === 'completed' &&
|
||||
item.videoUrl &&
|
||||
!item.isPrimary &&
|
||||
(!(videoRepairInfo(item.rawJson) || videoQualityInfo(item.rawJson)) ||
|
||||
savedVideoValidation(item.rawJson)?.passed === true)
|
||||
sessionVideoValidation(projectId, item.shotId, item.id)?.passed === true
|
||||
"
|
||||
:disabled="assetBlocked"
|
||||
@click="confirmingVideo = item.id"
|
||||
@@ -473,6 +472,9 @@ async function inspectSpecs() {
|
||||
</article>
|
||||
</div>
|
||||
<p v-else class="mt-4 text-xs text-muted">尚无视频任务记录。</p>
|
||||
<p v-if="videos.some(item => !item.isPrimary)" class="mt-3 text-xs text-muted">
|
||||
候选视频的历史质量结果未公开;手动设为主视频前需在本会话完成视觉校验。自动质量任务的晋升结果以刷新后的主视频标记为准。
|
||||
</p>
|
||||
<div class="mt-4 flex flex-wrap gap-3">
|
||||
<ConfirmAction
|
||||
:label="
|
||||
@@ -525,7 +527,15 @@ async function inspectSpecs() {
|
||||
Negative prompt: {{ videoSpec.negativePrompt }}
|
||||
</p>
|
||||
<p class="mt-3 break-all font-mono text-[10px] text-muted">
|
||||
Keyframe ID · {{ videoSpec.keyframe.id }}
|
||||
业务主首帧 ID · {{ videoSpec.keyframe.id }}
|
||||
</p>
|
||||
<p v-if="videoSpec.providerInputKeyframe" class="mt-2 break-all text-[10px] text-muted">
|
||||
模型输入首帧 ID · {{ videoSpec.providerInputKeyframe.id }}
|
||||
{{
|
||||
videoSpec.providerInputKeyframe.source === 'provider_variant'
|
||||
? '(专用变体)'
|
||||
: '(业务主首帧)'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div></NCollapseItem
|
||||
@@ -537,7 +547,6 @@ async function inspectSpecs() {
|
||||
:project-id="projectId"
|
||||
:target="qualityTarget"
|
||||
:disabled="assetBlocked"
|
||||
:saved-raw-json="qualityRawJson"
|
||||
@changed="refreshAll"
|
||||
/>
|
||||
<KeyframeDialog
|
||||
|
||||
Reference in New Issue
Block a user