記錄一下之前寫過的一個文件管理系統(tǒng)demo。
功能包括文件夾的新增、刪除、重命名及移動,文件的上傳、刪除、移動及下載功能。
相關(guān)功能的操作直接和 后端 進行請求交互。
因為該demo集成在大的系統(tǒng)中,懶得提取建庫開源,所以算是只記錄思路。
運行截圖
- 右鍵文件夾時顯示操作目錄
- 右鍵文件時顯示操作目錄
- 新建文件夾
- 上傳文件
- 重命名文件夾
- 移動
實現(xiàn)代碼
shareSpace.vue 為頁面組件
addFolder.vue 為文件上傳彈窗組件
moveFolder.vue 為移動文件/文件夾彈窗組件
// shareSpace.vue
<template>
<div class="app-container">
<el-page-header class="pageHeader" :content="'當前所處:' + currentLocationName" @back="goBack">
</el-page-header>
<el-divider></el-divider>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5" style="float: right;">
<el-button plain icon="el-icon-refresh" size="mini" @click="refreshGetList">刷新</el-button>
</el-col>
<el-col :span="1.5" style="float: right;">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addFolder">新建文件夾</el-button>
</el-col>
<el-col :span="1.5" style="float: right;">
<el-button type="success" plain icon="el-icon-upload" size="mini" @click="addFile">上傳文件</el-button>
</el-col>
</el-row>
<!-- 文件瀏覽區(qū) -->
<div style="overflow: hidden;">
<el-card class="drawing_card" v-loading="cardLoading" style="height: 60vh">
<template v-if="folderList.length === 0 && filesList.length === 0">
<el-empty description="暫無文件,請創(chuàng)建一個文件夾吧" style="height:60vh"></el-empty>
</template>
<!-- 文件夾 -->
<div v-for="( item, index ) in folderList ">
<div class="folderContainer">
<div class="folderWrapper" @dblclick="doubleClickFolder(index, item)"
@contextmenu.prevent.stop="rightClickFolder(index, item, $event)">
<img src="@/assets/images/folder/folder.png" style="width: 100px;height: 90px;margin-top: -13px"
@contextmenu.prevent.stop="rightClickFolder(index, item, $event)" />
<div class="folderName">
<span>{{
item.folderName.length > 10 ? item.folderName.substring(0, 6) + '...' : item.folderName
}}</span>
</div>
</div>
</div>
</div>
<!-- 文件 -->
<div v-for="( item, index ) in filesList ">
<div class="folderContainer">
<div class="folderWrapper" @dblclick="down(item.fileUrl)">
<img src="@/assets/images/folder/fileImg.png" style="width: 100px;height: 90px;margin-top: -13px"
@contextmenu.prevent.stop="rightClickfile(index, item, $event)" />
<div class="folderName">
<span>{{
item.fileName.length > 10 ? item.fileName.substring(0, 6) + '...' : item.fileName
}}</span>
</div>
</div>
</div>
</div>
</el-card>
</div>
<!-- 文件夾【右鍵菜單】 -->
<div class="add-folder-9" :style="folderStyle" v-show="folderShow">
<div class="add-folder-1">
<div class="add-folder-2" @click="openFolder">
打開文件夾
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div>
<div class="add-folder-2" @click="moveFolder">
移動
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div>
<div class="add-folder-2" @click="updateFloder">
重命名
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div>
<div class="add-folder-6" @click="deleteFolder">
刪 除
</div>
</div>
</div>
<!-- 文件【右鍵菜單】 -->
<div class="add-folder-9" :style="fileStyle" v-show="fileShow">
<div class="add-folder-1">
<div class="add-folder-2">
<a :href="clickFilePath" download="1">下載文件</a>
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div>
<!-- <div class="add-folder-2" @click="updateFloder">
重命名
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div> -->
<div class="add-folder-2" @click="moveFolder">
移動
</div>
<div style="border: 2px solid rgba(18,17,42,.07)"></div>
<div class="add-folder-6" @click="deleteFileFun">
刪 除
</div>
</div>
</div>
<!-- 上傳文件 彈窗 -->
<addFolder ref="addFolder1" :currentLocationId="currentLocationId" />
<moveFolder ref="moveFolder1" :moveData="moveData"></moveFolder>
</div>
</template>
<script>
import addFolder from '../components/addFolder.vue'
import moveFolder from '../components/moveFolder.vue'
import { qeryFolderList, createPublicFolder, renameFolder, deleteFolder, deleteFile } from '@/api/folder/folder'
export default {
name: 'shareSpace',
components: { addFolder, moveFolder },
data() {
return {
historyFolderId: 0,//歷史文件夾id,用于【返回上一級】
historyFolderName: '',//歷史文件夾name,用于【返回上一級】
currentLocationId: 0,//當前所處位置(文件夾)id,0為根目錄
currentLocationName: '共享空間',//當前所處位置(文件夾)名
//移動文件(夾)時需要的參數(shù)
moveData: {
typeofFolder: 0,//所選對象的類型(1:文件夾;2:文件)
clickFolderId: -1,//被右鍵的文件夾id
},
cardLoading: false,
folderList: [],//文件夾列表
filesList: [],//文件列表
// 文件夾 右鍵菜單欄
folderStyle: {
left: '0px',
top: '0px'
},
folderShow: false,
clickFolderId: -1,//被右鍵的文件夾id
clickFolderName: '',//被右鍵的文件夾名
// 文件 右鍵菜單欄
fileStyle: {
left: '0px',
top: '0px'
},
fileShow: false,
clickFileId: -1,//被右鍵的文件id
clickFileName: '',//被右鍵的文件名
clickFilePath: '',//被右鍵的文件路徑-已加上下載的路徑網(wǎng)站前端
queryParams: { //查詢參數(shù)
folderId: 0 //目標文件(夾)id,值為0則查詢根目錄文件(夾)
}
}
},
methods: {
a() {
window.open(`這里填服務器儲存文件的地址啦~` + this.clickFileName);
},
//返回上一級
goBack() {
if (this.currentLocationId == 0) {
this.$message({
message: '已經(jīng)不能再往后退啦!',
type: 'warning'
});
} else {
this.queryParams.folderId = this.historyFolderId;
this.currentLocationId = this.historyFolderId;
this.currentLocationName = this.historyFolderName == null ? '文件管理空間' : this.historyFolderName;
this.historyFolderId = this.currentLocationId;
this.historyFolderName = this.currentLocationName;
this.getList();
}
},
// 獲取列表數(shù)據(jù)
getList() {
this.loading = true
qeryFolderList(this.queryParams).then(response => {
console.log(response)
this.folderList = response.data.folders
this.filesList = response.data.sysFiles
this.historyFolderId = response.data.sysFolder == null ? 0 : response.data.sysFolder.parentId;
this.historyFolderName = response.data.sysFolder == null ? '文件管理空間' : response.data.sysFolder.parentName;
})
},
// 刷新當前列表
refreshGetList() {
this.queryParams.folderId = this.currentLocationId;
this.getList()
this.$message({
message: '已經(jīng)成功獲取最新數(shù)據(jù)啦!',
type: 'success'
});
this.initClickId()
},
//上傳文件
addFile() {
this.$refs.addFolder1.open();
},
//創(chuàng)建文件夾
addFolder() {
this.$prompt('請輸入新文件夾名稱', '創(chuàng)建文件夾', {
confirmButtonText: '確定',
cancelButtonText: '取消',
}).then(({ value }) => {
let sysFolder = {
folderName: value,
parentId: this.currentLocationId
}
createPublicFolder(sysFolder).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '創(chuàng)建成功 '
});
const that = this;
setTimeout(function () {
that.refreshGetList(); // 刷新當前頁面
}, 500);
} else {
this.$message({
type: 'error',
message: '創(chuàng)建失敗 '
});
}
})
}).catch(() => {
});
},
// 重命名文件夾
updateFloder() {
this.folderShow = false;
this.$prompt('請輸入文件夾的新名稱', '重命名', {
confirmButtonText: '確定',
cancelButtonText: '取消',
inputValue: this.clickFolderName,
inputErrorMessage: '輸入不能為空',
inputValidator: (value) => { // 點擊按鈕時,對文本框里面的值進行驗證
if (!value) {
return '輸入不能為空';
}
},
}).then(({ value }) => {
let sysFolder = {
folderName: value,
folderId: this.clickFolderId //默認為0
}
renameFolder(sysFolder).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '修改成功 '
});
let that = this;
setTimeout(function () {
that.refreshGetList(); // 刷新當前頁面
}, 500);
} else {
this.$message({
type: 'error',
message: '修改失敗 '
});
}
})
})
},
//刪除文件夾
deleteFolder() {
this.folderShow = false;
this.$confirm('此操作將永久刪除該文件夾,包括文件夾內(nèi)的所有內(nèi)容,是否繼續(xù)?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteFolder(this.clickFolderId).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '刪除成功 '
});
let that = this;
setTimeout(function () {
that.refreshGetList(); // 刷新當前頁面
}, 1000);
} else {
this.$message({
type: 'error',
message: '刪除失??! '
});
}
})
})
},
//打開文件夾
openFolder() {
this.folderShow = false;
this.queryParams.folderId = this.clickFolderId;
this.currentLocationId = this.clickFolderId;
this.currentLocationName = this.clickFolderName;
this.getList();
},
//鼠標雙擊文件夾
doubleClickFolder(index, item) {
this.clickFolderId = item.folderId;
this.clickFolderName = item.folderName;
this.openFolder();
},
//文件夾右鍵
rightClickFolder(index, item, e) {
this.initClickId()
this.clickFolderId = item.folderId
this.clickFolderName = item.folderName
this.folderStyle.left = e.pageX - 140 + 'px'
this.folderStyle.top = e.pageY - 70 + 'px'
this.folderShow = true
this.moveData.typeofFolder = 1
},
//文件 右鍵
rightClickfile(index, item, e) {
this.initClickId()
this.clickFileId = item.fileId
this.clickFileName = item.fileName
this.clickFilePath = "https://huang-pu.oss-cn-guangzhou.aliyuncs.com/" + item.filePath
this.fileStyle.left = e.pageX - 140 + 'px'
this.fileStyle.top = e.pageY - 70 + 'px'
this.fileShow = true
this.moveData.typeofFolder = 2
},
//刪除文件
deleteFileFun() {
this.fileShow = false;
this.$confirm('此操作將永久刪除該文件, 是否繼續(xù)?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteFile(this.clickFileId).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '刪除成功 '
});
let that = this;
setTimeout(function () {
that.refreshGetList(); // 刷新當前頁面
}, 1000);
} else {
this.$message({
type: 'error',
message: '刪除失??! '
});
}
})
})
},
//移動文件(夾)
moveFolder() {
this.fileShow = false
//通過判斷文件/文件夾被右鍵選擇而進行參數(shù)存儲
if (this.clickFolderId != -1) {
this.moveData.clickFolderId = this.clickFolderId;
} else {
this.moveData.clickFolderId = this.clickFileId;
}
this.$refs.moveFolder1.open();
},
//初始化右鍵選擇相關(guān)參數(shù)
initClickId() {
this.clickFileId = -1;
this.clickFolderId = -1;
this.fileShow = false;
this.folderShow = false;
}
},
mounted() {
//監(jiān)聽鼠標點擊事件
document.addEventListener("click", (e) => {
if (!this.folderShow && !this.fileShow) return; // 如果右鍵菜單不顯示,則不處理點擊事件
let target = e.target;
while (target && target.parentNode) {
if (target.parentNode.class === "folderContainer") {
return;
}
target = target.parentNode;
}
this.folderShow = false;
this.fileShow = false; // 如果點擊的是其他區(qū)域,則隱藏
this.clickFolderId = -1;
this.clickFileId = -1;
});
},
created() {
this.getList()
}
}
</script>
<style lang="scss">
.pageHeader {
.el-page-header__content {
font-size: 16px !important;
}
}
</style>
<style scoped lang="scss">
.drawing_card {
width: 100%;
height: 100%;
float: left;
margin-top: 15px;
overflow: auto;
box-shadow: 0 5px 5px rgb(0 0 0 /10%);
transition: all 0.9s;
border-radius: 10px;
}
.folderContainer {
width: 150px;
float: left;
display: block;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 20px;
margin-left: 30px;
}
.folder {
width: 110px;
height: 80px;
perspective: 600px;
transform-style: preserve-3d;
cursor: pointer;
}
.folderWrapper {
width: 140px;
height: 130px;
padding: 20px 20px 10px 20px;
position: relative;
transition: all .2s ease;
border-radius: 6px;
cursor: pointer;
}
.folderWrapper:hover {
background-color: aliceblue;
}
.folderName {
margin-top: 5px;
font-size: 14px;
line-height: 20px;
text-align: center;
width: 100px;
}
.add-folder-9 {
position: absolute;
display: flex;
justify-content: center;
padding: 2px;
align-items: center;
width: 130px;
background-color: rgba(6, 13, 20, .18);
border-radius: 12px;
box-shadow: 0px 8px 24px rgba(25, 25, 26, .06), 0px 4px 16px rgba(25, 25, 26, .04), 0px 0px 4px rgba(25, 25, 26, .04);
}
.add-folder-1 {
overflow: hidden;
width: 97%;
height: 96%;
background-color: #fff;
border-radius: 10px;
}
.add-folder-2 {
color: #19191a;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 36px;
// margin-top: 5px;
// margin-bottom: 5px
}
.add-folder-2:hover {
background-color: rgba(6, 13, 20, .18);
// border-radius: 10px;
cursor: pointer;
}
.add-folder-6 {
color: #19191a;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 36px;
// margin-top: 5px;
}
.add-folder-6:hover {
background-color: red;
// border-radius: 10px;
cursor: pointer;
}
</style>
移動操作時,當點擊移動后,需要先獲取整個系統(tǒng)的樹型目錄,將該文件(夾)所屬的父文件夾id更改為 樹型目錄中所選的文件夾id 。
//moveFolder.vue
<template>
<el-dialog v-if="dialogVisible" :modal-append-to-body="false" :close-on-click-modal="false" title="移動"
:visible.sync="dialogVisible" :show-close="false" width="400px" class="moveFolderDialog">
<el-alert title="請選擇要將當前文件(夾)移動到:" type="info" show-icon>
</el-alert>
<el-tree accordion :data="data" node-key="id" ref="tree" highlight-current @node-click="handleNodeClick">
</el-tree>
<div style="margin-top: 20px">
<el-button type="success" @click="submit">確定</el-button>
<el-button @click="close">取消</el-button>
</div>
</el-dialog>
</template>
<script>
import { getTreeDirectory, moveFolder, moveFile } from "@/api/folder/folder";
export default {
name: 'moveFolder',
props: ['moveData'],
// moveDate對象中有兩個參數(shù): typeofFolder: 0,//所選對象的類型(1:文件夾;2:文件)
// clickFolderId: -1,//所選對象的id
data() {
return {
dialogVisible: false,
data: [],//樹型目錄
defaultProps: {
children: 'children',
label: 'label'
},
clickDirectoryId: -1,//所選擇的移動目標文件夾id
}
},
methods: {
open() {
this.dialogVisible = true,
getTreeDirectory().then(res => {
console.log(res)
this.data = res.data
})
},
close() {
this.dialogVisible = false
},
submit() {
if (this.moveData.typeofFolder == 1 && this.moveData.clickFolderId == this.clickDirectoryId) {
this.$message({
type: 'error',
message: '移動失敗!請勿把文件夾移動到它本身中! '
});
} else {
if (this.moveData.typeofFolder == 1) {
this.moveFolderFun()
} else if (this.moveData.typeofFolder == 2) {
this.moveFileFun()
}
}
},
//移動 文件夾
moveFolderFun() {
let dataObj = {
folderId: this.moveData.clickFolderId,
parentId: this.clickDirectoryId
}
moveFolder(dataObj).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '修改成功 '
});
let that = this;
this.dialogVisible = false
setTimeout(function () {
that.$parent.refreshGetList(); // 刷新當前頁面
}, 500);
} else {
this.$message({
type: 'error',
message: '修改失敗 '
});
}
})
},
//移動 文件
moveFileFun() {
let dataObj = {
fileId: this.moveData.clickFolderId,
folderId: this.clickDirectoryId
}
moveFile(dataObj).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '修改成功 '
});
let that = this;
this.dialogVisible = false
setTimeout(function () {
that.$parent.refreshGetList(); // 刷新當前頁面
}, 500);
} else {
this.$message({
type: 'error',
message: '修改失敗 '
});
}
})
},
//樹型目錄被選擇時
handleNodeClick(DirectoryId) {
this.clickDirectoryId = DirectoryId.id
}
}
}
</script>
<style lang="scss">
.moveFolderDialog {
.el-dialog__body {
padding-top: 0 !important;
}
.el-alert {
margin-bottom: 20px;
}
}
</style>
文件上傳時,后端同學需要對文件信息做進一步處理,即先執(zhí)行自定義policy()方法獲取服務器存儲的key加入文件信息再存入數(shù)據(jù)庫。
不必要,可根據(jù)個人需求直接修改返回文件信息即可。
//addFolder.vue
<template>
<el-dialog v-if="dialogVisible" :modal-append-to-body="false" :close-on-click-modal="false" title="上傳文件"
:visible.sync="dialogVisible" :show-close="false" width="400px">
<el-upload ref="upload" :data="dataObj" action="這里填寫文件上傳到的服務器地址" class="upload-demo"
drag :limit="1" :on-success="uploadSuccess" :on-error="uploadError" :on-exceed="handleExceed"
:before-upload="beforeUpload" :auto-upload="false">
<i class="el-icon-upload"></i>
<div class="el-upload__text">將文件拖到此處,或<em>點擊上傳,當前目錄只允許上傳1個文件</em></div>
</el-upload>
<div style="margin-top: 20px">
<el-button icon="el-icon-upload2" type="success" @click="submit">提交</el-button>
<el-button @click="close">取消</el-button>
</div>
</el-dialog>
</template>
<script>
import { policy, addFile } from "@/api/folder/folder";
import { getUUID } from "../../../utils/index"
export default {
name: 'addFolder',
props: ['currentLocationId'], //當前所處文件夾id
data() {
return {
// oss資源
dataObj: {},
dialogVisible: false,
// 文件信息 - 存于后端數(shù)據(jù)庫
fileInfo: {
fileName: '',
filePath: '',
fileSize: 0,//單位為kb
folderId: 0
}
}
},
methods: {
open() {
this.dialogVisible = true
},
close() {
this.dialogVisible = false
this.$parent.refreshGetList();
},
//文件改變調(diào)用
handleExceed() {
this.$message.error('當前目錄只能上傳一個文件!');
},
//上傳成功
uploadSuccess(res) {
this.dialogVisible = false
this.$parent.refreshGetList();
},
//上傳失敗
uploadError() {
this.$message.error('服務器異常請重試!');
},
//上傳文件
submit() {
this.$refs.upload.submit();
},
// 資源上傳前
beforeUpload(files) {
return new Promise((resolve, reject) => {
policy().then(response => {
//數(shù)據(jù)處理因為業(yè)務需求寫入的,不必要。
//存儲服務器數(shù)據(jù)處理
this.dataObj.policy = response.data.policy
this.dataObj.signature = response.data.signature
this.dataObj.ossaccessKeyId = response.data.accessid
this.dataObj.dir = response.data.dir
this.dataObj.host = response.data.host
this.dataObj.key = response.data.dir + getUUID() + files.name
console.log(this.dataObj)
//后端數(shù)據(jù)庫數(shù)據(jù)處理
this.fileInfo.fileName = files.name;
this.fileInfo.filePath = this.dataObj.key;
this.fileInfo.fileSize = parseInt(files.size / 2024);//file.size的單位為字節(jié),轉(zhuǎn)換成kb
console.log(this.fileInfo)
resolve(true)
this.fileInfo.folderId = this.currentLocationId;//確定該文件所處的文件夾id
//上傳到后端數(shù)據(jù)庫
addFile(this.fileInfo).then(res => {
if (res.code == 200) {
this.$message({
type: 'success',
message: '上傳成功 '
});
} else {
this.$message({
type: 'error',
message: '上傳失敗 '
});
}
})
})
})
},
}
}
</script>
<style scoped lang="scss"></style>
api不知道需要不需要,一并丟上來好了。
該系統(tǒng)是集成在基于ruoyi框架的系統(tǒng)中。文章來源:http://www.zghlxwxcb.cn/news/detail-837300.html
//folder.js
import request from '@/utils/request'
//查詢文件夾及文件列表
export function qeryFolderList(query) {
return request({
url: '/system/folder/listFolderAndFile/' + query.folderId,
method: 'get',
params: query
})
}
//移動 前置請求-獲取所有目錄結(jié)構(gòu)
export function getTreeDirectory() {
return request({
url: '/system/folder/listFolderids',
method: 'get'
})
}
//===================文件夾=====================
//新建公共文件夾
export function createPublicFolder(data) {
return request({
url: '/system/folder',
method: 'post',
data: data
})
}
//重命名文件夾
export function renameFolder(data) {
return request({
url: '/system/folder',
method: 'put',
data: data
})
}
//刪除文件夾
export function deleteFolder(folderId) {
return request({
url: '/system/folder/' + folderId,
method: 'delete'
})
}
//移動文件夾
export function moveFolder(data) {
return request({
url: '/system/folder',
method: 'put',
data: data
})
}
//===================文件=====================
// oss資源上傳 - 后端服務器
export function policy() {
return request({
url: '/system/ziyuan/oss/policy',
method: 'get'
})
}
//上傳文件-后端數(shù)據(jù)庫
export function addFile(data) {
return request({
url: '/system/file',
method: 'post',
data: data
})
}
//刪除文件
export function deleteFile(fileId) {
return request({
url: '/system/file/' + fileId,
method: 'delete'
})
}
//移動文件夾
export function moveFile(data) {
return request({
url: '/system/file',
method: 'put',
data: data
})
}
TODO:
沒有制作分頁查詢操作。
有點亂(磕頭,有空再整理。文章來源地址http://www.zghlxwxcb.cn/news/detail-837300.html
到了這里,關(guān)于基于Vue+Element UI的文件管理系統(tǒng)-Demo的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!