高效服务器文件管理工具网页版

背景与需求

我最近使用了一个免费的VPS虚拟主机搭建测试网站,但发现其文件传输功能存在诸多限制:上传和下载均有严格的大小限制,自带的FTP网页工具体验不佳,下载的压缩文件经常损坏。特别是当需要处理大型网站项目(如700MB+的备份文件)时,这些限制使得文件传输几乎无法进行。

为此,我开发了一个专门的文件管理工具,主要解决了以下痛点:

  • 自动分块处理大文件上传(默认10MB分块,可配置)
  • 支持大文件稳定下载,避免中断问题
  • 无需手动拆分压缩包,直接处理完整大文件

核心功能详解

1. 智能文件浏览与导航

  • 可视化浏览服务器文件系统,支持无缝目录导航
  • 面包屑导航设计,支持快速层级跳转
  • 使用直观的emoji图标区分文件与文件夹类型
  • 文件夹优先排序,便于快速定位
  • 实时显示文件大小等详细信息

2. 先进的大文件上传机制

  • 普通上传:支持多文件同时传输
  • 智能分块上传:自动识别超过15MB的文件并进行分块处理
  • 可配置分块大小(默认10MB,根据服务器限制调整)
  • 实时上传进度显示
  • 内置断点续传功能,应对网络不稳定情况
  • 智能重命名:自动为重名文件添加时间戳避免覆盖

3. 远程文件下载功能

  • 支持从外部URL直接下载文件到服务器
  • 专用存储目录(yuanchengdownload)管理下载文件
  • 完整的URL格式验证机制
  • 5分钟下载超时保护
  • 自动处理文件名冲突
  • HTTP状态码检查确保下载完整性

4. 多功能文件编辑器

  • 支持多种文本格式:txt, html, css, js, php, py等20+格式
  • 全屏编辑模式,占用95%屏幕空间
  • 专业编辑器特性:等宽字体、Tab键支持(插入4空格)
  • 快捷键操作(Ctrl+S保存)
  • 自动备份功能防止数据丢失
  • 安全限制:5MB文件大小限制,仅处理UTF-8/ASCII文本

5. 压缩与解压解决方案

  • 智能压缩:支持文件与目录的ZIP格式压缩
  • 压缩文件存储在源文件同级目录
  • 自动时间戳命名避免覆盖
  • 安全解压:支持ZIP格式完整解压
  • 递归解压保持目录结构
  • 路径安全验证防止遍历攻击
  • 详细解压日志记录
  • 自动处理重名文件冲突

6. 可视化文件移动功能

  • 图形化目录树选择目标位置
  • 安全检查防止递归移动(文件夹到自身子目录)
  • 智能重命名处理目标位置同名文件
  • 实时操作验证确保移动有效性

7. 稳定可靠的文件下载

  • 单文件直接下载
  • 大文件分块下载(256KB分块)
  • 优化传输:移除执行时间限制,禁用输出缓冲
  • 支持断点续传
  • 实时连接中断检测与恢复

8. 基本文件管理操作

  • 新建文件夹与空白文件
  • 安全删除功能(支持递归删除目录)
  • 文件名合法性验证防止系统冲突

9. 智能右键上下文菜单

  • 根据文件类型动态显示可用操作
  • 直观的emoji图标标识功能:
    • 📦 压缩功能
    • 🗂️ 解压(ZIP文件)
    • 📝 编辑(支持格式)
    • ✂️ 移动/剪切
    • 🗑️ 删除

技术优势

此工具专门针对有限制的VPS环境优化,解决了免费主机服务常见的文件传输痛点。通过分块传输、断点续传和智能重命名机制,确保了大规模文件传输的可靠性和稳定性,极大提高了网站管理和备份的效率。

无论是大型网站迁移、定期备份还是日常文件管理,这个工具都能提供稳定高效的支持,彻底解决了免费VPS文件传输的种种限制问题。

图片[1]-高效服务器文件管理工具网页版-九零社区

使用方法

只有一个php页面就上传到网站根目录直接访问这个php页面就可以,
使用方法,把下面的代码复制到一个txt文件中,然后重命名为file-manager.php或者其他名字,直接访问就可以,例如https://www.90ii.cn/file-manager.php,放在网站根目录就可以。

文件代码

<?php
// 错误报告设置
error_reporting(E_ALL);
ini_set('display_errors', 1);
 
// 脚本最大执行时间(0为不限时)
set_time_limit(0);
ignore_user_abort(true);
 
// 针对免费服务器优化:禁用输出缓冲
ini_set('output_buffering', 0);
 
// 自动获取绝对路径
$absolutePath = realpath(__DIR__);
$basePath = $absolutePath;
 
