U8 Chat 2.0 · 消息表情回复(Reaction)产品需求文档(PRD)
| 项目 | 内容 |
|---|
| 文档版本 | v1.0(2026-09-17)· 在 PM 初稿基础上补齐交互口径、边界与判定规则,补充清单见第十二章,需产品拍板的点见第十一章 |
| 功能模块 | 聊天 → 消息级表情回复(Reaction) |
| 适用端 | iOS / Android / Web / Desktop(四端同一套规则,只有触发方式不同) |
| 线框与演示 | 同目录 index.html(17 屏可点击,含桌面端与移动端) |
| 参照产品 | Telegram「Reactions」· 本期为阉割版,阉割点见 2.2 |
| 设计稿 | 暂无(Figma 画布待建,样式沿用现有聊天页) |
本 PRD 相对初稿补了什么:初稿把交互主线写清楚了(触发 → 选表情 → 气泡内展示 → 数据反馈)。
缺的是开发无法自行决定的那些口径:一个人能回几个表情、点哪儿取消、数字代表什么意思、
单聊和群聊显示是否一样、什么消息不能回、撤回后怎么办、失败怎么表现、禁言用户能不能回(已拍板:不能)。
这些不是新功能,是同一功能的"判定规则",全部补齐在第六、七章;我没有增加任何初稿没提的能力。
一、背景与目标
1.1 背景
U8 Chat 目前的互动方式只有一种:再发一条消息。想表达"收到""好笑""同意",用户只能打字,或者发一个孤零零的 emoji 消息。
- 打字成本高:群里"哈哈哈"刷屏的场景,本可以用一个 😁 解决。
- 有表达力的成本:图片、语音、表情包都要先生产再发送,门槛高。
- 发送者拿不到反馈:一条公告/通知发出去,如果没有文字回复,发送者完全不知道有多少人看过、认同。
表情回复是在已有消息上追加一层轻量反馈,不产生新消息、不改变会话结构。
1.2 现状问题(本次要解决的)
| # | 问题 | 影响 |
|---|
| 1 | 只有"再发一条"一种互动方式 | 群聊被无信息量的短消息刷屏,"收到"类回复挤掉有效信息 |
| 2 | 消息发送者收不到任何反响数据 | 公告、通知类消息发出去后不知道有没有人看 |
| 3 | 长列表里"哪些消息重要"没有信号 | 用户翻记录时缺少"这条被很多人认可"的线索 |
1.3 目标
业务目标
- 给聊天增加一个低成本互动通道,抬升消息层面的互动率(而非消息量)。
用户目标
- 2 步完成一次表态:长按/右键消息 → 点表情。
- 不打扰:不会因为"有人给我点赞"而收到任何提醒、红点或未读。
成功指标(上线首月,目标值需与数据侧对齐后锁定)
| 指标 | 目标 |
|---|
| 日活用户中使用过表情回复的比例 | ≥ 25% |
| 人均每日表情回复次数 | ≥ 3 次 |
| 有表情回复的消息占比 | ≥ 6% |
| 操作成功率(点击 → 服务端写成功) | ≥ 99% |
| 表情回复相关的客诉("我明明点了" / "怎么冒出个图标") | ≈ 0 |
二、范围
2.1 本期做
| 模块 | 内容 |
|---|
| 触发 | 桌面端右键消息、移动端长按消息,调出「表情栏 + 消息操作栏」 |
| 表情栏 | 7 个固定快捷表情 + 「更多」入口 |
| 更多面板 | 一屏固定表情网格(48 个,顺序固定、无搜索、无分类、无最近使用) |
| 添加 / 更改 / 取消 | 每人每条消息最多 1 个表情;换一个 = 替换;再点一次 = 取消 |
| 气泡内展示 | 表情 + 头像(1~3 人)/ 数字(4 人及以上);自己参与的高亮;多端同步 |
| 谁回复了 | 桌面端悬停、移动端长按表情条 → 回复者名单 |
| 不打扰 | 无通知、无红点、不计未读、不改排序、不改会话列表预览 |
| 边界 | 消息撤回 / 删除 / 编辑 / 转发、禁言、拉黑、系统消息等(见第七章) |
2.2 本期不做(阉割版清单,明确划出)
| 不做的事 | 原因 |
|---|
| 「有人用表情回复我」的通知 / 提醒 / 红点 / 未读 | 初稿已定:阉割版核心。表情回复不进入任何聚合入口,只有消息在屏幕内时才看得见 |
| 表情回复的集中列表页(如"我收到的表情") | 同上,与"不打扰"冲突 |
| 自定义表情包 / 贴纸 / 付费表情 / 付费星标 | Telegram 的收费能力,本期不做 |
| 表情搜索、分类页签、"最近使用" | 已拍板:更多面板是一屏固定网格,顺序不变(决策 D1) |
| 会话级 / 群级表情开关(群主可选哪些表情) | 设置项,本期不做 |
| 表情回复的数量排行、统计、导出 | 超出"隐性反馈"的定位 |
| 给表情回复加文字说明 / 连击动画 / 礼花特效 | 非必要 |
| 深色模式、大字号无障碍适配 | 随全局一起排期 |
2.3 四端一致性
同一套规则四端一致,唯一的差异是"怎么唤出浮层"(见 6.1 与第八章)。
三、名词定义(务必与开发对齐,避免和现有功能混名)
| 名词 | 定义 |
|---|
| 表情回复 / Reaction(本功能) | 附加在某条已有消息上的表态,不产生新消息。一人一条消息最多 1 个。 |
| 引用回复 / Reply(已有功能,不是本功能) | 引用某条消息再发一条新消息。会进入会话、计数、通知。 |
| 输入框表情面板(已有功能,不是本功能) | 输入栏里打出 emoji 字符的工具,与 Reaction 无任何数据关系,不要复用同一套数据。 |
| 快捷表情栏 | 长按/右键后浮层里的那一行:7 个固定表情 + 「更多」。 |
| 更多面板 | 点「更多」后展开的一屏固定表情网格(48 个);移动端以一张紧贴消息的卡片呈现,背景模糊、操作栏收起(见 6.3)。 |
| 表情条 / chip | 渲染在消息气泡内部底部的那一个小胶囊:「表情 + 头像(1~3 人)/ 数字(4 人及以上)」。 |
| 回复者名单 | 悬停/长按某个 chip 后弹出的"谁回复了这个表情"列表。 |
| 阉割版 | 无通知、无聚合入口、无设置项、无搜索的 Reaction。 |
四、用户与场景
角色只有一个:会话里的成员(单聊双方、群成员)。无管理员、无主播/嘉宾之分。
场景 A · 群里表态(高频,主场景)
群里有人发了个通知。用户长按消息 → 👍 → 这条气泡里出现「👍 3 个头像」。没有被"收到"刷屏。
场景 B · 收到反馈(发送者视角)
用户发了一张图。过一会儿对方给这条消息点了 ❤️。用户此时正在这个会话里,看到图标冒出来。
如果用户已经划走 / 退出会话,不会有任何提醒,回到会话时才看到。
场景 C · 改主意
用户点了 👌,想改成 🔥:长按同一条消息 → 点 🔥(自动替换)。
或者直接点气泡里的 👌 那个 chip → 取消。
场景 D · 想知道是谁
一条消息的气泡里显示「🎉 8」(8 人 ≥ 4,只显示数字)。用户想知道都是谁 → 桌面端鼠标停在 chip 上 / 移动端长按 chip → 名单。
场景 E · 撤回
消息被撤回,气泡里所有表情回复一起消失。
五、功能总览
| 模块 | 功能点 | 线框图 | 优先级 |
|---|
| A 触发 | 桌面端右键唤起(浮层 = 表情栏 + 操作栏) | #R1 #R2 | P0 |
| A 触发 | 移动端长按唤起 | #R3 | P0 |
| B 表情栏 | 7 个固定快捷表情 + 已回复项的选中态 | #R1 #R2 #R3 | P0 |
| B 表情栏 | 「更多」→ 一屏固定表情网格 | #R4 | P0 |
| C 操作 | 添加 / 替换 / 取消(含两条取消路径) | #R1 #R5 | P0 |
| D 展示 | 气泡内 chip(表情 + 头像 / 数字 + 自己的高亮,单聊群聊同一套) | #R5 #R6 #R7 | P0 |
| D 展示 | 多个不同表情并存、一行放不下自动换行 | #R16 | P0 |
| D 展示 | 点击表情的「坠落炸开」动效(统一一套) | #R17 | P0 |
| E 名单 | 悬停 / 长按 chip → 回复者名单 | #R8 #R9 | P0 |
| F 边界 | 撤回 / 删除 / 编辑 / 转发 / 系统消息 | #R10 #R11 | P0 |
| F 边界 | 操作失败与回滚 | #R12 | P0 |
| F 边界 | 禁言成员(已拍板:不能回) | #R13 | P0 |
| F 边界 | 被拉黑关系 | #R13 | 待确认 |
| G 不打扰 | 无通知 / 不计未读 / 不改排序与预览 | #R15 | P0 |
| H 对照 | Reaction 与 Reply、输入框表情面板的区别 | #R14 | 讲解用 |
六、功能详情
6.1 触发
桌面端(Web / Windows / macOS)
- 鼠标在任意消息气泡(文字、图片、文件、语音、红包等)上右键 → 浮层出现。
- 浮层结构:上半部分 = 快捷表情栏(7 个表情 + 「更多」),下半部分 = 消息操作栏(复制 / 引用回复 / 转发 / 删除等现有菜单项,一项都不改)。
- 浮层位置:出现在鼠标位置附近,不遮挡被操作的那条消息;靠屏幕边缘时自动翻转方向。
- 被操作的那条消息加高亮底色(与被选中态一致),提示用户"浮层是对这条消息生效的"。
- Web 端在触屏设备上同时支持长按(与移动端同一套行为)。
移动端(iOS / Android)
- 长按消息气泡(约 0.3~0.5 秒)→ 轻微震动反馈(跟随系统能力)→ 浮层出现。
- 浮层结构:上面一行 = 快捷表情栏,下面 = 消息操作栏;浮层贴在被长按的那条消息附近,避免被手指遮住。
- 表情栏一屏内放下 10 个格位(9 表情 + 更多);窄屏(< 360pt)允许横向滑动。
浮层通用行为(四端一致)
| 行为 | 规则 |
|---|
| 关闭 | 点浮层外任意位置关闭;Android 系统返回键关闭;移动端从浮层向下拖动关闭 |
| 换目标 | 浮层开着时按另一条消息 → 直接切换为对这条消息生效,不要求先关再开 |
| 点击表情后 | 立即关闭浮层,不等待服务端返回(气泡内的 chip 同步出现,见 6.8) |
| 不唤出 | 见 7.2「不可回复的消息」;消息未发送成功(转圈 / 失败态)时也不唤出表情栏 |
6.2 快捷表情栏
- 固定 7 个 + 「更多」,按顺序:
👌 ❤️ 👍 👎 🔥 🥰 👏,最后是「更多」入口(圆形按钮 + 向下箭头,与 Telegram 一致)。 - 顺序由产品固定,永不变动(不做"最近使用"、不做"我的常用")。
- 选中态:若用户已经用某个表情回复过这条消息,该表情在表情栏中显示高亮(紫底 / 紫色描边),再点一次即取消(见 6.4)。
- 尺寸建议(给开发):桌面端每格 40×40、图标 24px、格间距 6px;移动端每格约 32×32、格间距 4px,保证 375pt 宽一屏放下。
- 表情栏不需要加载、不需要联网(固定清单,可预置)。
6.3 「更多」面板
- 点「更多」→ 浮层内容切换为固定表情网格(不是叠加第二层),面板右上角一个 ✕ 关闭。
- 网格规格:8 列 × 6 行 = 48 个,顺序固定(已拍板:不做搜索 / 不做分类 / 不做最近使用)。
- 网格内若包含用户已回复的表情,同样显示选中态,再点一次即取消。
- 点击任意表情 → 与快捷栏行为完全一致(关闭浮层 + 立即生效)。
移动端形态(对齐 Telegram,2026-09-18 补写)
| 项 | 规则 |
|---|
| 快捷栏与操作栏 | 点「更多」后整块收起,屏上只留这张网格卡片(避免"两套东西同时挂在消息上") |
| 卡片位置 | 紧贴被操作的那条消息:优先在其上方,上方放不下时置于下方 |
| 背景 | 聊天背景(含页面其余消息)整体模糊;被操作的那条消息保持清晰,浮在模糊层之上 |
| 关闭 | 点卡片外任意位置关闭;卡片右上角另留一个 ✕;不做"返回上一级" |
| 不做 | TG 面板顶部的「最近使用」一行、搜索框、分类页签——本期全部不做(见 2.2 阉割清单) |
| 桌面端 | 仍是"鼠标位置附近弹出"(见 6.1),不做模糊背景 |
建议网格清单(顺序即上线顺序,产品可替换,替换后同样固定)
| 👍 | 👎 | ❤️ | 🔥 | 🥰 | 👏 | 😁 | 🤔 |
| 🤯 | 😱 | 🤬 | 😢 | 🎉 | 🤩 | 🤮 | 💩 |
| 🙏 | 👌 | 🕊 | 🤡 | 🥱 | 😘 | 😍 | 🐳 |
| 💯 | 🤣 | ⚡ | 🍌 | 🏆 | 🤨 | 😐 | 🍓 |
| 🍾 | 💋 | 😈 | 😴 | 😇 | 😨 | 🤓 | 😎 |
| 🤷 | 😭 | 😂 | 🥳 | 😡 | 🤝 | 💪 | 🫡 |
快捷表情栏那 7 个是这张网格的子集,两处重复显示是正常现象(与 Telegram 一致)。
6.4 添加 / 更改 / 取消(核心规则,初稿未写全)
| 规则 | 内容 |
|---|
| 唯一性 | 一个用户对一条消息最多只有 1 个表情回复。不存在"同一条消息点 3 个表情"的情况。 |
| 新增 | 无回复 → 点任意表情 = 新增该表情。 |
| 替换 | 已有回复 A → 点另一个表情 B = 我的回复由 A 变为 B(A 的人数 −1,若减到 0 则 A 的 chip 消失;B 的人数 +1 或新建 chip)。 |
| 取消(路径一) | 点表情栏里高亮的那个表情 = 取消我的回复。 |
| 取消(路径二) | 点气泡里我自己参与的那个 chip = 取消我的回复(与路径一等价,TG 行为一致)。 |
| 取消的后果 | 人数 −1;若该表情人数归零,chip 整体消失(允许 0.2s 淡出);不影响其他人的回复。 |
| 自己的消息 | 可以给自己发的消息回复(与 Telegram 一致)。 |
| 他人回复 | 不能替别人回复,也不能删除别人的回复(本期无任何"管理/删除他人回复"的能力)。 |
| 重复点击 | 短时间重复点击同一条消息的同一表情,最终以服务端最后一次成功结果为准(前端做本地去抖,见 6.8)。 |
6.5 气泡内的展示(chip)
a. 位置与对齐
- 包在被回复消息的气泡内部底部:与时间同一行,chip 在左、时间靠右(与 Telegram 一致)。
- 气泡底部内边距收紧(chip 与文字间距建议 5px);多个 chip 一行放不下时在气泡内自动换行,气泡跟着变高。
- 动画:自己点击时播 6.9 的「坠落炸开」;别人点、或消息不在屏幕内时,只用 0.15~0.2s 淡入 + 轻微上移。
b. chip 内部构成
| 该表情的回复人数 | 显示 |
|---|
| 1 ~ 3 人 | 表情 + 这几个人的头像(几个就显示几个),不显示数字,例:🎉 [头1][头2][头3] |
| 4 人及以上 | 表情 + 数字(该表情的回复总人数),不显示头像,例:🎉 12 |
| 单聊 / 群聊 | 同一套规则,单聊最多 2 人参与 → 永远显示头像,不会出现数字 |
| 人数上限显示 | 超过 999 显示 999+ |
⚠ 初稿需要修正的一处口径:初稿例子写「有 5 个人选了 👌,显示为 👌 头像1头像2头像3 +5」。
这里 +5 有两种截然不同的读法("一共 5 人" vs "除了这 3 个还有 5 人")。
本文档取"数字 = 该表情的回复总人数",且数字只在 4 人及以上时出现(1~3 人直接显示头像):5 人即显示 5(不加 + 号,避免误读为"还有 5 个")。
2026-09-18 更新:改为「1~3 人显示头像、4 人及以上显示数字」后,原先"头像最多 3 个、取最早还是最新 3 个"的纠结自然消失(见待确认 ⑨,已关闭)。
c. 排序规则(多表情时)
- 先按该表情的回复人数降序;
- 人数相同的,按首次出现时间升序;
- 自己参与的表情 chip 不额外改变排序,只用紫色描边 + 淡紫底高亮(TG 同款处理)。
d. 数量
- 一条消息下的 chip 全部展示、自动换行,不做"N 个表情折叠 / 展开"(避免新增交互)。
- 建议后端对单条消息的表情种类数设一个上限(如 20 种)作为兜底,前端不需要为此做特殊处理。
6.6 「谁回复了」名单(已拍板要做)
| 项 | 规则 |
|---|
| 唤出(桌面端) | 鼠标悬停在某 chip 上约 0.4s → 弹出名单浮层;移开即消失。 |
| 唤出(移动端) | 长按某 chip → 弹出名单;点浮层外关闭。 |
| 唤出(备选) | 桌面端点击 chip 时若自己已参与仍然是"取消回复",不要把点击改成打开名单(保持 6.4 路径二)。 |
| 名单结构(移动端,对齐 TG) | 大表情(标明是哪个表情的名单)→ 该表情的 chip(与消息上那个 chip 长得一样,只做展示、不可点)→ 回复者列表。 |
| 名单排序(移动端) | 按回复时间倒序(最近的排最上面);自己不置顶、也不做「你」标注。 |
| 回复时间 | 列表里显示该成员做这次表情回复的时间(不是消息时间),格式与现有聊天时间一致:今天 = HH:mm;昨天 = 昨天 HH:mm;更早 = 日期。 |
| 列表滚动 | 人多时名单上下滚动;不做"查看全部"页面。 |
| 名单内容(桌面端) | 桌面端仍是"一行一人"的列表:头像 + 昵称 + 回复时间,自己排最前;最多 8 行、超出名单内滚动。 |
| 位置与背景(移动端) | 整块(大表情 + chip + 列表)紧贴被长按的那条消息,优先在其上方、放不下时置于下方;聊天背景整体模糊,被操作的那条消息保持清晰。 |
| 空名单 | 不会出现(chip 存在即至少有 1 人)。 |
| 与撤回的联动 | 若名单里有成员已被移出群 / 已注销,显示为「已注销用户」,不做级联删除(保留回复痕迹)。 |
6.7 不打扰规则(阉割版的核心,初稿的"业务说明"展开)
表情回复不是消息,因此:
| 不做什么 | 说明 |
|---|
| 不产生任何通知 | 无推送、无站内系统消息、无红点、无"有人用表情回复我"的提示 |
| 不进入任何聚合入口 | 没有"我收到的表情"列表、没有会话列表上的计数 |
| 不改变未读 | 不增加会话未读数、不清除未读、不改变"已读回执"(别人给我点了表情 ≠ 他读了我的消息) |
| 不改变排序 | 会话列表顺序不变,不置顶、不冒泡 |
| 不改变预览 | 会话列表里显示的"最后一条消息"仍是原消息,不显示表情、不显示"XX 回复了表情" |
| 不产生消息 | 不进消息计数、不影响"最后一条消息"时间戳 |
"只在屏幕内看得见"的准确含义(开发最容易理解错的一点):
- 数据是真实存在、会多端同步的,滑走不是删除。
- 只是没有任何地方会提醒你:没有通知、没有聚合入口。
- 所以:用户把这条消息滑回来 / 重新进入会话时,能按最新数据看到别人后来追加的表情回复。
- 换句话说,本功能"没有曝光渠道",只有"就地查看"。
6.8 多端、实时与失败
| 项 | 规则 |
|---|
| 多端同步 | 同一账号在其它端(已打开该会话)实时看到同一条消息的表情变化(WebSocket 推送 → 就地刷新,在屏幕内时带 6.5a 的淡入动画)。 |
| 不做二次确认 | 点击表情后立即在这条消息的气泡内渲染(乐观更新),浮层同时关闭。 |
| 失败回滚 | 服务端返回失败(超时 / 断网 / 被限流)→ 撤掉刚渲染的那一个 chip,并 Toast「操作失败,请重试」。不做"重试中"的中间态。 |
| 断网时 | 允许点击(同样乐观更新 + 失败回滚),不做离线队列(表情回复不值得排队,避免用户误以为成功)。 |
| 去抖 | 同一条消息 500ms 内的重复点击只提交最后一次,避免"点-取消-再点"打出一串请求。 |
| 限流 | 后端对单用户做频率限制(建议 10 次 / 10 秒),前端不做特殊提示,走失败回滚。 |
6.9 点击表情的动效(坠落炸开 · 只有一套)
点表情的那一刻要有"落下去"的反馈。TG 给每个 emoji 单独做了一套动效(小丑会蹦、爱心会跳…),我们只做一套统一的:不区分表情、不区分是否首次、不区分单聊群聊。
| 阶段 | 时长 | 表现 |
\
| ① 坠落 | 约 190ms | 该表情从点击处(表情栏里的那一格)沿直线落到 chip 位置,缩放 1.55 → 0.72,缓动 ease-in(越落越快) |
\
| ② 炸开 | 约 280ms | 落点扩散一圈描边光环(放大到约 3 倍并淡出)+ 8 个小粒子向四周飞散(品牌紫 / 亮紫 / 金色交替) |
\
| ③ 弹一下 | 约 180ms | chip 出现并 scale 1 → 1.18 → 1 |
- 总时长约 480ms;动效不阻塞交互:点击后 chip 立即写入数据(6.8 的乐观更新),动画只是视觉。
\
- 只在自己点击、且消息在屏幕内时播;其它情况回落到 6.5a 的淡入。
\
- 跟随系统的「减弱动效」设置:开启时全部动效退化为 150ms 淡入,不播坠落与炸开。
\
- 不做礼花、连击、彩带一类的花哨效果;也不用为单个 emoji 定制动效(本期明确不做)。
\
- 演示见
#R17(页面里可以直接点「▶ 重播动效」看一遍)。
6.10 与既有功能的关系(逐条对照,避免误伤)
| 既有功能 | 与表情回复的关系 |
|---|
| 引用回复(Reply) | 互相独立。Reply 产生新消息,Reaction 不产生。命名/埋点/文案绝不混用。 |
| 输入框表情面板 | 完全无关,不要复用数据结构。 |
| 长按消息的操作栏 | 一项不改,本功能只是在这行菜单上方多了一行表情栏。 |
| 撤回消息(双方撤回) | 消息消失时,其下所有表情回复一起消失(各端同步)。见 7.1。 |
| 删除消息(仅自己可见的删除) | 只影响本机;其它成员端仍然显示该消息及其表情回复。 |
| 清空聊天记录 | 与删除消息一致,仅本机。 |
| 编辑消息 | 表情回复保留、不重置。 |
| 转发消息 | 不带原消息的表情回复(表情回复不随转发复制)。 |
| 红包 / 图片 / 文件 / 语音消息 | 与文字消息一视同仁,都可回复。 |
| 禁言(群成员被限制发言) | 不能回(2026-09-18 已拍板,见第十一章 ⑤):与发言权限同一套判定;被禁言时长按消息整块不出现表情栏、也不给任何提示,只出原有操作栏(与 7.2「不可回复的消息」完全同一套处理,不为禁言单开置灰态);历史消息上已有的表情条照常显示,解禁后自动恢复。被禁言 = 不能发言,所以操作栏里的「引用回复」也不出现(其余项照旧)。演示见 #R13。 |
| 拉黑 / 删除好友 | 待确认(见第十一章 ⑥):建议历史表情回复照常显示(与历史消息同理),只是不能对已被拉黑关系的消息新增回复。 |
| 群成员退群 / 被踢 | 他做过的表情回复保留(与历史消息同理),名单里显示为「已注销用户」或保留昵称(与现有消息处理一致)。 |
| 频道 / 官方账号会话 | 与普通会话同规则(本期不做频道级开关)。 |
七、异常与边界
7.1 消息生命周期对照表(必须逐条验收)
| 场景 | 消息 | 表情回复 | 是否需要同步其它端 |
|---|
| 被发送者撤回(双方撤回) | 消失 | 全部一起消失 | 是 |
| 被自己删除(仅本机) | 本机消失 | 本机一起消失,其它端不变 | 否 |
| 清空聊天记录 | 本机消失 | 本机一起消失 | 否 |
| 被编辑 | 保留 | 保留,不重置 | 是(原有逻辑) |
| 被转发 | 新消息 | 不携带表情回复 | — |
| 消息发送失败(红色感叹号) | 保留在输入区上方 | 不允许回复(不唤出表情栏) | — |
| 消息正在发送中(转圈) | 保留 | 不允许回复(同上) | — |
| 会话被删除 | 消失 | 一起消失 | 是 |
7.2 不可回复的消息(初稿未定义,必须定)
以下情况不唤出表情栏(长按/右键仍然可以出操作栏,只是没有表情那一行)——本人被禁言时同样处理:不出、也不提示:
| 消息类型 | 是否可回复 |
|---|
| 普通消息(文字 / 图片 / 文件 / 语音 / 视频 / 红包 / 位置…) | ✅ 可 |
| 系统提示类("XX 撤回了一条消息"、"XX 加入了群聊"、"你领取了 XX 的红包"、群公告变更等) | ❌ 不可 |
| 通话记录(语音/视频通话已结束) | ❌ 不可 |
| 发送中 / 发送失败的消息 | ❌ 不可 |
| 本人被禁言(用户权限状态,不是消息类型) | ❌ 不可(整块不唤出,且不给任何提示,见 7.3 与待确认 ⑤) |
| 被拉黑关系下的消息 | ⚠ 待确认(建议不可) |
判定方式建议由消息类型字段决定(白名单),不要用"看起来像系统消息"的文案判断。
7.3 其它边界
| 场景 | 预期表现 |
|---|
| 一条消息的表情被点爆(如 500 人各点一个) | 不再显示头像,人数显示 500(或 999+);不做性能降级,由后端聚合返回 |
| 同一秒多人回复同一表情 | chip 人数 +1,不重复创建 chip;头像按回复先后排列。新规则下 1~3 人全部显示头像,不存在"挑哪 3 个"的问题(原待确认 ⑨ 已关闭) |
| 自己被移出该群后再看历史 | 历史表情回复照常显示(与历史消息一致),不可再新增 |
| 网络恢复后 | 重新拉取当前可见消息的表情,覆盖本地乐观数据 |
| 表情回复的人是自己时 | 名单里不做「你」标注(自己与别人同样显示头像 + 昵称 + 时间),chip 高亮 |
八、跨端差异(只有触发方式不同)
| iOS / Android | Web | Windows / macOS 桌面端 |
|---|
| 唤出 | 长按消息 0.3~0.5s(带震动) | 鼠标右键;触屏设备长按 | 鼠标右键 |
| 关闭 | 点外部、Android 返回键、下滑 | 点外部、Esc | 点外部、Esc |
| 名单 | 长按 chip | 悬停 chip 0.4s | 悬停 chip 0.4s |
| 浮层位置 | 贴在消息旁,避开手指 | 鼠标位置附近,避让边缘 | 同 Web |
| 表情栏格位 | 32pt(10 格 / 一屏) | 40pt | 40pt |
九、新增文案
| 位置 | 文案 | 说明 |
|---|
| 操作失败 Toast | 操作失败,请重试 | 与现有全局失败提示保持同一句式 |
| 回复者名单里自己 | 你 | 与现有消息/名单里的自称保持一致 |
| 已注销 / 已退群成员 | 与现有消息列表的显示方式一致 | 不新增说法 |
本功能不新增空态、不新增页面标题、不新增引导提示。
十、埋点与数据
埋点
| 事件 | 关键参数 |
|---|
reaction_panel_open | 入口(右键 / 长按)、会话类型(单聊 / 群聊)、消息类型 |
reaction_more_open | 来源(快捷栏) |
reaction_add / reaction_replace / reaction_remove | 表情、路径(表情栏 / chip)、会话类型 |
reaction_chip_click | 是否为自己参与 |
reaction_list_open | 端(桌面悬停 / 移动长按) |
reaction_fail | 失败原因(超时 / 网络 / 限流) |
看板
- 使用率:日活中使用过表情回复的 UV 占比;人均次数
- 分布:Top 10 表情、单聊 vs 群聊比例、消息类型分布
- 健康度:成功率、失败原因分布、去抖命中率
十一、待确认(需要产品拍板,开发据此实现)
| # | 问题 | 建议 |
|---|
| ① | 快捷栏表情的最终清单与顺序 | ✅ 已拍板(2026-09-18):改为 7 个,顺序 👌 ❤️ 👍 👎 🔥 🥰 👏,定稿后不再变更 |
| ② | 更多面板 48 个表情的清单与顺序(见 6.3 建议稿) | 采用建议稿;一旦定稿不再变更 |
| ③ | chip 数字含义:总人数 还是 剩余人数 | ✅ 已定:数字 = 该表情的回复总人数,不加 +;且数字只在 4 人及以上时显示(1~3 人显示头像),见 6.5b |
| ④ | 单聊是否显示头像堆叠 | ✅ 已拍板(2026-09-18):显示。单聊与群聊同一套规则(1~3 人头像、4 人及以上数字);单聊最多 2 人,所以永远显示头像 |
| ⑤ | 被禁言的群成员能否做表情回复 | ✅ 已拍板(2026-09-18):不能。判定与发言权限同一套;被禁言时不出现表情栏、也不给任何提示(与「不可回复的消息」同一套处理),只出原有操作栏;历史表情条照常显示,解禁后自动恢复。演示见 #R13 |
| ⑥ | 被拉黑关系下能否对历史消息做表情回复 | 建议不能新增,历史表情照常显示 |
| ⑦ | 长按/右键的等待时长与是否震动 | 建议 0.4s + 跟随系统震动 |
| ⑧ | 失败时用 Toast 提示还是静默回滚 | 建议 Toast(避免用户误以为成功) |
| ⑨ | 头像取"最早 3 个"还是"最新 3 个" | ✅ 已关闭:新规则下 1~3 人全部显示头像、4 人及以上只显示数字,不存在"挑 3 个"的情况 |
| ⑩ | 后端单条消息的表情种类上限、单用户限流阈值 | 建议 20 种 / 10 次 10 秒 |
| ⑪ | 是否需要旧消息的表情回复"按需加载"策略 | 建议进入会话加载当前屏可见消息,滚动到更早时按需拉取 |
| ⑫ | 是否需要为运营/风控提供"删除某条消息的全部表情"的能力 | 建议不做(本期无此场景) |
十二、相对初稿的补充清单(我补了什么、为什么必须补)
| # | 初稿没有的 | 为什么必须补 |
|---|
| 1 | 一个用户能回几个表情 | 不写,开发会做成"可以点多个",与"表情条 + 人数"的展示模型直接冲突 |
| 2 | 两条取消路径(表情栏高亮项 / 气泡里的 chip) | 初稿只写了表情栏那一条,用户最常见的动作是点气泡里那个图标 |
| 3 | chip 数字的含义(总人数 / 剩余) | 初稿例子 头像×3 + 5 有歧义,会做错 |
| 4 | 单聊与群聊显示一致 | 单聊最多 2 人,走"显示头像"分支;两套规则统一,开发少写一个分支 |
| 5 | 自己的回复要高亮 | 否则用户看不出"哪个是我点的",也就找不到取消入口 |
| 6 | chip 排序规则 | 多种表情并存时必须有稳定顺序 |
| 7 | 哪些消息不能回复 | 撤回提示、通话记录等如果也能点表情,观感很怪 |
| 8 | 撤回/删除/编辑/转发 的联动 | 不写就会漏掉"撤回后图标还挂在空中"这类问题 |
| 9 | 发送中/失败的消息能否回复 | 同一条消息会出现两个状态,必须禁止 |
| 10 | 失败回滚 = 撤掉图标 + Toast | 初稿的"状态反馈"只写了成功态 |
| 11 | "屏幕内才可见"的准确含义 | 否则可能被理解成"滑走就删数据" |
| 12 | 明确"不算已读、不改未读、不改预览与排序" | "不记消息数"这句太粗,需要逐条落到可验收的动作上 |
| 13 | Reaction / Reply / 输入框表情 的命名区分 | 项目里已有"回复"和"表情"两个词,不区分必出事故 |
| 14 | 更多面板的清单、行列数、无搜索无分类 | 已拍板"一屏固定网格",需要给出确定的清单 |
| 15 | 四端触发与关闭的差异表 | Web / 桌面 / 移动行为不同,必须逐端写清 |
| 16 | 多端同步与实时刷新 | 同一账号多端在线是本产品前提 |
| 17 | 禁言 / 拉黑 / 退群等权限边界 | 与现有群权限和黑名单机制交叉,必须给判定(禁言已拍板:不能回、不提示;拉黑见 ⑥) |
| 18 | 成功指标与埋点 | 初稿没有可验收的目标,上线后无法判断成没成 |