🐛 fix(im): TIP_TEXT 系统提示不再显示空白
群解散 / 退群 / 踢人 等系统提示后端发的是裸字符串,之前按 TextMessage JSON
解析 → 主聊天窗显示空行、会话列表摘要变空。
- message.ts:新增 resolveTipText helper,兼容裸字符串 + {"content":"..."}
- MessageItem / conversationStore.resolveLastContent 把 TIP_TEXT 从 TEXT
分支拆出来,统一走 resolveTipText(TEXT 仍按 JSON 解析,没有裸字符串可能)
im
parent
cb5d30e327
commit
9e8d04249c
|
|
@ -217,6 +217,7 @@ import { CommonStatusEnum } from '@/utils/constants'
|
||||||
import {
|
import {
|
||||||
parseMessage,
|
parseMessage,
|
||||||
buildRecallTip,
|
buildRecallTip,
|
||||||
|
resolveTipText,
|
||||||
type TextMessage,
|
type TextMessage,
|
||||||
type ImageMessage,
|
type ImageMessage,
|
||||||
type FileMessage,
|
type FileMessage,
|
||||||
|
|
@ -319,21 +320,8 @@ function formatTipTime(timestamp: number): string {
|
||||||
/** 文本内容 */
|
/** 文本内容 */
|
||||||
const textContent = computed(() => parseMessage<TextMessage>(props.message.content)?.content ?? '')
|
const textContent = computed(() => parseMessage<TextMessage>(props.message.content)?.content ?? '')
|
||||||
|
|
||||||
/**
|
/** TIP_TEXT 文案:与 conversationStore.resolveLastContent / MessageHistory.renderContent 共用 helper,避免兼容性逻辑分裂 */
|
||||||
* TIP_TEXT 文案:后端这里 content 通常是裸字符串(群解散 / 退群 / 踢人 等系统提示),
|
const tipText = computed(() => resolveTipText(props.message.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
|
|
||||||
})
|
|
||||||
const imagePayload = computed(() =>
|
const imagePayload = computed(() =>
|
||||||
isImage.value ? parseMessage<ImageMessage>(props.message.content) : null
|
isImage.value ? parseMessage<ImageMessage>(props.message.content) : null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
generateClientMessageId,
|
generateClientMessageId,
|
||||||
parseMessage,
|
parseMessage,
|
||||||
parseRecallMessageId,
|
parseRecallMessageId,
|
||||||
|
resolveTipText,
|
||||||
type TextMessage
|
type TextMessage
|
||||||
} from '../../utils/message'
|
} from '../../utils/message'
|
||||||
import type { Conversation, ConversationStoreMeta, Message } from '../types'
|
import type { Conversation, ConversationStoreMeta, Message } from '../types'
|
||||||
|
|
@ -449,8 +450,10 @@ export const useConversationStore = defineStore('imConversationStore', {
|
||||||
case ImMessageType.RECALL:
|
case ImMessageType.RECALL:
|
||||||
return buildRecallTip(messageInfo.senderNickName, messageInfo.selfSend)
|
return buildRecallTip(messageInfo.senderNickName, messageInfo.selfSend)
|
||||||
case ImMessageType.TEXT:
|
case ImMessageType.TEXT:
|
||||||
case ImMessageType.TIP_TEXT:
|
|
||||||
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
|
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
|
||||||
|
case ImMessageType.TIP_TEXT:
|
||||||
|
// TIP_TEXT 后端常发裸字符串(群解散 / 退群 / 踢人),不能按 TextMessage JSON 解析,否则摘要变空
|
||||||
|
return resolveTipText(messageInfo.content)
|
||||||
default:
|
default:
|
||||||
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
|
return parseMessage<TextMessage>(messageInfo.content)?.content ?? ''
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ import { generateUUID } from '@/utils'
|
||||||
// cn.iocoder.yudao.module.im.service.websocket.dto.message.* 下的 DTO。
|
// cn.iocoder.yudao.module.im.service.websocket.dto.message.* 下的 DTO。
|
||||||
// 各类消息 payload interface 字段对齐后端;解析统一用 parseMessage<T>,
|
// 各类消息 payload interface 字段对齐后端;解析统一用 parseMessage<T>,
|
||||||
// 序列化直接 JSON.stringify(payload)。
|
// 序列化直接 JSON.stringify(payload)。
|
||||||
|
//
|
||||||
|
// 例外:TIP_TEXT(系统提示,群解散 / 退群 / 踢人 等)后端会直接发裸字符串,
|
||||||
|
// 展示侧需走 resolveTipText 兼容裸字符串 + 老接口可能的 {"content":"..."} 两种形态。
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
|
||||||
// ==================== 客户端 ID ====================
|
// ==================== 客户端 ID ====================
|
||||||
|
|
@ -79,6 +82,29 @@ export const parseMessage = <T>(content: string): T | null => {
|
||||||
/** 序列化消息 payload 为 content JSON 字符串;与 parseMessage 对称 */
|
/** 序列化消息 payload 为 content JSON 字符串;与 parseMessage 对称 */
|
||||||
export const serializeMessage = <T>(payload: T): string => JSON.stringify(payload)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 撤回 ====================
|
// ==================== 撤回 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue