feat: 同步精简接口并统一表单校验

This commit is contained in:
GJ
2026-09-10 22:34:47 +08:00
parent 82d7bde631
commit 2eea0ea72e
66 changed files with 1611 additions and 1100 deletions
+86 -44
View File
@@ -1,4 +1,7 @@
<script setup lang="ts">
import AppForm from '../../components/ui/AppForm.vue'
import { NFormItem } from 'naive-ui'
import { integerRule, sizeRules } from '../../lib/form-rules'
import WorkspacePage from '../../components/ui/WorkspacePage.vue'
import WorkspaceTools from '../../components/ui/WorkspaceTools.vue'
import {
@@ -164,6 +167,21 @@ watch(
if (receipt) toolsOpen.value = true
}
)
const batchModel = computed(() => ({ concurrency: concurrency.value }))
const batchRules = { concurrency: integerRule('批量并发') }
const keyframeModel = computed(() => ({
keyframeLimit: keyframeLimit.value,
keyframeWidth: keyframeWidth.value,
keyframeHeight: keyframeHeight.value
}))
const dimensionRules = sizeRules(() => ({ width: keyframeWidth.value, height: keyframeHeight.value }))
const keyframeRules = {
keyframeLimit: integerRule('本批上限', 1, true),
keyframeWidth: dimensionRules.width,
keyframeHeight: dimensionRules.height
}
const videoModel = computed(() => ({ videoLimit: videoLimit.value, videoRepairAttempts: videoRepairAttempts.value }))
const videoRules = { videoLimit: integerRule('本批镜头上限'), videoRepairAttempts: integerRule('每镜最多自动修复') }
</script>
<template>
@@ -219,25 +237,31 @@ watch(
</RouterLink>
</div>
<section class="mt-3" aria-label="项目生产配置">
<div class="production-controls">
<label>
<span class="field-label">批量并发</span>
<NInputNumber
<AppForm
:model="batchModel"
:rules="batchRules"
:disabled="operation.pending"
validate-on-change
>
<div class="form-controls production-controls">
<NFormItem path="concurrency" label="批量并发">
<NInputNumber
:input-props="{ 'aria-label': '批量并发' }"
:disabled="operation.pending"
:value="typeof concurrency === 'number' ? concurrency : null"
@update:value="concurrency = $event ?? 0"
:min="1"
:step="1"
></NInputNumber>
</NFormItem>
<NCheckbox
v-model:checked="force"
:disabled="operation.pending"
:value="typeof concurrency === 'number' ? concurrency : null"
@update:value="concurrency = $event ?? 0"
:min="1"
:step="1"
></NInputNumber>
<span v-if="!batchValid" class="mt-1 block text-xs text-danger">请输入正整数</span>
</label>
<NCheckbox
v-model:checked="force"
:disabled="operation.pending"
class="control-row-checkbox text-xs"
>覆盖模式重写提示词新增图视频候选
</NCheckbox>
</div>
class="control-row-checkbox text-xs"
>覆盖模式重写提示词新增图视频候选
</NCheckbox>
</div>
</AppForm>
<DetailDisclosure title="处理范围与覆盖规则" class="mt-3"
><p class="text-xs leading-6 text-muted">
提示词与视频就绪检查面向全项目视频实际提交受本批镜头上限控制并使用严格质量流水线首帧默认补当前剧集存在过期主首帧时优先更新全项目过期项覆盖模式处理全项目过期首帧成功后会自动接替旧主图其余新增候选图片模型视频模型与视觉校验均可能产生费用
@@ -393,63 +417,69 @@ watch(
:primary="stage.key === 'videos'"
@confirm="run(stage.key)"
/>
<div v-if="stage.key === 'keyframes'" class="mt-4 grid gap-3">
<label
><span class="field-label">本批上限可选</span
<AppForm
v-if="stage.key === 'keyframes'"
:model="keyframeModel"
:rules="keyframeRules"
:disabled="operation.pending"
validate-on-change
class="mt-4 grid gap-3"
>
<NFormItem path="keyframeLimit" label="本批上限(可选)"
><NInputNumber
:input-props="{ 'aria-label': '本批上限可选' }"
:value="keyframeLimit === '' ? null : keyframeLimit"
@update:value="keyframeLimit = $event ?? ''"
:min="1"
:precision="0"
:disabled="operation.pending"
placeholder="留空不限制"
/></label>
/></NFormItem>
<div class="grid grid-cols-2 gap-3">
<label
><span class="field-label">宽度像素</span
<NFormItem path="keyframeWidth" label="宽度(像素)"
><NInputNumber
:input-props="{ 'aria-label': '宽度像素' }"
:value="keyframeWidth === '' ? null : keyframeWidth"
@update:value="keyframeWidth = $event ?? ''"
:min="1"
:disabled="operation.pending"
placeholder="默认" /></label
><label
><span class="field-label">高度像素</span
placeholder="默认" /></NFormItem
><NFormItem path="keyframeHeight" label="高度(像素)"
><NInputNumber
:input-props="{ 'aria-label': '高度像素' }"
:value="keyframeHeight === '' ? null : keyframeHeight"
@update:value="keyframeHeight = $event ?? ''"
:min="1"
:disabled="operation.pending"
placeholder="默认"
/></label>
/></NFormItem>
</div>
<p v-if="!keyframeValid" class="text-xs text-danger">
上限须为正整数宽高须同时留空或填写正整数
</p>
</div>
<div v-if="stage.key === 'videos'" class="mt-4 grid gap-3">
<label
><span class="field-label">本批镜头上限</span
</AppForm>
<AppForm
v-if="stage.key === 'videos'"
:model="videoModel"
:rules="videoRules"
:disabled="operation.pending"
validate-on-change
class="mt-4 grid gap-3"
>
<NFormItem path="videoLimit" label="本批镜头上限"
><NInputNumber
v-model:value="videoLimit"
:min="1"
:precision="0"
:disabled="operation.pending"
:input-props="{ 'aria-label': '视频质量任务镜头上限' }"
/></label>
<label
><span class="field-label">每镜最多自动修复</span
/></NFormItem>
<NFormItem path="videoRepairAttempts" label="每镜最多自动修复"
><NInputNumber
v-model:value="videoRepairAttempts"
:min="1"
:precision="0"
:disabled="operation.pending"
:input-props="{ 'aria-label': '视频自动修复次数' }"
/></label>
<p v-if="!videoQualityValid" class="text-xs text-danger">
本批上限和自动修复次数都必须是正整数
</p>
</div>
/></NFormItem>
</AppForm>
</article>
</div>
<div v-if="query.data.value" class="panel mt-4 p-5">
@@ -466,7 +496,7 @@ watch(
blocked || !batchValid || !query.data.value.videoStatus.failed
"
acknowledgement
description="为当前最近一次状态为失败的镜头重新创建视频模型任务。成功镜头和进行中的镜头不会处理。"
description="仅重新提交后端判定可重试的失败视频;不可重试项会跳过,并在回执中显示数量。"
@confirm="run('retry-videos')"
/>
</div>
@@ -591,6 +621,18 @@ watch(
</div>
<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>
<NAlert
v-if="videoStatusItem?.status === 'failed'"
type="error"
:show-icon="false"
class="mt-3"
>
{{ videoStatusItem.error || '最近一次视频任务失败' }}
<p v-if="videoStatusItem.retryable === false" class="mt-2">
此失败不支持普通重试,请先处理失败原因。
</p>
<p v-else-if="videoStatusItem.retryable === true" class="mt-2">后端允许重试此任务。</p>
</NAlert>
<StaleKeyframeNotice
v-if="selectedKeyframeStale"
:key="shot.shotId"