mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
引用消息支持
This commit is contained in:
@@ -585,6 +585,263 @@ interface GroupPanelMember {
|
|||||||
messageCountStatus: GroupMessageCountStatus
|
messageCountStatus: GroupMessageCountStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUOTED_SENDER_CACHE_TTL_MS = 10 * 60 * 1000
|
||||||
|
const quotedSenderDisplayCache = new Map<string, { displayName: string; updatedAt: number }>()
|
||||||
|
const quotedSenderDisplayLoading = new Map<string, Promise<string | undefined>>()
|
||||||
|
const quotedGroupMembersCache = new Map<string, { members: GroupPanelMember[]; updatedAt: number }>()
|
||||||
|
const quotedGroupMembersLoading = new Map<string, Promise<GroupPanelMember[]>>()
|
||||||
|
|
||||||
|
function buildQuotedSenderCacheKey(
|
||||||
|
sessionId: string,
|
||||||
|
senderUsername: string,
|
||||||
|
isGroupChat: boolean
|
||||||
|
): string {
|
||||||
|
const normalizedSessionId = normalizeSearchIdentityText(sessionId) || String(sessionId || '').trim()
|
||||||
|
const normalizedSender = normalizeSearchIdentityText(senderUsername) || String(senderUsername || '').trim()
|
||||||
|
return `${isGroupChat ? 'group' : 'direct'}::${normalizedSessionId}::${normalizedSender}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameQuotedSenderIdentity(left?: string | null, right?: string | null): boolean {
|
||||||
|
const leftCandidates = buildSearchIdentityCandidates(left)
|
||||||
|
const rightCandidates = buildSearchIdentityCandidates(right)
|
||||||
|
if (leftCandidates.length === 0 || rightCandidates.length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const leftCandidate of leftCandidates) {
|
||||||
|
for (const rightCandidate of rightCandidates) {
|
||||||
|
if (leftCandidate === rightCandidate) return true
|
||||||
|
if (leftCandidate.startsWith(rightCandidate + '_')) return true
|
||||||
|
if (rightCandidate.startsWith(leftCandidate + '_')) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeQuotedGroupMember(member: Partial<GroupPanelMember> | null | undefined): GroupPanelMember | null {
|
||||||
|
const username = String(member?.username || '').trim()
|
||||||
|
if (!username) return null
|
||||||
|
|
||||||
|
const displayName = String(member?.displayName || '').trim()
|
||||||
|
const nickname = String(member?.nickname || '').trim()
|
||||||
|
const remark = String(member?.remark || '').trim()
|
||||||
|
const alias = String(member?.alias || '').trim()
|
||||||
|
const groupNickname = String(member?.groupNickname || '').trim()
|
||||||
|
|
||||||
|
return {
|
||||||
|
username,
|
||||||
|
displayName: displayName || groupNickname || remark || nickname || alias || username,
|
||||||
|
avatarUrl: member?.avatarUrl,
|
||||||
|
nickname,
|
||||||
|
alias,
|
||||||
|
remark,
|
||||||
|
groupNickname,
|
||||||
|
isOwner: Boolean(member?.isOwner),
|
||||||
|
isFriend: Boolean(member?.isFriend),
|
||||||
|
messageCount: Number.isFinite(member?.messageCount) ? Math.max(0, Math.floor(member?.messageCount as number)) : 0,
|
||||||
|
messageCountStatus: 'ready'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveQuotedSenderFallbackDisplayName(
|
||||||
|
sessionId: string,
|
||||||
|
senderUsername?: string | null,
|
||||||
|
fallbackDisplayName?: string | null
|
||||||
|
): string | undefined {
|
||||||
|
const resolved = resolveSearchSenderDisplayName(fallbackDisplayName, senderUsername, sessionId)
|
||||||
|
if (resolved) return resolved
|
||||||
|
return resolveSearchSenderUsernameFallback(senderUsername)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveQuotedSenderUsername(
|
||||||
|
fromusr?: string | null,
|
||||||
|
chatusr?: string | null
|
||||||
|
): string {
|
||||||
|
const normalizedChatUsr = String(chatusr || '').trim()
|
||||||
|
const normalizedFromUsr = String(fromusr || '').trim()
|
||||||
|
|
||||||
|
if (normalizedChatUsr) {
|
||||||
|
return normalizedChatUsr
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedFromUsr.endsWith('@chatroom')) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedFromUsr
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveQuotedGroupMemberDisplayName(member: GroupPanelMember): string | undefined {
|
||||||
|
const remark = normalizeSearchIdentityText(member.remark)
|
||||||
|
if (remark) return remark
|
||||||
|
|
||||||
|
const groupNickname = normalizeSearchIdentityText(member.groupNickname)
|
||||||
|
if (groupNickname) return groupNickname
|
||||||
|
|
||||||
|
const nickname = normalizeSearchIdentityText(member.nickname)
|
||||||
|
if (nickname) return nickname
|
||||||
|
|
||||||
|
const displayName = resolveSearchSenderDisplayName(member.displayName, member.username)
|
||||||
|
if (displayName) return displayName
|
||||||
|
|
||||||
|
const alias = normalizeSearchIdentityText(member.alias)
|
||||||
|
if (alias) return alias
|
||||||
|
|
||||||
|
return resolveSearchSenderUsernameFallback(member.username)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveQuotedPrivateDisplayName(contact: any): string | undefined {
|
||||||
|
const remark = normalizeSearchIdentityText(contact?.remark)
|
||||||
|
if (remark) return remark
|
||||||
|
|
||||||
|
const nickname = normalizeSearchIdentityText(
|
||||||
|
contact?.nickName || contact?.nick_name || contact?.nickname
|
||||||
|
)
|
||||||
|
if (nickname) return nickname
|
||||||
|
|
||||||
|
const alias = normalizeSearchIdentityText(contact?.alias)
|
||||||
|
if (alias) return alias
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getQuotedGroupMembers(chatroomId: string): Promise<GroupPanelMember[]> {
|
||||||
|
const normalizedChatroomId = String(chatroomId || '').trim()
|
||||||
|
if (!normalizedChatroomId || !normalizedChatroomId.includes('@chatroom')) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const cached = quotedGroupMembersCache.get(normalizedChatroomId)
|
||||||
|
if (cached && Date.now() - cached.updatedAt < QUOTED_SENDER_CACHE_TTL_MS) {
|
||||||
|
return cached.members
|
||||||
|
}
|
||||||
|
|
||||||
|
const pending = quotedGroupMembersLoading.get(normalizedChatroomId)
|
||||||
|
if (pending) return pending
|
||||||
|
|
||||||
|
const request = window.electronAPI.groupAnalytics.getGroupMembersPanelData(
|
||||||
|
normalizedChatroomId,
|
||||||
|
{ forceRefresh: false, includeMessageCounts: false }
|
||||||
|
).then((result) => {
|
||||||
|
const members = Array.isArray(result.data)
|
||||||
|
? result.data
|
||||||
|
.map((member) => normalizeQuotedGroupMember(member as Partial<GroupPanelMember>))
|
||||||
|
.filter((member): member is GroupPanelMember => Boolean(member))
|
||||||
|
: []
|
||||||
|
|
||||||
|
if (members.length > 0) {
|
||||||
|
quotedGroupMembersCache.set(normalizedChatroomId, {
|
||||||
|
members,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
|
return cached?.members || []
|
||||||
|
}).catch(() => cached?.members || []).finally(() => {
|
||||||
|
quotedGroupMembersLoading.delete(normalizedChatroomId)
|
||||||
|
})
|
||||||
|
|
||||||
|
quotedGroupMembersLoading.set(normalizedChatroomId, request)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveQuotedSenderDisplayName(options: {
|
||||||
|
sessionId: string
|
||||||
|
senderUsername?: string | null
|
||||||
|
fallbackDisplayName?: string | null
|
||||||
|
isGroupChat?: boolean
|
||||||
|
myWxid?: string | null
|
||||||
|
}): Promise<string | undefined> {
|
||||||
|
const normalizedSessionId = String(options.sessionId || '').trim()
|
||||||
|
const normalizedSender = String(options.senderUsername || '').trim()
|
||||||
|
const fallbackDisplayName = resolveQuotedSenderFallbackDisplayName(
|
||||||
|
normalizedSessionId,
|
||||||
|
normalizedSender,
|
||||||
|
options.fallbackDisplayName
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!normalizedSender) {
|
||||||
|
return fallbackDisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheKey = buildQuotedSenderCacheKey(normalizedSessionId, normalizedSender, Boolean(options.isGroupChat))
|
||||||
|
const cached = quotedSenderDisplayCache.get(cacheKey)
|
||||||
|
if (cached && Date.now() - cached.updatedAt < QUOTED_SENDER_CACHE_TTL_MS) {
|
||||||
|
return cached.displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
const pending = quotedSenderDisplayLoading.get(cacheKey)
|
||||||
|
if (pending) return pending
|
||||||
|
|
||||||
|
const request = (async (): Promise<string | undefined> => {
|
||||||
|
if (options.isGroupChat) {
|
||||||
|
const members = await getQuotedGroupMembers(normalizedSessionId)
|
||||||
|
const matchedMember = members.find((member) => isSameQuotedSenderIdentity(member.username, normalizedSender))
|
||||||
|
const groupDisplayName = matchedMember ? resolveQuotedGroupMemberDisplayName(matchedMember) : undefined
|
||||||
|
if (groupDisplayName) {
|
||||||
|
quotedSenderDisplayCache.set(cacheKey, {
|
||||||
|
displayName: groupDisplayName,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
return groupDisplayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCurrentUserSearchIdentity(normalizedSender, options.myWxid)) {
|
||||||
|
const selfDisplayName = fallbackDisplayName || '我'
|
||||||
|
quotedSenderDisplayCache.set(cacheKey, {
|
||||||
|
displayName: selfDisplayName,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
return selfDisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contact = await window.electronAPI.chat.getContact(normalizedSender)
|
||||||
|
const contactDisplayName = resolveQuotedPrivateDisplayName(contact)
|
||||||
|
if (contactDisplayName) {
|
||||||
|
quotedSenderDisplayCache.set(cacheKey, {
|
||||||
|
displayName: contactDisplayName,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
return contactDisplayName
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore contact lookup failures and fall back below
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profile = await window.electronAPI.chat.getContactAvatar(normalizedSender)
|
||||||
|
const profileDisplayName = normalizeSearchIdentityText(profile?.displayName)
|
||||||
|
if (profileDisplayName && !isWxidLikeSearchIdentity(profileDisplayName)) {
|
||||||
|
quotedSenderDisplayCache.set(cacheKey, {
|
||||||
|
displayName: profileDisplayName,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
return profileDisplayName
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore avatar lookup failures and keep fallback usable
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackDisplayName) {
|
||||||
|
quotedSenderDisplayCache.set(cacheKey, {
|
||||||
|
displayName: fallbackDisplayName,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackDisplayName
|
||||||
|
})().finally(() => {
|
||||||
|
quotedSenderDisplayLoading.delete(cacheKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
quotedSenderDisplayLoading.set(cacheKey, request)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
interface SessionListCachePayload {
|
interface SessionListCachePayload {
|
||||||
updatedAt: number
|
updatedAt: number
|
||||||
sessions: ChatSession[]
|
sessions: ChatSession[]
|
||||||
@@ -2394,6 +2651,10 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
const handleAccountChanged = useCallback(async () => {
|
const handleAccountChanged = useCallback(async () => {
|
||||||
senderAvatarCache.clear()
|
senderAvatarCache.clear()
|
||||||
senderAvatarLoading.clear()
|
senderAvatarLoading.clear()
|
||||||
|
quotedSenderDisplayCache.clear()
|
||||||
|
quotedSenderDisplayLoading.clear()
|
||||||
|
quotedGroupMembersCache.clear()
|
||||||
|
quotedGroupMembersLoading.clear()
|
||||||
sessionContactProfileCacheRef.current.clear()
|
sessionContactProfileCacheRef.current.clear()
|
||||||
pendingSessionContactEnrichRef.current.clear()
|
pendingSessionContactEnrichRef.current.clear()
|
||||||
sessionContactEnrichAttemptAtRef.current.clear()
|
sessionContactEnrichAttemptAtRef.current.clear()
|
||||||
@@ -5660,6 +5921,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
session={currentSession!}
|
session={currentSession!}
|
||||||
showTime={!showDateDivider && showTime}
|
showTime={!showDateDivider && showTime}
|
||||||
myAvatarUrl={myAvatarUrl}
|
myAvatarUrl={myAvatarUrl}
|
||||||
|
myWxid={myWxid}
|
||||||
isGroupChat={isCurrentSessionGroup}
|
isGroupChat={isCurrentSessionGroup}
|
||||||
autoTranscribeVoiceEnabled={autoTranscribeVoiceEnabled}
|
autoTranscribeVoiceEnabled={autoTranscribeVoiceEnabled}
|
||||||
onRequireModelDownload={handleRequireModelDownload}
|
onRequireModelDownload={handleRequireModelDownload}
|
||||||
@@ -5678,6 +5940,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
formatDateDivider,
|
formatDateDivider,
|
||||||
currentSession,
|
currentSession,
|
||||||
myAvatarUrl,
|
myAvatarUrl,
|
||||||
|
myWxid,
|
||||||
isCurrentSessionGroup,
|
isCurrentSessionGroup,
|
||||||
autoTranscribeVoiceEnabled,
|
autoTranscribeVoiceEnabled,
|
||||||
handleRequireModelDownload,
|
handleRequireModelDownload,
|
||||||
@@ -7258,6 +7521,7 @@ function MessageBubble({
|
|||||||
session,
|
session,
|
||||||
showTime,
|
showTime,
|
||||||
myAvatarUrl,
|
myAvatarUrl,
|
||||||
|
myWxid,
|
||||||
isGroupChat,
|
isGroupChat,
|
||||||
autoTranscribeVoiceEnabled,
|
autoTranscribeVoiceEnabled,
|
||||||
onRequireModelDownload,
|
onRequireModelDownload,
|
||||||
@@ -7271,6 +7535,7 @@ function MessageBubble({
|
|||||||
session: ChatSession;
|
session: ChatSession;
|
||||||
showTime?: boolean;
|
showTime?: boolean;
|
||||||
myAvatarUrl?: string;
|
myAvatarUrl?: string;
|
||||||
|
myWxid?: string;
|
||||||
isGroupChat?: boolean;
|
isGroupChat?: boolean;
|
||||||
autoTranscribeVoiceEnabled?: boolean;
|
autoTranscribeVoiceEnabled?: boolean;
|
||||||
onRequireModelDownload?: (sessionId: string, messageId: string) => void;
|
onRequireModelDownload?: (sessionId: string, messageId: string) => void;
|
||||||
@@ -7290,6 +7555,7 @@ function MessageBubble({
|
|||||||
const isSent = message.isSend === 1
|
const isSent = message.isSend === 1
|
||||||
const [senderAvatarUrl, setSenderAvatarUrl] = useState<string | undefined>(undefined)
|
const [senderAvatarUrl, setSenderAvatarUrl] = useState<string | undefined>(undefined)
|
||||||
const [senderName, setSenderName] = useState<string | undefined>(undefined)
|
const [senderName, setSenderName] = useState<string | undefined>(undefined)
|
||||||
|
const [quotedSenderName, setQuotedSenderName] = useState<string | undefined>(undefined)
|
||||||
const senderProfileRequestSeqRef = useRef(0)
|
const senderProfileRequestSeqRef = useRef(0)
|
||||||
const [emojiError, setEmojiError] = useState(false)
|
const [emojiError, setEmojiError] = useState(false)
|
||||||
const [emojiLoading, setEmojiLoading] = useState(false)
|
const [emojiLoading, setEmojiLoading] = useState(false)
|
||||||
@@ -8214,6 +8480,53 @@ function MessageBubble({
|
|||||||
appMsgTextCache.set(selector, value)
|
appMsgTextCache.set(selector, value)
|
||||||
return value
|
return value
|
||||||
}, [appMsgDoc, appMsgTextCache])
|
}, [appMsgDoc, appMsgTextCache])
|
||||||
|
const quotedSenderUsername = resolveQuotedSenderUsername(
|
||||||
|
queryAppMsgText('refermsg > fromusr'),
|
||||||
|
queryAppMsgText('refermsg > chatusr')
|
||||||
|
)
|
||||||
|
const quotedContent = message.quotedContent || queryAppMsgText('refermsg > content') || ''
|
||||||
|
const quotedSenderFallbackName = useMemo(
|
||||||
|
() => resolveQuotedSenderFallbackDisplayName(
|
||||||
|
session.username,
|
||||||
|
quotedSenderUsername,
|
||||||
|
message.quotedSender || queryAppMsgText('refermsg > displayname') || ''
|
||||||
|
),
|
||||||
|
[message.quotedSender, queryAppMsgText, quotedSenderUsername, session.username]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false
|
||||||
|
const nextFallbackName = quotedSenderFallbackName || undefined
|
||||||
|
setQuotedSenderName(nextFallbackName)
|
||||||
|
|
||||||
|
if (!quotedContent || !quotedSenderUsername) {
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolveQuotedSenderDisplayName({
|
||||||
|
sessionId: session.username,
|
||||||
|
senderUsername: quotedSenderUsername,
|
||||||
|
fallbackDisplayName: nextFallbackName,
|
||||||
|
isGroupChat,
|
||||||
|
myWxid
|
||||||
|
}).then((resolvedName) => {
|
||||||
|
if (cancelled) return
|
||||||
|
setQuotedSenderName(resolvedName || nextFallbackName)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
quotedContent,
|
||||||
|
quotedSenderFallbackName,
|
||||||
|
quotedSenderUsername,
|
||||||
|
session.username,
|
||||||
|
isGroupChat,
|
||||||
|
myWxid
|
||||||
|
])
|
||||||
|
|
||||||
const locationMessageMeta = useMemo(() => {
|
const locationMessageMeta = useMemo(() => {
|
||||||
if (message.localType !== 48) return null
|
if (message.localType !== 48) return null
|
||||||
@@ -8248,7 +8561,8 @@ function MessageBubble({
|
|||||||
: (isGroupChat ? resolvedSenderAvatarUrl : session.avatarUrl)
|
: (isGroupChat ? resolvedSenderAvatarUrl : session.avatarUrl)
|
||||||
|
|
||||||
// 是否有引用消息
|
// 是否有引用消息
|
||||||
const hasQuote = message.quotedContent && message.quotedContent.length > 0
|
const hasQuote = quotedContent.length > 0
|
||||||
|
const displayQuotedSenderName = quotedSenderName || quotedSenderFallbackName
|
||||||
|
|
||||||
const handlePlayVideo = useCallback(async () => {
|
const handlePlayVideo = useCallback(async () => {
|
||||||
if (!videoInfo?.videoUrl) return
|
if (!videoInfo?.videoUrl) return
|
||||||
@@ -8659,7 +8973,6 @@ function MessageBubble({
|
|||||||
if (xmlType === '57') {
|
if (xmlType === '57') {
|
||||||
const replyText = q('title') || cleanedParsedContent || ''
|
const replyText = q('title') || cleanedParsedContent || ''
|
||||||
const referContent = q('refermsg > content') || ''
|
const referContent = q('refermsg > content') || ''
|
||||||
const referSender = q('refermsg > displayname') || ''
|
|
||||||
const referType = q('refermsg > type') || ''
|
const referType = q('refermsg > type') || ''
|
||||||
|
|
||||||
// 根据被引用消息类型渲染对应内容
|
// 根据被引用消息类型渲染对应内容
|
||||||
@@ -8691,7 +9004,7 @@ function MessageBubble({
|
|||||||
return (
|
return (
|
||||||
<div className="bubble-content">
|
<div className="bubble-content">
|
||||||
<div className="quoted-message">
|
<div className="quoted-message">
|
||||||
{referSender && <span className="quoted-sender">{referSender}</span>}
|
{displayQuotedSenderName && <span className="quoted-sender">{displayQuotedSenderName}</span>}
|
||||||
<span className="quoted-text">{renderReferContent()}</span>
|
<span className="quoted-text">{renderReferContent()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
||||||
@@ -8787,11 +9100,10 @@ function MessageBubble({
|
|||||||
// 引用回复消息(appMsgKind='quote',xmlType=57)
|
// 引用回复消息(appMsgKind='quote',xmlType=57)
|
||||||
const replyText = message.linkTitle || q('title') || cleanedParsedContent || ''
|
const replyText = message.linkTitle || q('title') || cleanedParsedContent || ''
|
||||||
const referContent = message.quotedContent || q('refermsg > content') || ''
|
const referContent = message.quotedContent || q('refermsg > content') || ''
|
||||||
const referSender = message.quotedSender || q('refermsg > displayname') || ''
|
|
||||||
return (
|
return (
|
||||||
<div className="bubble-content">
|
<div className="bubble-content">
|
||||||
<div className="quoted-message">
|
<div className="quoted-message">
|
||||||
{referSender && <span className="quoted-sender">{referSender}</span>}
|
{displayQuotedSenderName && <span className="quoted-sender">{displayQuotedSenderName}</span>}
|
||||||
<span className="quoted-text">{renderTextWithEmoji(cleanMessageContent(referContent))}</span>
|
<span className="quoted-text">{renderTextWithEmoji(cleanMessageContent(referContent))}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
||||||
@@ -8982,7 +9294,6 @@ function MessageBubble({
|
|||||||
if (appMsgType === '57') {
|
if (appMsgType === '57') {
|
||||||
const replyText = parsedDoc?.querySelector('title')?.textContent?.trim() || cleanedParsedContent || ''
|
const replyText = parsedDoc?.querySelector('title')?.textContent?.trim() || cleanedParsedContent || ''
|
||||||
const referContent = parsedDoc?.querySelector('refermsg > content')?.textContent?.trim() || ''
|
const referContent = parsedDoc?.querySelector('refermsg > content')?.textContent?.trim() || ''
|
||||||
const referSender = parsedDoc?.querySelector('refermsg > displayname')?.textContent?.trim() || ''
|
|
||||||
const referType = parsedDoc?.querySelector('refermsg > type')?.textContent?.trim() || ''
|
const referType = parsedDoc?.querySelector('refermsg > type')?.textContent?.trim() || ''
|
||||||
|
|
||||||
const renderReferContent2 = () => {
|
const renderReferContent2 = () => {
|
||||||
@@ -9008,7 +9319,7 @@ function MessageBubble({
|
|||||||
return (
|
return (
|
||||||
<div className="bubble-content">
|
<div className="bubble-content">
|
||||||
<div className="quoted-message">
|
<div className="quoted-message">
|
||||||
{referSender && <span className="quoted-sender">{referSender}</span>}
|
{displayQuotedSenderName && <span className="quoted-sender">{displayQuotedSenderName}</span>}
|
||||||
<span className="quoted-text">{renderReferContent2()}</span>
|
<span className="quoted-text">{renderReferContent2()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
<div className="message-text">{renderTextWithEmoji(cleanMessageContent(replyText))}</div>
|
||||||
@@ -9294,8 +9605,8 @@ function MessageBubble({
|
|||||||
return (
|
return (
|
||||||
<div className="bubble-content">
|
<div className="bubble-content">
|
||||||
<div className="quoted-message">
|
<div className="quoted-message">
|
||||||
{message.quotedSender && <span className="quoted-sender">{message.quotedSender}</span>}
|
{displayQuotedSenderName && <span className="quoted-sender">{displayQuotedSenderName}</span>}
|
||||||
<span className="quoted-text">{renderTextWithEmoji(cleanMessageContent(message.quotedContent || ''))}</span>
|
<span className="quoted-text">{renderTextWithEmoji(cleanMessageContent(quotedContent))}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-text">{renderTextWithEmoji(cleanedParsedContent)}</div>
|
<div className="message-text">{renderTextWithEmoji(cleanedParsedContent)}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -9398,6 +9709,7 @@ const MemoMessageBubble = React.memo(MessageBubble, (prevProps, nextProps) => {
|
|||||||
if (prevProps.messageKey !== nextProps.messageKey) return false
|
if (prevProps.messageKey !== nextProps.messageKey) return false
|
||||||
if (prevProps.showTime !== nextProps.showTime) return false
|
if (prevProps.showTime !== nextProps.showTime) return false
|
||||||
if (prevProps.myAvatarUrl !== nextProps.myAvatarUrl) return false
|
if (prevProps.myAvatarUrl !== nextProps.myAvatarUrl) return false
|
||||||
|
if (prevProps.myWxid !== nextProps.myWxid) return false
|
||||||
if (prevProps.isGroupChat !== nextProps.isGroupChat) return false
|
if (prevProps.isGroupChat !== nextProps.isGroupChat) return false
|
||||||
if (prevProps.autoTranscribeVoiceEnabled !== nextProps.autoTranscribeVoiceEnabled) return false
|
if (prevProps.autoTranscribeVoiceEnabled !== nextProps.autoTranscribeVoiceEnabled) return false
|
||||||
if (prevProps.isSelectionMode !== nextProps.isSelectionMode) return false
|
if (prevProps.isSelectionMode !== nextProps.isSelectionMode) return false
|
||||||
|
|||||||
Reference in New Issue
Block a user