修复群公告发布通知消息正文完全不显示、聊天列表预览显示"undefined"
群公告发布后自动生成的通知消息,真实content是{text:"群公告\n<内容>"}这种
扁平对象(不是纯字符串,也不是标准Drafty的{txt,fmt,ent}结构),且
head['x-im-type']是"text"而不是已处理的"system_notice",落到Drafty处理
分支后既渲染不出气泡正文、列表预览也变成字面的"undefined"字符串。
抽出dispatch.ts里原本只服务system_notice的{text}扁平内容识别逻辑
(重命名为flatTextContentOf并导出),在renderDrafty和
formatMessagePreview的Drafty分支之前都接上——不改变已有的居中系统提示
样式(这条消息本来就该是普通气泡,发送者信息一直是正确的,只是正文
丢了),只是把"文本内容是扁平{text}对象"这一种情况也当作合法纯文本处理。
实测:真实发布一条群公告后,气泡正文和列表预览都正确显示"群公告
全功能测试公告内容",不再是空白或"undefined"。
This commit is contained in:
@@ -18,12 +18,28 @@ export function isRecalled(msg: StoredMessage): boolean {
|
|||||||
return !isServerDeleted(msg) && msg.content == null;
|
return !isServerDeleted(msg) && msg.content == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SystemNoticeContent {
|
interface FlatTextContent {
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSystemNoticeContent(content: unknown): content is SystemNoticeContent {
|
function isFlatTextContent(content: unknown): content is FlatTextContent {
|
||||||
return !!content && typeof content === 'object' && typeof (content as SystemNoticeContent).text === 'string';
|
return !!content && typeof content === 'object' && typeof (content as FlatTextContent).text === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `{text: "..."}` -- a flat, non-Drafty content shape (no `txt`/`fmt`/`ent`) this backend uses for
|
||||||
|
* more than one kind of message, not just the centered system-event lines `systemNoticeText` below
|
||||||
|
* renders: a real, live-confirmed example is the auto-posted "群公告\n<announcement text>" message
|
||||||
|
* a group's announcement publish creates, which has an ordinary sender/avatar (NOT a centered system
|
||||||
|
* line) and `head['x-im-type']:"text"` (not `system_notice`) -- but the SAME flat `{text}` content
|
||||||
|
* shape regardless. `renderDrafty`/`formatMessagePreview` both need this recognized as plain text
|
||||||
|
* before falling through to real Drafty processing (`Drafty.format`/`Drafty.preview` on an object
|
||||||
|
* with none of the fields they expect renders empty/`undefined`, confirmed live: a group's own
|
||||||
|
* announcement-notice bubble showed no text at all, and the chat list's preview literally read "我:
|
||||||
|
* undefined").
|
||||||
|
*/
|
||||||
|
export function flatTextContentOf(content: unknown): string | null {
|
||||||
|
return isFlatTextContent(content) ? content.text : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +51,7 @@ function isSystemNoticeContent(content: unknown): content is SystemNoticeContent
|
|||||||
export function systemNoticeText(msg: StoredMessage): string | null {
|
export function systemNoticeText(msg: StoredMessage): string | null {
|
||||||
const headType = msg.head?.['x-im-type'];
|
const headType = msg.head?.['x-im-type'];
|
||||||
if (headType !== 'system_notice' && headType !== 'system_action') return null;
|
if (headType !== 'system_notice' && headType !== 'system_action') return null;
|
||||||
return isSystemNoticeContent(msg.content) ? msg.content.text : null;
|
return flatTextContentOf(msg.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContactCardContent {
|
export interface ContactCardContent {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Drafty, type DraftyContent } from 'tinode-sdk';
|
|||||||
|
|
||||||
import { AudioAttachment, FileAttachment, ImageAttachment, VideoAttachment } from '@/features/messages/AttachmentPreview';
|
import { AudioAttachment, FileAttachment, ImageAttachment, VideoAttachment } from '@/features/messages/AttachmentPreview';
|
||||||
import { SafeLink } from '@/features/messages/SafeLink';
|
import { SafeLink } from '@/features/messages/SafeLink';
|
||||||
|
import { flatTextContentOf } from '@/lib/messages/dispatch';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bubble content renderer for the Drafty style tags this app currently sends/receives. Grown
|
* Bubble content renderer for the Drafty style tags this app currently sends/receives. Grown
|
||||||
@@ -124,6 +125,8 @@ function makeFormatNode(highlightQuery: string | undefined) {
|
|||||||
export function renderDrafty(content: DraftyContent | string | null | undefined, highlightQuery?: string): ReactNode {
|
export function renderDrafty(content: DraftyContent | string | null | undefined, highlightQuery?: string): ReactNode {
|
||||||
if (content == null) return null;
|
if (content == null) return null;
|
||||||
if (typeof content === 'string') return highlightQuery ? <>{highlightMatches(content, highlightQuery, 'plain')}</> : content;
|
if (typeof content === 'string') return highlightQuery ? <>{highlightMatches(content, highlightQuery, 'plain')}</> : content;
|
||||||
|
const flatText = flatTextContentOf(content);
|
||||||
|
if (flatText != null) return highlightQuery ? <>{highlightMatches(flatText, highlightQuery, 'plain')}</> : flatText;
|
||||||
if (Drafty.isPlainText(content)) {
|
if (Drafty.isPlainText(content)) {
|
||||||
const text = Drafty.toPlainText(content);
|
const text = Drafty.toPlainText(content);
|
||||||
return highlightQuery ? <>{highlightMatches(text, highlightQuery, 'plain')}</> : text;
|
return highlightQuery ? <>{highlightMatches(text, highlightQuery, 'plain')}</> : text;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Drafty, type DraftyContent, type StoredMessage } from 'tinode-sdk';
|
import { Drafty, type DraftyContent, type StoredMessage } from 'tinode-sdk';
|
||||||
|
|
||||||
import { callResultDisplay, contactCardContentOf, isServerDeleted, systemNoticeText } from '@/lib/messages/dispatch';
|
import { callResultDisplay, contactCardContentOf, flatTextContentOf, isServerDeleted, systemNoticeText } from '@/lib/messages/dispatch';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One-line chat-list preview text (README §2.1): plain text renders as-is, everything else falls
|
* One-line chat-list preview text (README §2.1): plain text renders as-is, everything else falls
|
||||||
@@ -26,6 +26,13 @@ export function formatMessagePreview(msg: StoredMessage | undefined, myUserId: s
|
|||||||
if (contactCardContentOf(msg)) return `${prefix}[名片]`;
|
if (contactCardContentOf(msg)) return `${prefix}[名片]`;
|
||||||
const callResult = callResultDisplay(msg, msg.from === myUserId);
|
const callResult = callResultDisplay(msg, msg.from === myUserId);
|
||||||
if (callResult) return `${prefix}${callResult.text}`;
|
if (callResult) return `${prefix}${callResult.text}`;
|
||||||
|
// Same flat `{text}` shape `systemNoticeText` above already knows about, but NOT gated to
|
||||||
|
// `system_notice`/`system_action` -- a real, live-confirmed example is a group's own
|
||||||
|
// announcement-publish notice (`head['x-im-type']:"text"`, ordinary sender, not a centered system
|
||||||
|
// line), which fell through everything above straight into the Drafty-entity branches below and
|
||||||
|
// produced the literal string "undefined" (confirmed live: chat list showed "我:undefined").
|
||||||
|
const flatText = flatTextContentOf(content);
|
||||||
|
if (flatText != null) return prefix + flatText;
|
||||||
if (typeof content === 'string' || Drafty.isPlainText(content)) {
|
if (typeof content === 'string' || Drafty.isPlainText(content)) {
|
||||||
return prefix + Drafty.toPlainText(content);
|
return prefix + Drafty.toPlainText(content);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user