refactor(vimp): 提取资源面板为独立组件并添加pinia存储

- 将原内嵌的资源标签页逻辑提取为独立组件
- 新增专用pinia存储管理资源面板的折叠和搜索状态
- 统一折叠展开与搜索交互的逻辑实现
This commit is contained in:
yangsy
2026-05-28 16:23:42 +08:00
parent bd1cc0483b
commit d5b380e1e3
3 changed files with 84 additions and 28 deletions
@@ -0,0 +1,62 @@
<script setup lang="ts">
import { NButton, NFlex, NIcon, NInput, NPageHeader, NTabPane, NTabs, type TabPaneProps } from 'naive-ui';
import { ref, type Component } from 'vue';
import AlarmTree from './alarm-tree.vue';
import CameraTree from './camera-tree.vue';
import { ChevronLeftIcon } from 'lucide-vue-next';
import { useResourcePanelStore } from '../stores';
import { watchImmediate } from '@vueuse/core';
import { storeToRefs } from 'pinia';
interface ResourceTabPane extends TabPaneProps {
name: string;
tab: string;
component?: Component;
}
const resourceTabPanes: ResourceTabPane[] = [
{ name: 'camera', tab: '摄像头', component: CameraTree },
{ name: 'alarm', tab: '警报器', component: AlarmTree },
{ name: 'monitor', tab: '监视器' },
];
const activeTabName = ref(resourceTabPanes.at(0)?.name ?? '');
const resourcePanelStore = useResourcePanelStore();
const { collapsed, searchInput } = storeToRefs(resourcePanelStore);
const collapseResourcePanel = () => {
if (!collapsed.value) {
resourcePanelStore.toggleCollapsed();
}
};
const expandResourcePanel = () => {
if (collapsed.value) {
resourcePanelStore.toggleCollapsed();
}
};
</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 @click="expandResourcePanel">资源</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">
<template v-if="!!component && !collapsed">
<component :is="component" />
</template>
</NTabPane>
</NTabs>
</NFlex>
</template>
<style scoped></style>
+20 -4
View File
@@ -1,12 +1,28 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
export interface ResourcePanelSearchInput {
enabled: boolean; // 是否启用搜索输入框 (只有在资源面板展开且选择摄像机或警报器时才启用)
show: boolean; // 是否显示搜索输入框 (只有当enabled为true时才允许控制显示)
value: string; // 搜索输入框的值
}
export const useResourcePanelStore = defineStore('vimp-resource-panel', () => { export const useResourcePanelStore = defineStore('vimp-resource-panel', () => {
const showSearch = ref<boolean>(false); const collapsed = ref<boolean>(false);
const searchText = ref<string>(''); const searchInput = ref<ResourcePanelSearchInput>({
enabled: false,
show: false,
value: '',
});
const toggleCollapsed = () => {
collapsed.value = !collapsed.value;
};
return { return {
showSearch, collapsed,
searchText, searchInput,
toggleCollapsed,
}; };
}); });
+2 -24
View File
@@ -1,19 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { NTabPane, NTabs, type TabPaneProps } from 'naive-ui'; import ResourcePanel from './components/resource-pannel.vue';
import { ref, type Component } from 'vue';
import CameraTree from './components/camera-tree.vue';
import AlarmTree from './components/alarm-tree.vue';
interface ResourceTabPane extends TabPaneProps {
name: string;
tab: string;
component?: Component;
}
const resourceTabPanes: ResourceTabPane[] = [
{ name: 'camera', tab: '摄像头', component: CameraTree },
{ name: 'alarm', tab: '警报器', component: AlarmTree },
];
const onDragover = (event: DragEvent) => { const onDragover = (event: DragEvent) => {
event.preventDefault(); event.preventDefault();
@@ -43,15 +29,7 @@ const onDrop = (event: DragEvent) => {
<template> <template>
<div style="height: 100%; overflow: hidden; display: flex"> <div style="height: 100%; overflow: hidden; display: flex">
<div style="width: 540px; height: 100%; overflow: hidden"> <ResourcePanel />
<NTabs :type="'line'" :placement="'left'" style="height: 100%">
<NTabPane v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes" :key="resourceName" :tab="resourceTab" :name="resourceName">
<template v-if="!!component">
<component :is="component" />
</template>
</NTabPane>
</NTabs>
</div>
<div style="flex: 1"> <div style="flex: 1">
<div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop"> <div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop">
<div>这里是播放器</div> <div>这里是播放器</div>