diff --git a/src/services/system.js b/src/services/system.js index 125a70ba..0dfcc430 100644 --- a/src/services/system.js +++ b/src/services/system.js @@ -66,7 +66,7 @@ const system = { }); watchSocket.on('message', fileChangeHandler); watchSocket.on('error', errorHandler); - return watchSocket + return watchSocket; }), /** * todo @@ -100,16 +100,178 @@ const system = { onErrorHandler(e); }); }), + // 解析文件/文件夹路径信息 + // { + // name: '11-28会议纪要.docx', + // extension:".docx", + // relativePath:"协同项目\\分析\\11-28会议纪要.docx", + // absolutePath:"C:\\Users\\yuan_rh\\easycloud\\332174685636661248\\协同项目\\分析\\11-28会议纪要.docx" + // } + analyzeSystemPath: safeCall(async (systemFullpath) => { + const response = await requestBySocket(io('getFolderFileInfo'), systemFullpath); + try { + const obj = JSON.parse(response.data); + const uploadTasks = Object.values(obj).map((data) => { + const { name: extensionedFileName, extension: dotExtension, relativePath, absolutePath } = data; + const extension = dotExtension.indexOf('.') === 0 ? dotExtension.slice(1) : dotExtension; + const fileName = extensionedFileName.slice(0, -dotExtension.length); + return { + fileName, + extension, + relativePath: relativePath.replace(/(\\)+/g, '/'), + fullPath: absolutePath, + }; + }); + return uploadTasks; + } catch(e) { + return []; + } + }), + // 选择文件 + chooseFiles: safeCall(async () => { + const { ipcRenderer } = global.electron; + const res = await ipcRenderer.invoke('project-choose-files'); + const { canceled, filePaths } = res; + if(canceled) return null; + return filePaths; + }), + // 选择文件 + chooseFolders: safeCall(async () => { + const { ipcRenderer } = global.electron; + const res = await ipcRenderer.invoke('project-choose-folders'); + const { canceled, filePaths } = res; + if(canceled) return null; + return filePaths; + }), + /** + * 上传文件到工作空间 + * 程序步骤: + * + 用户选择本地文件/文件夹 + * + 文件上传至本地ipfs节点 + * + 将文件的ipfsCid连同文件信息发送到远端服务器 + * @param {params.projectId} 项目Id + * @param {params.projectName} 项目名称 + * @param {params.folderId} 节点文件夹Id + * @param {params.folderName} 节点文件夹Id + * @param {params.folderLevelId} 节点文件夹levelId + * @param {params.distFileRelativePath} 节点文件夹下的相对路径, 直接在节点文件夹下则为空 + * @param {params.sourceFilePath} 上传文件的完整路径 + * @param {params.fileName} 上传文件名 + * @param {params.fileExtension} 上传文件名 + * @param {params.fileList} 用于对比文件名是否重复的文件队列 + * @param {params.onSuccessHandler} 完成上传时的回调 + * @param {params.onProgressHandler} 上传进度反馈的回调 + * @param {params.onErrorHandler} 上传失败的回调 + * + */ + uploadFile: safeCall(async (params) => { + const { + projectId, projectName, + folderId, folderName, folderLevelId, distFileRelativePath = '', + fileName, fileExtension, sourceFilePath, + fileList, onSuccess: onSuccessHandler, onProgress: onProgressHandler = identity, onError: onErrorHandler = identity + } = params; + const extensionedFileName = fileExtension ? `${fileName}.${fileExtension}`: fileName; + const distFilePath = `${folderName}/${distFileRelativePath}`; + const maybeFile = fileList.find(iFile => distFileRelativePath === iFile.relativePath && `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName); + // 检测当前工作目录中是否存在同名文件 + if(maybeFile) { + let confirmRes = false; + try { + await Vue.prototype.$confirm('监测到文件夹存在同名文件,是否继续上传并覆盖同名文件?'); + confirmRes = true; + } catch(e) { console.log('user canceled'); } + if(!confirmRes) return; + } + + const uploadFile = maybeFile + ? firstCharToUpperCase({ ...maybeFile, ModifyUserId: sessionStorage.userId }) + : { + // 文件名称 不带扩展名 + ArchName: fileName, + // CommonStatus: 0, + // CreateTime: "string", + // 文件上传者Id + CreateUserId: sessionStorage.userId, + // Deleted: 0, + Extension: fileExtension, + // 文件大小 单位? + // FileSize: +size, + // 所处文件夹id + FolderId: folderId, + // 所处文件夹层级,拼接符:_ + FolderLevelId: folderLevelId, + Id: `upload:${`${Math.random()}`.slice(2, 8)}`, + // IpfsCid: hash, + // IsShowRecycle: 0, + // Milestone: 0, + // ModifyTime: "string", + // ModifyUserId: 0, + // 项目id + ProjId: projectId, + RelativePath: distFileRelativePath, + // ShowUrl: "string", + Status: 2, + Version: 1, + // WorkStatus: 0 + }; + + const socket = io('upload'); + socket.on('open', () => { + const data = [sourceFilePath, extensionedFileName, projectName, distFilePath].join('|'); + socket.send(data); + onProgressHandler({ process: 0 }, uploadFile); + }); + + socket.on('message', async (e) => { + console.log('receive download file message:', e); + if(e.data === '-1') { + notify.error('文件上传失败'); + onErrorHandler(e, uploadFile); + return; + } + if(e.data === '-2') { + notify.error('请先关闭本地文件后再上传'); + onErrorHandler(e, uploadFile); + return; + } + try { + const progressData = JSON.parse(e.data); + const { size, process, hash } = progressData; + onProgressHandler(progressData, uploadFile); + if(process !== 100 || !hash) return; + socket.close(); + // {"size":"88.69","currentSize":"88.69","unit":"KiB","process":100,"hash":""} + // {"size":"","currentSize":"","unit":"","process":100,"hash":"QmPJ9i4z5UdoQpLH1DrkhZiTZra2rGicXiPabiLw4LvTmX"} + // const maybeFile = fileList.find(iFile => `${iFile.archName}${iFile.extension ? `.${iFile.extension}` : ''}` === extensionedFileName); + uploadFile.FileSize = +size; + uploadFile.IpfsCid = hash; + if(!maybeFile) { + delete uploadFile.Id; + } + const res = await fetchApi(`file/${maybeFile ? 'updateFile' : 'addFile'}`, uploadFile); + wrapErrorHint(res); + if(res.Code !== 0) return; + //notify.success(maybeFile ? '上传成功, 已覆盖同名文件' : '上传成功'); + notify.success('文件已上传。') + onSuccessHandler(uploadFile); + } catch (e) { + console.error('socket-upload-file parse data have error:', e); + onErrorHandler(e, uploadFile); + } + }); + socket.on('error', e => { + onErrorHandler(e, uploadFile); + }); + }), /** * 上传文件到工作空间 - * issue: - * + 浏览器的文件上传不会带有本地的文件路径,本地服务是否可以唤起一个选择文件的弹窗? * 程序步骤: - * + 用户选择本地文件 + * + 用户选择本地文件/文件夹 * + 文件上传至本地ipfs节点 * + 将文件的ipfsCid连同文件信息发送到远端服务器 */ - uploadFile: safeCall(async (projectId, projectName, folderId, folderName, levelId, fileList, onSuccessHandler, onProgressHandler = identity, onErrorHandler = identity) => { + uploadFileOld: safeCall(async (projectId, projectName, folderId, folderName, levelId, fileList, onSuccessHandler, onProgressHandler = identity, onErrorHandler = identity) => { const { ipcRenderer } = global.electron; const res = await ipcRenderer.invoke('project-upload-file'); console.log('ipcRenderer project-selected-upload-file: ', res); diff --git a/src/views/main_web/workspace/components/add-file-button.vue b/src/views/main_web/workspace/components/add-file-button.vue index 7311a419..948452f6 100644 --- a/src/views/main_web/workspace/components/add-file-button.vue +++ b/src/views/main_web/workspace/components/add-file-button.vue @@ -23,11 +23,18 @@
点击上传本地文件
+
+ + 点击上传本地文件夹 +
@@ -37,7 +44,8 @@ export default { props: { onButtnClick: Function, - clientUpload: Function, + selectSystemFiles: Function, + selectSystemFolders: Function, }, data() { return { diff --git a/src/views/main_web/workspace/components/file-item.vue b/src/views/main_web/workspace/components/file-item.vue index a37d9050..6afddf90 100644 --- a/src/views/main_web/workspace/components/file-item.vue +++ b/src/views/main_web/workspace/components/file-item.vue @@ -190,7 +190,7 @@