529 lines
16 KiB
JavaScript
529 lines
16 KiB
JavaScript
import SparkMD5 from 'spark-md5'
|
||
const fs = require('fs')
|
||
const path = require('path')
|
||
import { ElectronDownloadManager } from 'electron-dl-manager'
|
||
import { dialog } from 'electron'
|
||
import axios from 'axios'
|
||
const uploadUrl = import.meta.env.VITE_APP_UPLOAD_API + '/smarttalk/file/upload'
|
||
const asyncUploadUrl = import.meta.env.VITE_APP_UPLOAD_API + '/smarttalk/file/asyncUpload'
|
||
const manager = new ElectronDownloadManager()
|
||
export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||
const userDataPath = app.getPath('userData')
|
||
const appRootFilePath = userDataPath + '\\selfFile\\'
|
||
const appTempFilePath = userDataPath + '\\tempFile\\'
|
||
let Spark = new SparkMD5.ArrayBuffer()
|
||
|
||
ipcMain.on('upload-file-change', (e, { id, fileNewName, cookie, fileType }) => {
|
||
let filePath = appRootFilePath + fileNewName
|
||
//执行更新,上传文件
|
||
let formData = new FormData()
|
||
formData.append('id', id)
|
||
uploadFileByFS({
|
||
url: asyncUploadUrl,
|
||
path: filePath,
|
||
name: fileNewName,
|
||
cookie,
|
||
fileType,
|
||
formData,
|
||
success: (response) => {
|
||
e.reply('upload-file-change-success' + fileNewName, {
|
||
data: response.data,
|
||
md5: formData.md5
|
||
})
|
||
},
|
||
error: (err) => {
|
||
console.error('Error uploading file:', err)
|
||
}
|
||
})
|
||
})
|
||
|
||
/*监听文件改变,如果有改变则返回触发*/
|
||
ipcMain.on('listen-file-change', (e, { id, fileNewName, md5, cookie, fileType }) => {
|
||
let filePath = appRootFilePath + fileNewName
|
||
let uploadId = null
|
||
let isOn = false
|
||
let lastMTime = fs.statSync(filePath).mtime.getTime()
|
||
console.log(lastMTime)
|
||
setInterval(() => {
|
||
getFileMsg(filePath).then((msg) => {
|
||
if (msg !== lastMTime) {
|
||
lastMTime = msg
|
||
if (uploadId) {
|
||
clearTimeout(uploadId)
|
||
}
|
||
if (isOn === false) {
|
||
console.log(fileNewName)
|
||
e.reply('listen-file-change-on' + fileNewName)
|
||
isOn = true
|
||
}
|
||
//倒数十秒提交更改,十秒之内有继续修改则重置倒数
|
||
uploadId = setTimeout(() => {
|
||
console.log(223)
|
||
//执行更新,上传文件
|
||
let formData = new FormData()
|
||
formData.append('id', id)
|
||
uploadFileByFS({
|
||
url: asyncUploadUrl,
|
||
path: filePath,
|
||
name: fileNewName,
|
||
cookie,
|
||
fileType,
|
||
formData,
|
||
success: (response) => {
|
||
e.reply('listen-file-change-success' + fileNewName, {
|
||
data: response.data,
|
||
md5: formData.md5
|
||
})
|
||
clearTimeout(uploadId)
|
||
isOn = false
|
||
},
|
||
error: (err) => {
|
||
console.error('Error uploading file:', err)
|
||
}
|
||
})
|
||
}, 5000)
|
||
}
|
||
})
|
||
}, 1000)
|
||
})
|
||
|
||
function getFileMsg(path) {
|
||
return new Promise((resolve, reject) => {
|
||
const stats = fs.statSync(path)
|
||
return resolve(stats.mtime.getTime())
|
||
})
|
||
}
|
||
|
||
function getFileMD5(path) {
|
||
return new Promise((resolve, reject) => {
|
||
fs.readFile(path, (err, dataFile) => {
|
||
if (err) {
|
||
reject(err)
|
||
return console.error(err)
|
||
}
|
||
Spark.append(dataFile)
|
||
let md5 = Spark.end()
|
||
resolve(md5)
|
||
})
|
||
})
|
||
}
|
||
|
||
/*
|
||
* 判断是否有本地文件
|
||
* */
|
||
ipcMain.on('is-have-local-file', (e, fileNewName) => {
|
||
let filePath = appRootFilePath + fileNewName
|
||
fs.access(filePath, fs.constants.F_OK, (err) => {
|
||
if (err) {
|
||
e.reply('is-have-local-file-reply' + fileNewName, false)
|
||
return
|
||
}
|
||
e.reply('is-have-local-file-reply' + fileNewName, true)
|
||
})
|
||
})
|
||
|
||
/*
|
||
* 判断是需要同步本地文件
|
||
* */
|
||
ipcMain.on('is-async-local-file', (e, { fileNewName, lastModifyTime, md5 }) => {
|
||
let filePath = appRootFilePath + fileNewName
|
||
fs.access(filePath, fs.constants.F_OK, (err) => {
|
||
if (err) {
|
||
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
|
||
return
|
||
}
|
||
getFileMsg(filePath).then((msg) => {
|
||
let time = new Date(lastModifyTime).getTime();
|
||
msg = parseInt(msg/1000)*1000;
|
||
if (msg == time) {
|
||
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: false, type: '' })
|
||
} else {
|
||
const stats = fs.statSync(filePath)
|
||
//如果线上时间大于线下时间,就需要从线上下载,否则则需要上传
|
||
if (time > stats.mtime.getTime()) {
|
||
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
|
||
} else if (time < stats.mtime.getTime()) {
|
||
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'upload' })
|
||
}
|
||
}
|
||
})
|
||
})
|
||
})
|
||
|
||
//默认浏览器打开url
|
||
ipcMain.on('open-url-browser', (e, url) => {
|
||
shell.openPath(url)
|
||
})
|
||
|
||
//使用默认应用打开本地文件
|
||
ipcMain.on('open-path-app', (e, destination) => {
|
||
let path = appRootFilePath + destination
|
||
shell.openPath(path).catch((error) => {
|
||
console.log(error)
|
||
})
|
||
})
|
||
|
||
//复制文件
|
||
ipcMain.on('copy-file-default', (e, { source, destination }) => {
|
||
copyFile(source, destination, (error, filePath) => {
|
||
e.reply('copy-file-default-reply', { error, filePath })
|
||
})
|
||
})
|
||
|
||
//导出文件
|
||
ipcMain.on('export-file-default', (e, list) => {
|
||
exportFile(list, (res) => {
|
||
e.reply('export-file-default-reply', res)
|
||
})
|
||
})
|
||
|
||
function uploadFileByFS({ url, path, name, cookie, fileType, formData, success, error }) {
|
||
fs.readFile(path, (err, data) => {
|
||
if (err) {
|
||
return console.error(err)
|
||
}
|
||
// 配置上传的请求
|
||
const config = {
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data', // 或者其他适合上传文件的Content-Type
|
||
Authorization: 'Bearer ' + cookie
|
||
}
|
||
}
|
||
Spark.append(data)
|
||
let md5 = Spark.end()
|
||
// 使用axios上传文件
|
||
let file = new File([data], name, {
|
||
type: fileType
|
||
})
|
||
const stats = fs.statSync(path)
|
||
formData.append('file', file)
|
||
formData.append('md5', md5)
|
||
formData.append('lastModifyTime', stats.mtime.toLocaleString())
|
||
axios
|
||
.post(url, formData, config)
|
||
.then((response) => {
|
||
success(response)
|
||
})
|
||
.catch((errorMsg) => {
|
||
error(errorMsg)
|
||
})
|
||
})
|
||
}
|
||
|
||
/*创建新的ppt文件*/
|
||
ipcMain.on('creat-file-default', (e, { name, uploadData, cookie }) => {
|
||
createFolder('tempFile').then(() => {
|
||
let path = appTempFilePath + name.replace(/[\\/:*?"<>|]/, '')
|
||
console.log(path)
|
||
fs.writeFileSync(path, '', 'utf-8')
|
||
let fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||
let formData = new FormData()
|
||
for (let key in uploadData) {
|
||
if (Object.prototype.hasOwnProperty.call(uploadData, key)) {
|
||
// 检查是否是对象自身的属性
|
||
formData.append(key, uploadData[key])
|
||
}
|
||
}
|
||
formData.append('fileFlag', '课件')
|
||
uploadFileByFS({
|
||
url: uploadUrl,
|
||
path,
|
||
name,
|
||
cookie,
|
||
fileType,
|
||
formData,
|
||
success: (response) => {
|
||
e.reply('creat-file-default-reply', response.data)
|
||
console.log('File uploaded successfully:', response.data)
|
||
},
|
||
error: (err) => {
|
||
console.error('Error uploading file:', err)
|
||
}
|
||
})
|
||
})
|
||
})
|
||
|
||
/*创建新的ppt文件*/
|
||
ipcMain.on('creat-ai-file-default', (e, { name, url, uploadData, cookie }) => {
|
||
createFolder('tempFile').then(async () => {
|
||
let lastname = decodeURIComponent(url);
|
||
name = lastname.substring(lastname.lastIndexOf("/")+1)
|
||
let path = appTempFilePath + name.replace(/[\\/:*?"<>|]/, '')
|
||
let {type,item} = await downloadFiles(url,name)
|
||
if (type==="成功") {
|
||
let fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||
let formData = new FormData()
|
||
for (let key in uploadData) {
|
||
if (Object.prototype.hasOwnProperty.call(uploadData, key)) {
|
||
// 检查是否是对象自身的属性
|
||
formData.append(key, uploadData[key])
|
||
}
|
||
}
|
||
formData.append('fileFlag', '课件')
|
||
uploadFileByFS({
|
||
url: uploadUrl,
|
||
path,
|
||
name,
|
||
cookie,
|
||
fileType,
|
||
formData,
|
||
success: (response) => {
|
||
e.reply('creat-ai-file-default-reply', response.data)
|
||
console.log('File uploaded successfully:', response.data)
|
||
},
|
||
error: (err) => {
|
||
console.error('Error uploading file:', err)
|
||
}
|
||
})
|
||
}else {
|
||
e.reply('creat-ai-file-default-reply', type)
|
||
}
|
||
})
|
||
})
|
||
|
||
function downloadFiles(url,fileName) {
|
||
console.log(url,fileName)
|
||
return new Promise((resolve, reject)=>{
|
||
const browserWindow = BrowserWindow.getFocusedWindow()
|
||
const id = manager.download({
|
||
window: browserWindow,
|
||
url: url,
|
||
saveAsFilename: fileName,
|
||
directory: appTempFilePath,
|
||
callbacks: {
|
||
onDownloadStarted: async ({ id, item, webContents }) => {
|
||
// Do something with the download id
|
||
},
|
||
onDownloadProgress: async ({ id, item, percentCompleted }) => {
|
||
// console.log(percentCompleted)
|
||
},
|
||
onDownloadCompleted: async ({ id, item }) => {
|
||
console.log('完成')
|
||
resolve({type:"成功",item})
|
||
},
|
||
onDownloadCancelled: async () => {
|
||
console.log("取消")
|
||
reject({type:"取消了下载"})
|
||
},
|
||
onDownloadInterrupted: async () => {
|
||
console.log('中断')
|
||
reject({type:"下载被中断"})
|
||
},
|
||
onError: (err, data) => {
|
||
console.log(err.toString())
|
||
reject({type:"下载出错",err})
|
||
}
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
//获取应用文件目录
|
||
ipcMain.on('get-root-file-path', (e) => {
|
||
e.reply('get-root-file-path-reply', appRootFilePath)
|
||
})
|
||
|
||
//下载文件
|
||
ipcMain.on('download-file-default', (e, { url, fileName }) => {
|
||
createFolder('selfFile')
|
||
.then(async () => {
|
||
const browserWindow = BrowserWindow.getFocusedWindow()
|
||
const id = await manager.download({
|
||
window: browserWindow,
|
||
url: url,
|
||
saveAsFilename: fileName,
|
||
directory: appRootFilePath,
|
||
callbacks: {
|
||
onDownloadStarted: async ({ id, item, webContents }) => {
|
||
// Do something with the download id
|
||
},
|
||
onDownloadProgress: async ({ id, item, percentCompleted }) => {
|
||
e.reply('download-file-default-prog' + fileName, percentCompleted)
|
||
},
|
||
onDownloadCompleted: async ({ id, item }) => {
|
||
console.log('完成')
|
||
e.reply('download-file-default' + fileName, true)
|
||
},
|
||
onDownloadCancelled: async () => {
|
||
console.log('取消')
|
||
e.reply('download-file-default' + fileName, false)
|
||
},
|
||
onDownloadInterrupted: async () => {
|
||
console.log('中断')
|
||
e.reply('download-file-default' + fileName, false)
|
||
},
|
||
onError: (err, data) => {
|
||
console.log(err.toString())
|
||
e.reply('download-file-default' + fileName, false)
|
||
}
|
||
}
|
||
})
|
||
})
|
||
.catch((error) => {
|
||
e.reply('download-file-default' + fileName, false)
|
||
})
|
||
})
|
||
|
||
/**另存为...
|
||
* 接收渲染进程 保存文件的 的通知
|
||
* @param {Object} event
|
||
* @param {String} url 下载链接
|
||
* @param {String} fileName 文件名称包括后缀名,例如图1.png
|
||
*/
|
||
ipcMain.on('save-as', function (event, url, fileName) {
|
||
let win = BrowserWindow.getFocusedWindow()
|
||
//通过扩展名识别文件类型
|
||
let filters = [{ name: '全部文件', extensions: ['*'] }]
|
||
let ext = path.extname(fileName) //获取扩展名
|
||
if (ext && ext !== '.') {
|
||
const name = ext.slice(1, ext.length)
|
||
if (name) {
|
||
filters.unshift({
|
||
name: '',
|
||
extensions: [name]
|
||
})
|
||
}
|
||
}
|
||
let filePath = null //用户选择存放文件的路径
|
||
|
||
//1- 弹出另存为弹框,用于获取保存路径
|
||
dialog
|
||
.showSaveDialog(win, {
|
||
title: '另存为',
|
||
filters,
|
||
defaultPath: fileName
|
||
})
|
||
.then((result) => {
|
||
//点击保存后开始下载
|
||
filePath = result.filePath
|
||
if (filePath) {
|
||
win.webContents.downloadURL(url) // 触发will-download事件
|
||
}
|
||
})
|
||
.catch(() => {
|
||
console.log('另存为--catch')
|
||
})
|
||
|
||
//2- 准备下载的时候触发
|
||
win.webContents.session.once('will-download', (event, item, webContents) => {
|
||
if (!filePath) return
|
||
//设置下载项的保存文件路径
|
||
item.setSavePath(filePath)
|
||
})
|
||
})
|
||
|
||
/*导出文件*/
|
||
function exportFile(list, callback) {
|
||
let win = BrowserWindow.getFocusedWindow()
|
||
//通过扩展名识别文件类型
|
||
let filePath = null //用户选择存放文件的路径
|
||
//1- 弹出另存为弹框,用于获取保存路径
|
||
dialog
|
||
.showOpenDialog(win, {
|
||
properties: ['openDirectory']
|
||
})
|
||
.then(async (result) => {
|
||
if (result.filePaths[0]) {
|
||
filePath = result.filePaths[0]
|
||
let res = []
|
||
for (let i = 0; i < list.length; i++) {
|
||
let item = list[i]
|
||
let source = appRootFilePath + item.id
|
||
let destination = filePath + '/' + item.name
|
||
await copyRelFile(source, filterCopyFile(destination), (error, path) => {
|
||
res.push({ error, path })
|
||
})
|
||
}
|
||
callback(res)
|
||
}
|
||
})
|
||
.catch(() => {
|
||
console.log('另存为--catch')
|
||
})
|
||
}
|
||
|
||
/*文件是否已经存在*/
|
||
function isHaveFile(path) {
|
||
return fs.existsSync(path)
|
||
}
|
||
|
||
/*判断是否已经存在这个名字的文件,如果已经存在则递增导出*/
|
||
function filterCopyFile(path, index = 0) {
|
||
if (isHaveFile(path) === true) {
|
||
index++
|
||
path = path.replaceAll('.', `(${index}).`)
|
||
return filterCopyFile(path, index)
|
||
} else {
|
||
return path
|
||
}
|
||
}
|
||
|
||
/*复制文件*/
|
||
function copyRelFile(source, destination, callback) {
|
||
return new Promise((resolve, reject) => {
|
||
const readStream = fs.createReadStream(source)
|
||
const writeStream = fs.createWriteStream(destination)
|
||
|
||
readStream.on('error', (error) => {
|
||
reject()
|
||
callback(error, null)
|
||
})
|
||
writeStream.on('error', (error) => {
|
||
reject()
|
||
callback(error, null)
|
||
})
|
||
writeStream.on('close', () => {
|
||
console.log('关闭写入流')
|
||
callback(null, destination)
|
||
resolve()
|
||
})
|
||
readStream.pipe(writeStream)
|
||
})
|
||
}
|
||
|
||
/*复制文件*/
|
||
function copyFile(source, destination, callback) {
|
||
let path = appRootFilePath + destination
|
||
createFolder('selfFile').then(() => {
|
||
const readStream = fs.createReadStream(source)
|
||
const writeStream = fs.createWriteStream(path)
|
||
|
||
readStream.on('error', (error) => {
|
||
callback(error, null)
|
||
})
|
||
writeStream.on('error', (error) => {
|
||
callback(error, null)
|
||
})
|
||
writeStream.on('close', () => {
|
||
callback(null, path)
|
||
})
|
||
|
||
readStream.pipe(writeStream)
|
||
})
|
||
}
|
||
|
||
/*创建文件夹*/
|
||
function createFolder(folderName) {
|
||
return new Promise((resolve, reject) => {
|
||
const folderPath = path.join(userDataPath, folderName)
|
||
// 异步检查文件夹是否存在,不存在则创建
|
||
fs.access(folderPath, fs.constants.F_OK, (err) => {
|
||
if (err) {
|
||
fs.mkdir(folderPath, { recursive: true }, (mkdirErr) => {
|
||
if (mkdirErr) {
|
||
console.error(mkdirErr)
|
||
reject()
|
||
} else {
|
||
console.log(`Folder ${folderName} created successfully.`)
|
||
resolve()
|
||
}
|
||
})
|
||
} else {
|
||
console.log(`Folder ${folderName} already exists.`)
|
||
resolve()
|
||
}
|
||
})
|
||
})
|
||
}
|
||
}
|