3.7 KiB
3.7 KiB
合并「批量生成」与「生成一篇」按钮设计
背景
WorkspaceToolbar.vue 当前并排放置两个独立按钮:
<button data-testid="batch-generate" @click="$emit('batchGenerate')">批量生成</button>
<button data-testid="generate" @click="$emit('generate')">生成一篇</button>
需求:把这两个按钮合并成一个按钮,点击后通过下拉菜单选择具体执行哪种生成方式。
交互
- 合并后的主按钮文案为「生成教案 ▾」。
- 点击主按钮只展开/收起下拉菜单,本身不直接触发任何生成动作。
- 下拉菜单包含两个选项:「生成一篇」「批量生成」。点击任意一项后:
- 触发对应事件(
generate/batchGenerate)。 - 自动收起菜单。
- 触发对应事件(
- 点击组件外部区域、或按下
Escape键,菜单自动收起。
组件设计
新增 src/components/GenerateMenuButton.vue
负责封装下拉菜单的全部状态与交互,对外接口与现状保持一致:
defineEmits<{
generate: []
batchGenerate: []
}>()
行为:
- 内部
open = ref(false)控制展开状态。 - 根元素绑定
ref,onMounted时在document上注册click监听,点击目标不在根元素内时关闭菜单;onUnmounted时移除监听。 - 监听
keydown的Escape关闭菜单。 - 菜单项按钮保留
data-testid="generate"与data-testid="batch-generate",点击后emit对应事件并将open置为false。 - 主按钮
data-testid="generate-menu-toggle",点击切换open,并设置aria-expanded反映状态;下拉<ul>设置role="menu",菜单项role="menuitem",提升可访问性。
WorkspaceToolbar.vue 改动
将原来两个 <button> 替换为:
<GenerateMenuButton @generate="$emit('generate')" @batch-generate="$emit('batchGenerate')" />
WorkspaceToolbar 的 defineEmits、以及 WorkspaceView.vue 中对 @generate / @batch-generate 的监听逻辑保持不变——这是一次纯粹的局部封装,不影响上层的生成流程(BatchGenerateDialog.vue、GenerateLessonDialog.vue 均无需改动)。
样式 (src/style.css)
新增:
.generate-menu:position: relative; display: inline-flex;,作为下拉容器的定位基准。.generate-menu-list:绝对定位在主按钮下方的面板,复用现有设计变量(var(--line)、var(--radius-md)、var(--green-100)、var(--green-600)),保持与其余 toolbar 按钮一致的视觉语言(边框、圆角、hover 高亮)。- 菜单项按钮去除默认边框,改为列表内的 flat 按钮,hover 时使用
var(--green-100)背景,与现有.workspace-toolbar button:hover视觉一致。
测试改动
WorkspaceToolbar.test.ts:原先直接点击[data-testid="generate"]的用例,改为先点击[data-testid="generate-menu-toggle"]展开菜单,再点击目标菜单项。WorkspaceView.test.ts(第 95、131 行附近):同理,先展开菜单再点击generate/batch-generate。- 新增
GenerateMenuButton.test.ts,覆盖:- 默认菜单收起(菜单项不在 DOM 中)。
- 点击主按钮展开菜单。
- 点击「生成一篇」触发
generate事件并收起菜单。 - 点击「批量生成」触发
batchGenerate事件并收起菜单。 - 点击组件外部区域后菜单收起。
范围说明
本次改动仅涉及 UI 层的按钮合并与交互封装,不涉及:
- 生成逻辑本身(
booksApi.generateOutline()、generateLessons()等)。 BatchGenerateDialog.vue/GenerateLessonDialog.vue内部实现。- 移动端窄屏样式的额外适配(沿用现有
.workspace-toolbar响应式规则,新按钮作为其中一个 flex item 自然换行)。