修改全局列问题了,联调设备升级mqtt
This commit is contained in:
@@ -33,16 +33,28 @@
|
||||
<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>
|
||||
<div class="comm-tabs mb10">
|
||||
<el-tooltip
|
||||
v-for="tab in commTabs"
|
||||
:key="tab.key"
|
||||
:content="tab.label"
|
||||
placement="top"
|
||||
:show-after="200"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="comm-tab"
|
||||
:class="[
|
||||
`is-${tab.key}`,
|
||||
{ 'is-active': commFilter === tab.key }
|
||||
]"
|
||||
@click="onCommFilter(tab.key)"
|
||||
>
|
||||
<Icon :name="tab.icon" :size="12" class="comm-tab__icon" />
|
||||
<span class="comm-tab__count">{{ tab.count }}</span>
|
||||
</button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<el-collapse
|
||||
@@ -67,9 +79,10 @@
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
:default-expand-all="false"
|
||||
v-bind="$attrs"
|
||||
v-bind="treeAttrs"
|
||||
:data="zlDevList"
|
||||
class="collapse-tree"
|
||||
@node-click="onTreeNodeClick"
|
||||
>
|
||||
<template #default="{ node, data: nodeData }">
|
||||
<span class="custom-tree-node">
|
||||
@@ -95,8 +108,9 @@
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
:data="bxsDeviceData"
|
||||
v-bind="$attrs"
|
||||
v-bind="treeAttrs"
|
||||
class="collapse-tree"
|
||||
@node-click="onTreeNodeClick"
|
||||
>
|
||||
<template #default="{ node, data: nodeData }">
|
||||
<span class="custom-tree-node">
|
||||
@@ -122,8 +136,9 @@
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
:data="frontDeviceData"
|
||||
v-bind="$attrs"
|
||||
v-bind="treeAttrs"
|
||||
class="collapse-tree"
|
||||
@node-click="onTreeNodeClick"
|
||||
>
|
||||
<template #default="{ node, data: nodeData }">
|
||||
<span class="custom-tree-node">
|
||||
@@ -147,10 +162,11 @@
|
||||
highlight-current
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
v-bind="$attrs"
|
||||
v-bind="treeAttrs"
|
||||
:data="props.data"
|
||||
class="engineering-tree"
|
||||
:default-expand-all="false"
|
||||
@node-click="onTreeNodeClick"
|
||||
>
|
||||
<template #default="{ node, data: nodeData }">
|
||||
<span class="custom-tree-node">
|
||||
@@ -172,7 +188,7 @@
|
||||
<script lang="ts" setup>
|
||||
import useCurrentInstance from '@/utils/useCurrentInstance'
|
||||
import { ElTree, type CollapseModelValue } from 'element-plus'
|
||||
import { ref, watch, onMounted, nextTick } from 'vue'
|
||||
import { ref, watch, onMounted, nextTick, computed, useAttrs } from 'vue'
|
||||
import { collectDeviceLeaves } from './govern/lineTreeUtils'
|
||||
import { collectDeviceApiLeaves } from './govern/deviceTreeUtils'
|
||||
|
||||
@@ -194,6 +210,8 @@ interface Props {
|
||||
leafMode?: 'line' | 'device'
|
||||
}
|
||||
|
||||
type CommFilter = 'all' | 'normal' | 'abnormal'
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
width: '280px',
|
||||
canExpand: true,
|
||||
@@ -211,11 +229,20 @@ const options = [
|
||||
]
|
||||
|
||||
const { proxy } = useCurrentInstance()
|
||||
const attrs = useAttrs()
|
||||
|
||||
/** 去掉 node-click,避免与本地处理重复/覆盖 */
|
||||
const treeAttrs = computed(() => {
|
||||
const { onNodeClick: _onNodeClick, ...rest } = attrs as Record<string, any>
|
||||
return rest
|
||||
})
|
||||
|
||||
const menuCollapse = ref(false)
|
||||
const activeName = ref('0')
|
||||
const filterText = ref('')
|
||||
const process = ref('')
|
||||
const loading = ref(false)
|
||||
const commFilter = ref<CommFilter>('all')
|
||||
|
||||
const defaultProps = { label: 'name', value: 'id' }
|
||||
|
||||
@@ -231,6 +258,67 @@ const treeRef4 = ref<InstanceType<typeof ElTree>>()
|
||||
|
||||
defineExpose({ treeRef1, treeRef2, treeRef3, treeRef4 })
|
||||
|
||||
const isCommNormal = (node: any) => Number(node?.comFlag) === 2
|
||||
|
||||
/** 设备叶子:Platform 且无子节点,或 type=device */
|
||||
function isDeviceLeaf(data: any): boolean {
|
||||
if (!data) return false
|
||||
if (data.type === 'device') return true
|
||||
if (data.icon === 'el-icon-Platform' && (!data.children || !data.children.length)) return true
|
||||
if (data.level === 2 && data.icon === 'el-icon-Platform') return true
|
||||
return false
|
||||
}
|
||||
|
||||
function collectDevices(nodes: any[], out: any[] = []): any[] {
|
||||
nodes?.forEach(n => {
|
||||
if (isDeviceLeaf(n)) out.push(n)
|
||||
if (n.children?.length) collectDevices(n.children, out)
|
||||
})
|
||||
return out
|
||||
}
|
||||
|
||||
const deviceList = computed(() => {
|
||||
if (treeType.value === '2') return collectDevices(props.data || [])
|
||||
const collectLeaves = props.leafMode === 'device' ? collectDeviceApiLeaves : collectDeviceLeaves
|
||||
const { govern, portable, monitor } = collectLeaves(
|
||||
zlDevList.value,
|
||||
bxsDeviceData.value,
|
||||
frontDeviceData.value
|
||||
)
|
||||
return [...govern, ...portable, ...monitor]
|
||||
})
|
||||
|
||||
const deviceStats = computed(() => {
|
||||
const list = deviceList.value
|
||||
const total = list.length
|
||||
const normal = list.filter(isCommNormal).length
|
||||
return { total, normal, abnormal: total - normal }
|
||||
})
|
||||
|
||||
const commTabs = computed(() => [
|
||||
{ key: 'all' as const, label: '全部设备', count: deviceStats.value.total, icon: 'el-icon-Platform' },
|
||||
{ key: 'normal' as const, label: '通讯正常', count: deviceStats.value.normal, icon: 'el-icon-Platform' },
|
||||
{ key: 'abnormal' as const, label: '通讯异常', count: deviceStats.value.abnormal, icon: 'el-icon-Platform' }
|
||||
])
|
||||
|
||||
function applyTreeFilter() {
|
||||
nextTick(() => {
|
||||
const val = filterText.value
|
||||
if (treeType.value === '1') {
|
||||
treeRef1.value?.filter(val)
|
||||
treeRef2.value?.filter(val)
|
||||
treeRef3.value?.filter(val)
|
||||
} else {
|
||||
treeRef4.value?.filter(val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const onCommFilter = (key: CommFilter) => {
|
||||
commFilter.value = key
|
||||
applyTreeFilter()
|
||||
}
|
||||
|
||||
function splitTreeData(val: any[]) {
|
||||
zlDeviceData.value = []
|
||||
bxsDeviceData.value = []
|
||||
@@ -270,6 +358,17 @@ function getActiveTreeRef() {
|
||||
return treeRef3.value
|
||||
}
|
||||
|
||||
function forwardNodeClick(data: any, node: any, ev?: any) {
|
||||
const handler = (attrs as any).onNodeClick
|
||||
if (!handler) return
|
||||
if (Array.isArray(handler)) handler.forEach((fn: any) => fn?.(data, node, ev))
|
||||
else handler(data, node, ev)
|
||||
}
|
||||
|
||||
function onTreeNodeClick(data: any, node: any, ev?: any) {
|
||||
forwardNodeClick(data, node, ev)
|
||||
}
|
||||
|
||||
function resolveActiveName() {
|
||||
if (zlDeviceData.value.length) return '0'
|
||||
if (bxsDeviceData.value.length) return '1'
|
||||
@@ -323,12 +422,13 @@ watch(
|
||||
if (treeType.value === '1') {
|
||||
nextTick(() => setActiveName())
|
||||
}
|
||||
applyTreeFilter()
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
watch(filterText, val => {
|
||||
getActiveTreeRef()?.filter(val)
|
||||
watch(filterText, () => {
|
||||
applyTreeFilter()
|
||||
})
|
||||
|
||||
watch(process, () => {
|
||||
@@ -336,6 +436,11 @@ watch(process, () => {
|
||||
if (activeName.value === '0') {
|
||||
nextTick(() => changeDevice(activeName.value))
|
||||
}
|
||||
applyTreeFilter()
|
||||
})
|
||||
|
||||
watch(treeType, () => {
|
||||
applyTreeFilter()
|
||||
})
|
||||
|
||||
const onMenuCollapse = () => {
|
||||
@@ -343,10 +448,20 @@ const onMenuCollapse = () => {
|
||||
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 filterNode = (_value: string, data: any, node: any): boolean => {
|
||||
if (filterText.value) {
|
||||
if (!data.name) return false
|
||||
if (!chooseNode(filterText.value, data, node)) return false
|
||||
}
|
||||
|
||||
if (commFilter.value === 'all') return true
|
||||
|
||||
if (isDeviceLeaf(data)) {
|
||||
const normal = isCommNormal(data)
|
||||
return commFilter.value === 'normal' ? normal : !normal
|
||||
}
|
||||
|
||||
return !!filterText.value
|
||||
}
|
||||
|
||||
const chooseNode = (value: string, data: any, node: any): boolean => {
|
||||
@@ -413,6 +528,115 @@ onMounted(() => {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.comm-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// justify-content: flex-end;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.comm-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
height: 22px;
|
||||
padding: 0 4px 0 6px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5eaf3;
|
||||
background: #fff;
|
||||
color: #4e5969;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
line-height: 1;
|
||||
|
||||
&__icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.is-all .comm-tab__icon,
|
||||
&.is-all :deep(.comm-tab__icon),
|
||||
&.is-all :deep(svg),
|
||||
&.is-all :deep(i) {
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
&.is-normal .comm-tab__icon,
|
||||
&.is-normal :deep(.comm-tab__icon),
|
||||
&.is-normal :deep(svg),
|
||||
&.is-normal :deep(i) {
|
||||
color: #2ab914 !important;
|
||||
}
|
||||
|
||||
&.is-abnormal .comm-tab__icon,
|
||||
&.is-abnormal :deep(.comm-tab__icon),
|
||||
&.is-abnormal :deep(svg),
|
||||
&.is-abnormal :deep(i) {
|
||||
color: #e26257 !important;
|
||||
}
|
||||
|
||||
&__count {
|
||||
min-width: 20px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
&:hover:not(.is-active) {
|
||||
border-color: var(--el-color-primary-light-5);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: #fff;
|
||||
|
||||
.comm-tab__icon,
|
||||
:deep(.comm-tab__icon),
|
||||
:deep(svg),
|
||||
:deep(i) {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.comm-tab__count {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-all.is-active {
|
||||
background: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
.comm-tab__count {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-normal.is-active {
|
||||
background: #2ab914;
|
||||
border-color: #2ab914;
|
||||
|
||||
.comm-tab__count {
|
||||
color: #2ab914;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-abnormal.is-active {
|
||||
background: #e26257;
|
||||
border-color: #e26257;
|
||||
|
||||
.comm-tab__count {
|
||||
color: #e26257;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.device-collapse {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
Reference in New Issue
Block a user