From 799f16d33650c6ed4e5cff25ab510820ba80c09e Mon Sep 17 00:00:00 2001 From: GouJ Date: Tue, 1 Sep 2026 19:40:40 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E6=8C=89=20Beat=20=E5=88=86=E7=BB=84?= =?UTF-8?q?=E6=95=B4=E7=90=86=E9=95=9C=E5=A4=B4=E7=9B=AE=E5=BD=95=E5=B9=B6?= =?UTF-8?q?=E5=8E=BB=E9=99=A4=E9=87=8D=E5=A4=8D=E7=BC=96=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/admin.css | 40 ++++++++++-- src/components/ui/DirectoryItem.test.ts | 2 +- src/features/production/ProductionPage.vue | 21 +++---- src/features/storyboard/StoryboardPage.vue | 31 ++++------ .../components/BeatShotDirectory.vue | 57 +++++++++++++++++ src/features/storyboard/directory.test.ts | 62 +++++++++++++++++++ src/features/workflows/pages.test.ts | 3 + 8 files changed, 182 insertions(+), 35 deletions(-) create mode 100644 src/features/storyboard/components/BeatShotDirectory.vue create mode 100644 src/features/storyboard/directory.test.ts diff --git a/README.md b/README.md index cc69a65..aa0f8fb 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ Oxfmt 不负责代码质量,Oxlint 不负责 Vue 的完整类型推导;Vue S - 主体身份、分镜设计和镜头生产共用 `DirectoryItem`:编号、完整标题和状态分层展示,桌面目录为 240–280px,窄屏改为可横向滚动的条目。目录标题与筛选固定,只有列表滚动。拆解结果的导出按钮与标签同排右对齐;形态图片筛选按内容区宽度自动排成一行或两列网格。 - 侧栏导航与主体/剧集/镜头目录采用直角满行背景,移除列表两侧的内缩,悬停和选中态都铺满所在列。条目内部保留文字间距;窄屏横向目录仍保持独立滚动,不影响表单与弹窗的圆角。 - 主体目录以母版缩略图搭配名称、编号与状态,默认保留行背景和细分隔线。人物优先复用选角接口的母版;缺少地址的条目进入可视区域后才读取正式身份图库,不为整份目录轮询。无母版或加载失败显示人物/场景/道具图标,候选与形态图不会替代母版;点击缩略图只切换主体,刷新目录可重试读取。 +- 分镜设计与镜头生产共用两级镜头目录:分组头展示 `BEAT 01` 和镜头数,组内仅显示“镜头 01”、标题及状态。分组头在本组内吸顶;窄屏横向模式才在条目上补回 Beat 归属。点击仍使用正式 Shot ID,不会混淆不同 Beat 的同号镜头。 - 身份、分镜、生产与图库的批量配置、说明和诊断统一放入 `WorkspaceTools`(Naive UI Drawer),按需覆盖当前工作区,不挤压列表。面板支持 Esc 或关闭按钮;关闭不会取消任务或清除配置。历史回执可从入口查看,新回执主动打开诊断;查询错误始终在外层可见。 - 生产步骤的操作按钮保留上下间距;`ConfirmAction` 用稳定根元素承接外部间距,避免多根弹窗组件吞掉 `class`。 - 右上角提供浅色、暗黑、跟随系统三种模式,默认跟随系统,选择保存在本机浏览器。存储被禁用时仍可在当前会话切换。 diff --git a/src/admin.css b/src/admin.css index e1a8232..3283e22 100644 --- a/src/admin.css +++ b/src/admin.css @@ -461,15 +461,40 @@ body { padding: 8px 0 16px; } .directory-group-heading { + position: sticky; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; flex-shrink: 0; - padding: 14px 14px 2px; + padding: 10px 14px; + border-block: 1px solid var(--app-border); + background: var(--app-subtle); font: - 11px/1.6 ui-monospace, + 600 11px/1.6 ui-monospace, monospace; + color: var(--app-ink); +} +.directory-group-count { + font-weight: 400; color: var(--app-muted); } -.directory-group-heading:first-child { - padding-top: 2px; +.beat-directory-group { + min-width: 0; +} +.beat-directory-items { + display: flex; + flex-direction: column; +} +.directory-mobile-beat { + display: none; +} +.shot-list-content, +.production-shot-list-content { + gap: 12px; + padding: 0 0 12px; } .n-button.directory-item { display: flex; @@ -1216,6 +1241,13 @@ body { .directory-group-heading { display: none; } + .beat-directory-group, + .beat-directory-items { + display: contents; + } + .directory-mobile-beat { + display: inline; + } .identity-workspace { grid-template-columns: minmax(0, 1fr); grid-template-rows: 250px minmax(0, 1fr); diff --git a/src/components/ui/DirectoryItem.test.ts b/src/components/ui/DirectoryItem.test.ts index 50d7b51..ff07683 100644 --- a/src/components/ui/DirectoryItem.test.ts +++ b/src/components/ui/DirectoryItem.test.ts @@ -81,7 +81,7 @@ describe('统一目录条目', () => { ) ) } - expect(css).toMatch(/\.directory-group-heading\s*\{[^}]*padding:\s*14px 14px 2px/) + expect(css).toMatch(/\.directory-group-heading\s*\{[^}]*padding:\s*10px 14px/) expect(css).toMatch(/\.directory-list-content\s*\{[^}]*flex-direction:\s*row;[^}]*width:\s*max-content/) }) diff --git a/src/features/production/ProductionPage.vue b/src/features/production/ProductionPage.vue index 59476ac..12b6c72 100644 --- a/src/features/production/ProductionPage.vue +++ b/src/features/production/ProductionPage.vue @@ -14,7 +14,8 @@ import { } from 'naive-ui' import { computed, ref, watch } from 'vue' import { ArrowLeft, CheckCircle2, CircleAlert, Film, Image, MessageSquareText, RefreshCw } from '@lucide/vue' -import { DirectoryItem, EmptyState, StatusBadge } from '../../components/ui' +import { EmptyState, StatusBadge } from '../../components/ui' +import BeatShotDirectory from '../storyboard/components/BeatShotDirectory.vue' import ConfirmAction from '../workflows/ConfirmAction.vue' import { issueLabel, productionStatusLabel } from './model' import { useProduction } from './useProduction' @@ -412,15 +413,13 @@ watch( content-class="directory-list-content production-shot-list-content" x-scrollable > - {{ item.title }} - -