refactor(vimp): 重命名右侧面板为ConfigPanel并镜像左侧面板结构

- 删除 right-panel.vue,新建 config-panel.vue + config-panel.ts store
- 接入 Pinia store 管理折叠状态,与 ResourcePanel store 结构镜像
- NTabs 改为纵向 placement=right + type=bar,Tab 标签加 lucide 图标
- 标题栏与 Tab 栏 72px 格纵向对齐,折叠后从右截断保留 Tab 标签
- 画布区域移除占位卡片,保留灰色斜纹 + drop 行为
- 删除未实现的"事件陷阱" Tab
This commit is contained in:
yangsy
2026-06-09 23:20:31 +08:00
parent 5092620008
commit 635d623994
6 changed files with 150 additions and 47 deletions
+1 -5
View File
@@ -59,10 +59,6 @@ const onDrop = (e: DragEvent) => {
}"
@dragover="onDragover"
@drop="onDrop"
>
<div :style="{ padding: '12px 24px', border: '1px solid #ddd', borderRadius: '4px', backgroundColor: '#fff', fontSize: '13px' }">
{{ screens.find(s => s.id === activeScreen)?.name }} 画布占位
</div>
</div>
/>
</div>
</template>
+131
View File
@@ -0,0 +1,131 @@
<script setup lang="ts">
import { NButton, NIcon, NTabPane, NTabs, NText } from 'naive-ui'
import { ChevronRightIcon, DatabaseIcon, LayoutGridIcon, SlidersHorizontalIcon, ZapIcon, type Component } from 'lucide-vue-next'
import { ref } from 'vue'
import { useConfigPanelStore } from '../stores'
import { storeToRefs } from 'pinia'
interface ControlTabPane {
name: string
tab: string
icon: Component
}
const tabs: ControlTabPane[] = [
{ name: 'component', tab: '组件', icon: LayoutGridIcon },
{ name: 'config', tab: '属性', icon: SlidersHorizontalIcon },
{ name: 'data', tab: '数据', icon: DatabaseIcon },
{ name: 'interaction', tab: '事件', icon: ZapIcon },
]
const PANEL_WIDTH_EXPANDED = '320px'
const PANEL_WIDTH_COLLAPSED = '72px'
const TAB_WIDTH = '72px'
const activeTab = ref(tabs[0]?.name ?? '')
const configPanelStore = useConfigPanelStore()
const { collapsed } = storeToRefs(configPanelStore)
const expandConfigPanel = () => {
if (collapsed.value) {
configPanelStore.toggleCollapsed()
}
}
</script>
<template>
<div
:style="{
width: collapsed ? PANEL_WIDTH_COLLAPSED : PANEL_WIDTH_EXPANDED,
flexShrink: 0,
height: '100%',
display: 'flex',
justifyContent: 'flex-end',
overflow: 'hidden',
transition: 'width 0.2s',
}"
>
<div
:style="{
width: PANEL_WIDTH_EXPANDED,
height: '100%',
display: 'flex',
flexDirection: 'column',
}"
>
<div
:style="{
height: '42px',
flexShrink: 0,
padding: '8px 0',
display: 'flex',
alignItems: 'center',
}"
>
<div
:style="{
display: 'grid',
placeItems: 'center',
width: '32px',
marginRight: 'auto',
}"
>
<NButton text @click="configPanelStore.toggleCollapsed()">
<NIcon :component="ChevronRightIcon" />
</NButton>
</div>
<div
:style="{
display: 'grid',
placeItems: 'center',
width: TAB_WIDTH,
}"
>
<NText>控制</NText>
</div>
</div>
<div
:style="{
flex: 1,
minHeight: 0,
overflow: 'hidden',
}"
>
<NTabs
v-model:value="activeTab"
:type="'bar'"
:placement="'right'"
:size="'small'"
:tab-style="{
width: TAB_WIDTH,
height: '64px',
}"
:style="{
height: '100%',
'--n-pane-padding-top': '0',
'--n-tab-gap-vertical': '0',
}"
>
<NTabPane
v-for="t in tabs"
:key="t.name"
:name="t.name"
:tab="t.tab"
:tab-props="{ onClick: () => expandConfigPanel() }"
>
<template #tab>
<div :style="{ width: '48px', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }">
<NIcon :size="18" :component="t.icon" />
<div :style="{ fontSize: '12px' }">{{ t.tab }}</div>
</div>
</template>
<div :style="{ padding: '20px', textAlign: 'center', fontSize: '12px' }">
{{ t.tab }}面板占位
</div>
</NTabPane>
</NTabs>
</div>
</div>
</div>
</template>
-40
View File
@@ -1,40 +0,0 @@
<script setup lang="ts">
import { NTabPane, NTabs, NText } from 'naive-ui'
import { ref } from 'vue'
const tabs = [
{ name: 'component', tab: '组件' },
{ name: 'config', tab: '属性' },
{ name: 'data', tab: '数据' },
{ name: 'interaction', tab: '事件' },
{ name: 'event-trap', tab: '事件陷阱' },
]
const activeTab = ref(tabs[0]?.name ?? '')
const collapsed = ref(false)
</script>
<template>
<div :style="{ width: collapsed ? '48px' : '320px', flexShrink: 0, transition: 'width 0.2s' }">
<div :style="{ width: '320px', height: '100%', display: 'flex', flexDirection: 'column' }">
<div :style="{ height: '42px', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 8px' }">
<NText>控制</NText>
<button
:style="{ border: 'none', background: 'transparent', cursor: 'pointer', fontSize: '16px', padding: '4px 8px' }"
@click="collapsed = !collapsed"
>
{{ collapsed ? '' : '' }}
</button>
</div>
<div v-show="!collapsed" :style="{ flex: 1, minHeight: 0, overflow: 'auto', padding: '8px' }">
<NTabs v-model:value="activeTab" type="line" size="small" animated>
<NTabPane v-for="t in tabs" :key="t.name" :name="t.name" :tab="t.tab">
<div :style="{ padding: '20px', textAlign: 'center', fontSize: '12px' }">
{{ t.tab }}面板占位
</div>
</NTabPane>
</NTabs>
</div>
</div>
</div>
</template>
+15
View File
@@ -0,0 +1,15 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useConfigPanelStore = defineStore('vimp-config-panel', () => {
const collapsed = ref<boolean>(false)
const toggleCollapsed = () => {
collapsed.value = !collapsed.value
}
return {
collapsed,
toggleCollapsed,
}
})
+1
View File
@@ -1,3 +1,4 @@
export * from './alarm';
export * from './camera';
export * from './config-panel';
export * from './resource-panel';
+2 -2
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import ResourcePanel from './components/resource-panel.vue'
import RightPanel from './components/right-panel.vue'
import ConfigPanel from './components/config-panel.vue'
import CanvasArea from './components/canvas-area.vue'
</script>
@@ -8,6 +8,6 @@ import CanvasArea from './components/canvas-area.vue'
<div style="height: 100%; display: flex; overflow: hidden">
<ResourcePanel />
<CanvasArea />
<RightPanel />
<ConfigPanel />
</div>
</template>