fix: 统一图库滚动区域并吸顶镜头筛选栏
This commit is contained in:
+30
-1
@@ -455,8 +455,19 @@ body {
|
|||||||
.production-pipeline-card > .confirm-action {
|
.production-pipeline-card > .confirm-action {
|
||||||
margin-block: 16px 4px;
|
margin-block: 16px 4px;
|
||||||
}
|
}
|
||||||
|
.gallery-workspace-page .workspace-scroll-content {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
/* 图库只使用正文纵向滚动;筛选栏在同一滚动上下文吸顶,不再被头部高度限制。 */
|
||||||
.gallery-workspace-page .form-image-filter-region {
|
.gallery-workspace-page .form-image-filter-region {
|
||||||
margin-block: 10px 0;
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: var(--app-subtle);
|
||||||
|
margin-block: 10px 12px;
|
||||||
|
}
|
||||||
|
.gallery-workspace-page .workspace-scroll > .n-scrollbar-container {
|
||||||
|
overflow-anchor: none;
|
||||||
}
|
}
|
||||||
.workspace-heading h2 {
|
.workspace-heading h2 {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -1501,6 +1512,24 @@ body {
|
|||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
background: var(--app-subtle);
|
background: var(--app-subtle);
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
/* 关联素材始终单行横向浏览,数量和长名称不会撑高定位区或压缩图片区域。 */
|
||||||
|
.asset-impact-links-scroll.n-scrollbar {
|
||||||
|
height: auto;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.asset-impact-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
width: max-content;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
.asset-impact-links > * {
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.asset-impact-select {
|
.asset-impact-select {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@@ -141,6 +141,22 @@ describe('全站平面主题', () => {
|
|||||||
expect(tools).not.toContain(':focusable="false"')
|
expect(tools).not.toContain(':focusable="false"')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('图库筛选吸顶,关联内容横向单行滚动,不给头部和图片区制造双重滚动边界', () => {
|
||||||
|
// 静态保护吸顶和横向尺寸规则;真实视口滚动与位置仍需浏览器验收。
|
||||||
|
const css = readFileSync('src/admin.css', 'utf8')
|
||||||
|
expect(css).toMatch(
|
||||||
|
/\.gallery-workspace-page \.form-image-filter-region\s*\{[^}]*position:\s*sticky;[^}]*top:\s*0;[^}]*z-index:\s*10;[^}]*background:\s*var\(--app-subtle\);/
|
||||||
|
)
|
||||||
|
expect(css).toMatch(
|
||||||
|
/\.gallery-workspace-page \.workspace-scroll > \.n-scrollbar-container\s*\{[^}]*overflow-anchor:\s*none;/
|
||||||
|
)
|
||||||
|
expect(css).toMatch(/\.asset-impact-links\s*\{[^}]*width:\s*max-content;[^}]*white-space:\s*nowrap;/)
|
||||||
|
expect(css).toMatch(/\.asset-impact-links-scroll\.n-scrollbar\s*\{[^}]*height:\s*auto;[^}]*max-width:\s*100%;/)
|
||||||
|
expect(readFileSync('src/features/subject-images/SubjectImagesPage.vue', 'utf8')).toMatch(
|
||||||
|
/<WorkspacePage\b[^>]*>\s*<template #default>/
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('图库顶部统一镜头选择和筛选的背景与垂直对齐,窄屏整组换行', () => {
|
it('图库顶部统一镜头选择和筛选的背景与垂直对齐,窄屏整组换行', () => {
|
||||||
// DOM 环境不计算几何;保护容器宽度断点和居中契约,真实坐标仍需浏览器验收。
|
// DOM 环境不计算几何;保护容器宽度断点和居中契约,真实坐标仍需浏览器验收。
|
||||||
const css = readFileSync('src/admin.css', 'utf8')
|
const css = readFileSync('src/admin.css', 'utf8')
|
||||||
|
|||||||
@@ -3,7 +3,18 @@ import WorkspacePage from '../../components/ui/WorkspacePage.vue'
|
|||||||
import ActionMenu from '../../components/ui/ActionMenu.vue'
|
import ActionMenu from '../../components/ui/ActionMenu.vue'
|
||||||
import DetailDisclosure from '../../components/ui/DetailDisclosure.vue'
|
import DetailDisclosure from '../../components/ui/DetailDisclosure.vue'
|
||||||
import WorkspaceTools from '../../components/ui/WorkspaceTools.vue'
|
import WorkspaceTools from '../../components/ui/WorkspaceTools.vue'
|
||||||
import { NAlert, NButton, NCheckbox, NCollapse, NCollapseItem, NInput, NInputNumber, NSelect, NTag } from 'naive-ui'
|
import {
|
||||||
|
NAlert,
|
||||||
|
NButton,
|
||||||
|
NCheckbox,
|
||||||
|
NCollapse,
|
||||||
|
NCollapseItem,
|
||||||
|
NInput,
|
||||||
|
NInputNumber,
|
||||||
|
NScrollbar,
|
||||||
|
NSelect,
|
||||||
|
NTag
|
||||||
|
} from 'naive-ui'
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { Search, RefreshCw, Download, ImagePlus, ArrowLeft, ArrowRight, LayoutGrid, AlertTriangle } from '@lucide/vue'
|
import { Search, RefreshCw, Download, ImagePlus, ArrowLeft, ArrowRight, LayoutGrid, AlertTriangle } from '@lucide/vue'
|
||||||
@@ -211,7 +222,8 @@ async function showStaleForms() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<WorkspacePage compact class="gallery-workspace-page"
|
<WorkspacePage compact class="gallery-workspace-page"
|
||||||
><template #header>
|
><template #default>
|
||||||
|
<!-- 筛选、关联说明和图片共用正文滚动区,避免镜头切换时两块滚动区域高度不同步。 -->
|
||||||
<div class="workspace-toolbar">
|
<div class="workspace-toolbar">
|
||||||
<span class="toolbar-summary">主图 {{ completeCount }} / {{ forms.length }}</span>
|
<span class="toolbar-summary">主图 {{ completeCount }} / {{ forms.length }}</span>
|
||||||
<NButton v-if="staleForms.length" text type="error" size="small" @click="toolsOpen = true"
|
<NButton v-if="staleForms.length" text type="error" size="small" @click="toolsOpen = true"
|
||||||
@@ -495,9 +507,15 @@ async function showStaleForms() {
|
|||||||
<p v-if="targetUnlinked" class="text-xs text-danger">
|
<p v-if="targetUnlinked" class="text-xs text-danger">
|
||||||
指定形态不在该镜头当前的有效引用列表中,关联可能已调整或主图缺失,请从下方关联素材重新核对。
|
指定形态不在该镜头当前的有效引用列表中,关联可能已调整或主图缺失,请从下方关联素材重新核对。
|
||||||
</p>
|
</p>
|
||||||
<div
|
<NScrollbar
|
||||||
v-if="linkedReferences.length && !impact.references.error.value"
|
v-if="linkedReferences.length && !impact.references.error.value"
|
||||||
class="flex flex-wrap items-center gap-3"
|
:key="sourceShotId"
|
||||||
|
class="asset-impact-links-scroll"
|
||||||
|
content-class="asset-impact-links"
|
||||||
|
x-scrollable
|
||||||
|
trigger="none"
|
||||||
|
role="region"
|
||||||
|
aria-label="本镜头关联素材,可横向滚动"
|
||||||
>
|
>
|
||||||
<span class="text-xs text-muted">本镜头当前关联素材:</span
|
<span class="text-xs text-muted">本镜头当前关联素材:</span
|
||||||
><RouterLink
|
><RouterLink
|
||||||
@@ -507,7 +525,7 @@ async function showStaleForms() {
|
|||||||
class="text-button"
|
class="text-button"
|
||||||
>{{ target.label }} →</RouterLink
|
>{{ target.label }} →</RouterLink
|
||||||
>
|
>
|
||||||
</div>
|
</NScrollbar>
|
||||||
<p v-if="impact.references.loading.value" class="text-xs text-muted">正在读取镜头关联素材…</p>
|
<p v-if="impact.references.loading.value" class="text-xs text-muted">正在读取镜头关联素材…</p>
|
||||||
<p v-if="impact.references.error.value" class="text-xs text-danger">
|
<p v-if="impact.references.error.value" class="text-xs text-danger">
|
||||||
{{ impact.references.error.value }}
|
{{ impact.references.error.value }}
|
||||||
@@ -536,141 +554,142 @@ async function showStaleForms() {
|
|||||||
><NAlert v-if="running" role="status" type="info" :show-icon="false" class="mt-4">
|
><NAlert v-if="running" role="status" type="info" :show-icon="false" class="mt-4">
|
||||||
数据库中仍有排队或生成中的图片,已暂停新的生图操作。长时间无变化时,请先核对后台任务;刷新或关闭页面不会取消任务。
|
数据库中仍有排队或生成中的图片,已暂停新的生图操作。长时间无变化时,请先核对后台任务;刷新或关闭页面不会取消任务。
|
||||||
</NAlert>
|
</NAlert>
|
||||||
</template>
|
<p v-if="!query.data.value && query.loading.value" class="py-10 text-sm text-muted" role="status">
|
||||||
<p v-if="!query.data.value && query.loading.value" class="py-10 text-sm text-muted" role="status">
|
正在读取形态和已有图片…
|
||||||
正在读取形态和已有图片…
|
</p>
|
||||||
</p>
|
<div v-else-if="filtered.length" class="form-image-grid">
|
||||||
<div v-else-if="filtered.length" class="form-image-grid">
|
<article
|
||||||
<article
|
v-for="form in filtered"
|
||||||
v-for="form in filtered"
|
:key="form.id"
|
||||||
:key="form.id"
|
class="panel form-image-card"
|
||||||
class="panel form-image-card"
|
:class="{
|
||||||
:class="{
|
'ring-1 ring-danger': isPrimaryIdentityStale(form),
|
||||||
'ring-1 ring-danger': isPrimaryIdentityStale(form),
|
'form-image-card-focused': targetFormId === form.id
|
||||||
'form-image-card-focused': targetFormId === form.id
|
}"
|
||||||
}"
|
:data-form-id="form.id"
|
||||||
:data-form-id="form.id"
|
>
|
||||||
>
|
<AssetImage
|
||||||
<AssetImage
|
:src="coverImage(form)?.imageUrl"
|
||||||
:src="coverImage(form)?.imageUrl"
|
:alt="`${form.subject.name} · ${form.name}`"
|
||||||
:alt="`${form.subject.name} · ${form.name}`"
|
object-fit="cover"
|
||||||
object-fit="cover"
|
preview
|
||||||
preview
|
:empty-text="hasRunningImages(form.images) ? '后台正在生成图片' : '尚未生成图片'"
|
||||||
:empty-text="hasRunningImages(form.images) ? '后台正在生成图片' : '尚未生成图片'"
|
/>
|
||||||
/>
|
<div class="p-4">
|
||||||
<div class="p-4">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<h3 class="text-sm font-semibold">{{ form.subject.name }}</h3>
|
||||||
<h3 class="text-sm font-semibold">{{ form.subject.name }}</h3>
|
<code class="subject-ref">{{ form.subject.ref }}</code>
|
||||||
<code class="subject-ref">{{ form.subject.ref }}</code>
|
</div>
|
||||||
</div>
|
<p class="mt-2 text-xs">
|
||||||
<p class="mt-2 text-xs">
|
{{ form.name }}<NTag v-if="form.isDefault" size="small" :bordered="false">默认形态</NTag>
|
||||||
{{ form.name }}<NTag v-if="form.isDefault" size="small" :bordered="false">默认形态</NTag>
|
</p>
|
||||||
</p>
|
<p v-if="form.description" class="mt-3 line-clamp-2 text-xs leading-6 text-muted">
|
||||||
<p v-if="form.description" class="mt-3 line-clamp-2 text-xs leading-6 text-muted">
|
{{ form.description }}
|
||||||
{{ form.description }}
|
</p>
|
||||||
</p>
|
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
<StatusBadge v-if="hasRunningImages(form.images)" status="generating" />
|
||||||
<StatusBadge v-if="hasRunningImages(form.images)" status="generating" />
|
<NTag v-if="isPrimaryIdentityStale(form)" size="small" :bordered="false"
|
||||||
<NTag v-if="isPrimaryIdentityStale(form)" size="small" :bordered="false">身份母版已变更</NTag>
|
>身份母版已变更</NTag
|
||||||
<NTag v-else-if="primaryImage(form.images)" size="small" :bordered="false">主参考图</NTag>
|
>
|
||||||
<NTag v-else-if="coverImage(form)" size="small" :bordered="false">候选图 · 尚未设主图</NTag>
|
<NTag v-else-if="primaryImage(form.images)" size="small" :bordered="false">主参考图</NTag>
|
||||||
<span v-else-if="form.images[0]?.status === 'failed'" class="text-xs text-danger"
|
<NTag v-else-if="coverImage(form)" size="small" :bordered="false">候选图 · 尚未设主图</NTag>
|
||||||
>最近一次生成失败</span
|
<span v-else-if="form.images[0]?.status === 'failed'" class="text-xs text-danger"
|
||||||
|
>最近一次生成失败</span
|
||||||
|
>
|
||||||
|
<span class="text-[10px] text-muted">{{ form.images.length }} 条记录</span>
|
||||||
|
</div>
|
||||||
|
<NAlert
|
||||||
|
v-if="isPrimaryIdentityStale(form)"
|
||||||
|
type="error"
|
||||||
|
:show-icon="false"
|
||||||
|
class="mt-3 text-xs leading-6"
|
||||||
>
|
>
|
||||||
<span class="text-[10px] text-muted">{{ form.images.length }} 条记录</span>
|
当前主图未能匹配最新已锁定母版。请基于当前 Identity Anchor
|
||||||
</div>
|
重新生成候选图,并在确认后设置为新的主参考图。
|
||||||
<NAlert
|
</NAlert>
|
||||||
v-if="isPrimaryIdentityStale(form)"
|
<NAlert
|
||||||
type="error"
|
v-if="
|
||||||
:show-icon="false"
|
sourceShot?.primaryKeyframeStale &&
|
||||||
class="mt-3 text-xs leading-6"
|
impact.relatedForms.value.has(form.id) &&
|
||||||
>
|
!impact.references.error.value
|
||||||
当前主图未能匹配最新已锁定母版。请基于当前 Identity Anchor
|
|
||||||
重新生成候选图,并在确认后设置为新的主参考图。
|
|
||||||
</NAlert>
|
|
||||||
<NAlert
|
|
||||||
v-if="
|
|
||||||
sourceShot?.primaryKeyframeStale &&
|
|
||||||
impact.relatedForms.value.has(form.id) &&
|
|
||||||
!impact.references.error.value
|
|
||||||
"
|
|
||||||
type="warning"
|
|
||||||
:show-icon="false"
|
|
||||||
class="mt-3 text-xs leading-6"
|
|
||||||
>
|
|
||||||
第 {{ sourceShot.episodeNo }} 集 · BEAT {{ sourceShot.beatNo }} / 镜头
|
|
||||||
{{ sourceShot.shotNo }} 的待处理首帧关联此素材。
|
|
||||||
{{
|
|
||||||
sourceShot.inconsistent
|
|
||||||
? '后端首帧与视频检查结果不一致,请先核对,不要据此重复生图。'
|
|
||||||
: isPrimaryIdentityStale(form)
|
|
||||||
? '请先更新该形态主图,再重建首帧。'
|
|
||||||
: '关联不等于本素材失效;核对形态主图与身份母版,确认无误后只需重建首帧。'
|
|
||||||
}}
|
|
||||||
<RouterLink v-if="sourceLocation" :to="sourceLocation" class="text-button mt-2"
|
|
||||||
>返回该镜头处理 →</RouterLink
|
|
||||||
>
|
|
||||||
</NAlert>
|
|
||||||
<p v-if="form.images[0]?.status === 'failed'" class="mt-2 line-clamp-2 text-xs text-danger">
|
|
||||||
{{ form.images[0].error }}
|
|
||||||
</p>
|
|
||||||
<div class="mt-4 flex flex-wrap items-center justify-between gap-2">
|
|
||||||
<NButton @click="openGallery(form)" text size="small">查看图片与记录</NButton>
|
|
||||||
<ActionMenu
|
|
||||||
:label="`${form.subject.name} · ${form.name} 更多操作`"
|
|
||||||
:items="[
|
|
||||||
{ key: 'prompt', label: '提示词与生成' },
|
|
||||||
{ key: 'identity', label: '主体身份与母版' }
|
|
||||||
]"
|
|
||||||
@select="
|
|
||||||
$event === 'prompt'
|
|
||||||
? openPrompt(form)
|
|
||||||
: router.push({
|
|
||||||
path: `/projects/${id}/subject-identity`,
|
|
||||||
query: { subjectId: form.subjectId }
|
|
||||||
})
|
|
||||||
"
|
"
|
||||||
/>
|
type="warning"
|
||||||
<NButton :disabled="blocked" @click="openGenerate(form)"
|
:show-icon="false"
|
||||||
><ImagePlus :size="14" />
|
class="mt-3 text-xs leading-6"
|
||||||
{{
|
|
||||||
isPrimaryIdentityStale(form)
|
|
||||||
? '基于当前母版重新生成'
|
|
||||||
: coverImage(form)
|
|
||||||
? '再生成一张'
|
|
||||||
: '生成图片'
|
|
||||||
}}</NButton
|
|
||||||
>
|
>
|
||||||
|
第 {{ sourceShot.episodeNo }} 集 · BEAT {{ sourceShot.beatNo }} / 镜头
|
||||||
|
{{ sourceShot.shotNo }} 的待处理首帧关联此素材。
|
||||||
|
{{
|
||||||
|
sourceShot.inconsistent
|
||||||
|
? '后端首帧与视频检查结果不一致,请先核对,不要据此重复生图。'
|
||||||
|
: isPrimaryIdentityStale(form)
|
||||||
|
? '请先更新该形态主图,再重建首帧。'
|
||||||
|
: '关联不等于本素材失效;核对形态主图与身份母版,确认无误后只需重建首帧。'
|
||||||
|
}}
|
||||||
|
<RouterLink v-if="sourceLocation" :to="sourceLocation" class="text-button mt-2"
|
||||||
|
>返回该镜头处理 →</RouterLink
|
||||||
|
>
|
||||||
|
</NAlert>
|
||||||
|
<p v-if="form.images[0]?.status === 'failed'" class="mt-2 line-clamp-2 text-xs text-danger">
|
||||||
|
{{ form.images[0].error }}
|
||||||
|
</p>
|
||||||
|
<div class="mt-4 flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<NButton @click="openGallery(form)" text size="small">查看图片与记录</NButton>
|
||||||
|
<ActionMenu
|
||||||
|
:label="`${form.subject.name} · ${form.name} 更多操作`"
|
||||||
|
:items="[
|
||||||
|
{ key: 'prompt', label: '提示词与生成' },
|
||||||
|
{ key: 'identity', label: '主体身份与母版' }
|
||||||
|
]"
|
||||||
|
@select="
|
||||||
|
$event === 'prompt'
|
||||||
|
? openPrompt(form)
|
||||||
|
: router.push({
|
||||||
|
path: `/projects/${id}/subject-identity`,
|
||||||
|
query: { subjectId: form.subjectId }
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<NButton :disabled="blocked" @click="openGenerate(form)"
|
||||||
|
><ImagePlus :size="14" />
|
||||||
|
{{
|
||||||
|
isPrimaryIdentityStale(form)
|
||||||
|
? '基于当前母版重新生成'
|
||||||
|
: coverImage(form)
|
||||||
|
? '再生成一张'
|
||||||
|
: '生成图片'
|
||||||
|
}}</NButton
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</article>
|
</div>
|
||||||
</div>
|
<EmptyState
|
||||||
<EmptyState
|
v-else-if="query.data.value"
|
||||||
v-else-if="query.data.value"
|
:title="forms.length ? '没有匹配的形态' : '还没有正式形态'"
|
||||||
:title="forms.length ? '没有匹配的形态' : '还没有正式形态'"
|
:description="
|
||||||
:description="
|
forms.length
|
||||||
forms.length
|
? '调整筛选条件后再查看。批量生图不受筛选影响。'
|
||||||
? '调整筛选条件后再查看。批量生图不受筛选影响。'
|
: '先完成剧本拆解和主体形态持久化,再来生成参考图。'
|
||||||
: '先完成剧本拆解和主体形态持久化,再来生成参考图。'
|
"
|
||||||
"
|
>
|
||||||
>
|
<NButton v-if="forms.length" @click="resetFilters">清除筛选</NButton>
|
||||||
<NButton v-if="forms.length" @click="resetFilters">清除筛选</NButton>
|
<RouterLink v-else :to="`/projects/${id}/breakdown`" class="button button-secondary"
|
||||||
<RouterLink v-else :to="`/projects/${id}/breakdown`" class="button button-secondary"
|
>前往剧本拆解</RouterLink
|
||||||
>前往剧本拆解</RouterLink
|
> </EmptyState
|
||||||
> </EmptyState
|
><FormPromptDialog
|
||||||
><FormPromptDialog
|
v-model:open="promptOpen"
|
||||||
v-model:open="promptOpen"
|
:form="promptForm"
|
||||||
:form="promptForm"
|
:disabled="blocked || !promptForm"
|
||||||
:disabled="blocked || !promptForm"
|
@generate="generatePrompt" /><GenerateImageDialog
|
||||||
@generate="generatePrompt" /><GenerateImageDialog
|
v-model:open="generateOpen"
|
||||||
v-model:open="generateOpen"
|
:form="generateForm"
|
||||||
:form="generateForm"
|
:disabled="blocked || !generateForm"
|
||||||
:disabled="blocked || !generateForm"
|
@generate="submitGenerate" /><ImageGalleryDialog
|
||||||
@generate="submitGenerate" /><ImageGalleryDialog
|
v-model:open="galleryOpen"
|
||||||
v-model:open="galleryOpen"
|
:project-id="id"
|
||||||
:project-id="id"
|
:form="galleryForm"
|
||||||
:form="galleryForm"
|
:disabled="blocked || !galleryForm"
|
||||||
:disabled="blocked || !galleryForm"
|
@changed="refreshAssets" /></template
|
||||||
@changed="refreshAssets"
|
></WorkspacePage>
|
||||||
/></WorkspacePage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -132,6 +132,68 @@ async function gallery(query = '') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('过期首帧到具体素材定位', () => {
|
describe('过期首帧到具体素材定位', () => {
|
||||||
|
it('切换镜头时筛选、关联说明和图片共用稳定纵向容器,长关联列表单独横向滚动', async () => {
|
||||||
|
const { keyframes, videos, references, fetcher } = await gallery('?sourceShotId=shot-target')
|
||||||
|
expect(wrapper!.find('.workspace-heading-scroll').exists()).toBe(false)
|
||||||
|
const scroll = wrapper!.get<HTMLElement>('.workspace-scroll > .n-scrollbar-container').element
|
||||||
|
const content = wrapper!.get('.workspace-scroll-content').element
|
||||||
|
const toolbar = wrapper!.get('.form-image-filter-region').element
|
||||||
|
expect(toolbar.parentElement).toBe(content)
|
||||||
|
expect(wrapper!.get('.asset-impact-context').element.parentElement).toBe(content)
|
||||||
|
expect(wrapper!.get('.form-image-grid').element.parentElement).toBe(content)
|
||||||
|
scroll.scrollTop = 480
|
||||||
|
keyframes.items.push({ ...keyframes.items[0]!, shotId: 'shot-next', shotNo: 2 })
|
||||||
|
videos.items.push({ ...videos.items[0]!, shotId: 'shot-next', shotNo: 2 })
|
||||||
|
keyframes.total = videos.total = 2
|
||||||
|
let finish!: (response: Response) => void
|
||||||
|
const original = fetcher.getMockImplementation()!
|
||||||
|
fetcher.mockImplementation((url, init) =>
|
||||||
|
String(url).endsWith('/shot-next/references')
|
||||||
|
? new Promise(resolve => {
|
||||||
|
finish = resolve
|
||||||
|
})
|
||||||
|
: original(url, init)
|
||||||
|
)
|
||||||
|
await wrapper!
|
||||||
|
.findAll('button')
|
||||||
|
.find(button => button.text() === '刷新图库')!
|
||||||
|
.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
wrapper!
|
||||||
|
.findAllComponents(NSelect)
|
||||||
|
.find(item => item.attributes('aria-label') === '选择关联镜头')!
|
||||||
|
.vm.$emit('update:value', 'shot-next')
|
||||||
|
await flushPromises()
|
||||||
|
expect(wrapper!.text()).toContain('正在读取镜头关联素材')
|
||||||
|
finish(
|
||||||
|
new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
data: {
|
||||||
|
...references,
|
||||||
|
shotId: 'shot-next',
|
||||||
|
references: Array.from({ length: 24 }, (_, index) => ({
|
||||||
|
...references.references[0]!,
|
||||||
|
subjectFormId: `long-form-${index}`,
|
||||||
|
subjectFormName: `很长的关联素材名称${index}`
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await flushPromises()
|
||||||
|
expect(wrapper!.get('.workspace-scroll > .n-scrollbar-container').element).toBe(scroll)
|
||||||
|
expect(wrapper!.get('.form-image-filter-region').element).toBe(toolbar)
|
||||||
|
expect(scroll.scrollTop).toBe(480)
|
||||||
|
expect(wrapper!.get('.asset-impact-context').element.parentElement).toBe(content)
|
||||||
|
expect(wrapper!.get('.form-image-grid').element.parentElement).toBe(content)
|
||||||
|
const links = wrapper!.get('.asset-impact-links-scroll')
|
||||||
|
expect(links.findAll('a')).toHaveLength(24)
|
||||||
|
expect(links.text()).toContain('很长的关联素材名称23')
|
||||||
|
expect(links.classes()).toContain('n-scrollbar')
|
||||||
|
expect(links.find('.n-scrollbar-container > .asset-impact-links').exists()).toBe(true)
|
||||||
|
expect(fetcher.mock.calls.every(([, init]) => init?.method === 'GET')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
it('切换镜头取消旧参考图查询,迟到响应不会产生旧素材链接', async () => {
|
it('切换镜头取消旧参考图查询,迟到响应不会产生旧素材链接', async () => {
|
||||||
const { references } = fixture()
|
const { references } = fixture()
|
||||||
let finish!: (response: Response) => void
|
let finish!: (response: Response) => void
|
||||||
|
|||||||
Reference in New Issue
Block a user