<template>
|
<a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native.stop="openBaseContextMenu">
|
<a-spin :spinning="loading">
|
<div style="display: flex;flex-direction: column;height: 100%">
|
<div style="display: flex;justify-content: space-between">
|
<a-input placeholder="输入关键字进行搜索" allowClear v-model="searchInput"
|
@change="handleSearchInputChange"/>
|
<!-- <a-tooltip title="刷新">-->
|
<!-- <a-button icon="reload" @click="handleTreeReload" style="width: 18%;margin-left: 8px"></a-button>-->
|
<!-- </a-tooltip>-->
|
<!-- <a-button type="primary" v-has="'product_add'" icon="plus" style="margin-left: 8px"-->
|
<!-- @click="$refs.productModalFormRef.triggerCorrespondingMethod({modalTitle:'添加产品',methodName:'handleProductAdd'})">-->
|
<!-- 产品-->
|
<!-- </a-button>-->
|
<!-- <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">-->
|
<!-- <a-menu slot="overlay">-->
|
<!-- <a-menu-item key="1" @click="expandedKeys = allTreeKeys">展开所有</a-menu-item>-->
|
<!-- <a-menu-item key="2" @click="expandedKeys = ['-1']">合并所有</a-menu-item>-->
|
<!-- <a-menu-item key="3" @click="getTreeDataByApi">刷新</a-menu-item>-->
|
<!-- </a-menu>-->
|
<!-- <a-button>-->
|
<!-- <a-icon type="bars"/>-->
|
<!-- </a-button>-->
|
<!-- </a-dropdown>-->
|
</div>
|
|
<!--产品结构树-->
|
<div id="tree-container" style="flex: 1;overflow:auto;margin-top: 10px">
|
<a-tree blockNode show-icon :expandedKeys.sync="expandedKeys"
|
:selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
|
@select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
|
<template slot="title" slot-scope="{ label, parentId, key:treeKey,type}">
|
<ProductStructureTreeContextMenu ref="contextMenuRef"
|
:treeParams="{label,treeKey,searchValue,type}"/>
|
</template>
|
|
<a-icon slot="switcherIcon" type="down"/>
|
<a-icon slot="product" type="shopping"/>
|
<a-icon slot="component" type="camera"/>
|
<a-icon slot="part" type="hdd"/>
|
<a-icon slot="processSpecVersion" type="tag"/>
|
<a-icon slot="process" type="apartment"/>
|
<a-icon slot="processStep" type="tool"/>
|
</a-tree>
|
</div>
|
</div>
|
</a-spin>
|
|
<!--产品弹窗-->
|
<ProductModal ref="productModalFormRef" :currentTreeNodeInfo="rightClickSelected"
|
@submitSuccess="getTreeDataByApi"/>
|
<!--部件弹窗-->
|
<ComponentModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--零件弹窗-->
|
<PartModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--工艺规程版本弹窗-->
|
<ProcessSpecVersionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--工序弹窗-->
|
<ProcessModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--工步弹窗-->
|
<ProcessStepModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--权限配置弹窗-->
|
<AssignPermissionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
|
<!--产品结构树基本右键菜单(空白处触发)-->
|
<ProductStructureBaseContextMenu ref="baseContextmenuRef"/>
|
</a-card>
|
</template>
|
|
<script>
|
import dncApi from '@/api/dnc'
|
import { deleteAction } from '@/api/manage'
|
import ProductStructureTreeContextMenu from './ProductStructureTreeContextMenu'
|
import ProductModal from './Product/ProductModal'
|
import ComponentModal from './Component/ComponentModal'
|
import PartModal from './Part/PartModal'
|
import ProcessSpecVersionModal from './ProcessSpecVersion/ProcessSpecVersionModal'
|
import ProcessModal from './Process/ProcessModal'
|
import ProcessStepModal from './ProcessStep/ProcessStepModal'
|
import AssignPermissionModal from './Permission/AssignPermissionModal'
|
import DeviceCustomTypeModal from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue'
|
import ProductStructureBaseContextMenu
|
from '@views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue'
|
|
export default {
|
name: 'ProductStructureTree',
|
components: {
|
ProductStructureBaseContextMenu,
|
DeviceCustomTypeModal,
|
AssignPermissionModal,
|
ProcessStepModal,
|
ProcessModal,
|
ProcessSpecVersionModal,
|
PartModal,
|
ComponentModal,
|
ProductModal,
|
ProductStructureTreeContextMenu
|
},
|
data() {
|
return {
|
searchInput: '',
|
cardLoading: false,
|
loading: false,
|
treeDataSource: [],
|
selectedKeys: [],
|
expandedKeys: [],
|
beforeSearchExpandedKeys: [],
|
searchValue: '',
|
dataList: [],
|
autoExpandParent: true,
|
checkStrictly: true,
|
allTreeKeys: [],
|
rightClickSelected: {},
|
url: {
|
delete: '/nc/product/delete'
|
}
|
}
|
},
|
created() {
|
this.getTreeDataByApi()
|
this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
|
},
|
beforeDestroy() {
|
this.$bus.$off('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
|
},
|
methods: {
|
// 调用接口获取树的数据
|
getTreeDataByApi() {
|
this.loading = true
|
this.cardLoading = true
|
this.treeDataSource = []
|
dncApi.getProductStructureTreeApi()
|
.then(res => {
|
if (res.success) {
|
this.dataList = []
|
this.allTreeKeys = []
|
this.treeDataSource = res.result
|
this.generateList(this.treeDataSource)
|
// this.expandedKeys = this.allTreeKeys
|
if (this.expandedKeys.length === 0) this.expandedKeys = this.beforeSearchExpandedKeys = [this.treeDataSource[0].id]
|
} else {
|
this.$message.warn(res.message)
|
}
|
}).finally(() => {
|
this.loading = false
|
this.cardLoading = false
|
})
|
},
|
|
/**
|
* 树节点选中时触发
|
* @param selectedKeys 选中节点key
|
* @param {node} node 节点对象
|
*/
|
handleTreeSelect(selectedKeys, { node }) {
|
const that = this
|
let record = node.dataRef
|
const { id, type } = record
|
dncApi.getProductStructureTreeNodeEntityApi({ id, type })
|
.then(res => {
|
if (res.success) {
|
let currentSelectedNodeInfo
|
if (res.result.length > 0) {
|
currentSelectedNodeInfo = Object.assign({}, record, { entity: res.result[0] })
|
} else {
|
currentSelectedNodeInfo = {}
|
that.$notification.warning({
|
message: '消息',
|
description: '暂无该节点详细信息'
|
})
|
}
|
// 向右侧父级组件发送当前选中树节点信息
|
this.$bus.$emit('sendCurrentTreeNodeInfo', currentSelectedNodeInfo)
|
} else {
|
that.$notification.error({
|
message: '消息',
|
description: res.message
|
})
|
}
|
})
|
if (selectedKeys.length === 0) return
|
this.selectedKeys = selectedKeys
|
},
|
|
/**
|
* 树节点右键单击节点时触发
|
* @param node 节点对象
|
*/
|
handleTreeRightClick({ node }) {
|
if (this.$refs.baseContextmenuRef) this.$refs.baseContextmenuRef.menuVisible = false
|
const that = this
|
const record = node.dataRef
|
const { id, type } = record
|
dncApi.getProductStructureTreeNodeEntityApi({ id, type })
|
.then(res => {
|
if (res.success) {
|
if (res.result.length > 0) {
|
that.rightClickSelected = Object.assign({}, record, { entity: res.result[0] })
|
} else {
|
that.rightClickSelected = {}
|
that.$notification.warning({
|
message: '消息',
|
description: '暂无该节点详细信息'
|
})
|
}
|
} else {
|
that.$notification.error({
|
message: '消息',
|
description: res.message
|
})
|
}
|
})
|
},
|
|
// 树节点右键单击菜单中删除按钮时触发
|
handleDelete() {
|
const that = this
|
const { rightClickSelected: { id, type }, $confirm, url, $notification } = that
|
$confirm({
|
title: '提示',
|
content: '确认删除此条记录吗?',
|
okText: '确认',
|
okType: 'danger',
|
cancelText: '取消',
|
onOk: () => {
|
if (!url.delete) {
|
this.$message.error('请设置url.delete属性!')
|
return
|
}
|
deleteAction(url.delete + `/${id}/${type}`)
|
.then((res) => {
|
if (res.success) {
|
that.getTreeDataByApi()
|
$notification.success({
|
message: '消息',
|
description: res.message
|
})
|
} else {
|
$notification.warning({
|
message: '消息',
|
description: res.message
|
})
|
}
|
})
|
.finally(() => {
|
that.$destroyAll()
|
})
|
},
|
onCancel: () => {
|
that.$destroyAll()
|
}
|
})
|
},
|
|
/**
|
* 自动展开添加下级节点的父节点
|
* @param isAddNextLevel 是否需要展开下级
|
*/
|
modalFormSubmitSuccess(isAddNextLevel) {
|
// 判断是否为添加下级并且判断父节点是否展开
|
if (isAddNextLevel && !this.expandedKeys.includes(this.rightClickSelected.id)) this.expandedKeys.push(this.rightClickSelected.id)
|
this.getTreeDataByApi()
|
},
|
|
/**
|
* 树节点展开合并时触发
|
* @param expandedKeys 展开项key
|
*/
|
handleTreeExpand(expandedKeys) {
|
this.expandedKeys = this.beforeSearchExpandedKeys = expandedKeys
|
this.autoExpandParent = false
|
},
|
|
// 输入查询内容变化时触发(增加防抖机制)
|
handleSearchInputChange() {
|
const that = this
|
let timer
|
if (timer) clearTimeout(timer)
|
timer = setTimeout(function() {
|
that.searchAndExpandTreeNode() // 加小括号调用函数
|
}, 1000)
|
},
|
|
// 防抖函数中触发搜索并展开树节点
|
searchAndExpandTreeNode() {
|
let search = this.searchInput
|
let expandedKeys
|
let autoExpandParent
|
if (search !== '') {
|
expandedKeys = this.dataList
|
.map(item => {
|
if (item.title != null) {
|
if (item.title.indexOf(search) > -1) {
|
return this.getParentKey(item.key, this.treeDataSource)
|
}
|
return null
|
}
|
})
|
.filter((item, i, self) => item && self.indexOf(item) === i)
|
autoExpandParent = true
|
} else {
|
expandedKeys = this.beforeSearchExpandedKeys
|
autoExpandParent = false
|
}
|
Object.assign(this, {
|
expandedKeys,
|
searchValue: search,
|
autoExpandParent
|
})
|
},
|
|
/**
|
* 递归获得输入项的父级key
|
* @param key 子项key
|
* @param tree 子项
|
*/
|
getParentKey(key, tree) {
|
let parentKey
|
for (let i = 0; i < tree.length; i++) {
|
const node = tree[i]
|
if (node.children) {
|
if (node.children.some(item => item.key === key)) {
|
parentKey = node.key
|
} else if (
|
this.getParentKey(key, node.children)) {
|
parentKey = this.getParentKey(key, node.children)
|
}
|
}
|
}
|
return parentKey
|
},
|
|
/**
|
* 递归获得所有树节点key
|
* @param data
|
*/
|
generateList(data) {
|
for (let i = 0; i < data.length; i++) {
|
data[i].key = data[i].id
|
const node = data[i]
|
const key = node.id
|
const title = node.label
|
this.dataList.push({ key, title })
|
this.allTreeKeys.push(key)
|
this.setTreeNodeIcon(node)
|
if (node.children) this.generateList(node.children)
|
}
|
},
|
|
/**
|
* 树所在父元素的右键事件
|
* @param event 事件对象
|
*/
|
openBaseContextMenu(event) {
|
event.preventDefault()
|
if (event.target.id !== 'tree-container') return
|
this.$refs.baseContextmenuRef.menuStyle.top = event.clientY + 'px'
|
this.$refs.baseContextmenuRef.menuStyle.left = event.clientX + 'px'
|
this.$refs.baseContextmenuRef.menuVisible = true
|
document.body.addEventListener('click', this.handleBaseContextMenuClose)
|
},
|
|
/**
|
* 设置树节点图标
|
* @param treeNode
|
*/
|
setTreeNodeIcon(treeNode) {
|
switch (+treeNode.type) {
|
case 1:
|
treeNode.slots = { icon: 'product' }
|
break
|
case 2:
|
treeNode.slots = { icon: 'component' }
|
break
|
case 3:
|
treeNode.slots = { icon: 'part' }
|
break
|
case 4:
|
treeNode.slots = { icon: 'processSpecVersion' }
|
break
|
case 5:
|
treeNode.slots = { icon: 'process' }
|
break
|
case 6:
|
treeNode.slots = { icon: 'processStep' }
|
break
|
default:
|
}
|
},
|
|
// 控制基础右键菜单关闭
|
handleBaseContextMenuClose() {
|
this.$refs.baseContextmenuRef.menuVisible = false
|
document.body.removeEventListener('click', this.handleBaseContextMenuClose)
|
},
|
|
// 刷新重新获取树的数据
|
handleTreeReload() {
|
this.getTreeDataByApi()
|
},
|
|
triggerCorrespondingMethod({ methodName }) {
|
if (this[methodName]) this[methodName]()
|
}
|
|
}
|
}
|
</script>
|
|
<style lang="less" scoped>
|
/deep/ .ant-card-body {
|
padding: 0 12px 0 0;
|
}
|
|
/deep/ .ant-card-body, /deep/ .ant-spin-nested-loading, /deep/ .ant-spin-container {
|
height: 100%;
|
}
|
|
/deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
|
display: inline-block;
|
width: calc(100% - 24px) !important;
|
}
|
|
::-webkit-scrollbar {
|
width: 8px;
|
}
|
|
@media screen and (min-width: 1920px) {
|
.tree_con {
|
height: 748px !important;
|
}
|
}
|
|
@media screen and (min-width: 1680px) and (max-width: 1920px) {
|
.tree_con {
|
height: 748px !important;
|
}
|
}
|
|
@media screen and (min-width: 1400px) and (max-width: 1680px) {
|
.tree_con {
|
height: 600px !important;
|
}
|
}
|
|
@media screen and (min-width: 1280px) and (max-width: 1400px) {
|
.tree_con {
|
height: 501px !important;
|
}
|
}
|
|
@media screen and (max-width: 1280px) {
|
.tree_con {
|
height: 501px !important;
|
}
|
}
|
</style>
|