mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-05-06 07:26:48 +00:00
This commit is contained in:
@@ -2530,7 +2530,7 @@ class ChatService {
|
||||
const rawRows = result.messages as Record<string, any>[]
|
||||
const hasMore = rawRows.length > pageLimit
|
||||
const selectedRows = hasMore ? rawRows.slice(0, pageLimit) : rawRows
|
||||
const mapped = this.mapRowsToMessages(selectedRows)
|
||||
const mapped = this.mapRowsToMessages(selectedRows, sessionId)
|
||||
const visible = mapped.filter((msg) => this.isMessageVisibleForSession(sessionId, msg))
|
||||
const outputMessages = (visible.length === 0 && mapped.length > 0)
|
||||
? mapped
|
||||
@@ -2541,6 +2541,7 @@ class ChatService {
|
||||
const normalized = this.normalizeMessageOrder(outputMessages)
|
||||
if (normalized.length > 0) {
|
||||
await this.repairEmojiMessages(normalized)
|
||||
await this.resolveQuotedMessages(normalized, sessionId)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -2597,7 +2598,7 @@ class ChatService {
|
||||
}
|
||||
|
||||
// 转换为 Message 对象
|
||||
const messages = this.mapRowsToMessages(res.messages as Record<string, any>[])
|
||||
const messages = this.mapRowsToMessages(res.messages as Record<string, any>[], sessionId)
|
||||
const normalized = this.normalizeMessageOrder(messages)
|
||||
|
||||
// 并发检查并修复缺失 CDN URL 的表情包
|
||||
@@ -2834,7 +2835,7 @@ class ChatService {
|
||||
|
||||
const rowsToProcess = queuedRows
|
||||
queuedRows = []
|
||||
const mappedMessages = this.mapRowsToMessages(rowsToProcess)
|
||||
const mappedMessages = this.mapRowsToMessages(rowsToProcess, sessionId)
|
||||
for (let index = 0; index < mappedMessages.length; index += 1) {
|
||||
const msg = mappedMessages[index]
|
||||
rawRowsConsumed += 1
|
||||
@@ -4825,8 +4826,8 @@ class ChatService {
|
||||
/**
|
||||
* HTTP API 复用消息解析逻辑,确保和应用内展示一致。
|
||||
*/
|
||||
mapRowsToMessagesForApi(rows: Record<string, any>[]): Message[] {
|
||||
return this.mapRowsToMessages(rows)
|
||||
mapRowsToMessagesForApi(rows: Record<string, any>[], sessionId: string): Message[] {
|
||||
return this.mapRowsToMessages(rows, sessionId)
|
||||
}
|
||||
|
||||
mapRowsToMessagesLiteForApi(rows: Record<string, any>[]): Message[] {
|
||||
@@ -4880,7 +4881,7 @@ class ChatService {
|
||||
return messages
|
||||
}
|
||||
|
||||
private mapRowsToMessages(rows: Record<string, any>[]): Message[] {
|
||||
private mapRowsToMessages(rows: Record<string, any>[], sessionId: string): Message[] {
|
||||
const myWxid = this.configService.get('myWxid')
|
||||
|
||||
const messages: Message[] = []
|
||||
@@ -5000,11 +5001,23 @@ class ChatService {
|
||||
encrypVer = imageInfo.encrypVer
|
||||
cdnThumbUrl = imageInfo.cdnThumbUrl
|
||||
imageDatName = this.parseImageDatNameFromRow(row)
|
||||
// 解析图片消息中的引用信息
|
||||
const quoteInfo = this.parseMediaQuoteMessage(content, sessionId)
|
||||
if (quoteInfo.content) quotedContent = quoteInfo.content
|
||||
if (quoteInfo.sender) quotedSender = quoteInfo.sender
|
||||
} else if (localType === 43) {
|
||||
// 视频消息:优先从 packed_info_data 提取真实文件名(32位十六进制),再回退 XML
|
||||
videoMd5 = this.parseVideoFileNameFromRow(row, content)
|
||||
// 解析视频消息中的引用信息
|
||||
const quoteInfo = this.parseMediaQuoteMessage(content, sessionId)
|
||||
if (quoteInfo.content) quotedContent = quoteInfo.content
|
||||
if (quoteInfo.sender) quotedSender = quoteInfo.sender
|
||||
} else if (localType === 34 && content) {
|
||||
voiceDurationSeconds = this.parseVoiceDurationSeconds(content)
|
||||
// 解析语音消息中的引用信息
|
||||
const quoteInfo = this.parseMediaQuoteMessage(content, sessionId)
|
||||
if (quoteInfo.content) quotedContent = quoteInfo.content
|
||||
if (quoteInfo.sender) quotedSender = quoteInfo.sender
|
||||
} else if (localType === 42 && content) {
|
||||
// 名片消息
|
||||
const cardInfo = this.parseCardInfo(content)
|
||||
@@ -5760,6 +5773,116 @@ class ChatService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析媒体消息(图片/视频/语音)中的引用信息
|
||||
* 这些消息的引用信息在 <extcommoninfo><refermsg> 中
|
||||
*/
|
||||
private parseMediaQuoteMessage(content: string, sessionId: string): { content?: string; sender?: string } {
|
||||
try {
|
||||
const normalizedContent = this.decodeHtmlEntities(content || '')
|
||||
const referMsgStart = normalizedContent.indexOf('<refermsg>')
|
||||
const referMsgEnd = normalizedContent.indexOf('</refermsg>')
|
||||
|
||||
if (referMsgStart === -1 || referMsgEnd === -1) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const referMsgXml = normalizedContent.substring(referMsgStart, referMsgEnd + 11)
|
||||
const svrid = this.extractXmlValue(referMsgXml, 'svrid')
|
||||
|
||||
console.log('[DEBUG] parseMediaQuoteMessage - svrid:', svrid)
|
||||
|
||||
if (!svrid) {
|
||||
return {}
|
||||
}
|
||||
|
||||
// 简化方案:返回 svrid 标记
|
||||
console.log('[DEBUG] parseMediaQuoteMessage - 返回标记:', `__SVRID__${svrid}__`)
|
||||
return { content: `__SVRID__${svrid}__` }
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
async resolveQuotedMessages(messages: Message[], sessionId: string): Promise<void> {
|
||||
console.log('[DEBUG] resolveQuotedMessages - 开始解析,消息数量:', messages.length)
|
||||
const svridsToResolve: Array<{ msg: Message; svrid: string }> = []
|
||||
|
||||
for (const msg of messages) {
|
||||
if (msg.quotedContent && msg.quotedContent.startsWith('__SVRID__')) {
|
||||
const match = msg.quotedContent.match(/__SVRID__(.+?)__/)
|
||||
if (match) {
|
||||
console.log('[DEBUG] resolveQuotedMessages - 找到需要解析的svrid:', match[1])
|
||||
svridsToResolve.push({ msg, svrid: match[1] })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[DEBUG] resolveQuotedMessages - 需要解析的数量:', svridsToResolve.length)
|
||||
|
||||
if (svridsToResolve.length === 0) return
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
svridsToResolve.map(({ svrid }) => {
|
||||
console.log('[DEBUG] resolveQuotedMessages - 查询svrid:', svrid, 'sessionId:', sessionId)
|
||||
return wcdbService.getMessageByServerId(sessionId, svrid)
|
||||
})
|
||||
)
|
||||
|
||||
console.log('[DEBUG] resolveQuotedMessages - 查询结果数量:', results.length)
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const result = results[i]
|
||||
const { msg, svrid } = svridsToResolve[i]
|
||||
|
||||
console.log('[DEBUG] resolveQuotedMessages - 处理结果', i, ':', {
|
||||
status: result.status,
|
||||
success: result.status === 'fulfilled' ? result.value.success : false,
|
||||
hasRow: result.status === 'fulfilled' && result.value.row ? true : false,
|
||||
error: result.status === 'fulfilled' ? result.value.error : undefined,
|
||||
svrid
|
||||
})
|
||||
|
||||
if (result.status === 'fulfilled' && result.value.success && result.value.row) {
|
||||
const localType = parseInt(result.value.row.local_type || '0', 10)
|
||||
const rawMessageContent = result.value.row.message_content
|
||||
const rawCompressContent = result.value.row.compress_content
|
||||
|
||||
console.log('[DEBUG] resolveQuotedMessages - 原始数据:', {
|
||||
hasMessageContent: !!rawMessageContent,
|
||||
hasCompressContent: !!rawCompressContent,
|
||||
messageContentType: typeof rawMessageContent,
|
||||
messageContentLength: rawMessageContent ? rawMessageContent.length : 0
|
||||
})
|
||||
|
||||
const content = this.decodeMessageContent(rawMessageContent, rawCompressContent)
|
||||
|
||||
console.log('[DEBUG] resolveQuotedMessages - 解码后:', { localType, contentLength: content.length, contentPreview: content.substring(0, 50) })
|
||||
|
||||
if (localType === 1) {
|
||||
msg.quotedContent = this.sanitizeQuotedContent(content)
|
||||
} else if (localType === 3) {
|
||||
msg.quotedContent = '[图片]'
|
||||
} else if (localType === 34) {
|
||||
msg.quotedContent = '[语音]'
|
||||
} else if (localType === 43) {
|
||||
msg.quotedContent = '[视频]'
|
||||
} else if (localType === 47) {
|
||||
msg.quotedContent = '[动画表情]'
|
||||
} else if (localType === 49) {
|
||||
msg.quotedContent = '[链接]'
|
||||
} else {
|
||||
msg.quotedContent = '[消息]'
|
||||
}
|
||||
console.log('[DEBUG] resolveQuotedMessages - 更新后的quotedContent:', msg.quotedContent)
|
||||
} else {
|
||||
msg.quotedContent = '[引用消息]'
|
||||
console.log('[DEBUG] resolveQuotedMessages - 查询失败,使用占位符')
|
||||
}
|
||||
}
|
||||
console.log('[DEBUG] resolveQuotedMessages - 完成')
|
||||
}
|
||||
|
||||
private extractPreferredQuotedText(referMsgXml: string): string {
|
||||
if (!referMsgXml) return ''
|
||||
|
||||
@@ -8792,7 +8915,7 @@ class ChatService {
|
||||
return { success: false, error: result.error || '查询语音消息失败' }
|
||||
}
|
||||
|
||||
let allVoiceMessages: Message[] = this.mapRowsToMessages(result.rows as Record<string, any>[])
|
||||
let allVoiceMessages: Message[] = this.mapRowsToMessages(result.rows as Record<string, any>[], sessionId)
|
||||
|
||||
// 按 createTime 降序排序
|
||||
allVoiceMessages.sort((a, b) => b.createTime - a.createTime)
|
||||
@@ -8835,7 +8958,7 @@ class ChatService {
|
||||
return { success: false, error: result.error || '查询图片消息失败' }
|
||||
}
|
||||
|
||||
const mapped = this.mapRowsToMessages(result.rows as Record<string, any>[])
|
||||
const mapped = this.mapRowsToMessages(result.rows as Record<string, any>[], sessionId)
|
||||
let allImages: Array<{ imageMd5?: string; imageDatName?: string; createTime?: number }> = mapped
|
||||
.filter(msg => msg.localType === 3)
|
||||
.map(msg => ({
|
||||
@@ -8960,7 +9083,7 @@ class ChatService {
|
||||
if (!result.success || !Array.isArray(result.rows) || result.rows.length === 0) continue
|
||||
if (result.rows.length >= perTypeFetch) maybeHasMore = true
|
||||
|
||||
const mapped = this.mapRowsToMessages(result.rows as Record<string, any>[])
|
||||
const mapped = this.mapRowsToMessages(result.rows as Record<string, any>[], sessionId)
|
||||
for (const message of mapped) {
|
||||
const resourceType = this.resolveResourceType(message)
|
||||
if (!resourceType || !typeSet.has(resourceType)) continue
|
||||
|
||||
Reference in New Issue
Block a user