|
|
@@ -69,13 +69,14 @@ |
|
|
|
<FileItem |
|
|
|
class="lisy-group-item" |
|
|
|
v-for="file in uploadFileList" |
|
|
|
:key="file.id || file.archName" |
|
|
|
:key="file.id" |
|
|
|
:file="file" |
|
|
|
:clientDownLoad="clientDownLoad" |
|
|
|
:setFileStatus="setFileStatus" |
|
|
|
:showFileMilestone="showFileMilestone" |
|
|
|
:nodeFolder="currentNodeFolder" |
|
|
|
:currentFolder="currentFolder" |
|
|
|
:localFileHashMap="localFileHashMap" |
|
|
|
:loadingState="localFileLoadStateMap[file.id]" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<draggable |
|
|
@@ -92,12 +93,13 @@ |
|
|
|
:key="file.id" |
|
|
|
:file="file" |
|
|
|
:clientDownLoad="clientDownLoad" |
|
|
|
:setFileStatus="setFileStatus" |
|
|
|
:showFileMilestone="showFileMilestone" |
|
|
|
:nodeFolder="currentNodeFolder" |
|
|
|
:currentFolder="currentFolder" |
|
|
|
:updateFileWorkStatus="updateFileWorkStatus" |
|
|
|
:commitFile="commitFile" |
|
|
|
@dblclick.native="fileClick(file)" |
|
|
|
:localFileHashMap="localFileHashMap" |
|
|
|
:loadingState="localFileLoadStateMap[file.id]" |
|
|
|
/> |
|
|
|
</draggable> |
|
|
|
<!--显示文件夹组 --> |
|
|
@@ -174,11 +176,12 @@ |
|
|
|
:key="file.id" |
|
|
|
:file="file" |
|
|
|
:clientDownLoad="clientDownLoad" |
|
|
|
:setFileStatus="setFileStatus" |
|
|
|
:showFileMilestone="showFileMilestone" |
|
|
|
:nodeFolder="currentNodeFolder" |
|
|
|
:currentFolder="currentFolder" |
|
|
|
@dblclick.native="fileClick(file)" |
|
|
|
:localFileHashMap="localFileHashMap" |
|
|
|
:loadingState="localFileLoadStateMap[file.id]" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@@ -263,11 +266,13 @@ import * as services from './service'; |
|
|
|
import { firstCharToLowerCase, firstCharToUpperCase, notify } from '@/utils/tool'; |
|
|
|
import FileItem from './components/file-item'; |
|
|
|
import FolderItem from './components/folder-item'; |
|
|
|
import { FileWorkStatus, DownloadStatus, injectionFileLocalStatus } from './helper'; |
|
|
|
import { FileWorkStatus, injectionFileLocalStatus, LoadingEnum } from './helper'; |
|
|
|
|
|
|
|
const $ = window.jQuery; |
|
|
|
const Velocity = window.Velocity; |
|
|
|
Vue.use(vuetify); |
|
|
|
const { DOWNLOADING, UPLOADING } = LoadingEnum; |
|
|
|
const { WORKING, NOT_WORKING } = FileWorkStatus; |
|
|
|
|
|
|
|
const initialTempFile = (folderGroupID, folderGroupName) => ({ |
|
|
|
archID: null, |
|
|
@@ -304,7 +309,7 @@ const initialFolderData = () =>({ |
|
|
|
ModifyTime:"", |
|
|
|
}); |
|
|
|
|
|
|
|
const fileIsDownloaded = file => file.downloadStatus === DownloadStatus.DOWNLOADED; |
|
|
|
// const fileIsDownloaded = file => file.downloadStatus === DownloadStatus.DOWNLOADED; |
|
|
|
|
|
|
|
export default { |
|
|
|
components: { |
|
|
@@ -338,9 +343,7 @@ export default { |
|
|
|
localWorkspacePrefix: '', // 本地工作目录前缀 |
|
|
|
socketIns: null, // 监听文件变化的socket实例 |
|
|
|
timerIns: null, // 文件定时任务实例 |
|
|
|
fileDownloadStatusHash: {}, // 文件上传/下载状态存储 |
|
|
|
folderMap: {}, // 文件夹id哈希: { [folderId]: folder } |
|
|
|
fileLocalStateMap: {}, // 本地网关文件通信数据缓存: { [fileId]: { } } |
|
|
|
|
|
|
|
breadcrumbFolderList: [], // 面包屑导航对应的文件夹队列 |
|
|
|
uploadFileList: [], // 上传文件的队列 |
|
|
@@ -350,6 +353,20 @@ export default { |
|
|
|
|
|
|
|
neibianju: "neibianju", // 协作文件槽样式 |
|
|
|
showadow: false, |
|
|
|
localFileHashMap: {}, // { `${节点名称}\\${文件名称}.${文件扩展名}`: `${ipfsCid}` } |
|
|
|
/** |
|
|
|
* 文件本地加载状态表 |
|
|
|
* 格式: { |
|
|
|
* [file.id]: { |
|
|
|
* type: DOWNLOADING | UPLOADING |
|
|
|
* loadProgress: number | string |
|
|
|
* loadSize: number | string |
|
|
|
* totalSize: number | string |
|
|
|
* unit: string |
|
|
|
* } |
|
|
|
* } |
|
|
|
*/ |
|
|
|
localFileLoadStateMap: {}, |
|
|
|
}; |
|
|
|
}, |
|
|
|
mounted: function () { |
|
|
@@ -364,7 +381,7 @@ export default { |
|
|
|
this.onSocketFileChangeDetected.bind(this), (localWorkspacePrefix) => { this.localWorkspacePrefix = localWorkspacePrefix;}, |
|
|
|
errorEvent => { notify.error('本地网关通讯失败'); } |
|
|
|
); |
|
|
|
this.intervalTask(); |
|
|
|
// this.intervalTask(); |
|
|
|
}, |
|
|
|
destroyed: function () { |
|
|
|
window.removeEventListener("scroll", this.onscroll); |
|
|
@@ -437,33 +454,26 @@ export default { |
|
|
|
* } |
|
|
|
*/ |
|
|
|
const hash = JSON.parse(data); |
|
|
|
this.fileDownloadStatusHash = hash; |
|
|
|
this.refreshFileStatus(); |
|
|
|
this.localFileHashMap = hash; |
|
|
|
}catch(e) { |
|
|
|
console.log('socket file change message error:', e); |
|
|
|
} |
|
|
|
// console.log('socket file change message detected:', args); |
|
|
|
}, |
|
|
|
refreshFileStatus(){ |
|
|
|
const fileStatusHash = this.fileDownloadStatusHash; |
|
|
|
const stateMap = this.fileLocalStateMap; |
|
|
|
const folderMap = this.folderMap; |
|
|
|
this.workFileList = injectionFileLocalStatus(this.workFileList, fileStatusHash, stateMap, folderMap); |
|
|
|
this.cooperationFileList = injectionFileLocalStatus(this.cooperationFileList, fileStatusHash, stateMap, folderMap); |
|
|
|
addLocalFileRecord(fileStoreKey, ipfsCid) { |
|
|
|
// this.localFileHashMap[fileStoreKey] = ipfsCid; |
|
|
|
this.localFileHashMap = { ...this.localFileHashMap, [fileStoreKey]: ipfsCid }; |
|
|
|
}, |
|
|
|
updateFileLoadState(file, progress, type){ |
|
|
|
const stateMap = this.fileLocalStateMap; |
|
|
|
updateFileLoadState(fileId, type, loadProgress = 0, loadSize, totalSize, unit){ |
|
|
|
const updateState = { |
|
|
|
loadProgress: progress, |
|
|
|
downloadStatus: type === 'download' ? DownloadStatus.DOWNLOADING : DownloadStatus.UPLOADING, |
|
|
|
}; |
|
|
|
this.fileLocalStateMap = { ...stateMap, [file.id]: updateState }; |
|
|
|
this.refreshFileStatus(); |
|
|
|
type, loadProgress, loadSize, totalSize, unit |
|
|
|
} |
|
|
|
this.localFileLoadStateMap = { ...this.localFileLoadStateMap, [fileId]: updateState }; |
|
|
|
}, |
|
|
|
removeFileLoadingState(fileId) { |
|
|
|
delete this.fileLocalStateMap[fileId]; |
|
|
|
this.fileLocalStateMap = {...this.fileLocalStateMap}; |
|
|
|
this.refreshFileStatus(); |
|
|
|
console.log(`going to remove file: ${fileId}`) |
|
|
|
// todo 待确认 |
|
|
|
delete this.localFileLoadStateMap[fileId]; |
|
|
|
}, |
|
|
|
/* 工作链API */ |
|
|
|
/** |
|
|
@@ -576,22 +586,21 @@ export default { |
|
|
|
// todo 接口去除公共文件夹配置 |
|
|
|
const folderResInfo = await services.fetchFolderFileList(currentFolder.id, userId, currentFolder.id); |
|
|
|
if(!folderResInfo) return; |
|
|
|
this.workFileList = injectionFileLocalStatus( |
|
|
|
folderResInfo.myFile.concat(folderResInfo.workFile), |
|
|
|
this.fileDownloadStatusHash, |
|
|
|
this.fileLocalStateMap, |
|
|
|
this.folderMap, |
|
|
|
); |
|
|
|
this.workFileList = folderResInfo.myFile.concat(folderResInfo.workFile); |
|
|
|
this.resolveUploadFileList(this.workFileList); |
|
|
|
this.workSubFolderList = folderResInfo.folder; |
|
|
|
this.cooperationFileList = injectionFileLocalStatus( |
|
|
|
folderResInfo.coordinationFiles, |
|
|
|
this.fileDownloadStatusHash, |
|
|
|
this.fileLocalStateMap, |
|
|
|
this.folderMap, |
|
|
|
); |
|
|
|
this.cooperationFileList = folderResInfo.coordinationFiles; |
|
|
|
this.resolveUploadFileList(this.cooperationFileList); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 去掉上传队列中已经上传成功的文件 |
|
|
|
*/ |
|
|
|
resolveUploadFileList(fileList) { |
|
|
|
this.uploadFileList = this.uploadFileList.filter(uploadFile => { |
|
|
|
const targetFile = fileList.find(iFile => iFile.archName === uploadFile.archName && iFile.extension === uploadFile.extension); |
|
|
|
return !targetFile; |
|
|
|
}); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 点击确定 保存文件夹组 |
|
|
|
*/ |
|
|
@@ -650,15 +659,6 @@ export default { |
|
|
|
// 重置面包屑导航数组 |
|
|
|
this.breadcrumbFolderList = this.breadcrumbFolderList.slice(0, breadFolderIdx + 1); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 去掉上传队列中已经上传成功的文件 |
|
|
|
*/ |
|
|
|
resolveUploadFileList(fileList) { |
|
|
|
this.uploadFileList = this.uploadFileList.filter(uploadFile => { |
|
|
|
const targetFile = fileList.find(iFile => iFile.archName === uploadFile.archName && iFile.extension === uploadFile.extension); |
|
|
|
return !targetFile; |
|
|
|
}); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 客户端上传文件 |
|
|
|
*/ |
|
|
@@ -672,43 +672,29 @@ export default { |
|
|
|
const {ArchName, IpfsCid, Extension} = file; |
|
|
|
// 注入到文件下载检测表中 |
|
|
|
const key = `${folderName}\\${ArchName}${Extension ? `.${Extension}`: ''}`; |
|
|
|
this.fileDownloadStatusHash[key] = IpfsCid; |
|
|
|
this.refreshFileStatus(); |
|
|
|
this.addLocalFileRecord(key, IpfsCid); |
|
|
|
this.removeFileLoadingState(file.Id); |
|
|
|
this.fetchFolderFiles(); |
|
|
|
}, |
|
|
|
(progressData, uploadFile) => { // onLoading |
|
|
|
const { process, hash } = progressData; |
|
|
|
const updateState = { |
|
|
|
loadProgress: process, |
|
|
|
downloadStatus: DownloadStatus.UPLOADING, |
|
|
|
}; |
|
|
|
if(uploadFile.Id) { // 若为同名覆盖 |
|
|
|
const stateMap = this.fileLocalStateMap; |
|
|
|
stateMap[uploadFile.Id] = updateState; |
|
|
|
this.refreshFileStatus(); |
|
|
|
(progressData, upperUploadFile) => { // onLoading |
|
|
|
const { process, hash, size, currentSize, unit } = progressData; |
|
|
|
const uploadFile = firstCharToLowerCase(upperUploadFile); |
|
|
|
this.updateFileLoadState(uploadFile.id, UPLOADING, process, currentSize, size, unit); |
|
|
|
// 覆盖已有的同名文件 |
|
|
|
if(uploadFile.id.indexOf('upload:') === -1) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const targetFile = this.uploadFileList.find(iFile => iFile.archName === uploadFile.ArchName && iFile.extension === uploadFile.Extension); |
|
|
|
if(targetFile) { |
|
|
|
const shadowFile = firstCharToLowerCase({ ...targetFile, ...updateState }); |
|
|
|
this.uploadFileList = this.uploadFileList.map(iFile => { |
|
|
|
if(iFile.archName === shadowFile.archName && iFile.extension === shadowFile.extension) { |
|
|
|
return shadowFile; |
|
|
|
} |
|
|
|
return iFile; |
|
|
|
}); |
|
|
|
return; |
|
|
|
// 插入上传队列 |
|
|
|
if(!this.uploadFileList.find(f => f === uploadFile)) { |
|
|
|
this.uploadFileList.push(uploadFile); |
|
|
|
} |
|
|
|
this.uploadFileList.push(firstCharToLowerCase({ ...uploadFile, ...updateState })); |
|
|
|
// console.log(this.uploadFileList); |
|
|
|
}, |
|
|
|
); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 客户端下载方法 |
|
|
|
* type :1 为文件,2位协作文件 |
|
|
|
*/ |
|
|
|
clientDownLoad: function (file, type) { |
|
|
|
clientDownLoad: function (file) { |
|
|
|
if(!this.isClient) return; |
|
|
|
console.log('下载的文件对象', file); |
|
|
|
const { ipfsCid, archName: fileName, extension, folderId, nodeName } = file; |
|
|
@@ -716,28 +702,22 @@ export default { |
|
|
|
// const { levelId } = folderMap[folderId] || {}; |
|
|
|
const nodeFolderName = nodeName || this.currentNodeFolder.folderName; |
|
|
|
const extensionedFileName = `${fileName}${extension ? `.${extension}`:''}`; |
|
|
|
const copyFile = { ...file }; |
|
|
|
const fileStoreKey = `${nodeFolderName}\\${extensionedFileName}`; |
|
|
|
const errorHandler = () => { |
|
|
|
notify.error('文件下载失败'); |
|
|
|
Object.assign(file, copyFile); |
|
|
|
delete this.fileLocalStateMap[file.id]; |
|
|
|
this.refreshFileStatus(); |
|
|
|
this.removeFileLoadingState(file.id); |
|
|
|
} |
|
|
|
this.updateFileLoadState(file, 0, 'download'); |
|
|
|
this.updateFileLoadState(file.id, DOWNLOADING, 0); |
|
|
|
system.downloadFile(ipfsCid, sessionStorage.projName, extensionedFileName, nodeFolderName, (resMessage, socketIns) => { |
|
|
|
console.log('receive download file message:', resMessage, socketIns); |
|
|
|
// {"size":"11","currentSize":"11","unit":"B","process":100,"hash":""} |
|
|
|
try { |
|
|
|
const { process } = JSON.parse(resMessage.data); |
|
|
|
const { process, hash } = JSON.parse(resMessage.data); |
|
|
|
if(resMessage.data === '-1') { throw 'download failed'; } |
|
|
|
this.updateFileLoadState(file, process, 'download'); |
|
|
|
this.updateFileLoadState(file.id, DOWNLOADING, process); |
|
|
|
if(process !== 100) return; |
|
|
|
// file.downloadStatus = 2; |
|
|
|
// file.isDownload = true; |
|
|
|
// 注入到文件下载检测表中 |
|
|
|
const key = `${nodeFolderName}\\${extensionedFileName}`; |
|
|
|
this.fileDownloadStatusHash[key] = ipfsCid; |
|
|
|
this.refreshFileStatus(); |
|
|
|
this.addLocalFileRecord(fileStoreKey, ipfsCid); |
|
|
|
this.removeFileLoadingState(file.id); |
|
|
|
notify.success(`文件:${fileName} 下载完成`); |
|
|
|
// this.$forceUpdate(); |
|
|
|
} catch (e) { |
|
|
@@ -757,65 +737,33 @@ export default { |
|
|
|
system.openFolder(path); |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 更改文件状态 |
|
|
|
*/ |
|
|
|
async setFileStatus(file, state, message, type) { |
|
|
|
if(state === 2 || state === 1) {//2代表是开启协同 1代表取消协同 |
|
|
|
let params = { |
|
|
|
FolderId: file.folderId, |
|
|
|
FileId: file.id, |
|
|
|
UserId: this.userId, |
|
|
|
FileStatus: state |
|
|
|
} |
|
|
|
try { |
|
|
|
const res = await services.fileCoordinationChange(params); |
|
|
|
if(res.Code === 0) { |
|
|
|
notify.success(res.Msg); |
|
|
|
this.fetchFolderFiles(); |
|
|
|
} else { |
|
|
|
notify.info(res.Msg); |
|
|
|
return; |
|
|
|
} |
|
|
|
} catch(err) { |
|
|
|
console.log(err); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 更新文件 |
|
|
|
* 提交本地文件 |
|
|
|
*/ |
|
|
|
async updateFileWorkStatus(file, nextWorkStatus, message) { |
|
|
|
if(!this.isClient || (nextWorkStatus === FileWorkStatus.WORKING && file.workStatus === FileWorkStatus.NOT_WORKING)) { |
|
|
|
const resFlag = await services.changeFileWorkStatus(file.id, nextWorkStatus); |
|
|
|
if(resFlag.Code !== 0) return; |
|
|
|
notify.success(message); |
|
|
|
this.$forceUpdate(); |
|
|
|
return; |
|
|
|
} |
|
|
|
// 仅当文件从工作中变成非工作状态时执行下面的代码 |
|
|
|
// todo 获取文件最新的hash并更新文件 |
|
|
|
async commitFile(file) { |
|
|
|
if(!this.isClient) return; |
|
|
|
const { folderName, levelId, id: folderId } = this.currentNodeFolder; |
|
|
|
const { archName, extension, id: fileId } = file; |
|
|
|
this.updateFileLoadState(file, 0, 'upload'); |
|
|
|
this.updateFileLoadState(fileId, UPLOADING, 0); |
|
|
|
// const fileList = this.currentPageType === 0 ? this.folderFileList.listMyFiles : this.folderFileList.listOtherFiles; |
|
|
|
const fileKey = `${folderName}\\${archName}${extension ? `.${extension}`:''}`; |
|
|
|
this.fileDownloadStatusHash[fileId] = `${file.localIpfsCid}--upload`; |
|
|
|
this.refreshFileStatus(); |
|
|
|
system.updateFile( |
|
|
|
file, this.localWorkspacePrefix, |
|
|
|
this.projectName, folderName, |
|
|
|
async (fileNewState) => { |
|
|
|
const resFlag = await services.changeFileWorkStatus(file.id, nextWorkStatus); |
|
|
|
const resFlag = await services.changeFileWorkStatus(file.id, 1); |
|
|
|
if(resFlag.Code !== 0) return; |
|
|
|
notify.success(message); |
|
|
|
notify.success('文件已更新'); |
|
|
|
const {IpfsCid} = fileNewState; |
|
|
|
// 注入到文件下载检测表中 |
|
|
|
this.fileDownloadStatusHash[fileKey] = IpfsCid; |
|
|
|
// 同时更新文件队列中file对象的ipfsCid属性这样才能在下次刷新前使文件的记录保持一致 |
|
|
|
file.ipfsCid = IpfsCid; |
|
|
|
file.workStatus = NOT_WORKING; |
|
|
|
this.addLocalFileRecord(fileKey, IpfsCid); |
|
|
|
this.removeFileLoadingState(fileId); |
|
|
|
}, |
|
|
|
(progressData) => { |
|
|
|
const { process, hash } = progressData; |
|
|
|
this.updateFileLoadState(file, process, 'upload'); |
|
|
|
const { process, hash, size, currentSize, unit } = progressData; |
|
|
|
this.updateFileLoadState(fileId, UPLOADING, process, currentSize, size, unit); |
|
|
|
}, |
|
|
|
); |
|
|
|
}, |
|
|
@@ -824,11 +772,12 @@ export default { |
|
|
|
*/ |
|
|
|
fileClick: async function (file) { |
|
|
|
if(!this.isClient) return; |
|
|
|
if(!fileIsDownloaded(file)) return; |
|
|
|
const { archName, extension, id: fileId, nodeName } = file; |
|
|
|
const { archName, extension, id: fileId, nodeName } = file; |
|
|
|
const folderName = nodeName || this.currentFolder.folderName; |
|
|
|
const localWorkspacePrefix = this.localWorkspacePrefix; |
|
|
|
const filePath = `${localWorkspacePrefix}\\${folderName}\\${archName}${extension ? `.${extension}` : ''}`; |
|
|
|
const fileStoreKey = `${folderName}\\${archName}${extension ? `.${extension}` : ''}`; |
|
|
|
if(!this.localFileHashMap[fileStoreKey]) return; |
|
|
|
const filePath = `${localWorkspacePrefix}\\${fileStoreKey}`; |
|
|
|
const isCooperationFile = !!nodeName; |
|
|
|
if(!isCooperationFile && (file.workStatus === 2 && sessionStorage.userId !== file.modifyUserId)) { |
|
|
|
notify.warning('文件正在工作编辑中,请耐心等待'); |
|
|
|