Files
admin-govern/src/components/tree/device.vue

420 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 设备管理使用折叠面板渲染多个tree -->
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
<!-- <Icon
v-show="menuCollapse"
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18px"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
/> -->
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<el-input
maxlength="32"
v-model.trim="filterText"
autocomplete="off"
placeholder="请输入内容"
clearable
>
<template #prepend>
<el-select v-model="treeType" @change="changeTreeType" style="min-width: 75px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
<!-- <Icon
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18px"
class="fold ml10 menu-collapse"
style="cursor: pointer"
v-if="props.canExpand"
/> -->
</div>
<el-collapse
:accordion="true"
v-model="activeName"
style="flex: 1; height: 100%"
@change="changeDevice"
v-if="treeType == '1'"
v-loading="loading"
>
<el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length">
<el-select v-model="process" clearable placeholder="请选择状态" class="mb10">
<el-option label="功能调试" value="2" />
<el-option label="出厂调试" value="3" />
<el-option label="正式投运" value="4" />
</el-select>
<el-tree
:style="{ height: governTreeHeight }"
ref="treeRef1"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
:default-expand-all="false"
v-bind="$attrs"
:data="zlDevList"
style="overflow: auto"
>
<template #default="{ node, data: nodeData }">
<span class="custom-tree-node">
<Icon
:name="nodeData.icon"
style="font-size: 16px"
:style="{ color: nodeData.color }"
v-if="nodeData.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</el-collapse-item>
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length">
<el-tree
:style="{ height: otherTreeHeight }"
ref="treeRef2"
:props="defaultProps"
highlight-current
:default-expand-all="false"
:filter-node-method="filterNode"
node-key="id"
:data="bxsDeviceData"
v-bind="$attrs"
style="overflow: auto"
>
<template #default="{ node, data: nodeData }">
<span class="custom-tree-node">
<Icon
:name="nodeData.icon"
style="font-size: 16px"
:style="{ color: nodeData.color }"
v-if="nodeData.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</el-collapse-item>
<el-collapse-item title="监测设备" name="2" v-if="frontDeviceData.length">
<el-tree
:style="{ height: otherTreeHeight }"
ref="treeRef3"
:props="defaultProps"
highlight-current
:default-expand-all="false"
:filter-node-method="filterNode"
node-key="id"
:data="frontDeviceData"
v-bind="$attrs"
style="overflow: auto"
>
<template #default="{ node, data: nodeData }">
<span class="custom-tree-node">
<Icon
:name="nodeData.icon"
style="font-size: 16px"
:style="{ color: nodeData.color }"
v-if="nodeData.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</el-collapse-item>
</el-collapse>
<div v-if="treeType == '2'" v-loading="loading">
<el-tree
:style="{ height: engineeringTreeHeight }"
ref="treeRef4"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
v-bind="$attrs"
:data="props.data"
style="overflow: auto"
:default-expand-all="false"
>
<template #default="{ node, data: nodeData }">
<span class="custom-tree-node">
<Icon
:name="nodeData.icon"
style="font-size: 16px"
:style="{ color: nodeData.color }"
v-if="nodeData.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree, type CollapseModelValue } from 'element-plus'
import { ref, watch, onMounted, nextTick, computed } from 'vue'
import { collectDeviceLeaves } from './govern/lineTreeUtils'
import { collectDeviceApiLeaves } from './govern/deviceTreeUtils'
defineOptions({
name: 'govern/tree',
inheritAttrs: false
})
const emit = defineEmits(['changeDeviceType', 'changeTreeType'])
interface Props {
width?: string
canExpand?: boolean
type?: string
data?: any[]
height?: number
engineering?: boolean
/** line: getLineTree 四层叶子device: getDeviceTree 三层叶子 */
leafMode?: 'line' | 'device'
}
const props = withDefaults(defineProps<Props>(), {
width: '280px',
canExpand: true,
type: '',
data: () => [],
height: 0,
engineering: false,
leafMode: 'line'
})
const treeType = ref('1')
const options = [
{ label: '设备', value: '1' },
{ label: '工程', value: '2' }
]
const { proxy } = useCurrentInstance()
const menuCollapse = ref(false)
const activeName = ref('0')
const filterText = ref('')
const process = ref('')
const loading = ref(false)
const defaultProps = { label: 'name', value: 'id' }
const zlDeviceData = ref<any[]>([])
const zlDevList = ref<any[]>([])
const bxsDeviceData = ref<any[]>([])
const frontDeviceData = ref<any[]>([])
const governTreeHeight = computed(() => `calc(100vh - 380px - ${props.height}px)`)
const otherTreeHeight = computed(() =>
zlDeviceData.value.length ? `calc(100vh - 340px - ${props.height}px)` : `calc(100vh - 238px - ${props.height}px)`
)
const engineeringTreeHeight = computed(() => `calc(100vh - 188px - ${props.height}px)`)
const treeRef1 = ref<InstanceType<typeof ElTree>>()
const treeRef2 = ref<InstanceType<typeof ElTree>>()
const treeRef3 = ref<InstanceType<typeof ElTree>>()
const treeRef4 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2, treeRef3, treeRef4 })
function splitTreeData(val: any[]) {
zlDeviceData.value = []
bxsDeviceData.value = []
frontDeviceData.value = []
val.forEach(item => {
if (item.name === '治理设备') {
zlDeviceData.value = item.children ?? []
} else if (item.name === '便携式设备') {
bxsDeviceData.value = item.children ?? []
} else if (item.name === '监测设备') {
frontDeviceData.value = item.children ?? []
}
})
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
}
function filterProcess(nodes: any[]): any[] {
if (!process.value) return nodes
return nodes
.map(node => {
const children = node.children ? filterProcess(node.children) : []
if (node.process == process.value || children.length > 0) {
return { ...node, children }
}
return null
})
.filter(Boolean)
}
function getActiveTreeRef() {
if (treeType.value === '2') return treeRef4.value
if (activeName.value === '0') return treeRef1.value
if (activeName.value === '1') return treeRef2.value
return treeRef3.value
}
function resolveActiveName() {
if (zlDeviceData.value.length) return '0'
if (bxsDeviceData.value.length) return '1'
if (frontDeviceData.value.length) return '2'
return ''
}
function selectDevicePanel(panelName: string, node?: any) {
if (!node) return
emit('changeDeviceType', panelName, node)
nextTick(() => {
getActiveTreeRef()?.setCurrentKey(node.id)
})
}
const changeDevice = (val: CollapseModelValue) => {
if (Array.isArray(val) || val == null || val === '') return
const panelName = String(val)
const collectLeaves = props.leafMode === 'device' ? collectDeviceApiLeaves : collectDeviceLeaves
const { govern, portable, monitor } = collectLeaves(
zlDevList.value,
bxsDeviceData.value,
frontDeviceData.value
)
const panelMap: Record<string, { nodes: any[]; clearOthers: any[][] }> = {
'0': { nodes: govern, clearOthers: [portable, monitor] },
'1': { nodes: portable, clearOthers: [govern, monitor] },
'2': { nodes: monitor, clearOthers: [govern, portable] }
}
const panel = panelMap[panelName]
if (!panel) return
panel.clearOthers.forEach(list => list.forEach(item => (item.checked = false)))
selectDevicePanel(panelName, panel.nodes[0])
}
const setActiveName = () => {
activeName.value = resolveActiveName()
if (activeName.value) {
nextTick(() => changeDevice(activeName.value))
}
}
watch(
() => props.data,
val => {
if (!val?.length) return
splitTreeData(val)
if (treeType.value === '1') {
nextTick(() => setActiveName())
}
},
{ immediate: true, deep: true }
)
watch(filterText, val => {
getActiveTreeRef()?.filter(val)
})
watch(process, () => {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
if (activeName.value === '0') {
nextTick(() => changeDevice(activeName.value))
}
})
const onMenuCollapse = () => {
menuCollapse.value = !menuCollapse.value
proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
}
const filterNode = (value: string, data: any, node: any): boolean => {
if (!value) return true
if (!data.name) return false
return chooseNode(value, data, node)
}
const chooseNode = (value: string, data: any, node: any): boolean => {
if (data.name.indexOf(value) !== -1) return true
const level = node.level
if (level === 1) return false
let parentData = node.parent
for (let i = 0; i < level - 1; i++) {
if (parentData?.data?.name?.indexOf(value) !== -1) return true
parentData = parentData.parent
}
return false
}
const changeTreeType = (val: string) => {
loading.value = true
emit('changeTreeType', val)
if (val === '1') {
nextTick(() => setActiveName())
}
setTimeout(() => {
loading.value = false
}, 300)
}
onMounted(() => {
treeType.value = props.engineering ? '2' : '1'
})
</script>
<style lang="scss" scoped>
.cn-tree {
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
height: 100%;
width: 100%;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.menu-collapse {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;
}
:deep(.el-input-group__prepend) {
background-color: var(--el-fill-color-blank);
}
:deep(.is-disabled) {
display: none !important;
}
</style>