fix: 合并图库镜头定位与筛选工具栏并统一对齐
This commit is contained in:
+21
-1
@@ -862,6 +862,21 @@ body {
|
||||
.form-image-filter-region {
|
||||
container-type: inline-size;
|
||||
margin-block: 16px;
|
||||
padding: 14px 16px;
|
||||
background: var(--app-subtle);
|
||||
}
|
||||
/* 镜头选择和图库筛选共用一行,以控件中心对齐;窄屏保留完整筛选组,不挤压复选框。 */
|
||||
.form-image-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 12px 16px;
|
||||
}
|
||||
.form-image-toolbar.has-impact-picker {
|
||||
grid-template-columns: minmax(220px, 340px) minmax(0, 1fr);
|
||||
}
|
||||
.form-image-toolbar > * {
|
||||
min-width: 0;
|
||||
}
|
||||
.form-image-filters {
|
||||
display: grid;
|
||||
@@ -888,6 +903,11 @@ body {
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@container (max-width: 1200px) {
|
||||
.form-image-toolbar.has-impact-picker {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
@container (max-width: 900px) {
|
||||
.form-image-filters {
|
||||
grid-template-columns: minmax(0, 1fr) 152px;
|
||||
@@ -1466,8 +1486,8 @@ body {
|
||||
background: var(--app-subtle);
|
||||
}
|
||||
.asset-impact-select {
|
||||
flex: 0 1 340px;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.form-image-card-focused {
|
||||
box-shadow: inset 3px 0 0 var(--app-accent-text);
|
||||
|
||||
@@ -141,6 +141,21 @@ describe('全站平面主题', () => {
|
||||
expect(tools).not.toContain(':focusable="false"')
|
||||
})
|
||||
|
||||
it('图库顶部统一镜头选择和筛选的背景与垂直对齐,窄屏整组换行', () => {
|
||||
// DOM 环境不计算几何;保护容器宽度断点和居中契约,真实坐标仍需浏览器验收。
|
||||
const css = readFileSync('src/admin.css', 'utf8')
|
||||
expect(css).toMatch(
|
||||
/\.form-image-filter-region\s*\{[^}]*padding:\s*14px 16px;[^}]*background:\s*var\(--app-subtle\);/
|
||||
)
|
||||
expect(css).toMatch(/\.form-image-toolbar\s*\{[^}]*align-items:\s*center;[^}]*gap:\s*12px 16px;/)
|
||||
expect(css).toMatch(
|
||||
/\.form-image-toolbar\.has-impact-picker\s*\{[^}]*grid-template-columns:\s*minmax\(220px, 340px\) minmax\(0, 1fr\);/
|
||||
)
|
||||
expect(css).toMatch(
|
||||
/@container \(max-width: 1200px\)\s*\{\s*\.form-image-toolbar\.has-impact-picker\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\);/
|
||||
)
|
||||
})
|
||||
|
||||
it('单图标按钮以当前控件高度为边长,尺寸与内容按钮互不影响', () => {
|
||||
// happy-dom 不计算几何尺寸,此项约束共用样式和调用方,实际布局仍需浏览器验收。
|
||||
const css = readFileSync('src/admin.css', 'utf8')
|
||||
|
||||
@@ -379,13 +379,10 @@ async function showStaleForms() {
|
||||
>镜头影响检查失败,暂时无法确认有无过期首帧:{{ impact.query.error.value }}
|
||||
<NButton text size="small" @click="impact.query.refresh">重试检查</NButton></NAlert
|
||||
>
|
||||
<div
|
||||
v-if="impactOptions.length || sourceShotId"
|
||||
class="asset-impact-context mt-3"
|
||||
aria-label="镜头与素材定位"
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<div class="form-image-filter-region">
|
||||
<div class="form-image-toolbar" :class="{ 'has-impact-picker': impactOptions.length || sourceShotId }">
|
||||
<NSelect
|
||||
v-if="impactOptions.length || sourceShotId"
|
||||
:value="sourceShot?.shotId ?? null"
|
||||
:options="impactOptions"
|
||||
placeholder="选择过期镜头,查看关联素材"
|
||||
@@ -394,6 +391,34 @@ async function showStaleForms() {
|
||||
class="asset-impact-select"
|
||||
@update:value="selectImpactShot"
|
||||
/>
|
||||
<div class="form-image-filters" role="group" aria-label="形态图片筛选">
|
||||
<NInput
|
||||
placeholder="搜索主体、引用或形态"
|
||||
:input-props="{ 'aria-label': '搜索形态图片' }"
|
||||
v-model:value="search"
|
||||
clearable
|
||||
><template #prefix><Search :size="14" /></template
|
||||
></NInput>
|
||||
<NSelect
|
||||
aria-label="筛选主体类型"
|
||||
v-model:value="module"
|
||||
:options="[
|
||||
{ label: String('全部类型'), value: 'all' },
|
||||
{ label: String('人物'), value: 'character' },
|
||||
{ label: String('场景'), value: 'scene' },
|
||||
{ label: String('道具'), value: 'prop' }
|
||||
]"
|
||||
></NSelect>
|
||||
<div class="filter-toggles">
|
||||
<NCheckbox v-model:checked="onlyMissing">仅看缺少主图</NCheckbox>
|
||||
<NCheckbox v-model:checked="onlyStale">仅看身份过期</NCheckbox>
|
||||
</div>
|
||||
<span class="filter-result-count">{{ filtered.length }} 个形态</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="sourceShotId" class="asset-impact-context mt-3" aria-label="镜头与素材定位">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<RouterLink v-if="sourceLocation" :to="sourceLocation" class="text-button"
|
||||
>返回第 {{ sourceShot?.episodeNo }} 集 · 镜头 {{ sourceShot?.shotNo }} →</RouterLink
|
||||
>
|
||||
@@ -470,32 +495,6 @@ async function showStaleForms() {
|
||||
}}</template>
|
||||
<NButton text size="small" @click="resetFilters">清除定位</NButton>
|
||||
</NAlert>
|
||||
<div class="form-image-filter-region">
|
||||
<div class="form-image-filters" role="group" aria-label="形态图片筛选">
|
||||
<NInput
|
||||
placeholder="搜索主体、引用或形态"
|
||||
:input-props="{ 'aria-label': '搜索形态图片' }"
|
||||
v-model:value="search"
|
||||
clearable
|
||||
><template #prefix><Search :size="14" /></template
|
||||
></NInput>
|
||||
<NSelect
|
||||
aria-label="筛选主体类型"
|
||||
v-model:value="module"
|
||||
:options="[
|
||||
{ label: String('全部类型'), value: 'all' },
|
||||
{ label: String('人物'), value: 'character' },
|
||||
{ label: String('场景'), value: 'scene' },
|
||||
{ label: String('道具'), value: 'prop' }
|
||||
]"
|
||||
></NSelect>
|
||||
<div class="filter-toggles">
|
||||
<NCheckbox v-model:checked="onlyMissing">仅看缺少主图</NCheckbox>
|
||||
<NCheckbox v-model:checked="onlyStale">仅看身份过期</NCheckbox>
|
||||
</div>
|
||||
<span class="filter-result-count">{{ filtered.length }} 个形态</span>
|
||||
</div>
|
||||
</div>
|
||||
<NAlert v-if="query.error.value" role="alert" type="error" :show-icon="false" class="mt-4"
|
||||
>{{ query.error.value }}<span v-if="forms.length"> 当前展示上次读取的数据。</span></NAlert
|
||||
><NAlert v-if="running" role="status" type="info" :show-icon="false" class="mt-4">
|
||||
|
||||
@@ -229,11 +229,22 @@ describe('过期首帧到具体素材定位', () => {
|
||||
expect(wrapper!.findAll('.form-image-card')).toHaveLength(3)
|
||||
expect(wrapper!.text()).not.toContain('个形态主图与当前已锁定身份母版不一致')
|
||||
expect(fetcher.mock.calls.some(([url]) => String(url).endsWith('/references'))).toBe(false)
|
||||
// 镜头选择和图库筛选共享上方工具栏;未选择镜头时不留下空的关联说明面板。
|
||||
const toolbar = wrapper!.get('.form-image-toolbar')
|
||||
const picker = toolbar.get('.asset-impact-select').element
|
||||
expect(toolbar.classes()).toContain('has-impact-picker')
|
||||
expect(picker.nextElementSibling).toBe(toolbar.get('.form-image-filters').element)
|
||||
expect(toolbar.find('input[aria-label="搜索形态图片"]').exists()).toBe(true)
|
||||
expect(toolbar.findAll('.filter-toggles [role="checkbox"]')).toHaveLength(2)
|
||||
expect(wrapper!.find('.asset-impact-context').exists()).toBe(false)
|
||||
const select = wrapper!
|
||||
.findAllComponents(NSelect)
|
||||
.find(item => item.attributes('aria-label') === '选择关联镜头')!
|
||||
select.vm.$emit('update:value', 'shot-target')
|
||||
await flushPromises()
|
||||
expect(wrapper!.get('.asset-impact-context').element.previousElementSibling).toBe(
|
||||
wrapper!.get('.form-image-filter-region').element
|
||||
)
|
||||
expect(wrapper!.text()).toContain('待处理首帧关联此素材')
|
||||
expect(fetcher.mock.calls.filter(([url]) => String(url).endsWith('/references'))).toHaveLength(1)
|
||||
})
|
||||
|
||||
@@ -817,6 +817,9 @@ describe('工作台页面交互', () => {
|
||||
vi.stubGlobal('fetch', fetcher)
|
||||
await mountSubjectImages()
|
||||
const filters = wrapper!.get('.form-image-filters')
|
||||
expect(wrapper!.get('.form-image-toolbar').classes()).not.toContain('has-impact-picker')
|
||||
expect(filters.element.parentElement).toBe(wrapper!.get('.form-image-toolbar').element)
|
||||
expect(wrapper!.findAll('.form-image-filters')).toHaveLength(1)
|
||||
expect(filters.get('.filter-result-count').text()).toBe('2 个形态')
|
||||
expect(filters.find('input[aria-label="搜索形态图片"]').exists()).toBe(true)
|
||||
expect(filters.findAll('.filter-toggles [role="checkbox"]')).toHaveLength(2)
|
||||
|
||||
Reference in New Issue
Block a user