Files
JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue

179 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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 cursor-move"
@mousedown="onDragStart"
@mousemove="onDragMove"
@mouseup="onDragEnd"
@mouseleave="onDragEnd">
<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', 'dragStart', 'dragMove', 'dragEnd']);
// 事件处理函数
const onToggleCollapse = () => {
emit('toggleCollapse', props.id);
};
const onMaximize = () => {
emit('maximize', props.id);
};
const onClose = () => {
emit('close', props.id);
};
const onToggleToolbar = () => {
emit('toggleToolbar', props.id);
};
// 拖拽相关状态
let isDragging = false;
// 拖拽开始
const onDragStart = (e) => {
// 只有当点击的是标题栏区域(不是按钮)时才触发拖拽
if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) {
isDragging = true;
emit('dragStart', {
clientX: e.clientX,
clientY: e.clientY
});
// 防止文本选择
e.preventDefault();
}
};
// 拖拽移动
const onDragMove = (e) => {
if (isDragging) {
emit('dragMove', {
clientX: e.clientX,
clientY: e.clientY
});
}
};
// 拖拽结束
const onDragEnd = () => {
if (isDragging) {
isDragging = false;
emit('dragEnd');
}
};
</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>