This commit is contained in:
zqm
2025-11-03 08:31:37 +08:00
6 changed files with 493 additions and 301 deletions

View File

@@ -6,7 +6,7 @@
7. AutoRobot\Windows\Robot\Web:这是AutoRobot项目的客户端的子项目目录编译npm run build
8. 在执行git或svn操作时需要切换代码页到 chcp 936 执行其它命令时,请先切换回默认的代码页 chcp 65001
9. Maven 仓库地址是 http://geek.cdjkt.com:30003/repository/maven-publicisAllowInsecureProtocol = true
10. go 仓库的地址是 http://geek.cdjkt.com:30003/repository/go-public
10. go 仓库的地址是 http://47.111.181.23:8081/repository/go-public/
11. Nexus 仓库地址是http://geek.cdjkt.com:30003用户名admin密码Access2cRte
12. 当前终端是powershell请注意命令的格式
13. 当文件被修改时,需要暂停执行,待我接受或者拒绝修改后,再继续执行

View File

@@ -0,0 +1,213 @@
<template>
<div class="vs-area-wrapper">
<div class="vs-area select-none" :class="{ 'is-maximized': isMaximized }" :style="areaStyle">
<!-- 顶部标题栏 -->
<div v-if="showTitleBar" class="vs-title-bar">
<div class="vs-title-left">
<div class="vs-app-icon" aria-label="AppIcon">
<svg class="vs-icon" viewBox="0 0 22.4 22.4" aria-hidden="true">
<path
fill="#68217A"
fill-rule="evenodd"
clip-rule="evenodd"
style="shape-rendering: crispEdges;"
d="M0 4.2 L1.8 3.4 L5.8 6.6 L12.6 0 L16.6 1.8 L16.6 15 L12.4 16.6 L6 10.2 L1.8 13.4 L0 12.6 Z
M1.8 5.8 L4.2 8.4 L1.8 10.8 Z
M8.2 8.4 L12.6 5 L12.4 11.6 Z" />
</svg>
</div>
<span class="vs-title-text">{{ title || '面板区' }}</span>
</div>
<div class="vs-title-right title-bar-buttons flex items-center gap-0.5">
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80" :aria-label="isMaximized ? '还原' : '最大化'" @click="onToggleMaximize">
<svg v-if="!isMaximized" class="icon-square-svg" width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<rect x="0.5" y="0.5" width="10" height="10" fill="#cbd6ff" stroke="#8ea3d8" stroke-width="1" />
<rect x="3" y="3" width="5" height="1" fill="#b8c6ff" />
<rect x="1" y="3" width="8.5" height="6.5" fill="#435d9c" />
</svg>
<svg v-else class="icon-square-svg" width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<path
fill="#CED4DD"
fill-rule="evenodd"
clip-rule="evenodd"
d="M1 4 L4 4 L4 1 L11 1 L11 8 L8 8 L8 11 L1 11 Z
M5 4 L5 3 L10 3 L10 7 L8 7 L8 4 Z
M2 6 L12.6 5 L7 6 L7 10 L2 10 Z" />
</svg>
</button>
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80" aria-label="关闭" @click="onClose">
<svg width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<line x1="2" y1="2" x2="9" y2="9" stroke="#e6efff" stroke-width="1"></line>
<line x1="2" y1="9" x2="9" y2="2" stroke="#e6efff" stroke-width="1"></line>
</svg>
</button>
</div>
</div>
<!-- 内容区域 -->
<div class="vs-content">
<!-- 内容区域已清空 -->
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, computed, defineEmits, ref } from 'vue'
const props = defineProps({
id: { type: String, required: true },
title: { type: String, default: '面板区' },
resizable: { type: Boolean, default: true },
// 新增:初始状态(支持中文值)
WindowState: { type: String, default: '正常' },
// 新增:默认尺寸
width: { type: Number, default: 300 },
height: { type: Number, default: 250 },
// 新增:控制标题栏显示
showTitleBar: { type: Boolean, default: true }
})
// 本地状态:不再向父组件发事件,内部维护最大化/还原
const localState = ref(props.WindowState)
// 根据本地状态计算是否最大化
const isMaximized = computed(() => localState.value === '最大化' || localState.value === 'maximized')
// 新增:根据状态计算尺寸样式
const areaStyle = computed(() => {
if (isMaximized.value) {
return { width: '100%', height: '100%' }
}
return { width: `${props.width}px`, height: `${props.height}px` }
})
const emit = defineEmits(['close'])
const onToggleMaximize = () => {
const next = isMaximized.value ? '正常' : '最大化'
// 直接更新本地状态,不再 emit 到父组件
localState.value = next
}
const onClose = () => emit('close')
</script>
<style scoped>
:root { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
/* 颜色(贴近 VS 蓝色主题) */
.vs-area {
--vs-blue-top: #4f72b3;
--vs-blue-bottom: #3c5a99;
--vs-blue-deep: #2c3e7a;
--vs-tab-blue: #4869a8;
--vs-border: #c7d2ea;
--vs-bg: #f5f7fb;
--vs-panel: #ffffff;
--vs-muted: #6b7aa9;
--vs-accent: #f0a000;
}
/* 容器 */
.vs-area {
display: flex;
flex-direction: column;
background: var(--vs-bg);
border: 1px solid var(--vs-border);
min-width: 300px;
min-height: 250px;
}
/* 标题栏 */
.vs-title-bar {
height: 28px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
color: #ffffff;
background: linear-gradient(to bottom, var(--vs-blue-top), var(--vs-blue-bottom));
border-bottom: 1px solid var(--vs-blue-deep);
}
.vs-title-left { display: flex; align-items: center; gap: 6px; }
.vs-app-icon { font-size: 12px; opacity: 0.9; }
.vs-title-text { font-size: 13px; }
.vs-title-right { display: flex; align-items: center; gap: 6px; }
.vs-btn {
width: 22px; height: 18px; line-height: 18px;
color: #ffffff; background: transparent; border: none; padding: 0; cursor: default;
}
.vs-btn:hover { background: rgba(255,255,255,0.12); }
.vs-close:hover { background: #e81123; }
/* 面板标题行(左右) */
.vs-pane-headers {
display: flex; align-items: center;
height: 26px; background: var(--vs-tab-blue);
border-bottom: 1px solid var(--vs-blue-deep);
color: #eaf1ff;
padding: 0 6px;
}
.vs-pane-header {
display: flex; align-items: center; gap: 8px;
height: 100%; padding: 0 10px;
}
.vs-pane-sep {
width: 1px; height: 18px; background: rgba(255,255,255,0.3);
margin: 0 8px;
}
.hdr-text { font-size: 12px; }
.hdr-icon { font-size: 10px; opacity: 0.9; }
.hdr-close { font-size: 12px; opacity: 0.9; }
.hdr-close:hover { opacity: 1; }
/* 内容区域 */
.vs-content { display: flex; flex: 1; overflow: hidden; }
/* 左侧输出 */
.vs-left { flex: 1; background: var(--vs-panel); display: flex; }
.left-blank { flex: 1; background: #eef1f9; border-right: 1px solid var(--vs-border); }
/* 中间分割线 */
.vs-divider { width: 1px; background: var(--vs-border); }
/* 右侧 Git 更改 */
.vs-right { flex: 1; background: #f5f7fb; padding: 0; }
.sec-text { margin-bottom: 8px; }
.vs-card {
display: inline-flex; align-items: center; gap: 8px;
background: #fff; border: 1px solid var(--vs-border);
padding: 6px 8px; border-radius: 2px; margin-bottom: 10px;
box-shadow: 0 1px 0 rgba(0,0,0,0.04);
}
.card-icon { color: var(--vs-accent); }
.card-text { color: #000; }
.hint-text { color: #666; }
/* 滚动条(接近 VS */
:deep(::-webkit-scrollbar) { width: 12px; height: 12px; }
:deep(::-webkit-scrollbar-track) { background: var(--vs-bg); border-left: 1px solid var(--vs-border); }
:deep(::-webkit-scrollbar-thumb) {
background: linear-gradient(to bottom, #d0d6ea, #c0c7e0);
border: 1px solid #b0b6d6; border-radius: 6px;
}
:deep(::-webkit-scrollbar-thumb:hover) { background: linear-gradient(to bottom, #c1c7e2, #b2b8d9); }
:deep(*) { box-sizing: border-box; }
.vs-area.is-maximized { width: 100%; height: 100%; }
.vs-icon-stage { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: transparent; overflow: auto; }
.vs-app-icon--x200 { width: 2800px; height: 2800px; }
.vs-app-icon { width: 14px; height: 14px; display: inline-block; background: transparent; opacity: 0.95; }
.vs-icon { width: 100%; height: 100%; shape-rendering: crispEdges; }
.vs-app-icon svg { display: block; }
/* 外层包裹,居中内容 */
.vs-area-wrapper {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<div class="dock-layout">
<!-- 主区域 -->
<Area :WindowState="windowState" :showTitleBar="false" title="主区域" />
<!-- 浮动区域列表 -->
<div
v-for="area in floatingAreas"
:key="area.id"
class="floating-area"
:style="{
left: area.x + 'px',
top: area.y + 'px',
width: area.width + 'px',
height: area.height + 'px'
}"
>
<Area
:id="area.id"
:title="area.title"
:WindowState="'正常'"
:showTitleBar="true"
:width="area.width"
:height="area.height"
@close="onCloseFloatingArea(area.id)"
/>
</div>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
import Area from './Area.vue';
import Panel from './Panel.vue';
// 主区域状态
const windowState = ref('最大化')
// 浮动区域列表
const floatingAreas = ref([])
// 区域ID计数器
let areaIdCounter = 1
// 添加新的浮动区域
const addFloatingArea = () => {
const newArea = {
id: `floating-area-${areaIdCounter++}`,
title: `浮动区域 ${areaIdCounter - 1}`,
x: 50 + (areaIdCounter - 2) * 20, // 错开位置
y: 50 + (areaIdCounter - 2) * 20,
width: 300,
height: 200,
collapsed: false,
toolbarExpanded: false
}
floatingAreas.value.push(newArea)
}
// 切换折叠状态
const onToggleCollapse = (id) => {
const area = floatingAreas.value.find(a => a.id === id)
if (area) {
area.collapsed = !area.collapsed
}
}
// 最大化/还原
const onMaximize = (id) => {
const area = floatingAreas.value.find(a => a.id === id)
if (area) {
// 简单实现:交换宽高
const temp = area.width
area.width = area.height
area.height = temp
}
}
// 关闭浮动区域
const onCloseFloatingArea = (id) => {
const index = floatingAreas.value.findIndex(a => a.id === id)
if (index !== -1) {
floatingAreas.value.splice(index, 1)
}
}
// 切换工具栏
const onToggleToolbar = (id) => {
const area = floatingAreas.value.find(a => a.id === id)
if (area) {
area.toolbarExpanded = !area.toolbarExpanded
}
}
// 暴露方法给父组件
defineExpose({
addFloatingArea
})
</script>
<style scoped>
.dock-layout {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
/* 浮动区域样式 */
.floating-area {
position: absolute;
z-index: 10;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
background-color: #fff;
overflow: hidden;
}
/* 添加浮动区域按钮样式 */
.add-floating-btn {
font-size: 14px;
cursor: pointer;
user-select: none;
}
.add-floating-btn:active {
transform: scale(0.98);
}
</style>

View File

@@ -1,263 +0,0 @@
import { ref, computed, defineComponent, onMounted, onUnmounted, watch, nextTick } from 'vue';
/**
* 浮动面板组件
* 提供可拖拽、最大化、最小化、折叠和工具栏扩展功能的窗口组件
*/
export default defineComponent({
name: 'Panel',
props: {
panel: {
type: Object,
required: true,
validator: (value) => {
return value && typeof value === 'object' && 'id' in value && 'title' in value;
}
},
hostRef: {
type: Object,
default: null
}
},
emits: ['close', 'toggleCollapse', 'toggleToolbar', 'maximize'],
setup(props, { emit }) {
// 响应式状态管理
const isDragging = ref(false);
const dragStartPos = ref({ x: 0, y: 0 });
const panelPosition = ref({
x: props.panel.x || 100,
y: props.panel.y || 100
});
const panelSize = ref({
width: props.panel.width || 300,
height: props.panel.height || 180
});
// 同步面板属性变化
const syncPanelProperties = () => {
if (props.panel.x !== undefined) panelPosition.value.x = props.panel.x;
if (props.panel.y !== undefined) panelPosition.value.y = props.panel.y;
if (props.panel.width !== undefined) panelSize.value.width = props.panel.width;
if (props.panel.height !== undefined) panelSize.value.height = props.panel.height;
};
// 计算面板样式
const panelStyle = computed(() => {
// 直接使用props.panel中的值确保与父组件状态同步
const posX = props.panel.x || 100;
const posY = props.panel.y || 100;
const width = props.panel.width || 300;
const height = props.panel.height || 180;
// 始终创建新对象避免Vue响应式系统无法检测变化
const style = {
position: 'absolute',
top: `${posY}px`,
left: `${posX}px`,
width: `${width}px`,
height: `${height}px`,
backgroundColor: 'white',
border: '1px solid #435d9c', // 更深的边框颜色以增强可见性
borderRadius: '4px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.15)',
overflow: 'hidden',
zIndex: 10,
display: 'flex',
flexDirection: 'column'
};
// 最大化状态
if (props.panel.maximized) {
// 获取host元素 - 直接使用hostRef或者hostRef.value如果是ref
const host = props.hostRef && typeof props.hostRef.getBoundingClientRect === 'function'
? props.hostRef
: props.hostRef?.value;
const rect = host?.getBoundingClientRect();
if (rect) {
style.top = '0px';
style.left = '0px';
style.width = `${rect.width - 2}px`;
style.height = `${rect.height - 2}px`;
}
}
return style;
});
// 处理标题栏拖拽
const handleTitleBarMouseDown = (event) => {
if (props.panel.maximized) return;
isDragging.value = true;
dragStartPos.value = {
x: event.clientX - panelPosition.value.x,
y: event.clientY - panelPosition.value.y
};
event.preventDefault();
};
// 处理窗口关闭
const handleClose = () => {
emit('close', props.panel.id);
};
// 处理折叠/展开
const handleToggleCollapse = () => {
emit('toggleCollapse', props.panel.id);
};
// 处理工具栏展开/收起
const handleToggleToolbar = () => {
emit('toggleToolbar', props.panel.id);
};
// 处理最大化/还原
const handleMaximize = () => {
emit('maximize', props.panel.id);
};
// 鼠标移动事件处理
const handleMouseMove = (event) => {
if (isDragging.value && !props.panel.maximized) {
panelPosition.value = {
x: event.clientX - dragStartPos.value.x,
y: event.clientY - dragStartPos.value.y
};
}
};
// 鼠标松开事件处理
const handleMouseUp = () => {
isDragging.value = false;
};
// 监听面板属性变化
watch(() => props.panel, (newPanel) => {
if (newPanel) {
syncPanelProperties();
}
}, { deep: true, immediate: true });
// 生命周期钩子
onMounted(async () => {
// 确保DOM更新后再同步状态
await nextTick();
// 同步外部面板状态
syncPanelProperties();
// 添加全局事件监听
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
});
onUnmounted(() => {
// 清理全局事件监听
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
});
return {
isDragging,
panelStyle,
handleTitleBarMouseDown,
handleClose,
handleToggleCollapse,
handleToggleToolbar,
handleMaximize
};
},
template: `
<div class="panel-container" :style="panelStyle">
<div class="flex flex-col h-full">
<!-- 标题栏 -->
<div
class="h-6 bg-[#435d9c] text-white px-2 flex items-center justify-between select-none"
@mousedown="handleTitleBarMouseDown"
>
<div class="flex items-center">
<span class="text-xs">{{ panel.title }}</span>
</div>
<div class="flex items-center gap-0.5">
<!-- 折叠按钮 -->
<button
class="p-[2px] rounded hover:opacity-100 opacity-80 flex items-center justify-center w-5 h-5"
@click.stop="handleToggleCollapse"
aria-label="折叠/展开"
>
<div class="icon-triangle-down"></div>
</button>
<!-- 最大化按钮 -->
<button
class="p-[2px] rounded hover:opacity-100 opacity-80 flex items-center justify-center w-5 h-5"
@click.stop="handleMaximize"
aria-label="最大化"
>
<div class="icon-square"></div>
</button>
<!-- 关闭按钮 -->
<button
class="p-[2px] rounded hover:opacity-100 opacity-80 flex items-center justify-center w-5 h-5"
@click.stop="handleClose"
aria-label="关闭"
>
<div class="icon-x"></div>
</button>
</div>
</div>
<!-- 工具栏 -->
<div class="h-6 bg-[#d5e2f6] text-[#2c3e7a] px-2 flex items-center justify-between border-b border-[#c7d2ea]">
<div class="flex items-center gap-2">
<span class="text-xs">工具栏</span>
<button v-if="panel.toolbarExpanded" class="px-2 py-0.5 text-xs bg-white/60 rounded hover:bg-white">示例按钮</button>
</div>
<button
class="px-2 py-0.5 text-xs rounded hover:bg-white/40"
@click.stop="handleToggleToolbar"
aria-label="展开工具栏"
>
<span v-if="panel.toolbarExpanded" class="text-xs">-</span>
<span v-else class="text-xs">+</span>
</button>
</div>
<!-- 内容区 -->
<div class="bg-[#f5f7fb] flex-1 p-2" v-if="!panel.collapsed">
<slot name="content"></slot>
</div>
</div>
</div>
`,
// 样式应该放在模板外部作为组件的style选项
style: `
/* 向下小三角 */
.panel-container .icon-triangle-down {
width: 0; height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 6px solid #cbd6ff;
}
/* 最大化图标 */
.panel-container .icon-square {
position: relative;
width: 11px; height: 11px;
background: linear-gradient(180deg, #cbd6ff 0%, #b9c8ff 100%);
border: 1px solid #b8c6ff;
box-sizing: border-box;
}
/* X图标 */
.panel-container .icon-x {
position: relative; width: 11px; height: 11px;
}
.panel-container .icon-x::before, .panel-container .icon-x::after {
content: ''; position: absolute; left: 5px; top: 0; width: 1px; height: 11px; background: #e6efff;
}
.panel-container .icon-x::before { transform: rotate(45deg); }
.panel-container .icon-x::after { transform: rotate(-45deg); }
`
});

View File

@@ -0,0 +1,140 @@
<template>
<div class="panel absolute bg-white shadow rounded border overflow-hidden"
:style="{ top: y + 'px', left: x + 'px', width: width + 'px', height: height + 'px' }">
<div class="flex flex-col h-full">
<!-- 标题栏 -->
<div class="title-bar h-6 bg-[#435d9c] text-white px-2 flex items-center justify-between select-none">
<div class="flex items-center">
<span class="text-xs">{{ title }}</span>
</div>
<div class="title-bar-buttons flex items-center gap-0.5">
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80"
@click="onToggleCollapse"
aria-label="折叠/展开">
<!-- 向下小三角使用内联SVG避免样式作用域问题 -->
<svg width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<polygon points="5.5,8 2,3.5 9,3.5" fill="#cbd6ff" />
</svg>
</button>
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80"
@click="onMaximize"
aria-label="最大化">
<!-- 最大化图标仅外框1px + 两行填充 -->
<svg class="icon-square-svg" width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<rect x="0.5" y="0.5" width="10" height="10" fill="#cbd6ff" stroke="#8ea3d8" stroke-width="1" />
<rect x="3" y="3" width="5" height="1" fill="#b8c6ff" />
<!-- 下行采用更宽填充以贴近示例图 -->
<rect x="1" y="3" width="8.5" height="6.5" fill="#435d9c" />
</svg>
</button>
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80"
@click="onClose"
aria-label="关闭">
<!-- 关闭图标X内联SVG确保1px线条 -->
<svg width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
<line x1="2" y1="2" x2="9" y2="9" stroke="#e6efff" stroke-width="1" />
<line x1="2" y1="9" x2="9" y2="2" stroke="#e6efff" stroke-width="1" />
</svg>
</button>
</div>
</div>
<!-- 工具栏位于标题栏下方右侧扩展钮 -->
<div class="toolbar h-6 bg-[#d5e2f6] text-[#2c3e7a] px-2 flex items-center justify-between border-b border-[#c7d2ea]">
<div class="toolbar-left flex items-center gap-2">
<span class="text-xs">工具栏</span>
<button v-if="toolbarExpanded" class="toolbar-button px-2 py-0.5 text-xs bg-white/60 rounded hover:bg-white">示例按钮</button>
</div>
<button class="toolbar-toggle px-2 py-0.5 text-xs rounded hover:bg-white/40"
@click="onToggleToolbar"
aria-label="展开工具栏">
<i class="fa-solid" :class="toolbarExpanded ? 'fa-angles-left' : 'fa-angles-right'"></i>
</button>
</div>
<!-- 内容区可折叠 -->
<div class="content-area bg-[#f5f7fb] flex-1" v-show="!collapsed"></div>
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
// 定义组件属性
const props = defineProps({
id: {
type: String,
required: true
},
title: {
type: String,
default: ''
},
x: {
type: Number,
default: 0
},
y: {
type: Number,
default: 0
},
width: {
type: Number,
default: 300
},
height: {
type: Number,
default: 180
},
collapsed: {
type: Boolean,
default: false
},
toolbarExpanded: {
type: Boolean,
default: false
}
});
// 定义事件
const emit = defineEmits(['toggleCollapse', 'maximize', 'close', 'toggleToolbar']);
// 事件处理函数
const onToggleCollapse = () => {
emit('toggleCollapse', props.id);
};
const onMaximize = () => {
emit('maximize', props.id);
};
const onClose = () => {
emit('close', props.id);
};
const onToggleToolbar = () => {
emit('toggleToolbar', props.id);
};
</script>
<style scoped>
/* 面板基础样式 */
.panel {
border: 1px solid #c7d2ea;
}
/* 图标样式优化 */
.icon-square-svg {
/* 优化SVG渲染避免1px边框显示过粗的问题 */
shape-rendering: crispEdges;
}
/* 禁用可能存在的旧伪元素样式 */
:deep(.icon-square::before),
:deep(.icon-square::after) {
content: none !important;
display: none !important;
border: 0 !important;
}
</style>

View File

@@ -44,35 +44,19 @@
<!-- 预留主区域暂不放面板 -->
<div ref="panelHost" class="flex-1 w-full h-[calc(100%-4rem)] relative bg-gray-100">
<!-- 浮动面板渲染区 - 使用Panel组件 -->
<Panel
v-for="panel in floatingPanels"
:key="panel.id"
:panel="panel"
:hostRef="panelHost"
@close="closePanel"
@toggleCollapse="toggleCollapse"
@toggleToolbar="toggleToolbarExpand"
@maximize="maximizePanel"
>
<template #content>
<!-- 面板内容区域 -->
<div class="p-4">
<div class="text-center text-gray-500 text-sm">面板内容区域 - {{ panel.id }}</div>
</div>
</template>
</Panel>
<DockLayout ref="dockLayoutRef" />
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import Panel from '../DockLayout/Panel.js';
import DockLayout from '../DockLayout/DockLayout.vue';
// 顶部控制栏按钮的引用
const layoutFileInput = ref(null);
const panelHost = ref(null);
const dockLayoutRef = ref(null);
// 浮动面板列表
const floatingPanels = ref([]);
@@ -85,24 +69,13 @@ function addPanel(position) {
function addFloatingPanel() {
console.log('[DockLayoutTest] addFloatingPanel called');
// 复原截图样式的默认面板参数
const defaultSize = { width: 300, height: 180 };
const offset = 16;
const idx = nextPanelIdx.value++;
const panel = {
id: 'float-' + idx,
title: '输出',
x: offset * idx,
y: offset * idx,
width: defaultSize.width,
height: defaultSize.height,
collapsed: false,
toolbarExpanded: false,
maximized: false,
};
console.log('[DockLayoutTest] Adding panel:', panel);
floatingPanels.value.push(panel);
console.log('[DockLayoutTest] Panels after add:', floatingPanels.value.length);
// 向DockLayout组件发送添加浮动区命令
if (dockLayoutRef.value && dockLayoutRef.value.addFloatingArea) {
console.log('[DockLayoutTest] 调用DockLayout的addFloatingArea方法');
dockLayoutRef.value.addFloatingArea();
} else {
console.warn('[DockLayoutTest] DockLayout引用未初始化或addFloatingArea方法不可用');
}
}
function closePanel(id) {