style: 优化设置界面布局,添加导航栏

This commit is contained in:
Baobhan Sith
2025-05-13 08:32:55 +08:00
parent ed415a5bd2
commit 83e3d8e043
5 changed files with 197 additions and 50 deletions
+99 -8
View File
@@ -1,31 +1,31 @@
<script setup lang="ts">
import { onMounted, onBeforeUnmount, computed, ref } from 'vue';
import { onMounted, onBeforeUnmount, computed, ref, shallowRef, type PropType } from 'vue';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { useBreakpoints, breakpointsTailwind } from '@vueuse/core'; // +++ 引入 useBreakpoints +++
import { useBreakpoints, breakpointsTailwind } from '@vueuse/core';
import { useLayoutStore } from '../stores/layout.store';
import { useConnectionsStore, type ConnectionInfo } from '../stores/connections.store';
import AddConnectionFormComponent from '../components/AddConnectionForm.vue';
import TerminalTabBar from '../components/TerminalTabBar.vue';
import LayoutRenderer from '../components/LayoutRenderer.vue';
import LayoutConfigurator from '../components/LayoutConfigurator.vue';
import RemoteDesktopModal from '../components/RemoteDesktopModal.vue';
import VncModal from '../components/VncModal.vue'; // +++ 引入 VncModal 组件 +++
import Terminal from '../components/Terminal.vue'; // +++ 引入 Terminal 组件 +++
import CommandInputBar from '../components/CommandInputBar.vue'; // +++ 引入 CommandInputBar 组件 +++
import VirtualKeyboard from '../components/VirtualKeyboard.vue'; // +++ 引入 VirtualKeyboard 组件 +++
import Terminal from '../components/Terminal.vue';
import CommandInputBar from '../components/CommandInputBar.vue';
import VirtualKeyboard from '../components/VirtualKeyboard.vue';
import FileManager from '../components/FileManager.vue';
import { useSessionStore } from '../stores/session.store';
import type { SessionTabInfoWithStatus, SshTerminalInstance } from '../stores/session/types';
import { useSettingsStore } from '../stores/settings.store';
import { useFileEditorStore, type FileTab } from '../stores/fileEditor.store';
import { useCommandHistoryStore } from '../stores/commandHistory.store';
import type { Terminal as XtermTerminal } from 'xterm';
import type { Terminal as XtermTerminal } from 'xterm';
import type { ISearchOptions } from '@xterm/addon-search';
import {
useWorkspaceEventSubscriber,
useWorkspaceEventOff,
type WorkspaceEventPayloads
} from '../composables/workspaceEvents';
import type { WebSocketDependencies } from '../composables/useSftpActions';
// --- Setup ---
const { t } = useI18n();
@@ -75,6 +75,15 @@ const currentSearchTerm = ref(''); // 当前搜索的关键词
const mobileTerminalRef = ref<InstanceType<typeof Terminal> | null>(null);
const isVirtualKeyboardVisible = ref(true); // +++ State for virtual keyboard visibility +++
// --- 文件管理器模态框状态 ---
const showFileManagerModal = ref(false);
const fileManagerProps = shallowRef<null | {
sessionId: string;
instanceId: string;
dbConnectionId: string;
wsDeps: WebSocketDependencies;
}>(null);
// --- 处理全局键盘事件 ---
const handleGlobalKeyDown = (event: KeyboardEvent) => {
// 检查是否按下了 Alt 键以及上/下箭头键
@@ -154,6 +163,7 @@ onMounted(() => {
subscribeToWorkspaceEvents('session:closeToRight', (payload) => handleCloseSessionsToRight(payload.targetSessionId));
subscribeToWorkspaceEvents('session:closeToLeft', (payload) => handleCloseSessionsToLeft(payload.targetSessionId));
subscribeToWorkspaceEvents('ui:openLayoutConfigurator', handleOpenLayoutConfigurator);
subscribeToWorkspaceEvents('fileManager:openModalRequest', handleFileManagerOpenRequest); // +++ 订阅文件管理器打开请求 +++
});
onBeforeUnmount(() => {
@@ -196,6 +206,7 @@ onBeforeUnmount(() => {
unsubscribeFromWorkspaceEvents('session:closeToRight', (payload) => handleCloseSessionsToRight(payload.targetSessionId));
unsubscribeFromWorkspaceEvents('session:closeToLeft', (payload) => handleCloseSessionsToLeft(payload.targetSessionId));
unsubscribeFromWorkspaceEvents('ui:openLayoutConfigurator', handleOpenLayoutConfigurator);
unsubscribeFromWorkspaceEvents('fileManager:openModalRequest', handleFileManagerOpenRequest); // +++ 取消订阅文件管理器打开请求 +++
});
const subscribeToWorkspaceEvents = useWorkspaceEventSubscriber(); // +++ 定义订阅和取消订阅函数 +++
@@ -634,6 +645,64 @@ const toggleVirtualKeyboard = () => {
tabsToClose.forEach(id => handleCloseEditorTab(id));
};
// --- 文件管理器模态框处理 ---
const handleFileManagerOpenRequest = (payload: { sessionId: string }) => {
const { sessionId } = payload;
const session = sessionStore.sessions.get(sessionId);
if (!session) {
console.error(`[WorkspaceView] Cannot open file manager: Session ${sessionId} not found.`);
// TODO: Show error notification
return;
}
// 1. 获取 dbConnectionId
const dbConnectionId = session.connectionId;
if (!dbConnectionId) {
console.error(`[WorkspaceView] Cannot open file manager: Missing dbConnectionId for session ${sessionId}.`);
// TODO: Show error notification
return;
}
// 2. 获取 wsDeps (从 session.wsManager 获取)
if (!session.wsManager) {
console.error(`[WorkspaceView] Cannot open file manager: wsManager not found for session ${sessionId}.`);
// TODO: Show error notification
return;
}
const wsDeps: WebSocketDependencies = {
sendMessage: session.wsManager.sendMessage,
onMessage: session.wsManager.onMessage,
isConnected: session.wsManager.isConnected,
isSftpReady: session.wsManager.isSftpReady,
};
console.log(`[WorkspaceView] Retrieved wsDeps from session.wsManager for session ${sessionId}.`);
if (!wsDeps) {
// 如果 wsDeps 仍然为 null,则无法继续
console.error(`[WorkspaceView] Cannot open file manager: wsDeps are null after attempting retrieval for session ${sessionId}.`);
return;
}
// 3. 生成 instanceId
const instanceId = `fm-modal-${sessionId}-${Date.now()}`;
// 4. 设置 props 并显示模态框
fileManagerProps.value = {
sessionId,
instanceId,
dbConnectionId: String(dbConnectionId), // 确保是 string
wsDeps,
};
showFileManagerModal.value = true;
console.log(`[WorkspaceView] Opening FileManager modal with props:`, fileManagerProps.value);
};
const closeFileManagerModal = () => {
showFileManagerModal.value = false;
fileManagerProps.value = null; // 清理 props
console.log('[WorkspaceView] FileManager modal closed.');
};
</script>
<template>
@@ -726,6 +795,28 @@ const toggleVirtualKeyboard = () => {
<!-- RDP Modal is now rendered in App.vue -->
<!-- VNC Modal is now rendered in App.vue -->
<!-- FileManager Modal -->
<div v-if="showFileManagerModal && fileManagerProps" class="fixed inset-0 bg-black bg-opacity-60 flex items-center justify-center z-50 p-4">
<div class="bg-background rounded-lg shadow-xl w-full max-w-4xl h-[85vh] flex flex-col overflow-hidden border border-border">
<div class="flex justify-between items-center p-3 border-b border-border flex-shrink-0 bg-header">
<h2 class="text-lg font-semibold text-foreground">{{ t('fileManager.modalTitle', '文件管理器') }} ({{ fileManagerProps.sessionId }})</h2>
<button @click="closeFileManagerModal" class="text-text-secondary hover:text-foreground transition-colors">
<i class="fas fa-times text-xl"></i>
</button>
</div>
<div class="flex-grow overflow-hidden">
<FileManager
:session-id="fileManagerProps.sessionId"
:instance-id="fileManagerProps.instanceId"
:db-connection-id="fileManagerProps.dbConnectionId"
:ws-deps="fileManagerProps.wsDeps"
class="h-full"
/>
</div>
</div>
</div>
</div>
</template>