style: 对齐拆解设置控件并修复单位换行

This commit is contained in:
GouJ
2026-09-02 17:06:06 +08:00
parent 6bc07b559e
commit 7d8074f90e
5 changed files with 164 additions and 43 deletions
@@ -140,6 +140,58 @@ async function selectTab(label: string) {
}
describe('拆解页内容滚动', () => {
it('拆解设置保留输入标签、单行单位与模块说明,改版后仍校验模块和剧本状态', async () => {
const fetcher = vi.fn<typeof fetch>()
vi.stubGlobal('fetch', fetcher)
const provided = mountPage()
await wrapper!.get('[data-workspace-tools]').trigger('click')
await flushPromises()
const config = wrapper!.get('.breakdown-config')
expect(config.get('label[for="group-size"]').text()).toBe('每组集数')
expect(config.get<HTMLInputElement>('#group-size').element.value).toBe('3')
expect(config.get('.breakdown-group-unit').text()).toBe('集 / 组')
expect(config.get('fieldset > legend').text()).toBe('抽取模块')
const options = config.findAll('.breakdown-module-option')
expect(options).toHaveLength(3)
const preview = config.get<HTMLButtonElement>('.breakdown-preview-button')
expect(preview.element.disabled).toBe(false)
for (const option of options) {
const checkbox = option.get('[role="checkbox"]')
const description = option.get('.breakdown-module-description')
expect(checkbox.attributes('aria-describedby')).toBe(description.attributes('id'))
expect(checkbox.find('.breakdown-module-description').exists()).toBe(false)
expect(description.text()).not.toBe('')
await checkbox.trigger('click')
}
expect(preview.element.disabled).toBe(true)
expect(wrapper!.text()).toContain('至少选择一个抽取模块')
await options[1]!.get('[role="checkbox"]').trigger('click')
expect(preview.element.disabled).toBe(false)
provided.data.value!.project.status = 'generating'
await flushPromises()
expect(preview.element.disabled).toBe(true)
expect(fetcher).not.toHaveBeenCalled()
})
it('拆解配置按抽屉宽度换行,单位不收缩,三类控件对齐且说明位于控件下方', () => {
// DOM 环境不计算坐标,检查统一标题偏移、34px 控件行和容器断点契约。
const css = readFileSync('src/admin.css', 'utf8')
expect(css).toMatch(/\.breakdown-settings-panel\s*\{\s*container:\s*breakdown-settings \/ inline-size;/)
expect(css).toMatch(/\.breakdown-config\s*\{[^}]*--breakdown-label-offset:\s*28px;/)
expect(css).toMatch(/\.breakdown-config \.field-label\s*\{[^}]*margin:\s*0 0 8px;[^}]*line-height:\s*20px;/)
expect(css).toMatch(/\.breakdown-group-unit\s*\{[^}]*flex-shrink:\s*0;[^}]*white-space:\s*nowrap;/)
expect(css).toMatch(
/\.n-checkbox\.control-row-checkbox\s*\{[^}]*align-items:\s*center;[^}]*min-height:\s*34px;/
)
expect(css).toMatch(
/\.breakdown-preview-button\.n-button\s*\{[^}]*align-self:\s*start;[^}]*margin-top:\s*var\(--breakdown-label-offset\);/
)
expect(css).toContain('@container breakdown-settings (max-width: 780px)')
expect(css).toContain('@container breakdown-settings (max-width: 560px)')
expect(css).toContain('repeat(auto-fit, minmax(min(100%, 160px), 1fr))')
expect(readFileSync('src/styles.css', 'utf8')).not.toContain('.breakdown-config')
})
it.each(['人物', '场景', '道具'])('%s 使用共用固定斑马纹样式,搜索后保持列表条目结构', async label => {
mountPage()
await selectTab(label)
+31 -23
View File
@@ -155,7 +155,7 @@ function exportResult() {
</div>
<div v-if="project?.episodes.length" class="toolbar-actions">
<WorkspaceTools v-model:open="toolsOpen" title="拆解设置与恢复" label="拆解设置与恢复">
<section class="panel p-5 lg:p-6">
<section class="panel breakdown-settings-panel p-5 lg:p-6">
<div class="mb-5 flex flex-wrap items-start justify-between gap-3">
<div>
<h2 class="flex items-center gap-2 font-semibold"><Layers :size="17" />拆解设置</h2>
@@ -168,38 +168,46 @@ function exportResult() {
<NTag size="small" :bordered="false">来源正式剧集</NTag>
</div>
<div class="breakdown-config">
<div>
<div class="breakdown-group-field">
<label class="field-label" for="group-size">每组集数</label>
<div class="flex items-center gap-3">
<div class="breakdown-group-input">
<NInputNumber
:disabled="operation.pending"
:input-props="{ id: 'group-size' }"
class="w-24"
class="breakdown-group-number"
:value="typeof groupSize === 'number' ? groupSize : null"
@update:value="groupSize = $event ?? 0"
:min="1"
:step="1"
></NInputNumber
><span class="text-sm text-muted"> / </span>
><span class="breakdown-group-unit"> / </span>
</div>
</div>
<fieldset class="flex flex-wrap gap-5 border-0 p-0">
<legend class="field-label mb-3">抽取模块</legend>
<NCheckbox
:checked="modules.includes(option.value)"
:disabled="operation.pending"
:aria-label="option.label"
@update:checked="toggleModule(option.value, $event)"
v-for="option in moduleOptions"
:key="option.value"
class="flex cursor-pointer items-start gap-2.5"
><span
><span class="block text-sm font-medium">{{ option.label }}</span
><span class="mt-1 block text-[11px] text-muted">{{
option.description
}}</span></span
></NCheckbox
>
<fieldset class="breakdown-modules-field">
<legend class="field-label">抽取模块</legend>
<div class="breakdown-module-options">
<div
v-for="option in moduleOptions"
:key="option.value"
class="breakdown-module-option"
>
<NCheckbox
:checked="modules.includes(option.value)"
:disabled="operation.pending"
:aria-label="option.label"
:aria-describedby="`breakdown-module-${option.value}-help`"
@update:checked="toggleModule(option.value, $event)"
class="control-row-checkbox"
><span class="text-sm font-medium">{{ option.label }}</span></NCheckbox
>
<p
:id="`breakdown-module-${option.value}-help`"
class="breakdown-module-description"
>
{{ option.description }}
</p>
</div>
</div>
</fieldset>
<NButton
:disabled="
@@ -210,7 +218,7 @@ function exportResult() {
!!error
"
@click="loadPreview"
class="self-end"
class="breakdown-preview-button"
><LoaderCircle v-if="previewBusy" :size="14" class="animate-spin" />预览分组
</NButton>
</div>