mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
@@ -234,6 +234,8 @@ class ChatService {
|
|||||||
// 缓存会话表信息,避免每次查询
|
// 缓存会话表信息,避免每次查询
|
||||||
private sessionTablesCache = new Map<string, Array<{ tableName: string; dbPath: string }>>()
|
private sessionTablesCache = new Map<string, Array<{ tableName: string; dbPath: string }>>()
|
||||||
private messageTableColumnsCache = new Map<string, { columns: Set<string>; updatedAt: number }>()
|
private messageTableColumnsCache = new Map<string, { columns: Set<string>; updatedAt: number }>()
|
||||||
|
private messageName2IdTableCache = new Map<string, string | null>()
|
||||||
|
private messageSenderIdCache = new Map<string, string | null>()
|
||||||
private readonly sessionTablesCacheTtl = 300000 // 5分钟
|
private readonly sessionTablesCacheTtl = 300000 // 5分钟
|
||||||
private readonly messageTableColumnsCacheTtlMs = 30 * 60 * 1000
|
private readonly messageTableColumnsCacheTtlMs = 30 * 60 * 1000
|
||||||
private sessionMessageCountCache = new Map<string, { count: number; updatedAt: number }>()
|
private sessionMessageCountCache = new Map<string, { count: number; updatedAt: number }>()
|
||||||
@@ -1990,6 +1992,62 @@ class ChatService {
|
|||||||
return [lowerRaw]
|
return [lowerRaw]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resolveMessageIsSend(rawIsSend: number | null, senderUsername?: string | null): {
|
||||||
|
isSend: number | null
|
||||||
|
selfMatched: boolean
|
||||||
|
correctedBySelfIdentity: boolean
|
||||||
|
} {
|
||||||
|
const normalizedRawIsSend = Number.isFinite(rawIsSend as number) ? rawIsSend : null
|
||||||
|
const senderKeys = this.buildIdentityKeys(String(senderUsername || ''))
|
||||||
|
if (senderKeys.length === 0) {
|
||||||
|
return {
|
||||||
|
isSend: normalizedRawIsSend,
|
||||||
|
selfMatched: false,
|
||||||
|
correctedBySelfIdentity: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const myWxid = String(this.configService.get('myWxid') || '').trim()
|
||||||
|
const selfKeys = this.buildIdentityKeys(myWxid)
|
||||||
|
if (selfKeys.length === 0) {
|
||||||
|
return {
|
||||||
|
isSend: normalizedRawIsSend,
|
||||||
|
selfMatched: false,
|
||||||
|
correctedBySelfIdentity: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selfMatched = senderKeys.some(senderKey =>
|
||||||
|
selfKeys.some(selfKey =>
|
||||||
|
senderKey === selfKey ||
|
||||||
|
senderKey.startsWith(selfKey + '_') ||
|
||||||
|
selfKey.startsWith(senderKey + '_')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (selfMatched && normalizedRawIsSend !== 1) {
|
||||||
|
return {
|
||||||
|
isSend: 1,
|
||||||
|
selfMatched: true,
|
||||||
|
correctedBySelfIdentity: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedRawIsSend === null) {
|
||||||
|
return {
|
||||||
|
isSend: selfMatched ? 1 : 0,
|
||||||
|
selfMatched,
|
||||||
|
correctedBySelfIdentity: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isSend: normalizedRawIsSend,
|
||||||
|
selfMatched,
|
||||||
|
correctedBySelfIdentity: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private extractGroupMemberUsername(member: any): string {
|
private extractGroupMemberUsername(member: any): string {
|
||||||
if (!member) return ''
|
if (!member) return ''
|
||||||
if (typeof member === 'string') return member.trim()
|
if (typeof member === 'string') return member.trim()
|
||||||
@@ -3048,9 +3106,6 @@ class ChatService {
|
|||||||
|
|
||||||
private mapRowsToMessages(rows: Record<string, any>[]): Message[] {
|
private mapRowsToMessages(rows: Record<string, any>[]): Message[] {
|
||||||
const myWxid = this.configService.get('myWxid')
|
const myWxid = this.configService.get('myWxid')
|
||||||
const cleanedWxid = myWxid ? this.cleanAccountDirName(myWxid) : null
|
|
||||||
const myWxidLower = myWxid ? myWxid.toLowerCase() : null
|
|
||||||
const cleanedWxidLower = cleanedWxid ? cleanedWxid.toLowerCase() : null
|
|
||||||
|
|
||||||
const messages: Message[] = []
|
const messages: Message[] = []
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
@@ -3075,30 +3130,14 @@ class ChatService {
|
|||||||
const content = this.decodeMessageContent(rawMessageContent, rawCompressContent);
|
const content = this.decodeMessageContent(rawMessageContent, rawCompressContent);
|
||||||
const localType = this.getRowInt(row, ['local_type', 'localType', 'type', 'msg_type', 'msgType', 'WCDB_CT_local_type'], 1)
|
const localType = this.getRowInt(row, ['local_type', 'localType', 'type', 'msg_type', 'msgType', 'WCDB_CT_local_type'], 1)
|
||||||
const isSendRaw = this.getRowField(row, ['computed_is_send', 'computedIsSend', 'is_send', 'isSend', 'WCDB_CT_is_send'])
|
const isSendRaw = this.getRowField(row, ['computed_is_send', 'computedIsSend', 'is_send', 'isSend', 'WCDB_CT_is_send'])
|
||||||
let isSend = isSendRaw === null ? null : parseInt(isSendRaw, 10)
|
const parsedRawIsSend = isSendRaw === null ? null : parseInt(isSendRaw, 10)
|
||||||
const senderUsername = this.getRowField(row, ['sender_username', 'senderUsername', 'sender', 'WCDB_CT_sender_username'])
|
const senderUsername = this.getRowField(row, ['sender_username', 'senderUsername', 'sender', 'WCDB_CT_sender_username'])
|
||||||
|| this.extractSenderUsernameFromContent(content)
|
|| this.extractSenderUsernameFromContent(content)
|
||||||
|| null
|
|| null
|
||||||
|
const { isSend } = this.resolveMessageIsSend(parsedRawIsSend, senderUsername)
|
||||||
const createTime = this.getRowInt(row, ['create_time', 'createTime', 'createtime', 'msg_create_time', 'msgCreateTime', 'msg_time', 'msgTime', 'time', 'WCDB_CT_create_time'], 0)
|
const createTime = this.getRowInt(row, ['create_time', 'createTime', 'createtime', 'msg_create_time', 'msgCreateTime', 'msg_time', 'msgTime', 'time', 'WCDB_CT_create_time'], 0)
|
||||||
|
|
||||||
if (senderUsername && (myWxidLower || cleanedWxidLower)) {
|
if (senderUsername && !myWxid) {
|
||||||
const senderLower = String(senderUsername).toLowerCase()
|
|
||||||
const expectedIsSend = (
|
|
||||||
senderLower === myWxidLower ||
|
|
||||||
senderLower === cleanedWxidLower ||
|
|
||||||
// 兼容非 wxid 开头的账号(如果文件夹名带后缀,如 custom_backup,而 sender 是 custom)
|
|
||||||
(myWxidLower && myWxidLower.startsWith(senderLower + '_')) ||
|
|
||||||
(cleanedWxidLower && cleanedWxidLower.startsWith(senderLower + '_'))
|
|
||||||
) ? 1 : 0
|
|
||||||
if (isSend === null) {
|
|
||||||
isSend = expectedIsSend
|
|
||||||
// [DEBUG] Issue #34: 记录 isSend 推断过程
|
|
||||||
if (expectedIsSend === 0 && localType === 1) {
|
|
||||||
// 仅在被判为接收且是文本消息时记录,避免刷屏
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (senderUsername && !myWxid) {
|
|
||||||
// [DEBUG] Issue #34: 未配置 myWxid,无法判断是否发送
|
// [DEBUG] Issue #34: 未配置 myWxid,无法判断是否发送
|
||||||
if (messages.length < 5) {
|
if (messages.length < 5) {
|
||||||
console.warn(`[ChatService] Warning: myWxid not set. Cannot determine if message is sent by me. sender=${senderUsername}`)
|
console.warn(`[ChatService] Warning: myWxid not set. Cannot determine if message is sent by me. sender=${senderUsername}`)
|
||||||
@@ -4421,6 +4460,75 @@ class ChatService {
|
|||||||
return result.rows[0]?.name || null
|
return result.rows[0]?.name || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async resolveMessageName2IdTableName(dbPath: string): Promise<string | null> {
|
||||||
|
const normalizedDbPath = String(dbPath || '').trim()
|
||||||
|
if (!normalizedDbPath) return null
|
||||||
|
if (this.messageName2IdTableCache.has(normalizedDbPath)) {
|
||||||
|
return this.messageName2IdTableCache.get(normalizedDbPath) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await wcdbService.execQuery(
|
||||||
|
'message',
|
||||||
|
normalizedDbPath,
|
||||||
|
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'Name2Id%' ORDER BY name DESC LIMIT 1"
|
||||||
|
)
|
||||||
|
const tableName = result.success && result.rows && result.rows.length > 0
|
||||||
|
? String(result.rows[0]?.name || '').trim() || null
|
||||||
|
: null
|
||||||
|
this.messageName2IdTableCache.set(normalizedDbPath, tableName)
|
||||||
|
return tableName
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveMessageSenderUsernameById(dbPath: string, senderId: unknown): Promise<string | null> {
|
||||||
|
const normalizedDbPath = String(dbPath || '').trim()
|
||||||
|
const numericSenderId = Number.parseInt(String(senderId ?? '').trim(), 10)
|
||||||
|
if (!normalizedDbPath || !Number.isFinite(numericSenderId) || numericSenderId <= 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheKey = `${normalizedDbPath}::${numericSenderId}`
|
||||||
|
if (this.messageSenderIdCache.has(cacheKey)) {
|
||||||
|
return this.messageSenderIdCache.get(cacheKey) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
const name2IdTable = await this.resolveMessageName2IdTableName(normalizedDbPath)
|
||||||
|
if (!name2IdTable) {
|
||||||
|
this.messageSenderIdCache.set(cacheKey, null)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const escapedTableName = String(name2IdTable).replace(/"/g, '""')
|
||||||
|
const result = await wcdbService.execQuery(
|
||||||
|
'message',
|
||||||
|
normalizedDbPath,
|
||||||
|
`SELECT user_name FROM "${escapedTableName}" WHERE rowid = ${numericSenderId} LIMIT 1`
|
||||||
|
)
|
||||||
|
const username = result.success && result.rows && result.rows.length > 0
|
||||||
|
? String(result.rows[0]?.user_name || result.rows[0]?.userName || '').trim() || null
|
||||||
|
: null
|
||||||
|
this.messageSenderIdCache.set(cacheKey, username)
|
||||||
|
return username
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveSenderUsernameForMessageRow(
|
||||||
|
row: Record<string, any>,
|
||||||
|
rawContent: string
|
||||||
|
): Promise<string | null> {
|
||||||
|
const directSender = this.getRowField(row, ['sender_username', 'senderUsername', 'sender', 'WCDB_CT_sender_username'])
|
||||||
|
|| this.extractSenderUsernameFromContent(rawContent)
|
||||||
|
if (directSender) {
|
||||||
|
return directSender
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbPath = this.getRowField(row, ['db_path', 'dbPath', '_db_path'])
|
||||||
|
const realSenderId = this.getRowField(row, ['real_sender_id', 'realSenderId'])
|
||||||
|
if (!dbPath || realSenderId === null || realSenderId === undefined || String(realSenderId).trim() === '') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.resolveMessageSenderUsernameById(String(dbPath), realSenderId)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否像 wxid
|
* 判断是否像 wxid
|
||||||
*/
|
*/
|
||||||
@@ -6690,7 +6798,7 @@ class ChatService {
|
|||||||
db_path: dbPath,
|
db_path: dbPath,
|
||||||
table_name: tableName
|
table_name: tableName
|
||||||
}
|
}
|
||||||
const message = this.parseMessage(row)
|
const message = await this.parseMessage(row, { source: 'detail', sessionId })
|
||||||
|
|
||||||
if (message.localId !== 0) {
|
if (message.localId !== 0) {
|
||||||
return { success: true, message }
|
return { success: true, message }
|
||||||
@@ -6711,7 +6819,45 @@ class ChatService {
|
|||||||
if (!result.success || !result.messages) {
|
if (!result.success || !result.messages) {
|
||||||
return { success: false, error: result.error || '搜索失败' }
|
return { success: false, error: result.error || '搜索失败' }
|
||||||
}
|
}
|
||||||
const messages = result.messages.map((row: any) => this.parseMessage(row)).filter(Boolean) as Message[]
|
const messages: Message[] = []
|
||||||
|
const isGroupSearch = Boolean(String(sessionId || '').trim().endsWith('@chatroom'))
|
||||||
|
|
||||||
|
for (const row of result.messages) {
|
||||||
|
let message = await this.parseMessage(row, { source: 'search', sessionId })
|
||||||
|
const needsDetailHydration = isGroupSearch &&
|
||||||
|
Boolean(sessionId) &&
|
||||||
|
message.localId > 0 &&
|
||||||
|
(!message.senderUsername || message.isSend === null)
|
||||||
|
|
||||||
|
if (needsDetailHydration && sessionId) {
|
||||||
|
const detail = await this.getMessageById(sessionId, message.localId)
|
||||||
|
if (detail.success && detail.message) {
|
||||||
|
message = {
|
||||||
|
...message,
|
||||||
|
...detail.message,
|
||||||
|
parsedContent: message.parsedContent || detail.message.parsedContent,
|
||||||
|
rawContent: message.rawContent || detail.message.rawContent,
|
||||||
|
content: message.content || detail.message.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGroupSearch && (needsDetailHydration || message.isSend === 1)) {
|
||||||
|
console.info('[ChatService][GroupSearchHydratedHit]', {
|
||||||
|
sessionId,
|
||||||
|
localId: message.localId,
|
||||||
|
senderUsername: message.senderUsername,
|
||||||
|
isSend: message.isSend,
|
||||||
|
senderDisplayName: message.senderDisplayName,
|
||||||
|
senderAvatarUrl: message.senderAvatarUrl,
|
||||||
|
usedDetailHydration: needsDetailHydration,
|
||||||
|
parsedContent: message.parsedContent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.push(message)
|
||||||
|
}
|
||||||
|
|
||||||
return { success: true, messages }
|
return { success: true, messages }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('ChatService: searchMessages 失败:', e)
|
console.error('ChatService: searchMessages 失败:', e)
|
||||||
@@ -6719,7 +6865,7 @@ class ChatService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseMessage(row: any): Message {
|
private async parseMessage(row: any, options?: { source?: 'search' | 'detail'; sessionId?: string }): Promise<Message> {
|
||||||
const sourceInfo = this.getMessageSourceInfo(row)
|
const sourceInfo = this.getMessageSourceInfo(row)
|
||||||
const rawContent = this.decodeMessageContent(
|
const rawContent = this.decodeMessageContent(
|
||||||
this.getRowField(row, [
|
this.getRowField(row, [
|
||||||
@@ -6746,9 +6892,9 @@ class ChatService {
|
|||||||
const localType = this.getRowInt(row, ['local_type', 'localType', 'type', 'msg_type', 'msgType', 'WCDB_CT_local_type'], 0)
|
const localType = this.getRowInt(row, ['local_type', 'localType', 'type', 'msg_type', 'msgType', 'WCDB_CT_local_type'], 0)
|
||||||
const createTime = this.getRowInt(row, ['create_time', 'createTime', 'createtime', 'msg_create_time', 'msgCreateTime', 'msg_time', 'msgTime', 'time', 'WCDB_CT_create_time'], 0)
|
const createTime = this.getRowInt(row, ['create_time', 'createTime', 'createtime', 'msg_create_time', 'msgCreateTime', 'msg_time', 'msgTime', 'time', 'WCDB_CT_create_time'], 0)
|
||||||
const sortSeq = this.getRowInt(row, ['sort_seq', 'sortSeq', 'seq', 'sequence', 'WCDB_CT_sort_seq'], createTime)
|
const sortSeq = this.getRowInt(row, ['sort_seq', 'sortSeq', 'seq', 'sequence', 'WCDB_CT_sort_seq'], createTime)
|
||||||
const senderUsername = this.getRowField(row, ['sender_username', 'senderUsername', 'sender', 'WCDB_CT_sender_username'])
|
const rawIsSend = this.getRowField(row, ['computed_is_send', 'computedIsSend', 'is_send', 'isSend', 'WCDB_CT_is_send'])
|
||||||
|| this.extractSenderUsernameFromContent(rawContent)
|
const senderUsername = await this.resolveSenderUsernameForMessageRow(row, rawContent)
|
||||||
|| null
|
const sendState = this.resolveMessageIsSend(rawIsSend === null ? null : parseInt(rawIsSend, 10), senderUsername)
|
||||||
const msg: Message = {
|
const msg: Message = {
|
||||||
messageKey: this.buildMessageKey({
|
messageKey: this.buildMessageKey({
|
||||||
localId,
|
localId,
|
||||||
@@ -6764,7 +6910,7 @@ class ChatService {
|
|||||||
localType,
|
localType,
|
||||||
createTime,
|
createTime,
|
||||||
sortSeq,
|
sortSeq,
|
||||||
isSend: this.getRowInt(row, ['computed_is_send', 'computedIsSend', 'is_send', 'isSend', 'WCDB_CT_is_send'], 0),
|
isSend: sendState.isSend,
|
||||||
senderUsername,
|
senderUsername,
|
||||||
rawContent: rawContent,
|
rawContent: rawContent,
|
||||||
content: rawContent, // 添加原始内容供视频MD5解析使用
|
content: rawContent, // 添加原始内容供视频MD5解析使用
|
||||||
@@ -6785,6 +6931,19 @@ class ChatService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options?.source === 'search' && String(options.sessionId || '').endsWith('@chatroom') && sendState.selfMatched) {
|
||||||
|
console.info('[ChatService][GroupSearchSelfHit]', {
|
||||||
|
sessionId: options.sessionId,
|
||||||
|
localId,
|
||||||
|
createTime,
|
||||||
|
senderUsername,
|
||||||
|
rawIsSend,
|
||||||
|
resolvedIsSend: sendState.isSend,
|
||||||
|
correctedBySelfIdentity: sendState.correctedBySelfIdentity,
|
||||||
|
rowKeys: Object.keys(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 图片/语音解析逻辑 (简化示例,实际应调用现有解析方法)
|
// 图片/语音解析逻辑 (简化示例,实际应调用现有解析方法)
|
||||||
if (msg.localType === 3) { // Image
|
if (msg.localType === 3) { // Image
|
||||||
const imgInfo = this.parseImageInfo(rawContent)
|
const imgInfo = this.parseImageInfo(rawContent)
|
||||||
|
|||||||
@@ -116,6 +116,40 @@ function resolveSearchSenderUsernameFallback(value?: string | null): string | un
|
|||||||
return normalized
|
return normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildSearchIdentityCandidates(value?: string | null): string[] {
|
||||||
|
const normalized = normalizeSearchIdentityText(value)
|
||||||
|
if (!normalized) return []
|
||||||
|
const lower = normalized.toLowerCase()
|
||||||
|
const candidates = new Set<string>([lower])
|
||||||
|
if (lower.startsWith('wxid_')) {
|
||||||
|
const match = lower.match(/^(wxid_[^_]+)/i)
|
||||||
|
if (match?.[1]) {
|
||||||
|
candidates.add(match[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...candidates]
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCurrentUserSearchIdentity(
|
||||||
|
senderUsername?: string | null,
|
||||||
|
myWxid?: string | null
|
||||||
|
): boolean {
|
||||||
|
const senderCandidates = buildSearchIdentityCandidates(senderUsername)
|
||||||
|
const selfCandidates = buildSearchIdentityCandidates(myWxid)
|
||||||
|
if (senderCandidates.length === 0 || selfCandidates.length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const sender of senderCandidates) {
|
||||||
|
for (const self of selfCandidates) {
|
||||||
|
if (sender === self) return true
|
||||||
|
if (sender.startsWith(self + '_')) return true
|
||||||
|
if (self.startsWith(sender + '_')) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
interface XmlField {
|
interface XmlField {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -2764,6 +2798,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
const {
|
const {
|
||||||
normalizedSessionId,
|
normalizedSessionId,
|
||||||
isDirectSearchSession,
|
isDirectSearchSession,
|
||||||
|
isGroupSearchSession,
|
||||||
resolvedSessionDisplayName,
|
resolvedSessionDisplayName,
|
||||||
resolvedSessionAvatarUrl
|
resolvedSessionAvatarUrl
|
||||||
} = resolveSearchSessionContext(sessionId)
|
} = resolveSearchSessionContext(sessionId)
|
||||||
@@ -2771,6 +2806,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
|
|
||||||
return sortedMessages.map((message) => {
|
return sortedMessages.map((message) => {
|
||||||
const senderUsername = normalizeSearchIdentityText(message.senderUsername) || message.senderUsername
|
const senderUsername = normalizeSearchIdentityText(message.senderUsername) || message.senderUsername
|
||||||
|
const inferredSelfFromSender = isGroupSearchSession && isCurrentUserSearchIdentity(senderUsername, myWxid)
|
||||||
const senderDisplayName = resolveSearchSenderDisplayName(
|
const senderDisplayName = resolveSearchSenderDisplayName(
|
||||||
message.senderDisplayName,
|
message.senderDisplayName,
|
||||||
senderUsername,
|
senderUsername,
|
||||||
@@ -2778,7 +2814,8 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
)
|
)
|
||||||
const senderUsernameFallback = resolveSearchSenderUsernameFallback(senderUsername)
|
const senderUsernameFallback = resolveSearchSenderUsernameFallback(senderUsername)
|
||||||
const senderAvatarUrl = normalizeSearchAvatarUrl(message.senderAvatarUrl)
|
const senderAvatarUrl = normalizeSearchAvatarUrl(message.senderAvatarUrl)
|
||||||
const nextSenderDisplayName = message.isSend === 1
|
const nextIsSend = inferredSelfFromSender ? 1 : message.isSend
|
||||||
|
const nextSenderDisplayName = nextIsSend === 1
|
||||||
? (senderDisplayName || '我')
|
? (senderDisplayName || '我')
|
||||||
: (
|
: (
|
||||||
senderDisplayName ||
|
senderDisplayName ||
|
||||||
@@ -2787,12 +2824,29 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
(isDirectSearchSession ? resolvedSessionUsernameFallback : undefined) ||
|
(isDirectSearchSession ? resolvedSessionUsernameFallback : undefined) ||
|
||||||
'未知'
|
'未知'
|
||||||
)
|
)
|
||||||
const nextSenderAvatarUrl = message.isSend === 1
|
const nextSenderAvatarUrl = nextIsSend === 1
|
||||||
? (senderAvatarUrl || myAvatarUrl)
|
? (senderAvatarUrl || myAvatarUrl)
|
||||||
: (senderAvatarUrl || (isDirectSearchSession ? resolvedSessionAvatarUrl : undefined))
|
: (senderAvatarUrl || (isDirectSearchSession ? resolvedSessionAvatarUrl : undefined))
|
||||||
|
|
||||||
|
if (inferredSelfFromSender) {
|
||||||
|
console.info('[InSessionSearch][GroupSelfHit][hydrate]', {
|
||||||
|
sessionId: normalizedSessionId,
|
||||||
|
localId: message.localId,
|
||||||
|
senderUsername,
|
||||||
|
rawIsSend: message.isSend,
|
||||||
|
nextIsSend,
|
||||||
|
rawSenderDisplayName: message.senderDisplayName,
|
||||||
|
nextSenderDisplayName,
|
||||||
|
rawSenderAvatarUrl: message.senderAvatarUrl,
|
||||||
|
nextSenderAvatarUrl,
|
||||||
|
myWxid,
|
||||||
|
hasMyAvatarUrl: Boolean(myAvatarUrl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
senderUsername === message.senderUsername &&
|
senderUsername === message.senderUsername &&
|
||||||
|
nextIsSend === message.isSend &&
|
||||||
nextSenderDisplayName === message.senderDisplayName &&
|
nextSenderDisplayName === message.senderDisplayName &&
|
||||||
nextSenderAvatarUrl === message.senderAvatarUrl
|
nextSenderAvatarUrl === message.senderAvatarUrl
|
||||||
) {
|
) {
|
||||||
@@ -2801,12 +2855,13 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
|
isSend: nextIsSend,
|
||||||
senderUsername,
|
senderUsername,
|
||||||
senderDisplayName: nextSenderDisplayName,
|
senderDisplayName: nextSenderDisplayName,
|
||||||
senderAvatarUrl: nextSenderAvatarUrl
|
senderAvatarUrl: nextSenderAvatarUrl
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [currentSessionId, myAvatarUrl, resolveSearchSessionContext])
|
}, [currentSessionId, myAvatarUrl, myWxid, resolveSearchSessionContext])
|
||||||
|
|
||||||
const enrichMessagesWithSenderProfiles = useCallback(async (rawMessages: Message[], sessionId?: string) => {
|
const enrichMessagesWithSenderProfiles = useCallback(async (rawMessages: Message[], sessionId?: string) => {
|
||||||
let messages = hydrateInSessionSearchResults(rawMessages, sessionId)
|
let messages = hydrateInSessionSearchResults(rawMessages, sessionId)
|
||||||
@@ -2962,6 +3017,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
return messages.map((message) => {
|
return messages.map((message) => {
|
||||||
const sender = normalizeSearchIdentityText(message.senderUsername)
|
const sender = normalizeSearchIdentityText(message.senderUsername)
|
||||||
const profile = sender ? profileMap.get(sender) : undefined
|
const profile = sender ? profileMap.get(sender) : undefined
|
||||||
|
const inferredSelfFromSender = isGroupSearchSession && isCurrentUserSearchIdentity(sender, myWxid)
|
||||||
const profileDisplayName = resolveSearchSenderDisplayName(
|
const profileDisplayName = resolveSearchSenderDisplayName(
|
||||||
profile?.displayName,
|
profile?.displayName,
|
||||||
sender,
|
sender,
|
||||||
@@ -2975,7 +3031,8 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
const senderUsernameFallback = resolveSearchSenderUsernameFallback(sender)
|
const senderUsernameFallback = resolveSearchSenderUsernameFallback(sender)
|
||||||
const sessionUsernameFallback = resolveSearchSenderUsernameFallback(normalizedSessionId)
|
const sessionUsernameFallback = resolveSearchSenderUsernameFallback(normalizedSessionId)
|
||||||
const currentSenderAvatarUrl = normalizeSearchAvatarUrl(message.senderAvatarUrl)
|
const currentSenderAvatarUrl = normalizeSearchAvatarUrl(message.senderAvatarUrl)
|
||||||
const nextSenderDisplayName = message.isSend === 1
|
const nextIsSend = inferredSelfFromSender ? 1 : message.isSend
|
||||||
|
const nextSenderDisplayName = nextIsSend === 1
|
||||||
? (currentSenderDisplayName || profileDisplayName || '我')
|
? (currentSenderDisplayName || profileDisplayName || '我')
|
||||||
: (
|
: (
|
||||||
profileDisplayName ||
|
profileDisplayName ||
|
||||||
@@ -2985,7 +3042,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
(isDirectSearchSession ? sessionUsernameFallback : undefined) ||
|
(isDirectSearchSession ? sessionUsernameFallback : undefined) ||
|
||||||
'未知'
|
'未知'
|
||||||
)
|
)
|
||||||
const nextSenderAvatarUrl = message.isSend === 1
|
const nextSenderAvatarUrl = nextIsSend === 1
|
||||||
? (currentSenderAvatarUrl || myAvatarUrl || normalizeSearchAvatarUrl(profile?.avatarUrl))
|
? (currentSenderAvatarUrl || myAvatarUrl || normalizeSearchAvatarUrl(profile?.avatarUrl))
|
||||||
: (
|
: (
|
||||||
currentSenderAvatarUrl ||
|
currentSenderAvatarUrl ||
|
||||||
@@ -2993,8 +3050,27 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
(isDirectSearchSession ? resolvedSessionAvatarUrl : undefined)
|
(isDirectSearchSession ? resolvedSessionAvatarUrl : undefined)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (inferredSelfFromSender) {
|
||||||
|
console.info('[InSessionSearch][GroupSelfHit][enrich]', {
|
||||||
|
sessionId: normalizedSessionId,
|
||||||
|
localId: message.localId,
|
||||||
|
senderUsername: sender,
|
||||||
|
rawIsSend: message.isSend,
|
||||||
|
nextIsSend,
|
||||||
|
profileDisplayName,
|
||||||
|
currentSenderDisplayName,
|
||||||
|
nextSenderDisplayName,
|
||||||
|
profileAvatarUrl: normalizeSearchAvatarUrl(profile?.avatarUrl),
|
||||||
|
currentSenderAvatarUrl,
|
||||||
|
nextSenderAvatarUrl,
|
||||||
|
myWxid,
|
||||||
|
hasMyAvatarUrl: Boolean(myAvatarUrl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sender === message.senderUsername &&
|
sender === message.senderUsername &&
|
||||||
|
nextIsSend === message.isSend &&
|
||||||
nextSenderDisplayName === message.senderDisplayName &&
|
nextSenderDisplayName === message.senderDisplayName &&
|
||||||
nextSenderAvatarUrl === message.senderAvatarUrl
|
nextSenderAvatarUrl === message.senderAvatarUrl
|
||||||
) {
|
) {
|
||||||
@@ -3003,6 +3079,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
|
isSend: nextIsSend,
|
||||||
senderUsername: sender || message.senderUsername,
|
senderUsername: sender || message.senderUsername,
|
||||||
senderDisplayName: nextSenderDisplayName,
|
senderDisplayName: nextSenderDisplayName,
|
||||||
senderAvatarUrl: nextSenderAvatarUrl
|
senderAvatarUrl: nextSenderAvatarUrl
|
||||||
@@ -3012,6 +3089,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
currentSessionId,
|
currentSessionId,
|
||||||
hydrateInSessionSearchResults,
|
hydrateInSessionSearchResults,
|
||||||
myAvatarUrl,
|
myAvatarUrl,
|
||||||
|
myWxid,
|
||||||
resolveSearchSessionContext
|
resolveSearchSessionContext
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user