Skyroc Admin React
专题能力

通知系统

使用 @skyroc/web-admin-notification 接入后台 header 通知按钮、通知 Provider 和演示页能力

这一页说明 apps/admin 如何使用 @skyroc/web-admin-notification。重点是区分三层职责:应用提供通知 Provider 和声音资源,后台 layout 把通知按钮放进 header,业务页面通过 context 创建和管理通知。

当前通知系统是前端内存态能力。刷新页面后,NotificationProvider 中的通知列表会重置;如果要做站内消息中心或服务端通知,需要在业务侧接接口,再把接口结果转换成 package 的 NotificationItem

只想查 NotificationProvider props、useNotificationContext() 返回值和类型,直接看 通知系统 API

适用场景

场景重点位置
在后台 header 显示通知入口pages/(admin)/layout.tsxNotificationButton
让业务页面发通知useNotificationContext()
修改通知声音App.tsxassets/audio/wechat-style-notification.wavNotificationProvider.soundUrl
控制浏览器通知、声音、勿扰模式NotificationConfigupdateConfig()
做通知演示或调试pages/(admin)/manage/user/index.tsxuseMockNotifications()
扩展通知包能力packages/web/admin-notification/src/*

当前实现位置

文件职责
apps/admin/src/App.tsxAntdProvider 内挂载 NotificationProvider,并注入应用自己的通知音频。
apps/admin/src/pages/(admin)/layout.tsxNotificationButton 注入 WebAdminLayoutheaderMiddleActions
apps/admin/src/pages/(admin)/manage/user/index.tsx当前通知系统演示页,展示不同类型、优先级、批量操作、权限和配置控制。
apps/admin/src/assets/audio/wechat-style-notification.wav当前应用注入的通知声音资源。
packages/web/admin-notification/src/NotificationProvider.tsx通知上下文 Provider,封装 useNotification()
packages/web/admin-notification/src/NotificationButton.tsxHeader 通知按钮,展示未读角标并弹出通知面板。
packages/web/admin-notification/src/NotificationPanel.tsx通知面板 UI。
packages/web/admin-notification/src/use-notification.ts通知状态、声音、浏览器通知、权限和勿扰模式逻辑。
packages/web/admin-notification/src/types.ts通知项、优先级、类型和运行时配置类型。

接入链路

当前应用接入链路是:

App.tsx
  -> <NotificationProvider soundUrl={wechatStyleNotification}>
    -> RouterProvider / GlobalEffect / 后台页面

pages/(admin)/layout.tsx
  -> <WebAdminLayout headerMiddleActions={<NotificationButton />} />

业务页面
  -> useNotificationContext()
  -> addNotification() / markAllAsRead() / updateConfig()

NotificationProvider 必须包住所有要使用通知 context 的页面和 header 按钮。当前它位于 App.tsx,所以后台 layout 和页面都能读取同一份通知状态。

Provider 配置

App.tsx 当前这样挂载通知能力:

import { NotificationProvider } from '@skyroc/web-admin-notification';

import wechatStyleNotification from './assets/audio/wechat-style-notification.wav';

const App = () => (
  <Provider>
    <AntdProvider>
      <NotificationProvider soundUrl={wechatStyleNotification}>
        <LazyAnimate>
          <RouterProvider />
          <GlobalEffect />
        </LazyAnimate>
      </NotificationProvider>
    </AntdProvider>
  </Provider>
);

这里有两个边界:

边界原因
@skyroc/web-admin-notification 提供运行时和 UI通知列表、角标、面板、声音播放和浏览器通知逻辑可复用。
apps/admin 注入 soundUrl音频资源属于宿主应用,不应该硬编码进共享包。

如果通知点击需要走 TanStack Router,而不是默认 window.location.href,可以给 NotificationProvideronNavigate,在应用侧调用 router 跳转。

Header 通知按钮

后台 layout 把通知按钮放在 header 中间动作区:

<WebAdminLayout
  footer={<AdminFooter />}
  headerMiddleActions={<NotificationButton className="px-12px" />}
  headerRightActions={<UserAvatar />}
  logo={<SystemLogo className="text-32px text-primary" />}
  logoTitle={t('system.title')}
/>

NotificationButton 做的事情包括:

能力当前行为
未读角标unreadCount > 99 时显示 99+
按钮动画有未读时使用 swing,无未读时使用 scale
面板打开Ant Design Dropdown,点击按钮打开通知面板。
标记已读点击通知项时调用 markAsRead(id)
删除通知调用 removeNotification(id)
全部已读和清空调用 markAllAsRead()clearAllNotifications()

Header 只负责展示入口。业务通知的创建不应该写在 layout 里。

业务页面发通知

页面通过 useNotificationContext() 获取通知 API:

import { Button } from 'antd';
import { useNotificationContext } from '@skyroc/web-admin-notification';

const SaveButton = () => {
  const { addSuccessNotification } = useNotificationContext();

  function handleSaveSuccess() {
    addSuccessNotification('保存成功', '用户信息已更新', {
      priority: 'normal'
    });
  }

  return (
    <Button type="primary" onClick={handleSaveSuccess}>
      保存
    </Button>
  );
};

快捷方法包括:

方法通知类型
addInfoNotification(title, content, options)info
addSuccessNotification(title, content, options)success
addWarningNotification(title, content, options)warning
addErrorNotification(title, content, options)error
addMessageNotification(title, content, options)message

需要完整控制时,使用 addNotification()

addNotification({
  content: '检测到异常登录行为,请立即检查账户安全。',
  link: '/user-center',
  priority: 'urgent',
  title: '安全警报',
  type: 'error'
});

通知项字段

NotificationItem 的核心字段如下:

字段作用
id稳定 ID;没有传入时由 nanoid() 生成。
title通知标题。
content通知正文。
type视觉类型:infosuccesswarningerrormessage
priority优先级:lownormalhighurgent
read是否已读;新增时默认 false
timestamp创建时间;新增时默认 Date.now()
link浏览器通知点击后的目标地址。
silent跳过通知声音。
showBrowserNotification是否触发浏览器原生通知。
meta业务自定义数据。

NotificationShortcutOptions 可以覆盖除 titlecontenttype 之外的多数通知项字段。

声音、浏览器通知和勿扰模式

通知运行时配置默认值:

export const DEFAULT_NOTIFICATION_CONFIG = {
  browserNotificationEnabled: true,
  doNotDisturb: false,
  maxNotifications: 99,
  soundEnabled: true
};

新增通知时,useNotification() 会按下面顺序处理副作用:

addNotification()
  -> setNotifications([newNotification, ...prev])
  -> playNotificationSound()
  -> showBrowserNotification()

副作用会被这些条件拦截:

条件影响
silent: true不播放声音,也不会触发浏览器通知。
showBrowserNotification: false只创建应用内通知。
config.soundEnabled === false不播放声音。
config.browserNotificationEnabled === false不触发浏览器通知。
config.doNotDisturb 且当前时间在 doNotDisturbTime不播放声音,也不触发浏览器通知。
浏览器通知权限不是 granted不触发浏览器通知。

请求浏览器通知权限用:

const granted = await requestNotificationPermission();

浏览器通知权限由浏览器控制,不能在应用里静默开启。页面可以引导用户点击按钮触发授权,但不能自动弹出授权请求。

演示页

当前 apps/admin/src/pages/(admin)/manage/user/index.tsx 是通知系统演示页。它展示了:

演示内容使用的 API
信息、成功、警告、错误、消息通知addInfoNotification() 等快捷方法
紧急、低优先级通知addNotification({ priority })
静音通知silent: true
仅应用内通知showBrowserNotification: false
带链接通知link
批量添加模拟通知useMockNotifications()
全部已读、清理已读、清空markAllAsRead()clearReadNotifications()clearAllNotifications()
配置切换updateConfig()

如果要把 /manage/user 恢复成用户管理列表,应先把通知演示迁移到独立示例页,或者重新选择一个示例路由,避免“用户管理”菜单和实际页面职责不一致。

常见误区

误区正确做法
在页面外使用 useNotificationContext() 却没有 Provider确保页面位于 NotificationProvider 子树下。当前 App.tsx 已覆盖后台页面。
把通知声音硬编码进共享包声音资源由宿主应用通过 soundUrl 注入。
以为通知会自动持久化当前通知状态是内存态;需要持久化时接业务接口或本地存储。
在 layout 里写业务通知创建逻辑layout 只放 NotificationButton,业务事件由页面或全局 effect 发通知。
直接依赖浏览器通知一定出现需要用户授权,且会受浏览器、系统和勿扰设置影响。

相关链接

On this page