import type { OpenDialogOptions, Event } from 'electron' import { dialog, ipcMain, shell, app } from 'electron' import * as fs from 'fs-extra' import * as path from 'path' /** 当前项目文件夹锁:持有一个项目内文件的句柄,防止用户删除项目文件夹 */ let projectLockFd: number | null = null /** * 选择文件夹 */ export const choeseDirectory = async () => { const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openDirectory'] }) if (!canceled) { return filePaths[0] } return } /** * 选择文件 */ export const choeseFile = async (_e: Event, options: OpenDialogOptions = {}) => { const { canceled, filePaths } = await dialog.showOpenDialog({ title: '选择文件', buttonLabel: '选择', ...options }) if (!canceled) { return filePaths } return } /** * 保存文件 */ export const writeFile = async (_e: Event, filePath: string, content: string) => { return fs.writeFileSync(filePath, content) } /** * 读取文件 */ export const readFile = async (_e: Event, filePath: string, encoding: BufferEncoding) => { return fs.readFileSync(filePath, { encoding }) } /** * 检查文件是否存在 */ export const checkFileExists = async (_e: Event, filePath: string) => { return fs.existsSync(filePath) } /** * 创建目录 */ export const createDirectory = async (_e: Event, directoryPath: string) => { return fs.mkdirSync(directoryPath, { recursive: true }) } /** * 复制文件 */ export const copyFile = async (_e: Event, sourcePath: string, destinationPath: string) => { return fs.copyFileSync(sourcePath, destinationPath) } /** * 打开文件夹 */ export const openDir = async ( _e: Event, directoryPath: string, cb: (err: NodeJS.ErrnoException | null, dir: fs.Dir) => void ) => { return fs.opendir(directoryPath, cb) } /** * 复制文件夹 */ export const cp = (_e: Event, sourcePath: string, destinationPath: string) => { return fs.cpSync(sourcePath, destinationPath) } /** * 删除文件 */ export const removeFile = (_e: Event, sourcePath: string) => { return fs.rmSync(sourcePath) } /** * 打开并锁定文件 */ export const openFile = (_e: Event, sourcePath: string, flag: string) => { return fs.openSync(sourcePath, flag || 'w') } /** * 关闭并解锁文件 */ export const closeFile = (_e: Event, fd: number) => { return fs.closeSync(fd) } /** * 修改文件名 */ export const renameFile = (_e: Event, sourcePath: string, targetPath: string) => { return fs.renameSync(sourcePath, targetPath) } /** * 资源管理器中打开 * @param path 文件路径 */ export const openFileInExplorer = (_e: Event, path: string) => { return shell.showItemInFolder(path) } /** * 锁定项目文件夹:打开项目目录内的 project.ui 并保持句柄,防止用户在资源管理器中删除该文件夹 * @param projectDir 项目根目录路径(如 D:\projects\myProject) */ const lockProjectFolder = async (_e: Event, projectDir: string) => { if (projectLockFd !== null) { try { fs.closeSync(projectLockFd) } catch (_) {} projectLockFd = null } const lockFilePath = path.join(projectDir, 'project.ui') if (!fs.existsSync(lockFilePath)) return try { projectLockFd = fs.openSync(lockFilePath, 'r') } catch (_) {} } /** * 解锁项目文件夹:关闭句柄,允许用户删除项目文件夹 */ export const unlockProjectFolder = () => { if (projectLockFd !== null) { try { fs.closeSync(projectLockFd) } catch (_) {} projectLockFd = null } } export const copyTemplate = async (_e: Event, targetPath: string) => { const templatePaths = app.isPackaged ? [ path.join(process.resourcesPath, 'template/src'), path.join(process.resourcesPath, 'app.asar.unpacked/resources/template/src') ] : [path.join(process.cwd(), 'resources/template/src')] const templatePath = templatePaths.find((item) => fs.existsSync(item)) await fs.ensureDir(targetPath) if (templatePath) { await fs.copy(templatePath, targetPath) } await fs.ensureDir(path.join(targetPath, 'assets/images')) await fs.ensureDir(path.join(targetPath, 'assets/fonts')) await fs.ensureDir(path.join(targetPath, 'assets/others')) // .gitkeep占位文件 创建后移除 await fs.remove(path.join(targetPath, 'assets/images/.gitkeep')) await fs.remove(path.join(targetPath, 'assets/others/.gitkeep')) } export function handleFile() { // 获取文件夹 ipcMain.handle('get-directory', choeseDirectory) // 获取文件 ipcMain.handle('get-file', choeseFile) // 创建文件夹 ipcMain.handle('create-directory', createDirectory) // 复制文件夹 ipcMain.handle('copy-directory', cp) // 写入文件 ipcMain.handle('write-file', writeFile) // 读取文件 ipcMain.handle('read-file', readFile) // 检查路径是否存在 ipcMain.handle('check-file-path', checkFileExists) // 复制文件 ipcMain.handle('copy-file', copyFile) // 删除文件 ipcMain.handle('delete-file', removeFile) // 独占打开 ipcMain.handle('exclusive-open', openFile) // 独占关闭 ipcMain.handle('exclusive-close', closeFile) // 修改文件名 ipcMain.handle('modify-file-name', renameFile) // 资源管理器中打开 ipcMain.handle('open-file-in-explorer', openFileInExplorer) // 锁定/解锁项目文件夹(防止用户删除正在使用的项目目录) ipcMain.handle('lock-project-folder', lockProjectFolder) // 解锁项目文件夹 ipcMain.handle('unlock-project-folder', unlockProjectFolder) // 复制模板文件 ipcMain.handle('copy-template', copyTemplate) }