Files
workspace/code/fms/.codebuddy/plans/message-notification-components_11d5494a.md
T
2026-08-16 22:01:32 +08:00

10 KiB
Raw Blame History

name, overview, design, todos
name overview design todos
message-notification-components 在 fms-vue 组件库新增 Message(轻提示)与 Notification(通知)两套组件,提供命令式全局 API(Message.success/error/...、Notification.open/close/closeAll)并保留可声明式使用的组件,遵循现有组件库规范(scoped SCSS + index.scss 变量、lucide 图标、Teleport/Transition 复用),最后在 App.vue 加演示入口并用 Playwright(端口 5082)实测。
architecture styleKeywords fontSystem colorSystem
framework component
vue shadcn
简洁卡片
轻提示
右上角通知
柔和阴影
类型配色
平滑过渡
fontFamily heading subheading body
PingFang SC
size weight
20px 600
size weight
15px 500
size weight
14px 400
primary background text functional
#2563EB
#16A34A
#D97706
#DC2626
#FFFFFF
#F8FAFC
#1E293B
#64748B
#16A34A
#DC2626
#D97706
#2563EB
id content status
explore-export 用 [subagent:code-explorer] 确认 ui 导出方式与 App.vue 演示结构 completed
id content status dependencies
build-message 实现 message.vue、message-manager.js、index.scss completed
explore-export
id content status dependencies
build-notification 实现 notification.vue、notification-manager.js、index.scss completed
explore-export
id content status dependencies
app-demo 在 App.vue 新增 Message/Notification 演示区块 completed
build-message
build-notification
id content status dependencies
verify-playwright 用 [skill:playwright-cli] 在 5082 端口验证显示/消失/关闭/堆叠 completed
app-demo
id content status dependencies
lint-check 运行 oxlint 确认新增文件无错误 completed
app-demo

用户需求

在 fms-vue 组件库中新增 Message(轻提示)与 Notification(通知)两套组件,采用命令式 API 为主、声明式组件为辅的设计。

产品概述

  • Message:页面顶部居中的轻量级反馈提示,用于操作结果反馈,自动消失,不打断用户操作。
  • Notification:页面右上角的通知卡片,用于承载较丰富的信息(标题 + 描述),支持手动关闭与自动消失。
  • 两者均支持全局命令式调用(Message.success / Notification.open),同时保留 <Message> / <Notification> 组件供声明式使用。

核心功能

  • 命令式入口:Message.success/error/warning/info(content, options);Notification.open(options);均返回可关闭的实例句柄。
  • 消息类型:info / success / warning / error 四种,复用 lucide 图标与现有主题 CSS 变量配色。
  • 自动关闭:Message 默认 3000ms,Notification 默认 4500ms;duration 为 0 时不自动关闭。
  • 手动关闭:Notification 提供关闭按钮;Message 在 hover 时可常驻并提供关闭按钮(可选)。
  • 堆叠与重排:多条消息纵向堆叠(Message 顶部居中、Notification 右上角),关闭后后续项平滑上移。
  • App.vue 演示区块:提供按钮触发各类型,便于人工与 Playwright 验证。
  • 严格遵循现有项目规范(scoped SCSS + @use 模式、无 placeholder 逻辑、复用 Teleport/Transition 模式)。

技术栈选择

  • 框架:Vue 3(SFC + <script setup>),与现有组件一致
  • 样式:SCSS(scoped + @use './index.scss'),复用现有 CSS 变量与主题体系
  • 图标:@lucide/vue(已引入),复用 CheckCircle2 / AlertCircle / Info / X 等
  • 浮层挂载:Teleport to="body" + Transition,参考 Popover 模式但采用 fixed 固定定位(不跟随触发器)

实现方案

总体策略

采用「单例容器 + 程序化挂载」的命令式方案:每个管理器(message-manager / notification-manager)在首次调用时创建一个挂在 document.body 的容器组件(用 createVNode + render),容器内部用响应式数组维护当前活跃条目,新增时 push、关闭时移除并播放退场动画后卸载。组件本身(message.vue / notification.vue)作为单条目渲染单元,既被管理器内部使用,也可被外部声明式引用。

关键技术决策

  1. 单例容器 vs 每次新建:单例避免重复创建 DOM 与监听器,降低开销;容器组件统一管理 Transition 与堆叠计算。
  2. fixed 定位而非 Popover 定位逻辑:Message/Notification 不依赖触发元素,使用 CSS position: fixed + 居中/右上角偏移即可,无需引入 position.js 计算,减少依赖与复杂度。
  3. id 句柄关闭:每条目生成唯一 id,命令式调用返回 { close },Notification.close(id) / closeAll 通过 id 过滤数组实现。
  4. 自动关闭计时器:在条目组件内用 setTimeout,onBeforeUnmount 清理;duration<=0 不启用。Hover 暂停(Notification 可选)提升可用性。
  5. 堆叠重排:依赖 Vue <TransitionGroup> 的 move 过渡实现关闭后其余项平滑位移,避免手动计算 top。

