Merge pull request #243 from jamebal/search

feat: 添加复制粘贴快捷键
This commit is contained in:
jmal 2024-07-29 18:30:35 +08:00 committed by GitHub
commit 1b43be79dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 294 additions and 54 deletions

View File

@ -94,7 +94,7 @@ export default {
setTimeout(function () { setTimeout(function () {
that.$refs.directoryTree.setCurrentKey('0') that.$refs.directoryTree.setCurrentKey('0')
}, 0) }, 0)
return resolve([{'id': "0", 'name': '全部文件'}]) return resolve([{'id': "0", 'name': '根目录'}])
} }
if (node.level > 1) { if (node.level > 1) {
fileId = node.data.id fileId = node.data.id

View File

@ -152,7 +152,7 @@ export default {
directoryTreeLoadNode(node, resolve) { directoryTreeLoadNode(node, resolve) {
let fileId = null; let fileId = null;
if (node.level === 0) { if (node.level === 0) {
let data = [{ id: "0", name: "全部文件" }]; let data = [{ id: "0", name: "根目录" }];
const that = this; const that = this;
setTimeout(function() { setTimeout(function() {
that.$refs.fileTree.setCurrentKey("0"); that.$refs.fileTree.setCurrentKey("0");

View File

@ -58,4 +58,12 @@ export default {
} }
} }
} }
>>> .svg-icon {
font-size: 28px;
}
>>> .el-avatar {
width: 28px;
height: 28px;
line-height: 28px;
}
</style> </style>

View File

@ -0,0 +1,164 @@
<template>
<div class="file-clipboard">
<el-card shadow="always">
<div class="file-clipboard-content">
<el-popover
placement="bottom"
popper-class="clipboard-popover"
width="420"
trigger="hover">
<div>
<dialog-file-list class="clipboard-content-file-list" :file-list="fileList" :image-url="imageUrl" :audio-cover-url="audioCoverUrl"></dialog-file-list>
<div class="clipboard-tips">
<div class="kdb"><kbd :style="{fontSize: cmdKey === '⌘' ? '14px' : '12px'}">{{ cmdKey }}</kbd><kbd>V</kbd>复制 </div>
<div class="kdb"><kbd :style="{fontSize: cmdKey === '⌘' ? '14px' : '12px'}">{{ cmdKey }}</kbd><kbd>X</kbd>移动 </div>
</div>
</div>
<div slot="reference">
<el-badge :value="fileList.length" class="item">
<el-button size="mini" round>剪切板</el-button>
</el-badge>
</div>
</el-popover>
<div class="file-clipboard-operation">
<el-tooltip :disabled="operationDisabled" popper-class="clipboard-operation-popover" :hide-after="0" effect="light" :content="'复制到: ' + targetPathName" placement="bottom">
<el-button :disabled="operationDisabled" icon="el-icon-document-copy" size="mini" circle @click="copy"></el-button>
</el-tooltip>
<el-tooltip :disabled="operationDisabled" popper-class="clipboard-operation-popover" effect="light" :content="'移动到: ' + targetPathName" placement="bottom">
<el-button :disabled="operationDisabled" icon="el-icon-scissors" size="mini" circle @click="move"></el-button>
</el-tooltip>
<el-button icon="el-icon-close" size="mini" title="关闭" circle @click="clear"></el-button>
</div>
</div>
</el-card>
</div>
</template>
<script>
import DialogFileList from '@/components/ShowFile/DialogFileList.vue'
export default {
components: { DialogFileList },
name: 'FileClipboard',
props: {
fileList: {
type: Array,
default: []
},
imageUrl: {
type: String,
default: ''
},
audioCoverUrl: {
type: String,
default: ''
},
/**
* 当前路径
*/
targetPath: {
type: String,
default: '/'
},
/**
* 当前文件夹id
*/
targetFolder: {
type: String,
default: ''
}
},
data() {
return {
}
},
computed: {
targetPathName() {
return this.targetPath.length > 0 ? this.targetPath : '/'
},
cmdKey() {
return navigator.platform.startsWith('Mac') ? '⌘' : 'Ctrl'
},
operationDisabled() {
return this.$route.path !== '/' && (!this.targetPath || this.targetPath.length < 2)
}
},
methods: {
clear() {
this.$store.dispatch('updateFileClipboard', [])
},
copy() {
/**
* @event onCopy
* @param {Array} fileIdList 文件id列表
* @param {String} targetPath 目标路径
* @param {String} targetFolder 目标文件夹id
*/
this.$emit('onCopy', this.getFileIdList(), this.targetPath, this.targetFolder)
},
move() {
/**
* @event onMove
* @param {Array} fileIdList 文件id列表
* @param {String} targetPath 目标路径
* @param {String} targetFolder 目标文件夹id
*/
this.$emit('onMove', this.getFileIdList(), this.targetPath, this.targetFolder)
},
getFileIdList() {
return this.fileList.map(file => file.id)
}
}
}
</script>
<style lang="scss" scoped>
.file-clipboard {
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
>>> .el-card__body {
padding: 10px;
}
>>> .el-card {
border-radius: 35px;
-webkit-backdrop-filter: saturate(180%) blur(20px);
backdrop-filter: saturate(180%) blur(20px);
background: rgba(255, 255, 255, .27) !important;
border: 0;
}
}
.file-clipboard-content {
width: 185px;
display: flex;
align-items: center;
justify-content: space-between;
}
.file-clipboard-operation {
display: flex;
}
.clipboard-tips {
font-size: 12px;
color: #5f6368ad;
padding: 2px 8px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
line-height: 22px;
border-top: 1px solid #e0e0e0;
background: #f6f6f6;
}
.clipboard-content-file-list {
padding: 5px 10px;
}
.kdb {
margin: 0 16px;
}
</style>

View File

@ -454,8 +454,6 @@
element-loading-background="#f6f7fa88" element-loading-background="#f6f7fa88"
> >
<van-checkbox-group <van-checkbox-group
v-model="selectRowData"
@change="handleSelectionChange"
ref="checkboxGroup" ref="checkboxGroup"
> >
<van-grid <van-grid
@ -760,13 +758,13 @@
<div class="el-message-box__container delete-attention el-alert--warning is-light"> <div class="el-message-box__container delete-attention el-alert--warning is-light">
<div class="el-message-box__status el-icon-warning"></div> <div class="el-message-box__status el-icon-warning"></div>
<div class="el-message-box__message"> <div class="el-message-box__message">
<p>确定删除所选的{{selectDeleteFile.length}}个文件?默认进入回收站</p> <p>确定删除所选的{{selectFileList.length}}个文件?默认进入回收站</p>
</div> </div>
</div> </div>
<div class="delete-attention mt-5"> <div class="delete-attention mt-5">
<el-checkbox v-model="permanentDelete" :disabled="permanentDeleteDisable">永久删除文件(不进入回收站,直接删除)</el-checkbox> <el-checkbox v-model="permanentDelete" :disabled="permanentDeleteDisable">永久删除文件(不进入回收站,直接删除)</el-checkbox>
</div> </div>
<dialog-file-list :file-list="selectDeleteFile" :image-url="imageUrl" :audio-cover-url="audioCoverUrl"></dialog-file-list> <dialog-file-list :file-list="selectFileList" :image-url="imageUrl" :audio-cover-url="audioCoverUrl"></dialog-file-list>
</el-row> </el-row>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button size="small" @click="deleteConfirmVisible = false">取 消</el-button> <el-button size="small" @click="deleteConfirmVisible = false">取 消</el-button>
@ -789,11 +787,13 @@
</el-row> </el-row>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button size="small" @click="copyOrMoveConfirmVisible = false">取 消</el-button> <el-button size="small" @click="copyOrMoveConfirmVisible = false">取 消</el-button>
<el-button type="warning" size="small" @click="copyOrMoveApi(copyOrMoveParams.operating, copyOrMoveParams.froms, copyOrMoveParams.to, true)">覆 盖</el-button> <el-button type="warning" size="small" @click="copyOrMoveApi(copyOrMoveParams.operating, copyOrMoveParams.froms, copyOrMoveParams.to, true, copyOrMoveParams.targetPath)">覆 盖</el-button>
<el-button type="primary" size="small" @click="copyOrMoveApi(copyOrMoveParams.operating, copyOrMoveParams.froms, copyOrMoveParams.to, false)">不覆盖</el-button> <el-button type="primary" size="small" @click="copyOrMoveApi(copyOrMoveParams.operating, copyOrMoveParams.froms, copyOrMoveParams.to, false, copyOrMoveParams.targetPath)">不覆盖</el-button>
</span> </span>
</el-dialog> </el-dialog>
<file-clipboard ref="fileClipboard" v-if="showClipboard && fileClipboard.length > 0" :file-list="fileClipboard" :image-url="imageUrl" :audio-cover-url="audioCoverUrl" :target-path="path" :target-folder="currentFolder" @onCopy="onCopy" @onMove="onMove"></file-clipboard>
<search-dialog :status.sync="searchDialogVisible"></search-dialog> <search-dialog :status.sync="searchDialogVisible"></search-dialog>
</div> </div>
</template> </template>
@ -801,6 +801,9 @@
<script> <script>
import SearchDialog from '@/components/SearchDialog/index.vue' import SearchDialog from '@/components/SearchDialog/index.vue'
import DialogFileList from '@/components/ShowFile/DialogFileList.vue' import DialogFileList from '@/components/ShowFile/DialogFileList.vue'
import FileClipboard from '@/components/ShowFile/FileClipboard.vue'
import store from '@/store'
import path from 'path'
import { fileOperations } from '@/utils/file-operations' import { fileOperations } from '@/utils/file-operations'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { formatSize, formatTime } from '@/utils/number' import { formatSize, formatTime } from '@/utils/number'
@ -835,6 +838,7 @@ import FileDetails from "@/components/preview/FileDetails.vue";
export default { export default {
name: 'ShowFile', name: 'ShowFile',
components: { components: {
FileClipboard,
DialogFileList, DialogFileList,
SearchDialog, SearchDialog,
FileDetails, FileDetails,
@ -931,6 +935,7 @@ export default {
}, },
fileOperations.rename, fileOperations.rename,
fileOperations.copy, fileOperations.copy,
fileOperations.copyOnly,
fileOperations.download, fileOperations.download,
fileOperations.remove, fileOperations.remove,
] ]
@ -947,6 +952,7 @@ export default {
}, },
{ iconClass: 'tag', label: '标签', operation: 'tag' }, { iconClass: 'tag', label: '标签', operation: 'tag' },
fileOperations.copy, fileOperations.copy,
fileOperations.copyOnly,
fileOperations.download, fileOperations.download,
fileOperations.remove, fileOperations.remove,
] ]
@ -956,6 +962,10 @@ export default {
type: Array, type: Array,
default: () => [], default: () => [],
}, },
showClipboard: {
type: Boolean,
default: false,
}
}, },
data() { data() {
return { return {
@ -1103,13 +1113,14 @@ export default {
copyOrMoveParams: { copyOrMoveParams: {
operating: 'copy', operating: 'copy',
froms: [], froms: [],
to: '' to: '',
targetPath: ''
}, // 移动或复制要传递的参数 }, // 移动或复制要传递的参数
copyOrMoveToName: '', // 移动或复制到的文件夹名称 copyOrMoveToName: '', // 移动或复制到的文件夹名称
deleteConfirmVisible: false, // 删除确认弹窗 deleteConfirmVisible: false, // 删除确认弹窗
permanentDelete: false, // 是否永久删除 permanentDelete: false, // 是否永久删除
permanentDeleteDisable: false, // 是否禁用永久删除选项 permanentDeleteDisable: false, // 是否禁用永久删除选项
selectDeleteFile: [], // 选中的删除文件 selectFileList: [], // 选中的文件
deleteLoading: false, // 删除loading deleteLoading: false, // 删除loading
debounceSearch: null,// 搜索防抖 debounceSearch: null,// 搜索防抖
searchDialogVisible: false searchDialogVisible: false
@ -1130,6 +1141,15 @@ export default {
return '名称' return '名称'
} }
}, },
fileClipboard() {
return store.getters.fileClipboard
},
getClipboardFileIdList() {
return store.getters.fileClipboard.map(file => file.id)
},
currentFolder() {
return this.$route.query.folder
},
gridFilename() { gridFilename() {
// 优化文件名,如果文件名过长,则进行截取 // 优化文件名,如果文件名过长,则进行截取
return function(item) { return function(item) {
@ -1371,7 +1391,6 @@ export default {
keydown(event) { keydown(event) {
const { keyCode } = event const { keyCode } = event
const isCmd = this.checkCmdKey(event) const isCmd = this.checkCmdKey(event)
const checkPreviewVisible = this.checkPreviewVisible() const checkPreviewVisible = this.checkPreviewVisible()
// space // space
if (keyCode === 32 && this.selectRowData.length > 0 && !this.drawer && !checkPreviewVisible) { if (keyCode === 32 && this.selectRowData.length > 0 && !this.drawer && !checkPreviewVisible) {
@ -1407,6 +1426,26 @@ export default {
event.stopPropagation() event.stopPropagation()
} }
} }
// ctrl + C / cmd + C
if (isCmd && keyCode === 67 && !checkPreviewVisible && !this.inputting && this.selectRowData.length > 0) {
this.copyOperation()
event.preventDefault()
event.stopPropagation()
}
// ctrl + V / cmd + V
if (isCmd && keyCode === 86 && !checkPreviewVisible && !this.inputting && this.fileClipboard.length > 0) {
// copy
this.onCopy(this.getClipboardFileIdList, this.path, this.currentFolder)
event.preventDefault()
event.stopPropagation()
}
// ctrl + X / cmd + X
if (isCmd && keyCode === 88 && !checkPreviewVisible && !this.inputting && this.fileClipboard.length > 0) {
// move
this.onMove(this.getClipboardFileIdList, this.path, this.currentFolder)
event.preventDefault()
event.stopPropagation()
}
// ctrl + P / cmd + P // ctrl + P / cmd + P
// if (isCmd && keyCode === 80) { // if (isCmd && keyCode === 80) {
// if (!this.inputting && this.editingIndex === -1) { // if (!this.inputting && this.editingIndex === -1) {
@ -1469,6 +1508,9 @@ export default {
} }
this.clearOnCreateFilename() this.clearOnCreateFilename()
} }
if (this.$route.path === '/trash' && msg.url === 'operationTips') {
this.getFileList()
}
}, },
// 延时清空onCreateFilename // 延时清空onCreateFilename
clearOnCreateFilename() { clearOnCreateFilename() {
@ -1568,18 +1610,13 @@ export default {
} }
// 点击的区域是否为文件, throughRow 不为空就证明点到了文件 // 点击的区域是否为文件, throughRow 不为空就证明点到了文件
let throughRow = elPath.find(path => { let throughRow = elPath.find(path => {
if ( if (path.className === itemClassName || path.className === 'el-table__row el-table__row--striped') {
path.className === itemClassName ||
path.className === 'el-table__row el-table__row--striped'
) {
return path return path
} }
}) })
if (throughRow) { if (throughRow) {
// 鼠标按下时就选中文件 // 鼠标按下时就选中文件
if ( if (!_this.selectRowData.includes(_this.fileList[throughRow.rowIndex])) {
!_this.selectRowData.includes(_this.fileList[throughRow.rowIndex])
) {
_this.editingIndex = -1 _this.editingIndex = -1
if (!_this.checkCmdKey(e) && !e.shiftKey) { if (!_this.checkCmdKey(e) && !e.shiftKey) {
_this.$refs.fileListTable.clearSelection() _this.$refs.fileListTable.clearSelection()
@ -2942,18 +2979,12 @@ export default {
} }
if (diff > 0) { if (diff > 0) {
for (let i = origin; i <= this.selectEnd; i++) { for (let i = origin; i <= this.selectEnd; i++) {
this.$refs.fileListTable.toggleRowSelection([ this.$refs.fileListTable.toggleRowSelection([{ row: this.fileList[i], selected: true }])
{ row: this.fileList[i], selected: true },
])
this.$refs.fileListTable.tableSelectData.push(this.fileList[i])
} }
} }
if (diff < 0) { if (diff < 0) {
for (let i = this.selectEnd; i <= origin; i++) { for (let i = this.selectEnd; i <= origin; i++) {
this.$refs.fileListTable.toggleRowSelection([ this.$refs.fileListTable.toggleRowSelection([{ row: this.fileList[i], selected: true }])
{ row: this.fileList[i], selected: true },
])
this.$refs.fileListTable.tableSelectData.push(this.fileList[i])
} }
} }
} }
@ -3332,6 +3363,7 @@ export default {
if (file.operationPermissionList.indexOf('UPLOAD') > -1) { if (file.operationPermissionList.indexOf('UPLOAD') > -1) {
if (file.operationPermissionList.indexOf('DELETE') > -1) { if (file.operationPermissionList.indexOf('DELETE') > -1) {
this.menus.splice(this.menus.length - 1, 0, fileOperations.copy) this.menus.splice(this.menus.length - 1, 0, fileOperations.copy)
this.menus.splice(this.menus.length - 1, 0, fileOperations.copyOnly)
} }
if (!file.isFolder) { if (!file.isFolder) {
this.menus.splice(this.menus.length - 1, 0, fileOperations.duplicate) this.menus.splice(this.menus.length - 1, 0, fileOperations.duplicate)
@ -3558,6 +3590,9 @@ export default {
// 移动或复制 // 移动或复制
this.moveOrCopy() this.moveOrCopy()
break break
case 'copyOnly':
this.copyOperation()
break
case 'download': case 'download':
// 下载 // 下载
this.downloadFile() this.downloadFile()
@ -3586,9 +3621,18 @@ export default {
}, },
removeOperation() { removeOperation() {
this.permanentDelete = false this.permanentDelete = false
this.selectDeleteFile = this.getSelectDeleteList() this.selectFileList = this.getSelectFileList()
this.deleteConfirmVisible = true 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() {
store.dispatch('updateFileClipboard', this.getSelectFileList())
},
// 加载下一级文件树 // 加载下一级文件树
directoryTreeLoadNode(node, resolve) { directoryTreeLoadNode(node, resolve) {
let fileId = null let fileId = null
@ -3597,7 +3641,7 @@ export default {
setTimeout(function() { setTimeout(function() {
that.$refs.directoryTree.setCurrentKey('0') that.$refs.directoryTree.setCurrentKey('0')
}, 0) }, 0)
return resolve([{ id: '0', name: '全部文件' }]) return resolve([{ id: '0', name: '根目录' }])
} }
if (node.level > 1) { if (node.level > 1) {
fileId = node.data.mountFileId || node.data.id fileId = node.data.mountFileId || node.data.id
@ -3726,24 +3770,32 @@ export default {
} }
this.checkCopyOrMoveApi(operating, fileIds, this.selectTreeNode.id, this.selectTreeNode.name) this.checkCopyOrMoveApi(operating, fileIds, this.selectTreeNode.id, this.selectTreeNode.name)
}, },
checkCopyOrMoveApi(operating, froms, to, toName) { checkCopyOrMoveApi(operating, froms, to, toName, targetPath) {
if (!to && !targetPath) {
to = '0'
toName = '根目录'
}
if (targetPath) {
toName = path.basename(targetPath)
}
api['checkMoveOrCopy']({ api['checkMoveOrCopy']({
userId: this.$store.state.user.userId, userId: this.$store.state.user.userId,
username: this.$store.state.user.name, username: this.$store.state.user.name,
froms: froms, froms: froms,
to: to, to: to,
targetPath: targetPath
}).then((res) => { }).then((res) => {
if (res.count > 0) { if (res.count > 0) {
this.copyOrMoveConfirmVisible = true this.copyOrMoveConfirmVisible = true
this.copyOrMoveParams = {operating: operating, froms: froms, to: to} this.copyOrMoveParams = {operating: operating, froms: froms, to: to, targetPath: targetPath}
this.copyOrMoveToName = `${(operating === 'copy' ? '复制' : '移动')}到: "${toName}"` this.copyOrMoveToName = `${(operating === 'copy' ? '复制' : '移动')}到: "${toName}"`
this.existsFileList = res.data this.existsFileList = res.data
} else { } else {
this.copyOrMoveApi(operating, froms, to, false) this.copyOrMoveApi(operating, froms, to, false, targetPath)
} }
}) })
}, },
copyOrMoveApi(operating, froms, to, isOverride) { copyOrMoveApi(operating, froms, to, isOverride, targetPath) {
this.copyOrMoveConfirmVisible = false this.copyOrMoveConfirmVisible = false
let operation = '复制' let operation = '复制'
if (operating === 'move') { if (operating === 'move') {
@ -3762,8 +3814,10 @@ export default {
username: this.$store.state.user.name, username: this.$store.state.user.name,
froms: froms, froms: froms,
to: to, to: to,
targetPath: targetPath,
isOverride: isOverride isOverride: isOverride
}).then(() => { }).then(() => {
this.$refs.fileClipboard.clear()
copying.iconClass = null copying.iconClass = null
copying.type = 'success' copying.type = 'success'
copying.message = operation + '中...' copying.message = operation + '中...'
@ -3976,8 +4030,8 @@ export default {
}, },
// 删除 // 删除
deleteFile() { deleteFile() {
// 提取出selectDeleteFile中的id // 提取出selectFileList中的id
const fileIds = this.selectDeleteFile.map(item => item.id) const fileIds = this.selectFileList.map(item => item.id)
this.deleteLoading = true this.deleteLoading = true
api.delete({ api.delete({
currentDirectory: this.getQueryPath(), currentDirectory: this.getQueryPath(),
@ -3998,9 +4052,7 @@ export default {
}, },
restoreFile() { restoreFile() {
const fileIds = this.getSelectIdList() const fileIds = this.getSelectIdList()
api.restore({fileIds: fileIds}).then(() => { api.restore({fileIds: fileIds}).then()
this.getFileList()
})
}, },
sweepFile() { sweepFile() {
const fileIds = this.getSelectIdList() const fileIds = this.getSelectIdList()
@ -4010,9 +4062,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(() => { }).then(() => {
api.sweep({fileIds: fileIds}).then(() => { api.sweep({fileIds: fileIds}).then()
this.getFileList()
})
}) })
}, },
clearTrash() { clearTrash() {
@ -4022,9 +4072,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(() => { }).then(() => {
api.clearTrash().then(() => { api.clearTrash().then()
this.getFileList()
})
}) })
}, },
// 获取选中项id列表 // 获取选中项id列表
@ -4039,19 +4087,21 @@ export default {
} }
return fileIds return fileIds
}, },
getSelectDeleteList() { getSelectFileList() {
const fileList = [] const fileList = [];
this.permanentDeleteDisable = false this.permanentDeleteDisable = false;
const addFileToList = ({ id, suffix, name, contentType, isFolder, music, video }) => {
fileList.push({ id, suffix, name, contentType, isFolder, music, video });
};
if (this.selectRowData.length > 1 || this.menusIsMultiple) { if (this.selectRowData.length > 1 || this.menusIsMultiple) {
this.$refs.fileListTable.tableSelectData.forEach(value => { this.$refs.fileListTable.tableSelectData.forEach(value => addFileToList(value));
this.checkPermanentDelete(value.id)
fileList.push({id: value.id, suffix: value.suffix, name: value.name, contentType: value.contentType, isFolder: value.isFolder, music: value.music, video: value.video})
})
} else { } else {
this.checkPermanentDelete(this.rowContextData.id) addFileToList(this.rowContextData);
fileList.push({id: this.rowContextData.id, suffix: this.rowContextData.suffix, name: this.rowContextData.name, contentType: this.rowContextData.contentType, isFolder: this.rowContextData.isFolder, music: this.rowContextData.music, video: this.rowContextData.video})
} }
return fileList if (fileList.length > 0) {
this.checkPermanentDelete(fileList[0].id);
}
return fileList;
}, },
checkPermanentDelete(fileId) { checkPermanentDelete(fileId) {
if (/\//.test(fileId)) { if (/\//.test(fileId)) {

View File

@ -11,5 +11,6 @@ const getters = {
userId: state => state.user.userId, userId: state => state.user.userId,
userInfo: state => state.user.userInfo, userInfo: state => state.user.userInfo,
menuList: state => state.user.menuList, menuList: state => state.user.menuList,
fileClipboard: state => state.fileClipboard
} }
export default getters export default getters

View File

@ -16,16 +16,23 @@ const store = new Vuex.Store({
getters, getters,
state: { state: {
message: null, message: null,
fileClipboard: []
}, },
mutations: { mutations: {
setMessage(state, message) { setMessage(state, message) {
state.message = message; state.message = message;
}, },
setFileClipboard(state, fileClipboard) {
state.fileClipboard = fileClipboard;
}
}, },
actions: { actions: {
updateMessage({ commit }, message) { updateMessage({ commit }, message) {
commit('setMessage', message); commit('setMessage', message);
}, },
updateFileClipboard({ commit }, fileClipboard) {
commit('setFileClipboard', fileClipboard);
}
} }
}) })

View File

@ -240,3 +240,10 @@ kbd {
-webkit-box-shadow: inset 0 -1px 0 rgba(175, 184, 193, .2); -webkit-box-shadow: inset 0 -1px 0 rgba(175, 184, 193, .2);
box-shadow: inset 0 -1px 0 rgba(175, 184, 193, .2); box-shadow: inset 0 -1px 0 rgba(175, 184, 193, .2);
} }
.clipboard-popover {
padding: 0 !important;
}
.clipboard-operation-popover {
max-width: 500px;
}

View File

@ -5,5 +5,5 @@ export const fileOperations = {
download: { iconClass: 'menu-download', label: '下载', operation: 'download' }, download: { iconClass: 'menu-download', label: '下载', operation: 'download' },
copy: { iconClass: 'menu-copy', label: '移动或复制', operation: 'copy' }, copy: { iconClass: 'menu-copy', label: '移动或复制', operation: 'copy' },
rename: { iconClass: 'menu-rename', label: '重命名', operation: 'rename', shortcut: ['F2'] }, rename: { iconClass: 'menu-rename', label: '重命名', operation: 'rename', shortcut: ['F2'] },
//copyKey: { iconClass: 'menu-copy', label: '复制', operation: 'copyKey', shortcut: [navigator.platform.startsWith('Mac') ? '⌘' : 'Ctrl', 'C'] }, copyOnly: { iconClass: 'menu-copy', label: '复制', operation: 'copyOnly', shortcut: [navigator.platform.startsWith('Mac') ? '⌘' : 'Ctrl', 'C'] },
} }

View File

@ -5,6 +5,7 @@
:defaultGrid="true" :defaultGrid="true"
:sortable="sortable" :sortable="sortable"
:orderCustom="true" :orderCustom="true"
:showClipboard="true"
:defaultSort="sortable" :defaultSort="sortable"
:queryCondition="queryCondition" :queryCondition="queryCondition"
:contextMenus="contextMenus" :contextMenus="contextMenus"

View File

@ -4,6 +4,7 @@
:defaultGrid="true" :defaultGrid="true"
:orderCustom="true" :orderCustom="true"
:contextMenus="contextMenus" :contextMenus="contextMenus"
:showClipboard="true"
:sortable="sortable"> :sortable="sortable">
</show-file> </show-file>
</div> </div>

View File

@ -4,6 +4,7 @@
:defaultGrid="true" :defaultGrid="true"
:sortable="sortable" :sortable="sortable"
:orderCustom="true" :orderCustom="true"
:showClipboard="true"
:defaultSort="sortable" :defaultSort="sortable"
:queryCondition="queryCondition" :queryCondition="queryCondition"
:contextMenus="contextMenus" :contextMenus="contextMenus"