重写ssh前端组件,通用化
This commit is contained in:
parent
03f2146546
commit
16b8db336f
133
frontend/src/components/FileManager/FileManagerWindowManager.tsx
Normal file
133
frontend/src/components/FileManager/FileManagerWindowManager.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* 文件管理器窗口管理器
|
||||||
|
* 独立管理文件管理器窗口的打开、最小化等状态
|
||||||
|
*/
|
||||||
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
|
import { FolderOpen } from 'lucide-react';
|
||||||
|
import { FileManager } from './FileManager';
|
||||||
|
|
||||||
|
export interface FileManagerWindow {
|
||||||
|
id: string;
|
||||||
|
serverId: number;
|
||||||
|
serverName: string;
|
||||||
|
isMinimized: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FileManagerWindowManager: React.FC = () => {
|
||||||
|
const [windows, setWindows] = useState<FileManagerWindow[]>([]);
|
||||||
|
const [activeWindowId, setActiveWindowId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// 打开文件管理器窗口
|
||||||
|
const openWindow = useCallback((serverId: number, serverName: string) => {
|
||||||
|
const windowId = `file-manager-${serverId}-${Date.now()}`;
|
||||||
|
|
||||||
|
// 检查是否已存在该服务器的窗口
|
||||||
|
const existingWindow = windows.find(w => w.serverId === serverId && !w.isMinimized);
|
||||||
|
if (existingWindow) {
|
||||||
|
// 如果已存在且未最小化,聚焦它
|
||||||
|
setActiveWindowId(existingWindow.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newWindow: FileManagerWindow = {
|
||||||
|
id: windowId,
|
||||||
|
serverId,
|
||||||
|
serverName,
|
||||||
|
isMinimized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
setWindows(prev => [...prev, newWindow]);
|
||||||
|
setActiveWindowId(windowId);
|
||||||
|
|
||||||
|
console.log(`✅ 打开文件管理器: ${serverName} (${windowId})`);
|
||||||
|
}, [windows]);
|
||||||
|
|
||||||
|
// 关闭窗口
|
||||||
|
const closeWindow = useCallback((windowId: string) => {
|
||||||
|
setWindows(prev => prev.filter(w => w.id !== windowId));
|
||||||
|
if (activeWindowId === windowId) {
|
||||||
|
setActiveWindowId(null);
|
||||||
|
}
|
||||||
|
console.log(`❌ 关闭文件管理器: ${windowId}`);
|
||||||
|
}, [activeWindowId]);
|
||||||
|
|
||||||
|
// 最小化窗口
|
||||||
|
const minimizeWindow = useCallback((windowId: string) => {
|
||||||
|
setWindows(prev => prev.map(w =>
|
||||||
|
w.id === windowId ? { ...w, isMinimized: true } : w
|
||||||
|
));
|
||||||
|
if (activeWindowId === windowId) {
|
||||||
|
setActiveWindowId(null);
|
||||||
|
}
|
||||||
|
console.log(`➖ 最小化文件管理器: ${windowId}`);
|
||||||
|
}, [activeWindowId]);
|
||||||
|
|
||||||
|
// 恢复窗口
|
||||||
|
const restoreWindow = useCallback((windowId: string) => {
|
||||||
|
setWindows(prev => prev.map(w =>
|
||||||
|
w.id === windowId ? { ...w, isMinimized: false } : w
|
||||||
|
));
|
||||||
|
setActiveWindowId(windowId);
|
||||||
|
console.log(`➕ 恢复文件管理器: ${windowId}`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 聚焦窗口
|
||||||
|
const focusWindow = useCallback((windowId: string) => {
|
||||||
|
setActiveWindowId(windowId);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 注册全局打开方法
|
||||||
|
useEffect(() => {
|
||||||
|
const globalKey = 'openFileManager';
|
||||||
|
(window as any)[globalKey] = openWindow;
|
||||||
|
console.log('📁 文件管理器窗口管理器已就绪');
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
delete (window as any)[globalKey];
|
||||||
|
};
|
||||||
|
}, [openWindow]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* 渲染所有文件管理器窗口 */}
|
||||||
|
{windows.map(win => !win.isMinimized && (
|
||||||
|
<FileManager
|
||||||
|
key={win.id}
|
||||||
|
serverId={win.serverId}
|
||||||
|
serverName={win.serverName}
|
||||||
|
open={true}
|
||||||
|
onClose={() => closeWindow(win.id)}
|
||||||
|
onMinimize={() => minimizeWindow(win.id)}
|
||||||
|
isActive={activeWindowId === win.id}
|
||||||
|
onFocus={() => focusWindow(win.id)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* 最小化的窗口悬浮按钮 */}
|
||||||
|
{windows.filter(w => w.isMinimized).length > 0 && (
|
||||||
|
<div className="fixed bottom-4 left-4 flex flex-col-reverse gap-2 z-[1001]">
|
||||||
|
{windows
|
||||||
|
.filter(w => w.isMinimized)
|
||||||
|
.map((win) => (
|
||||||
|
<button
|
||||||
|
key={win.id}
|
||||||
|
className="flex items-center gap-3 px-4 py-3 bg-blue-600 text-white rounded-lg shadow-lg transition-all hover:scale-105 hover:shadow-xl"
|
||||||
|
onClick={() => restoreWindow(win.id)}
|
||||||
|
title={`恢复: ${win.serverName}`}
|
||||||
|
>
|
||||||
|
<FolderOpen className="h-5 w-5" />
|
||||||
|
<div className="text-left">
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{win.serverName}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs opacity-90">
|
||||||
|
文件管理
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user