LaiTool_PRO/src/main/service/system/electronInterface.ts

322 lines
9.7 KiB
TypeScript
Raw Normal View History

2025-08-19 14:33:59 +08:00
import { dialog, nativeTheme, shell } from 'electron'
import { CheckFileOrDirExist, CopyFileOrFolder } from '../../../define/Tools/file'
import path from 'path'
import fs from 'fs/promises'
2025-08-19 14:33:59 +08:00
import { errorMessage, successMessage } from '../../../public/generalTools'
import { ErrorItem, SuccessItem } from '@/define/model/generalResponse'
import { t } from '@/i18n'
2025-08-19 14:33:59 +08:00
/** 打开指定的文件夹的方法 */
export type OpenFolderParams = {
/** 是不是基于项目文件,是的话,会在项目文件夹的基础上进行拼接 */
baseProject: boolean
/** 判断是不是打开父文件夹 */
dirFolder: boolean
2025-08-19 14:33:59 +08:00
/** 文件路径baseProject 为false需要设置完整的文件路径 */
folderPath: string
}
/** 一些对electron接口的封装配合业务逻辑 */
export default class ElectronInterface {
constructor() { }
2025-08-19 14:33:59 +08:00
/**
*
* @param value
* @returns
*/
public async OpenFile(value: string): Promise<ErrorItem | SuccessItem> {
if (!(await CheckFileOrDirExist(value))) {
return errorMessage(t("目的文件/文件夹不存在,{data}", {
data: value
}), 'SystemIpc_OPEN_FILE')
2025-08-19 14:33:59 +08:00
}
await shell.openPath(value)
return successMessage(null, t("打开文件/文件夹成功", {
data: value
}), 'SystemIpc_OPEN_FILE')
2025-08-19 14:33:59 +08:00
}
/**
*
* @param source
* @param destination
* @returns
*/
public async CopyFolderContents(
source: string,
destination: string
): Promise<ErrorItem | SuccessItem> {
try {
// 使用更完善的复制方法
await CopyFileOrFolder(source, destination, false)
return successMessage(null, t('复制文件夹成功'), 'SystemIpc_COPY_FOLDER_CONTENTS')
2025-08-19 14:33:59 +08:00
} catch (error: any) {
return errorMessage(
t("复制文件夹失败,{error}", {
error: error.message
}),
2025-08-19 14:33:59 +08:00
'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) {
2025-08-19 14:33:59 +08:00
openFolder = path.dirname(params.folderPath)
}
if (!openFolder) {
openFolder = params.folderPath
}
// 判断文件夹是不是存在
let isExist = await CheckFileOrDirExist(openFolder)
if (!isExist) {
throw new Error(t("目的文件/文件夹不存在,{data}", {
data: openFolder
}))
2025-08-19 14:33:59 +08:00
}
shell.openPath(openFolder)
return successMessage(null, t('打开文件/文件夹成功'))
2025-08-19 14:33:59 +08:00
} catch (error: any) {
return errorMessage(t("打卡开文件/文件夹失败,{error}", {
error: error.message
}), 'SystemIpc_OPEN_FOLDER')
2025-08-19 14:33:59 +08:00
}
}
/**
*
* @param value
*/
public async SelectSingleFile(value: string[]): Promise<SuccessItem | ErrorItem> {
try {
let { filePaths } = await dialog.showOpenDialog({
properties: ['openFile'],
filters: [{ name: 'fileName', extensions: value }]
})
if (filePaths.length === 0) {
throw new Error(t('没有选择的文件或文件夹'))
2025-08-19 14:33:59 +08:00
}
return successMessage(filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectSingleFile')
2025-08-19 14:33:59 +08:00
} catch (error: any) {
return errorMessage(
t("选择文件/文件夹失败,{error}", {
error: error.message
}),
2025-08-19 14:33:59 +08:00
'SystemIpc_SelectSingleFile'
)
}
}
/**
*
* @param value
* @returns
*/
public async SelectMultipleFile(value: string[]): Promise<SuccessItem | ErrorItem> {
try {
const { filePaths } = await dialog.showOpenDialog({
properties: ['openFile', 'multiSelections'],
filters: [{ name: 'fileName', extensions: value }]
})
if (filePaths.length === 0) {
throw new Error(t('没有选择的文件或文件夹'))
2025-08-19 14:33:59 +08:00
}
return successMessage(filePaths, t("选择文件/文件夹成功"), 'SystemIpc_SelectMultipleFile')
2025-08-19 14:33:59 +08:00
} catch (error: any) {
console.error('选择文件错误:', error) // 记录错误日志
return errorMessage(
t("选择文件/文件夹失败,{error}", {
error: error.message
}),
2025-08-19 14:33:59 +08:00
'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<SuccessItem | ErrorItem> {
try {
const { filePaths } = await dialog.showOpenDialog({
properties: ['openDirectory'],
defaultPath: defaultPath,
title: t('选择文件夹'),
buttonLabel: t('选择文件夹')
2025-08-19 14:33:59 +08:00
})
if (filePaths.length === 0) {
throw new Error(t('没有选择的文件或文件夹'))
2025-08-19 14:33:59 +08:00
}
return successMessage(filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectSingleFolder')
2025-08-19 14:33:59 +08:00
} catch (error: any) {
return errorMessage(
t("选择文件/文件夹失败,{error}", {
error: error.message
}),
2025-08-19 14:33:59 +08:00
'SystemIpc_SelectSingleFolder'
)
}
}
/**
*
* @param extensions
* @returns
*/
public async SelectFolderOrFile(extensions?: string[]): Promise<SuccessItem | ErrorItem> {
try {
// 使用消息框让用户选择类型
const choice = await dialog.showMessageBox({
type: 'question',
title: t('选择类型'),
message: t('请选择要选择的类型:'),
buttons: [t('选择文件'), t('选择文件夹'), t('取消')],
2025-08-19 14:33:59 +08:00
defaultId: 0,
cancelId: 2
})
if (choice.response === 2) {
throw new Error(t("取消操作"))
2025-08-19 14:33:59 +08:00
}
if (choice.response === 0) {
// 选择文件
const result = await dialog.showOpenDialog({
properties: ['openFile'],
filters:
extensions && extensions.length > 0
? [
{ name: 'Audio Files', extensions },
{ name: 'All Files', extensions: ['*'] }
]
2025-08-19 14:33:59 +08:00
: [{ name: 'All Files', extensions: ['*'] }],
title: t('选择文件')
2025-08-19 14:33:59 +08:00
})
if (result.filePaths.length === 0) {
throw new Error(t('没有选择的文件或文件夹'))
2025-08-19 14:33:59 +08:00
}
return successMessage(result.filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectFolderOrFile')
2025-08-19 14:33:59 +08:00
} else {
// 选择文件夹
const result = await dialog.showOpenDialog({
properties: ['openDirectory'],
title: t('选择文件夹')
2025-08-19 14:33:59 +08:00
})
if (result.filePaths.length === 0) {
throw new Error(t('没有选择的文件或文件夹'))
2025-08-19 14:33:59 +08:00
}
return successMessage(result.filePaths[0], t("选择文件/文件夹成功"), 'SystemIpc_SelectFolderOrFile')
2025-08-19 14:33:59 +08:00
}
} catch (error: any) {
console.error('选择文件或文件夹错误:', error)
return errorMessage(
t("选择文件/文件夹失败,{error}", {
error: error.message
}),
2025-08-19 14:33:59 +08:00
'SystemIpc_SelectFolderOrFile'
)
}
}
/**
* URL
* @param url
*/
public OpenUrl(url: string) {
shell.openExternal(url)
}
/**
*
* @param filePath
* @returns
*/
public async ReadTextFile(filePath: string): Promise<SuccessItem | ErrorItem> {
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'
)
}
}
2025-08-19 14:33:59 +08:00
}