Skip to content

🐛 群聊文件消息已正确显示后又重复出现在会话底部 #192

@yeejiaa

Description

@yeejiaa

反馈来源

佳佳在 PM 娃群实际使用中发现(2026-04-01)

问题描述

在群聊中发送文件消息后,文件消息已经在正确的时间位置显示。但在其他群成员持续发送消息(产生多条新 messageSeq)后,该文件消息又突然出现在会话底部,而不是保持在原来的正确位置。

注意:这不是文件上传延迟导致的初始排序问题——文件已确认发送成功并在正确位置显示过,是事后才错位到底部的。

复现场景

  1. 在群聊中发送一个文件(如 .md 文件)
  2. 确认文件消息已在会话中正确位置显示
  3. 群内其他成员继续发送多条文本消息
  4. 过一段时间后,该文件消息突然出现在会话最底部(好几条消息之后)

源码分析

排序机制

  • Conversation/vm.ts 中消息按 order 字段排序
  • fillOrder() 计算方式:order = OrderFactor(10000) × messageSeq
  • messageSeq 由 WuKongIM 服务端在收到消息时递增分配

根因定位:messageListener 缺少前置去重

Conversation/vm.ts 第301-342行,messageListener 收到消息后的处理链路:

WS 收到消息 → new MessageWrap(message) → fillOrder() → appendMessage()

appendMessage 直接将消息 push 到 messagesOfOrigin 尾部,没有先检查是否已存在相同 clientMsgNomessageID 的消息。

虽然 refreshMessages()distinctMessages() 会按 clientMsgNo 事后去重(保留前一个,删除后一个),但存在以下风险:

  1. WS 断连重连:WuKongIM 服务端重新推送未确认的消息(RecvPacket),如果重推的消息 clientMsgNo 与本地版本不一致或为空,distinctMessages 无法匹配去重
  2. 发送方同时收到 SendackPacket 和 RecvPacket:群消息场景下,发送方可能既收到 ack 又收到服务端推送的 RecvPacket,两个 Message 对象的 clientMsgNo 来源不同(一个来自本地 fromSendPacket,一个来自服务端 RecvPacket

相关代码位置(dmwork-web 仓库)

文件 行号 说明
packages/dmworkbase/src/Components/Conversation/vm.ts 301-342 messageListener,无前置去重
同上 753-785 appendMessage,直接 push 到 messagesOfOrigin
同上 1221-1231 distinctMessages,按 clientMsgNo 事后去重
同上 620-640 updateMessageStatusBySendAck,成功消息不重新调 fillOrder
packages/dmworkdatasource/src/task.ts 全文 MediaMessageUploadTask,文件上传完成后才发送消息
wukongimjssdk(v1.2.11) ChatManager.sendWithOptions 文件消息先触发上传任务,上传完成后才 sendPacket
同上 ChatManager.onPacket RecvPacket 直接 notifyMessageListeners,无去重

附加发现:fillOrder 不一致

updateMessageStatusBySendAck()(第620行)收到成功的 SendackPacket 后:

  • ✅ 更新了 message.messageSeq
  • 没有重新调用 fillOrder() 重新计算 order

这导致发送方本地消息的 order 保持临时值,与服务端基于 messageSeq 的排序不一致。刷新页面或 pullup 加载时,消息可能跳到不同位置。

建议修复方向

  1. 前置去重(最直接):messageListener 在调用 appendMessage 前,先检查 messagesOfOrigin 中是否已存在相同 messageID 的消息,已存在则更新而非追加
  2. fillOrder 一致性updateMessageStatusBySendAck 成功时也调用 fillOrder() 重新计算 order
  3. SDK 层ChatManager.onPacket 处理 RecvPacket 时,检查 sendingQueues 中是否有相同 clientMsgNo 的消息,有则跳过(避免发送方重复处理)

影响范围

  • 影响端:Web 端(dmwork-web)
  • 影响场景:群聊中发送文件/图片等需要上传的消息
  • 严重程度:P0 — 消息顺序是 IM 基础体验,错乱直接影响信息理解

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions