322 lines
9.7 KiB
TypeScript
322 lines
9.7 KiB
TypeScript
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<ErrorItem | SuccessItem> {
|
||
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<ErrorItem | SuccessItem> {
|
||
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<SuccessItem | ErrorItem> {
|
||
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<SuccessItem | ErrorItem> {
|
||
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<SuccessItem | ErrorItem> {
|
||
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<SuccessItem | ErrorItem> {
|
||
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<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'
|
||
)
|
||
}
|
||
}
|
||
}
|