Skip to content

实时消息与角标

Trix 的实时消息能力独立于通知下拉组件存在。后端注入配置后,前端会启动统一的 realtime 服务;通知铃铛、自定义导航项、菜单角标都从同一份通知状态读取数量。

配置结构

后端注入的 realtime 配置会传给 useNotificationRealtime()

json
{
  "enabled": true,
  "driver": "polling",
  "polling": {
    "api": "/notifications/poll",
    "interval": 15000
  },
  "websocket": {
    "url": ""
  },
  "enableNotification": true,
  "behaviors": {
    "audit.pending": {
      "notify": false,
      "actions": [
        { "type": "sound", "src": "/sounds/audit.mp3", "times": 3 },
        { "type": "notification", "title": "新的审核任务" }
      ]
    }
  }
}

driver 支持:

  • polling:按间隔请求 polling.api,请求参数会带 since_id
  • ws:连接 websocket.url,收到 { "type": "notification", "data": {...} } 时处理新消息。

消息数据

一条消息至少应包含:

json
{
  "id": 1001,
  "type": "audit.pending",
  "title": "新的审核任务",
  "content": "用户提交了实名审核",
  "isRead": false,
  "createdAt": "2026-07-03 10:00:00",
  "extra": {
    "actions": [
      { "type": "sound", "src": "/sounds/audit.mp3", "times": 3 }
    ]
  }
}

若消息自身的 extra.actions 存在,会优先使用它;否则使用 realtime.behaviors[type].actions

行为动作

内置动作:

  • sound:播放 src 指定的声音,times 控制播放次数,范围 1 到 10。
  • notification:弹出 Naive UI notification,可覆盖 titlecontentduration

业务也可以注册自定义动作:

typescript
import { useNotificationRealtime } from '@/service/notification/realtime'

useNotificationRealtime().registerBehaviorAction('openRoute', async (action, message) => {
  // 根据 action 或 message 执行业务逻辑
})

浏览器通常要求用户先与页面交互后才能播放声音。Trix 启动时会安装 audio unlock 监听,在首次 pointerdownkeydowntouchstartclick 后解锁;解锁前到达的声音会进入队列,解锁后按顺序播放。

角标统计

菜单和自定义导航项的角标统一使用 badge 配置:

json
{
  "badge": {
    "source": "notification",
    "types": ["audit.pending"],
    "mode": "count",
    "max": 99,
    "color": "#f5222d"
  }
}

source: "notification" 时,数量来自 realtime 返回的 unread_count_by_type,不是当前通知列表分页结果,因此不会因分页只加载一部分数据而统计错误。处理完业务后,后端应在下一次轮询或 WebSocket 推送中返回新的未读计数;前端也可调用 useNotificationRealtime().refresh() 主动刷新。

自定义导航项跳转

自定义导航项支持:

  • click: "route":后台内部路由跳转,效果与点击菜单一致。
  • click: "link":打开链接;target: "_blank" 新标签页,target: "_self" 当前页。
  • click: "modal" / click: "drawer":保留给 schema 内容交互。
  • schema_api:接口返回任意 schema 节点,由导航项位置渲染。

内部路由建议配置为最终路由路径,例如 /finance/recharges。如果后端菜单生成时已经带模块前缀,不要在前端或配置中再重复拼接模块名。

基于 MIT 许可发布