// 处理AJAX请求
if (isset($_POST['action'])) {
     // 设置错误处理,确保返回JSON格式
    set_error_handler(function($errno, $errstr, $errfile, $errline) {
        die(json_encode(['error' => "PHP Error: $errstr in $errfile on line $errline"]));
    });
     
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }
     
    if ($_POST['action'] == 'list_dir') {
        // 列出目录内容
        $dir = isset($_POST['dir']) ? $_POST['dir'] : $basePath;
        $dir = realpath($dir);
         
        // 安全检查:确保请求的目录在允许的根目录之下
        if (strpos($dir, $basePath) !== 0) {
            die(json_encode(['error' => '访问被拒绝:目录不在允许范围内']));
        }
         
        $files = scandir($dir);
        $result = [];
         
        foreach ($files as $file) {
            if ($file == '.' || $file == '..') continue;
             
            $fullPath = $dir . DIRECTORY_SEPARATOR . $file;
            $isDir = is_dir($fullPath);
             
            $result[] = [
                'name' => $file,
                'path' => $fullPath,
                'is_dir' => $isDir,
                'size' => $isDir ? null : filesize($fullPath)
            ];
        }
         
        // 按文件夹优先排序
        usort($result, function($a, $b) {
            if ($a['is_dir'] && !$b['is_dir']) return -1;
            if (!$a['is_dir'] && $b['is_dir']) return 1;
            return strcmp($a['name'], $b['name']);
        });
         
        echo json_encode([
            'current_dir' => $dir,
            'files' => $result
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'upload_file') {
        // 文件上传处理
        $uploadDir = isset($_POST['upload_dir']) ? $_POST['upload_dir'] : $basePath;
        $uploadDir = realpath($uploadDir);
         
        // 安全检查
        if (!$uploadDir || strpos($uploadDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的上传目录']));
        }
         
        if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
            die(json_encode(['error' => '文件上传失败']));
        }
         
        $file = $_FILES['file'];
        $fileName = basename($file['name']);
        $targetPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
         
        // 检查文件是否已存在
        if (file_exists($targetPath)) {
            $fileName = pathinfo($fileName, PATHINFO_FILENAME) . '_' . date('Y-m-d_H-i-s') . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
            $targetPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
        }
         
        if (move_uploaded_file($file['tmp_name'], $targetPath)) {
            echo json_encode([
                'success' => true,
                'message' => "文件上传成功:$fileName",
                'filename' => $fileName
            ]);
        } else {
            echo json_encode(['error' => '文件保存失败']);
        }
        exit;
    }
    elseif ($_POST['action'] == 'chunk_upload') {
        // 分块上传处理
        $uploadDir = isset($_POST['upload_dir']) ? $_POST['upload_dir'] : $basePath;
        $uploadDir = realpath($uploadDir);
         
        // 安全检查
        if (!$uploadDir || strpos($uploadDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的上传目录']));
        }
         
        $fileName = isset($_POST['fileName']) ? basename($_POST['fileName']) : '';
        $chunkIndex = isset($_POST['chunkIndex']) ? intval($_POST['chunkIndex']) : 0;
        $totalChunks = isset($_POST['totalChunks']) ? intval($_POST['totalChunks']) : 1;
        $fileId = isset($_POST['fileId']) ? $_POST['fileId'] : '';
         
        if (empty($fileName) || empty($fileId)) {
            die(json_encode(['error' => '缺少必要参数']));
        }
         
        if (!isset($_FILES['chunk']) || $_FILES['chunk']['error'] !== UPLOAD_ERR_OK) {
            die(json_encode(['error' => '分块上传失败']));
        }
         
        // 创建临时目录
        $tempDir = $uploadDir . DIRECTORY_SEPARATOR . 'temp_uploads';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0755, true);
        }
         
        // 保存分块文件
        $chunkPath = $tempDir . DIRECTORY_SEPARATOR . $fileId . '_' . $chunkIndex;
        if (!move_uploaded_file($_FILES['chunk']['tmp_name'], $chunkPath)) {
            die(json_encode(['error' => '分块保存失败']));
        }
         
        // 检查是否所有分块都已上传
        $uploadedChunks = 0;
        for ($i = 0; $i < $totalChunks; $i++) {
            if (file_exists($tempDir . DIRECTORY_SEPARATOR . $fileId . '_' . $i)) {
                $uploadedChunks++;
            }
        }
         
        if ($uploadedChunks === $totalChunks) {
            // 所有分块上传完成,合并文件
            $finalPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
             
            // 检查文件是否已存在
            if (file_exists($finalPath)) {
                $fileName = pathinfo($fileName, PATHINFO_FILENAME) . '_' . date('Y-m-d_H-i-s') . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
                $finalPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
            }
             
            $finalFile = fopen($finalPath, 'wb');
            if (!$finalFile) {
                die(json_encode(['error' => '无法创建最终文件']));
            }
             
            // 合并所有分块
            for ($i = 0; $i < $totalChunks; $i++) {
                $chunkPath = $tempDir . DIRECTORY_SEPARATOR . $fileId . '_' . $i;
                if (file_exists($chunkPath)) {
                    $chunkData = file_get_contents($chunkPath);
                    fwrite($finalFile, $chunkData);
                    unlink($chunkPath); // 删除临时分块
                }
            }
            fclose($finalFile);
             
            echo json_encode([
                'success' => true,
                'completed' => true,
                'message' => "大文件上传成功:$fileName",
                'filename' => $fileName,
                'size' => filesize($finalPath)
            ]);
        } else {
            // 返回上传进度
            echo json_encode([
                'success' => true,
                'completed' => false,
                'progress' => round(($uploadedChunks / $totalChunks) * 100, 2),
                'uploaded' => $uploadedChunks,
                'total' => $totalChunks
            ]);
        }
        exit;
    }
    elseif ($_POST['action'] == 'remote_download') {
        // 远程下载功能
        $url = isset($_POST['url']) ? trim($_POST['url']) : '';
         
        if (empty($url)) {
            die(json_encode(['error' => '请输入有效的下载链接']));
        }
         
        // 验证URL格式
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            die(json_encode(['error' => '无效的URL格式']));
        }
         
        // 创建远程下载目录
        $downloadDir = $basePath . DIRECTORY_SEPARATOR . 'yuanchengdownload';
        if (!is_dir($downloadDir)) {
            mkdir($downloadDir, 0755, true);
        }
         
        // 获取文件名
        $fileName = basename(parse_url($url, PHP_URL_PATH));
        if (empty($fileName) || strpos($fileName, '.') === false) {
            $fileName = 'download_' . date('Y-m-d_H-i-s') . '.file';
        }
         
        $targetPath = $downloadDir . DIRECTORY_SEPARATOR . $fileName;
         
        // 如果文件已存在,添加时间戳
        if (file_exists($targetPath)) {
            $ext = pathinfo($fileName, PATHINFO_EXTENSION);
            $name = pathinfo($fileName, PATHINFO_FILENAME);
            $fileName = $name . '_' . date('Y-m-d_H-i-s') . '.' . $ext;
            $targetPath = $downloadDir . DIRECTORY_SEPARATOR . $fileName;
        }
         
        // 使用cURL下载文件
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 300); // 5分钟超时
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
         
        $data = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
         
        if ($data === false || !empty($error)) {
            die(json_encode(['error' => '下载失败: ' . $error]));
        }
         
        if ($httpCode !== 200) {
            die(json_encode(['error' => "下载失败,HTTP状态码: $httpCode"]));
        }
         
        if (file_put_contents($targetPath, $data) === false) {
            die(json_encode(['error' => '保存文件失败']));
        }
         
        echo json_encode([
            'success' => true,
            'message' => "远程文件下载成功:$fileName",
            'filename' => $fileName,
            'size' => filesize($targetPath)
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'create_folder') {
        // 创建文件夹
        $currentDir = isset($_POST['current_dir']) ? $_POST['current_dir'] : $basePath;
        $folderName = isset($_POST['folder_name']) ? trim($_POST['folder_name']) : '';
         
        $currentDir = realpath($currentDir);
         
        // 安全检查
        if (!$currentDir || strpos($currentDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的目录路径']));
        }
         
        if (empty($folderName)) {
            die(json_encode(['error' => '请输入文件夹名称']));
        }
         
        // 验证文件夹名称
        if (preg_match('/[<>:"|?*]/', $folderName)) {
            die(json_encode(['error' => '文件夹名称包含非法字符']));
        }
         
        $folderPath = $currentDir . DIRECTORY_SEPARATOR . $folderName;
         
        if (file_exists($folderPath)) {
            die(json_encode(['error' => '文件夹已存在']));
        }
         
        if (mkdir($folderPath, 0755)) {
            echo json_encode([
                'success' => true,
                'message' => "文件夹创建成功:$folderName"
            ]);
        } else {
            echo json_encode(['error' => '文件夹创建失败']);
        }
        exit;
    }
    elseif ($_POST['action'] == 'create_file') {
        // 创建文件
        $currentDir = isset($_POST['current_dir']) ? $_POST['current_dir'] : $basePath;
        $fileName = isset($_POST['file_name']) ? trim($_POST['file_name']) : '';
         
        $currentDir = realpath($currentDir);
         
        // 安全检查
        if (!$currentDir || strpos($currentDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的目录路径']));
        }
         
        if (empty($fileName)) {
            die(json_encode(['error' => '请输入文件名称']));
        }
         
        // 验证文件名
        if (preg_match('/[<>:"|?*]/', $fileName)) {
            die(json_encode(['error' => '文件名包含非法字符']));
        }
         
        $filePath = $currentDir . DIRECTORY_SEPARATOR . $fileName;
         
        if (file_exists($filePath)) {
            die(json_encode(['error' => '文件已存在']));
        }
         
        if (file_put_contents($filePath, '') !== false) {
            echo json_encode([
                'success' => true,
                'message' => "文件创建成功:$fileName"
            ]);
        } else {
            echo json_encode(['error' => '文件创建失败']);
        }
        exit;
    }
    elseif ($_POST['action'] == 'compress_single') {
        // 压缩单个文件或目录
        $targetPath = isset($_POST['path']) ? $_POST['path'] : '';
        $targetPath = realpath($targetPath);
         
        // 安全检查
        if (!$targetPath || strpos($targetPath, $basePath) !== 0 || !file_exists($targetPath)) {
            die(json_encode(['error' => '无效的文件路径']));
        }
         
        // 获取文件/目录所在的目录
        $parentDir = dirname($targetPath);
         
        $fileName = basename($targetPath);
        $zipFileName = $fileName . '_' . date('Y-m-d_H-i-s') . '.zip';
        $zipFilePath = $parentDir . DIRECTORY_SEPARATOR . $zipFileName;
         
        $zip = new ZipArchive();
        if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
            die(json_encode(['error' => "无法创建ZIP文件: $zipFileName"]));
        }
         
        // 递归添加目录到ZIP的函数
        function addToZip($path, &$zip, $basePath) {
            if (is_file($path)) {
                $localPath = basename($path);
                $zip->addFile($path, $localPath);
            } elseif (is_dir($path)) {
                $localPath = basename($path);
                $zip->addEmptyDir($localPath);
                 
                $handle = opendir($path);
                if ($handle) {
                    while (false !== ($f = readdir($handle))) {
                        if ($f != '.' && $f != '..') {
                            $filePath = "$path/$f";
                            $relativePath = $localPath . '/' . $f;
                             
                            if (is_file($filePath)) {
                                $zip->addFile($filePath, $relativePath);
                            } elseif (is_dir($filePath)) {
                                $zip->addEmptyDir($relativePath);
                                addFolderToZipRecursive($filePath, $zip, $relativePath);
                            }
                        }
                    }
                    closedir($handle);
                }
            }
        }
         
        function addFolderToZipRecursive($folder, &$zip, $localBase) {
            $handle = opendir($folder);
            if ($handle) {
                while (false !== ($f = readdir($handle))) {
                    if ($f != '.' && $f != '..') {
                        $filePath = "$folder/$f";
                        $localPath = $localBase . '/' . $f;
                         
                        if (is_file($filePath)) {
                            $zip->addFile($filePath, $localPath);
                        } elseif (is_dir($filePath)) {
                            $zip->addEmptyDir($localPath);
                            addFolderToZipRecursive($filePath, $zip, $localPath);
                        }
                    }
                }
                closedir($handle);
            }
        }
         
        addToZip($targetPath, $zip, $basePath);
        $zip->close();
         
        echo json_encode([
            'success' => true,
            'message' => "压缩完成!文件已保存为: $zipFileName",
            'filename' => $zipFileName,
            'size' => filesize($zipFilePath)
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'download_single') {
        // 下载单个文件
        $targetPath = isset($_POST['path']) ? $_POST['path'] : '';
        $targetPath = realpath($targetPath);
         
        // 安全检查
        if (!$targetPath || strpos($targetPath, $basePath) !== 0 || !file_exists($targetPath)) {
            header('HTTP/1.1 404 Not Found');
            die('文件不存在');
        }
         
        // 只允许下载文件,不允许下载目录
        if (is_dir($targetPath)) {
            die(json_encode(['error' => '请使用压缩功能来下载目录']));
        }
         
        $fileName = basename($targetPath);
        $fileSize = filesize($targetPath);
         
        // 重新设置执行时间限制和忽略用户中断
        set_time_limit(0);
        ignore_user_abort(true);
         
        // 清除所有输出缓冲
        while (ob_get_level()) {
            ob_end_clean();
        }
         
        // 禁用Apache的输出压缩(如果可能)
        if (function_exists('apache_setenv')) {
            apache_setenv('no-gzip', '1');
        }
         
        // 设置下载头信息
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $fileName . '"');
        header('Content-Length: ' . $fileSize);
        header('Content-Transfer-Encoding: binary');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Connection: close');
         
        $handle = fopen($targetPath, 'rb');
        if ($handle === false) {
            header('HTTP/1.1 500 Internal Server Error');
            die('无法打开文件');
        }
         
        // 使用256KB块大小
        $chunkSize = 262144;
         
        while (!feof($handle)) {
            if (connection_aborted()) {
                break;
            }
             
            set_time_limit(30);
            $data = fread($handle, $chunkSize);
             
            if ($data === false || strlen($data) == 0) {
                break;
            }
             
            echo $data;
             
            if (function_exists('fastcgi_finish_request')) {
                fastcgi_finish_request();
            } else {
                flush();
            }
        }
         
        fclose($handle);
        exit;
    }
    elseif ($_POST['action'] == 'delete_item') {
        // 删除文件或目录
        $targetPath = isset($_POST['path']) ? $_POST['path'] : '';
        $targetPath = realpath($targetPath);
         
        // 安全检查
        if (!$targetPath || strpos($targetPath, $basePath) !== 0 || !file_exists($targetPath)) {
            die(json_encode(['error' => '无效的文件路径']));
        }
         
        // 递归删除目录的函数
        function deleteDirectory($dir) {
            if (!is_dir($dir)) {
                return unlink($dir);
            }
             
            $files = array_diff(scandir($dir), array('.', '..'));
            foreach ($files as $file) {
                $filePath = $dir . DIRECTORY_SEPARATOR . $file;
                if (is_dir($filePath)) {
                    deleteDirectory($filePath);
                } else {
                    unlink($filePath);
                }
            }
            return rmdir($dir);
        }
         
        $fileName = basename($targetPath);
        $isDir = is_dir($targetPath);
         
        try {
            if ($isDir) {
                $success = deleteDirectory($targetPath);
                $message = $success ? "目录 '$fileName' 删除成功!" : "删除目录失败!";
            } else {
                $success = unlink($targetPath);
                $message = $success ? "文件 '$fileName' 删除成功!" : "删除文件失败!";
            }
             
            if ($success) {
                echo json_encode([
                    'success' => true,
                    'message' => $message
                ]);
            } else {
                echo json_encode(['error' => $message]);
            }
        } catch (Exception $e) {
            echo json_encode(['error' => '删除时发生错误: ' . $e->getMessage()]);
        }
         
        exit;
    }
    elseif ($_POST['action'] == 'read_file') {
        // 读取文件内容用于编辑
        $targetPath = isset($_POST['path']) ? $_POST['path'] : '';
        $targetPath = realpath($targetPath);
         
        // 安全检查
        if (!$targetPath || strpos($targetPath, $basePath) !== 0 || !file_exists($targetPath)) {
            die(json_encode(['error' => '无效的文件路径']));
        }
         
        // 只允许编辑文件,不允许编辑目录
        if (is_dir($targetPath)) {
            die(json_encode(['error' => '无法编辑目录']));
        }
         
        // 检查文件大小,避免加载过大的文件
        $fileSize = filesize($targetPath);
        if ($fileSize > 5 * 1024 * 1024) { // 5MB限制
            die(json_encode(['error' => '文件过大,无法编辑(超过5MB)']));
        }
         
        // 尝试读取文件内容
        $content = file_get_contents($targetPath);
        if ($content === false) {
            die(json_encode(['error' => '无法读取文件内容']));
        }
         
        // 检查是否为二进制文件
        if (mb_check_encoding($content, 'UTF-8') === false && !mb_check_encoding($content, 'ASCII')) {
            die(json_encode(['error' => '无法编辑二进制文件']));
        }
         
        echo json_encode([
            'success' => true,
            'content' => $content,
            'filename' => basename($targetPath),
            'size' => $fileSize
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'save_file') {
        // 保存文件内容
        $targetPath = isset($_POST['path']) ? $_POST['path'] : '';
        $content = isset($_POST['content']) ? $_POST['content'] : '';
        $targetPath = realpath($targetPath);
         
        // 安全检查
        if (!$targetPath || strpos($targetPath, $basePath) !== 0) {
            die(json_encode(['error' => '无效的文件路径']));
        }
         
        // 创建备份
        $backupPath = $targetPath . '.backup.' . date('Y-m-d_H-i-s');
        if (file_exists($targetPath)) {
            copy($targetPath, $backupPath);
        }
         
        // 保存文件
        $result = file_put_contents($targetPath, $content);
        if ($result === false) {
            die(json_encode(['error' => '保存文件失败']));
        }
         
        echo json_encode([
            'success' => true,
            'message' => '文件保存成功!',
            'bytes_written' => $result
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'move_item') {
        // 移动文件或目录
        $sourcePath = isset($_POST['source_path']) ? $_POST['source_path'] : '';
        $targetDir = isset($_POST['target_dir']) ? $_POST['target_dir'] : '';
         
        $sourcePath = realpath($sourcePath);
        $targetDir = realpath($targetDir);
         
        // 安全检查
        if (!$sourcePath || !$targetDir || 
            strpos($sourcePath, $basePath) !== 0 || 
            strpos($targetDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的路径']));
        }
         
        if (!file_exists($sourcePath)) {
            die(json_encode(['error' => '源文件或目录不存在']));
        }
         
        if (!is_dir($targetDir) || !is_writable($targetDir)) {
            die(json_encode(['error' => '目标目录无效或无写入权限']));
        }
         
        $fileName = basename($sourcePath);
        $targetPath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
         
        // 检查是否试图移动到自身或子目录中(防止递归移动)
        if (is_dir($sourcePath)) {
            $realSource = realpath($sourcePath);
            $realTarget = realpath($targetDir);
             
            if ($realSource === $realTarget || strpos($realTarget, $realSource . DIRECTORY_SEPARATOR) === 0) {
                die(json_encode(['error' => '不能将目录移动到自身或其子目录中']));
            }
        }
         
        // 检查目标位置是否已存在同名文件/目录
        if (file_exists($targetPath)) {
            // 生成新的文件名
            $counter = 1;
            $extension = '';
            $baseName = $fileName;
             
            if (!is_dir($sourcePath) && strrpos($fileName, '.') !== false) {
                $extension = substr($fileName, strrpos($fileName, '.'));
                $baseName = substr($fileName, 0, strrpos($fileName, '.'));
            }
             
            do {
                $newFileName = $baseName . '_' . $counter . $extension;
                $targetPath = $targetDir . DIRECTORY_SEPARATOR . $newFileName;
                $counter++;
            } while (file_exists($targetPath));
             
            $fileName = $newFileName;
        }
         
        // 执行移动操作
        if (rename($sourcePath, $targetPath)) {
            $itemType = is_dir($targetPath) ? '目录' : '文件';
            echo json_encode([
                'success' => true,
                'message' => "{$itemType} '{$fileName}' 已成功移动到目标位置",
                'new_name' => $fileName
            ]);
        } else {
            echo json_encode(['error' => '移动失败,请检查文件权限']);
        }
        exit;
    }
    elseif ($_POST['action'] == 'extract_archive') {
        // 解压缩文件
        $archivePath = isset($_POST['path']) ? $_POST['path'] : '';
        $archivePath = realpath($archivePath);
         
        // 安全检查
        if (!$archivePath || strpos($archivePath, $basePath) !== 0 || !file_exists($archivePath)) {
            die(json_encode(['error' => '无效的压缩文件路径']));
        }
         
        if (is_dir($archivePath)) {
            die(json_encode(['error' => '无法解压目录']));
        }
         
        $fileName = basename($archivePath);
        $fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        $currentDir = dirname($archivePath);
         
        // 检查是否为支持的压缩格式
        $supportedFormats = ['zip'];
        if (!in_array($fileExtension, $supportedFormats)) {
            die(json_encode(['error' => "不支持的压缩格式: .$fileExtension (当前仅支持: " . implode(', ', $supportedFormats) . ")"]));
        }
         
        // 检查ZipArchive扩展是否可用
        if (!class_exists('ZipArchive')) {
            die(json_encode(['error' => 'PHP ZipArchive 扩展不可用']));
        }
         
        // 创建解压目录
        $extractBaseName = pathinfo($fileName, PATHINFO_FILENAME);
        $extractDir = $currentDir . DIRECTORY_SEPARATOR . $extractBaseName;
         
        // 如果解压目录已存在,创建带时间戳的新目录
        if (file_exists($extractDir)) {
            $extractDir = $currentDir . DIRECTORY_SEPARATOR . $extractBaseName . '_extracted_' . date('Y-m-d_H-i-s');
        }
         
        if (!mkdir($extractDir, 0755, true)) {
            die(json_encode(['error' => '无法创建解压目录']));
        }
         
        // 执行解压操作
        $zip = new ZipArchive();
        $result = $zip->open($archivePath);
         
        if ($result !== TRUE) {
            // 删除创建的空目录
            rmdir($extractDir);
             
            $errorMessages = [
                ZipArchive::ER_OK => '没有错误',
                ZipArchive::ER_MULTIDISK => '不支持多磁盘ZIP文件',
                ZipArchive::ER_RENAME => '重命名临时文件失败',
                ZipArchive::ER_CLOSE => '关闭ZIP文件失败',
                ZipArchive::ER_SEEK => '查找错误',
                ZipArchive::ER_READ => '读取错误',
                ZipArchive::ER_WRITE => '写入错误',
                ZipArchive::ER_CRC => 'CRC错误',
                ZipArchive::ER_ZIPCLOSED => 'ZIP文件已关闭',
                ZipArchive::ER_NOENT => 'ZIP文件不存在',
                ZipArchive::ER_EXISTS => '文件已存在',
                ZipArchive::ER_OPEN => '无法打开文件',
                ZipArchive::ER_TMPOPEN => '无法创建临时文件',
                ZipArchive::ER_ZLIB => 'ZLIB错误',
                ZipArchive::ER_MEMORY => '内存分配失败',
                ZipArchive::ER_CHANGED => 'ZIP文件已被修改',
                ZipArchive::ER_COMPNOTSUPP => '不支持的压缩方法',
                ZipArchive::ER_EOF => '过早的EOF',
                ZipArchive::ER_INVAL => '无效参数',
                ZipArchive::ER_NOZIP => '不是一个ZIP文件',
                ZipArchive::ER_INTERNAL => '内部错误',
                ZipArchive::ER_INCONS => 'ZIP文件不一致',
                ZipArchive::ER_REMOVE => '无法删除文件',
                ZipArchive::ER_DELETED => '文件已被删除'
            ];
             
            $errorMsg = isset($errorMessages[$result]) ? $errorMessages[$result] : "未知错误 (代码: $result)";
            die(json_encode(['error' => "打开ZIP文件失败: $errorMsg"]));
        }
         
       // 获取ZIP文件信息
        $numFiles = $zip->numFiles;
        $extractedFiles = 0;
        $skippedDirectories = 0;
        $errors = [];
        $detailedLog = [];
         
        // 逐个解压文件
        for ($i = 0; $i < $numFiles; $i++) {
            $fileInfo = $zip->statIndex($i);
            if ($fileInfo === false) {
                $errors[] = "无法获取文件信息 (索引: $i)";
                $detailedLog[] = "ERROR: 无法获取文件信息 (索引: $i)";
                continue;
            }
             
            $fileName = $fileInfo['name'];
            $detailedLog[] = "处理文件: $fileName";
             
            // 安全检查:防止路径遍历攻击
            // 检查文件名中是否包含危险的路径模式
            if (strpos($fileName, '../') !== false || strpos($fileName, '..\') !== false) {
                $errors[] = "危险的文件路径(包含上级目录): $fileName";
                $detailedLog[] = "ERROR: 危险路径 - $fileName";
                continue;
            }
             
            // 检查是否为绝对路径
            if (substr($fileName, 0, 1) === '/' || (strlen($fileName) > 1 && substr($fileName, 1, 1) === ':')) {
                $errors[] = "危险的文件路径(绝对路径): $fileName";
                $detailedLog[] = "ERROR: 绝对路径 - $fileName";
                continue;
            }
             
            $targetPath = $extractDir . DIRECTORY_SEPARATOR . $fileName;
             
            // 规范化路径分隔符
            $targetPath = str_replace(['/', '\'], DIRECTORY_SEPARATOR, $targetPath);
             
            // 如果是目录,跳过(目录会在创建文件时自动创建)
            if (substr($fileName, -1) === '/') {
                $skippedDirectories++;
                $detailedLog[] = "SKIP: 目录 - $fileName";
                continue;
            }
             
            // 确保目标路径在解压目录内
            $realExtractDir = realpath($extractDir);
            $targetDirPath = dirname($targetPath);
             
            // 创建目录结构
            if (!is_dir($targetDirPath)) {
                if (!mkdir($targetDirPath, 0755, true)) {
                    $errors[] = "无法创建目录: $targetDirPath (文件: $fileName)";
                    $detailedLog[] = "ERROR: 创建目录失败 - $targetDirPath";
                    continue;
                }
                $detailedLog[] = "SUCCESS: 创建目录 - $targetDirPath";
            }
             
            // 再次验证路径安全性(在目录创建后)
            $realTargetDir = realpath($targetDirPath);
            if ($realTargetDir === false || strpos($realTargetDir, $realExtractDir) !== 0) {
                $errors[] = "危险的文件路径(超出解压范围): $fileName";
                $detailedLog[] = "ERROR: 路径验证失败 - $fileName";
                continue;
            }
             
            // 解压文件
            $fileContent = $zip->getFromIndex($i);
            if ($fileContent === false) {
                $errors[] = "无法提取文件内容: $fileName";
                $detailedLog[] = "ERROR: 提取内容失败 - $fileName";
                continue;
            }
             
            // 检查文件内容长度
            if ($fileContent === '') {
                // 空文件是正常的,继续处理
                $detailedLog[] = "INFO: 空文件 - $fileName";
            }
             
            if (file_put_contents($targetPath, $fileContent) === false) {
                $errors[] = "无法写入文件: $fileName (目标: $targetPath)";
                $detailedLog[] = "ERROR: 写入失败 - $fileName";
                continue;
            }
             
            $extractedFiles++;
            $detailedLog[] = "SUCCESS: 解压成功 - $fileName";
        }
         
        $zip->close();
         
        // 计算统计信息
        $totalProcessed = $extractedFiles + $skippedDirectories + count($errors);
        $actualFiles = $numFiles - $skippedDirectories; // 实际文件数(排除目录)
         
        // 生成结果消息
        $resultMessage = "解压完成!\n";
        $resultMessage .= "压缩文件: $fileName\n";
        $resultMessage .= "解压目录: " . basename($extractDir) . "\n";
        $resultMessage .= "ZIP中总条目数: $numFiles 个\n";
        $resultMessage .= "其中目录条目: $skippedDirectories 个\n";
        $resultMessage .= "实际文件数: $actualFiles 个\n";
        $resultMessage .= "成功解压文件: $extractedFiles 个\n";
        $resultMessage .= "失败文件数: " . count($errors) . " 个";
         
        if (!empty($errors)) {
            $resultMessage .= "\n\n解压失败的文件:\n";
            // 只显示前10个错误,避免消息过长
            $displayErrors = array_slice($errors, 0, 10);
            foreach ($displayErrors as $error) {
                $resultMessage .= "• $error\n";
            }
             
            if (count($errors) > 10) {
                $resultMessage .= "... 还有 " . (count($errors) - 10) . " 个错误未显示";
            }
        }
         
        // 保存详细日志到文件(可选,用于调试)
        $logFile = $extractDir . DIRECTORY_SEPARATOR . 'extraction_log.txt';
        file_put_contents($logFile, implode("\n", $detailedLog));
         
        echo json_encode([
            'success' => true,
            'message' => $resultMessage,
            'extracted_files' => $extractedFiles,
            'total_files' => $numFiles,
            'actual_files' => $actualFiles,
            'skipped_directories' => $skippedDirectories,
            'extract_dir' => basename($extractDir),
            'errors' => $errors,
            'error_count' => count($errors),
            'log_file' => 'extraction_log.txt'
        ]);
        exit;
    }
    elseif ($_POST['action'] == 'get_directory_tree') {
        // 获取目录树用于移动操作的目标选择
        $rootDir = isset($_POST['root_dir']) ? $_POST['root_dir'] : $basePath;
        $rootDir = realpath($rootDir);
         
        // 安全检查
        if (!$rootDir || strpos($rootDir, $basePath) !== 0) {
            die(json_encode(['error' => '无效的根目录路径']));
        }
         
        function buildDirectoryTree($dir, $basePath, $maxDepth = 3, $currentDepth = 0) {
            if ($currentDepth >= $maxDepth) {
                return [];
            }
             
            $tree = [];
             
            try {
                $items = scandir($dir);
                foreach ($items as $item) {
                    if ($item === '.' || $item === '..') continue;
                     
                    $itemPath = $dir . DIRECTORY_SEPARATOR . $item;
                     
                    if (is_dir($itemPath)) {
                        $relativePath = str_replace($basePath, '', $itemPath);
                        $relativePath = ltrim($relativePath, DIRECTORY_SEPARATOR);
                         
                        $node = [
                            'name' => $item,
                            'path' => $itemPath,
                            'relative_path' => $relativePath,
                            'children' => buildDirectoryTree($itemPath, $basePath, $maxDepth, $currentDepth + 1)
                        ];
                        $tree[] = $node;
                    }
                }
            } catch (Exception $e) {
                // 忽略权限错误等异常
            }
             
            // 按名称排序
            usort($tree, function($a, $b) {
                return strcmp($a['name'], $b['name']);
            });
             
            return $tree;
        }
         
        $tree = buildDirectoryTree($rootDir, $basePath);
         
        echo json_encode([
            'success' => true,
            'root_path' => $rootDir,
            'tree' => $tree
        ]);
        exit;
    }
     
    // 如果没有匹配的action,返回错误
    die(json_encode(['error' => '未知的操作类型']));
}
 
// 获取文件图标的函数
function getFileIcon($fileName) {
    $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
     
    $iconMap = [
        // 文档类
        'txt' => '📄', 'doc' => '📄', 'docx' => '📄', 'pdf' => '📕',
        'rtf' => '📄', 'odt' => '📄',
         
        // 表格类
        'xls' => '📊', 'xlsx' => '📊', 'csv' => '📊', 'ods' => '📊',
         
        // 演示文稿
        'ppt' => '📊', 'pptx' => '📊', 'odp' => '📊',
         
        // 图像类
        'jpg' => '🖼️', 'jpeg' => '🖼️', 'png' => '🖼️', 'gif' => '🖼️',
        'bmp' => '🖼️', 'svg' => '🖼️', 'ico' => '🖼️', 'webp' => '🖼️',
        'tiff' => '🖼️', 'tif' => '🖼️',
         
        // 音频类
        'mp3' => '🎵', 'wav' => '🎵', 'flac' => '🎵', 'aac' => '🎵',
        'ogg' => '🎵', 'm4a' => '🎵', 'wma' => '🎵',
         
        // 视频类
        'mp4' => '🎬', 'avi' => '🎬', 'mkv' => '🎬', 'mov' => '🎬',
        'wmv' => '🎬', 'flv' => '🎬', 'webm' => '🎬', '3gp' => '🎬',
         
        // 压缩文件
        'zip' => '📦', 'rar' => '📦', '7z' => '📦', 'tar' => '📦',
        'gz' => '📦', 'bz2' => '📦', 'xz' => '📦',
         
        // 代码文件
        'html' => '🌐', 'htm' => '🌐', 'css' => '🎨', 'js' => '⚡',
        'php' => '🐘', 'py' => '🐍', 'java' => '☕', 'cpp' => '⚙️',
        'c' => '⚙️', 'cs' => '⚙️', 'go' => '🐹', 'rs' => '🦀',
        'rb' => '💎', 'swift' => '🦉', 'kt' => '🎯',
         
        // 配置文件
        'json' => '📋', 'xml' => '📋', 'yaml' => '📋', 'yml' => '📋',
        'ini' => '⚙️', 'conf' => '⚙️', 'cfg' => '⚙️',
         
        // 数据库
        'sql' => '🗃️', 'db' => '🗃️', 'sqlite' => '🗃️',
         
        // 日志文件
        'log' => '📜',
         
        // 字体文件
        'ttf' => '🔤', 'otf' => '🔤', 'woff' => '🔤', 'woff2' => '🔤',
         
        // 可执行文件
        'exe' => '⚡', 'msi' => '⚡', 'deb' => '⚡', 'rpm' => '⚡',
        'dmg' => '⚡', 'app' => '⚡',
         
        // 其他常见格式
        'md' => '📝', 'readme' => '📖', 'license' => '📜',
        'gitignore' => '🚫', 'htaccess' => '⚙️'
    ];
     
    return isset($iconMap[$ext]) ? $iconMap[$ext] : '📄';
}
 
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网站文件压缩下载工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
         
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            color: #333;
        }
         
                .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
         
        header {
            text-align: center;
            color: white;
            margin-bottom: 30px;
        }
         
        header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        }
         
        .subtitle {
            font-size: 1.1em;
            opacity: 0.9;
        }
         
        .path-info {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 20px;
            color: white;
            word-break: break-all;
        }
         
        .main-content {
            background: white;
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            backdrop-filter: blur(10px);
        }
         
        /* 工具栏样式 */
        .toolbar {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            flex-wrap: wrap;
            align-items: center;
            padding: 15px;
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 10px;
            border: 1px solid #dee2e6;
        }
         
        .toolbar-btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 10px 16px;
            border-radius: 8px;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 6px;
            font-weight: 500;
            min-height: 38px;
        }
         
        .toolbar-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
        }
         
        .toolbar-btn:active {
            transform: translateY(0);
        }
         
        .toolbar-btn.success {
            background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
        }
         
        .toolbar-btn.success:hover {
            box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
        }
         
        .toolbar-btn.warning {
            background: linear-gradient(135deg, #ffc107 0%, #fd7e14 100%);
            color: #212529;
        }
         
        .toolbar-btn.warning:hover {
            box-shadow: 0 4px 12px rgba(255, 193, 7, 0.4);
        }
         
        .toolbar-btn.info {
            background: linear-gradient(135deg, #17a2b8 0%, #6f42c1 100%);
        }
         
        .toolbar-btn.info:hover {
            box-shadow: 0 4px 12px rgba(23, 162, 184, 0.4);
        }
         
        .toolbar-btn.danger {
            background: linear-gradient(135deg, #dc3545 0%, #e83e8c 100%);
        }
         
        .toolbar-btn.danger:hover {
            box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4);
        }
         
        .toolbar-btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none !important;
        }
         
        /* 文件上传样式 */
        .upload-input {
            display: none;
        }
         
        .file-explorer {
            position: relative;
        }
         
        .file-list {
            list-style: none;
            max-height: 600px;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            background: #fafafa;
        }
         
        .file-item {
            display: flex;
            align-items: center;
            padding: 12px 15px;
            border-bottom: 1px solid #f0f0f0;
            cursor: pointer;
            transition: all 0.2s ease;
            user-select: none;
        }
         
        .file-item:last-child {
            border-bottom: none;
        }
         
        .file-item:hover {
            background: #e6f7ff;
            transform: translateX(3px);
        }
         
        .file-item.directory {
            font-weight: 600;
            color: #1890ff;
        }
         
        .file-item.directory:hover {
            background: #f0f9ff;
        }
         
        .file-item.selected {
            background: #bae7ff;
            border-left: 4px solid #1890ff;
        }
         
        .file-icon {
            margin-right: 10px;
            font-size: 1.2em;
            min-width: 25px;
        }
         
        .file-name {
            flex: 1;
            margin-right: 15px;
            word-break: break-all;
        }
         
        .file-size {
            color: #666;
            font-size: 0.9em;
            min-width: 80px;
            text-align: right;
        }
         
        .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 25px;
            font-size: 16px;
            cursor: pointer;
            transition: all 0.3s ease;
            text-decoration: none;
            display: inline-block;
            text-align: center;
            margin: 5px;
        }
         
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }
         
        .btn:active {
            transform: translateY(0);
        }
         
        .status {
            margin-top: 20px;
            padding: 15px;
            border-radius: 8px;
            display: none;
            animation: slideIn 0.3s ease;
        }
         
        .status.success {
            background: #f6ffed;
            border: 1px solid #b7eb8f;
            color: #52c41a;
        }
         
        .status.error {
            background: #fff2f0;
            border: 1px solid #ffccc7;
            color: #ff4d4f;
        }
         
        .loading {
            display: none;
            text-align: center;
            margin: 50px 0;
            color: #666;
        }
         
        .loading.large-upload {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
        }
         
        .spinner {
            border: 3px solid #f3f3f3;
            border-top: 3px solid #667eea;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 1s linear infinite;
            margin: 0 auto 10px;
        }
         
        .loading.large-upload .spinner {
            border: 3px solid rgba(255, 255, 255, 0.3);
            border-top: 3px solid white;
        }
         
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
         
        .breadcrumb {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }
         
        .breadcrumb-item {
            cursor: pointer;
            color: #1890ff;
        }
         
        .breadcrumb-item:hover {
            text-decoration: underline;
        }
         
        .breadcrumb-separator {
            margin: 0 8px;
            color: #999;
        }
         
        /* 右键菜单样式 */
        .context-menu {
            position: fixed;
            background: white;
            border: 1px solid #ddd;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            padding: 5px 0;
            z-index: 1000;
            display: none;
            min-width: 150px;
        }
         
        .context-menu-item {
            padding: 10px 15px;
            cursor: pointer;
            transition: background-color 0.2s;
            font-size: 14px;
        }
         
        .context-menu-item:hover {
            background-color: #f5f5f5;
        }
         
        .context-menu-item.disabled {
            color: #ccc;
            cursor: not-allowed;
        }
         
        .context-menu-item.disabled:hover {
            background-color: transparent;
        }
         
        /* 编辑弹窗样式 */
        .edit-modal {
            display: none;
            position: fixed;
            z-index: 9999;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            overflow: auto;
        }
         
        .edit-modal-content {
            background-color: white;
            margin: 2.5% auto;
            padding: 0;
            border-radius: 8px;
            width: 95%;
            height: 95%;
            display: flex;
            flex-direction: column;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            position: relative;
        }
         
        .edit-modal-header {
            padding: 15px 20px;
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            color: white;
            border-radius: 8px 8px 0 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
            min-height: 60px;
            flex-shrink: 0;
        }
         
        .edit-modal-header h3 {
            margin: 0;
            font-size: 18px;
            font-weight: 600;
        }
         
        .edit-modal-close {
            font-size: 32px;
            font-weight: bold;
            cursor: pointer;
            line-height: 1;
            padding: 5px;
            border-radius: 50%;
            transition: all 0.3s ease;
        }
         
        .edit-modal-close:hover {
            background-color: rgba(255, 255, 255, 0.2);
            transform: scale(1.1);
        }
         
        .edit-modal-body {
            flex: 1;
            padding: 20px;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }
         
        #file-content {
            width: 100%;
            height: 100%;
            border: 2px solid #e0e0e0;
            border-radius: 6px;
            padding: 15px;
            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
            font-size: 14px;
            line-height: 1.6;
            resize: none;
            outline: none;
            background-color: #f8f9fa;
            transition: all 0.3s ease;
        }
         
        #file-content:focus {
            border-color: #1890ff;
            box-shadow: 0 0 10px rgba(24, 144, 255, 0.3);
            background-color: #ffffff;
        }
         
        .edit-modal-footer {
            padding: 15px 20px;
            border-top: 2px solid #f0f0f0;
            display: flex;
            gap: 15px;
            justify-content: flex-end;
            flex-shrink: 0;
            background-color: #fafafa;
            border-radius: 0 0 8px 8px;
        }
         
        .edit-modal-footer .btn {
            padding: 10px 20px;
            font-size: 14px;
            font-weight: 600;
            border-radius: 6px;
            border: none;
            cursor: pointer;
            transition: all 0.3s ease;
        }
         
        .edit-modal-footer .btn-primary {
            background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
            color: white;
        }
         
        .edit-modal-footer .btn-primary:hover {
            background: linear-gradient(135deg, #096dd9 0%, #0050b3 100%);
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
        }
         
        .edit-modal-footer .btn:not(.btn-primary) {
            background-color: #f5f5f5;
            color: #666;
            border: 1px solid #d9d9d9;
        }
         
        .edit-modal-footer .btn:not(.btn-primary):hover {
            background-color: #e6f7ff;
            border-color: #1890ff;
            color: #1890ff;
        }
         
        /* 统一消息弹窗样式 */
        .message-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.6);
            z-index: 10000;
            display: none;
            justify-content: center;
            align-items: center;
            backdrop-filter: blur(5px);
            animation: fadeIn 0.3s ease;
        }
 
        .message-modal {
            background: white;
            border-radius: 16px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            max-width: 500px;
            width: 90%;
            max-height: 80vh;
            overflow-y: auto;
            transform: scale(0.8);
            animation: modalSlideIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
        }
 
        .message-header {
            padding: 25px 30px 15px;
            border-bottom: 2px solid #f0f0f0;
            display: flex;
            align-items: center;
            gap: 15px;
        }
 
        .message-icon {
            font-size: 32px;
            min-width: 40px;
        }
 
        .message-icon.success { color: #52c41a; }
        .message-icon.error { color: #ff4d4f; }
        .message-icon.warning { color: #faad14; }
        .message-icon.info { color: #1890ff; }
        .message-icon.confirm { color: #722ed1; }
 
        .message-title {
            font-size: 20px;
            font-weight: 600;
            color: #333;
            margin: 0;
        }
 
        .message-body {
            padding: 20px 30px;
            font-size: 16px;
            line-height: 1.6;
            color: #666;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
 
        .message-footer {
            padding: 15px 30px 25px;
            display: flex;
            justify-content: flex-end;
            gap: 12px;
        }
 
        .message-btn {
            padding: 10px 24px;
            border: none;
            border-radius: 8px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            min-width: 80px;
        }
 
        .message-btn-primary {
            background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
            color: white;
        }
 
        .message-btn-primary:hover {
            background: linear-gradient(135deg, #096dd9 0%, #0050b3 100%);
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(24, 144, 255, 0.4);
        }
 
        .message-btn-success {
            background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
            color: white;
        }
 
        .message-btn-success:hover {
            background: linear-gradient(135deg, #389e0d 0%, #237804 100%);
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(82, 196, 26, 0.4);
        }
 
        .message-btn-danger {
            background: linear-gradient(135deg, #ff4d4f 0%, #cf1322 100%);
            color: white;
        }
 
        .message-btn-danger:hover {
            background: linear-gradient(135deg, #cf1322 0%, #a8071a 100%);
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(255, 77, 79, 0.4);
        }
 
        .message-btn-secondary {
            background: #f5f5f5;
            color: #666;
            border: 1px solid #d9d9d9;
        }
 
        .message-btn-secondary:hover {
            background: #e6f7ff;
            border-color: #1890ff;
            color: #1890ff;
            transform: translateY(-1px);
        }
 
        .message-btn:active {
            transform: translateY(0);
        }
 
        /* 动画效果 */
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }
 
        @keyframes modalSlideIn {
            from {
                opacity: 0;
                transform: scale(0.8) translateY(-20px);
            }
            to {
                opacity: 1;
                transform: scale(1) translateY(0);
            }
        }
 
        @keyframes modalSlideOut {
            from {
                opacity: 1;
                transform: scale(1) translateY(0);
            }
            to {
                opacity: 0;
                transform: scale(0.8) translateY(-20px);
            }
        }
 
        .message-modal.closing {
            animation: modalSlideOut 0.3s ease forwards;
        }
 
        /* 加载动画 */
        .message-loading {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 2px solid #f3f3f3;
            border-radius: 50%;
            border-top-color: #1890ff;
            animation: spin 1s ease-in-out infinite;
            margin-right: 8px;
        }
 
        /* 输入模态框样式 */
        .input-modal {
            display: none;
            position: fixed;
            z-index: 10001;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.6);
            backdrop-filter: blur(5px);
        }
 
        .input-modal-content {
            background: white;
            margin: 10% auto;
            padding: 0;
            border-radius: 16px;
            width: 90%;
            max-width: 500px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            animation: modalSlideIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
        }
 
        .input-modal-header {
            padding: 25px 30px 15px;
            border-bottom: 2px solid #f0f0f0;
            display: flex;
            align-items: center;
            gap: 15px;
        }
 
        .input-modal-title {
            font-size: 20px;
            font-weight: 600;
            color: #333;
            margin: 0;
        }
 
        .input-modal-body {
            padding: 20px 30px;
        }
 
        .input-group {
            margin-bottom: 20px;
        }
 
        .input-label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #333;
        }
 
        .input-field {
            width: 100%;
            padding: 12px 16px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 14px;
            transition: all 0.3s ease;
            outline: none;
        }
 
        .input-field:focus {
            border-color: #1890ff;
            box-shadow: 0 0 10px rgba(24, 144, 255, 0.3);
        }
 
        .input-modal-footer {
            padding: 15px 30px 25px;
            display: flex;
            justify-content: flex-end;
            gap: 12px;
        }
        /* 目录选择弹窗样式 */
        .directory-modal {
            display: none;
            position: fixed;
            z-index: 9998;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            overflow: auto;
        }
 
        .directory-modal-content {
            background-color: white;
            margin: 5% auto;
            padding: 0;
            border-radius: 12px;
            width: 90%;
            max-width: 700px;
            max-height: 85vh;
            display: flex;
            flex-direction: column;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
            position: relative;
        }
 
        .directory-modal-header {
            padding: 20px 25px;
            background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
            color: white;
            border-radius: 12px 12px 0 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
            min-height: 60px;
            flex-shrink: 0;
        }
 
        .directory-modal-header h3 {
            margin: 0;
            font-size: 18px;
            font-weight: 600;
        }
 
        .directory-modal-close {
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            line-height: 1;
            padding: 5px;
            border-radius: 50%;
            transition: all 0.3s ease;
        }
 
        .directory-modal-close:hover {
            background-color: rgba(255, 255, 255, 0.2);
            transform: scale(1.1);
        }
 
        .directory-modal-body {
            flex: 1;
            padding: 20px 25px;
            overflow-y: auto;
            min-height: 300px;
            max-height: 50vh;
        }
 
        .directory-tree {
            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
            font-size: 14px;
            line-height: 1.6;
        }
 
        .loading-tree {
            text-align: center;
            padding: 40px 20px;
            color: #666;
        }
 
        .loading-tree .spinner {
            width: 30px;
            height: 30px;
            margin: 0 auto 15px;
        }
 
        .tree-node {
            margin: 2px 0;
            user-select: none;
        }
 
        .tree-item {
            display: flex;
            align-items: center;
            padding: 8px 12px;
            cursor: pointer;
            border-radius: 6px;
            transition: all 0.2s ease;
            position: relative;
        }
 
        .tree-item:hover {
            background-color: #f0f9ff;
            transform: translateX(3px);
        }
 
        .tree-item.selected {
            background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
            border-left: 4px solid #1890ff;
            color: #0050b3;
            font-weight: 600;
        }
 
        .tree-toggle {
            margin-right: 8px;
            font-size: 12px;
            cursor: pointer;
            transition: transform 0.2s ease;
            color: #666;
            min-width: 16px;
            text-align: center;
        }
 
        .tree-toggle.expanded {
            transform: rotate(90deg);
        }
 
        .tree-toggle.no-children {
            visibility: hidden;
        }
 
        .tree-icon {
            margin-right: 8px;
            font-size: 16px;
        }
 
        .tree-name {
            flex: 1;
        }
 
        .tree-children {
            margin-left: 24px;
            border-left: 1px dotted #d9d9d9;
            padding-left: 8px;
            display: none;
        }
 
        .tree-children.expanded {
            display: block;
        }
 
        .directory-modal-footer {
            padding: 20px 25px;
            border-top: 2px solid #f0f0f0;
            background-color: #fafafa;
            border-radius: 0 0 12px 12px;
            flex-shrink: 0;
        }
 
        .selected-path {
            margin-bottom: 15px;
            padding: 12px;
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 6px;
            font-size: 14px;
        }
 
        .selected-path strong {
            color: #333;
        }
 
        .selected-path span {
            color: #1890ff;
            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
            word-break: break-all;
        }
 
        .modal-buttons {
            display: flex;
            gap: 12px;
            justify-content: flex-end;
        }
 
        .modal-buttons .btn {
            padding: 10px 20px;
            font-size: 14px;
            font-weight: 600;
            border-radius: 6px;
            border: none;
            cursor: pointer;
            transition: all 0.3s ease;
        }
 
        .modal-buttons .btn-primary {
            background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
            color: white;
        }
 
        .modal-buttons .btn-primary:hover:not(:disabled) {
            background: linear-gradient(135deg, #389e0d 0%, #237804 100%);
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(82, 196, 26, 0.4);
        }
 
        .modal-buttons .btn-primary:disabled {
            background: #f5f5f5;
            color: #bfbfbf;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
 
        .modal-buttons .btn-secondary {
            background-color: #f5f5f5;
            color: #666;
            border: 1px solid #d9d9d9;
        }
 
        .modal-buttons .btn-secondary:hover {
            background-color: #e6f7ff;
            border-color: #1890ff;
            color: #1890ff;
            transform: translateY(-1px);
        }
        /* 响应式设计 */
        [url=home.php?mod=space&uid=945662]@media[/url] (max-width: 768px) {
            .toolbar {
                flex-direction: column;
                gap: 8px;
            }
             
            .toolbar-btn {
                width: 100%;
                justify-content: center;
            }
             
            .edit-modal-content {
                width: 98%;
                height: 98%;
                margin: 1% auto;
            }
             
            .edit-modal-header {
                padding: 10px 15px;
                min-height: 50px;
            }
             
            .edit-modal-header h3 {
                font-size: 16px;
            }
             
            .edit-modal-close {
                font-size: 28px;
            }
             
            .edit-modal-body {
                padding: 15px;
            }
             
            #file-content {
                font-size: 12px;
                padding: 10px;
            }
             
            .edit-modal-footer {
                padding: 10px 15px;
                flex-direction: column;
            }
             
            .edit-modal-footer .btn {
                width: 100%;
                margin-bottom: 10px;
            }
             
            .message-modal {
                width: 95%;
                margin: 10px;
            }
 
            .message-header {
                padding: 20px 20px 10px;
            }
 
            .message-icon {
                font-size: 28px;
                min-width: 32px;
            }
 
            .message-title {
                font-size: 18px;
            }
 
            .message-body {
                padding: 15px 20px;
                font-size: 15px;
            }
 
            .message-footer {
                padding: 10px 20px 20px;
                flex-direction: column;
            }
 
            .message-btn {
                width: 100%;
                margin-bottom: 8px;
            }
 
            .message-btn:last-child {
                margin-bottom: 0;
            }
             
            .input-modal-content {
                width: 95%;
                margin: 5% auto;
            }
             .directory-modal-content {
                width: 95%;
                height: 90vh;
                margin: 5vh auto;
            }
 
            .directory-modal-header {
                padding: 15px 20px;
            }
 
            .directory-modal-body {
                padding: 15px 20px;
                max-height: 60vh;
            }
 
            .directory-modal-footer {
                padding: 15px 20px;
            }
 
            .modal-buttons {
                flex-direction: column;
            }
 
            .modal-buttons .btn {
                width: 100%;
                margin-bottom: 10px;
            }
 
            .modal-buttons .btn:last-child {
                margin-bottom: 0;
            }
        }
         
        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>网站文件压缩下载工具</h1>
            <p class="subtitle">文件管理、上传下载、编辑压缩一体化工具</p>
        </header>
         
        <div class="path-info">
            <strong>当前服务器绝对路径:</strong> <?php echo $absolutePath; ?>
        </div>
         
        <div class="main-content">
            <div class="file-explorer">
                <!-- 工具栏 -->
                <div class="toolbar">
                    <button class="toolbar-btn success" id="upload-btn">
                        📤 上传文件
                    </button>
                    <button class="toolbar-btn" id="download-selected-btn" disabled>
                        📥 下载选中
                    </button>
                    <button class="toolbar-btn info" id="remote-download-btn">
                        🌐 远程下载
                    </button>
                    <button class="toolbar-btn warning" id="create-folder-btn">
                        📁 新建文件夹
                    </button>
                    <button class="toolbar-btn warning" id="create-file-btn">
                        📄 新建文件
                    </button>
                </div>
                 
                <div class="breadcrumb" id="breadcrumb">
                    <span class="breadcrumb-item" data-path="<?php echo $basePath; ?>">根目录</span>
                </div>
                 
                <ul class="file-list" id="file-list">
                    <li>加载中...</li>
                </ul>
                 
                <div class="loading" id="loading">
                    <div class="spinner"></div>
                    <p>处理中,请稍候...</p>
                </div>
                 
                <div class="status" id="status"></div>
            </div>
        </div>
         
        <!-- 文件上传隐藏输入框 -->
        <input type="file" id="upload-input" class="upload-input" multiple>
         
        <!-- 右键菜单 -->
        <div class="context-menu" id="context-menu">
            <div class="context-menu-item" id="compress-item">📦 压缩</div>
            <div class="context-menu-item" id="extract-item">📂 解压</div>
            <div class="context-menu-item" id="download-item">⬇️ 下载</div>
            <div class="context-menu-item" id="edit-item">📝 编辑</div>
            <div class="context-menu-item" id="move-item">✂️ 移动</div>
            <div class="context-menu-item" id="delete-item">🗑️ 删除</div>
        </div>
        <!-- 目录选择弹窗(用于移动操作) -->
        <div class="directory-modal" id="directory-modal" tabindex="-1">
            <div class="directory-modal-content">
                <div class="directory-modal-header">
                    <h3 id="directory-modal-title">选择目标目录</h3>
                    <span class="directory-modal-close" id="directory-modal-close" title="关闭 (ESC)">×</span>
                </div>
                <div class="directory-modal-body">
                    <div class="directory-tree" id="directory-tree">
                        <div class="loading-tree">
                            <div class="spinner"></div>
                            <p>正在加载目录树...</p>
                        </div>
                    </div>
                </div>
                <div class="directory-modal-footer">
                    <div class="selected-path">
                        <strong>选中路径:</strong>
                        <span id="selected-target-path">未选择</span>
                    </div>
                    <div class="modal-buttons">
                        <button class="btn btn-secondary" id="cancel-move" title="取消移动 (ESC)">❌ 取消</button>
                        <button class="btn btn-primary" id="confirm-move" title="确认移动" disabled>✂️ 移动到此位置</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- 文件编辑弹窗 -->
        <div class="edit-modal" id="edit-modal" tabindex="-1">
            <div class="edit-modal-content">
                <div class="edit-modal-header">
                    <h3 id="edit-file-name">编辑文件</h3>
                    <span class="edit-modal-close" id="edit-modal-close" title="关闭 (ESC)">×</span>
                </div>
                <div class="edit-modal-body">
                    <textarea id="file-content" placeholder="文件内容将在此处显示..." spellcheck="false"></textarea>
                </div>
                <div class="edit-modal-footer">
                    <button class="btn btn-primary" id="save-file" title="保存文件 (Ctrl+S)">💾 保存</button>
                    <button class="btn" id="cancel-edit" title="取消编辑 (ESC)">❌ 取消</button>
                </div>
            </div>
        </div>
 
        <!-- 统一消息弹窗 -->
        <div class="message-overlay" id="messageOverlay">
            <div class="message-modal" id="messageModal">
                <div class="message-header">
                    <span class="message-icon" id="messageIcon">ℹ️</span>
                    <h3 class="message-title" id="messageTitle">提示</h3>
                </div>
                <div class="message-body" id="messageBody">
                    消息内容
                </div>
                <div class="message-footer" id="messageFooter">
                    <button class="message-btn message-btn-primary" id="messageOkBtn">确定</button>
                </div>
            </div>
        </div>
 
        <!-- 输入弹窗 -->
        <div class="input-modal" id="inputModal">
            <div class="input-modal-content">
                <div class="input-modal-header">
                    <span class="message-icon" id="inputIcon">📝</span>
                    <h3 class="input-modal-title" id="inputTitle">输入信息</h3>
                </div>
                <div class="input-modal-body">
                    <div class="input-group">
                        <label class="input-label" id="inputLabel">请输入:</label>
                        <input type="text" class="input-field" id="inputField" placeholder="请输入...">
                    </div>
                </div>
                <div class="input-modal-footer">
                    <button class="message-btn message-btn-secondary" id="inputCancelBtn">取消</button>
                    <button class="message-btn message-btn-primary" id="inputOkBtn">确定</button>
                </div>
            </div>
        </div>
    </div>
 
    <script>
        // 统一消息弹窗系统
        class MessageModal {
            constructor() {
                this.overlay = document.getElementById('messageOverlay');
                this.modal = document.getElementById('messageModal');
                this.icon = document.getElementById('messageIcon');
                this.title = document.getElementById('messageTitle');
                this.body = document.getElementById('messageBody');
                this.footer = document.getElementById('messageFooter');
                this.okBtn = document.getElementById('messageOkBtn');
                 
                this.currentResolve = null;
                this.isVisible = false;
                 
                this.init();
            }
             
                        init() {
                // 点击遮罩层关闭(可选)
                this.overlay.addEventListener('click', (e) => {
                    if (e.target === this.overlay) {
                        this.close(false);
                    }
                });
                 
                // ESC键关闭
                document.addEventListener('keydown', (e) => {
                    if (e.key === 'Escape' && this.isVisible) {
                        e.preventDefault();
                        this.close(false);
                    }
                });
            }
             
            show(options = {}) {
                return new Promise((resolve) => {
                    this.currentResolve = resolve;
                     
                    const {
                        type = 'info',
                        title = '提示',
                        message = '',
                        showCancel = false,
                        okText = '确定',
                        cancelText = '取消',
                        allowEscapeKey = true
                    } = options;
                     
                    // 设置图标和样式
                    const iconMap = {
                        success: { icon: '✅', class: 'success' },
                        error: { icon: '❌', class: 'error' },
                        warning: { icon: '⚠️', class: 'warning' },
                        info: { icon: 'ℹ️', class: 'info' },
                        confirm: { icon: '❓', class: 'confirm' }
                    };
                     
                    const iconInfo = iconMap[type] || iconMap.info;
                    this.icon.textContent = iconInfo.icon;
                    this.icon.className = `message-icon ${iconInfo.class}`;
                     
                    // 设置标题和内容
                    this.title.textContent = title;
                    this.body.textContent = message;
                     
                    // 设置按钮
                    this.footer.innerHTML = '';
                     
                    if (showCancel) {
                        const cancelBtn = document.createElement('button');
                        cancelBtn.className = 'message-btn message-btn-secondary';
                        cancelBtn.textContent = cancelText;
                        cancelBtn.onclick = () => this.close(false);
                        this.footer.appendChild(cancelBtn);
                    }
                     
                    const okBtn = document.createElement('button');
                    okBtn.className = `message-btn ${type === 'error' ? 'message-btn-danger' : 
                                                   type === 'success' ? 'message-btn-success' : 
                                                   'message-btn-primary'}`;
                    okBtn.textContent = okText;
                    okBtn.onclick = () => this.close(true);
                    this.footer.appendChild(okBtn);
                     
                    // 显示弹窗
                    this.overlay.style.display = 'flex';
                    this.isVisible = true;
                     
                    // 聚焦到确定按钮
                    setTimeout(() => {
                        okBtn.focus();
                    }, 100);
                });
            }
             
            close(result) {
                if (!this.isVisible) return;
                 
                this.modal.classList.add('closing');
                 
                setTimeout(() => {
                    this.overlay.style.display = 'none';
                    this.modal.classList.remove('closing');
                    this.isVisible = false;
                     
                    if (this.currentResolve) {
                        this.currentResolve(result);
                        this.currentResolve = null;
                    }
                }, 300);
            }
             
            // 简化的方法
            alert(message, title = '提示', type = 'info') {
                return this.show({
                    type,
                    title,
                    message,
                    showCancel: false
                });
            }
             
            confirm(message, title = '确认', type = 'confirm') {
                return this.show({
                    type,
                    title,
                    message,
                    showCancel: true,
                    okText: '确定',
                    cancelText: '取消'
                });
            }
             
            success(message, title = '成功') {
                return this.alert(message, title, 'success');
            }
             
            error(message, title = '错误') {
                return this.alert(message, title, 'error');
            }
             
            warning(message, title = '警告') {
                return this.alert(message, title, 'warning');
            }
        }
 
        // 输入弹窗系统
        class InputModal {
            constructor() {
                this.modal = document.getElementById('inputModal');
                this.icon = document.getElementById('inputIcon');
                this.title = document.getElementById('inputTitle');
                this.label = document.getElementById('inputLabel');
                this.field = document.getElementById('inputField');
                this.okBtn = document.getElementById('inputOkBtn');
                this.cancelBtn = document.getElementById('inputCancelBtn');
                 
                this.currentResolve = null;
                this.isVisible = false;
                 
                this.init();
            }
             
            init() {
                // 点击取消按钮
                this.cancelBtn.addEventListener('click', () => this.close(null));
                 
                // 点击确定按钮
                this.okBtn.addEventListener('click', () => {
                    const value = this.field.value.trim();
                    this.close(value);
                });
                 
                // 回车键确定
                this.field.addEventListener('keydown', (e) => {
                    if (e.key === 'Enter') {
                        e.preventDefault();
                        const value = this.field.value.trim();
                        this.close(value);
                    } else if (e.key === 'Escape') {
                        e.preventDefault();
                        this.close(null);
                    }
                });
                 
                // 点击遮罩层关闭
                this.modal.addEventListener('click', (e) => {
                    if (e.target === this.modal) {
                        this.close(null);
                    }
                });
            }
             
            show(options = {}) {
                return new Promise((resolve) => {
                    this.currentResolve = resolve;
                     
                    const {
                        title = '输入信息',
                        label = '请输入:',
                        placeholder = '请输入...',
                        defaultValue = '',
                        icon = '📝'
                    } = options;
                     
                    // 设置内容
                    this.title.textContent = title;
                    this.label.textContent = label;
                    this.field.placeholder = placeholder;
                    this.field.value = defaultValue;
                    this.icon.textContent = icon;
                     
                    // 显示弹窗
                    this.modal.style.display = 'flex';
                    this.isVisible = true;
                     
                    // 聚焦到输入框
                    setTimeout(() => {
                        this.field.focus();
                        this.field.select();
                    }, 100);
                });
            }
             
            close(result) {
                if (!this.isVisible) return;
                 
                this.modal.style.display = 'none';
                this.isVisible = false;
                this.field.value = '';
                 
                if (this.currentResolve) {
                    this.currentResolve(result);
                    this.currentResolve = null;
                }
            }
        }
         
        // 创建全局实例
        const messageModal = new MessageModal();
        const inputModal = new InputModal();
         
        // 重写全局alert和confirm函数
        window.alert = function(message) {
            return messageModal.alert(message);
        };
         
        window.confirm = function(message) {
            return messageModal.confirm(message);
        };
 
        document.addEventListener('DOMContentLoaded', function() {
            const fileList = document.getElementById('file-list');
            const breadcrumb = document.getElementById('breadcrumb');
            const loading = document.getElementById('loading');
            const status = document.getElementById('status');
            const contextMenu = document.getElementById('context-menu');
           const compressItem = document.getElementById('compress-item');
           const extractItem = document.getElementById('extract-item');
            const downloadItem = document.getElementById('download-item');
            const editItem = document.getElementById('edit-item');
            const deleteItem = document.getElementById('delete-item');
            const moveItem = document.getElementById('move-item');
             
            // 工具栏按钮
            const uploadBtn = document.getElementById('upload-btn');
            const downloadSelectedBtn = document.getElementById('download-selected-btn');
            const remoteDownloadBtn = document.getElementById('remote-download-btn');
            const createFolderBtn = document.getElementById('create-folder-btn');
            const createFileBtn = document.getElementById('create-file-btn');
            const uploadInput = document.getElementById('upload-input');
             
            // 编辑相关元素
            const editModal = document.getElementById('edit-modal');
            const editFileName = document.getElementById('edit-file-name');
            const fileContent = document.getElementById('file-content');
            const saveFileBtn = document.getElementById('save-file');
            const cancelEditBtn = document.getElementById('cancel-edit');
            const editModalClose = document.getElementById('edit-modal-close');
             
            // 目录选择相关元素
            const directoryModal = document.getElementById('directory-modal');
            const directoryModalTitle = document.getElementById('directory-modal-title');
            const directoryTree = document.getElementById('directory-tree');
            const selectedTargetPath = document.getElementById('selected-target-path');
            const confirmMoveBtn = document.getElementById('confirm-move');
            const cancelMoveBtn = document.getElementById('cancel-move');
            const directoryModalClose = document.getElementById('directory-modal-close');
             
            let currentPath = '<?php echo $basePath; ?>';
            let currentSelectedPath = '';
            let currentSelectedIsDir = false;
            let selectedFiles = new Set();
            let selectedMoveTarget = '';
            let moveSourcePath = '';
            let moveSourceIsDir = false;
             
            // 工具栏按钮事件
            uploadBtn.addEventListener('click', () => {
                uploadInput.click();
            });
             
            uploadInput.addEventListener('change', handleFileUpload);
             
            downloadSelectedBtn.addEventListener('click', () => {
                if (selectedFiles.size === 1) {
                    const filePath = Array.from(selectedFiles)[0];
                    downloadFile(filePath);
                }
            });
             
            remoteDownloadBtn.addEventListener('click', handleRemoteDownload);
            createFolderBtn.addEventListener('click', handleCreateFolder);
            createFileBtn.addEventListener('click', handleCreateFile);
             
            // 文件上传处理
            function handleFileUpload(event) {
                const files = event.target.files;
                if (files.length === 0) return;
                 
                Array.from(files).forEach(file => {
                    // 判断文件大小,大于15MB使用分块上传
                    if (file.size > 15 * 1024 * 1024) {
                        uploadLargeFile(file);
                    } else {
                        uploadSingleFile(file);
                    }
                });
                 
                // 清空input
                uploadInput.value = '';
            }
             
            function uploadSingleFile(file) {
                const formData = new FormData();
                formData.append('action', 'upload_file');
                formData.append('upload_dir', currentPath);
                formData.append('file', file);
                 
                loading.style.display = 'block';
                 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    loading.style.display = 'none';
                     
                    if (data.error) {
                        messageModal.error('上传失败:' + data.error);
                        return;
                    }
                     
                    messageModal.success(data.message, '上传成功').then(() => {
                        loadDirectory(currentPath);
                    });
                })
                .catch(error => {
                    loading.style.display = 'none';
                    messageModal.error('上传时出错: ' + error);
                });
            }
 
            // 大文件分块上传需要分多少M上传在这里设置就行
            function uploadLargeFile(file) {
                const chunkSize = 10 * 1024 * 1024; // 10MB 分块大小 可以分30等等
                const totalChunks = Math.ceil(file.size / chunkSize);
                const fileId = 'upload_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
                 
                messageModal.show({
                    type: 'info',
                    title: '大文件上传',
                    message: `文件大小: ${formatFileSize(file.size)}\n将采用分块上传模式,请耐心等待...`,
                    showCancel: false,
                    okText: '确定'
                }).then(() => {
                    startChunkUpload(file, chunkSize, totalChunks, fileId, 0);
                });
            }
 
            function startChunkUpload(file, chunkSize, totalChunks, fileId, chunkIndex) {
                if (chunkIndex >= totalChunks) {
                    return;
                }
 
                const start = chunkIndex * chunkSize;
                const end = Math.min(start + chunkSize, file.size);
                const chunk = file.slice(start, end);
 
                const formData = new FormData();
                formData.append('action', 'chunk_upload');
                formData.append('upload_dir', currentPath);
                formData.append('fileName', file.name);
                formData.append('fileId', fileId);
                formData.append('chunkIndex', chunkIndex);
                formData.append('totalChunks', totalChunks);
                formData.append('chunk', chunk);
 
                // 显示上传进度
                loading.style.display = 'block';
                const progressText = `上传进度: ${chunkIndex + 1}/${totalChunks} (${Math.round(((chunkIndex + 1) / totalChunks) * 100)}%)`;
                document.querySelector('#loading p').textContent = progressText;
 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.error) {
                        loading.style.display = 'none';
                        messageModal.error('分块上传失败:' + data.error);
                        return;
                    }
 
                    if (data.completed) {
                        // 上传完成
                        loading.style.display = 'none';
                        document.querySelector('#loading p').textContent = '处理中,请稍候...';
                         
                        messageModal.success(data.message + '\n文件大小: ' + formatFileSize(data.size), '上传完成').then(() => {
                            loadDirectory(currentPath);
                        });
                    } else {
                        // 继续上传下一个分块
                        setTimeout(() => {
                            startChunkUpload(file, chunkSize, totalChunks, fileId, chunkIndex + 1);
                        }, 100); // 稍作延迟避免服务器压力
                    }
                })
                .catch(error => {
                    loading.style.display = 'none';
                    document.querySelector('#loading p').textContent = '处理中,请稍候...';
                    messageModal.error('分块上传时出错: ' + error);
                });
            }
             
            // 远程下载处理
            function handleRemoteDownload() {
                inputModal.show({
                    title: '远程下载',
                    label: '请输入下载链接:',
                    placeholder: 'https://example.com/file.zip',
                    icon: '🌐'
                }).then((url) => {
                    if (!url) return;
                     
                    const formData = new FormData();
                    formData.append('action', 'remote_download');
                    formData.append('url', url);
                     
                    loading.style.display = 'block';
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        loading.style.display = 'none';
                         
                        if (data.error) {
                            messageModal.error('下载失败:' + data.error);
                            return;
                        }
                         
                        messageModal.success(data.message, '下载成功').then(() => {
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        loading.style.display = 'none';
                        messageModal.error('下载时出错: ' + error);
                    });
                });
            }
             
            // 创建文件夹处理
            function handleCreateFolder() {
                inputModal.show({
                    title: '新建文件夹',
                    label: '文件夹名称:',
                    placeholder: '新建文件夹',
                    icon: '📁'
                }).then((folderName) => {
                    if (!folderName) return;
                     
                    const formData = new FormData();
                    formData.append('action', 'create_folder');
                    formData.append('current_dir', currentPath);
                    formData.append('folder_name', folderName);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.error) {
                            messageModal.error('创建失败:' + data.error);
                            return;
                        }
                         
                        messageModal.success(data.message, '创建成功').then(() => {
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        messageModal.error('创建时出错: ' + error);
                    });
                });
            }
             
            // 创建文件处理
            function handleCreateFile() {
                inputModal.show({
                    title: '新建文件',
                    label: '文件名称:',
                    placeholder: 'newfile.txt',
                    icon: '📄'
                }).then((fileName) => {
                    if (!fileName) return;
                     
                    const formData = new FormData();
                    formData.append('action', 'create_file');
                    formData.append('current_dir', currentPath);
                    formData.append('file_name', fileName);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.error) {
                            messageModal.error('创建失败:' + data.error);
                            return;
                        }
                         
                        messageModal.success(data.message, '创建成功').then(() => {
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        messageModal.error('创建时出错: ' + error);
                    });
                });
            }
             
            // 更新下载按钮状态
            function updateDownloadButtonState() {
                if (selectedFiles.size === 1) {
                    const filePath = Array.from(selectedFiles)[0];
                    // 检查是否为文件(非目录)
                    const fileItem = document.querySelector(`[data-path="${filePath}"]`);
                    const isDir = fileItem ? fileItem.getAttribute('data-is-dir') === 'true' : false;
                     
                    downloadSelectedBtn.disabled = isDir;
                    downloadSelectedBtn.textContent = isDir ? '📥 下载选中 (目录请用压缩)' : '📥 下载选中';
                } else {
                    downloadSelectedBtn.disabled = true;
                    downloadSelectedBtn.textContent = '📥 下载选中';
                }
            }
             
            // 隐藏右键菜单
            function hideContextMenu() {
                contextMenu.style.display = 'none';
            }
             
            // 显示右键菜单
            function showContextMenu(e, path, isDir) {
                e.preventDefault();
                currentSelectedPath = path;
                currentSelectedIsDir = isDir;
                 
                // 设置菜单项状态
                compressItem.classList.remove('disabled');
                deleteItem.classList.remove('disabled');
                moveItem.classList.remove('disabled');
                 
                // 检查是否为压缩文件
                const fileName = path.split(/[\/]/).pop();
                const ext = getFileExtension(fileName);
                const archiveExts = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz'];
                const isArchive = !isDir && archiveExts.includes(ext);
                 
                if (isArchive) {
                    extractItem.classList.remove('disabled');
                    if (ext === 'zip') {
                        extractItem.textContent = '📂 解压';
                    } else {
                        extractItem.textContent = `📂 解压 (仅支持ZIP)`;
                        extractItem.classList.add('disabled');
                    }
                } else {
                    extractItem.classList.add('disabled');
                    extractItem.textContent = '📂 解压 (非压缩文件)';
                }
                 
                if (isDir) {
                    downloadItem.classList.add('disabled');
                    downloadItem.textContent = '⬇️ 下载 (目录请用压缩)';
                    editItem.classList.add('disabled');
                    editItem.textContent = '📝 编辑 (不支持目录)';
                } else {
                    downloadItem.classList.remove('disabled');
                    downloadItem.textContent = '⬇️ 下载';
                     
                    // 检查是否为可编辑的文件类型
                    const editableExts = ['txt', 'html', 'htm', 'css', 'js', 'php', 'py', 'java', 'cpp', 'c', 'cs', 'xml', 'json', 'md', 'log', 'sql', 'ini', 'conf', 'yaml', 'yml'];
                     
                    if (editableExts.includes(ext)) {
                        editItem.classList.remove('disabled');
                        editItem.textContent = '📝 编辑';
                    } else {
                        editItem.classList.add('disabled');
                        editItem.textContent = '📝 编辑 (不支持此格式)';
                    }
                }
                 
                // 先显示菜单以获取其尺寸
                contextMenu.style.display = 'block';
                contextMenu.style.visibility = 'hidden';
                 
                // 获取菜单尺寸和视窗尺寸
                const menuWidth = contextMenu.offsetWidth;
                const menuHeight = contextMenu.offsetHeight;
                const windowWidth = window.innerWidth;
                const windowHeight = window.innerHeight;
                 
                // 计算菜单位置
                let left = e.clientX + 10; // 鼠标右侧10px
                let top = e.clientY - 10;  // 鼠标位置稍微向上
                 
                // 防止菜单超出右边界
                if (left + menuWidth > windowWidth) {
                    left = e.clientX - menuWidth - 10; // 显示在鼠标左侧
                }
                 
                // 防止菜单超出下边界
                if (top + menuHeight > windowHeight) {
                    top = windowHeight - menuHeight - 10;
                }
                 
                // 防止菜单超出上边界
                if (top < 0) {
                    top = 10;
                }
                 
                // 防止菜单超出左边界
                if (left < 0) {
                    left = 10;
                }
                 
                // 设置最终位置并显示菜单
                contextMenu.style.left = left + 'px';
                contextMenu.style.top = top + 'px';
                contextMenu.style.visibility = 'visible';
            }
             
            // 点击其他地方隐藏菜单
            document.addEventListener('click', hideContextMenu);
             
            // 右键菜单项点击事件
            compressItem.addEventListener('click', function() {
                if (currentSelectedPath) {
                    compressFile(currentSelectedPath);
                }
                hideContextMenu();
            });
 
            extractItem.addEventListener('click', function() {
                if (currentSelectedPath && !currentSelectedIsDir && !extractItem.classList.contains('disabled')) {
                    extractArchive(currentSelectedPath);
                }
                hideContextMenu();
            });
             
            downloadItem.addEventListener('click', function() {
                if (currentSelectedPath && !currentSelectedIsDir) {
                    downloadFile(currentSelectedPath);
                }
                hideContextMenu();
            });
             
            editItem.addEventListener('click', function() {
                if (currentSelectedPath && !currentSelectedIsDir && !editItem.classList.contains('disabled')) {
                    editFile(currentSelectedPath);
                }
                hideContextMenu();
            });
 
            moveItem.addEventListener('click', function() {
                if (currentSelectedPath) {
                    showMoveDialog(currentSelectedPath, currentSelectedIsDir);
                }
                hideContextMenu();
            });
             
            deleteItem.addEventListener('click', function() {
                if (currentSelectedPath) {
                    deleteItem_func(currentSelectedPath, currentSelectedIsDir);
                }
                hideContextMenu();
            });
             
            // 编辑弹窗事件
            editModalClose.addEventListener('click', closeEditModal);
            cancelEditBtn.addEventListener('click', closeEditModal);
            saveFileBtn.addEventListener('click', saveFile);
 
             // 目录选择弹窗事件
            directoryModalClose.addEventListener('click', closeMoveDialog);
            cancelMoveBtn.addEventListener('click', closeMoveDialog);
            confirmMoveBtn.addEventListener('click', performMove);
             
            // 添加键盘快捷键支持
            document.addEventListener('keydown', function(e) {
                // ESC键关闭模态框
                if (e.key === 'Escape' && editModal.style.display === 'block') {
                    e.preventDefault();
                    closeEditModal();
                }
                 
                // ESC键关闭移动对话框
                if (e.key === 'Escape' && directoryModal.style.display === 'block') {
                    e.preventDefault();
                    closeMoveDialog();
                }
                 
                // Ctrl+S保存文件
                if (e.ctrlKey && e.key === 's' && editModal.style.display === 'block') {
                    e.preventDefault();
                    saveFile();
                }
            });
             
            // 点击弹窗外部关闭
            editModal.addEventListener('click', function(e) {
                if (e.target === editModal) {
                    closeEditModal();
                }
            });
 
             // 点击目录选择弹窗外部关闭
            directoryModal.addEventListener('click', function(e) {
                if (e.target === directoryModal) {
                    closeMoveDialog();
                }
            });
             
            // 为文本框添加Tab键支持(插入4个空格)
            fileContent.addEventListener('keydown', function(e) {
                if (e.key === 'Tab') {
                    e.preventDefault();
                    const start = this.selectionStart;
                    const end = this.selectionEnd;
                     
                    // 插入4个空格
                    this.value = this.value.substring(0, start) + '    ' + this.value.substring(end);
                     
                    // 移动光标
                    this.selectionStart = this.selectionEnd = start + 4;
                }
            });
            // 解压文件
            function extractArchive(path) {
                const fileName = path.split(/[\/]/).pop();
                 
                messageModal.confirm(
                    `确定要解压文件 "${fileName}" 吗?\n\n文件将被解压到当前目录中,如果存在同名文件夹会自动重命名。`,
                    '确认解压',
                    'confirm'
                ).then((confirmed) => {
                    if (!confirmed) return;
                     
                    loading.style.display = 'block';
                    status.style.display = 'none';
                     
                    const formData = new FormData();
                    formData.append('action', 'extract_archive');
                    formData.append('path', path);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        loading.style.display = 'none';
                         
                        if (data.error) {
                            messageModal.error('解压失败:' + data.error);
                            return;
                        }
                         
                        // 显示详细的解压结果
                        let resultMessage = data.message;
                        if (data.errors && data.errors.length > 0) {
                            messageModal.warning(resultMessage, '解压完成(部分文件失败)').then(() => {
                                loadDirectory(currentPath);
                            });
                        } else {
                            messageModal.success(resultMessage, '解压成功').then(() => {
                                loadDirectory(currentPath);
                            });
                        }
                    })
                    .catch(error => {
                        loading.style.display = 'none';
                        messageModal.error('解压时出错: ' + error);
                    });
                });
            }
            // 压缩文件/目录
            function compressFile(path) {
                loading.style.display = 'block';
                status.style.display = 'none';
                 
                const formData = new FormData();
                formData.append('action', 'compress_single');
                formData.append('path', path);
                 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    loading.style.display = 'none';
                     
                    if (data.error) {
                        messageModal.error(data.error);
                        return;
                    }
                     
                    messageModal.success(data.message).then(() => {
                        // 刷新当前目录以显示新创建的压缩文件
                        loadDirectory(currentPath);
                    });
                })
                .catch(error => {
                    loading.style.display = 'none';
                    messageModal.error('压缩时出错: ' + error);
                });
            }
             // 显示移动对话框
            function showMoveDialog(sourcePath, isDir) {
                moveSourcePath = sourcePath;
                moveSourceIsDir = isDir;
                selectedMoveTarget = '';
                 
                const fileName = sourcePath.split(/[\/]/).pop();
                const itemType = isDir ? '文件夹' : '文件';
                directoryModalTitle.textContent = `移动${itemType}: ${fileName}`;
                selectedTargetPath.textContent = '未选择';
                confirmMoveBtn.disabled = true;
                 
                // 显示模态框
                directoryModal.style.display = 'block';
                document.body.style.overflow = 'hidden';
                 
                // 加载目录树
                loadDirectoryTree();
                 
                // 聚焦到模态框
                setTimeout(() => {
                    directoryModal.focus();
                }, 100);
            }
             
            // 加载目录树
            function loadDirectoryTree() {
                directoryTree.innerHTML = `
                    <div class="loading-tree">
                        <div class="spinner"></div>
                        <p>正在加载目录树...</p>
                    </div>
                `;
                 
                const formData = new FormData();
                formData.append('action', 'get_directory_tree');
                formData.append('root_dir', '<?php echo $basePath; ?>');
                 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.error) {
                        directoryTree.innerHTML = `
                            <div style="text-align: center; padding: 20px; color: #ff4d4f;">
                                <p>❌ 加载目录树失败</p>
                                <p>${data.error}</p>
                            </div>
                        `;
                        return;
                    }
                     
                    renderDirectoryTree(data.tree, data.root_path);
                })
                .catch(error => {
                    directoryTree.innerHTML = `
                        <div style="text-align: center; padding: 20px; color: #ff4d4f;">
                            <p>❌ 加载目录树时出错</p>
                            <p>${error}</p>
                        </div>
                    `;
                });
            }
             
            // 渲染目录树
            function renderDirectoryTree(tree, rootPath) {
                // 添加根目录选项
                let html = `
                    <div class="tree-node">
                        <div class="tree-item" data-path="${rootPath}" data-level="0">
                            <span class="tree-toggle no-children">📁</span>
                            <span class="tree-icon">🏠</span>
                            <span class="tree-name">根目录</span>
                        </div>
                    </div>
                `;
                 
                // 递归渲染子目录
                html += renderTreeNodes(tree, 1);
                 
                directoryTree.innerHTML = html;
                 
                // 添加点击事件
                directoryTree.querySelectorAll('.tree-item').forEach(item => {
                    const path = item.getAttribute('data-path');
                     
                    item.addEventListener('click', function(e) {
                        e.stopPropagation();
                         
                        // 移除所有选中状态
                        directoryTree.querySelectorAll('.tree-item').forEach(i => i.classList.remove('selected'));
                         
                        // 选中当前项
                        this.classList.add('selected');
                        selectedMoveTarget = path;
                         
                        // 显示相对路径
                        const basePath = '<?php echo $basePath; ?>';
                        const relativePath = path === basePath ? '根目录' : path.replace(basePath, '').replace(/^[\/]+/, '');
                        selectedTargetPath.textContent = relativePath || '根目录';
                         
                        // 检查是否可以移动(防止移动到自身或子目录)
                        let canMove = true;
                         
                        if (moveSourceIsDir && path !== moveSourcePath) {
                            // 检查是否试图移动到自身的子目录
                            if (path.startsWith(moveSourcePath + '/') || path.startsWith(moveSourcePath + '\')) {
                                canMove = false;
                            }
                        }
                         
                        // 不能移动到自身
                        if (path === moveSourcePath) {
                            canMove = false;
                        }
                         
                        confirmMoveBtn.disabled = !canMove;
                         
                        if (!canMove) {
                            selectedTargetPath.innerHTML = `<span style="color: #ff4d4f;">${relativePath || '根目录'} (不能移动到此位置)</span>`;
                        }
                    });
                });
                 
                // 添加展开/折叠功能
                directoryTree.querySelectorAll('.tree-toggle:not(.no-children)').forEach(toggle => {
                    toggle.addEventListener('click', function(e) {
                        e.stopPropagation();
                         
                        const treeNode = this.closest('.tree-node');
                        const children = treeNode.querySelector('.tree-children');
                         
                        if (children) {
                            const isExpanded = children.classList.contains('expanded');
                             
                            if (isExpanded) {
                                children.classList.remove('expanded');
                                this.classList.remove('expanded');
                            } else {
                                children.classList.add('expanded');
                                this.classList.add('expanded');
                            }
                        }
                    });
                });
            }
             
            // 递归渲染树节点
            function renderTreeNodes(nodes, level) {
                if (!nodes || nodes.length === 0) return '';
                 
                return nodes.map(node => {
                    const hasChildren = node.children && node.children.length > 0;
                    const toggleClass = hasChildren ? 'tree-toggle' : 'tree-toggle no-children';
                    const childrenHtml = hasChildren ? `
                        <div class="tree-children">
                            ${renderTreeNodes(node.children, level + 1)}
                        </div>
                    ` : '';
                     
                    return `
                        <div class="tree-node">
                            <div class="tree-item" data-path="${node.path}" data-level="${level}">
                                <span class="${toggleClass}">▶</span>
                                <span class="tree-icon">📁</span>
                                <span class="tree-name">${node.name}</span>
                            </div>
                            ${childrenHtml}
                        </div>
                    `;
                }).join('');
            }
             
            // 执行移动操作
            function performMove() {
                if (!selectedMoveTarget || !moveSourcePath) return;
                 
                const fileName = moveSourcePath.split(/[\/]/).pop();
                const itemType = moveSourceIsDir ? '文件夹' : '文件';
                 
                messageModal.confirm(
                    `确定要将${itemType} "${fileName}" 移动到选中的目录吗?\n\n如果目标位置存在同名文件,系统会自动重命名。`,
                    '确认移动',
                    'confirm'
                ).then((confirmed) => {
                    if (!confirmed) return;
                     
                    confirmMoveBtn.disabled = true;
                    confirmMoveBtn.innerHTML = '<span class="message-loading"></span>移动中...';
                     
                    const formData = new FormData();
                    formData.append('action', 'move_item');
                    formData.append('source_path', moveSourcePath);
                    formData.append('target_dir', selectedMoveTarget);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        confirmMoveBtn.disabled = false;
                        confirmMoveBtn.innerHTML = '✂️ 移动到此位置';
                         
                        if (data.error) {
                            messageModal.error('移动失败:' + data.error);
                            return;
                        }
                         
                        messageModal.success(data.message, '移动成功').then(() => {
                            closeMoveDialog();
                            // 刷新当前目录
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        confirmMoveBtn.disabled = false;
                        confirmMoveBtn.innerHTML = '✂️ 移动到此位置';
                        messageModal.error('移动时出错: ' + error);
                    });
                });
            }
             
            // 关闭移动对话框
            function closeMoveDialog() {
                directoryModal.style.display = 'none';
                document.body.style.overflow = 'auto';
                selectedMoveTarget = '';
                moveSourcePath = '';
                moveSourceIsDir = false;
                selectedTargetPath.textContent = '未选择';
                confirmMoveBtn.disabled = true;
                confirmMoveBtn.innerHTML = '✂️ 移动到此位置';
            }
             
            // 下载文件
            function downloadFile(path) {
                messageModal.success('正在准备下载...');
                 
                // 创建隐藏表单进行下载
                const form = document.createElement('form');
                form.method = 'POST';
                form.action = '';
                form.style.display = 'none';
                 
                const actionInput = document.createElement('input');
                actionInput.type = 'hidden';
                actionInput.name = 'action';
                actionInput.value = 'download_single';
                 
                const pathInput = document.createElement('input');
                pathInput.type = 'hidden';
                pathInput.name = 'path';
                pathInput.value = path;
                 
                form.appendChild(actionInput);
                form.appendChild(pathInput);
                document.body.appendChild(form);
                 
                // 提交表单开始下载
                form.submit();
                 
                // 清理表单
                setTimeout(() => {
                    if (document.body.contains(form)) {
                        document.body.removeChild(form);
                    }
                    messageModal.success('下载已开始...');
                }, 1000);
            }
             
            // 编辑文件
            function editFile(path) {
                const fileName = path.split(/[\/]/).pop();
                editFileName.textContent = `编辑文件: ${fileName}`;
                fileContent.value = '正在加载文件内容,请稍候...';
                fileContent.disabled = true;
                 
                // 显示模态框
                editModal.style.display = 'block';
                document.body.style.overflow = 'hidden'; // 防止背景滚动
                 
                // 聚焦到模态框
                setTimeout(() => {
                    editModal.focus();
                }, 100);
                 
                const formData = new FormData();
                formData.append('action', 'read_file');
                formData.append('path', path);
                 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.error) {
                        messageModal.error('读取文件失败:' + data.error).then(() => {
                            closeEditModal();
                        });
                        return;
                    }
                     
                    fileContent.value = data.content;
                    fileContent.disabled = false;
                     
                    // 添加文件信息显示
                    const fileInfo = `文件大小: ${formatFileSize(data.size)} | 编码: UTF-8`;
                    editFileName.textContent = `编辑文件: ${fileName} (${fileInfo})`;
                     
                    // 聚焦到文本框
                    setTimeout(() => {
                        fileContent.focus();
                        fileContent.setSelectionRange(0, 0); // 光标移到开始
                    }, 100);
                })
                .catch(error => {
                    messageModal.error('读取文件时出错: ' + error).then(() => {
                        closeEditModal();
                    });
                });
            }
             
            // 保存文件
            function saveFile() {
                if (!currentSelectedPath) return;
                 
                // 确认保存
                messageModal.confirm('确定要保存文件吗?\n注意:保存前会自动创建备份文件。', '确认保存').then((confirmed) => {
                    if (!confirmed) return;
                     
                    saveFileBtn.disabled = true;
                    saveFileBtn.innerHTML = '<span class="message-loading"></span>保存中...';
                     
                    const formData = new FormData();
                    formData.append('action', 'save_file');
                    formData.append('path', currentSelectedPath);
                    formData.append('content', fileContent.value);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        saveFileBtn.disabled = false;
                        saveFileBtn.innerHTML = '💾 保存';
                         
                        if (data.error) {
                            messageModal.error('保存失败:' + data.error);
                            return;
                        }
                         
                                                // 使用美化的成功消息
                        messageModal.success(`${data.message}\n已写入 ${data.bytes_written} 字节`, '保存成功').then(() => {
                            closeEditModal();
                            // 刷新当前目录
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        saveFileBtn.disabled = false;
                        saveFileBtn.innerHTML = '💾 保存';
                        messageModal.error('保存时出错: ' + error);
                    });
                });
            }
             
            // 关闭编辑弹窗
            function closeEditModal() {
                // 检查是否有未保存的更改
                if (fileContent.value && !fileContent.disabled) {
                    messageModal.confirm('有未保存的更改,确定要关闭吗?', '确认关闭').then((confirmed) => {
                        if (confirmed) {
                            performCloseModal();
                        }
                    });
                } else {
                    performCloseModal();
                }
            }
             
            // 执行关闭模态框
            function performCloseModal() {
                editModal.style.display = 'none';
                document.body.style.overflow = 'auto'; // 恢复背景滚动
                fileContent.value = '';
                fileContent.disabled = false;
                currentSelectedPath = '';
                editFileName.textContent = '编辑文件';
            }
             
            // 格式化文件大小
            function formatFileSize(bytes) {
                if (bytes === 0) return '0 字节';
                const k = 1024;
                const sizes = ['字节', 'KB', 'MB', 'GB'];
                const i = Math.floor(Math.log(bytes) / Math.log(k));
                return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
            }
             
            // 删除文件/目录
            function deleteItem_func(path, isDir) {
                const fileName = path.split(/[\/]/).pop();
                const itemType = isDir ? '目录' : '文件';
                 
                const message = `确定要删除${itemType} "${fileName}" 吗?${isDir ? '\n注意:这将删除目录及其所有内容!' : ''}`;
                 
                messageModal.confirm(message, '确认删除', 'warning').then((confirmed) => {
                    if (!confirmed) return;
                     
                    loading.style.display = 'block';
                    status.style.display = 'none';
                     
                    const formData = new FormData();
                    formData.append('action', 'delete_item');
                    formData.append('path', path);
                     
                    fetch('', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(data => {
                        loading.style.display = 'none';
                         
                        if (data.error) {
                            messageModal.error('删除失败:' + data.error);
                            return;
                        }
                         
                        messageModal.success(data.message, '删除成功').then(() => {
                            // 刷新当前目录
                            loadDirectory(currentPath);
                        });
                    })
                    .catch(error => {
                        loading.style.display = 'none';
                        messageModal.error('删除时出错: ' + error);
                    });
                });
            }
             
            // 加载目录内容
            function loadDirectory(path) {
                loading.style.display = 'block';
                 
                const formData = new FormData();
                formData.append('action', 'list_dir');
                formData.append('dir', path);
                 
                fetch('', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    loading.style.display = 'none';
                     
                    if (data.error) {
                        messageModal.error(data.error);
                        return;
                    }
                     
                    currentPath = data.current_dir;
                    selectedFiles.clear();
                    updateDownloadButtonState();
                    updateBreadcrumb(currentPath);
                    renderFileList(data.files);
                })
                .catch(error => {
                    loading.style.display = 'none';
                    messageModal.error('加载目录时出错: ' + error);
                });
            }
             
            // 更新面包屑导航
            function updateBreadcrumb(path) {
                const basePath = '<?php echo $basePath; ?>';
                const parts = path.replace(basePath, '').split(/[\/]/).filter(part => part !== '');
                 
                let html = `<span class="breadcrumb-item" data-path="${basePath}">根目录</span>`;
                let current = basePath;
                 
                for (const part of parts) {
                    current += '/' + part;
                    html += `<span class="breadcrumb-separator">/</span>
                             <span class="breadcrumb-item" data-path="${current}">${part}</span>`;
                }
                 
                breadcrumb.innerHTML = html;
                 
                // 添加面包屑点击事件
                breadcrumb.querySelectorAll('.breadcrumb-item').forEach(item => {
                    item.addEventListener('click', function() {
                        const targetPath = this.getAttribute('data-path');
                        loadDirectory(targetPath);
                    });
                });
            }
             
            // 渲染文件列表
            function renderFileList(files) {
                if (files.length === 0) {
                    fileList.innerHTML = '<li style="text-align: center; color: #999; padding: 40px;">此目录为空</li>';
                    return;
                }
                 
                const fileItems = files.map(file => {
                    const icon = file.is_dir ? '📁' : getFileIcon(file.name);
                    const sizeText = file.is_dir ? '' : formatFileSize(file.size || 0);
                    const itemClass = file.is_dir ? 'directory' : '';
                     
                    return `
                        <li class="file-item ${itemClass}" data-path="${file.path}" data-is-dir="${file.is_dir}">
                            <span class="file-icon">${icon}</span>
                            <span class="file-name">${file.name}</span>
                            <span class="file-size">${sizeText}</span>
                        </li>
                    `;
                }).join('');
                 
                fileList.innerHTML = fileItems;
                 
                // 添加文件项事件监听
                fileList.querySelectorAll('.file-item').forEach(item => {
                    const path = item.getAttribute('data-path');
                    const isDir = item.getAttribute('data-is-dir') === 'true';
                     
                    // 单击选中文件
                    item.addEventListener('click', function(e) {
                        // 清除其他选中状态
                        fileList.querySelectorAll('.file-item').forEach(i => i.classList.remove('selected'));
                         
                        // 选中当前项
                        this.classList.add('selected');
                        selectedFiles.clear();
                        selectedFiles.add(path);
                        updateDownloadButtonState();
                    });
                     
                    // 双击进入目录
                    item.addEventListener('dblclick', function() {
                        if (isDir) {
                            loadDirectory(path);
                        }
                    });
                     
                    // 右键菜单
                    item.addEventListener('contextmenu', function(e) {
                        showContextMenu(e, path, isDir);
                    });
                });
            }
             
            // 获取文件扩展名
            function getFileExtension(fileName) {
                return fileName.split('.').pop().toLowerCase();
            }
             
            // 获取文件图标
            function getFileIcon(fileName) {
                const ext = getFileExtension(fileName);
                 
                const iconMap = {
                    // 文档类
                    'txt': '📄', 'doc': '📄', 'docx': '📄', 'pdf': '📕',
                    'rtf': '📄', 'odt': '📄',
                     
                    // 表格类
                    'xls': '📊', 'xlsx': '📊', 'csv': '📊', 'ods': '📊',
                     
                    // 演示文稿
                    'ppt': '📊', 'pptx': '📊', 'odp': '📊',
                     
                    // 图像类
                    'jpg': '🖼️', 'jpeg': '🖼️', 'png': '🖼️', 'gif': '🖼️',
                    'bmp': '🖼️', 'svg': '🖼️', 'ico': '🖼️', 'webp': '🖼️',
                    'tiff': '🖼️', 'tif': '🖼️',
                     
                    // 音频类
                    'mp3': '🎵', 'wav': '🎵', 'flac': '🎵', 'aac': '🎵',
                    'ogg': '🎵', 'm4a': '🎵', 'wma': '🎵',
                     
                    // 视频类
                    'mp4': '🎬', 'avi': '🎬', 'mkv': '🎬', 'mov': '🎬',
                    'wmv': '🎬', 'flv': '🎬', 'webm': '🎬', '3gp': '🎬',
                     
                    // 压缩文件
                    'zip': '📦', 'rar': '📦', '7z': '📦', 'tar': '📦',
                    'gz': '📦', 'bz2': '📦', 'xz': '📦',
                     
                    // 代码文件
                    'html': '🌐', 'htm': '🌐', 'css': '🎨', 'js': '⚡',
                    'php': '🐘', 'py': '🐍', 'java': '☕', 'cpp': '⚙️',
                    'c': '⚙️', 'cs': '⚙️', 'go': '🐹', 'rs': '🦀',
                    'rb': '💎', 'swift': '🦉', 'kt': '🎯',
                     
                    // 配置文件
                    'json': '📋', 'xml': '📋', 'yaml': '📋', 'yml': '📋',
                    'ini': '⚙️', 'conf': '⚙️', 'cfg': '⚙️',
                     
                    // 数据库
                    'sql': '🗃️', 'db': '🗃️', 'sqlite': '🗃️',
                     
                    // 日志文件
                    'log': '📜',
                     
                    // 字体文件
                    'ttf': '🔤', 'otf': '🔤', 'woff': '🔤', 'woff2': '🔤',
                     
                    // 可执行文件
                    'exe': '⚡', 'msi': '⚡', 'deb': '⚡', 'rpm': '⚡',
                    'dmg': '⚡', 'app': '⚡',
                     
                    // 其他常见格式
                    'md': '📝', 'readme': '📖', 'license': '📜',
                    'gitignore': '🚫', 'htaccess': '⚙️'
                };
                 
                return iconMap[ext] || '📄';
            }
             
            // 显示状态消息
            function showStatus(message, type = 'success') {
                status.textContent = message;
                status.className = `status ${type}`;
                status.style.display = 'block';
                 
                // 3秒后自动隐藏
                setTimeout(() => {
                    status.style.display = 'none';
                }, 3000);
            }
             
            // 初始加载
            loadDirectory(currentPath);
        });
    </script>
</body>
</html>
© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容