AIx_Smarttalk_WS/src/main/file.js

529 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}
})
})
}
}