From 66b7ab35e942f2e01de47572cf1298ba290d46f5 Mon Sep 17 00:00:00 2001 From: jmal Date: Wed, 6 Aug 2025 17:57:04 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84ShowFile.vue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ShowFile/ShowFile.vue | 4021 +---------------- src/components/ShowFile/mixins/clipboard.js | 49 + src/components/ShowFile/mixins/common.js | 20 + .../ShowFile/mixins/fileContextmenu.js | 452 ++ src/components/ShowFile/mixins/fileDrag.js | 738 +++ src/components/ShowFile/mixins/fileHandel.js | 876 ++++ src/components/ShowFile/mixins/fileList.js | 477 ++ src/components/ShowFile/mixins/fileTooltip.js | 56 + .../ShowFile/mixins/filenameHandle.js | 132 + .../ShowFile/mixins/filepathHandle.js | 145 + .../ShowFile/mixins/globalContextmenu.js | 140 + .../ShowFile/mixins}/scrollLockMixin.js | 0 src/components/ShowFile/mixins/searchFile.js | 321 ++ src/components/ShowFile/mixins/shortcutKey.js | 109 + .../ShowFile/mixins/styleControl.js | 174 + src/components/ShowFile/style/index.scss | 343 ++ src/views/public/share/shareList.vue | 7 - src/views/share/index.vue | 2 - 18 files changed, 4074 insertions(+), 3988 deletions(-) create mode 100644 src/components/ShowFile/mixins/clipboard.js create mode 100644 src/components/ShowFile/mixins/common.js create mode 100644 src/components/ShowFile/mixins/fileContextmenu.js create mode 100644 src/components/ShowFile/mixins/fileDrag.js create mode 100644 src/components/ShowFile/mixins/fileHandel.js create mode 100644 src/components/ShowFile/mixins/fileList.js create mode 100644 src/components/ShowFile/mixins/fileTooltip.js create mode 100644 src/components/ShowFile/mixins/filenameHandle.js create mode 100644 src/components/ShowFile/mixins/filepathHandle.js create mode 100644 src/components/ShowFile/mixins/globalContextmenu.js rename src/{utils => components/ShowFile/mixins}/scrollLockMixin.js (100%) create mode 100644 src/components/ShowFile/mixins/searchFile.js create mode 100644 src/components/ShowFile/mixins/shortcutKey.js create mode 100644 src/components/ShowFile/mixins/styleControl.js create mode 100644 src/components/ShowFile/style/index.scss diff --git a/src/components/ShowFile/ShowFile.vue b/src/components/ShowFile/ShowFile.vue index bd6f5d0..a82e6f3 100644 --- a/src/components/ShowFile/ShowFile.vue +++ b/src/components/ShowFile/ShowFile.vue @@ -306,7 +306,6 @@ :fit="true" :cell-style="rowStyle" :height-change="false" - :row-class-name="tableRowClassName" element-loading-text="文件加载中" element-loading-spinner="el-icon-loading" element-loading-background="#f6f7fa88" @@ -505,8 +504,7 @@ renameInputFocus($event.currentTarget, item.suffix) " @blur="setInputBlur()" - @keyup.enter.prevent.native=" - rowRename(renameFileName, item) + @keyup.enter.prevent.native="rowRename(renameFileName, item) " > @@ -739,7 +737,6 @@ @@ -4692,348 +1097,6 @@ export default { diff --git a/src/components/ShowFile/mixins/clipboard.js b/src/components/ShowFile/mixins/clipboard.js new file mode 100644 index 0000000..b290f65 --- /dev/null +++ b/src/components/ShowFile/mixins/clipboard.js @@ -0,0 +1,49 @@ +import store from '@/store' +import fileConfig from '@/utils/file-config' + +export default { + created() { + }, + computed: { + fileClipboard() { + return store.getters.fileClipboard + }, + getClipboardFileIdList() { + return store.getters.fileClipboard.map(file => file.id) + }, + }, + props: { + showClipboard: { + type: Boolean, + default: false, + } + }, + methods: { + // 复制下载链接 + copyDownloadLink(row) { + let url = window.location.origin + fileConfig.previewUrl(this.$store.getters.name, row, undefined, this.shareToken) + if (row.isFolder) { + url = fileConfig.packageDownloadUrl(row.id, row.name + '.zip', this.shareToken) + } + let clipboard = new Clipboard('.file-contextmenu', { + text: function() { + return url + }, + }) + clipboard.on('success', () => { + this.$message({ message: '复制成功', type: 'success', duration: 1000 }) + // 释放内存 + clipboard.destroy() + }) + clipboard.on('error', () => { + // 不支持复制 + this.$message({ + message: '该浏览器不支持自动复制', + type: 'warning', + duration: 1000, + }) + clipboard.destroy() + }) + }, + } +} diff --git a/src/components/ShowFile/mixins/common.js b/src/components/ShowFile/mixins/common.js new file mode 100644 index 0000000..5cc643f --- /dev/null +++ b/src/components/ShowFile/mixins/common.js @@ -0,0 +1,20 @@ +import { formatSize, formatTime } from '@/utils/number' + +export default { + data() { + return { + imageUrl: `${process.env.VUE_APP_BASE_API}/view/thumbnail?jmal-token=${this.$store.state.user.token}&name=${this.$store.state.user.name}&id=`, + audioCoverUrl: `${process.env.VUE_APP_BASE_API}/view/cover?jmal-token=${this.$store.state.user.token}&name=${this.$store.state.user.name}&id=`, + } + }, + methods: { + // 格式化最近时间 + formatTime(time) { + return formatTime(time) + }, + // 格式化文件大小 + formatSize(size) { + return formatSize(size) + }, + } +} diff --git a/src/components/ShowFile/mixins/fileContextmenu.js b/src/components/ShowFile/mixins/fileContextmenu.js new file mode 100644 index 0000000..044ade5 --- /dev/null +++ b/src/components/ShowFile/mixins/fileContextmenu.js @@ -0,0 +1,452 @@ +import api from '@/api/file-api' +import fileConfig from '@/utils/file-config' +import { directLinkSubMenus, fileOperations } from '@/utils/file-operations' +import { suffix } from '@/utils/file-type' + +export default { + props: { + singleMenus: { + type: Array, + default: function() { + return [ + fileOperations.open, + { iconClass: 'link', label: '直链', operation: 'directLink', child: directLinkSubMenus }, + fileOperations.download, + { iconClass: 'share', label: '分享...', operation: 'share' }, + { iconClass: 'tag', label: '标签...' , operation: 'tag'}, + { iconClass: 'menu-favorite', label: '收藏', operation: 'favorite' }, + fileOperations.detail, + fileOperations.copyOnly, + fileOperations.rename, + fileOperations.copy, + fileOperations.remove, + ] + }, + }, + multipleRightMenus: { + type: Array, + default: function() { + return [ + { + iconClass: 'menu-deselect', + label: '取消选定', + operation: 'deselect', + }, + fileOperations.download, + { iconClass: 'tag', label: '标签', operation: 'tag' }, + fileOperations.copyOnly, + fileOperations.copy, + fileOperations.remove, + ] + }, + }, + }, + data() { + return { + isJustHideMenus: false, + menusIsMultiple: false, + menus: [], + rowContextData: {}, + } + }, + methods: { + contextmenu(e) { + e.preventDefault() + e.stopPropagation() + }, + show() { + const that = this + this.contextmenuDisabled = true + setTimeout(function() { + that.contextmenuDisabled = false + }, 1000) + }, + hide() { + const that = this + this.isJustHideMenus = true + setTimeout(function() { + that.isJustHideMenus = false + }, 100) + this.cellMouseIndex = -1 + }, + setMenus(row) { + this.menus = JSON.parse(JSON.stringify(this.singleMenus)) + // 挂载的文件 + const owner = localStorage.getItem('mountFileOwner') + const notSelf = row.userId && row.userId !== this.$store.getters.userId + if ((this.$route.query.folder && owner) || notSelf) { + // 根据权限设置菜单 + this.setMenusByPermission(row) + } else { + if (row.suffix && row.suffix === 'md' && this.queryFileType !== 'trash') { + this.menus.splice(this.getIndexOfFileContextMenus(fileOperations.copyOnly.operation), 0, { + iconClass: 'menu-edit1', + label: '编辑', + operation: 'edit', + }) + } + if (row.isFolder && row.mountFileId) { + const reservations = ['open', 'tag', 'favorite', 'remove'] + // 删除this.menus中不要的菜单, 仅保留reservations中的菜单 + this.menus = this.menus.filter(item => + reservations.includes(item.operation) + ) + } + if (!row.isFolder && this.queryFileType !== 'trash') { + // 创建副本 + const copyIndex = this.getIndexOfFileContextMenus(fileOperations.copy.operation) + if (copyIndex > -1) { + this.menus.splice(copyIndex, 0, fileOperations.duplicate) + } + } + if (row.ossFolder) { + const reservations = ['open', 'tag'] + // 删除this.menus中不要的菜单, 仅保留reservations中的菜单 + this.menus = this.menus.filter(item => + reservations.includes(item.operation) + ) + } + this.setMenusCopyDownLoadLinks(row) + } + this.preliminaryRowData(row) + }, + setFileContextMenusDivider() { + // 下载栏下面添加分隔符 + const downloadIndex = this.getIndexOfFileContextMenus(fileOperations.download.operation) + if (downloadIndex > -1 && this.menus.length - 1 > downloadIndex && !this.menus[downloadIndex + 1].divider) { + this.menus.splice(downloadIndex + 1, 0, { divider: true, operation: 'divider' }) + } + // 删除栏上面添加分隔符 + const removeIndex = this.getIndexOfFileContextMenus(fileOperations.remove.operation) + if (removeIndex > 0 && !this.menus[removeIndex - 1].divider) { + this.menus.splice(removeIndex, 0, { divider: true, operation: 'divider' }) + } + // 详情栏下面添加分隔符 + const detailIndex = this.getIndexOfFileContextMenus(fileOperations.detail.operation) + if (detailIndex > -1 && this.menus.length - 1 > detailIndex && !this.menus[detailIndex + 1].divider) { + this.menus.splice(detailIndex + 1, 0, { divider: true, operation: 'divider' }) + } + }, + getIndexOfFileContextMenus(operation) { + return this.menus.findIndex(item => item.operation === operation) + }, + setMenusCopyDownLoadLinks(row) { + if (row.isShare) { + // 获取this.menus中download的索引 + const downloadIndex = this.menus.findIndex( + item => item.operation === 'download' + ) + this.shareToken = undefined + // 在download之前添加复制下载链接选项 + this.addMenusCopyDownLoadLinks(downloadIndex) + if (row.isPrivacy) { + // 如果是私密分享需要先获取shareToken + api.generateShareToken({fileId: row.id}).then(res => { + this.shareToken = res.data + }).catch(() => { + this.menus.splice(downloadIndex, 1) + }) + } + } + }, + addMenusCopyDownLoadLinks(index) { + this.menus.splice(index, 0, { + iconClass: 'menu-fuzhi', + label: '复制下载链接', + operation: 'copyDownloadLink', + }) + }, + setMenusByPermission(file) { + const reservations = ['open', 'download', 'details'] + // 删除this.menus中不要的菜单, 仅保留reservations中的菜单 + this.menus = this.menus.filter(item => + reservations.includes(item.operation) + ) + if (file.operationPermissionList && file.operationPermissionList.length > 0) { + if (file.operationPermissionList.indexOf('PUT') > -1) { + this.menus.splice(this.menus.length, 0, fileOperations.rename) + } + if (file.operationPermissionList.indexOf('UPLOAD') > -1) { + if (file.operationPermissionList.indexOf('DELETE') > -1) { + this.menus.splice(this.menus.length, 0, fileOperations.copy) + this.menus.splice(this.menus.length, 0, fileOperations.copyOnly) + } + if (!file.isFolder) { + this.menus.splice(this.menus.length, 0, fileOperations.duplicate) + } + } + if (file.operationPermissionList.indexOf('DELETE') > -1) { + this.menus.splice(this.menus.length, 0, fileOperations.remove) + } + } + this.setMenusCopyDownLoadLinks(file) + }, + // 鼠标右击 + rowContextmenu(row) { + this.$refs.homeContextmenu.hide() + if (this.selectFile) { + return + } + if ( + this.$refs.fileListTable.tableSelectData.length > 1 && + this.$refs.fileListTable.tableSelectData.findIndex(item => item.index === row.index) > -1 + ) { + this.menusIsMultiple = true + this.menus = JSON.parse(JSON.stringify(this.multipleRightMenus)) + this.highlightFavorite(false, false) + } else { + this.fileListTableClearSelection() + this.$refs.fileListTable.toggleRowSelection([{ row: row }]) + this.menusIsMultiple = false + this.setMenus(row) + } + + // 设置分割线 + this.setFileContextMenusDivider() + + event.preventDefault() + event.stopPropagation() + const e = {} + e.pageX = event.pageX + 5 + e.pageY = event.pageY + 20 + e.clientX = event.clientX + 50 + e.clientY = event.clientY + 2 + e.top = event.clientY + e.left = event.clientX + 2 + + const dividerSize = this.menus.filter(item => item.divider).length + + const containerWidth = 180 + 10 + const containerHeight = (this.menus.length - dividerSize) * 35 + (dividerSize * 11) + 18 + 10 + const distanceToBottom = document.documentElement.clientHeight - event.clientY + const distanceToRight = document.documentElement.clientWidth - event.clientX + + if (distanceToBottom < containerHeight) { + e.top = event.clientY - (containerHeight - distanceToBottom) + } + if (distanceToRight < containerWidth) { + e.left = event.clientX - containerWidth + 8 + } + + this.$refs.contextShow.showMenu(e) + this.cellMouseIndex = -1 + }, + // 列表右键菜单操作 + menusOperations(operation, event) { + switch (operation) { + case 'share': + // 分配标签 + this.share() + break + case 'tag': + // 分配标签 + this.allocateTag() + break + case 'favorite': + // 收藏 + this.favoriteOperating(true) + break + case 'edit': + // 编辑 + window.open( + `/setting/website/manager-articles?operation=editor&id=${this.rowContextData.id}`, + '_blank' + ) + break + case 'open': + // 打开 + this.fileClick(this.rowContextData, event) + break + case 'deselect': + // 取消选定 + this.fileListTableClearSelection() + break + case 'unFavorite': + // 取消收藏 + this.favoriteOperating(false) + break + case 'details': + this.drawer = true + break + case 'rename': + // 重命名 + this.renameFileName = this.rowContextData.name + this.editingIndex = this.rowContextData.index + break + case 'duplicate': + // 创建副本 + this.duplicate() + break + case 'copy': + // 移动或复制 + this.moveOrCopy() + break + case 'copyOnly': + this.copyOperation() + break + case 'download': + // 下载 + this.downloadFile() + break + case 'copyDownloadLink': + // 复制下载链接 + this.copyDownloadLink(this.rowContextData) + break + case 'remove': + // 删除 + this.removeOperation() + break + case 'sweep': + // 清空回收站 + this.sweepFile() + break + case 'restore': + // 返回原处 + this.restoreFile() + break + case 'manageDirectLink': + // 管理直链 + this.directLinkDialogVisible = true + this.directLinkDialogGetDirectLink(this.rowContextData) + break + case 'copyDirectLink': + // 复制直链 + this.directLinkDialogGetDirectLink(this.rowContextData, true) + break + } + this.$refs.contextShow.hideMenu() + }, + // 点击文件或文件夹 + fileClick(row, event) { + this.drawer = false + if (this.queryFileType === 'trash') { + return + } + if (this.editingIndex === row.index) { + return + } + this.openingFile = row + if (row.isFolder) { + this.editingIndex = -1 + const queryTagId = this.$route.query.tagId ? `&tagId=${this.$route.query.tagId}` : '' + const keyword = this.$route.query.keyword ? `&keyword=${this.$route.query.keyword}` : '' + // 打开文件夹 + if (this.listModeSearch) { + const item = {} + item['folder'] = row.name + item['search'] = true + item['row'] = row + this.pathList.push(item) + this.pagination.pageIndex = 1 + const searchOpenFolder = row.id ? `&searchOpenFolder=${row.id}` : '' + const path = this.$route.query.path ? `&path=${this.$route.query.path}` : '' + const folder = this.$route.query.folder ? `&folder=${this.$route.query.folder}` : '' + const basePath = this.getBasePath() + this.$router.push( + `?vmode=${ + this.vmode + }${path}${keyword}${searchOpenFolder}${folder}${queryTagId}${basePath}` + ) + this.searchFileAndOpenDir(row.id) + } else { + let notHomePage = this.$route.path.length > 1 + if ( + notHomePage && + this.path + '/' !== row.path && + this.basePath.length === 1 + ) { + this.basePath = row.path + } + + this.path += '/' + row.name + this.path = this.path.replace(/\\/g, '/') + this.path = this.path.replace(/\/\//g, '/') + // 去掉this.path开头的this.basePath + this.path = this.path.replace(this.basePath, '/') + const path = encodeURIComponent(this.path) + const item = { folder: row.name, shareBase: row.shareBase } + this.pathList.push(item) + this.pagination.pageIndex = 1 + if (this.$store.getters.userId !== row.userId) { + row.mountFileId = row.id + } + if (row.mountFileId) { + localStorage.setItem(this.path, row.mountFileId) + } + const basePath = this.basePath && this.basePath.length > 1 ? `&basePath=${this.basePath}` : '' + const searchOpenFolder = this.$route.query.searchOpenFolder ? `&searchOpenFolder=${this.$route.query.searchOpenFolder}` : '' + this.$router.push(`?vmode=${this.vmode}&path=${path}${row.mountFileId ? '&folder=' + row.mountFileId : ''}${queryTagId}${basePath}${keyword}${searchOpenFolder}`) + this.openDir(row) + } + } else { + if (this.selectFile) { + let selectFile = row + const selectData = this.$refs.fileListTable.tableSelectData + if (selectData.length < 1 || selectData[0].id !== row.id) { + this.fileListTableClearSelection() + this.$refs.fileListTable.toggleRowSelection([{ row: row }]) + this.pinSelect(row, event) + } else { + this.fileListTableClearSelection() + selectFile = {} + } + this.$emit('selectedFile', selectFile) + return + } + const fileHandler = fileConfig.hasIframePreview(row.suffix, this.$store.getters.iframePreviewConfig) + if (fileHandler !== null) { + // iframe 预览 + this.iframePreviewVisible = true + this.iframePreviewRow = row + this.fileHandler = fileHandler + return + } + if (row.contentType.startsWith('image')) { + // 图片 + this.imagePreviewVisible = true + this.imagePreviewRow = row + return + } + if (suffix.simText.includes(row.suffix)) { + // 文本文件 + this.textPreviewRow = row + this.textPreviewVisible = true + return + } + if (row.contentType.indexOf('video') > -1) { + // 视频文件 + this.videoPreviewVisible = true + this.videoPreviewRow = row + return + } + if (row.contentType.indexOf('audio') > -1) { + // 音频文件 + this.$store.dispatch('updateMessage', { + event: 'onAddAudio', + data: { row: row, audioCoverUrl: this.audioCoverUrl }, + }) + return + } + if (suffix.compressedFile.includes(row.suffix)) { + // 压缩文件 + this.openCompressionVisible = true + return + } + if (row.contentType.indexOf('office') > -1 || suffix.iframePreviewFile.includes(row.suffix)) { + // iframe 预览 + this.iframePreviewVisible = true + this.iframePreviewRow = row + this.fileHandler = {} + return + } + if (row.contentType.indexOf('utf-8') > -1) { + // 文本文件 + this.textPreviewRow = row + this.textPreviewVisible = true + return + } + this.notPreviewDialogVisible = true + } + }, + } +} diff --git a/src/components/ShowFile/mixins/fileDrag.js b/src/components/ShowFile/mixins/fileDrag.js new file mode 100644 index 0000000..b0ddc45 --- /dev/null +++ b/src/components/ShowFile/mixins/fileDrag.js @@ -0,0 +1,738 @@ +import { getElementToPageLeft } from '@/utils/dom' + +export default { + data() { + return { + dragElementList: [], + drawFlag: false, + draging: 0, // 是否正在拖拽中,0:没有拖拽,1:拖拽中, + selectRowData: [], + selectOrigin: -1, // 选择起点(主要用于按住shift键多选) + selectEnd: -1, // 选择终点 + inputting: false, // 是否正在输入 + fileListScrollTop: 0, + initFileListScrollTop: 0, + } + }, + methods: { + // 画矩形选区 + drawRectangle() { + let scrollDiv = this.$refs.fileListTableContainer.querySelector('.el-table__body-wrapper') + if (this.grid) { + scrollDiv = this.$refs.gridDiv.querySelector('.van-grid') + } + // 添加scroll事件 + scrollDiv.onscroll = e => { + this.tableBodyScroll(null, e) + } + + if (this.selectFile) { + return + } + const _this = this + let $$ = function(id) { + return document.getElementById(id) + } + let draw = $$('v-draw-rectangle') + let wId = 'rectangle1' + let startX = 0, + startY = 0 + let retcLeft = 0, + retcTop = 0, + retcHeight = 0, + retcWidth = 0 + _this.drawFlag = false + let itemClassName = 'el-table__row' + if (_this.grid) { + itemClassName = + 'grid-item van-grid-item__content van-grid-item__content--center van-grid-item__content--square' + } + draw.onmousedown = null + draw.onmousedown = function(e) { + let evt = window.event || e + const elPath = e.path || (e.composedPath && e.composedPath()) + // 列表模式下点击表头,阻止点击事件 + if (!_this.grid && _this.selectRowData.length > 0) { + const findIndex = elPath.findIndex(path => { + if (path.className === 'el-table__header-wrapper') { + return path + } + }) + if (findIndex > -1) { + _this.stopSortChange = true + } + } + // 点击的区域是否为文件, throughRow 不为空就证明点到了文件 + let throughRow = elPath.find(path => { + if (path.className === itemClassName || path.className === 'el-table__row el-table__row--striped') { + return path + } + }) + if (throughRow) { + // 鼠标按下时就选中文件 + if (!_this.selectRowData.includes(_this.fileList[throughRow.rowIndex])) { + _this.editingIndex = -1 + if (!_this.checkCmdKey(e) && !e.shiftKey) { + _this.fileListTableClearSelection() + _this.$refs.fileListTable.toggleRowSelection([ + { row: _this.fileList[throughRow.rowIndex], selected: true }, + ]) + } + } + return + } else { + _this.editingIndex = -1 + } + if (evt.button !== 0) { + return + } + if (!_this.checkCmdKey(e) && !e.shiftKey) { + const index = elPath.findIndex( + el => + el.className === itemClassName || + el.className === 'el-table__row el-table__row--striped' + ) + if (index < 0) { + _this.fileListTableClearSelection() + } + } + let scrollTop = draw.scrollTop || draw.scrollTop + let scrollLeft = draw.scrollLeft || draw.scrollLeft + startX = evt.clientX + scrollLeft + startY = evt.clientY + scrollTop + + let div = document.createElement('div') + div.id = wId + div.className = 'draw-rectangle' + div.style.left = startX + 'px' + div.style.top = startY + 'px' + div.style.position = 'fixed' + div.style.border = '1px dashed #2898ff' + div.style.width = '0px' + div.style.height = '0px' + div.style.left = '0px' + div.style.top = '0px' + div.style.overflow = 'hidden' + draw.appendChild(div) + document.onmousemove = function(e) { + let evt = window.event || e + let scrollTop = + document.body.scrollTop || document.documentElement.scrollTop + let scrollLeft = + document.body.scrollLeft || document.documentElement.scrollLeft + retcLeft = + startX - evt.clientX - scrollLeft > 0 + ? evt.clientX + scrollLeft + : startX + retcTop = + startY - evt.clientY - scrollTop > 0 + ? evt.clientY + scrollTop + : startY + retcHeight = Math.abs(startY - evt.clientY - scrollTop) + retcWidth = Math.abs(startX - evt.clientX - scrollLeft) + _this.drawFlag = true + if (retcHeight + retcWidth < 4) { + return + } + const drawRectangle = document.getElementById(wId) + if (drawRectangle) { + drawRectangle.style.left = retcLeft + 'px' + drawRectangle.style.top = retcTop + 'px' + drawRectangle.style.width = retcWidth + 'px' + drawRectangle.style.height = retcHeight + 'px' + drawRectangle.style.backgroundColor = '#f2f5fa55' + } + if (_this.drawFlag && retcHeight + retcWidth > 4) { + if (!drawSelecting) { + drawSelect({ + x: retcLeft, + y: retcTop + _this.fileListScrollTop, + w: retcWidth, + h: retcHeight, + }) + } + } + } + document.onmouseup = function(e) { + document.onmousemove = null + document.onmouseup = null + if (_this.stopSortChange) { + _this.stopSortChange = false + setTimeout(() => { + _this.changeSelectedStyle(_this.selectRowData) + }, 200) + } + setTimeout(function() { + _this.drawFlag = false + }, 50) + const rectangle = document.getElementById(wId) + if (rectangle) { + draw.removeChild(rectangle) + } + if (!_this.grid) { + draw = document.getElementById('drag-table') + } + const dragingDivs = Array.prototype.slice.call( + draw.getElementsByClassName('dragingDiv') + ) + dragingDivs.forEach(el => draw.removeChild(el)) + } + } + + let drawSelecting = false + let drawSelect = function(drawNode) { + drawSelecting = true + _this.dragElementList.forEach(element => { + if (checkTouch(element, drawNode)) { + _this.$refs.fileListTable.toggleRowSelection([ + { row: _this.fileList[element.rowIndex], selected: true }, + ]) + } else { + _this.$refs.fileListTable.toggleRowSelection([ + { row: _this.fileList[element.rowIndex], selected: false }, + ]) + } + }) + setTimeout(() => (drawSelecting = false), 10) + } + //检查两个DIV是否有接触 + let checkTouch = function(item, draw) { + //得到左上角的绝对坐标 + let x1 = item.x + let y1 = item.y + let x2 = draw.x + let y2 = draw.y + let w1 = item.w + let h1 = item.h + let w2 = draw.w + let h2 = draw.h + return ( + ((x1 - x2 <= 0 && x2 - x1 < w1) || (x1 - x2 >= 0 && x1 - x2 < w2)) && + ((y1 - y2 <= 0 && y2 - y1 < h1) || (y1 - y2 >= 0 && y1 - y2 < h2)) + ) + } + }, + // 行拖拽 + rowDrop() { + if (this.selectFile) { + return + } + // 目标元素的背景颜色 + let dragEnterBackCorlor = null + // 被拖拽元素的背景色 + let dragBackCorlor = null + const _this = this + // 被拖动的元素 + let dragged = null + // 被拖动的元素的索引 + let draggedIndex = -1 + + let parentClassName = 'van-grid' + let itemClassName = 'van-grid-item van-grid-item--square' + let gridItemChildenClassName = + 'grid-item van-grid-item__content van-grid-item__content--center van-grid-item__content--square' + if (!_this.grid) { + itemClassName = 'el-table__row' + parentClassName = 'el-table__body' + } + + // 正在拖动的元素 + let dragingDiv = null + + let container = document.querySelector('.dashboard-container') + + // 目标元素 + let target = document.querySelector('.el-table__body-wrapper tbody') + if (this.grid) { + target = document.querySelector('.van-checkbox-group .van-grid') + } + let draw = document.getElementById('v-draw-rectangle') + if (!this.grid) { + draw = document.getElementById('drag-table') + } + let rows = 0 //行数 + + let drawOffsetLeft = getElementToPageLeft(draw) + + let firstOver = 0 // 是否刚开始拖动 + let moveTitle = '' + setTimeout(function() { + rows = target.childElementCount + _this.dragElementList = [] + for (let i = 0; i < target.childElementCount; i++) { + let child = target.children[i] + // 设置索引,表格自带rowIndex,这里我们设置grid的 + if (_this.grid) { + if (child.rowIndex !== i) { + child.rowIndex = i + } + child.children[0].children[0].rowIndex = i + child = child.children[0].children[0] + } + // 为画矩形选取准备数据 + let pos = getObjPos(child) + child.w = child.offsetWidth + child.h = child.offsetHeight + child.x = pos.x + child.y = pos.y + pos.rowIndex = child.rowIndex + _this.dragElementList.push(child) + + // 使元素可拖动 + child.draggable = true + // 给能拖动的元素加上标识,只有加上此标识才能被拖动,否则即使draggable = true,也无法拖动(在全局的ondragstart里拦截) + child.slot = 'jmal' + let childOfImg = child.querySelector('.el-avatar > img') + if (_this.grid) { + childOfImg = child.querySelector('.el-image > img') + } + if (childOfImg) { + childOfImg.draggable = false + } + } + }, 300) + + // 被拖动的元素正在那个容器里 + let dragIndex = -1 + + // 判断经过了那个元素 + let judgThroughDom = function(e, d) { + const elPath = e.path || (e.composedPath && e.composedPath()) + if (d === 'enter') { + // 这里进入其他容器后 清除上次进入的容器的状态 + let node = null + const className = e.toElement.className + if (_this.grid) { + if (e.toElement.className === itemClassName) { + node = e.toElement + } + if (e.toElement.className === parentClassName) { + node = e.fromElement + } + } else { + // 列表模式 + if ( + elPath[0].id === 'v-draw-rectangle' || + elPath[0].className === 'el-table__virtual-wrapper' + ) { + // 超出列表底部 + node = e.toElement + } else { + // 超出列表顶部 + node = elPath.find(path => { + if (path.className === 'el-table__header-wrapper') { + return path + } + }) + } + } + if (node) { + // console.log(d,e,node,node.rowIndex) + if (dragIndex > -1) { + // 清除上次进入的容器的状态 + const last = target.children[dragIndex] + clearClass(last) + } + dragIndex = -1 + } + } + let throughRow = null + if (_this.grid) { + if (elPath[0].className === gridItemChildenClassName) { + // throughRow 表示被拖动的元素正在哪一行上 + return throughRow + } else { + throughRow = elPath.find(path => { + if (path.className === gridItemChildenClassName) { + return path + } + }) + } + return throughRow + } else { + if (elPath[0].tagName === 'TD') { + // throughRow 表示被拖动的元素正在哪一行上 + throughRow = elPath.find(path => { + if ( + path.className === 'el-table__row el-table__row--striped' || + path.className === 'el-table__row' + ) { + return path + } + }) + } + return throughRow + } + } + + /*** + * 复原拖拽的dom + * @param animation 是否显示动画 + */ + let recoverDragDom = function(animation) { + if (animation) { + _this.selectRowData.forEach(row => { + let dragingDiv = document.getElementById('dragingDiv' + row.index) + dragingDiv.style.transition = 'all 0.3s' + dragingDiv.style.top = + dragingDiv.original.top - + (_this.fileListScrollTop - _this.initFileListScrollTop) + + 'px' + dragingDiv.style.left = dragingDiv.original.left + }) + setTimeout(() => { + _this.selectRowData.forEach(row => { + draw.removeChild( + document.getElementById('dragingDiv' + row.index) + ) + }) + }, 300) + } else { + _this.selectRowData.forEach(row => { + draw.removeChild(document.getElementById('dragingDiv' + row.index)) + }) + } + setTimeout(() => { + if (!_this.grid) { + document + .getElementsByClassName('el-table')[0] + .classList.add('el-table--enable-row-hover') + } else { + target.querySelectorAll('.grid-hover-back').forEach(e => { + e.classList.add('grid-hover') + }) + } + }, 350) + _this.draging = 0 + } + + container.ondragend = function(e) { + _this.$store.dispatch('updateMessage', { + event: 'onDragStart', + data: false, + }) + e.dataTransfer.effectAllowed = 'none' + // 清除上次进入的容器的状态 + const last = target.children[dragIndex] + clearClass(last) + dragged.style.cursor = 'default' + e.target.parentNode.parentNode.title = moveTitle + } + // 开始拖拽 + container.ondragstart = e => { + if (this.queryFileType === 'trash') { + e.preventDefault() + e.stopPropagation() + return false + } + // 正在选区获取按住关键键时禁止拖拽 + if (_this.drawFlag || _this.checkCmdKey(e) || e.shiftKey) { + e.preventDefault() + e.stopPropagation() + return + } + // 判断被拖拽dom是否有slot属性并且等于'jmal' + if (!e.target.slot || e.target.slot !== 'jmal') { + return true + } + // 该文件正在重命名 + if (e.target.rowIndex === _this.editingIndex) { + e.preventDefault() + e.stopPropagation() + return + } + e.target.style.cursor = 'no-drop' + // 复制被拖拽dom的title, 拖拽过程中移除, 拖拽完后还原 + moveTitle = e.target.parentNode.parentNode.title + e.target.parentNode.parentNode.title = '' + // 创建拖拽时的dom, 克隆自被拖拽dom + _this.selectRowData.forEach((row, index) => { + const element = _this.dragElementList[row.index] + const rowIndex = element.rowIndex + dragingDiv = element.cloneNode(true) + dragingDiv.id = 'dragingDiv' + rowIndex + dragingDiv.classList.add('dragingDiv') + dragingDiv.classList.remove('el-table_row') + dragingDiv.style.transition = 'all 0.3s' + dragingDiv.style.zIndex = -1 + dragingDiv.style.position = 'absolute' + const pos = _this.dragElementList[rowIndex] + dragingDiv.style.width = pos.w + 'px' + dragingDiv.style.height = pos.h + 'px' + dragingDiv.style.left = pos.x - drawOffsetLeft + 'px' + let dragingDivStyleTop = 0 + if (!_this.grid) { + dragingDiv.firstChild.style.textAlign = 'center' + let tds = Array.prototype.slice.call(dragingDiv.childNodes) + tds.forEach((node, index) => { + if (index === 0) { + node.firstChild.style.margin = '0 20px' + } + if (index === 1) { + node.firstChild.style.width = '280px' + node.firstChild.style.marginRight = '20px' + } + if (index === 2) { + node.style.borderRadius = '0 12px 12px 0' + node.style.borderRight = 'solid 1px var(--apple-shadow-color)' + node.firstChild.style.height = '44px' + node.firstChild.style.lineHeight = '44px' + node.firstChild.style.width = '80px' + return true + } + if (index === 3) { + dragingDiv.removeChild(node) + } + }) + dragingDivStyleTop = pos.y - _this.fileListScrollTop - 51.5 + } else { + dragingDivStyleTop = pos.y - _this.fileListScrollTop - pos.h / 2 + 10 + } + dragingDiv.style.top = dragingDivStyleTop + 'px' + if (index === 0) { + let numberFilesCopy = document + .getElementById('numberFiles') + .cloneNode(true) + numberFilesCopy.id = 'numberFilesCopy' + numberFilesCopy.querySelector('.number').innerHTML = + _this.selectRowData.length + '个文件' + dragingDiv.appendChild(numberFilesCopy) + } + dragingDiv.original = { + top: dragingDivStyleTop, + left: dragingDiv.style.left, + } + _this.initFileListScrollTop = _this.fileListScrollTop + draw.appendChild(dragingDiv) + }) + firstOver = 0 + let dragImage = document.getElementById('dragImage') + e.dataTransfer.setDragImage(dragImage, 10, 10) + _this.$store.dispatch('updateMessage', { + event: 'onDragStart', + data: true, + }) + // 避免和画矩形选区冲突 + _this.drawFlag = false + let rectangle = document.getElementById('rectangle1') + if (rectangle) { + document.getElementById('v-draw-rectangle').removeChild(rectangle) + } + dragged = e.target + draggedIndex = dragged.rowIndex + // 只有选中的才能拖拽 + _this.cellMouseIndex = -1 + dragBackCorlor = dragged.style.backgroundColor + + if (!_this.grid) { + document + .getElementsByClassName('el-table--enable-row-hover')[0] + .classList.remove('el-table--enable-row-hover') + } else { + target.querySelectorAll('.grid-hover-back').forEach(e => { + e.classList.remove('grid-hover') + }) + } + _this.draging = 1 + } + container.ondragenter = function(e) { + clearTimeout(loop) + // 由于被拖动的元素 经过区域内中的每一元素都会触发该事件, 但是我们只需要它正在那一行上就行了 + let throughRow = judgThroughDom(e, 'enter') + if (throughRow) { + if (dragIndex !== throughRow.rowIndex) { + if (dragIndex > -1) { + // 清除上次进入的容器的状态 + const last = target.children[dragIndex] + clearClass(last) + } + // console.log('拖动进入目标元素'+throughRow.rowIndex,'dragIndex:',dragIndex); + // 不是自己或为文件夹时才改变状态 + if ( + draggedIndex !== throughRow.rowIndex && + _this.fileList[throughRow.rowIndex].isFolder && + _this.selectRowData.findIndex( + item => item.index === throughRow.rowIndex + ) === -1 + ) { + // 改变本次进入的容器的状态 + dragged.style.cursor = 'copy' + + let numberFilesCopy = document.getElementById('numberFilesCopy') + numberFilesCopy.style.backgroundColor = '#40a9ffc9' + numberFilesCopy.querySelector('.number').style.display = 'none' + numberFilesCopy.querySelector('.icon').style.display = 'inline' + numberFilesCopy.querySelector('.operate').style.display = 'inline' + let targetFolder = numberFilesCopy.querySelector( + '.target .folder' + ) + targetFolder.style.display = 'inline' + targetFolder.innerHTML = _this.fileList[throughRow.rowIndex].name + + dragEnterBackCorlor = throughRow.style.backgroundColor + // 当拖拽文件夹上时,文件夹当背景色 + const color = '#9fcdfc99' + if (_this.grid) { + throughRow.style.backgroundColor = color + } else { + throughRow.childNodes.forEach( + node => (node.style.backgroundColor = color) + ) + } + } + dragIndex = throughRow.rowIndex + } + leaveIndex = -1 + } + } + + container.ondragover = function(e) { + _this.selectRowData.forEach((row, index) => { + const drawRectangle = document.getElementById( + 'dragingDiv' + row.index + ) + if (drawRectangle) { + drawRectangle.style.left = + e.clientX - drawOffsetLeft + index * 3 + 10 + 'px' + drawRectangle.style.top = e.clientY - 50 + index * 3 + 10 + 'px' + if (firstOver === 0) { + drawRectangle.style.zIndex = 999 + setTimeout(() => { + drawRectangle.style.transition = '' + }, 300) + } + } + }) + e.preventDefault() + leaveIndex = -1 + firstOver++ + } + + let loop = null + let leaveIndex = -1 // 是否拖出了整个table, -1表示还在table内 + + container.ondragleave = function(e) { + clearTimeout(loop) + let throughRow = judgThroughDom(e, 'leave') + if (throughRow) { + if (!_this.grid) { + if (throughRow.rowIndex === 0 || throughRow.rowIndex === rows - 1) { + // 离开第一行或最后一行 + leaveIndex = throughRow.rowIndex + loop = setTimeout(function() { + if (leaveIndex > -1) { + const leave = target.children[leaveIndex] + clearClass(leave) + dragIndex = -1 + } + }, 100) + } + } + } + } + container.ondrop = function() { + const form = _this.fileList[draggedIndex] + const to = _this.fileList[dragIndex] + if ( + form && + to && + form.id !== to.id && + to.isFolder && + !_this.selectRowData.includes(to) + ) { + // 移动文件/文件夹 + let forms = [] + _this.selectRowData.forEach(row => { + forms.push(row.id) + }) + _this + .$confirm( + `是否将选中的${_this.selectRowData.length}项移动到 ${to.name}?`, + '提示', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'info', + } + ) + .then(() => { + _this.checkCopyOrMoveApi('move', forms, to.id, to.name) + recoverDragDom(false) + }) + .catch(() => { + recoverDragDom(true) + }) + } else { + recoverDragDom(true) + } + } + // 清除之前的样式 + let clearClass = function(node) { + if (!dragged) { + return + } + if (node) { + if (_this.grid) { + node = node.children[0].children[0] + // #9fcdfc99 + if (node.style.backgroundColor === 'rgba(159, 205, 252, 0.6)') { + node.style.backgroundColor = null + } + } else { + // #9fcdfc99 + if ( + node.firstChild.style.backgroundColor === + 'rgba(159, 205, 252, 0.6)' + ) { + node.childNodes.forEach(node => { + node.style.backgroundColor = null + }) + } + } + dragged.style.cursor = 'default' + + let numberFilesCopy = document.getElementById('numberFilesCopy') + if (numberFilesCopy) { + numberFilesCopy.style.backgroundColor = '#d2eefa66' + numberFilesCopy.querySelector('.number').style.display = 'inline' + numberFilesCopy.querySelector('.icon').style.display = 'none' + numberFilesCopy.querySelector('.operate').style.display = 'none' + numberFilesCopy.querySelector('.target .folder').style.display = + 'none' + } + } + dragged.style.backgroundColor = dragBackCorlor + } + + function getObjPos(obj) { + let pos = { x: 0, y: 0 } + while (obj) { + pos.x += obj.offsetLeft + pos.y += obj.offsetTop + obj = obj.offsetParent + } + return pos + } + }, + tableBodyScroll(table, e) { + this.fileListScrollTop = e.target.scrollTop + let scrollBottom = e.target.scrollHeight - e.target.clientHeight - e.target.scrollTop + if (scrollBottom < (e.target.scrollHeight * 0.2)) { + if (!this.finished) { + if (!this.pageLoadCompleteList[this.pagination.pageIndex]) { + return + } + if (this.listModeSearch) { + if (this.listModeSearchOpenDir) { + this.searchFileAndOpenDir(this.listModeSearchOpenDir, true) + } else { + this.searchFile(this.searchFileName, true) + } + } else { + this.getFileListEnter(true) + } + } + } + }, + } +} diff --git a/src/components/ShowFile/mixins/fileHandel.js b/src/components/ShowFile/mixins/fileHandel.js new file mode 100644 index 0000000..8ce960c --- /dev/null +++ b/src/components/ShowFile/mixins/fileHandel.js @@ -0,0 +1,876 @@ +import api from '@/api/file-api' +import fileConfig from '@/utils/file-config' +export default { + props: { + showUploadButton: { + type: Boolean, + default: true, + }, + }, + data() { + return { + newCreateFileDialog: false, + newCreateFileName: '', + newCreateFileDialogTitle: '', + createFileLoading: false, + renameFileName: '', + newFolderLoading: false, + renameLoading: false, + cellMouseIndex: -1, + editingIndex: -1, + titlePrefix: '', + unzipOperating: false, + dialogMoveOrCopyVisible: false, + fileTreeAndNewFolderDisabled: false, + directoryTreeData: [], + compressedFileVisible: false, + compressedFileData: [], + compressedFileName: '', + compressedFileTempDir: false, + selectTreeNode: {}, + directoryTreeProps: { + label: 'name', + children: 'children', + isLeaf: 'isLeaf', + }, + existsFileList: [], // 移动或复制存在的文件列表 + copyOrMoveConfirmVisible: false, // 移动或复制警告弹出框 + copyOrMoveParams: { + operating: 'copy', + froms: [], + to: '', + targetPath: '' + }, // 移动或复制要传递的参数 + copyOrMoveToName: '', // 移动或复制到的文件夹名称 + deleteConfirmVisible: false, // 删除确认弹窗 + permanentDelete: false, // 是否永久删除 + permanentDeleteDisable: false, // 是否禁用永久删除选项 + } + }, + methods: { + // 新建文件夹 + newFolderNameClick() { + if (this.newFolderName) { + if (/[\[\]\/\\"<>\?\*]/gi.test(this.newFolderName)) { + this.$message({ + message: '文件名不能包含以下字符:<,>,|,*,?,,/,[,]', + type: 'warning', + }) + return + } + this.newFolderLoading = true + this.createFileLoading = true + api.uploadFolder({ + isFolder: true, + filename: encodeURIComponent(this.newFolderName), + currentDirectory: this.getQueryPath(), + folder: this.$route.query.searchOpenFolder || this.$route.query.folder, + username: this.$store.state.user.name, + userId: this.$store.state.user.userId, + }) + .then(res => { + if (res.data === 1) { + this.newFolderLoading = false + this.$message({ + message: '该文件夹已存在', + type: 'warning', + }) + } else { + this.createFileLoading = false + this.newCreateFileDialog = false + this.newFolderLoading = false + this.showNewFolder = false + this.isShowNewFolder = false + this.$notify({ + title: '新建文件夹成功', + type: 'success', + duration: 1000, + }) + this.getFileListEnter() + } + }) + .catch(() => { + this.newFolderLoading = false + this.createFileLoading = false + }) + } else { + this.newFolderLoading = false + this.$message({ + message: '请输入文件夹名称', + type: 'warning', + }) + } + }, + // 新建文件 + createFile(newFileName) { + if (this.newCreateFileDialogTitle === '新建文件夹') { + this.newFolderName = newFileName + this.newFolderNameClick() + return + } + if (newFileName) { + if (/[\[\]\/\\"<>\?\*]/gi.test(newFileName)) { + this.$message({ + message: '文件名不能包含以下字符:<,>,|,*,?,,/,[,]', + type: 'warning', + }) + return + } + this.createFileLoading = true + let parentPath = '/' + if (this.path) { + if (this.path.length > 0) { + parentPath = this.path + } + } + let suffix = newFileName.substring(newFileName.lastIndexOf('.') + 1) + api.addFile({ + fileName: encodeURIComponent(newFileName), + isFolder: false, + folder: this.$route.query.searchOpenFolder || this.$route.query.folder, + username: this.$store.state.user.name, + parentPath: encodeURIComponent(parentPath), + }) + .then(res => { + this.createFileLoading = false + switch (suffix && !this.$route.query.folder) { + case 'txt': + // 打开编辑器 + this.textPreviewRow = res.data + this.textPreviewVisible = true + break + case 'drawio': + case 'mind': + case 'docx': + case 'xlsx': + case 'pptx': + this.iframePreviewRow = res.data + this.iframePreviewVisible = true + break + } + const that = this + this.setOnCreateFilename(newFileName) + setTimeout(function() { + that.newCreateFileDialog = false + }, 200) + }) + .catch(() => { + this.createFileLoading = false + }) + } + }, + // 新建文件 + createNewFile(suffix) { + if (this.newCreateFileDialogTitle === '新建文件夹') { + this.newCreateFileName = `新建文件夹` + } else { + this.newCreateFileName = `未命名文件.${suffix}` + } + this.newCreateFileName = this.getNewFileName( + this.fileList, + this.newCreateFileName + ) + this.newCreateFileDialog = true + this.$nextTick(() => { + let newFileNameInput = this.$refs.newCreateFileName.$el.querySelector( + '.el-input__inner' + ) + this.renameInputFocus(newFileNameInput, suffix) + }) + }, + newFolder() { + this.newFolderName = this.getNewFileName(this.fileList, '新建文件夹') + this.showNewFolder = true + this.$nextTick(() => { + this.$refs.newFolderName.focus() + this.$refs.newFolderName.select() + }) + }, + // 统计文件和文件夹 + getShowSumFileAndFolder(fileList) { + let folderSize = 0 + let fileSize = 0 + fileList.forEach(fileInfo => { + if (fileInfo.isFolder) { + folderSize += 1 + } else { + fileSize += 1 + } + }) + let folderSum = '' + if (folderSize > 0) { + folderSum = folderSize + '个文件夹' + } + let fileSum = '' + if (fileSize > 0) { + fileSum = fileSize + '个文件' + } + const stand = folderSize > 0 && fileSize > 0 ? '、' : '' + return folderSum + stand + fileSum + }, + // 计算总大小 + getShowSumSize(totalSize) { + let sizeSum = '' + if (totalSize < 1024) { + sizeSum += totalSize + 'B' + } else if (totalSize >= 1024 && totalSize < 1024 * 1024) { + sizeSum += (totalSize / 1024).toFixed(2) + 'K' + } else if (totalSize >= 1024 * 1024 && totalSize < 1024 * 1024 * 1024) { + sizeSum += (totalSize / (1024 * 1024)).toFixed(2) + 'M' + } else { + sizeSum += (totalSize / (1024 * 1024 * 1024)).toFixed(2) + 'G' + } + return sizeSum + }, + // 重命名 + rowRename(newFileName, row) { + //去掉回车换行 + newFileName = newFileName.replace(/[\r\n]/g, '') + if (newFileName) { + if (/[\[\]\/\\"<>\?\*]/gi.test(newFileName)) { + this.$message({ + message: '文件名不能包含以下字符:<,>,|,*,?,,/,[,]', + type: 'warning', + }) + return + } + let strFileName = newFileName.replace(/(.*\/)*([^.]+).*/gi, '$2') + let newExt = newFileName.replace(/.+\./, '') + if (!row.isFolder) { + if (row.suffix !== newExt) { + this.$confirm( + `您确定要将扩展名“.${row.suffix}”更改为“.${newExt}”吗?`, + '提示', + { + type: 'warning', + showClose: false, + closeOnClickModal: false, + confirmButtonText: `保持.${row.suffix}`, + cancelButtonText: `使用.${newExt}`, + } + ).then(() => { + newFileName = strFileName + '.' + row.suffix + }).catch(() => {}).then(() => { + this.rename(row, newFileName) + }) + } else { + this.rename(row, newFileName) + } + } else { + this.rename(row, newFileName) + } + } else { + this.editingIndex = -1 + } + }, + rename(row, newFileName) { + if (row.name === newFileName) { + this.editingIndex = -1 + return + } + this.renameLoading = true + const findIndex = this.fileList.findIndex(item => { + if (newFileName === item.name) { + return item + } + }) + if (findIndex > -1) { + let msg = '该文件已存在' + if (row.isFolder) { + msg = '该文件夹已存在' + } + this.$message({ + message: msg, + type: 'warning', + }) + this.renameLoading = false + return + } + api.rename({ + newFileName: encodeURIComponent(newFileName), + username: this.$store.state.user.name, + folder: this.$route.query.searchOpenFolder || this.$route.query.folder, + id: row.id, + }).then(() => { + this.renameLoading = false + row.name = newFileName + row.suffix = newFileName.replace(/.+\./, '') + this.fileList[row.index] = row + this.editingIndex = -1 + }).then(() => { + this.fileListTableClearSelection() + this.setOnCreateFilename(newFileName) + }).catch(() => { + this.renameLoading = false + this.editingIndex = -1 + }) + }, + // 选取输入框部分内容 + renameInputFocus(doc, suffix) { + this.setInputFocus() + doc.focus() + doc.selectionStart = 0 + doc.selectionEnd = doc.value.length + if (suffix) { + doc.selectionEnd -= suffix.length + 1 + } + }, + setOnCreateFilename(newFileName) { + if (this.$route.query.folder) { + this.onCreateFilename = newFileName + this.getFileListEnter() + this.clearOnCreateFilename() + } + }, + removeOperation() { + this.permanentDelete = false + this.selectFileList = this.getSelectFileList() + this.deleteConfirmVisible = true + }, + onCopy(fileIdList, targetPath, targetFolder) { + this.checkCopyOrMoveApi('copy', fileIdList, targetFolder, undefined, targetPath) + }, + onMove(fileIdList, targetPath, targetFolder) { + this.checkCopyOrMoveApi('move', fileIdList, targetFolder, undefined, targetPath) + }, + copyOperation() { + this.$store.dispatch('updateFileClipboard', this.getSelectFileList()) + }, + // 加载下一级文件树 + directoryTreeLoadNode(node, resolve) { + let fileId = null + if (node.level === 0) { + const that = this + setTimeout(function() { + that.$refs.directoryTree.setCurrentKey('0') + }, 0) + return resolve([{ id: '0', name: '根目录' }]) + } + if (node.level > 1) { + fileId = node.data.mountFileId || node.data.id + } + api.queryFileTree({ + userId: this.$store.state.user.userId, + username: this.$store.state.user.name, + fileId: fileId, + }).then(res => { + const nextNodes = res.data + return resolve(nextNodes) + }) + }, + // 点击文件树 + treeNodeClick(row, node, event) { + this.fileTreeAndNewFolderDisabled = row.hasOwnProperty('newFolder') + this.selectTreeNode = row + this.selectTreeNode.showName = ' "' + row.name + '"' + }, + // 节点被展开时触发 + treeNodeExpand(row, node, event) {}, + // 文件树里新建文件夹 + fileTreeAndNewFolder() { + let newNodeId = 'newFolderNodeKey' + let node = this.$refs.directoryTree.getNode(newNodeId) + if (node !== null) { + this.$refs.directoryTree.remove(node) + } + + let childNodes = this.$refs.directoryTree.store.currentNode.childNodes + let newFolderName = this.getNewFileName(childNodes, '新建文件夹') + let newNode = { + id: newNodeId, + newFolder: true, + name: newFolderName, + showName: newFolderName, + isLeaf: true, + } + this.$refs.directoryTree.append(newNode, this.selectTreeNode) + setTimeout(function() { + let treeInput = document.getElementById('treeInput') + if (treeInput) { + treeInput.value = newFolderName + treeInput.focus() + treeInput.select() + } + }, 100) + }, + // 移动文件 + moveFileTree() { + this.copyOrMove('move') + }, + // 复制文件 + copyFileTree() { + this.copyOrMove('copy') + }, + // 解压文件 + confirmUnzip() { + this.unzip(this.openingFile, this.selectTreeNode.id, false) + }, + showDialogMoveOrCopyVisible() { + this.dialogMoveOrCopyVisible = true + }, + /** + * 创建副本 + */ + duplicate() { + const newFilename = this.getDuplicateFileName( + this.fileList, + this.rowContextData.name + ) + api + .duplicateFile({ + fileId: this.rowContextData.id, + newFilename: newFilename, + }) + .then(() => { + this.$message.success('创建副本成功') + this.setOnCreateFilename(newFilename) + }) + }, + moveOrCopy() { + this.showDialogMoveOrCopyVisible() + + this.titlePrefix = '移动或复制到: ' + this.unzipOperating = false + const that = this + setTimeout(function() { + that.selectTreeNode = that.$refs.directoryTree.getCurrentNode() + that.selectTreeNode.showName = ' "' + that.selectTreeNode.name + '"' + }, 100) + }, + copyOrMove(operating) { + let operation = '复制' + if (operating === 'move') { + operation = '移动' + } + let selectNodePath = '/' + if (this.selectTreeNode.path) { + selectNodePath = + this.selectTreeNode.path + this.selectTreeNode.name + '/' + } + + let fileIds = [] + if (this.menusIsMultiple || this.selectRowData.length > 1) { + const exits = this.$refs.fileListTable.tableSelectData.some(value => { + fileIds.push(value.id) + const thisParentPath = value.path + if (thisParentPath === selectNodePath) { + this.$message({ + message: '不能将文件' + operation + '到自身或其子目录下', + type: 'warning', + }) + return true + } + }) + if (exits) { + return + } + } else { + if (this.rowContextData.id) { + fileIds.push(this.rowContextData.id) + } else { + fileIds.push(this.rowContextData[0].id) + } + } + this.checkCopyOrMoveApi(operating, fileIds, this.selectTreeNode.id, this.selectTreeNode.name) + }, + checkCopyOrMoveApi(operating, froms, to, toName, targetPath) { + if (!to && !targetPath) { + to = '0' + toName = '根目录' + } + if (targetPath) { + toName = path.basename(targetPath) + } + api['checkMoveOrCopy']({ + userId: this.$store.state.user.userId, + username: this.$store.state.user.name, + froms: froms, + to: to, + targetPath: targetPath + }).then((res) => { + if (res.count > 0) { + this.copyOrMoveConfirmVisible = true + this.copyOrMoveParams = {operating: operating, froms: froms, to: to, targetPath: targetPath} + this.copyOrMoveToName = `${(operating === 'copy' ? '复制' : '移动')}到: "${toName}"` + this.existsFileList = res.data + } else { + this.copyOrMoveApi(operating, froms, to, false, targetPath) + } + }) + }, + copyOrMoveApi(operating, froms, to, isOverride, targetPath) { + this.copyOrMoveConfirmVisible = false + let operation = '复制' + if (operating === 'move') { + operation = '移动' + } + let copying = this.$message({ + iconClass: 'el-icon-loading', + type: 'info', + duration: 0, + dangerouslyUseHTMLString: true, + message: operation + '中...', + }) + this.dialogMoveOrCopyVisible = false + api[operating]({ + userId: this.$store.state.user.userId, + username: this.$store.state.user.name, + froms: froms, + to: to, + targetPath: targetPath, + isOverride: isOverride + }).then(() => { + this.$refs.fileClipboard.clear() + copying.iconClass = null + copying.type = 'success' + copying.message = operation + '中...' + if (this.rowContextData.isFolder) { + this.$refs.directoryTree.append(this.rowContextData, to) + } + if (operating === 'move') { + // 移除列表 + this.getFileListEnter() + } + setTimeout(function() { + copying.close() + }, 1000) + }).catch(() => { + copying.close() + }) + }, + renderContent(h, { node, data, store }) { + if (data.newFolder) { + return ( + + + + + +
+ +
+