性能与可靠性

  • 单例容器,全局仅 1 个监听器集合;条目数量受控(可设 maxCount 限制,超出时移除最早项)。
  • 计时器在卸载时清理,防止内存泄漏;render(null) 在容器无条目且长时间空闲时可销毁(可选,初版保留单例)。
  • 命令式 API 与组件 props 共用同一套类型定义,保证一致性。

实现注意事项

  • 严格沿用现有组件 SFC 结构:<style scoped lang="scss"> @use './index.scss',不写内联 style。
  • 配色复用现有 CSS 变量(如 --fms-text-secondary、主色变量),接入 ColorThemePicker 主题体系,不硬编码颜色。
  • 不得引入任何 placeholder 相关逻辑(遵循近期规范清理结果)。
  • 图标复用 @lucide/vue,不新增图标依赖。
  • 过渡动画命名约定风格与 popover transition 一致(如 message-fade、notification-slide)。
  • 容器设置 pointer-events: none,子项 pointer-events: auto,避免遮挡页面交互。

架构设计

组件关系

graph TD
  A[命令式 API] --> B[message-manager.js]
  A --> C[notification-manager.js]
  B --> D[MessageContainer 内部]
  C --> E[NotificationContainer 内部]
  D --> F[message.vue 单条]
  E --> G[notification.vue 单条]
  F --> H[(document.body 单例容器)]
  G --> H

管理器负责创建/复用 body 上的单例容器,容器内用 TransitionGroup 渲染多个条目组件。

目录结构

src/components/ui/
├── message/
│   ├── message.vue            # [NEW] 单条消息组件。props: type/content/duration/closable/onClose;渲染图标+文案+关闭按钮;内置自动关闭计时与淡出;可被声明式使用
│   ├── message-manager.js     # [NEW] 命令式入口。单例容器 createVNode+render 挂 body;导出 success/error/warning/info/close;维护活跃列表与堆叠
│   └── index.scss             # [NEW] 消息样式。fixed 顶部居中、pointer-events 处理、type 配色、message-fade 过渡
├── notification/
│   ├── notification.vue       # [NEW] 单条通知组件。props: type/title/description/duration/closable/onClose;图标+标题+描述+关闭按钮;自动关闭+滑动退场
│   ├── notification-manager.js# [NEW] 命令式入口。open/close(id)/closeAll;右上角堆叠、TransitionGroup 重排
│   └── index.scss             # [NEW] 通知样式。右侧卡片、阴影、type 配色、notification-slide 进场/退场
└── (导出) 若项目存在 barrel 文件则补充导出,否则 App.vue 直接按路径 import
src/App.vue                    # [MODIFY] 新增演示区块:按钮组触发各类型 Message/Notification,沿用现有演示布局风格

关键代码结构

管理器导出口(message-manager.js):

export const Message = {
  success: (content, opts) => open({ type: 'success', content, ...opts }),
  error:   (content, opts) => open({ type: 'error', content, ...opts }),
  warning: (content, opts) => open({ type: 'warning', content, ...opts }),
  info:    (content, opts) => open({ type: 'info', content, ...opts }),
  close:   (id) => remove(id),
}

通知管理器导出口(notification-manager.js):

export const Notification = {
  open: (options) => open({ ...options }),
  close: (id) => remove(id),
  closeAll: () => clear(),
}

设计风格

沿用现有 fms-vue 组件库的简洁卡片风格,与 Button/Select 视觉体系保持一致。Message 为顶部居中的轻量胶囊/卡片提示,带左侧类型图标与柔和阴影;Notification 为右上角白色卡片,左侧类型色条+图标,标题加粗、描述次要色,右上角关闭按钮。整体采用现有主题 CSS 变量配色,支持明暗主题切换,过渡平滑(淡入下滑 / 滑出上移)。

页面区块(App.vue 演示)

  • 顶部标题区块:说明 Message 与 Notification 演示区
  • Message 触发区:四枚按钮(info/success/warning/error)触发对应轻提示
  • Notification 触发区:按钮触发通知,并含「关闭全部」按钮
  • 底部说明:调用方式代码示例(纯文本展示)

Agent Extensions

Skill

  • playwright-cli
  • Purpose: 在端口 5082 启动/复用 dev server 后,通过 Playwright 实测 Message/Notification 的显示、自动消失、手动关闭与多条堆叠顺序
  • Expected outcome: 验证各类型元素出现、文案与 type class 正确、duration 后自动移除、关闭按钮可移除、连续触发堆叠顺序正确,输出断言结果

SubAgent

  • code-explorer
  • Purpose: 在生成计划前确认 src/components/ui 是否存在 barrel 导出文件及 App.vue 现有演示区块结构,避免路径与风格冲突
  • Expected outcome: 明确导出方式与 App.vue 插入位置,保证新增演示与现有布局一致