diff --git a/electron/main.ts b/electron/main.ts index a04dc4c..9747a28 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -13,7 +13,7 @@ import { imagePreloadService } from './services/imagePreloadService' import { analyticsService } from './services/analyticsService' import { groupAnalyticsService } from './services/groupAnalyticsService' import { annualReportService } from './services/annualReportService' -import { exportService, ExportOptions } from './services/exportService' +import { exportService, ExportOptions, ExportProgress } from './services/exportService' import { KeyService } from './services/keyService' import { voiceTranscribeService } from './services/voiceTranscribeService' import { videoService } from './services/videoService' @@ -646,8 +646,13 @@ function registerIpcHandlers() { }) // 导出相关 - ipcMain.handle('export:exportSessions', async (_, sessionIds: string[], outputDir: string, options: ExportOptions) => { - return exportService.exportSessions(sessionIds, outputDir, options) + ipcMain.handle('export:exportSessions', async (event, sessionIds: string[], outputDir: string, options: ExportOptions) => { + const onProgress = (progress: ExportProgress) => { + if (!event.sender.isDestroyed()) { + event.sender.send('export:progress', progress) + } + } + return exportService.exportSessions(sessionIds, outputDir, options, onProgress) }) ipcMain.handle('export:exportSession', async (_, sessionId: string, outputPath: string, options: ExportOptions) => { diff --git a/electron/preload.ts b/electron/preload.ts index f04e6f4..e70b70b 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -191,7 +191,11 @@ contextBridge.exposeInMainWorld('electronAPI', { exportSessions: (sessionIds: string[], outputDir: string, options: any) => ipcRenderer.invoke('export:exportSessions', sessionIds, outputDir, options), exportSession: (sessionId: string, outputPath: string, options: any) => - ipcRenderer.invoke('export:exportSession', sessionId, outputPath, options) + ipcRenderer.invoke('export:exportSession', sessionId, outputPath, options), + onProgress: (callback: (payload: { current: number; total: number; currentSession: string; phase: string }) => void) => { + ipcRenderer.on('export:progress', (_, payload) => callback(payload)) + return () => ipcRenderer.removeAllListeners('export:progress') + } }, whisper: { diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx index 19d8605..ef0e68e 100644 --- a/src/pages/ExportPage.tsx +++ b/src/pages/ExportPage.tsx @@ -154,6 +154,19 @@ function ExportPage() { loadExportDefaults() }, [loadSessions, loadExportPath, loadExportDefaults]) + useEffect(() => { + const removeListener = window.electronAPI.export.onProgress?.((payload) => { + setExportProgress({ + current: payload.current, + total: payload.total, + currentName: payload.currentSession + }) + }) + return () => { + removeListener?.() + } + }, []) + useEffect(() => { if (!searchKeyword.trim()) { setFilteredSessions(sessions) diff --git a/src/types/electron.d.ts b/src/types/electron.d.ts index bacefb3..45d134d 100644 --- a/src/types/electron.d.ts +++ b/src/types/electron.d.ts @@ -314,6 +314,7 @@ export interface ElectronAPI { success: boolean error?: string }> + onProgress: (callback: (payload: ExportProgress) => void) => () => void } whisper: { downloadModel: () => Promise<{ success: boolean; modelPath?: string; tokensPath?: string; error?: string }> @@ -334,6 +335,13 @@ export interface ExportOptions { excelCompactColumns?: boolean } +export interface ExportProgress { + current: number + total: number + currentSession: string + phase: 'preparing' | 'exporting' | 'writing' | 'complete' +} + export interface WxidInfo { wxid: string modifiedTime: number