效果图
文件分布模块
安装依赖
npm install vue - splitpane --save
npm install file-saver
npm install jszip
代码模块
1、papersList页面
<!-- 文件管理 -->
<template>
<a-card>
<splitPane
:max-percent="100"
:default-percent="defaultPercentOne"
:min-percent="10"
split="vertical"
class="splitpanes__pane"
:style="{ height: screenHeight - 128 + 'px' }"
>
<template slot="paneL">
<papersTree @fold="getPercent" @hasect="hasect" />
</template>
<template slot="paneR">
<div class="penclass">
<a-icon type="bug" style="color:#fff;font-size: 10px;" />
</div>
<papersfile />
</template>
</splitPane>
</a-card>
</template>
<script>
import papersTree from '@views/erp/papers/modal/papersTree'
import papersfile from '@views/erp/papers/modal/papersfile'
import splitPane from 'vue-splitpane'
export default {
components: {
papersTree,
papersfile,
splitPane
},
name: 'handModale',
data() {
return {
defaultPercentOne: 15,
url: {
list: '/cnsMainFiles/cnsMainFiles/list'
}
}
},
beforeCreate() {
// 屏幕高度
this.screenHeight = document.documentElement.clientHeight
},
methods: {
getPercent(text) {
if (text) this.defaultPercentOne = 15
if (!text) this.defaultPercentOne = 5
},
// 点击传递来的参数
hasect(ist) {
console.log(ist)
}
}
}
</script>
<style lang="less" scoped>
.penclass {
position: absolute;
background: blue;
top: 40%;
left: -5px;
width: 10px;
height: 45px;
display: flex;
justify-content: center;
align-self: center;
align-items: center;
border-radius: 10px;
}
</style>
2、papersTree页面
<!-- 文件管理左侧 -->
<template>
<a-card :body-style="{ padding: '0', height: screenHeight - 128 + 'px' }">
<a-card :body-style="{ padding: '8px 10px' }">
<a-breadcrumb class="reumb">
<a-breadcrumb-item>
<a-icon type="home" @click="getHome" />
</a-breadcrumb-item>
<a-breadcrumb-item v-for="(item, index) in crumbArr" :key="index">
<a href="#" @click="hdSelect(item)">{{ item.title }}</a>
</a-breadcrumb-item>
</a-breadcrumb>
</a-card>
<a-card :body-style="{ padding: '5px 10px' }" :bordered="false">
<a-directory-tree
:clickRowToExpand="true"
:treeData="treeData"
:replace-fields="replaceFields"
:autoExpandParent="pandAll"
:default-expand-all="true"
@select="onSelect"
>
</a-directory-tree>
</a-card>
</a-card>
</template>
<script>
import { postAction } from '@/api/manage'
import VuexBus from '@/views/erp/papers/modal/VuexBus'
export default {
name: 'handTree',
data() {
return {
pandAll: false,
expandedKeysss: [],
crumbArr: [],
replaceFields: {
children: 'child',
title: 'name'
},
treeData: [],
url: {
readDirIter: '/oss/upyun/filee/listTree',
// 创建文件夹
mkdir: '/oss/upyun/filee/mkdir',
// 删除文件夹
delFileOrDir: '/oss/upyun/filee/delFileOrDir'
}
}
},
beforeCreate() {
// 屏幕高度
this.screenHeight = document.documentElement.clientHeight
},
created() {
let that = this
that.loadData()
},
methods: {
hdSelect(item) {
let that = this
let company = item.filePath.split('/')
let Arr = company.filter(item => {
return item.length > 0
})
that.crumbArr = []
Arr.forEach((item1, index) => {
let path = {}
let textArr = item.filePath
.split('/')
.slice(0, index + 2)
.join('/')
path.title = item1
path.filePath = textArr
that.crumbArr.push(path)
})
VuexBus.$emit('Pafile', that.crumbArr)
},
// 回到首页
getHome() {
this.loadData()
this.crumbArr = []
VuexBus.$emit('Pafile', '')
},
// 数据请求接口
loadData() {
let that = this
let params = {}
postAction(that.url.readDirIter, params).then(res => {
if (res.success) {
that.onTree(res.result)
} else {
this.$message.warning(res.message)
}
})
},
// 组合数据
onTree(arr) {
let that = this
let Arr = this.deepFilter(arr)
that.treeData = Arr
},
deepFilter(list) {
// 使用filter 过滤当前层的数组
return list.filter(item => {
// filter其实也是遍历
// 把当前遍历的节点的children 也调用一次 deepFilter 函数,返回过滤后的数组重新赋值
if (item.child) item.child = this.deepFilter(item.child)
// 最后判断当前节点是否符合过滤要求
return item.type == 'folder'
})
},
onSelect(selectedKeys, event) {
let that = this
let file = event.node.dataRef
let company = file.filePath.split('/')
let Arr = company.filter(item => {
return item.length > 0
})
that.crumbArr = []
Arr.forEach((item1, index) => {
let path = {}
let textArr = file.filePath
.split('/')
.slice(0, index + 2)
.join('/')
path.title = item1
path.filePath = textArr
that.crumbArr.push(path)
})
VuexBus.$emit('Pafile', that.crumbArr)
}
}
}
</script>
<style scoped lang="less">
.reumb {
height: 32px;
display: flex;
align-self: center;
align-items: center;
}
.ClVoum {
margin-left: 10px;
}
.ClInput {
padding-left: 10px;
border: 1px solid #d9d9d9;
border-radius: 3px;
}
.ClInput:focus {
outline: none;
border: 1px solid #597ef7;
}
</style>
3、papersfile页面
<!-- 文件管理右侧 -->
<template>
<a-card :body-style="{ padding: '0px', height: screenHeight - 128 + 'px' }">
<a-card :body-style="{ padding: '8px 10px' }">
<div class="Crumb">
<a-breadcrumb class="reumb">
<a-breadcrumb-item>
<a-icon type="home" @click="getHome()" />
</a-breadcrumb-item>
<a-breadcrumb-item v-for="(item, index) in crumbArr" :key="index">
<a href="#" @click="hdSelect(item)">{{ item.title }}</a>
</a-breadcrumb-item>
</a-breadcrumb>
<div>
<a-button @click="loadData()" icon="redo" type="primary">刷新</a-button>
<a-divider type="vertical" />
<a-popover trigger="click" placement="bottomLeft" v-model="pushShow">
<template slot="content">
<div @click="getupload" style="margin-bottom: 10px;"><a>上传本地文件</a></div>
<div><a @click="getIncreased">新增文件夹</a></div>
</template>
<a-button icon="plus" v-if="!ShowMove">添加</a-button>
</a-popover>
<span v-if="selectedRowKeys.length > 0">
<a-divider type="vertical" />
<a-button icon="swap" @click="getMove">移动</a-button>
<a-divider type="vertical" />
<a-button icon="delete" type="danger" @click="getdele">删除</a-button>
<a-divider type="vertical" />
<a-button icon="arrow-down" @click="batcLhLoad()">下载</a-button>
</span>
<span v-if="ShowMove">
<a-divider type="vertical" />
<a-button @click="stickup" icon="snippets">粘贴</a-button>
<a-divider type="vertical" />
<a-button @click="MoveCancel" icon="retweet">取消</a-button>
</span>
</div>
</div>
</a-card>
<a-table
ref="table"
size="small"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
@change="handleTableChange"
>
<!-- 文件名 -->
<span slot="filePathSlot" slot-scope="text, record">
<span class="around">
<a-space>
<a-icon
:type="getType(record)"
style="color: #999;font-size: 18px;"
:style="{ color: record.type == 'folder' ? 'Orange' : 'blue' }"
/>
<span class="ant-dropdown-link" @click="hdSelect(record)" v-if="record.type == 'folder'">{{
record.name
}}</span>
<span class="ant-dropdown-link" v-else>{{ getwnload(record) }}</span>
</a-space>
<a-space>
<span class="contenter">
<div>
<a-icon
type="cloud-download"
v-if="record.type != 'folder'"
class="iconOne"
@click="batcLhLoad(record)"
style="font-size: 20px;margin-right:25px"
/>
</div>
</span>
<Apopover :round="record" />
</a-space>
</span>
</span>
<!-- 格式 -->
<span slot="SizeSlot" slot-scope="text, record">
<span>{{ text }} K</span>
</span>
</a-table>
<Aupload ref="uploadFrom" :crumbArr="crumbArr" @loadData="loadData" />
</a-card>
</template>
<script>
import VuexBus from '@/views/erp/papers/modal/VuexBus'
import Apopover from '@/views/erp/papers/modal/sembly/Apopover'
import Aupload from '@/views/erp/papers/modal/sembly/upload'
import FileSaver from 'file-saver'
import Vue from 'vue'
import JsZip from 'jszip'
import { postAction } from '@/api/manage'
export default {
components: {
Apopover,
Aupload
},
name: 'papersfile',
data() {
return {
crumbArr: [],
pushShow: false,
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' 共' + total + '条'
},
total: 0
},
loading: false,
ShowMove: false,
columns: [
{
title: '文件名',
dataIndex: 'name',
align: 'left',
width: 360,
ellipsis: true,
scopedSlots: { customRender: 'filePathSlot' }
},
{
title: '文件大小',
dataIndex: 'size',
align: 'center',
width: 80,
scopedSlots: { customRender: 'SizeSlot' }
},
{
title: '创建时间',
dataIndex: 'date',
align: 'center'
}
],
dataSource: [],
selectedRowKeys: [],
selectedRecord: [],
queryParam: {},
url: {
// 列表
readDirIter: '/oss/upyun/filee/listTree',
// 删除文件夹
delFileOrDir: '/oss/upyun/filee/delFileOrDir',
// 创建文件夹
mkdir: '/oss/upyun/filee/mkdir',
// 复制/移动文件
copyMoveFiles: '/oss/upyun/filee/copyMoveFiles',
// 获取文件信息
getFileInfo: '/oss/upyun/filee/getFileInfo'
}
}
},
beforeCreate() {
// 屏幕高度
this.screenHeight = document.documentElement.clientHeight
},
mounted() {
VuexBus.$on('Pafile', res => {
if (res.length > 0) {
this.crumbArr = res
} else {
this.crumbArr = []
}
this.loadData()
})
},
created() {
let that = this
that.loadData()
// 赋值为空 移动 复制
Vue.ls.remove('move')
this.ShowMove = false
},
methods: {
// 数据请求接口
loadData() {
let that = this
let params = {}
that.loading = true
if (that.crumbArr.length > 0) params.fileUrl = that.Onsift()
postAction(that.url.readDirIter, params).then(res => {
that.loading = false
if (res.success) {
that.dataSource = res.result
that.selectedRowKeys = []
that.selectedRecord = []
if (that.crumbArr.length < 1) that.getHome('loadData')
} else {
this.$message.warning(res.message)
}
})
},
// 文件名称
getwnload(round) {
let file = ''
if (round.name) {
let text = round.name.substring(round.name.lastIndexOf('/') + 1)
file = text.substring(0, text.lastIndexOf('.'))
}
return file
},
// 操作图标
getType(round) {
let ioc = ''
if (round.name) {
let file = round.name.substring(round.name.lastIndexOf('.') + 1)
if (file == 'JPG' || file == 'jpg') ioc = 'file-jpg'
if (file == 'xlsx') ioc = 'file-excel'
if (file == 'xls') ioc = 'file-excel'
if (file == 'png') ioc = 'file-image'
if (file == 'sql') ioc = 'layout'
}
if (round.type == 'folder') ioc = 'folder'
return ioc
},
// 下载
batcLhLoad(round) {
// round 传递过来的是一个对象
//dataSource为一个数组
var blogTitle = `文件下载` // 下载后压缩包的命名
var zip = new JsZip()
var promises = []
let cache = {}
let arrImg = []
// 这里是执行单个文件下载
if (round) {
arrImg.push({
path: round.name, // 文件链接
name: round.name // 文件名称
})
} else {
// 多个文件下载
this.selectedRecord.forEach((item, index) => {
arrImg.push({
path: item.name, // 文件链接
name: item.name // 文件名称
})
})
}
arrImg.forEach(item => {
const promise = this.getImgArrayBuffer(item.path).then(data => {
// 下载文件, 并存成ArrayBuffer对象(blob)
zip.file(item.name, data, { binary: true }) // 逐个添加文件
cache[item.name] = data
})
promises.push(promise)
})
Promise.all(promises)
.then(() => {
zip.generateAsync({ type: 'blob' }).then(content => {
// 生成二进制流
FileSaver.saveAs(content, blogTitle) // 利用file-saver保存文件 自定义文件名
})
})
.catch(res => {
alert('文件压缩失败')
})
},
getImgArrayBuffer(url) {
return new Promise((resolve, reject) => {
//通过请求获取文件blob格式
let xmlhttp = new XMLHttpRequest()
xmlhttp.open('GET', url, true)
xmlhttp.responseType = 'blob'
xmlhttp.onload = function() {
if (this.status == 200) {
resolve(this.response)
} else {
reject(this.status)
}
}
xmlhttp.send()
})
},
// 监听选框变化
onSelectChange(selectedRowKeys, record) {
let that = this
that.selectedRowKeys = selectedRowKeys
that.selectedRecord = record
},
handleTableChange(pagination, filters, sorter) {
//分页、排序、筛选变化时触发
if (Object.keys(sorter).length > 0) {
this.isorter.column = sorter.field
this.isorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
}
this.ipagination = pagination
this.loadData()
},
// 移动到
getMove() {
let move = this.selectedRecord
this.ShowMove = true
Vue.ls.set('move', move)
this.selectedRowKeys = []
this.selectedRecord = []
},
// 取消移动
MoveCancel() {
Vue.ls.remove('move')
this.ShowMove = false
},
// 删除
getdele() {
let that = this
this.$confirm({
title: '你确定要删除?',
content: '删除文件夹文件夹必须为空文件夹',
onOk() {
that.confirm()
},
onCancel() {}
})
},
confirm() {
let that = this
let params = {}
params.itemList = that.selectedRecord
params.fileUrl = that.Onsift()
postAction(that.url.delFileOrDir, params).then(res => {
if (res.success) {
this.$message.success('删除成功')
that.selectedRecord = []
this.selectedRowKeys = []
this.loadData()
} else {
that.$message.warning(res.message)
return false
}
})
},
// 粘贴
stickup() {
let that = this
let move = Vue.ls.get('move')
let params = {}
params.targetPath = that.Onsift()
params.copyMove = 'MOVE'
params.itemList = move
postAction(that.url.copyMoveFiles, params).then(res => {
console.log(res)
if (res.success) {
this.loadData()
} else {
that.$message.warning(res.message)
return false
}
})
that.ShowMove = false
},
// 上传
getupload() {
let that = this
that.pushShow = false
that.$refs.uploadFrom.showModal()
},
// 面包屑home
getHome(round) {
this.crumbArr = []
if (!round) this.loadData()
},
hdSelect(item) {
let that = this
console.log(item)
let company = item.filePath.split('/')
let Arr = company.filter(item => {
return item.length > 0
})
that.crumbArr = []
Arr.forEach((item1, index) => {
let path = {}
let textArr = item.filePath
.split('/')
.slice(0, index + 2)
.join('/')
path.title = item1
path.filePath = textArr
that.crumbArr.push(path)
})
that.loadData()
},
// 新增文件夹
getIncreased() {
let that = this
let reased = {}
reased.filePath = that.Onsift()
this.$confirm({
content: (
<span class="clRecord">
<span>文件名:</span>
<span class="ClVoum">
<input class="ClInput" vModel={reased.fileUrl} />
</span>
</span>
),
onOk() {
that.onMkdir(reased)
},
onCancel() {}
})
},
// 新增文件夹调用接口
onMkdir(round) {
let that = this
let params = round
params.fileUrl = round.filePath + '/' + round.fileUrl
postAction(that.url.mkdir, params).then(res => {
if (res.success) {
that.loadData(round.filePath)
} else {
that.$message.warning(res.message)
}
})
},
// 筛选面包屑文件地址
Onsift() {
let that = this
let text = '/'
if (that.crumbArr.length > 0) {
let index = that.crumbArr.length - 1
text = that.crumbArr[index].filePath
}
return text
}
}
}
</script>
<style scoped lang="less">
.around {
display: flex;
justify-content: space-between;
align-items: center;
align-self: center;
}
.contenter {
display: none;
}
.around:hover .contenter {
display: block;
}
.iconOne:hover {
color: blue;
}
.icontwe:hover {
color: blue;
}
.iconSan:hover {
color: blue;
}
.Crumb {
display: flex;
justify-content: space-between;
align-items: center;
align-self: center;
}
.ClVoum {
margin-left: 10px;
}
.ClInput {
padding-left: 10px;
border: 1px solid #d9d9d9;
border-radius: 3px;
}
.ClInput:focus {
outline: none;
border: 1px solid #597ef7;
}
</style>
4、drabute文件
<template>
<a-drawer width="600px" title="属性" placement="right" :closable="false" :visible="visible" @close="onClose">
<a-row>
<a-col :md="24">
<a-form-item label="名字:" :labelCol="{ span: 4 }" :wrapperCol="{ span: 17 }">
<span><a-input disabled v-model="round.name" placeholder=" "/></span>
</a-form-item>
</a-col>
<a-col :md="24">
<a-form-item label="大小:" :labelCol="{ span: 4 }" :wrapperCol="{ span: 17 }">
<span><a-input disabled v-model="round.size" placeholder=" "/></span>
</a-form-item>
</a-col>
<a-col :md="24">
<a-form-item label="名字:" :labelCol="{ span: 4 }" :wrapperCol="{ span: 17 }">
<span><a-input disabled v-model="round.name" placeholder=" "/></span>
</a-form-item>
</a-col>
</a-row>
</a-drawer>
</template>
<script>
import { postAction } from '@/api/manage'
export default {
data() {
return {
visible: false,
url: {
// 列表
getFileInfo: '/oss/upyun/filee/getFileInfo'
}
}
},
props: {
round: {
type: Object,
default: () => ({})
}
},
methods: {
showDrawer() {
this.visible = true
this.loadData()
},
loadData() {
let that = this
let params = {}
params.fileUrl = that.round.filePath
postAction(that.url.getFileInfo, params).then(res => {
if (res.success) {
} else {
that.$message.warning(res.message)
}
})
},
onClose() {
this.visible = false
}
}
}
</script>
5、Apopover,模块
<template>
<div>
<a-popover trigger="click" v-model="visible">
<span slot="content">
<a-row style="width: 100px;">
<a-col :md="24" @click="showConfirm"> <a-icon type="edit" style="margin:8px 20px 8px 5px" />重命名 </a-col>
<a-col :md="24" @click="gettribute">
<a-icon type="question-circle" style="margin:8px 20px 8px 5px" />属性</a-col
>
</a-row>
</span>
<a-icon type="small-dash" class="iconSan" style="font-size: 20px;" />
</a-popover>
<drabute ref="buteFrom" :round="round" />
</div>
</template>
<script>
import drabute from '@/views/erp/papers/modal/drabute'
export default {
name: 'Apopover',
components: {
drabute
},
data() {
return {
visible: false
}
},
props: {
round: {
type: Object,
default: () => ({})
}
},
methods: {
// 属性
gettribute() {
let that = this
that.visible = false
that.$refs.buteFrom.showDrawer()
},
// 重命名
showConfirm() {
this.visible = false
this.$confirm({
content: (
<span class="clRecord">
<span>文件名:</span>
<span class="ClVoum">
<input class="ClInput" vModel={this.round.name} />
</span>
</span>
),
onOk() {
console.log('修改方法')
},
onCancel() {}
})
}
}
}
</script>
<style scoped lang="less">
.box {
display: flex;
flex-direction: column;
}
.clRecord {
display: flex;
justify-content: center;
margin-top: 20px;
align-items: center;
align-self: center;
font-size: 16px;
}
.ClVoum {
margin-left: 10px;
}
.ClInput {
padding-left: 10px;
border: 1px solid #d9d9d9;
border-radius: 3px;
}
.ClInput:focus {
outline: none;
border: 1px solid #597ef7;
}
</style>
7、upload模块
<!-- 上传 -->
<template>
<a-modal v-model="visible" title="文件上传" @ok="handleOk" v-if="visible">
<a-upload-dragger
name="file"
:multiple="true"
:method="'post'"
:action="uploadAction"
@change="handleChange"
:headers="headers"
:data="{
fileUrl: fileUrlText
}"
:remove="handleFileRemove"
>
<p class="ant-upload-drag-icon"><a-icon type="inbox" /></p>
<p class="ant-upload-text">
请把需要上传的文件拖放进来,或者点击上传文件
</p>
</a-upload-dragger>
</a-modal>
</template>
<script>
import { postAction } from '@/api/manage'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import Vue from 'vue'
export default {
name: 'upload',
data() {
return {
visible: false,
uploadLoading: false,
headers: '',
fileUrlText: '/',
defaultFileList: [],
url: {
// 上传
uploadUpyun: '/oss/upyun/filee/uploadUpyun',
// 删除
deleteFile: '/oss/upyun/filee/deleteFile'
}
}
},
// 传递过来的路径
props: {
crumbArr: {
type: Array,
default: []
}
},
watch: {
crumbArr: {
immediate: true,
handler(val) {
let that = this
if (val.length > 0) {
let index = val.length - 1
that.fileUrlText = val[index].filePath
}
}
}
},
created() {
// 拿到本地token
const token = Vue.ls.get(ACCESS_TOKEN)
this.headers = { 'X-Access-Token': token }
},
computed: {
uploadAction: function() {
// 抛出上传接口
return window._CONFIG['domianURL'] + this.url.uploadUpyun
}
},
methods: {
showModal() {
this.visible = true
},
handleOk() {
this.$emit('loadData')
this.defaultFileList = []
this.visible = false
},
// 文件上传
handleChange(info) {
if (info.file.status === 'uploading') {
this.uploadLoading = true
return
}
if (info.file.status === 'done') {
var response = info.file.response
this.uploadLoading = false
if (response.success) {
this.$message.success('上传成功')
} else {
this.$message.warning(response.message)
}
}
},
// 删除方法
handleFileRemove(file) {
let that = this
let params = {}
params.fileUrl = file.response.result.fileUrl
postAction(that.url.deleteFile, params).then(res => {
if (res.success) {
this.$message.success('删除成功')
} else {
that.$message.warning(res.message)
return false
}
})
}
}
}
</script>
<style scoped lang="less"></style>
gitt:后期更新