feat(vimp): 在vimp-page中新增三栏布局占位(resource-panel + canvas-area + right-panel)

新增 components/canvas-area.vue(多屏NTabs + 灰色斜纹画布占位)。新增 components/right-panel.vue(5 NTabs 占位 + 折叠按钮)。改造 vimp-page.vue 为三栏 flex div + 内联样式。保留 ResourcePanel 与原有 drop 行为不动。
This commit is contained in:
yangsy
2026-06-09 21:53:39 +08:00
parent 2df67df74a
commit 5092620008
3 changed files with 114 additions and 34 deletions
+68
View File
@@ -0,0 +1,68 @@
<script setup lang="ts">
import { NTabs, NTabPane } from 'naive-ui'
import { ref } from 'vue'
const screens = [
{ id: 'screen-1', name: '屏幕 1' },
{ id: 'screen-2', name: '屏幕 2' },
{ id: 'screen-3', name: '屏幕 3' },
{ id: 'screen-4', name: '屏幕 4' },
]
const activeScreen = ref(screens[0]?.id ?? '')
const onDragover = (e: DragEvent) => {
e.preventDefault()
if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'
}
const onDrop = (e: DragEvent) => {
e.preventDefault()
const type = e.dataTransfer?.getData('type')
if (!type) return
if (type === 'camera' || type === 'alarm') {
const code = e.dataTransfer.getData('code')
const name = e.dataTransfer.getData('name')
window.$message?.info(`播放:${JSON.stringify({ code, name })}`)
}
}
</script>
<template>
<div :style="{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }">
<div :style="{ flexShrink: 0, padding: '0 8px' }">
<NTabs
v-model:value="activeScreen"
type="line"
size="small"
animated
>
<NTabPane
v-for="s in screens"
:key="s.id"
:name="s.id"
:tab="s.name"
/>
</NTabs>
</div>
<div
:style="{
flex: 1,
minHeight: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
backgroundImage: 'linear-gradient(45deg, #e5e5e5 25%, transparent 25%), linear-gradient(-45deg, #e5e5e5 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #e5e5e5 75%), linear-gradient(-45deg, transparent 75%, #e5e5e5 75%)',
backgroundSize: '16px 16px',
backgroundPosition: '0 0, 0 8px, 8px -8px, -8px 0',
}"
@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>
+40
View File
@@ -0,0 +1,40 @@
<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>
+6 -34
View File
@@ -1,41 +1,13 @@
<script setup lang="ts">
import ResourcePanel from './components/resource-panel.vue';
const onDragover = (event: DragEvent) => {
event.preventDefault();
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'copy';
}
};
const onDrop = (event: DragEvent) => {
event.preventDefault();
const type = event.dataTransfer?.getData('type');
if (!type) return;
if (type === 'camera') {
const code = event.dataTransfer?.getData('code');
if (!code) return;
const name = event.dataTransfer?.getData('name');
window.$message.info(`播放:${JSON.stringify({ code, name })}`);
} else if (type === 'alarm') {
const code = event.dataTransfer?.getData('code');
if (!code) return;
const name = event.dataTransfer?.getData('name');
window.$message.info(`查看警报器:${JSON.stringify({ code, name })}`);
} else {
}
};
import ResourcePanel from './components/resource-panel.vue'
import RightPanel from './components/right-panel.vue'
import CanvasArea from './components/canvas-area.vue'
</script>
<template>
<div style="height: 100%; overflow: hidden; display: flex">
<div style="height: 100%; display: flex; overflow: hidden">
<ResourcePanel />
<div style="flex: 1">
<div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop">
<div>这里是播放器</div>
</div>
</div>
<CanvasArea />
<RightPanel />
</div>
</template>
<style scoped></style>