From 7059ebcc0e5403255d6f19e7036bd37375ac9c46 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Tue, 16 Sep 2025 19:40:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=99=A8=E6=BB=9A=E5=8A=A8=E5=8A=9F=E8=83=BD=E5=92=8C?= =?UTF-8?q?=E8=BD=AF=E9=93=BE=E6=8E=A5=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要改进: - 重新设计布局结构,确保状态栏始终可见 - 添加软链接图标和目标路径显示支持 - 修复滚动条功能,使用绝对定位的滚动容器 - 优化文件名编辑框的自适应宽度和居中显示 - 完善软链接点击处理逻辑 布局优化: - 外层容器:h-full flex flex-col overflow-hidden - 滚动区域:flex-1 relative overflow-hidden 包含 absolute inset-0 overflow-y-auto - 状态栏:flex-shrink-0 确保始终可见 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../Apps/File Manager/FileManagerGrid.tsx | 112 +++++++++++------- .../Apps/File Manager/FileManagerModern.tsx | 91 +++++++++++++- 2 files changed, 157 insertions(+), 46 deletions(-) diff --git a/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx b/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx index 9e72d17e..4b00ee33 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManagerGrid.tsx @@ -15,7 +15,8 @@ import { ChevronRight, MoreHorizontal, RefreshCw, - ArrowUp + ArrowUp, + FileSymlink } from "lucide-react"; import { useTranslation } from "react-i18next"; import type { FileItem } from "../../../types/index.js"; @@ -64,14 +65,18 @@ interface FileManagerGridProps { onCancelEdit?: () => void; } -const getFileIcon = (fileName: string, isDirectory: boolean, viewMode: 'grid' | 'list' = 'grid') => { +const getFileIcon = (file: FileItem, viewMode: 'grid' | 'list' = 'grid') => { const iconClass = viewMode === 'grid' ? "w-8 h-8" : "w-6 h-6"; - if (isDirectory) { + if (file.type === 'directory') { return ; } - const ext = fileName.split('.').pop()?.toLowerCase(); + if (file.type === 'link') { + return ; + } + + const ext = file.name.split('.').pop()?.toLowerCase(); switch (ext) { case 'txt': @@ -273,6 +278,12 @@ export function FileManagerGrid({ e.stopPropagation(); }, []); + // 滚轮事件处理,确保滚动正常工作 + const handleWheel = useCallback((e: React.WheelEvent) => { + // 不阻止默认滚动行为,让浏览器自己处理滚动 + e.stopPropagation(); + }, []); + const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -394,7 +405,7 @@ export function FileManagerGrid({ } return ( -
+
{/* 工具栏和路径导航 */}
{/* 导航按钮 */} @@ -463,42 +474,44 @@ export function FileManagerGrid({
- {/* 主文件网格 */} -
onContextMenu?.(e)} - tabIndex={0} - > - {isDragging && ( -
-
- -

- {t("fileManager.dragFilesToUpload")} -

+ {/* 主文件网格 - 滚动区域 */} +
+
onContextMenu?.(e)} + tabIndex={0} + > + {isDragging && ( +
+
+ +

+ {t("fileManager.dragFilesToUpload")} +

+
-
- )} + )} - {files.length === 0 ? ( -
-
- -

{t("fileManager.emptyFolder")}

+ {files.length === 0 ? ( +
+
+ +

{t("fileManager.emptyFolder")}

+
-
- ) : viewMode === 'grid' ? ( -
- {files.map((file) => { + ) : viewMode === 'grid' ? ( +
+ {files.map((file) => { const isSelected = selectedFiles.some(f => f.path === file.path); // 详细调试路径比较 @@ -531,11 +544,11 @@ export function FileManagerGrid({
{/* 文件图标 */}
- {getFileIcon(file.name, file.type === 'directory', viewMode)} + {getFileIcon(file, viewMode)}
{/* 文件名 */} -
+
{editingFile?.path === file.path ? ( ) : (

{ // 阻止文件选择事件 @@ -571,6 +584,11 @@ export function FileManagerGrid({ {formatFileSize(file.size)}

)} + {file.type === 'link' && file.linkTarget && ( +

+ → {file.linkTarget} +

+ )}
@@ -600,7 +618,7 @@ export function FileManagerGrid({ > {/* 文件图标 */}
- {getFileIcon(file.name, file.type === 'directory', viewMode)} + {getFileIcon(file, viewMode)}
{/* 文件信息 */} @@ -622,7 +640,7 @@ export function FileManagerGrid({ /> ) : (

{ // 阻止文件选择事件 @@ -635,6 +653,11 @@ export function FileManagerGrid({ {file.name}

)} + {file.type === 'link' && file.linkTarget && ( +

+ → {file.linkTarget} +

+ )} {file.modified && (

{file.modified} @@ -664,6 +687,7 @@ export function FileManagerGrid({ })}

)} +
{/* 状态栏 */} diff --git a/src/ui/Desktop/Apps/File Manager/FileManagerModern.tsx b/src/ui/Desktop/Apps/File Manager/FileManagerModern.tsx index 8169aad0..3ec6e2ec 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManagerModern.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManagerModern.tsx @@ -30,7 +30,8 @@ import { deleteSSHItem, renameSSHItem, connectSSH, - getSSHStatus + getSSHStatus, + identifySSHSymlink } from "@/ui/main-axios.ts"; @@ -345,9 +346,95 @@ function FileManagerContent({ initialHost, onClose }: FileManagerModernProps) { setIsCreatingNewFile(true); } - function handleFileOpen(file: FileItem) { + // Handle symlink resolution + const handleSymlinkClick = async (file: FileItem) => { + if (!currentHost || !sshSessionId) { + toast.error(t("fileManager.noSSHConnection")); + return; + } + + try { + // 确保SSH连接有效 + let currentSessionId = sshSessionId; + try { + const status = await getSSHStatus(currentSessionId); + if (!status.connected) { + const result = await connectSSH(currentSessionId, { + hostId: currentHost.id, + host: currentHost.ip, + port: currentHost.port, + username: currentHost.username, + authType: currentHost.authType, + password: currentHost.password, + key: currentHost.key, + keyPassword: currentHost.keyPassword, + credentialId: currentHost.credentialId + }); + + if (!result.success) { + throw new Error(t("fileManager.failedToReconnectSSH")); + } + } + } catch (sessionErr) { + throw sessionErr; + } + + const symlinkInfo = await identifySSHSymlink(currentSessionId, file.path); + + if (symlinkInfo.type === "directory") { + // 如果软链接指向目录,导航到它 + setCurrentPath(symlinkInfo.target); + } else if (symlinkInfo.type === "file") { + // 如果软链接指向文件,打开文件 + // 计算窗口位置(稍微错开) + const windowCount = Date.now() % 10; + const offsetX = 120 + (windowCount * 30); + const offsetY = 120 + (windowCount * 30); + + // 创建目标文件对象 + const targetFile: FileItem = { + ...file, + path: symlinkInfo.target + }; + + // 创建窗口组件工厂函数 + const createWindowComponent = (windowId: string) => ( + + ); + + openWindow({ + title: file.name, + x: offsetX, + y: offsetY, + width: 800, + height: 600, + isMaximized: false, + isMinimized: false, + component: createWindowComponent + }); + } + } catch (error: any) { + toast.error( + error?.response?.data?.error || + error?.message || + t("fileManager.failedToResolveSymlink") + ); + } + }; + + async function handleFileOpen(file: FileItem) { if (file.type === 'directory') { setCurrentPath(file.path); + } else if (file.type === 'link') { + // 处理软链接 + await handleSymlinkClick(file); } else { // 在新窗口中打开文件 if (!sshSessionId) {