# 站内信顶部铃铛未读角标接入（前端对接 spec · 管理后台）

- **类型**：前端对接说明（**后端零改动**，数据/信令均已就绪）
- **端类型**：管理后台（hl-ui，各业务页顶部铃铛）
- **日期**：2026-06-25
- **后端联系人**：王骁（wx）

> 现象（wx 反馈）：房务给定制师发了消息，定制师（在 order-v2 订单详情页）顶部铃铛 🔔 **没有红点**。
> 排查结论：**后端完全正确**（收件方未读已落库、实时信令已推、未读数接口返真值），铃铛没红点是**前端没把未读数接到铃铛上**。

---

## 1 后端已就绪（实测确认）

某条消息发给收件方后，后端做了三件事：

1. **落库未读**：`admin_message`（收件方 adminId、`is_read=0`）+ 收件方 `member.unread_count+1`。实测房务发「4」后 `countUnread(定制师)=1`、`member.unread_count=1`。
2. **推实时信令**（事务提交后 SSE 广播，跨实例）：
   - 聊天消息 → 事件 `im-chat`（`type=CHAT`），payload 含 **`unreadCount`=收件方合并未读（NOTIFY+CHAT）**、`conversationKey`、`senderName`、`preview`、`priority`。
   - 系统通知 → 事件 `message`（`type=NOTIFY`），payload 含 `unreadCount`。
   - 标记已读后 → 事件 `unread-count`（`type=UNREAD`），payload 含最新 `unreadCount`（角标回落）。
3. **未读数接口**：`GET /admin/message/unread-count` 返回当前登录员工合并未读总数（含聊天+通知）。

---

## 2 前端要做的（铃铛角标）

铃铛红点/数字 = 当前登录员工的合并未读数，前端需两路驱动：

1. **页面加载时**：调 `GET /admin/message/unread-count` 取初值，>0 显红点/数字。**每个有铃铛的页面都要调**（order-v2 订单详情、房务管家、各工作台…），不能只在某一个页面调。
2. **实时更新**：订阅 SSE 流（`/ws/admin-msg/stream`，与聊天同一条连接），在以下事件里读 `payload.unreadCount` 刷新铃铛角标：
   - `im-chat`（收到聊天）→ 取 `unreadCount` 刷角标（红点点亮/数字+1）。
   - `message`（收到通知）→ 同上。
   - `unread-count`（自己标已读后）→ 取 `unreadCount` 刷角标（回落）。

> 关键：`im-chat` 事件**既驱动聊天 UI（live append）也驱动铃铛角标**——前端收到 `im-chat` 别只 append 聊天、要同时用 `payload.unreadCount` 刷铃铛。order-v2 订单详情页当前的铃铛大概率①没订阅这条 SSE 流，②或没在加载时调 unread-count，所以收了消息不亮红点。

---

## 3 注意

1. 铃铛角标是**合并未读**（聊天+通知），口径就是 `GET /admin/message/unread-count`，SSE 各事件 payload 的 `unreadCount` 与之一致，直接用即可，不用前端自己累加计数。
2. SSE 连接要保证在用户登录后的各页面都建立（铃铛是全局组件），否则切到没订阅的页面就收不到实时点亮（刷新时靠 unread-count 兜底）。
3. 有疑问找后端（王骁/wx）。
