<template> <div class="DocumentFolder"> <div class="DocumentFolder-top"> <dee-search-box v-if="contextVisible" type-name="DxDocument" v-bind="filterConfig.configDetails" @formChange="searchEvent" /> </div> <div class="DocumentFolder-main"> <el-tree ref="tree" node-key="id" empty-text="请选择上下文" class="tree-line" icon-class="el-icon-circle-plus-outline" :highlight-current="true" :expand-on-click-node="false" :data="data" :props="defaultProps" :lazy="lazy" :load="loadNode" :default-expanded-keys="defaultExpandedKeys" @node-drag-end="handleDragEnd" @current-change="currentChange" > <div slot-scope="{node}" class="DocumentFolder-node"> <template v-if="!node.edit"> <div class="DocumentFolder-label" :title="node.label"> <img v-if="node.expanded" class="folderIcon" src="../../icons/folder_open.svg" alt=""> <img v-else class="folderIcon" src="../../icons/folder_closed.svg" alt=""> <span v-if="node.label" class="change-text"> {{ node.label }} </span> <i v-else><未命名></i> </div> <div v-if="!readonly && !edit" class="DocumentFolder-btn"> <button v-if="node.level>1" title="重命名" class="DocumentFolder-btnItem btn-edit" @click.stop="editFolder(node)" /> <button title="添加" class="DocumentFolder-btnItem btn-add" @click.stop="addFolder(node)" /> <button v-if="node.level>1" slot="reference" title="删除" class="DocumentFolder-btnItem btn-delete" @click.stop="deleteFolder(node)" /> </div> </template> <template v-else> <div class="DocumentFolder-label"> <el-input ref="input" v-model="node.rename" size="mini" @blur="endEdit(node)" @keyup.enter.native="editEnter(node)" @keyup.esc.native="cancelEdit(node)" /> </div> </template> </div> </el-tree> </div> </div> </template> <script> import { getLayouts } from '@/api/doc' export default { name: 'DxDocumentFolder', displayName: '文档文件夹', modelRelationObjs: ['DxDocumentFolder'], props: { fixContext: { type: Object, default() { return null } }, contextVisible: { type: Boolean, default: true }, readonly: { type: Boolean, default: false } }, data() { return { edit: false, canEdit: true, lazy: true, defaultExpandedKeys: [], filterConfig: {}, dxDocumentFolderService: this.$getService('DxDocumentFolder'), context: this.fixContext, data: [], defaultProps: { children: 'children', label: 'name', isLeaf: 'isLeaf' }, selectFolderObj: { dxContext: {}, dxDocumentFolder: {} } } }, watch: { context() { if (this.context && this.context.id) { this.data = [this.context] } else { this.data = [] } } }, created() { if (this.fixContext && this.fixContext.id) { this.defaultExpandedKeys = [this.fixContext.id] } getLayouts('DxDocument', 'OnlyContext'/* 'OnlyContext'*/).then(res => { this.filterConfig = res.items ? res.items.slice(-1)[0] : {} this.filterConfig.configDetails = JSON.parse(this.filterConfig.configDetails) }) }, methods: { searchEvent(data) { const contextId = data.contextId.value this.$getService('DxContext').byId(contextId).then(r => { this.selectFolderObj.dxContext = r this.$emit('currentChange', {}, {}, this.selectFolderObj) this.$set(this, 'defaultExpandedKeys', r ? [r.id] : []) this.$set(this, 'context', r || null) }).finally(() => { }) }, // getTreeId(data) { // alert(data.id) // return Date.now() // }, loadNode(node, resolve) { if (node.level === 0) { if (this.context && this.context.id) { resolve([this.context]) } } else if (node.level === 1) { this.dxDocumentFolderService.getRootFolders(this.context.id).then(r => { resolve(r.content) }).catch(e => { resolve([]) }) } else { this.dxDocumentFolderService.getFolders(node.data.id).then(r => { resolve(r.content) }).catch(e => { resolve([]) }) } resolve([]) }, getItem() { // this.docFolderModel. }, currentChange(data, node) { this.selectFolderObj.dxDocumentFolder = data this.$emit('currentChange', data, node, this.selectFolderObj) }, addFolder(node) { this.$prompt('请输入名称', '新建目录', { confirmButtonText: '确定', cancelButtonText: '取消', inputPattern: /^[^\\/:\*\?""<>|]{1,120}$/, inputErrorMessage: '文件名不能包含:\\/:*?"<>|' }).then(({ value }) => { this.dxDocumentFolderService.addFolder(this.context.id, node.level > 1 ? node.data.id : 0, value).then((r) => { if (node.loaded) { this.$refs.tree.append(r.items, node) } node.expand() this.$message({ type: 'success', message: '操作成功' }) }) }).catch(() => { this.$message({ type: 'info', message: '取消输入' }) }) // const newChild = { id: 'new', name: '', children: [] } // node.expand() // if (!node.data.children) { // this.$set(node.data, 'children', []) // } // node.data.children.push(newChild) // this.$nextTick(() => { // var nodes = this.$refs.tree.store.nodesMap // console.log('nodes', nodes) // console.log('node', node) // console.log('tree', this.$refs.tree) // }) }, deleteFolder(node) { const h = this.$createElement const fullPath = this.getNodeFullPath(node) this.$confirm(null, '提示', { message: h('div', null, [ h('div', null, '请确认是否删除目录?'), h('div', { attrs: { title: fullPath }, style: { marginTop: '8px', color: '#909399', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' } }, `"${fullPath}"`) ]), confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.dxDocumentFolderService.delete(node.data).then(() => { this.$refs.tree.remove(node) this.$message({ type: 'success', message: '删除成功!' }) }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) }, getNodeFullPath(node) { let path = node.label let parentNode = node.parent while (parentNode && parentNode.level > 0) { path = `${parentNode.label}/${path}` parentNode = parentNode.parent } return '/' + path }, // 修改名称 editFolder(node) { this.edit = true this.$set(node, 'edit', true) this.$set(node, 'rename', node.data.name) this.$nextTick(() => { this.$refs.input.focus() this.$refs.input.select() }) }, // 失去焦点确定修改 endEdit(node) { if (!node.rename && !node.cancelEdit) { this.$refs.input.focus() this.$message.warning(`名称不能为空`) return } this.$set(node, 'edit', false) this.$set(this, 'edit', false) if (!node.cancelEdit) { if (node.data.name !== node.rename) { const oldName = node.data.name node.data.name = node.rename node.data.fullPath = null this.dxDocumentFolderService.save(node.data).then(() => { this.$message.success('修改成功') }).catch(() => { this.$set(node.data, 'name', oldName) }) } } else { this.$message.info('已取消修改') } node.cancelEdit && delete node.cancelEdit }, // 回车确定 editEnter(node) { node.cancelEdit = false this.$refs.input.blur() }, // ESC 退出 cancelEdit(node) { node.cancelEdit = true this.$refs.input.blur() }, handleDragEnd(before, after, inner) { alert(after.level) before.data.parentId = after.level > 2 ? after.data.id : null before.data.fullPath = null this.dxDocumentFolderService.save(before.data).then(r => { this.$message.success('操作成功') }) } } } </script> <style lang="scss"> .DocumentFolder{ height: 100%; box-sizing: border-box; padding: 8px; // display: flex; // flex-direction: column; overflow: hidden; // .DocumentFolder-top{ // padding: 0px 8px; // } .DocumentFolder-main{ flex: 1; height: calc(100% - 70px); overflow: auto; } .search-form-box{ padding:0px; } .search-form-box .dee-search-form .el-form-item__label { text-align: center; } .search-form-box .search-box-item { width: 100%; } .dee-search-form{ &>div{ padding-bottom: 8px !important; } } .dee-search-form{ border-bottom: 1px solid #dcdfe6; } .dee-search-form{ margin-bottom: 0px !important; margin-top: 20px; // padding-bottom: 20px; .dee-form-item{ width: 100%; } } .search-box-btn{ display: none; } .searchBtn{ display: none !important; } .el-tree{ background-color: transparent; } .el-scrollbar .el-scrollbar__wrap { overflow-x: hidden; } .el-tree>.el-tree-node { min-width: 100%; display:inline-block; } .el-tree-node__content { align-self: baseline; } .el-tree-node__content{ padding:1px 8px; &:hover{ .DocumentFolder-btn{ display: block; visibility: visible; } } } .el-tree-node__expand-icon{ font-size: 16px; // &::after{ // content: ""; // position:absolute; // width: 1px; // top:0px; // display: block; // height: 100%; // border-left: 1px dotted #52627C; // z-index: 2; // } } .el-tree-node__expand-icon.expanded{ transform:none; &::before{ content: "\e722" !important; } } .DocumentFolder-btnItem{ width: 18px; height: 18px; border: none; background-color: transparent; background-size:100% 100%; border-radius: 0; outline:none; cursor: pointer; // &:hover{ // // border-top: 1px solid transparent; // } &.btn-add{ background-image: url("/icons/c-add.png"); } &.btn-edit{ background-image: url("/icons/c-edit.png"); } &.btn-delete{ background-image: url("/icons/c-creatbackups.png"); } } &-node{ width: 100%; display: flex; flex-direction:row; align-items: center; justify-content: space-between; flex: 1; box-sizing: border-box; overflow: hidden; } &-label{ flex: 1; overflow: hidden; white-space:nowrap; text-overflow:ellipsis; } &-btn{ // display: none; visibility: hidden; // width: 180px; text-align: right; button { margin-left: 8px; } } } .tree-line{ // .el-tree-node { // position: relative; // // padding-left: 16px; // 缩进量 // } // .el-tree-node__children { // // padding-left: 16px; // 缩进量 // } // // 当前层最后一个节点的竖线高度固定 // .el-tree-node:last-child::before { // height: 38px; // 可以自己调节到合适数值 // } // // 横线 // .el-tree-node::after { // content: ""; // width: 8px; // height: 20px; // position: absolute; // left: 14px; // top: 13px; // border-width: 1px; // border-top: 1px dotted #52627C; // } // // 去掉最顶层的虚线,放最下面样式才不会被上面的覆盖了 // & > .el-tree-node::after { // border-top: none; // } // & > .el-tree-node::before { // border-left: none; // } // // 展开关闭的icon // .el-tree-node__expand-icon{ // font-size: 16px; // // 叶子节点(无子节点) // &.is-leaf{ // color: transparent; // // display: none; // 也可以去掉 // } // } } </style>