fix: 使用 NScrollbar 统一内容区滚动条
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import WorkspacePage from '../../components/ui/WorkspacePage.vue'
|
||||
import {
|
||||
NScrollbar,
|
||||
NAlert,
|
||||
NButton,
|
||||
NCheckbox,
|
||||
@@ -155,95 +156,99 @@ watch(
|
||||
</div>
|
||||
</section></template
|
||||
>
|
||||
<NCollapse v-model:expanded-names="overview" class="workspace-overview"
|
||||
><NCollapseItem name="generation" title="生成配置、批量操作与回执"
|
||||
><div class="overview-content">
|
||||
<div class="generation-row">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold">
|
||||
<span class="mr-2 font-mono text-xs text-muted">01</span>导演摄影设计
|
||||
</h3>
|
||||
<p class="mt-2 text-xs leading-6 text-muted">
|
||||
景别、机位、运镜与构图。单集操作会重新生成并覆盖;批量默认跳过完整剧集。
|
||||
</p>
|
||||
<NScrollbar class="workspace-overview" content-class="overview-scroll-content"
|
||||
><NCollapse v-model:expanded-names="overview"
|
||||
><NCollapseItem name="generation" title="生成配置、批量操作与回执"
|
||||
><div class="overview-content">
|
||||
<div class="generation-row">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold">
|
||||
<span class="mr-2 font-mono text-xs text-muted">01</span>导演摄影设计
|
||||
</h3>
|
||||
<p class="mt-2 text-xs leading-6 text-muted">
|
||||
景别、机位、运镜与构图。单集操作会重新生成并覆盖;批量默认跳过完整剧集。
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ConfirmAction
|
||||
label="生成本集导演设计"
|
||||
:disabled="!allowed['direction-one']"
|
||||
acknowledgement
|
||||
description="调用模型生成当前整集的导演设计,校验通过后保存。如果此集已有设计,将覆盖原结果。"
|
||||
@confirm="run('direction-one')"
|
||||
/><ConfirmAction
|
||||
:label="force ? '重生成全部导演设计' : '补齐项目导演设计'"
|
||||
:disabled="!allowed['direction-all']"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '重新生成项目全部剧集的导演设计,覆盖已有结果。'
|
||||
: '对整个项目生成导演设计,跳过已完整保存的剧集,可用于重试失败或未完成的剧集。'
|
||||
"
|
||||
@confirm="run('direction-all')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ConfirmAction
|
||||
label="生成本集导演设计"
|
||||
:disabled="!allowed['direction-one']"
|
||||
acknowledgement
|
||||
description="调用模型生成当前整集的导演设计,校验通过后保存。如果此集已有设计,将覆盖原结果。"
|
||||
@confirm="run('direction-one')"
|
||||
/><ConfirmAction
|
||||
:label="force ? '重生成全部导演设计' : '补齐项目导演设计'"
|
||||
:disabled="!allowed['direction-all']"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '重新生成项目全部剧集的导演设计,覆盖已有结果。'
|
||||
: '对整个项目生成导演设计,跳过已完整保存的剧集,可用于重试失败或未完成的剧集。'
|
||||
"
|
||||
@confirm="run('direction-all')"
|
||||
/>
|
||||
<div class="generation-row">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold">
|
||||
<span class="mr-2 font-mono text-xs text-muted">02</span>即时视觉状态
|
||||
</h3>
|
||||
<p class="mt-2 text-xs leading-6 text-muted">
|
||||
表情、姿态、位置、环境与连续性。每集需要完整导演设计;批量中缺少前置设计的剧集会单独报错。
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ConfirmAction
|
||||
label="生成本集即时状态"
|
||||
:disabled="!allowed['visual-one']"
|
||||
acknowledgement
|
||||
description="依据本集导演设计和主体形态生成即时视觉状态,按配置尝试自动修复。校验通过才保存,已有状态将被覆盖。"
|
||||
@confirm="run('visual-one')"
|
||||
/><ConfirmAction
|
||||
:label="force ? '重生成全部即时状态' : '补齐项目即时状态'"
|
||||
:disabled="!allowed['visual-all']"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '重新生成整个项目的即时状态,覆盖已有结果。每集必须先有完整导演设计。'
|
||||
: '补齐项目即时状态,跳过完整剧集;未完成导演设计的剧集会返回失败原因。'
|
||||
"
|
||||
@confirm="run('visual-all')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="generation-row">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold">
|
||||
<span class="mr-2 font-mono text-xs text-muted">02</span>即时视觉状态
|
||||
</h3>
|
||||
<p class="mt-2 text-xs leading-6 text-muted">
|
||||
表情、姿态、位置、环境与连续性。每集需要完整导演设计;批量中缺少前置设计的剧集会单独报错。
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ConfirmAction
|
||||
label="生成本集即时状态"
|
||||
:disabled="!allowed['visual-one']"
|
||||
acknowledgement
|
||||
description="依据本集导演设计和主体形态生成即时视觉状态,按配置尝试自动修复。校验通过才保存,已有状态将被覆盖。"
|
||||
@confirm="run('visual-one')"
|
||||
/><ConfirmAction
|
||||
:label="force ? '重生成全部即时状态' : '补齐项目即时状态'"
|
||||
:disabled="!allowed['visual-all']"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '重新生成整个项目的即时状态,覆盖已有结果。每集必须先有完整导演设计。'
|
||||
: '补齐项目即时状态,跳过完整剧集;未完成导演设计的剧集会返回失败原因。'
|
||||
"
|
||||
@confirm="run('visual-all')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-4 text-[11px] leading-6 text-muted">
|
||||
修改或覆盖上游设计后,后端不会自动使旧状态、旧提示词失效;请按顺序重生成下游内容。自动修复次数仅用于
|
||||
VisualState。
|
||||
</p>
|
||||
<NCollapse class="mt-3 border-t border-line pt-3"
|
||||
><NCollapseItem name="details"
|
||||
><template #header>视频提示词批量操作</template>
|
||||
<p class="my-3 text-xs leading-6 text-muted">
|
||||
后端会先校验 GenerationSpec
|
||||
与主体参考图。这里只生成提示词;首帧、视频任务、就绪诊断与失败重试已整理到
|
||||
<RouterLink :to="`/projects/${id}/production`" class="text-button mx-1"
|
||||
>镜头生产</RouterLink
|
||||
>。
|
||||
</p>
|
||||
<ConfirmAction
|
||||
:label="force ? '重生成全部视频提示词' : '补齐项目视频提示词'"
|
||||
:disabled="!allowed.prompts"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '调用模型重新生成全项目镜头的视频提示词,覆盖已有正文。'
|
||||
: '调用模型生成缺少视频提示词的镜头,已有提示词直接跳过。参考图缺失会返回失败。'
|
||||
"
|
||||
@confirm="run('prompts')" /></NCollapseItem
|
||||
></NCollapse>
|
||||
<GenerationReceipt v-if="session.receipt" :receipt="session.receipt" /></div></NCollapseItem
|
||||
></NCollapse>
|
||||
<div class="workspace-feedback">
|
||||
<p class="mt-4 text-[11px] leading-6 text-muted">
|
||||
修改或覆盖上游设计后,后端不会自动使旧状态、旧提示词失效;请按顺序重生成下游内容。自动修复次数仅用于
|
||||
VisualState。
|
||||
</p>
|
||||
<NCollapse class="mt-3 border-t border-line pt-3"
|
||||
><NCollapseItem name="details"
|
||||
><template #header>视频提示词批量操作</template>
|
||||
<p class="my-3 text-xs leading-6 text-muted">
|
||||
后端会先校验 GenerationSpec
|
||||
与主体参考图。这里只生成提示词;首帧、视频任务、就绪诊断与失败重试已整理到
|
||||
<RouterLink :to="`/projects/${id}/production`" class="text-button mx-1"
|
||||
>镜头生产</RouterLink
|
||||
>。
|
||||
</p>
|
||||
<ConfirmAction
|
||||
:label="force ? '重生成全部视频提示词' : '补齐项目视频提示词'"
|
||||
:disabled="!allowed.prompts"
|
||||
acknowledgement
|
||||
:description="
|
||||
force
|
||||
? '调用模型重新生成全项目镜头的视频提示词,覆盖已有正文。'
|
||||
: '调用模型生成缺少视频提示词的镜头,已有提示词直接跳过。参考图缺失会返回失败。'
|
||||
"
|
||||
@confirm="run('prompts')" /></NCollapseItem
|
||||
></NCollapse>
|
||||
<GenerationReceipt
|
||||
v-if="session.receipt"
|
||||
:receipt="session.receipt"
|
||||
/></div></NCollapseItem></NCollapse
|
||||
></NScrollbar>
|
||||
<NScrollbar class="workspace-feedback">
|
||||
<NAlert v-if="query.error.value" role="alert" type="error" :show-icon="false" class="mt-4"
|
||||
>{{ query.error.value }} 当前保留上次成功读取的数据,暂停生成操作。<NButton
|
||||
@click="query.refresh"
|
||||
@@ -269,7 +274,7 @@ watch(
|
||||
>
|
||||
本集导演设计尚未补齐,请先完成第 01 步,再生成本集即时状态。
|
||||
</NAlert>
|
||||
</div>
|
||||
</NScrollbar>
|
||||
<div class="my-6 flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold">第 {{ episodeNo || '—' }} 集 · 镜头检查</h3>
|
||||
@@ -306,57 +311,63 @@ watch(
|
||||
</div>
|
||||
<div v-else-if="shot" class="panel storyboard-workspace">
|
||||
<nav class="shot-list" aria-label="本集镜头">
|
||||
<p class="px-4 pb-3 pt-5 text-[10px] text-muted">{{ shots.length }} 个镜头 · 按 Beat 排列</p>
|
||||
<template v-for="(item, index) in shots" :key="item.shotId"
|
||||
><h4
|
||||
v-if="index === 0 || shots[index - 1]?.beatNo !== item.beatNo"
|
||||
class="px-4 pb-2 pt-4 font-mono text-[10px] text-muted"
|
||||
<NScrollbar class="panel-scroll" content-class="shot-list-content">
|
||||
<p class="px-4 pb-3 pt-5 text-[10px] text-muted">{{ shots.length }} 个镜头 · 按 Beat 排列</p>
|
||||
<template v-for="(item, index) in shots" :key="item.shotId"
|
||||
><h4
|
||||
v-if="index === 0 || shots[index - 1]?.beatNo !== item.beatNo"
|
||||
class="px-4 pb-2 pt-4 font-mono text-[10px] text-muted"
|
||||
>
|
||||
BEAT {{ String(item.beatNo).padStart(2, '0') }}
|
||||
</h4>
|
||||
<NButton
|
||||
:aria-current="shot.shotId === item.shotId ? 'true' : undefined"
|
||||
@click="selectedShot = item.shotId"
|
||||
class="shot-link"
|
||||
:class="{ selected: shot.shotId === item.shotId }"
|
||||
><span class="font-mono text-[10px] text-muted">{{
|
||||
String(item.shotNo).padStart(2, '0')
|
||||
}}</span
|
||||
><span class="min-w-0"
|
||||
><span class="block truncate text-xs font-medium">{{ item.title }}</span
|
||||
><span class="mt-1 block text-[10px] text-muted"
|
||||
>{{ item.direction ? '设计已保存' : '待设计' }} ·
|
||||
{{ item.visualState ? '状态已保存' : '待状态' }}</span
|
||||
></span
|
||||
></NButton
|
||||
></template
|
||||
>
|
||||
BEAT {{ String(item.beatNo).padStart(2, '0') }}
|
||||
</h4>
|
||||
<NButton
|
||||
:aria-current="shot.shotId === item.shotId ? 'true' : undefined"
|
||||
@click="selectedShot = item.shotId"
|
||||
class="shot-link"
|
||||
:class="{ selected: shot.shotId === item.shotId }"
|
||||
><span class="font-mono text-[10px] text-muted">{{ String(item.shotNo).padStart(2, '0') }}</span
|
||||
><span class="min-w-0"
|
||||
><span class="block truncate text-xs font-medium">{{ item.title }}</span
|
||||
><span class="mt-1 block text-[10px] text-muted"
|
||||
>{{ item.direction ? '设计已保存' : '待设计' }} ·
|
||||
{{ item.visualState ? '状态已保存' : '待状态' }}</span
|
||||
></span
|
||||
></NButton
|
||||
></template
|
||||
>
|
||||
</NScrollbar>
|
||||
</nav>
|
||||
<article class="min-w-0 p-5 lg:p-7">
|
||||
<header class="mb-6">
|
||||
<p class="eyebrow">
|
||||
BEAT {{ shot.beatNo }} / SHOT {{ shot.shotNo }}
|
||||
<span v-if="shot.durationSeconds" class="ml-3">{{ shot.durationSeconds }}s</span>
|
||||
</p>
|
||||
<h3 class="mt-2 text-lg font-semibold">{{ shot.title }}</h3>
|
||||
<p v-if="shot.description" class="mt-3 whitespace-pre-wrap text-sm leading-7">
|
||||
{{ shot.description }}
|
||||
</p>
|
||||
<p v-if="shot.visualFocus" class="mt-2 text-xs leading-6 text-muted">
|
||||
视觉重点:{{ shot.visualFocus }}
|
||||
</p>
|
||||
<p class="mt-3 break-all font-mono text-[10px] text-muted">Shot ID · {{ shot.shotId }}</p>
|
||||
<p class="mt-1 text-[10px] text-muted">
|
||||
标题与剧情描述取自最近可用 Breakdown 快照;以下设计与状态取自数据库。
|
||||
</p>
|
||||
</header>
|
||||
<div>
|
||||
<NTabs v-model:value="detailTab" type="line" size="small" aria-label="镜头详情"
|
||||
><NTab name="design">设计与状态</NTab><NTab name="tools">参考图与生成规格</NTab></NTabs
|
||||
>
|
||||
<div v-if="detailTab === 'design'" class="pt-6"><ShotDesign :shot="shot" /></div>
|
||||
<div v-if="detailTab === 'tools'" class="pt-6">
|
||||
<ShotTools :key="shot.shotId" :project-id="id" :shot="shot" :disabled="blocked" />
|
||||
<article class="storyboard-detail min-w-0">
|
||||
<NScrollbar class="panel-scroll" content-class="p-5 lg:p-7">
|
||||
<header class="mb-6">
|
||||
<p class="eyebrow">
|
||||
BEAT {{ shot.beatNo }} / SHOT {{ shot.shotNo }}
|
||||
<span v-if="shot.durationSeconds" class="ml-3">{{ shot.durationSeconds }}s</span>
|
||||
</p>
|
||||
<h3 class="mt-2 text-lg font-semibold">{{ shot.title }}</h3>
|
||||
<p v-if="shot.description" class="mt-3 whitespace-pre-wrap text-sm leading-7">
|
||||
{{ shot.description }}
|
||||
</p>
|
||||
<p v-if="shot.visualFocus" class="mt-2 text-xs leading-6 text-muted">
|
||||
视觉重点:{{ shot.visualFocus }}
|
||||
</p>
|
||||
<p class="mt-3 break-all font-mono text-[10px] text-muted">Shot ID · {{ shot.shotId }}</p>
|
||||
<p class="mt-1 text-[10px] text-muted">
|
||||
标题与剧情描述取自最近可用 Breakdown 快照;以下设计与状态取自数据库。
|
||||
</p>
|
||||
</header>
|
||||
<div>
|
||||
<NTabs v-model:value="detailTab" type="line" size="small" aria-label="镜头详情"
|
||||
><NTab name="design">设计与状态</NTab><NTab name="tools">参考图与生成规格</NTab></NTabs
|
||||
>
|
||||
<div v-if="detailTab === 'design'" class="pt-6"><ShotDesign :shot="shot" /></div>
|
||||
<div v-if="detailTab === 'tools'" class="pt-6">
|
||||
<ShotTools :key="shot.shotId" :project-id="id" :shot="shot" :disabled="blocked" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NScrollbar>
|
||||
</article>
|
||||
</div>
|
||||
<EmptyState
|
||||
|
||||
Reference in New Issue
Block a user