feat(vimp-resource): 优化资源面板,添加设备搜索与图标展示

- 新增bullet-camera、hemi-ptz-camera、ptz-camera三个自定义svg摄像头图标
- 替换告警和摄像头列表的文字前缀为对应图标展示
- 重构资源面板状态管理,简化搜索关键词的存储逻辑
- 为摄像头和告警树添加本地搜索过滤功能,搜索时自动展开所有节点
- 重构资源面板UI布局,添加折叠动画,优化搜索框显示逻辑与侧边栏样式
This commit is contained in:
yangsy
2026-05-29 00:11:43 +08:00
parent 2f38e97481
commit 8fae86d6ff
9 changed files with 174 additions and 54 deletions
+96 -28
View File
@@ -1,13 +1,16 @@
<script setup lang="ts">
import { NButton, NFlex, NIcon, NInput, NPageHeader, NTabPane, NTabs, type TabPaneProps } from 'naive-ui';
import { ref, type Component } from 'vue';
import { NButton, NFlex, NIcon, NInput, NPageHeader, NTabPane, NTabs, NText, type TabPaneProps } from 'naive-ui';
import { computed, ref, type Component } from 'vue';
import AlarmTree from './alarm-tree.vue';
import CameraTree from './camera-tree.vue';
import { ChevronLeftIcon } from 'lucide-vue-next';
import { ChevronLeftIcon, PanelBottom } from 'lucide-vue-next';
import { useResourcePanelStore } from '../stores';
import { watchImmediate } from '@vueuse/core';
import { storeToRefs } from 'pinia';
const PANEL_WIDTH_EXPANDED = '480px';
const PANEL_WIDTH_COLLAPSED = '72px';
interface ResourceTabPane extends TabPaneProps {
name: string;
tab: string;
@@ -22,8 +25,12 @@ const resourceTabPanes: ResourceTabPane[] = [
const activeTabName = ref(resourceTabPanes.at(0)?.name ?? '');
const showSearchInput = computed(() => {
return ['camera', 'alarm'].includes(activeTabName.value);
});
const resourcePanelStore = useResourcePanelStore();
const { collapsed, searchInput } = storeToRefs(resourcePanelStore);
const { collapsed, searchPattern } = storeToRefs(resourcePanelStore);
const collapseResourcePanel = () => {
if (!collapsed.value) {
@@ -39,30 +46,91 @@ const expandResourcePanel = () => {
</script>
<template>
<NFlex vertical :size="0" style="width: 480px; height: 100%; overflow: hidden">
<NFlex style="width: 100%; min-height: 38px; padding: 8px 16px" :align="'center'">
<div>资源</div>
<template v-if="!collapsed">
<NInput clearable :size="'tiny'" :placeholder="'搜索'" style="width: 360px; margin-left: auto" />
<NButton text @click="collapseResourcePanel">
<NIcon :component="ChevronLeftIcon"></NIcon>
</NButton>
</template>
</NFlex>
<NTabs :type="'line'" :placement="'left'" style="height: 100%; flex: 1" v-model:value="activeTabName">
<NTabPane
v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes"
:key="resourceName"
:tab="resourceTab"
:name="resourceName"
:tab-props="{ onClick: () => expandResourcePanel() }"
>
<template v-if="!collapsed && !!component">
<component :is="component" />
<div
class="resource-panel__wrapper"
:style="{
width: collapsed ? PANEL_WIDTH_COLLAPSED : PANEL_WIDTH_EXPANDED,
}"
>
<div
class="resource-panel"
:style="{
width: PANEL_WIDTH_EXPANDED,
}"
>
<div class="resource-panel__title">
<div style="display: grid; place-items: center" :style="{ width: PANEL_WIDTH_COLLAPSED }">
<NText>资源</NText>
</div>
<template v-if="showSearchInput">
<div style="width: 240px; margin-left: auto">
<NInput clearable :size="'tiny'" :placeholder="'搜索'" v-model:value="searchPattern" />
</div>
</template>
</NTabPane>
</NTabs>
</NFlex>
<div style="margin: 0px 16px; display: grid; place-items: center" :style="{ marginLeft: showSearchInput ? '8px' : 'auto' }">
<NButton text @click="collapseResourcePanel">
<NIcon :component="ChevronLeftIcon"></NIcon>
</NButton>
</div>
</div>
<div class="resource-panel__tabs-wrapper">
<NTabs
:type="'bar'"
:size="'small'"
:placement="'left'"
v-model:value="activeTabName"
:tab-style="{
height: '64px',
width: '72px',
}"
:style="{
height: '100%', // 为了确保 tabs 高度和 panel 高度一致,否则设备树会超出 panel 高度,导致虚拟滚动失效
'--n-pane-padding-top': '0',
'--n-tab-gap-vertical': '0',
// '--n-tab-padding-vertical': '14px 6px',
}"
>
<NTabPane
v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes"
:key="resourceName"
:tab="resourceTab"
:name="resourceName"
:tab-props="{ onClick: () => expandResourcePanel() }"
>
<template v-if="!!component">
<component :is="component" />
</template>
</NTabPane>
</NTabs>
</div>
</div>
</div>
</template>
<style scoped></style>
<style scoped lang="scss">
.resource-panel__wrapper {
height: 100%;
overflow: hidden;
transition: width 0.3s ease;
.resource-panel {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
&__title {
min-height: 42px;
max-height: 42px;
padding: 8px 0px;
display: flex;
align-items: center;
}
&__tabs-wrapper {
flex: 1;
overflow: hidden;
}
}
}
</style>