From c4c7df26086494e78881bd07582f7083d53db301 Mon Sep 17 00:00:00 2001 From: v0 Date: Mon, 6 Apr 2026 03:35:39 +0000 Subject: [PATCH] fix: resolve insight tab loading and performance issues Fix chat session loading logic and optimize session retrieval performance. Co-authored-by: Jason <159670257+Jasonzhu1207@users.noreply.github.com> --- electron/services/insightService.ts | 69 +++++++++++++++++++---------- src/pages/SettingsPage.tsx | 13 +++--- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/electron/services/insightService.ts b/electron/services/insightService.ts index 138eb2b..4299d12 100644 --- a/electron/services/insightService.ts +++ b/electron/services/insightService.ts @@ -24,8 +24,11 @@ import { chatService, ChatSession, Message } from './chatService' // ─── 常量 ──────────────────────────────────────────────────────────────────── -/** DB 变更防抖延迟(毫秒) */ -const DB_CHANGE_DEBOUNCE_MS = 500 +/** + * DB 变更防抖延迟(毫秒)。 + * 设为 2s:微信写库通常是批量操作,500ms 过短会在开机/重连时产生大量连续触发。 + */ +const DB_CHANGE_DEBOUNCE_MS = 2000 /** 首次沉默扫描延迟(毫秒),避免启动期间抢占资源 */ const SILENCE_SCAN_INITIAL_DELAY_MS = 3 * 60 * 1000 @@ -208,6 +211,15 @@ class InsightService { */ private lastSeenTimestamp: Map = new Map() + /** + * 本地会话快照缓存,避免 analyzeRecentActivity 在每次 DB 变更时都做全量读取。 + * 首次调用时填充,此后只在沉默扫描里刷新(沉默扫描间隔更长,更合适做全量刷新)。 + */ + private sessionCache: ChatSession[] | null = null + /** sessionCache 最后刷新时间戳(ms),超过 5 分钟强制重新拉取 */ + private sessionCacheAt = 0 + private static readonly SESSION_CACHE_TTL_MS = 5 * 60 * 1000 + private started = false constructor() { @@ -230,7 +242,7 @@ class InsightService { this.dbDebounceTimer = null } if (this.silenceScanTimer !== null) { - clearInterval(this.silenceScanTimer) + clearTimeout(this.silenceScanTimer) this.silenceScanTimer = null } if (this.silenceInitialDelayTimer !== null) { @@ -358,6 +370,29 @@ class InsightService { return whitelist.includes(sessionId) } + /** + * 获取会话列表,优先使用缓存(5 分钟 TTL)。 + * 缓存命中时不访问 DB,显著减少对主线程的占用。 + */ + private async getSessionsCached(forceRefresh = false): Promise { + const now = Date.now() + if ( + !forceRefresh && + this.sessionCache !== null && + now - this.sessionCacheAt < InsightService.SESSION_CACHE_TTL_MS + ) { + return this.sessionCache + } + const connectResult = await chatService.connect() + if (!connectResult.success) return this.sessionCache ?? [] + const result = await chatService.getSessions() + if (result.success && result.sessions) { + this.sessionCache = result.sessions as ChatSession[] + this.sessionCacheAt = now + } + return this.sessionCache ?? [] + } + private resetIfNewDay(): void { const todayStart = getStartOfDay() if (todayStart > this.todayDate) { @@ -426,19 +461,13 @@ class InsightService { insightLog('INFO', `沉默阈值:${silenceDays} 天`) - const connectResult = await chatService.connect() - if (!connectResult.success) { - insightLog('WARN', '数据库连接失败,跳过沉默扫描') + // 沉默扫描间隔较长,强制刷新缓存以获取最新数据 + const sessions = await this.getSessionsCached(true) + if (sessions.length === 0) { + insightLog('WARN', '获取会话列表失败,跳过沉默扫描') return } - const sessionsResult = await chatService.getSessions() - if (!sessionsResult.success || !sessionsResult.sessions) { - insightLog('WARN', '获取会话列表失败') - return - } - - const sessions: ChatSession[] = sessionsResult.sessions insightLog('INFO', `共 ${sessions.length} 个会话,开始过滤...`) let silentCount = 0 @@ -489,19 +518,13 @@ class InsightService { this.processing = true insightLog('INFO', 'DB 变更防抖触发,开始活跃分析...') try { - const connectResult = await chatService.connect() - if (!connectResult.success) { - insightLog('WARN', '数据库连接失败,跳过活跃分析') + // 使用缓存版本,避免每次 DB 变更都做全量读取(5 分钟 TTL) + const sessions = await this.getSessionsCached() + if (sessions.length === 0) { + insightLog('WARN', '会话缓存为空,跳过活跃分析') return } - const sessionsResult = await chatService.getSessions() - if (!sessionsResult.success || !sessionsResult.sessions) { - insightLog('WARN', '获取会话列表失败') - return - } - - const sessions: ChatSession[] = sessionsResult.sessions const now = Date.now() // 从 config 读取冷却分钟数(0 = 无冷却) diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 2bacd86..2f89347 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -864,16 +864,19 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) { } useEffect(() => { - if (activeTab !== 'antiRevoke') return + if (activeTab !== 'antiRevoke' && activeTab !== 'insight') return let canceled = false ;(async () => { try { + // 两个 Tab 都需要会话列表;antiRevoke 还需要额外检查防撤回状态 const sessionIds = await ensureAntiRevokeSessionsLoaded() if (canceled) return - await handleRefreshAntiRevokeStatus(sessionIds) + if (activeTab === 'antiRevoke') { + await handleRefreshAntiRevokeStatus(sessionIds) + } } catch (e: any) { if (!canceled) { - showMessage(`加载防撤回会话失败: ${e?.message || String(e)}`, false) + showMessage(`加载会话失败: ${e?.message || String(e)}`, false) } } })() @@ -1215,7 +1218,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) { if (result.success && result.aesKey) { if (typeof result.xorKey === 'number') setImageXorKey(`0x${result.xorKey.toString(16).toUpperCase().padStart(2, '0')}`) setImageAesKey(result.aesKey) - setImageKeyStatus('已获取图片密钥') + setImageKeyStatus('已获取图片��钥') showMessage('已自动获取图片密钥', true) const newXorKey = typeof result.xorKey === 'number' ? result.xorKey : 0 const newAesKey = result.aesKey @@ -3551,7 +3554,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
当前版本

{appVersion || '...'}

-

{updateInfo?.hasUpdate ? `发现新版本 v${updateInfo.version}` : '当前已是最新版本,可手动检查更新'}

+

{updateInfo?.hasUpdate ? `发现新版本 v${updateInfo.version}` : '当前已是最新版本,可手动检查更���'}

{updateInfo?.hasUpdate ? (