8fae86d6ff
- 新增bullet-camera、hemi-ptz-camera、ptz-camera三个自定义svg摄像头图标 - 替换告警和摄像头列表的文字前缀为对应图标展示 - 重构资源面板状态管理,简化搜索关键词的存储逻辑 - 为摄像头和告警树添加本地搜索过滤功能,搜索时自动展开所有节点 - 重构资源面板UI布局,添加折叠动画,优化搜索框显示逻辑与侧边栏样式
132 lines
3.9 KiB
Vue
132 lines
3.9 KiB
Vue
<script setup lang="ts">
|
|
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
|
|
import { h, type CSSProperties } from 'vue';
|
|
import { useAlarmStore, useResourcePanelStore } from '../stores';
|
|
import { storeToRefs } from 'pinia';
|
|
import { useDeviceCenterQuery } from '../composables';
|
|
import { isAlarmNode, isAlarmSiteNode, isAlarmAreaNode } from '../types';
|
|
|
|
const { isLoading } = useDeviceCenterQuery();
|
|
|
|
const alarmStore = useAlarmStore();
|
|
const { lineTabPanes } = storeToRefs(alarmStore);
|
|
|
|
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
|
|
const hasChildren = (option.children?.length ?? 0) > 0;
|
|
if (hasChildren) {
|
|
return 'toggleExpand';
|
|
} else {
|
|
return 'none';
|
|
}
|
|
};
|
|
|
|
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|
// 是车站节点
|
|
if (isAlarmSiteNode(option)) {
|
|
const siteOnline = option.online;
|
|
const siteNodeStyle: CSSProperties = {
|
|
opacity: siteOnline ? 1 : 0.5,
|
|
};
|
|
return h('div', { style: siteNodeStyle }, option.label);
|
|
}
|
|
|
|
// 是中间节点(一级/二级区域)
|
|
if (isAlarmAreaNode(option)) {
|
|
const site = option.site;
|
|
const nodeStyle: CSSProperties = {
|
|
opacity: site.online ? 1 : 0.5,
|
|
};
|
|
return h('div', { style: nodeStyle }, option.label);
|
|
}
|
|
|
|
// 是警报器节点
|
|
if (isAlarmNode(option)) {
|
|
const alarm = option.alarm;
|
|
const site = option.site;
|
|
|
|
const alarmOnline = () => {
|
|
return alarm.status === 1 && site.online;
|
|
};
|
|
|
|
const alarmNodeStyle: CSSProperties = {
|
|
opacity: alarmOnline() ? 1 : 0.5,
|
|
cursor: alarmOnline() ? 'pointer' : 'not-allowed',
|
|
};
|
|
return h(
|
|
'div',
|
|
{
|
|
style: alarmNodeStyle,
|
|
draggable: alarmOnline(),
|
|
onDblclick() {
|
|
if (!alarmOnline()) return;
|
|
window.$message.info(`查看警报器:${JSON.stringify({ code: alarm.code, name: alarm.name })}`);
|
|
},
|
|
onDragstart(event) {
|
|
if (!alarmOnline()) return;
|
|
console.log(event);
|
|
event.dataTransfer?.setData('type', 'alarm');
|
|
event.dataTransfer?.setData('code', alarm.code);
|
|
event.dataTransfer?.setData('name', alarm.name);
|
|
},
|
|
},
|
|
alarm.name,
|
|
);
|
|
}
|
|
|
|
// 其他节点(兜底,理论上不会走到这里)
|
|
return option.label;
|
|
};
|
|
|
|
const resourcePanelStore = useResourcePanelStore();
|
|
const { searchPattern } = storeToRefs(resourcePanelStore);
|
|
|
|
const searchFilter: TreeProps['filter'] = (pattern, node) => {
|
|
if (!isAlarmNode(node)) return false;
|
|
return node.alarm.name.includes(pattern);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<template v-if="isLoading">
|
|
<div>loading...</div>
|
|
</template>
|
|
<template v-else-if="lineTabPanes.length === 1">
|
|
<NTree
|
|
block-line
|
|
block-node
|
|
show-line
|
|
virtual-scroll
|
|
style="height: 100%"
|
|
:render-label="renderNodeLabel"
|
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
|
:default-expand-all="searchPattern.trim().length > 0"
|
|
:show-irrelevant-nodes="false"
|
|
:data="lineTabPanes.at(0)?.alarmTree"
|
|
:pattern="searchPattern"
|
|
:filter="searchFilter"
|
|
/>
|
|
</template>
|
|
<template v-if="lineTabPanes.length > 1">
|
|
<NTabs :type="'card'" :placement="'left'" style="height: 100%">
|
|
<NTabPane v-for="{ lineCode, lineName, alarmTree } in lineTabPanes" :key="lineCode" :name="lineName" :tab="lineName">
|
|
<NTree
|
|
block-line
|
|
block-node
|
|
show-line
|
|
virtual-scroll
|
|
style="height: 100%"
|
|
:render-label="renderNodeLabel"
|
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
|
:default-expand-all="false"
|
|
:show-irrelevant-nodes="false"
|
|
:data="alarmTree"
|
|
:pattern="searchPattern"
|
|
:filter="searchFilter"
|
|
/>
|
|
</NTabPane>
|
|
</NTabs>
|
|
</template>
|
|
</template>
|
|
|
|
<style scoped></style>
|