diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue new file mode 100644 index 0000000..8b5814c --- /dev/null +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue @@ -0,0 +1,145 @@ + + + + + \ No newline at end of file diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js deleted file mode 100644 index afc1af9..0000000 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js +++ /dev/null @@ -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: ` -
-
- -
-
- {{ panel.title }} -
-
- - - - - - - - -
-
- - -
-
- 工具栏 - -
- -
- - -
- -
-
-
- `, - // 样式应该放在模板外部,作为组件的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); } - ` -}); diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue new file mode 100644 index 0000000..0be7e66 --- /dev/null +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue @@ -0,0 +1,140 @@ + + + + + \ No newline at end of file