/** * @Description: 库房查询树 * @author wangzhao * @date 2022/12/02 */ <template> <div class="dee-as-tree-com"> <div class="root"> <div class="root-title sub-title sub-title-fix">仓储组织</div> <div class="root-add" src="/icons/add-L.png" title="新增库房" @click.stop="addKF" /> </div> <div class="search-area"> <el-input v-model="inputVal" placeholder="输入关键字筛选,快速定位" clearable size="small" class="search-input" /> <dee-tools :tools="tools" mode="dual" /> </div> <div class="tree-box"> <el-tree id="houseTree" ref="houseTree" :key="treeId" class="tree" node-key="id" :data="treeData" :props="props" :check-strictly="true" :expand-on-click-node="true" :default-expand-all="false" :highlight-current="true" :default-expanded-keys="defaultExpandedKeys" @node-expand="highLightTreeNode" > <div slot-scope="{ node, data }" :class="['house-tree-node', node.data.endless?'endless':null]" @click="clickNode(node.data)" > <div> <img class="node-prefix-icon" :src="data.subTypeName === 'DxStOrgHouse' ? '/icons/dee-storage/icons/stg-kf.png' : '/icons/dee-storage/icons/stg-kq.png'"> <span class="change-text"> {{ data.name }} </span> </div> <span class="node-handle"> <img v-if="data.subTypeName === 'DxStOrgHouse'" class="node-handle-icon" src="/icons/add-L.png" title="新增库区" @click.stop="addStorageOrg(data, node)"> <img class="node-handle-icon" src="/icons/edit-L.png" :title="'编辑' + data.subTypeDisplayName" @click.stop="editCurrentNode(data, node)"> </span> </div> </el-tree> </div> <dee-drawer width="766px" :title="dialogTitle" :dialog-visible="showDialog" @handleClose="closeDialog" > <dee-as-com v-if="showDialog" parent-show-mode="dialog" :lay-config="layConfig" :basic-data="clickItem" v-bind="formConfig" @close="closeDialog" @on-cancel="closeDialog" @completeEven="completeEven" /> </dee-drawer> </div> </template> <script> import _get from 'lodash.get' export default { componentName: '库房查询树', name: 'HouseTree', props: { rootId: { type: [String, Number], default: () => '' }, defaultLevel: { type: Number, default: 2 // 懒加载,默认展开层级 }, canOperate: { type: Boolean, default: true } }, data() { return { formConfig: {}, defaultExpandedKeys: [], evenList: [ { even: 'showTop', name: '刷新仓储查看列表' } ], inputVal: '', index: 0, stateOption: [], defaultExpandAll: false, treeId: 1, // 选择工具条 filterTool: { keyword: '', currentIndex: -1, nodes: [] }, treeData: [], defaultNode: {}, props: { children: 'children', label: 'label', isLeaf: 'isLeaf' }, dialogTitle: '新建库房', showDialog: false, typeName: '', layKey: '', layConfig: null, curentNodeData: null, clickItem: null } }, computed: { Props() { return { children: 'children', label: 'name', isLeaf: 'isLeaf' } }, tools() { return [ { name: '下一个', icon: '/icons/c-next.png', handler: { click: () => { this.findNext() } } }, { name: '上一个', icon: '/icons/c-last.png', handler: { click: () => { this.findPrev() } } }, { name: '全部展开', icon: '/icons/b-expansion.png', handler: { click: () => { this.expandAllFun(true) } } }, { name: '全部收起', icon: '/icons/b-allpackup.png', handler: { click: () => { this.expandAllFun(false) } } }, { name: '刷新', icon: '/icons/b-fresh.png', handler: { click: () => { } } } ] } }, watch: { inputVal: { handler: function(keyword) { this.filterTool.currentIndex = -1 this.highLightTreeNode() } } }, mounted() { this.getTreeData(() => { this.clickNode(this.treeData[0]) this.$refs.houseTree.setCurrentKey(this.treeData[0].id) }) this.$bus.$on('DxStOrgHouse-submit', (data) => { this.treeData.push(data.items) this.$refs.houseTree.$forceUpdate() }) }, beforeDestroy() { this.$bus.$off('DxStOrgHouse-submit') }, methods: { getTreeData(cb) { const params = { 'openProps': [ { 'name': 'dxStOrgUnitResClassLinks', 'openProps': [{ 'name': 'target' }] } ], 'searchItems': { 'children': [ { 'items': [ { 'fieldName': 'subTypeName', 'operator': 'EQ', 'value': 'DxStOrgArea' }, { 'fieldName': 'subTypeName', 'operator': 'EQ', 'value': 'DxStOrgHouse' } ], 'operator': 'OR' }, { 'items': [ { 'fieldName': 'enabledState', 'operator': 'EQ', 'value': true }, { 'fieldName': 'enabledState', 'operator': 'EQ', 'value': false } ], 'operator': 'OR' } ], 'operator': 'AND' }, sortItem: [{ fieldName: 'name', sortOrder: 'asc' }] } this.$api.searchApi('DxStOrganization', params) .then(res => { this.treeData = this.$utils.generateTree(this.$utils._clonedeep(_get(res, 'items.content', [])), { id: 'id', pid: 'parentId' }) if (typeof cb === 'function') { this.$nextTick(cb) } }) }, // 查询下一个 findNext() { if (!this.inputVal) { return } this.findAll().then(() => { if (this.filterTool.nodes.length < 1) { return } if (++this.filterTool.currentIndex >= this.filterTool.nodes.length) { this.filterTool.currentIndex = 0 } this.expandToMatchNode() }) }, // 查询上一个 findPrev() { if (!this.inputVal) { return } this.findAll().then(() => { if (this.filterTool.nodes.length < 1) { return } if (--this.filterTool.currentIndex < 0) { this.filterTool.currentIndex = this.filterTool.nodes.length - 1 } this.expandToMatchNode() }) }, // 查找所有满足条件的节点 findAll() { return new Promise((resolve) => { this.findMatchNodes() resolve() }) }, expandAllFun(bool) { var nodes = this.$refs.houseTree.store._getAllNodes() this.expandAll = bool this.setNodeExpanded(nodes, bool) this.highLightTreeNode() }, findMatchNodes() { let nodeMap = this.$refs.houseTree.store.nodesMap nodeMap = Object.values(nodeMap) this.filterTool.nodes = nodeMap.filter(node => node.data.name && node.data.name.toUpperCase().includes(this.inputVal.toUpperCase())) }, expandToMatchNode() { const node = this.filterTool.nodes[this.filterTool.currentIndex] let currentNode = node.parent while (currentNode) { currentNode.expanded = true currentNode = currentNode.parent } this.$refs.houseTree.setCurrentKey(node.key) this.highLightTreeNode() this.$nextTick(() => { const treeEl = document.getElementById('houseTree') const el = this.$refs.houseTree.$el.getElementsByClassName('is-current')[0] let parentNode = el.parentNode let offsetParent = el.offsetParent let offsetTop = el.offsetTop || 0 while (parentNode !== treeEl) { if (offsetParent !== parentNode.offsetParent) { offsetTop += parentNode.offsetTop || 0 } else { offsetParent = parentNode.offsetParent } parentNode = parentNode.parentNode } treeEl.scrollTop = offsetTop - treeEl.clientHeight * 0.5 + 10 }) }, setNodeExpanded(nodes, bool) { nodes.forEach(Node => { if (bool) { Node.expand() } else { Node.collapse() } }) }, highLightTreeNode() { this.$nextTick(() => { const treeNode = this.$refs.houseTree.$el const spans = treeNode.getElementsByClassName('change-text') if (spans.length > 0) { for (let i = 0; i < spans.length; i++) { var labelText = spans[i].textContent const reg = this.inputVal .replace(/\(/g, '\\(') .replace(/\)/g, '\\)') .replace(/\./g, '\\.') const allVal = labelText.match(new RegExp(reg, 'ig')) if (allVal) { const newAllVal = [...new Set(allVal)] for (let j = 0; j < newAllVal.length; j++) { if (newAllVal[j]) { const tp = newAllVal[j] .replace(/\(/g, '\\(') .replace(/\)/g, '\\)') .replace(/\./g, '\\.') labelText = labelText.replace( new RegExp(tp, 'g'), '*' + newAllVal[j] + '*' ) } } for (let k = 0; k < allVal.length; k++) { if (allVal[k]) { labelText = labelText.replace( '*' + allVal[k] + '*', '<span class="highlight-text">' + allVal[k] + '</span>' ) } } } spans[i].innerHTML = labelText } } }) }, // 节点点击事件 clickNode(data) { this.curentNodeData = data this.$emit('showTop', data) }, completeEven() { // 重新加载树 this.closeDialog() this.treeData = [] this.getTreeData(() => { // 获取指定id节点 const nodeKey = _get(this, 'curentNodeData.id', '') if (nodeKey) { const node = this.$refs.houseTree.getNode(nodeKey) if (node) { this.$bus.$emit('DetailCom-update', node.data) } } }) }, closeDialog() { this.showDialog = false }, findState(data) { let state = '' this.stateOption.forEach(item => { if (item.value === data) { state = item.label } }) return state }, // 关闭新增弹窗 cancel() { this.$emit('close') }, // 添加仓储组织节点 addStorageOrg(item) { this.index++ this.addArea(item) this.showDialog = true }, // 添加库区 addArea(item) { this.clickItem = item this.formConfig = { form: { parentId: item.id, subTypeName: 'DxStOrgArea' } } this.layConfig = { typeName: 'DxStOrgArea', layKey: 'defaultCreate' } this.dialogTitle = '新增库区' }, // 编辑当前节点(库房/库区) editCurrentNode(item, node) { this.index++ // 将父node数据 传到basicData中 用于控制库区物料范围 this.clickItem = JSON.parse(JSON.stringify(item)) this.clickItem.parent = node.parent.data this.formConfig = { form: { parentId: item.parentId, subTypeName: item.subTypeName } } this.dialogTitle = '编辑' + item.subTypeDisplayName this.layConfig = { typeName: item.subTypeName, layKey: 'defaultEdit' } this.showDialog = true }, // 添加库房 addKF() { this.index++ this.clickItem = {} this.formConfig = { form: { subTypeName: 'DxStOrgHouse' } } this.dialogTitle = '新增库房' this.layConfig = { typeName: 'DxStOrgHouse', layKey: 'defaultCreate' } this.showDialog = true } } } </script> <style lang="scss" > .dee-as-tree-com{ height: 100%; background-color: #fff; overflow: hidden !important; .root{ display: flex; justify-content: space-between; padding-top: 12px; padding-bottom: 6px; padding-left:8px; .sub-title-fix{ align-self: center; padding-top: 0px; padding-bottom: 0px; } } .search-area { //border-bottom: 1px solid #DDDDDD; display: flex; align-items: center; justify-content:flex-start; padding: 6px 0px; .search-input{ width: calc(100% - 150px); flex:1; margin-right:10px; } } .tree { height: calc(100% - 83px); overflow-y: scroll; padding-bottom: 10px; /deep/ .el-tree-node__content { height: 30px; } } .el-tree-node__content:hover .house-tree-node .node-handle{ visibility: visible; } .house-tree-node { flex: 1; display: flex; align-items: center; justify-content: space-between; color: #212121; font-size: 14px; padding-right: 8px; &.endless{ .change-text{ color: #F56C6C } } .node-prefix-icon { vertical-align: middle; } .node-handle { visibility: hidden; .node-handle-icon { height: 14px; margin-left: 10px; } } } .tree-btn-box{ width: 66px; display: flex; justify-content: space-between; align-items: center; height: 100%; display: none; .btn-item img{ padding: 4px; width: 16px; height: 16px; } } .highlight-text{ background-color: #FFFF00; } .house-tree-node{ &> div >.change-text > .highlight-text{ background-color: #FF9632; } } .changeText { font-size: 14px } .root { display: flex; justify-content: space-between; padding-left: 8px; .root-title { font-size: 16px; } .root-add { display: inline-block; width: 14px; height: 14px; margin: auto 0px; background-size: cover; background-position: center; background-image: url('/icons/add-L.png'); } } .tree-box{ height: 100%; margin: 4px 0; overflow-y: auto; } .custom-tree-node{ width: 100%; display: flex; justify-content: space-between; div{ width: 100px; display: flex; justify-content: flex-end; } div >span{ width:14px; height:14px; margin: 0 4px; background-size: cover; background-position: center; } } .load-more { line-height: 50px; height: 50px; text-align: center; span { margin: auto; color: #2f90e2; height: 26px; line-height: 26px; padding: 0 20px; font-size: 12px; background: #e7f2ff; border-radius: 13px; display: inline-block; cursor: pointer; } } } </style>