主页 > 手机  > 

简易的仿桌面文件夹上传(vue2)

简易的仿桌面文件夹上传(vue2)
<el-tab-pane label="项目资料"> <Information :projectId="form.id"></Information> </el-tab-pane>

Information/index.vue

<template> <div> <el-row :gutter="20"> <!--文件夹目录数据--> <el-col :span="4" :xs="24"> <div class="head-container"> <el-input v-model="name" placeholder="请输入文件夹名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" /> </div> <div class="head-container"> <el-tree :data="folderOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" /> </div> </el-col> <el-col :span="20" :xs="24"> <div class="top"> <!-- <el-button size="small" type="primary" plain @click="goBack" v-if="currentFolder">--> <!-- <i class="el-icon-back" style="margin-right: 2px;" /> 返回--> <!-- </el-button>--> <el-upload v-if="currentFolder.id != 0" multiple :action="uploadFileUrl" :file-list="fileList" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" ref="fileUpload"> <el-button slot="trigger" size="small" type="success" plain><i class="el-icon-upload" style="margin-right: 2px;"/>上传文件</el-button> </el-upload> <el-button v-if="currentFolder.id != 0" size="small" type="primary" plain @click="createNewFolder"><i class="el-icon-plus" style="margin-right: 2px;" /> 新建文件夹</el-button> <el-button type="info" plain @click="queryData"><i class="el-icon-refresh-left" style="margin-right: 2px;"></i>主目录</el-button> </div> <div class="main"> <ContextMenu :menu="['重命名', '删除']" :row="selectedRow" @action="handleContextMenuAction"> <el-table ref="singleTable" :data="files" highlight-current-row style="width: 100%" @row-dblclick="handleRowClick" @row-contextmenu="handleRightClick"> <el-table-column label="文件名" > <template slot-scope="scope"> <!-- <svg-icon :icon-class="scope.row.type === 'folder' ? 'folder' : 'fileEmpty'" style="font-size: 26px" />--> <div v-if="scope.row.type === 'folder'"> <svg-icon :icon-class="'folder'" style="font-size: 26px" /> <span style="margin-left: 10px">{{ scope.row.name }}</span> </div> <file-upload v-else :only-list="true" v-model="scope.row.fileUrl"></file-upload> </template> </el-table-column> <el-table-column property="createBy" label="创建者" ></el-table-column> <el-table-column property="createTime" label="创建时间"></el-table-column> </el-table> </ContextMenu> </div> </el-col> </el-row> <!-- 新建文件夹对话框--> <el-dialog title="新建文件夹" :visible.sync="dialogVisible" width="30%" append-to-body> <el-form :model="form" ref="numberValidateForm" label-width="100px" class="demo-ruleForm"> <el-form-item label="文件名称" prop="name" :rules="[{ required: true, message: '文件名称不能为空'}]" > <el-input v-model.number="form.name" autocomplete="off"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">取 消</el-button> <el-button type="primary" @click="submitFile">确 定</el-button> </span> </el-dialog> </div> </template> <script> import { getToken } from "@/utils/auth"; import FileUpload from "@/components/FileUpload/index.vue"; import { getFolderFile, addFolder, getFildsList, addFile, delFolder, delFolderFile, updateFolder } from "@/api/system/project"; import ContextMenu from "@/components/ContextMenu/index.vue"; export default { name: 'Information', components: { FileUpload, ContextMenu }, props: { // 项目id projectId: { type: String, default: "" } }, data() { return { currentFolder: { id: 0, }, // 当前所在文件夹的信息 folderOptions: null, // 文件夹树选项 name: null, // 文件夹名称 defaultProps: { children: "children", label: "label" }, invoiceFile: null, uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传文件服务器地址 headers: { Authorization: "Bearer " + getToken(), }, fileList: [], dialogVisible: false, form: { name: '' }, files: [], contextMenuVisible: false, // 是否显示右键弹框 menuPosition: { x: 0, y: 0 }, // 右键菜单的显示位置 selectedRow: null // 右键选中的行 }; }, watch: { // 根据名称筛选部门树 name(val) { this.$refs.tree.filter(val); } }, created() { this.queryData() }, methods: { // 初始化列表 queryData() { this.getDeptTree(); this.getList(0); }, // 获取列表数据 getList(parentId) { getFolderFile({ parentId, projectId: this.projectId }).then(response => { let folders = response.data.map(item => ({ ...item, type: 'folder' })); getFildsList(parentId, this.projectId).then(res => { let files = res.data.map(item => ({ ...item, name: item.fileName, type: 'fileEmpty' })); this.files = [...folders, ...files]; }); }); }, // 文件表格点击事件 handleRowClick(row) { if (row.type === 'folder') { this.currentFolder = row; this.getList(row.id); // 选中树形结构中的对应节点 this.$nextTick(() => { this.$refs.tree.setCurrentKey(row.id); // 使用当前文件夹的 id 设置树节点选中 }); } }, // 右键点击事件 handleRightClick(row, column, event) { event.preventDefault(); // 阻止默认右键菜单 this.selectedRow = row; // 设置当前右键点击的行 console.log(' this.selectedRow', this.selectedRow) }, // 鼠标右键的点击事件 handleContextMenuAction(action, row) { console.log('handleContextMenuAction', action, row) if (action === "删除") { this.deleteRow(row); // 删除操作 } else if (action === "重命名") { this.renameRow(row); // 重命名操作 } }, // 删除 deleteRow(row) { this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { if (row.type === 'folder') { delFolder(row.id).then(response => { this.getList(this.currentFolder.id); }); } else { delFolderFile(row.id).then(response => { this.getList(this.currentFolder.id); }); } this.$message({ type: 'success', message: '删除成功!' }); }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); }); }, // 重命名 renameRow(row) { this.$prompt('', '重新命名', { confirmButtonText: '确定', cancelButtonText: '取消', inputValue: row.name }).then(({ value }) => { if(row.type === 'folder') { updateFolder({id: row.id, name: value}).then(response => { this.getList(this.currentFolder.id); this.$message({ type: 'success', message: '修改成功!' }); }) } }).catch(() => { this.$message({ type: 'info', message: '取消输入' }); }); }, /** 查询部门下拉树结构 */ getDeptTree() { getFolderFile({ projectId: this.projectId}).then(response => { let originData = response.data.map(item => { return { id: item.id, parentId: item.parentId, label: item.name, children: item.children } }) this.folderOptions = this.handleTree(originData) }); }, // 筛选节点 filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; }, // 节点单击事件 handleNodeClick(data) { this.currentFolder = data; this.getList(data.id); }, // 文件上传成功的回调 handleUploadSuccess(res, file) { if (res.code === 200) { const params = { folderId: this.currentFolder.id || 0, fileName: res.originalFilename, fileUrl: res.url, projectId: this.projectId } // 上传文件 addFile(params).then(res => { this.getList(this.currentFolder.id) this.$modal.msgSuccess("上传成功"); }) } else { this.$modal.msgError(res.msg); } }, // 新建文件夹 createNewFolder() { this.dialogVisible = true; }, // 提交新建文件夹 submitFile() { // 在这里实现新建文件夹的逻辑 const params = { parentId: this.currentFolder.id, name: this.form.name, projectId: this.projectId }; addFolder(params).then(res => { this.getList(this.currentFolder.id) this.getDeptTree(); this.form = { name: undefined } }) this.dialogVisible = false; }, } }; </script> <style lang="scss"> .el-popover { z-index: 9999 !important; } ::v-deep .svg-icon { vertical-align: -0.28em; } .top { display: flex; justify-content: flex-end; align-items: center; //margin-bottom: 20px; height: 56px; .el-button { margin-right: 10px; } } .file-name { font-size: 14px; margin-left: 10px; width: 300px; } .file-creater { font-size: 14px; width: 100px; } .file-time { font-size: 14px; color: #999; width: 100px; } .file-desc { color: #999; font-size: 14px; } .main { border: 1px solid #eee; border-radius: 4px; box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1); margin: 0 10px; padding: 16px; box-sizing: border-box; .h-file-row, .h-file-title { display: flex; align-items: center; border-bottom: 1px solid #eee; padding: 6px 0; } .h-file-row:hover { background-color: #f0f9ff; } } </style>

ContentMenu/index.vue

<template> <div ref="contentRef" v-bind="$attrs"> <slot></slot> <Teleport to="body" v-if="showMenu"> <div class="content-menu" :style="{ left: x + 'px', top: y + 'px' }"> <div class="menu-list"> <div class="menu-item" v-for="(item, index) in menu" :key="index" @click="handleMenuClick(item, $event)"> {{ item }} </div> </div> </div> </Teleport> </div> </template> <script> import Teleport from "../Teleport/index.vue" export default { name: 'ContextMenu', components: { Teleport }, props: { menu: { type: Array, default: () => ['重命名', '删除'] }, row: { type: Object, default: () => ({}) } }, data() { return { showMenu: false, x: 0, y: 0, mode: process.env.NODE_ENV, isTeleport: false, // 控制什么时候被传送 }; }, mounted() { if (this.mode === 'production') { return; } const div = this.$refs.contentRef; div.addEventListener('contextmenu', this.showContextMenu); window.addEventListener('click', this.closeMenu, true); }, beforeDestroy() { const div = this.$refs.contentRef; if (div) { div.removeEventListener('contextmenu', this.showContextMenu); } window.removeEventListener('click', this.closeMenu); }, methods: { showContextMenu(e) { e.preventDefault(); e.stopPropagation(); this.x = e.clientX; this.y = e.pageY; this.showMenu = true; }, closeMenu() { this.showMenu = false; }, handleMenuClick(item, e) { e.stopPropagation(); this.showMenu = false; this.$emit("action", item, this.row); } } }; </script> <style lang="scss" scoped> .content-menu { position: absolute; cursor: pointer; z-index: 3001; width: 180px; background-color: #fff; padding: 8px 0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); } .menu-list { text-align: center; letter-spacing: 4px; min-width: 100px; } .menu-item { padding: 6px 0; font-size: 12px; cursor: pointer; &:hover { background-color: #f6f6f6; } } </style>

Teleport/index.vue

<script> export default { name: 'teleport', props: { /* 移动至哪个标签内,最好使用id */ to: { type: String, required: true } }, mounted() { // 把内容移动到指定的标签内this.to渲染 document.querySelector(this.to).appendChild(this.$el) }, beforeDestroy() { // 移除内容 const targetElement = document.querySelector(this.to) if (targetElement && targetElement.contains(this.$el)) { targetElement.removeChild(this.$el) } }, render() { return this.$scopedSlots.default() } } </script>

标签:

简易的仿桌面文件夹上传(vue2)由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“简易的仿桌面文件夹上传(vue2)