diff --git a/src/main/presenter/syncPresenter/index.ts b/src/main/presenter/syncPresenter/index.ts index f4422b573..208fd9826 100644 --- a/src/main/presenter/syncPresenter/index.ts +++ b/src/main/presenter/syncPresenter/index.ts @@ -1,6 +1,7 @@ import { app, shell } from 'electron' import path from 'path' import fs from 'fs' +import Database from 'better-sqlite3-multiple-ciphers' import { ISyncPresenter, IConfigPresenter, ISQLitePresenter } from '@shared/presenter' import { eventBus, SendTarget } from '@/eventbus' import { SYNC_EVENTS } from '@/events' @@ -121,7 +122,13 @@ export class SyncPresenter implements ISyncPresenter { */ public async importFromSync( importMode: ImportMode = ImportMode.INCREMENT - ): Promise<{ success: boolean; message: string }> { + ): Promise<{ success: boolean; message: string; count?: number }> { + // Cancel any pending backup to prevent overwriting the backup files during import + if (this.backupTimer) { + clearTimeout(this.backupTimer) + this.backupTimer = null + } + // 检查同步文件夹是否存在 const { exists, path: syncFolderPath } = await this.checkSyncFolder() if (!exists) { @@ -174,13 +181,22 @@ export class SyncPresenter implements ISyncPresenter { this.copyDirectory(this.PROVIDER_MODELS_DIR_PATH, tempProviderModelsPath) } + let importedCount = 0 try { if (importMode === ImportMode.OVERWRITE) { + // For overwrite mode, count conversations from backup db in read-only mode + const backupDb = new Database(dbBackupPath, { readonly: true }) + const result = backupDb.prepare('SELECT COUNT(*) as count FROM conversations').get() as { + count: number + } + importedCount = result.count + backupDb.close() + fs.copyFileSync(dbBackupPath, this.DB_PATH) } else { - // 使用 DataImporter 导入数据 + // For incremental mode, DataImporter returns the actual imported count const importer = new DataImporter(dbBackupPath, this.DB_PATH) - const importedCount = await importer.importData() + importedCount = await importer.importData() console.log(`成功导入 ${importedCount} 个会话`) importer.close() } @@ -229,7 +245,7 @@ export class SyncPresenter implements ISyncPresenter { } eventBus.send(SYNC_EVENTS.IMPORT_COMPLETED, SendTarget.ALL_WINDOWS) - return { success: true, message: 'sync.success.importComplete' } + return { success: true, message: 'sync.success.importComplete', count: importedCount } } catch (error: unknown) { console.error('导入文件失败,恢复备份:', error) diff --git a/src/renderer/settings/components/DataSettings.vue b/src/renderer/settings/components/DataSettings.vue index 97a7ea242..d5bd883e1 100644 --- a/src/renderer/settings/components/DataSettings.vue +++ b/src/renderer/settings/components/DataSettings.vue @@ -67,12 +67,7 @@ - @@ -219,7 +214,11 @@ : t('settings.data.importErrorTitle') }} - {{ syncStore.importResult?.message ? t(syncStore.importResult.message) : '' }} + {{ + syncStore.importResult?.message + ? t(syncStore.importResult.message, { count: syncStore.importResult.count || 0 }) + : '' + }} diff --git a/src/renderer/src/i18n/en-US/sync.json b/src/renderer/src/i18n/en-US/sync.json index af5f8bccc..07295cc5c 100644 --- a/src/renderer/src/i18n/en-US/sync.json +++ b/src/renderer/src/i18n/en-US/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "Import complete. The application will now restart." + "importComplete": "Successfully imported {count} conversation(s). The application will now restart." }, "error": { "notEnabled": "Sync is not enabled", diff --git a/src/renderer/src/i18n/fa-IR/sync.json b/src/renderer/src/i18n/fa-IR/sync.json index b70504028..5902773be 100644 --- a/src/renderer/src/i18n/fa-IR/sync.json +++ b/src/renderer/src/i18n/fa-IR/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "داده با موفقیت وارد شد. برای راه‌اندازی دوباره برنامه، روی دکمه خوب بزنید." + "importComplete": "{count} مکالمه با موفقیت وارد شد. برای راه‌اندازی دوباره برنامه، روی دکمه خوب بزنید." }, "error": { "notEnabled": "ویژگی همگام‌سازی روشن نیست", diff --git a/src/renderer/src/i18n/fr-FR/sync.json b/src/renderer/src/i18n/fr-FR/sync.json index 6e3872241..07b5fa03d 100644 --- a/src/renderer/src/i18n/fr-FR/sync.json +++ b/src/renderer/src/i18n/fr-FR/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "Données importées avec succès. Cliquez sur OK pour redémarrer l'application." + "importComplete": "{count} conversation(s) importée(s) avec succès. Cliquez sur OK pour redémarrer l'application." }, "error": { "notEnabled": "La fonction de synchronisation n'est pas activée", diff --git a/src/renderer/src/i18n/ja-JP/sync.json b/src/renderer/src/i18n/ja-JP/sync.json index e65c46123..dd278b1e3 100644 --- a/src/renderer/src/i18n/ja-JP/sync.json +++ b/src/renderer/src/i18n/ja-JP/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "データのインポートが完了しました。OKをクリックして、アプリケーションを再起動します。" + "importComplete": "{count}件の会話をインポートしました。OKをクリックして、アプリケーションを再起動します。" }, "error": { "notEnabled": "同期機能が有効になっていません", diff --git a/src/renderer/src/i18n/ko-KR/sync.json b/src/renderer/src/i18n/ko-KR/sync.json index 9ae57fd34..366d84a95 100644 --- a/src/renderer/src/i18n/ko-KR/sync.json +++ b/src/renderer/src/i18n/ko-KR/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "데이터가 성공적으로 가져와졌습니다. 애플리케이션을 다시 시작하려면 확인을 클릭하세요." + "importComplete": "{count}개의 대화를 성공적으로 가져왔습니다. 애플리케이션을 다시 시작하려면 확인을 클릭하세요." }, "error": { "notEnabled": "동기화 기능이 활성화되지 않았습니다", diff --git a/src/renderer/src/i18n/pt-BR/sync.json b/src/renderer/src/i18n/pt-BR/sync.json index 5699995d8..50f01e576 100644 --- a/src/renderer/src/i18n/pt-BR/sync.json +++ b/src/renderer/src/i18n/pt-BR/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "Importação concluída. O aplicativo será reiniciado agora." + "importComplete": "{count} conversa(s) importada(s) com sucesso. O aplicativo será reiniciado agora." }, "error": { "notEnabled": "A sincronização não está ativada", diff --git a/src/renderer/src/i18n/ru-RU/sync.json b/src/renderer/src/i18n/ru-RU/sync.json index 10630ebaa..b5e006a53 100644 --- a/src/renderer/src/i18n/ru-RU/sync.json +++ b/src/renderer/src/i18n/ru-RU/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "Данные успешно импортированы. Нажмите OK для перезапуска приложения." + "importComplete": "Успешно импортировано {count} диалогов. Нажмите OK для перезапуска приложения." }, "error": { "notEnabled": "Функция синхронизации не включена", diff --git a/src/renderer/src/i18n/zh-CN/sync.json b/src/renderer/src/i18n/zh-CN/sync.json index 3b6142d49..a015922b0 100644 --- a/src/renderer/src/i18n/zh-CN/sync.json +++ b/src/renderer/src/i18n/zh-CN/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "数据导入成功,点击确定后将重启应用" + "importComplete": "成功导入 {count} 个对话,点击确定后将重启应用" }, "error": { "notEnabled": "同步功能未启用", diff --git a/src/renderer/src/i18n/zh-HK/sync.json b/src/renderer/src/i18n/zh-HK/sync.json index b97f96406..9b9ec1906 100644 --- a/src/renderer/src/i18n/zh-HK/sync.json +++ b/src/renderer/src/i18n/zh-HK/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "數據導入成功,點擊確定後將重新啟動應用" + "importComplete": "成功導入 {count} 個對話,點擊確定後將重新啟動應用" }, "error": { "notEnabled": "同步功能未啟用", diff --git a/src/renderer/src/i18n/zh-TW/sync.json b/src/renderer/src/i18n/zh-TW/sync.json index 5046efafa..89f0d4ee9 100644 --- a/src/renderer/src/i18n/zh-TW/sync.json +++ b/src/renderer/src/i18n/zh-TW/sync.json @@ -1,6 +1,6 @@ { "success": { - "importComplete": "資料匯入成功,點選「確定」後將重新啟動應用程式" + "importComplete": "成功匯入 {count} 個對話,點選「確定」後將重新啟動應用程式" }, "error": { "notEnabled": "同步功能未啟用", diff --git a/src/renderer/src/stores/sync.ts b/src/renderer/src/stores/sync.ts index c99164456..f6be79f21 100644 --- a/src/renderer/src/stores/sync.ts +++ b/src/renderer/src/stores/sync.ts @@ -10,7 +10,7 @@ export const useSyncStore = defineStore('sync', () => { const lastSyncTime = ref(0) const isBackingUp = ref(false) const isImporting = ref(false) - const importResult = ref<{ success: boolean; message: string } | null>(null) + const importResult = ref<{ success: boolean; message: string; count?: number } | null>(null) // 获取 presenter 实例 const configPresenter = usePresenter('configPresenter') diff --git a/src/shared/types/presenters/legacy.presenters.d.ts b/src/shared/types/presenters/legacy.presenters.d.ts index 7d787fa6a..b18ef014a 100644 --- a/src/shared/types/presenters/legacy.presenters.d.ts +++ b/src/shared/types/presenters/legacy.presenters.d.ts @@ -1339,7 +1339,9 @@ export interface ISyncPresenter { getBackupStatus(): Promise<{ isBackingUp: boolean; lastBackupTime: number }> // Import related operations - importFromSync(importMode?: ImportMode): Promise<{ success: boolean; message: string }> + importFromSync( + importMode?: ImportMode + ): Promise<{ success: boolean; message: string; count?: number }> checkSyncFolder(): Promise<{ exists: boolean; path: string }> openSyncFolder(): Promise