From a331f45f8700d6bcf45f8c8e8e86d2adefe25d1f Mon Sep 17 00:00:00 2001 From: xuncha <1658671838@qq.com> Date: Fri, 20 Mar 2026 16:01:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=BC=E5=87=BA=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ExportPage.tsx | 69 ++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx index 04efb15..3c21ce3 100644 --- a/src/pages/ExportPage.tsx +++ b/src/pages/ExportPage.tsx @@ -2796,7 +2796,9 @@ function ExportPage() { emojiMessages: typeof metric.emojiMessages === 'number' ? metric.emojiMessages : previous.emojiMessages, transferMessages: typeof metric.transferMessages === 'number' ? metric.transferMessages : previous.transferMessages, redPacketMessages: typeof metric.redPacketMessages === 'number' ? metric.redPacketMessages : previous.redPacketMessages, - callMessages: typeof metric.callMessages === 'number' ? metric.callMessages : previous.callMessages + callMessages: typeof metric.callMessages === 'number' ? metric.callMessages : previous.callMessages, + firstTimestamp: typeof metric.firstTimestamp === 'number' ? metric.firstTimestamp : previous.firstTimestamp, + lastTimestamp: typeof metric.lastTimestamp === 'number' ? metric.lastTimestamp : previous.lastTimestamp } if ( previous.totalMessages === nextMetric.totalMessages && @@ -4033,21 +4035,42 @@ function ExportPage() { const normalizedSessionIds = Array.from(new Set((sessionIds || []).map(id => String(id || '').trim()).filter(Boolean))) if (normalizedSessionIds.length === 0) return null + const sessionRowMap = new Map() + for (const session of sessions) { + sessionRowMap.set(session.username, session) + } + let minTimestamp: number | undefined let maxTimestamp: number | undefined - const resolvedSessionIds = new Set() + const resolvedSessionBounds = new Map() const absorbMetric = (sessionId: string, metric?: { firstTimestamp?: number; lastTimestamp?: number } | null) => { if (!metric) return const firstTimestamp = normalizeTimestampSeconds(metric.firstTimestamp) const lastTimestamp = normalizeTimestampSeconds(metric.lastTimestamp) - if (typeof firstTimestamp !== 'number' || typeof lastTimestamp !== 'number') return - resolvedSessionIds.add(sessionId) - if (minTimestamp === undefined || firstTimestamp < minTimestamp) minTimestamp = firstTimestamp - if (maxTimestamp === undefined || lastTimestamp > maxTimestamp) maxTimestamp = lastTimestamp + if (typeof firstTimestamp !== 'number' && typeof lastTimestamp !== 'number') return + + const previous = resolvedSessionBounds.get(sessionId) || { hasMin: false, hasMax: false } + const nextState = { + hasMin: previous.hasMin || typeof firstTimestamp === 'number', + hasMax: previous.hasMax || typeof lastTimestamp === 'number' + } + resolvedSessionBounds.set(sessionId, nextState) + + if (typeof firstTimestamp === 'number' && (minTimestamp === undefined || firstTimestamp < minTimestamp)) { + minTimestamp = firstTimestamp + } + if (typeof lastTimestamp === 'number' && (maxTimestamp === undefined || lastTimestamp > maxTimestamp)) { + maxTimestamp = lastTimestamp + } } for (const sessionId of normalizedSessionIds) { + const sessionRow = sessionRowMap.get(sessionId) + absorbMetric(sessionId, { + firstTimestamp: undefined, + lastTimestamp: sessionRow?.sortTimestamp || sessionRow?.lastTimestamp + }) absorbMetric(sessionId, sessionContentMetrics[sessionId]) if (sessionDetail?.wxid === sessionId) { absorbMetric(sessionId, { @@ -4068,23 +4091,37 @@ function ExportPage() { } } - const missingSessionIds = () => normalizedSessionIds.filter(sessionId => !resolvedSessionIds.has(sessionId)) + const missingSessionIds = () => normalizedSessionIds.filter(sessionId => { + const resolved = resolvedSessionBounds.get(sessionId) + return !resolved?.hasMin || !resolved?.hasMax + }) + + const staleSessionIds = new Set() if (missingSessionIds().length > 0) { - applyStatsResult(await window.electronAPI.chat.getExportSessionStats( + const cacheResult = await window.electronAPI.chat.getExportSessionStats( missingSessionIds(), { includeRelations: false, allowStaleCache: true, cacheOnly: true } + ) + applyStatsResult(cacheResult) + for (const sessionId of cacheResult?.needsRefresh || []) { + staleSessionIds.add(String(sessionId || '').trim()) + } + } + + const sessionsNeedingFreshStats = Array.from(new Set([ + ...missingSessionIds(), + ...Array.from(staleSessionIds).filter(Boolean) + ])) + + if (sessionsNeedingFreshStats.length > 0) { + applyStatsResult(await window.electronAPI.chat.getExportSessionStats( + sessionsNeedingFreshStats, + { includeRelations: false } )) } if (missingSessionIds().length > 0) { - applyStatsResult(await window.electronAPI.chat.getExportSessionStats( - missingSessionIds(), - { includeRelations: false, allowStaleCache: true } - )) - } - - if (resolvedSessionIds.size !== normalizedSessionIds.length) { return null } if (typeof minTimestamp !== 'number' || typeof maxTimestamp !== 'number') { @@ -4095,7 +4132,7 @@ function ExportPage() { minDate: new Date(minTimestamp * 1000), maxDate: new Date(maxTimestamp * 1000) } - }, [applySessionMediaMetricsFromStats, sessionContentMetrics, sessionDetail]) + }, [applySessionMediaMetricsFromStats, sessionContentMetrics, sessionDetail, sessions]) const openTimeRangeDialog = useCallback(() => { void (async () => {