私聊安全提醒与封禁用户脱敏 (2026-08-10)

接口变更

user

echo / event

  • ChatCreated
    • 功能:广播新私聊
    • 变更:广播载荷中的用户对象同样脱敏
  • ChatUpdated
    • 功能:广播私聊更新
    • 变更:广播载荷中的用户对象同样脱敏
  • ChatMessageCreated
    • 功能:广播私聊新消息
    • 变更:广播载荷中的用户对象同样脱敏
  • ChatMessageTranslateSuccessed
    • 功能:广播私聊消息翻译完成
    • 变更:广播载荷中的用户对象同样脱敏
  • GroupCreated
    • 功能:广播新群聊
    • 变更:广播载荷中的用户对象同样脱敏
  • GroupUpdated
    • 功能:广播群聊更新
    • 变更:广播载荷中的用户对象同样脱敏
  • GroupMessageCreated
    • 功能:广播群聊新消息
    • 变更:广播载荷中的用户对象同样脱敏

接口示例

user

POST /api/chat_messages/enter_chat

  • 功能说明:进入私聊,分页返回聊天消息,并返回当前用户在该私聊中所有未关闭的安全提醒。
  • 变更说明:响应新增 notices 数组;next / prev / current 结构不变。

请求参数

字段类型必填说明
chat_idnumber是私聊 ID,必须是当前用户参与的私聊
sizenumber否每页消息数,默认 20,范围 1 ~ 50

请求示例

{
  "chat_id": 123,
  "size": 10
}

响应示例

{
  "next": [],
  "prev": [],
  "current": null,
  "notices": [
    {
      "id": 9001,
      "code": "private_chat_scam_warning",
      "title": {
        "zh": "PIPIPEN 安全提醒",
        "en": "PIPIPEN Safety Notice",
        "ja": "PIPIPEN セキュリティ通知",
        "_lang": "zh"
      },
      "content": {
        "zh": "近期出现针对画师的诈骗……",
        "en": "Recently, scams targeting artists have appeared...",
        "ja": "最近、アーティストを狙った詐欺が発生しています……",
        "_lang": "zh"
      },
      "link_url": "/questions/123",
      "is_dismissible": true,
      "sort": 100,
      "visibility": "single",
      "created_at": "2026-08-10T10:00:00+08:00"
    }
  ]
}

notices 数组说明:

  • 始终为数组,可能为空。
  • 只返回当前用户(recipient_user_id 等于当前登录用户)且未关闭(dismissed_at 为空)的提醒。
  • 按投放记录的 sort 降序、id 升序排序。
  • title / content 为多语言对象,前端按聊天语言选择对应语言;_lang 为默认语言。
  • code:模板业务编码,稳定标识,不随数据库 ID 变化。
  • visibility:single 表示仅你可见;multiple 表示双方可见。
  • is_dismissible:为 false 时前端不渲染关闭按钮。
  • link_url:站内路径(/ 开头)或 https:// 地址,可能为 null。
  • sort:提醒展示顺序,数字越大越靠上。
  • 提醒不属于聊天消息流,不影响消息数量、未读数、最后一条消息,也不参与消息翻译和限制词检查。

错误响应

  • 422:chat_id 不是当前用户参与的私聊,或参数校验失败

无新增,沿用原有错误语义。

POST /api/user/chat_notices/dismiss

  • 功能说明:关闭当前用户在某个私聊中的一条安全提醒。关闭状态仅对当前用户生效,不影响另一个用户的投放记录。
  • 变更说明:新增接口。

请求参数

字段类型必填说明
notice_idnumber是安全提醒投放记录 ID(notices[].id)

请求示例

{
  "notice_id": 9001
}

响应示例

{
  "ok": true
}

接口约束

  • 必须登录。
  • 投放记录必须属于当前用户。
  • 当前用户必须仍属于对应私聊。
  • 重复关闭返回成功,保持幂等。
  • 关闭一条提醒不影响同一私聊中的其他提醒。

错误响应

  • 404:投放记录不存在、不属于当前用户或当前用户已不在该私聊(统一返回 404,避免探测其他用户的记录)
  • 422:该提醒不可关闭(is_dismissible=false)
{
  "message": "This notice cannot be dismissed."
}

封禁用户脱敏:聊天 / 群聊用户对象

  • 功能说明:chats / groups 系列接口返回的用户对象统一脱敏。
  • 变更说明:被封禁的用户不再返回原名称和画师信息,避免前端泄露封禁用户身份。脱敏只作用于响应数据,不影响数据库。

用户对象字段变化

字段封禁用户普通用户
name""(空字符串)原值
cname""(空字符串)原值
artistnull画师对象或 null
is_user_bannedtruefalse
id / roles保留不变

封禁用户示例:

{
  "id": 10001,
  "name": "",
  "cname": "",
  "is_user_banned": true,
  "artist": null,
  "roles": ["artist"]
}

前端建议

  • 统一使用 user.is_user_banned 判断并渲染多语言名称:

    function displayUserName(user: ChatUser): string {
      if (user.is_user_banned) return t('common.banned_user')
      return user.artist?.name || user.name || ''
    }
  • 至少替换以下区域中的直接名称访问:私聊列表、私聊消息气泡、私聊标题或成员信息、与私聊关联的用户快捷卡片。

  • 封禁用户头像使用统一封禁头像;名称和头像不可跳转个人主页。

  • 中、英、日分别配置“被封禁的用户”文案,不要复用仅表示状态的“已封禁”标签文案。

错误响应

无新增,沿用原有错误语义。

echo / event

广播事件中的用户脱敏

  • 功能说明:Echo 广播事件中的 chat.users / group.users 用户对象与接口返回保持一致。
  • 变更说明:被封禁用户同样脱敏(name / cname 置空、artist 置空、is_user_banned=true)。

涉及事件:

  • ChatCreated / ChatUpdated / ChatMessageCreated / ChatMessageTranslateSuccessed
  • GroupCreated / GroupUpdated / GroupMessageCreated

前端收到广播后,应使用与接口相同的 displayUserName 逻辑渲染用户名称,避免在消息气泡中展示空名称。

前端对接清单

  • 进入私聊后,根据 enter_chat 响应中的 notices 渲染顶部安全提醒栏;提醒位于消息列表之上,不跟随消息滚动。
  • 提醒栏元素:安全盾牌图标、多语言标题、visibility=single 时展示“仅你可见”、多语言正文、有 link_url 时展示“了解更多”、is_dismissible=true 时展示关闭按钮。
  • 点击关闭后调用 POST /api/user/chat_notices/dismiss,后端成功后再从本地列表移除;请求失败时保留提醒并给出轻量错误提示。
  • 点击“了解更多”时,站内链接使用应用路由跳转。
  • 正文按纯文本渲染并保留换行,不使用 v-html。
  • 切换私聊时提醒随当前 chat_id 更新。
  • 提醒不应出现在左侧会话摘要中,不应成为消息气泡,不产生未读红点,不参与聊天自动翻译。
  • 所有聊天用户名称渲染统一走 displayUserName。

兼容性说明

  • enter_chat 只新增 notices 字段,旧前端忽略该字段,不影响原有消息分页。
  • chat_notices/dismiss 为全新接口,不影响旧逻辑。
  • 新增数据表不影响现有聊天消息结构;提醒不产生未读红点、不参与消息计数和自动翻译。
  • 封禁用户脱敏与前端多语言“被封禁的用户”文案应同步发布,否则部署间隙旧前端可能显示空名称。
  • 后台停用全部安全提醒模板后停止新投放;已投放的提醒不受影响,历史数据不删除。