🐛 fix(im): TIP_TEXT 系统提示不再显示空白

群解散 / 退群 / 踢人 等系统提示后端发的是裸字符串,之前按 TextMessage JSON
解析 → 主聊天窗显示空行、会话列表摘要变空。

- message.ts:新增 resolveTipText helper,兼容裸字符串 + {"content":"..."}
- MessageItem / conversationStore.resolveLastContent 把 TIP_TEXT 从 TEXT
  分支拆出来,统一走 resolveTipText(TEXT 仍按 JSON 解析,没有裸字符串可能)
im
YunaiV 2026-04-27 19:56:54 +08:00
parent cb5d30e327
commit 9e8d04249c
3 changed files with 33 additions and 16 deletions

View File

@ -217,6 +217,7 @@ import { CommonStatusEnum } from '@/utils/constants'
import {
parseMessage,
buildRecallTip,
resolveTipText,
type TextMessage,
type ImageMessage,
type FileMessage,
@ -319,21 +320,8 @@ function formatTipTime(timestamp: number): string {
/** 文本内容 */
const textContent = computed(() => parseMessage<TextMessage>(props.message.content)?.content ?? '')
/**
* TIP_TEXT 文案后端这里 content 通常是裸字符串群解散 / 退群 / 踢人 等系统提示
* 老接口可能包成 {"content": "..."}解析得到 .content 就用否则当裸文案展示避免出现空行
*/
const tipText = computed(() => {
const raw = props.message.content || ''
if (!raw) {
return ''
}
const parsed = parseMessage<TextMessage>(raw)
if (parsed && typeof parsed.content === 'string') {
return parsed.content
}
return raw
})
/** TIP_TEXT 文案:与 conversationStore.resolveLastContent / MessageHistory.renderContent 共用 helper避免兼容性逻辑分裂 */
const tipText = computed(() => resolveTipText(props.message.content))
const imagePayload = computed(() =>
isImage.value ? parseMessage<ImageMessage>(props.message.content) : null
)

View File

@ -16,6 +16,7 @@ import {
generateClientMessageId,
parseMessage,
parseRecallMessageId,
resolveTipText,
type TextMessage
} from '../../utils/message'
import type { Conversation, ConversationStoreMeta, Message } from '../types'
@ -449,8 +450,10 @@ export const useConversationStore = defineStore('imConversationStore', {
case ImMessageType.RECALL:
return buildRecallTip(messageInfo.senderNickName, messageInfo.selfSend)
case ImMessageType.TEXT:
case ImMessageType.TIP_TEXT:
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
case ImMessageType.TIP_TEXT:
// TIP_TEXT 后端常发裸字符串(群解散 / 退群 / 踢人),不能按 TextMessage JSON 解析,否则摘要变空
return resolveTipText(messageInfo.content)
default:
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
}

View File

@ -7,6 +7,9 @@ import { generateUUID } from '@/utils'
// cn.iocoder.yudao.module.im.service.websocket.dto.message.* 下的 DTO。
// 各类消息 payload interface 字段对齐后端;解析统一用 parseMessage<T>
// 序列化直接 JSON.stringify(payload)。
//
// 例外TIP_TEXT系统提示群解散 / 退群 / 踢人 等)后端会直接发裸字符串,
// 展示侧需走 resolveTipText 兼容裸字符串 + 老接口可能的 {"content":"..."} 两种形态。
// ====================================================================
// ==================== 客户端 ID ====================
@ -79,6 +82,29 @@ export const parseMessage = <T>(content: string): T | null => {
/** 序列化消息 payload 为 content JSON 字符串;与 parseMessage 对称 */
export const serializeMessage = <T>(payload: T): string => JSON.stringify(payload)
// ==================== TIP_TEXT ====================
/**
* TIP_TEXT
*
* / 退 / {"content": "..."}
* .content
*
* MessageItem / conversationStore.resolveLastContent / MessageHistory.renderContent
*
*/
export const resolveTipText = (content: string): string => {
const raw = content || ''
if (!raw) {
return ''
}
const parsed = parseMessage<TextMessage>(raw)
if (parsed && typeof parsed.content === 'string') {
return parsed.content
}
return raw
}
// ==================== 撤回 ====================
/**