You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
15 KiB
526 lines
15 KiB
<template>
|
|
<div class="app-container">
|
|
<div class="filter-container">
|
|
<el-page-header
|
|
@back="handleGoToLastFolder"
|
|
>
|
|
<template
|
|
slot="content"
|
|
class="file-system-page"
|
|
>
|
|
<el-breadcrumb
|
|
ref="fileSystemBreadCrumb"
|
|
separator-class="el-icon-arrow-right"
|
|
>
|
|
<el-breadcrumb-item
|
|
v-for="(fileRoot, index) in fileSystemRoot"
|
|
:key="index"
|
|
class="file-system-breadcrumb"
|
|
@click.native="(event) => onBreadCrumbClick(event, index)"
|
|
>
|
|
{{ fileRoot }}
|
|
</el-breadcrumb-item>
|
|
</el-breadcrumb>
|
|
</template>
|
|
</el-page-header>
|
|
</div>
|
|
|
|
<el-table
|
|
ref="fileSystemTable"
|
|
v-loading="fileSystemListLoading"
|
|
row-key="name"
|
|
:data="fileSystemList"
|
|
border
|
|
fit
|
|
highlight-current-row
|
|
style="width: 100%;"
|
|
:row-class-name="tableRowClassName"
|
|
@row-click="onRowClick"
|
|
@row-dblclick="onRowDoubleClick"
|
|
@contextmenu.native="onContextMenu"
|
|
>
|
|
<el-table-column
|
|
type="selection"
|
|
width="50"
|
|
align="center"
|
|
/>
|
|
<el-table-column
|
|
:label="$t('fileSystem.name')"
|
|
prop="name"
|
|
sortable
|
|
width="350"
|
|
align="left"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<svg-icon
|
|
:name="row.type | fileSystemTypeIconFilter"
|
|
:class="row.type | fileSystemTypeIconClassFilter"
|
|
/>
|
|
<span>{{ row.name }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('fileSystem.creationTime')"
|
|
prop="creationTime"
|
|
sortable
|
|
width="200"
|
|
align="center"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<span>{{ row.creationTime | dateTimeFilter }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('fileSystem.lastModificationTime')"
|
|
prop="lastModificationTime"
|
|
sortable
|
|
width="200"
|
|
align="center"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<span>{{ row.lastModificationTime | dateTimeFilter }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('fileSystem.type')"
|
|
prop="type"
|
|
sortable
|
|
width="150"
|
|
align="center"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<span>{{ row.type === 0 ? $t('fileSystem.folder') : $t('fileSystem.fileType', {exten: row.extension}) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('fileSystem.size')"
|
|
prop="size"
|
|
sortable
|
|
width="200"
|
|
align="center"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<span>{{ row.size | fileSystemSizeFilter }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('global.operaActions')"
|
|
align="center"
|
|
width="250"
|
|
min-width="250"
|
|
>
|
|
<template slot-scope="{row}">
|
|
<el-button
|
|
:disabled="row.type === 0 ? !checkPermission(['AbpFileManagement.FileSystem.Delete']) : !checkPermission(['AbpFileManagement.FileSystem.FileManager.Delete'])"
|
|
size="mini"
|
|
type="danger"
|
|
@click="handleDeleteFolderOrFile(row)"
|
|
>
|
|
{{ row.type === 0 ? $t('fileSystem.deleteFolder') : $t('fileSystem.deleteFile') }}
|
|
</el-button>
|
|
<el-dropdown
|
|
class="options"
|
|
@command="handleFileSystemCommand"
|
|
>
|
|
<el-button
|
|
v-permission="['AbpFileManagement.FileSystem']"
|
|
size="mini"
|
|
type="info"
|
|
>
|
|
{{ $t('global.otherOpera') }}<i class="el-icon-arrow-down el-icon--right" />
|
|
</el-button>
|
|
<el-dropdown-menu slot="dropdown">
|
|
<el-dropdown-item
|
|
v-permission="['AbpFileManagement.FileSystem.FileManager.Create']"
|
|
:command="{key: 'upload', row}"
|
|
>
|
|
{{ $t('fileSystem.upload') }}
|
|
</el-dropdown-item>
|
|
<el-dropdown-item
|
|
v-permission="['AbpFileManagement.FileSystem.FileManager.Download']"
|
|
divided
|
|
:command="{key: 'download', row}"
|
|
:disabled="downloading || row.type === 0"
|
|
>
|
|
{{ $t('fileSystem.download') }}
|
|
</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</el-dropdown>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<Pagination
|
|
v-show="fileSystemCount>0"
|
|
:total="fileSystemCount"
|
|
:page.sync="fileSystemGetFilter.skipCount"
|
|
:limit.sync="fileSystemGetFilter.maxResultCount"
|
|
@pagination="handleGetFileSystemList"
|
|
/>
|
|
|
|
<el-dialog
|
|
:visible.sync="showFileUploadDialog"
|
|
:title="$t('fileSystem.upload')"
|
|
:show-close="false"
|
|
@closed="onFileUploadFormClosed"
|
|
>
|
|
<file-upload-form
|
|
ref="fileUploadForm"
|
|
:path="lastFilePath"
|
|
@onFileUploaded="onFileUploaded"
|
|
/>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { dateFormat } from '@/utils'
|
|
import { checkPermission } from '@/utils/permission'
|
|
import { Component, Vue } from 'vue-property-decorator'
|
|
import FileUploadForm from './components/FileUploadForm.vue'
|
|
import Pagination from '@/components/Pagination/index.vue'
|
|
import FileSystemService, { FileSystem, FileSystemGetByPaged, FileSystemType } from '@/api/filemanagement'
|
|
|
|
const kbUnit = 1 * 1024
|
|
const mbUnit = kbUnit * 1024
|
|
const gbUnit = mbUnit * 1024
|
|
const $contextmenu = Vue.prototype.$contextmenu
|
|
|
|
@Component({
|
|
name: 'FileManagement',
|
|
components: {
|
|
Pagination,
|
|
FileUploadForm
|
|
},
|
|
filters: {
|
|
dateTimeFilter(datetime: string) {
|
|
const date = new Date(datetime)
|
|
return dateFormat(date, 'YYYY-mm-dd HH:MM')
|
|
},
|
|
fileSystemTypeIconFilter(type: FileSystemType) {
|
|
if (type === FileSystemType.Folder) {
|
|
return 'folder'
|
|
}
|
|
return 'file'
|
|
},
|
|
fileSystemTypeIconClassFilter(type: FileSystemType) {
|
|
if (type === FileSystemType.Folder) {
|
|
return 'folder-icon'
|
|
}
|
|
return 'file-icon'
|
|
},
|
|
fileSystemTypeFilter(type: FileSystemType) {
|
|
if (type === FileSystemType.Folder) {
|
|
return 'fileSystem.folder'
|
|
}
|
|
return 'fileSystem.fileType'
|
|
},
|
|
fileSystemSizeFilter(size: number) {
|
|
if (size > gbUnit) {
|
|
let gb = Math.round(size / gbUnit)
|
|
if (gb < 1) {
|
|
gb = 1
|
|
}
|
|
return gb + ' GB'
|
|
}
|
|
if (size > mbUnit) {
|
|
let mb = Math.round(size / mbUnit)
|
|
if (mb < 1) {
|
|
mb = 1
|
|
}
|
|
return mb + ' MB'
|
|
}
|
|
let kb = Math.round(size / kbUnit)
|
|
if (kb < 1) {
|
|
kb = 1
|
|
}
|
|
return kb + ' KB'
|
|
}
|
|
},
|
|
methods: {
|
|
checkPermission,
|
|
tableRowClassName(row: any) {
|
|
if (row.row.type === 0) {
|
|
return 'folder-row'
|
|
}
|
|
return 'file-row'
|
|
}
|
|
}
|
|
})
|
|
export default class extends Vue {
|
|
private showFileUploadDialog!: boolean
|
|
private downloading!: boolean
|
|
private lastFilePath!: string
|
|
private fileSystemRoot!: string[]
|
|
private fileSystemList?: FileSystem[]
|
|
private fileSystemCount!: number
|
|
private fileSystemListLoading!: boolean
|
|
private fileSystemGetFilter!: FileSystemGetByPaged
|
|
|
|
constructor() {
|
|
super()
|
|
this.lastFilePath = ''
|
|
this.fileSystemCount = 0
|
|
this.downloading = false
|
|
this.fileSystemListLoading = false
|
|
this.showFileUploadDialog = false
|
|
this.fileSystemRoot = new Array<string>()
|
|
this.fileSystemList = new Array<FileSystem>()
|
|
this.fileSystemGetFilter = new FileSystemGetByPaged()
|
|
}
|
|
|
|
mounted() {
|
|
this.fileSystemRoot.push(this.$t('fileSystem.root').toString())
|
|
this.handleGetFileSystemList()
|
|
}
|
|
|
|
private handleGetFileSystemList() {
|
|
this.fileSystemListLoading = true
|
|
FileSystemService.getFileSystemList(this.fileSystemGetFilter).then(res => {
|
|
this.fileSystemCount = res.totalCount
|
|
this.fileSystemList = res.items
|
|
}).finally(() => {
|
|
this.fileSystemListLoading = false
|
|
})
|
|
}
|
|
|
|
private navigationToFilePath() {
|
|
const fileSystemPathArray = this.fileSystemRoot.slice(1)
|
|
const fileSystemPath = fileSystemPathArray.join('/')
|
|
this.fileSystemGetFilter.parent = fileSystemPath
|
|
this.handleGetFileSystemList()
|
|
}
|
|
|
|
private handleGoToLastFolder() {
|
|
if (this.fileSystemRoot.length > 1) {
|
|
this.fileSystemRoot.splice(this.fileSystemRoot.length - 1)
|
|
this.navigationToFilePath()
|
|
}
|
|
}
|
|
|
|
private handleDeleteFolderOrFile(row: any) {
|
|
this.$confirm(this.l('global.whetherDeleteData', { name: row.name }),
|
|
this.l('global.questingDeleteByMessage',
|
|
{ message: row.type === 0 ? this.l('fileSystem.folder') : this.l('fileSystem.file') }), {
|
|
callback: (action) => {
|
|
if (action === 'confirm') {
|
|
if (row.type === 0) {
|
|
let path = row.name
|
|
if (row.parent) {
|
|
path = row.parent + '/' + row.name
|
|
}
|
|
FileSystemService.deleteFolder(path).then(() => {
|
|
this.$notify.success(this.l('global.dataHasBeenDeleted', { name: row.name }))
|
|
this.handleGetFileSystemList()
|
|
})
|
|
} else {
|
|
FileSystemService.deleteFile(row.parent, row.name).then(() => {
|
|
this.$notify.success(this.l('global.dataHasBeenDeleted', { name: row.name }))
|
|
this.handleGetFileSystemList()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
private handleFileSystemCommand(command: { key: string, row: any}) {
|
|
switch (command.key) {
|
|
case 'download':
|
|
this.handleDownloadFile(command.row.parent, command.row.name, command.row.size)
|
|
break
|
|
case 'upload':
|
|
if (command.row.type === 0) {
|
|
let path = command.row.name
|
|
if (command.row.parent) {
|
|
path = command.row.parent + '/' + path
|
|
}
|
|
this.handleUploadFile(path)
|
|
} else {
|
|
this.handleUploadFile(command.row.parent)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
private handleUploadFile(path: string) {
|
|
this.lastFilePath = path
|
|
this.showFileUploadDialog = true
|
|
}
|
|
|
|
private handleDownloadFile(path: string, fileName: string, size: number) {
|
|
this.downloading = true
|
|
const blobs = new Array<BlobPart>()
|
|
this.downlodFile(path, fileName, size, 0, blobs,
|
|
(downloadSize: number) => {
|
|
if (downloadSize >= size) {
|
|
this.downloading = false
|
|
// 释放空间
|
|
blobs.length = 0
|
|
}
|
|
})
|
|
}
|
|
|
|
private downlodFile(path: string, fileName: string, size: number, currentByte: number, blobs: BlobPart[], callback: Function) {
|
|
FileSystemService.downlodFle(fileName, path, currentByte).then((res: any) => {
|
|
// 获取当前下载字节大小
|
|
const downloadByte = res.data.size
|
|
// 当前下载分块入栈
|
|
blobs.push(res.data)
|
|
currentByte += downloadByte
|
|
if (size > currentByte) {
|
|
this.downlodFile(path, fileName, size, currentByte, blobs, callback)
|
|
} else {
|
|
// 合并下载文件
|
|
const url = window.URL.createObjectURL(new Blob(blobs, { type: res.headers['content-type'] }))
|
|
const link = document.createElement('a')
|
|
link.style.display = 'none'
|
|
link.href = url
|
|
link.setAttribute('download', fileName)
|
|
document.body.appendChild(link)
|
|
link.click()
|
|
// 下载完成后的回调
|
|
callback(size)
|
|
}
|
|
}).catch(() => {
|
|
callback(size)
|
|
})
|
|
}
|
|
|
|
private onRowClick(row: any) {
|
|
if (row.type === FileSystemType.Folder) {
|
|
let path = row.name
|
|
if (row.parent) {
|
|
path = row.parent + '/' + row.name
|
|
}
|
|
this.lastFilePath = path
|
|
}
|
|
const table = this.$refs.fileSystemTable as any
|
|
table.toggleRowSelection(row)
|
|
}
|
|
|
|
private onRowDoubleClick(row: any) {
|
|
if (row.type === FileSystemType.Folder) {
|
|
this.fileSystemRoot.push(row.name)
|
|
this.navigationToFilePath()
|
|
}
|
|
}
|
|
|
|
private onBreadCrumbClick(event: any, index: number) {
|
|
// 如果点击的索引为最后一个,不做响应
|
|
if ((index + 1) < this.fileSystemRoot.length) {
|
|
this.fileSystemRoot.splice(index + 1)
|
|
this.navigationToFilePath()
|
|
} else {
|
|
this.handleGetFileSystemList()
|
|
}
|
|
}
|
|
|
|
private onFileUploaded() {
|
|
this.handleGetFileSystemList()
|
|
}
|
|
|
|
private onFileUploadFormClosed() {
|
|
this.showFileUploadDialog = false
|
|
const frmUpload = this.$refs.fileUploadForm as any
|
|
frmUpload.close()
|
|
}
|
|
|
|
private onContextMenu(event: any) {
|
|
event.preventDefault()
|
|
$contextmenu({
|
|
items: [
|
|
{
|
|
label: this.$t('fileSystem.addFolder'),
|
|
disabled: !checkPermission(['AbpFileManagement.FileSystem.Create']),
|
|
onClick: () => {
|
|
let parent = ''
|
|
// 在根目录下
|
|
if (this.fileSystemRoot.length > 1) {
|
|
parent = this.fileSystemRoot.slice(1).join('/')
|
|
}
|
|
this.$prompt(this.$t('global.pleaseInputBy', { key: this.$t('fileSystem.name') }).toString(),
|
|
this.$t('fileSystem.addFolder').toString(), {
|
|
showInput: true,
|
|
inputValidator: (val) => {
|
|
return !(!val || val.length === 0)
|
|
},
|
|
inputErrorMessage: this.$t('fileSystem.folderNameIsRequired').toString(),
|
|
inputPlaceholder: this.$t('global.pleaseInputBy', { key: this.$t('fileSystem.name') }).toString()
|
|
}).then((val: any) => {
|
|
FileSystemService.createFolder(val.value, parent).then(() => {
|
|
this.$message.success(this.$t('fileSystem.folderCreateSuccess', { name: val.value }).toString())
|
|
this.handleGetFileSystemList()
|
|
})
|
|
}).catch(_ => _)
|
|
},
|
|
divided: true
|
|
},
|
|
{
|
|
label: this.$t('fileSystem.upload'),
|
|
disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Create']),
|
|
onClick: () => {
|
|
let path = ''
|
|
if (this.fileSystemRoot.length > 1) {
|
|
path = this.fileSystemRoot.slice(1).join('/')
|
|
}
|
|
this.lastFilePath = path
|
|
this.showFileUploadDialog = true
|
|
}
|
|
}
|
|
],
|
|
event,
|
|
customClass: 'context-menu',
|
|
zIndex: 3,
|
|
minWidth: 150
|
|
})
|
|
return false
|
|
}
|
|
|
|
private l(name: string, values?: any[] | { [key: string]: any }) {
|
|
return this.$t(name, values).toString()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.options {
|
|
vertical-align: top;
|
|
margin-left: 20px;
|
|
}
|
|
.el-dropdown + .el-dropdown {
|
|
margin-left: 15px;
|
|
}
|
|
.el-icon-arrow-down {
|
|
font-size: 12px;
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
.el-table .folder-row {
|
|
cursor: pointer;
|
|
background-color:rgb(245, 235, 226);
|
|
}
|
|
.el-table .file-row {
|
|
cursor: pointer;
|
|
background-color: rgb(210, 219, 235);
|
|
}
|
|
.file-system-breadcrumb .el-breadcrumb__inner {
|
|
color: rgb(34, 34, 173);
|
|
cursor: pointer;
|
|
}
|
|
.file-icon {
|
|
margin-left: 0px;
|
|
margin-right: 5px;
|
|
margin-top: 0px;
|
|
margin-bottom: 0px;
|
|
color: rgb(55, 189, 189);
|
|
}
|
|
.folder-icon {
|
|
margin-left: 0px;
|
|
margin-right: 5px;
|
|
margin-top: 0px;
|
|
margin-bottom: 0px;
|
|
color: rgb(235, 130, 33);
|
|
}
|
|
</style>
|
|
|