diff --git a/src/main/api/renderer/localShortcuts.ts b/src/main/api/renderer/localShortcuts.ts index 1c5166b9..910a165d 100644 --- a/src/main/api/renderer/localShortcuts.ts +++ b/src/main/api/renderer/localShortcuts.ts @@ -1,8 +1,9 @@ -import { app, dialog, ipcMain, shell } from 'electron' +import { app, ipcMain, shell } from 'electron' import { promises as fs } from 'fs' import path from 'path' import { pinyin as getPinyin } from 'pinyin-pro' import databaseAPI from '../shared/database' +import { openDialog } from '../../utils/windowUtils' /** * 本地启动项类型 @@ -82,18 +83,19 @@ export class LocalShortcutsAPI { } else { properties = ['openFile'] } - // 打开文件选择对话框 - const result = await dialog.showOpenDialog(this.mainWindow, { - title: type === 'folder' ? '选择文件夹' : '选择文件或应用', - properties - }) - - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '用户取消选择' } + const result = await openDialog( + this.mainWindow, + { + title: type === 'folder' ? '选择文件夹' : '选择文件或应用', + properties + }, + '用户取消选择' + ) + if (!result.success) { + return result } - - const selectedPath = result.filePaths[0] + const selectedPath = result.data!.filePaths[0] // 获取文件信息 const stats = await fs.stat(selectedPath) diff --git a/src/main/api/renderer/pluginDevProjects.ts b/src/main/api/renderer/pluginDevProjects.ts index ac55c422..97812965 100644 --- a/src/main/api/renderer/pluginDevProjects.ts +++ b/src/main/api/renderer/pluginDevProjects.ts @@ -20,6 +20,7 @@ import { type DevProjectRegistry, type DevProjectRecord } from './pluginDevelopmentRegistry' +import { openDialog } from '../../utils/windowUtils' // ============================================================ // Dependencies Interface @@ -349,16 +350,20 @@ export class PluginDevProjectsAPI { public async importDevPlugin(pluginJsonPath?: string): Promise { try { if (!pluginJsonPath) { - const result = await dialog.showOpenDialog(this.deps.mainWindow!, { - title: '选择插件配置文件', - properties: ['openFile'], - filters: [{ name: '插件配置', extensions: ['json'] }], - message: '请选择 plugin.json 文件' - }) - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '未选择文件' } + const result = await openDialog( + this.deps.mainWindow!, + { + title: '选择插件配置文件', + properties: ['openFile'], + filters: [{ name: '插件配置', extensions: ['json'] }], + message: '请选择 plugin.json 文件' + }, + '未选择文件' + ) + if (!result.success) { + return result } - pluginJsonPath = result.filePaths[0] + pluginJsonPath = result.data!.filePaths[0] } if (path.basename(pluginJsonPath) !== 'plugin.json') { @@ -639,16 +644,20 @@ export class PluginDevProjectsAPI { let configPath = providedConfigPath ? path.resolve(providedConfigPath) : '' if (!configPath) { - const result = await dialog.showOpenDialog(this.deps.mainWindow!, { - title: '选择 plugin.json', - properties: ['openFile'], - filters: [{ name: '插件配置', extensions: ['json'] }], - message: `为 ${projectName} 选择 plugin.json` - }) - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '未选择文件' } + const result = await openDialog( + this.deps.mainWindow!, + { + title: '选择 plugin.json', + properties: ['openFile'], + filters: [{ name: '插件配置', extensions: ['json'] }], + message: `为 ${projectName} 选择 plugin.json` + }, + '未选择文件' + ) + if (!result.success) { + return result } - configPath = path.resolve(result.filePaths[0]) + configPath = path.resolve(result.data!.filePaths[0]) } if (path.basename(configPath) !== 'plugin.json') { diff --git a/src/main/api/renderer/pluginInstaller.ts b/src/main/api/renderer/pluginInstaller.ts index 2a215b6c..79d6228e 100644 --- a/src/main/api/renderer/pluginInstaller.ts +++ b/src/main/api/renderer/pluginInstaller.ts @@ -1,6 +1,6 @@ import type { PluginManager } from '../../managers/pluginManager' import type { PluginDevProjectsAPI } from './pluginDevProjects' -import { app, dialog, shell } from 'electron' +import { app, shell } from 'electron' import { promises as fs } from 'fs' import path from 'path' import { pathToFileURL } from 'url' @@ -11,6 +11,7 @@ import { downloadFile } from '../../utils/download.js' import { httpGet } from '../../utils/httpRequest.js' import { sleep } from '../../utils/common.js' import databaseAPI from '../shared/database' +import { openDialog } from '../../utils/windowUtils' /** 插件的本地安装目录 */ const PLUGIN_DIR = path.join(app.getPath('userData'), 'plugins') @@ -57,17 +58,21 @@ export class PluginInstallerAPI { */ public async selectPluginFile(): Promise { try { - const result = await dialog.showOpenDialog(this.deps.mainWindow!, { - title: '选择插件文件', - filters: [{ name: '插件文件', extensions: ['zpx', 'zip'] }], - properties: ['openFile'] - }) + const result = await openDialog( + this.deps.mainWindow!, + { + title: '选择插件文件', + filters: [{ name: '插件文件', extensions: ['zpx', 'zip'] }], + properties: ['openFile'] + }, + '未选择文件' + ) - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '未选择文件' } + if (!result.success) { + return result } - return { success: true, filePath: result.filePaths[0] } + return { success: true, filePath: result.data!.filePaths[0] } } catch (error: unknown) { console.error('[Plugins] 选择插件文件失败:', error) return { success: false, error: error instanceof Error ? error.message : '未知错误' } @@ -81,17 +86,21 @@ export class PluginInstallerAPI { */ public async importPlugin(): Promise { try { - const result = await dialog.showOpenDialog(this.deps.mainWindow!, { - title: '选择插件文件', - filters: [{ name: '插件文件', extensions: ['zpx', 'zip'] }], - properties: ['openFile'] - }) + const result = await openDialog( + this.deps.mainWindow!, + { + title: '选择插件文件', + filters: [{ name: '插件文件', extensions: ['zpx', 'zip'] }], + properties: ['openFile'] + }, + '未选择文件' + ) - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '未选择文件' } + if (!result.success) { + return result } - return await this.installPluginFromPath(result.filePaths[0]) + return await this.installPluginFromPath(result.data!.filePaths[0]) } catch (error: unknown) { console.error('[Plugins] 导入插件失败:', error) return { success: false, error: error instanceof Error ? error.message : '未知错误' } diff --git a/src/main/api/renderer/system.ts b/src/main/api/renderer/system.ts index c623ebcb..90a93836 100644 --- a/src/main/api/renderer/system.ts +++ b/src/main/api/renderer/system.ts @@ -1,10 +1,10 @@ -import { app, clipboard, dialog, ipcMain, Menu, shell } from 'electron' +import { app, clipboard, ipcMain, Menu, shell } from 'electron' import { promises as fs } from 'fs' import path from 'path' import { pathToFileURL } from 'url' import clipboardManager from '../../managers/clipboardManager' import appleScriptHelper from '../../utils/appleScriptHelper' -import { isWindows11 } from '../../utils/windowUtils' +import { isWindows11, openDialog } from '../../utils/windowUtils' // 头像目录 const AVATAR_DIR = path.join(app.getPath('userData'), 'avatar') @@ -212,17 +212,19 @@ export class SystemAPI { public async selectAvatar(): Promise { try { - const result = await dialog.showOpenDialog(this.mainWindow!, { - title: '选择头像图片', - filters: [{ name: '图片文件', extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'] }], - properties: ['openFile'] - }) - - if (result.canceled || result.filePaths.length === 0) { - return { success: false, error: '未选择文件' } + const result = await openDialog( + this.mainWindow!, + { + title: '选择头像图片', + filters: [{ name: '图片文件', extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'] }], + properties: ['openFile'] + }, + '未选择文件' + ) + if (!result.success) { + return result } - - const originalPath = result.filePaths[0] + const originalPath = result.data!.filePaths[0] const ext = path.extname(originalPath) const fileName = `avatar${ext}` diff --git a/src/main/utils/windowUtils.ts b/src/main/utils/windowUtils.ts index 024052c2..7eedb434 100644 --- a/src/main/utils/windowUtils.ts +++ b/src/main/utils/windowUtils.ts @@ -1,4 +1,10 @@ -import { BrowserWindow } from 'electron' +import { + BaseWindow, + OpenDialogOptions, + OpenDialogReturnValue, + BrowserWindow, + dialog +} from 'electron' import os from 'os' /** @@ -84,3 +90,29 @@ export function applyWindowMaterial( break } } +/** + * 打开文件选择窗口 + * + * @param parentWindow 父窗口 + * @param options 文件窗口选项 + * @param errorMessage 未选择任何文件时,返回错误信息 + */ +export async function openDialog( + parentWindow: BrowserWindow, + options: OpenDialogOptions, + errorMessage: string +): Promise<{ + success: boolean + data?: OpenDialogReturnValue + error?: string +}> { + const result = await dialog.showOpenDialog(parentWindow, options) + if (!parentWindow.isDestroyed()) { + parentWindow.show() + } + if (result.canceled || result.filePaths.length === 0) { + return { success: false, error: errorMessage } + } + return { success: true, data: result } +} +}