import { dialog, nativeTheme, shell } from 'electron' import { CheckFileOrDirExist, CopyFileOrFolder } from '../../../define/Tools/file' import path from 'path' import fs from 'fs/promises' import { errorMessage, successMessage } from '../../../public/generalTools' import { ErrorItem, SuccessItem } from '@/define/model/generalResponse' import { t } from '@/i18n' /** 打开指定的文件夹的方法 */ export type OpenFolderParams = { /** 是不是基于项目文件,是的话,会在项目文件夹的基础上进行拼接 */ baseProject: boolean /** 判断是不是打开父文件夹 */ dirFolder: boolean /** 文件路径,baseProject 为false,需要设置完整的文件路径 */ folderPath: string } /** 一些对electron接口的封装,配合业务逻辑 */ export default class ElectronInterface { constructor() { } /** * 打开指定的文件,试用默认的打开方式 * @param value * @returns */ public async OpenFile(value: string): Promise { if (!(await CheckFileOrDirExist(value))) { return errorMessage(t("目的文件/文件夹不存在,{data}", { data: value }), 'SystemIpc_OPEN_FILE') } await shell.openPath(value) return successMessage(null, t("打开文件/文件夹成功", { data: value }), 'SystemIpc_OPEN_FILE') } /** * 深度复制文件夹内容到目标文件夹 * @param source 源文件夹路径 * @param destination 目标文件夹路径 * @returns */ public async CopyFolderContents( source: string, destination: string ): Promise { try { // 使用更完善的复制方法 await CopyFileOrFolder(source, destination, false) return successMessage(null, t('复制文件夹成功'), 'SystemIpc_COPY_FOLDER_CONTENTS') } catch (error: any) { return errorMessage( t("复制文件夹失败,{error}", { error: error.message }), 'SystemIpc_COPY_FOLDER_CONTENTS' ) } } /** * 打开对应的文件夹 * @param params * @returns */ public async OpenFolder(params: OpenFolderParams) { try { let openFolder = '' if (params.baseProject) { openFolder = path.join(global.config.project_path, params.folderPath) } if (params.dirFolder) { openFolder = path.dirname(params.folderPath) } if (!openFolder) { openFolder = params.folderPath } // 判断文件夹是不是存在 let isExist = await CheckFileOrDirExist(openFolder) if (!isExist) { throw new Error(t("目的文件/文件夹不存在,{data}", { data: openFolder })) } shell.openPath(openFolder) return successMessage(null, t('打开文件/文件夹成功')) } catch (error: any) { return errorMessage(t("打卡开文件/文件夹失败,{error}", { error: error.message }), 'SystemIpc_OPEN_FOLDER') } } /** * 选择单个指定文件后缀的文件 * @param value 后缀列表 */ public async SelectSingleFile(value: string[]): Promise { try { let { filePaths } = await dialog.showOpenDialog({ properties: ['openFile'], filters: [{ name: 'fileName', extensions: value }] }) if (filePaths.length === 0) { throw new Error(t('没有选择的文件或文件夹')) } return successMessage(filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectSingleFile') } catch (error: any) { return errorMessage( t("选择文件/文件夹失败,{error}", { error: error.message }), 'SystemIpc_SelectSingleFile' ) } } /** * 选择多个指定文件后缀的文件 * @param value 文件后缀列表 * @returns */ public async SelectMultipleFile(value: string[]): Promise { try { const { filePaths } = await dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'], filters: [{ name: 'fileName', extensions: value }] }) if (filePaths.length === 0) { throw new Error(t('没有选择的文件或文件夹')) } return successMessage(filePaths, t("选择文件/文件夹成功"), 'SystemIpc_SelectMultipleFile') } catch (error: any) { console.error('选择文件错误:', error) // 记录错误日志 return errorMessage( t("选择文件/文件夹失败,{error}", { error: error.message }), 'SystemIpc_SelectMultipleFile' ) } } /** * 切换主题 * @param theme 主题名称 * @returns 返回当前是否使用深色模式 */ public async ToggleTheme(theme: string) { if (theme != 'light' && theme != 'dark') { nativeTheme.themeSource = 'system' } else { nativeTheme.themeSource = theme } return nativeTheme.shouldUseDarkColors } /** * 选择单个文件夹 * @param defaultPath 可选配置 * @returns 成功返回选择的文件夹路径,失败返回错误信息 */ public async SelectSingleFolder(defaultPath: string): Promise { try { const { filePaths } = await dialog.showOpenDialog({ properties: ['openDirectory'], defaultPath: defaultPath, title: t('选择文件夹'), buttonLabel: t('选择文件夹') }) if (filePaths.length === 0) { throw new Error(t('没有选择的文件或文件夹')) } return successMessage(filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectSingleFolder') } catch (error: any) { return errorMessage( t("选择文件/文件夹失败,{error}", { error: error.message }), 'SystemIpc_SelectSingleFolder' ) } } /** * 选择文件夹或指定后缀的文件 * @param extensions 文件后缀列表(可选) * @returns */ public async SelectFolderOrFile(extensions?: string[]): Promise { try { // 使用消息框让用户选择类型 const choice = await dialog.showMessageBox({ type: 'question', title: t('选择类型'), message: t('请选择要选择的类型:'), buttons: [t('选择文件'), t('选择文件夹'), t('取消')], defaultId: 0, cancelId: 2 }) if (choice.response === 2) { throw new Error(t("取消操作")) } if (choice.response === 0) { // 选择文件 const result = await dialog.showOpenDialog({ properties: ['openFile'], filters: extensions && extensions.length > 0 ? [ { name: 'Audio Files', extensions }, { name: 'All Files', extensions: ['*'] } ] : [{ name: 'All Files', extensions: ['*'] }], title: t('选择文件') }) if (result.filePaths.length === 0) { throw new Error(t('没有选择的文件或文件夹')) } return successMessage(result.filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectFolderOrFile') } else { // 选择文件夹 const result = await dialog.showOpenDialog({ properties: ['openDirectory'], title: t('选择文件夹') }) if (result.filePaths.length === 0) { throw new Error(t('没有选择的文件或文件夹')) } return successMessage(result.filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectFolderOrFile') } } catch (error: any) { console.error('选择文件或文件夹错误:', error) return errorMessage( t("选择文件/文件夹失败,{error}", { error: error.message }), 'SystemIpc_SelectFolderOrFile' ) } } /** * 打开指定的URL * @param url */ public OpenUrl(url: string) { shell.openExternal(url) } /** * 读取文件内容(仅支持常见的文本格式) * @param filePath 文件路径 * @returns 返回文件内容或错误信息 */ public async ReadTextFile(filePath: string): Promise { try { // 定义支持的文本文件格式 const supportedExtensions = [ '.txt', '.json', '.xml', '.html', '.htm', '.css', '.js', '.ts', '.jsx', '.tsx', '.vue', '.md', '.yml', '.yaml', '.csv', '.log', '.ini', '.conf', '.config', '.py', '.java', '.c', '.cpp', '.h', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.scala', '.sql', '.sh', '.bat', '.ps1', '.dockerfile', '.gitignore', '.env' ] // 检查文件是否存在 if (!(await CheckFileOrDirExist(filePath))) { throw new Error(t('文件不存在')) } // 获取文件扩展名 const ext = path.extname(filePath).toLowerCase() // 检查文件格式是否支持 if (!supportedExtensions.includes(ext)) { throw new Error(t("不支持的文件格式: {ext}。支持的格式: {supportedExt}", { ext: ext, supportedExt: supportedExtensions.join(', ') })) } // 读取文件内容 const content = await fs.readFile(filePath, 'utf-8') return successMessage( { content: content, filePath: filePath, size: Buffer.byteLength(content, 'utf-8'), extension: ext }, t('读取文件成功!'), 'SystemIpc_ReadTextFile' ) } catch (error: any) { console.error('读取文件错误:', error) return errorMessage( t("读取文件失败,{error}", { error: error.message }), 'SystemIpc_ReadTextFile' ) } } }