feat: 为rdp和vnc模态框添加最小化按钮
This commit is contained in:
@@ -31,6 +31,13 @@ const mouse = ref<any | null>(null);
|
||||
const desiredModalWidth = ref(1064);
|
||||
const desiredModalHeight = ref(858);
|
||||
const isKeyboardDisabledForInput = ref(false); // 标记键盘是否因输入框聚焦而禁用
|
||||
const isMinimized = ref(false);
|
||||
const restoreButtonRef = ref<HTMLButtonElement | null>(null);
|
||||
const isDraggingRestoreButton = ref(false);
|
||||
const restoreButtonPosition = ref({ x: 16, y: window.innerHeight / 2 - 25 }); // 16px from left, vertically centered
|
||||
let dragOffsetX = 0;
|
||||
let dragOffsetY = 0;
|
||||
let hasDragged = false; // 新增 hasDragged 标志
|
||||
|
||||
const MIN_MODAL_WIDTH = 1024;
|
||||
const MIN_MODAL_HEIGHT = 768;
|
||||
@@ -338,6 +345,55 @@ const enableRdpKeyboard = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const minimizeModal = () => {
|
||||
isMinimized.value = true;
|
||||
};
|
||||
|
||||
const restoreModal = () => {
|
||||
isMinimized.value = false;
|
||||
};
|
||||
|
||||
const onRestoreButtonMouseDown = (event: MouseEvent) => {
|
||||
if (!restoreButtonRef.value) return;
|
||||
hasDragged = false; // 重置拖拽标志
|
||||
isDraggingRestoreButton.value = true;
|
||||
dragOffsetX = event.clientX - restoreButtonRef.value.getBoundingClientRect().left;
|
||||
dragOffsetY = event.clientY - restoreButtonRef.value.getBoundingClientRect().top;
|
||||
event.preventDefault();
|
||||
document.addEventListener('mousemove', onRestoreButtonMouseMove);
|
||||
document.addEventListener('mouseup', onRestoreButtonMouseUp);
|
||||
};
|
||||
|
||||
const onRestoreButtonMouseMove = (event: MouseEvent) => {
|
||||
if (!isDraggingRestoreButton.value) return;
|
||||
hasDragged = true; // 如果鼠标移动则设置拖拽标志
|
||||
let newX = event.clientX - dragOffsetX;
|
||||
let newY = event.clientY - dragOffsetY;
|
||||
|
||||
const buttonWidth = 50;
|
||||
const buttonHeight = 50;
|
||||
newX = Math.max(0, Math.min(newX, window.innerWidth - buttonWidth));
|
||||
newY = Math.max(0, Math.min(newY, window.innerHeight - buttonHeight));
|
||||
|
||||
restoreButtonPosition.value = { x: newX, y: newY };
|
||||
};
|
||||
|
||||
const onRestoreButtonMouseUp = () => {
|
||||
isDraggingRestoreButton.value = false;
|
||||
document.removeEventListener('mousemove', onRestoreButtonMouseMove);
|
||||
document.removeEventListener('mouseup', onRestoreButtonMouseUp);
|
||||
// click 事件会在 mouseup 后触发。如果我们拖拽了,我们不希望 click 事件恢复模态框。
|
||||
// handleClickRestoreButton 会检查 hasDragged。
|
||||
};
|
||||
|
||||
const handleClickRestoreButton = () => {
|
||||
if (!hasDragged) {
|
||||
restoreModal();
|
||||
}
|
||||
// 为下一次交互重置
|
||||
hasDragged = false;
|
||||
};
|
||||
|
||||
const disconnectGuacamole = () => {
|
||||
removeInputListeners();
|
||||
isKeyboardDisabledForInput.value = false; // 确保状态重置
|
||||
@@ -444,6 +500,8 @@ onMounted(() => {
|
||||
|
||||
onUnmounted(() => {
|
||||
disconnectGuacamole(); // 这里已经调用了 removeInputListeners
|
||||
document.removeEventListener('mousemove', onRestoreButtonMouseMove);
|
||||
document.removeEventListener('mouseup', onRestoreButtonMouseUp);
|
||||
});
|
||||
|
||||
watch(() => props.connection, (newConnection, oldConnection) => {
|
||||
@@ -473,17 +531,35 @@ const computedModalStyle = computed(() => {
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-overlay p-4">
|
||||
<div
|
||||
:style="computedModalStyle"
|
||||
class="bg-background text-foreground rounded-lg shadow-xl flex flex-col overflow-hidden border border-border"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'fixed inset-0 z-50 flex items-center justify-center p-4',
|
||||
isMinimized ? '' : 'bg-overlay',
|
||||
isMinimized ? 'pointer-events-none' : '' // 允许恢复按钮接收事件
|
||||
]"
|
||||
>
|
||||
<button
|
||||
ref="restoreButtonRef"
|
||||
v-if="isMinimized"
|
||||
@mousedown="onRestoreButtonMouseDown"
|
||||
@click="handleClickRestoreButton"
|
||||
:style="{ left: `${restoreButtonPosition.x}px`, top: `${restoreButtonPosition.y}px`, width: '50px', height: '50px' }"
|
||||
class="fixed z-[100] flex items-center justify-center bg-primary text-white rounded-full shadow-lg hover:bg-primary-dark focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50 pointer-events-auto cursor-grab active:cursor-grabbing"
|
||||
:title="t('common.restore')"
|
||||
>
|
||||
<i class="fas fa-window-restore fa-lg"></i>
|
||||
</button>
|
||||
<div
|
||||
v-show="!isMinimized"
|
||||
:style="computedModalStyle"
|
||||
class="bg-background text-foreground rounded-lg shadow-xl flex flex-col overflow-hidden border border-border pointer-events-auto"
|
||||
>
|
||||
<div class="flex items-center justify-between p-3 border-b border-border flex-shrink-0">
|
||||
<h3 class="text-base font-semibold truncate">
|
||||
<i class="fas fa-desktop mr-2 text-text-secondary"></i>
|
||||
{{ t('remoteDesktopModal.title') }} - {{ props.connection?.name || props.connection?.host || t('remoteDesktopModal.titlePlaceholder') }}
|
||||
</h3>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="flex items-center space-x-1">
|
||||
<span class="text-xs px-2 py-0.5 rounded"
|
||||
:class="{
|
||||
'bg-yellow-200 text-yellow-800': connectionStatus === 'connecting',
|
||||
@@ -493,6 +569,13 @@ const computedModalStyle = computed(() => {
|
||||
}">
|
||||
{{ t('remoteDesktopModal.status.' + connectionStatus) }}
|
||||
</span>
|
||||
<button
|
||||
@click="minimizeModal"
|
||||
class="text-text-secondary hover:text-foreground transition-colors duration-150 p-1 rounded hover:bg-hover"
|
||||
:title="t('common.minimize')"
|
||||
>
|
||||
<i class="fas fa-window-minimize fa-sm"></i>
|
||||
</button>
|
||||
<button
|
||||
@click="closeModal"
|
||||
class="text-text-secondary hover:text-foreground transition-colors duration-150 p-1 rounded hover:bg-hover"
|
||||
|
||||
Reference in New Issue
Block a user