<?php
require_once __DIR__ . '/../MPHX/common.php';

// 确保用户已登录
$user = check_user();
if (!$user) {
    header('Location: /user/login.php');
    exit;
}

// 获取系统配置中的建站目录（使用$GLOBALS获取全局变量）
$conf = isset($GLOBALS['conf']) ? $GLOBALS['conf'] : null;
if (!$conf) {
    $conf = $DB->get_row("SELECT * FROM `config` WHERE `id`=1");
}
$linux_path = isset($conf['hxi']) && !empty($conf['hxi']) ? $conf['hxi'] : '/www/wwwroot';
$windows_path = isset($conf['hxo']) && !empty($conf['hxo']) ? $conf['hxo'] : 'D:/wwwroot';

// 获取当前用户的宝塔服务器信息，判断操作系统类型
$bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$user['btid']}'");
$os_type = isset($bt['czzt']) ? $bt['czzt'] : 'Linux';

// 根据操作系统选择建站目录
$site_root = ($os_type == 'Linux' ? $linux_path : $windows_path) . '/' . $user['user'];
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo L('file_manager', 'menu'); ?></title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/all.min.css">
    <style>
        html, body {
            overflow-y: auto;
        }
        :root {
            --bt-green: #20a53a;
            --bt-green-hover: #1d9534;
            --bt-green-bg: #f1f9f3;
            --bt-border: #e4e7ed;
            --bt-text: #606266;
            --bt-head-bg: #f6f6f6;
        }

        body {
            background: #f5f7fa;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei', Arial, sans-serif;
        font-size: 13px;
            color: #333;
            padding: 15px;
        }

        .bt-file-body {
            min-width: 900px;
            background: #fff;
            border-radius: 4px;
            border: 1px solid var(--bt-border);
            box-shadow: 0 1px 3px rgba(0,0,0,.08);
            display: flex;
            flex-direction: column;
            height: calc(100vh - 120px);
        }

        .bt-path-row {
        display: flex;
        align-items: center;
            padding: 8px 12px;
            border-bottom: 1px solid var(--bt-border);
            background: #fff;
        gap: 8px;
        }
        .bt-path-back,
        .bt-path-refresh {
            width: 32px;
            height: 32px;
            border: 1px solid var(--bt-border);
            background: #fff;
            border-radius: 2px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            color: var(--bt-text);
        }
        .bt-path-back:hover,
        .bt-path-refresh:hover {
            background: var(--bt-green-bg);
            color: var(--bt-green);
            border-color: #bce4c4;
        }
        .bt-path-input-wrap {
            flex: 1;
            min-width: 200px;
            position: relative;
        }
        .bt-path-input {
        width: 100%;
            height: 32px;
            padding: 0 10px;
            border: 1px solid var(--bt-border);
            border-radius: 2px;
        font-size: 12px;
        }
        .bt-path-input:focus {
            outline: none;
            border-color: var(--bt-green);
        }
        .bt-search-wrap {
        display: flex;
            height: 32px;
            border: 1px solid var(--bt-border);
            border-radius: 2px;
            overflow: hidden;
        }
        .bt-search-wrap input {
            width: 180px;
            padding: 0 10px;
            border: none;
        font-size: 12px;
        }
        .bt-search-wrap input:focus { outline: none; }
        .bt-search-wrap button {
            width: 36px;
        border: none;
            border-left: 1px solid var(--bt-border);
            background: var(--bt-green-bg);
            color: var(--bt-green);
        cursor: pointer;
        }
        .bt-search-wrap button:hover { background: #bce4c4; }

        .bt-nav-row {
        display: flex;
        align-items: center;
            padding: 8px 12px;
            border-bottom: 1px solid var(--bt-border);
            background: #fafafa;
            flex-wrap: wrap;
            gap: 6px;
        }
        .bt-nav-btn {
            height: 30px;
            padding: 0 12px;
            border: 1px solid var(--bt-border);
        background: #fff;
            border-radius: 2px;
            font-size: 12px;
            color: var(--bt-text);
        cursor: pointer;
            display: inline-flex;
            align-items: center;
            gap: 6px;
        }
        .bt-nav-btn:hover {
            background: var(--bt-green-bg);
            color: var(--bt-green);
            border-color: #bce4c4;
        }
        .bt-nav-btn.primary {
            background: var(--bt-green-bg);
            color: var(--bt-green);
            border-color: var(--bt-green);
        }
        .bt-nav-btn.primary:hover {
            background: #bce4c4;
        }
        .bt-nav-dropdown {
            position: relative;
            display: inline-block;
        }
        .bt-nav-dropdown > ul {
            display: none;
            position: absolute;
            top: 100%;
            left: 0;
            margin: 2px 0 0;
            padding: 4px 0;
            min-width: 140px;
            background: #fff;
            border: 1px solid var(--bt-border);
            border-radius: 2px;
            box-shadow: 0 2px 12px rgba(0,0,0,.1);
            z-index: 1000;
            list-style: none;
        }
        .bt-nav-dropdown.show > ul {
            display: block;
        }
        .bt-nav-dropdown > button {
            position: relative;
            z-index: 1;
        }
        .bt-nav-dropdown li {
            padding: 8px 16px;
            font-size: 12px;
        cursor: pointer;
            color: var(--bt-text);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .bt-nav-dropdown li:hover {
            background: var(--bt-green-bg);
            color: var(--bt-green);
        }
        .bt-nav-dropdown li.sep {
            height: 1px;
            padding: 0;
            margin: 4px 0;
            background: #e9ecef;
            pointer-events: none;
        }
        .bt-nav-tip {
        margin-left: auto;
        font-size: 12px;
            color: #909399;
        }
        .bt-paste-badge {
            margin-left: 4px;
            background: var(--bt-green);
            color: #fff;
            padding: 0 6px;
            border-radius: 10px;
            font-size: 11px;
        }

        .bt-table-wrap { 
            overflow: auto; 
            flex: 1;
        }
        .bt-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 12px;
        }
        .bt-table thead { background: var(--bt-head-bg); }
        .bt-table th {
            padding: 8px 10px;
            text-align: left;
        font-weight: 500;
            color: var(--bt-text);
            border-bottom: 1px solid var(--bt-border);
            white-space: nowrap;
        }
        .bt-table th.th-check { width: 40px; text-align: center; }
        .bt-table th.th-name { min-width: 260px; }
        .bt-table th.th-perm { width: 120px; }
        .bt-table th.th-size { width: 110px; }
        .bt-table th.th-time { width: 170px; }
        .bt-table th.th-op { width: 120px; text-align: right; }
        .bt-table td {
            padding: 8px 10px;
            border-bottom: 1px solid #f0f0f0;
            color: var(--bt-text);
            vertical-align: middle;
        }
        .bt-table tbody tr { cursor: pointer; }
        .bt-table tbody tr:hover { background: #f0f9f4; }
        .bt-table tbody tr.selected { background: #e8f5ec; }
        .bt-table .td-check { text-align: center; width: 40px; }
        .bt-table .td-name { display: flex; align-items: center; gap: 8px; }
        .bt-table .td-name i { font-size: 16px; width: 20px; text-align: center; }
        .bt-table .td-name .file-name { cursor: pointer; }
        
        /* 文件类型颜色编码 - 遵循行业通用标准 */
        /* 文件夹 - 橙色/琥珀色 */
        .bt-table .td-name i.file-type-folder { color: #FF9800; }
        /* 压缩包 - 紫色 */
        .bt-table .td-name i.file-type-archive { color: #9C27B0; }
        /* 文档文件 - 蓝色 */
        .bt-table .td-name i.file-type-document { color: #2196F3; }
        /* 图片文件 - 绿色 */
        .bt-table .td-name i.file-type-image { color: #4CAF50; }
        /* 普通文件 - 灰色 */
        .bt-table .td-name i.file-type-default { color: #757575; }
        /* 代码文件 - 青色 */
        .bt-table .td-name i.file-type-code { color: #00BCD4; }
        .bt-table .td-op { text-align: right; white-space: nowrap; }
        .bt-table .op-link {
            margin-left: 6px;
            color: #409EFF;
            text-decoration: none;
            font-size: 12px;
            opacity: 0;
            transition: opacity .15s;
        }
        .bt-table .op-link:hover { text-decoration: underline; }
        .bt-table tbody tr:hover .td-op .op-link,
        .bt-table tbody tr.selected .td-op .op-link {
            opacity: 1;
        }
        .bt-loading,
        .bt-empty {
        text-align: center;
            padding: 40px 16px;
            color: #909399;
    }
        .bt-loading i,
        .bt-empty i {
        font-size: 32px;
        display: block;
        margin-bottom: 8px;
            color: #c0c4cc;
        }

        .bt-ctx-menu {
        position: fixed;
        background: #fff;
            border: 1px solid var(--bt-border);
            border-radius: 2px;
            box-shadow: 0 2px 12px rgba(0,0,0,.12);
            padding: 4px 0;
        min-width: 160px;
            z-index: 9999;
        display: none;
            font-size: 12px;
        }
        .bt-ctx-menu li {
            padding: 8px 20px;
        cursor: pointer;
            list-style: none;
        display: flex;
        align-items: center;
        gap: 8px;
            color: var(--bt-text);
        }
        .bt-ctx-menu li:hover {
            background: var(--bt-green-bg);
            color: var(--bt-green);
        }
        .bt-ctx-menu li.sep {
            height: 1px;
            padding: 0;
            margin: 4px 0;
            background: var(--bt-border);
        }
        .bt-ctx-menu li.danger:hover {
            color: #f56c6c;
            background: #fef0f0;
        }

        .bt-modal .modal-dialog { max-width: 500px; }
        #modalSearchContent .modal-dialog { max-width: 1100px; }
        #modalSearchContent .custom-control-input:checked ~ .custom-control-label::before {
            background-color: var(--bt-green);
            border-color: var(--bt-green);
        }
        #modalSearchContent .custom-control-label::before { border-radius: 3px; }
        #modalSearchContent .btn-success {
            background: var(--bt-green);
            border-color: var(--bt-green);
        }
        #modalSearchContent .btn-success:hover {
            background: var(--bt-green-hover);
            border-color: var(--bt-green-hover);
        }
        #modalSearchContent .btn-outline-secondary {
            border-color: #dcdfe6;
            color: #606266;
        }
        #modalSearchContent .modal-header {
            background: #ffffff;
        }
        #modalSearchContent .modal-body { padding: 14px 16px; }
        #modalSearchContent label { color: #606266; font-size: 13px; }
        #modalSearchContent .form-control { height: 34px; font-size: 13px; }
        #modalSearchContent .custom-control-label { font-size: 13px; color: #606266; }
        #modalSearchContent .input-group .form-control { border-right: 0; }
        #modalSearchContent .input-group-append {
            border: 1px solid #dcdfe6;
            border-left: 0;
            border-radius: 4px;
            overflow: hidden;
            background: #f5f7fa;
        }
        #modalSearchContent .input-group-append .btn-outline-secondary {
            border: 0;
            border-right: 1px solid #e4e7ed;
            border-radius: 0;
            background: transparent;
        }
        #modalSearchContent .input-group-append .btn-outline-secondary:last-child { border-right: 0; }
        #modalSearchContent .input-group .btn-secondary {
            background: #909399;
            border-color: #909399;
        }
        #modalSearchContent .input-group .btn-secondary:hover {
            background: #7d8086;
            border-color: #7d8086;
        }
        #modalSearchContent .input-group .btn { min-width: 44px; }
        .bt-modal .modal-header {
            border-bottom: 1px solid var(--bt-border);
            padding: 12px 16px;
        }
        .bt-modal .modal-title {
            font-size: 14px;
            font-weight: normal;
            color: #333;
        }
        .bt-modal .close {
            font-size: 20px;
            color: #999;
            opacity: 1;
        }
        .bt-modal .close:hover {
            color: #666;
        }
        .bt-modal .modal-body { padding: 16px; }
        .bt-modal .modal-footer {
            border-top: 1px solid var(--bt-border);
            padding: 10px 16px;
            justify-content: flex-end;
        }
        .bt-modal .btn-primary {
            background: var(--bt-green);
            border-color: var(--bt-green);
        }
        .bt-modal .btn-primary:hover {
            background: var(--bt-green-hover);
            border-color: var(--bt-green-hover);
        }

        .bt-toast {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 12px 18px;
        border-radius: 4px;
        display: flex;
        align-items: center;
        gap: 8px;
            z-index: 10000;
            font-size: 13px;
            box-shadow: 0 2px 12px rgba(0,0,0,.15);
    }
        .bt-toast.success { background: var(--bt-green); color: #fff; }
        .bt-toast.error { background: #f56c6c; color: #fff; }
        .bt-toast.info { background: #409eff; color: #fff; }

        .bt-dropzone {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(32, 165, 58, 0.2);
            z-index: 9998;
            display: none;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-size: 22px;
            font-weight: 500;
            text-shadow: 1px 1px 2px rgba(0,0,0,.5);
            border: 2px dashed var(--bt-green);
            margin: 10px;
            border-radius: 5px;
            pointer-events: none; /* 允许下层元素响应事件 */
        }
        
        /* 统计信息栏 */
        .bt-file-stats {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 15px;
            background: #f8f9fa;
            border-top: 1px solid #e9ecef;
            font-size: 13px;
            color: #666;
            flex-shrink: 0;
        }
        .bt-file-stats .stats-left {
            display: flex;
            gap: 20px;
        }
        .bt-file-stats .stats-item {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .bt-file-stats .stats-item i {
            color: #999;
        }
        .bt-file-stats .stats-item strong {
            color: #333;
            font-weight: 600;
        }
        .bt-file-stats .stats-right {
            color: #999;
        }
        
        /* 权限设置 */
        .chmod-container {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 4px;
        }
        .chmod-section {
            flex: 1;
            text-align: center;
            padding: 0 10px;
            border-right: 1px solid #e9ecef;
        }
        .chmod-section:last-child {
            border-right: none;
        }
        .chmod-title {
            font-weight: 600;
            margin-bottom: 15px;
            color: #333;
        }
        .chmod-checkboxes {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .chmod-checkbox {
            display: flex;
            align-items: center;
            cursor: pointer;
            position: relative;
            padding-left: 28px;
            margin: 0;
        }
        .chmod-checkbox input {
            position: absolute;
            opacity: 0;
            cursor: pointer;
        }
        .chmod-checkbox .checkmark {
            position: absolute;
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            width: 18px;
            height: 18px;
            border: 2px solid #ccc;
            border-radius: 3px;
            background: #fff;
            transition: all 0.2s;
        }
        .chmod-checkbox input:checked ~ .checkmark {
            background: #20a53a;
            border-color: #20a53a;
        }
        .chmod-checkbox .checkmark:after {
            content: '';
            position: absolute;
            display: none;
            left: 5px;
            top: 2px;
            width: 5px;
            height: 9px;
            border: solid white;
            border-width: 0 2px 2px 0;
            transform: rotate(45deg);
        }
        .chmod-checkbox input:checked ~ .checkmark:after {
            display: block;
        }
        .chmod-checkbox .label-text {
            font-size: 13px;
            color: #666;
        }
        .chmod-bottom {
            padding: 15px;
            background: #f8f9fa;
            border-radius: 4px;
        }
        .chmod-input-group {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 15px;
        }
        .chmod-mode-input {
            width: 60px !important;
            text-align: center;
            font-family: monospace;
            font-weight: 600;
        }
        .chmod-owner-select {
            width: 120px !important;
        }
        .chmod-label {
            color: #666;
            font-size: 13px;
        }
        .chmod-recursive {
            display: flex;
            align-items: center;
            cursor: pointer;
            position: relative;
            padding-left: 28px;
            margin: 0;
        }
        .chmod-recursive input {
            position: absolute;
            opacity: 0;
            cursor: pointer;
        }
        .chmod-recursive .checkmark {
            position: absolute;
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            width: 18px;
            height: 18px;
            border: 2px solid #ccc;
            border-radius: 3px;
            background: #fff;
            transition: all 0.2s;
        }
        .chmod-recursive input:checked ~ .checkmark {
            background: #20a53a;
            border-color: #20a53a;
        }
        .chmod-recursive .checkmark:after {
            content: '';
            position: absolute;
            display: none;
            left: 5px;
            top: 2px;
            width: 5px;
            height: 9px;
            border: solid white;
            border-width: 0 2px 2px 0;
            transform: rotate(45deg);
        }
        .chmod-recursive input:checked ~ .checkmark:after {
            display: block;
        }
        .chmod-recursive .label-text {
            font-size: 13px;
            color: #666;
        }
        
        /* 上传弹窗样式 */
        .upload-toolbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }
        #btnStartUpload {
            background: #52c41a;
            border-color: #52c41a;
            border-radius: 4px;
            padding: 6px 20px;
        }
        #btnStartUpload:disabled {
            background: #d9d9d9;
            border-color: #d9d9d9;
        }
        #btnClearList {
            border-color: #d9d9d9;
            color: #666;
            font-size: 13px;
        }
        #btnClearList:hover {
            border-color: #ff4d4f;
            color: #ff4d4f;
            background: #fff;
        }
        .upload-dropdown {
            position: relative;
        }
        .upload-dropdown-btn {
            padding: 6px 15px;
            border: 1px solid #d9d9d9;
            background: #fff;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            color: #333;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .upload-dropdown-btn:hover {
            border-color: #20a53a;
            color: #20a53a;
        }
        .upload-dropdown-menu {
            display: none;
            position: absolute;
            top: 100%;
            left: 0;
            margin-top: 5px;
            background: #fff;
            border: 1px solid #e9ecef;
            border-radius: 4px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            list-style: none;
            padding: 5px 0;
            min-width: 140px;
            z-index: 100;
        }
        .upload-dropdown.show .upload-dropdown-menu {
            display: block;
        }
        .upload-dropdown-menu li {
            padding: 8px 15px;
            cursor: pointer;
            font-size: 13px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .upload-dropdown-menu li:hover {
            background: #f5f5f5;
            color: #20a53a;
        }
        .upload-list-container {
            border: 1px solid #e9ecef;
            border-radius: 4px;
            min-height: 200px;
            max-height: 350px;
            overflow-y: auto;
        }
        .upload-empty {
            padding: 60px 20px;
            text-align: center;
            color: #999;
            font-size: 14px;
        }
        .upload-list-header {
            display: grid;
            grid-template-columns: 2fr 1fr 1fr 60px;
            padding: 10px 15px;
            background: #f8f9fa;
            border-bottom: 1px solid #e9ecef;
            font-weight: normal;
            font-size: 13px;
            color: #666;
        }
        .upload-item {
            display: grid;
            grid-template-columns: 2fr 1fr 1fr 60px;
            padding: 12px 15px;
            border-bottom: 1px solid #f0f0f0;
            align-items: center;
            font-size: 13px;
        }
        .upload-item:last-child {
            border-bottom: none;
        }
        .upload-item .filename {
            display: flex;
            align-items: center;
            gap: 8px;
            overflow: hidden;
            color: #333;
        }
        .upload-item .filename i {
            font-size: 16px;
        }
        /* 上传队列文件类型颜色 */
        .upload-item .filename i.file-type-folder { color: #FF9800; }
        .upload-item .filename i.file-type-archive { color: #9C27B0; }
        .upload-item .filename i.file-type-document { color: #2196F3; }
        .upload-item .filename i.file-type-image { color: #4CAF50; }
        .upload-item .filename i.file-type-default { color: #757575; }
        .upload-item .filename i.file-type-code { color: #00BCD4; }
        .upload-item .filename span {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .upload-item .size {
            color: #666;
        }
        .upload-item .status {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .upload-item .status .progress {
            flex: 1;
            height: 6px;
            background: #e9ecef;
            border-radius: 3px;
            overflow: hidden;
        }
        .upload-item .status .progress-bar {
            height: 100%;
            background: #20a53a;
            transition: width 0.3s;
        }
        .upload-item .status-text {
            font-size: 12px;
            color: #999;
            min-width: 50px;
        }
        .upload-item .status-text.success {
            color: #52c41a;
        }
        .upload-item .status-text.error {
            color: #ff4d4f;
        }
        .upload-item .actions {
            text-align: center;
        }
        .upload-item .actions button {
            padding: 2px 8px;
            font-size: 12px;
        }
    </style>
</head>
<body>

<div class="bt-file-body">
    <div class="bt-path-row">
        <button type="button" class="bt-path-back" id="btPathBack" title="上一层"><i class="fas fa-arrow-left"></i></button>
        <div class="bt-path-input-wrap">
            <input type="text" class="bt-path-input" id="btPathInput" readonly placeholder="当前路径">
    </div>
        <button type="button" class="bt-path-refresh" id="btPathRefresh" title="刷新"><i class="fas fa-sync-alt"></i></button>
        <div class="bt-search-wrap">
            <input type="text" id="btSearchInput" placeholder="搜索文件/目录">
            <button type="button" id="btSearchBtn"><i class="fas fa-search"></i></button>
        </div>
        </div>
        
    <div class="bt-nav-row">
        <div class="bt-nav-dropdown">
            <button type="button" class="bt-nav-btn primary"><i class="fas fa-cloud-upload-alt"></i> 上传 <i class="fas fa-chevron-down"></i></button>
            <ul>
                <li id="btUploadFile"><i class="fas fa-file-upload"></i> 上传文件</li>
                <li id="btUploadFolder"><i class="fas fa-folder-upload"></i> 上传文件夹</li>
                <li class="sep"></li>
                <li id="btDownloadUrl"><i class="fas fa-link"></i> URL链接下载</li>
            </ul>
        </div>
        <div class="bt-nav-dropdown">
            <button type="button" class="bt-nav-btn">新建 <i class="fas fa-chevron-down"></i></button>
            <ul>
                <li id="btNewDir"><i class="fas fa-folder-plus"></i> 新建目录</li>
                <li id="btNewFile"><i class="fas fa-file-plus"></i> 新建文件</li>
            </ul>
        </div>
        <button type="button" class="bt-nav-btn" id="btSearchContent"><i class="fas fa-search"></i> 文件内容搜索</button>
        <div class="bt-nav-dropdown" id="btFavoritesWrap">
            <button type="button" class="bt-nav-btn">收藏夹 <i class="fas fa-chevron-down"></i></button>
            <ul id="btFavoritesList"></ul>
        </div>
        <div class="bt-nav-dropdown" id="btBatchWrap">
            <button type="button" class="bt-nav-btn">批量操作 <i class="fas fa-chevron-down"></i></button>
            <ul>
                <li id="btBatchCopy"><i class="fas fa-copy"></i> 复制</li>
                <li id="btBatchCut"><i class="fas fa-cut"></i> 剪切</li>
                <li id="btBatchPaste"><i class="fas fa-paste"></i> 粘贴</li>
                <li id="btBatchZip"><i class="fas fa-file-archive"></i> 压缩</li>
                <li id="btBatchUnzip"><i class="fas fa-file-import"></i> 解压</li>
                <li id="btBatchChmod"><i class="fas fa-lock"></i> 权限</li>
                <li id="btBatchDel" class="danger"><i class="fas fa-trash"></i> 删除</li>
            </ul>
        </div>
        <button type="button" class="bt-nav-btn" id="btPaste" style="display:none;">
            <i class="fas fa-paste"></i> 粘贴 <span class="bt-paste-badge" id="btPasteCount">0</span>
            </button>
        <span class="bt-nav-tip">提示：支持右键、双击、批量操作</span>
    </div>
    
    <div class="bt-table-wrap" style="position:relative;">
        <div class="bt-dropzone"><?php echo L('please_upload', 'form'); ?></div>
        <table class="bt-table">
            <thead>
                <tr>
                    <th class="th-check"><input type="checkbox" id="btSelectAll" title="<?php echo L('select_all', 'file'); ?>"></th>
                    <th class="th-name"><?php echo L('file_name', 'file'); ?></th>
                    <th class="th-perm"><?php echo L('permissions', 'file'); ?></th>
                    <th class="th-size"><?php echo L('file_size', 'file'); ?></th>
                    <th class="th-time"><?php echo L('modified_time', 'file'); ?></th>
                    <th class="th-op"><?php echo L('actions', 'file'); ?></th>
                </tr>
            </thead>
            <tbody id="fileTableBody">
                <tr><td colspan="6" class="bt-loading"><i class="fas fa-spinner fa-spin"></i><p><?php echo L('loading', 'common'); ?>...</p></td></tr>
            </tbody>
        </table>
    </div>
    
    <!-- 统计信息栏 -->
    <div class="bt-file-stats" id="fileStatsBar">
        <div class="stats-left">
            <span class="stats-item"><i class="fas fa-folder"></i> 共 <strong id="statsDirCount">0</strong> 个目录</span>
            <span class="stats-item"><i class="fas fa-file"></i> 共 <strong id="statsFileCount">0</strong> 个文件</span>
            <span class="stats-item"><i class="fas fa-hdd"></i> 文件大小 <strong id="statsTotalSize">0 B</strong></span>
        </div>
        <div class="stats-right">
            <span class="stats-item">共 <strong id="statsTotalCount">0</strong> 条</span>
        </div>
    </div>
    </div>
    
<!-- 右键菜单 - 文件/目录 -->
<ul class="bt-ctx-menu" id="ctxMenu">
    <li data-id="open"><i class="fas fa-edit"></i> <?php echo L('edit_file', 'file'); ?></li>
    <li data-id="download"><i class="fas fa-download"></i> <?php echo L('download', 'file'); ?></li>
    <li class="sep"></li>
    <li data-id="copy"><i class="fas fa-copy"></i> <?php echo L('copy', 'file'); ?></li>
    <li data-id="cut"><i class="fas fa-cut"></i> <?php echo L('move', 'file'); ?></li>
    <li data-id="rename"><i class="fas fa-i-cursor"></i> <?php echo L('rename', 'file'); ?></li>
    <li data-id="chmod"><i class="fas fa-lock"></i> <?php echo L('permissions', 'file'); ?></li>
    <li data-id="zip"><i class="fas fa-file-archive"></i> <?php echo L('compress', 'file'); ?></li>
    <li data-id="unzip"><i class="fas fa-file-import"></i> <?php echo L('extract', 'file'); ?></li>
    <li data-id="del" class="danger"><i class="fas fa-trash"></i> <?php echo L('delete', 'common'); ?></li>
</ul>

<!-- 新建目录 -->
<div class="modal fade bt-modal" id="modalNewDir" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header"><h5 class="modal-title"><?php echo L('create_folder', 'file'); ?></h5><button type="button" class="close" data-dismiss="modal">&times;</button></div>
      <div class="modal-body">
        <label><?php echo L('file_name', 'file'); ?></label>
        <input type="text" class="form-control" id="newDirName" placeholder="<?php echo L('please_input', 'form') . L('file_name', 'file'); ?>">
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo L('cancel', 'common'); ?></button>
        <button type="button" class="btn btn-primary" id="btnConfirmNewDir"><?php echo L('confirm', 'common'); ?></button>
      </div>
    </div>
  </div>
</div>
    
    <!-- 新建文件 -->
<div class="modal fade bt-modal" id="modalNewFile" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header"><h5 class="modal-title"><?php echo L('create_file', 'file'); ?></h5><button type="button" class="close" data-dismiss="modal">&times;</button></div>
      <div class="modal-body">
        <label><?php echo L('file_name', 'file'); ?></label>
        <input type="text" class="form-control" id="newFileName" placeholder="<?php echo L('please_input', 'form') . L('file_name', 'file'); ?>">
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo L('cancel', 'common'); ?></button>
        <button type="button" class="btn btn-primary" id="btnConfirmNewFile"><?php echo L('confirm', 'common'); ?></button>
      </div>
    </div>
  </div>
</div>
    
    <!-- 编辑文件 -->
<div class="modal fade bt-modal" id="modalEdit" tabindex="-1">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header"><h5 class="modal-title">编辑文件</h5><button type="button" class="close" data-dismiss="modal">&times;</button></div>
      <div class="modal-body">
        <input type="hidden" id="editFilePath">
        <textarea class="form-control" id="editFileContent" rows="20" style="font-family:monospace;font-size:13px;"></textarea>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary" id="btnSaveFile">保存</button>
      </div>
    </div>
  </div>
</div>
    
    <!-- 解压文件 -->
<div class="modal fade bt-modal" id="modalUnzip" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header"><h5 class="modal-title">解压文件</h5><button type="button" class="close" data-dismiss="modal">&times;</button></div>
      <div class="modal-body">
        <input type="hidden" id="unzipFilePath">
        <div class="alert alert-info">
          <i class="fas fa-file-archive"></i>
          <span id="unzipFileName"></span>
        </div>
        <div class="form-group">
          <label>解压到</label>
          <div class="input-group mb-2">
            <div class="input-group-prepend">
              <span class="input-group-text">/</span>
            </div>
            <input type="text" class="form-control" id="unzipTargetDir" placeholder="选择或输入解压目录">
          </div>
          <small class="text-muted">留空则解压到当前目录</small>
        </div>
        <div class="form-group">
          <label>快速选择目录</label>
          <div class="unzip-dir-list" id="unzipDirList" style="max-height: 200px; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px; padding: 8px;">
            <!-- 目录列表将动态加载 -->
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary" id="btnConfirmUnzip">解压</button>
      </div>
    </div>
  </div>
</div>

    <!-- 批量压缩 -->
<div class="modal fade bt-modal" id="modalBatchZip" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">批量压缩</h5>
        <button type="button" class="close" data-dismiss="modal">&times;</button>
      </div>
      <div class="modal-body">
        <div class="alert alert-info">
          <i class="fas fa-info-circle"></i> 
          已选择 <span id="batchZipCount" class="font-weight-bold">0</span> 个文件/目录
        </div>
        <div class="form-group">
          <label>压缩文件名</label>
          <input type="text" class="form-control" id="batchZipName" placeholder="请输入压缩文件名，如：backup.zip">
          <small class="text-muted">支持格式：.zip, .tar.gz, .tar</small>
        </div>
        <div class="form-group">
          <label>保存位置</label>
          <input type="text" class="form-control" id="batchZipPath" readonly>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary" id="btnConfirmBatchZip">
          <i class="fas fa-file-archive"></i> 开始压缩
        </button>
      </div>
    </div>
  </div>
</div>

    <!-- 权限设置 -->
    <div class="modal fade bt-modal" id="modalChmod" tabindex="-1">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">权限设置</h5>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
          </div>
          <div class="modal-body">
            <input type="hidden" id="chmodFilePath">
            <div class="chmod-container">
              <div class="chmod-section">
                <div class="chmod-title">所有者</div>
                <div class="chmod-checkboxes">
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodOwnerRead" data-value="4">
                    <span class="checkmark"></span>
                    <span class="label-text">读取</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodOwnerWrite" data-value="2">
                    <span class="checkmark"></span>
                    <span class="label-text">写入</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodOwnerExec" data-value="1">
                    <span class="checkmark"></span>
                    <span class="label-text">执行</span>
                  </label>
                </div>
              </div>
              <div class="chmod-section">
                <div class="chmod-title">用户组</div>
                <div class="chmod-checkboxes">
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodGroupRead" data-value="4">
                    <span class="checkmark"></span>
                    <span class="label-text">读取</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodGroupWrite" data-value="2">
                    <span class="checkmark"></span>
                    <span class="label-text">写入</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodGroupExec" data-value="1">
                    <span class="checkmark"></span>
                    <span class="label-text">执行</span>
                  </label>
                </div>
              </div>
              <div class="chmod-section">
                <div class="chmod-title">公共</div>
                <div class="chmod-checkboxes">
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodPublicRead" data-value="4">
                    <span class="checkmark"></span>
                    <span class="label-text">读取</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodPublicWrite" data-value="2">
                    <span class="checkmark"></span>
                    <span class="label-text">写入</span>
                  </label>
                  <label class="chmod-checkbox">
                    <input type="checkbox" id="chmodPublicExec" data-value="1">
                    <span class="checkmark"></span>
                    <span class="label-text">执行</span>
                  </label>
                </div>
              </div>
            </div>
            <div class="chmod-bottom">
              <div class="chmod-input-group">
                <input type="text" class="form-control chmod-mode-input" id="chmodModeInput" value="755" maxlength="3">
                <span class="chmod-label">权限</span>
                <select class="form-control chmod-owner-select" id="chmodOwnerSelect">
                  <option value="www">www</option>
                </select>
                <span class="chmod-label">所有者</span>
              </div>
              <label class="chmod-recursive">
                <input type="checkbox" id="chmodRecursive">
                <span class="checkmark"></span>
                <span class="label-text">应用到子目录</span>
              </label>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
            <button type="button" class="btn btn-primary" id="btnConfirmChmod">应用</button>
          </div>
        </div>
      </div>
    </div>

    <!-- URL链接下载 -->
    <div class="modal fade bt-modal" id="modalDownloadUrl" tabindex="-1">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">URL链接下载</h5>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
          </div>
          <div class="modal-body">
            <div class="form-group">
              <label>下载链接</label>
              <textarea class="form-control" id="downloadUrlInput" rows="3" placeholder="请输入下载链接，每行一个"></textarea>
              <small class="text-muted">支持多个链接，每行一个</small>
            </div>
            <div class="form-group">
              <label>保存路径</label>
              <input type="text" class="form-control" id="downloadUrlPath" readonly>
            </div>
            <div class="form-group">
              <label>文件名（可选）</label>
              <input type="text" class="form-control" id="downloadUrlFilename" placeholder="留空使用默认文件名">
              <small class="text-muted">如果链接包含文件名，可留空</small>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
            <button type="button" class="btn btn-primary" id="btnConfirmDownloadUrl">
              <i class="fas fa-download"></i> 开始下载
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- 上传文件弹窗 -->
    <div class="modal fade bt-modal" id="modalUpload" tabindex="-1">
      <div class="modal-dialog modal-lg">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">上传文件到【<span id="uploadTargetPath"></span>】--支持断点续传</h5>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
          </div>
          <div class="modal-body">
            <div class="upload-toolbar">
              <div class="upload-dropdown">
                <button type="button" class="upload-dropdown-btn" id="uploadDropdownBtn">
                  <span id="uploadDropdownText">上传文件</span> <i class="fas fa-chevron-down"></i>
                </button>
                <ul class="upload-dropdown-menu">
                  <li id="uploadMenuFile"><i class="fas fa-file"></i> 上传文件</li>
                  <li id="uploadMenuFolder"><i class="fas fa-folder"></i> 上传文件夹</li>
                </ul>
              </div>
              <button type="button" class="btn btn-outline-secondary btn-sm" id="btnClearList">
                <i class="fas fa-trash-alt"></i> 清空列表
              </button>
            </div>
            <!-- 文件列表区域 -->
            <div class="upload-list-container" id="uploadListContainer">
              <div class="upload-list-header">
                <span>文件名</span>
                <span>文件大小</span>
                <span>上传状态</span>
                <span>操作</span>
              </div>
              <div class="upload-list-body" id="uploadListBody">
                <div class="upload-empty">暂无文件，请点击"上传文件"选择要上传的文件</div>
              </div>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-success" id="btnStartUpload" disabled>
              <i class="fas fa-upload"></i> 开始上传
            </button>
          </div>
        </div>
      </div>
    </div>

    <div class="modal fade bt-modal" id="modalSearchContent" tabindex="-1">
      <div class="modal-dialog modal-xl">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">文件内容搜索</h5>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
          </div>
          <div class="modal-body">
            <div class="form-row align-items-center">
              <div class="col-auto mb-2">
                <label class="mb-0">搜索内容</label>
              </div>
              <div class="col-auto mb-2" style="min-width: 120px;">
                <select class="form-control" id="searchMode">
                  <option value="content">文本</option>
                  <option value="name">文件名</option>
                </select>
              </div>
              <div class="col mb-2">
                <div class="input-group">
                  <input type="text" class="form-control" id="searchKeyword" placeholder="请输入搜索内容">
                  <div class="input-group-append">
                    <button type="button" class="btn btn-outline-secondary" id="toggleIgnore" data-value="0" title="忽略">I</button>
                    <button type="button" class="btn btn-outline-secondary" id="toggleMatchCase" data-value="0" title="区分大小写">Aa</button>
                    <button type="button" class="btn btn-outline-secondary" id="toggleWholeWord" data-value="0" title="全词匹配">[ab]</button>
                    <button type="button" class="btn btn-outline-secondary" id="toggleRegex" data-value="0" title="正则表达式">*</button>
                  </div>
                </div>
              </div>
              <div class="col-auto mb-2">
                <div class="btn-group" role="group">
                  <button type="button" class="btn btn-success" id="btnExecuteSearch">搜索</button>
                  <button type="button" class="btn btn-outline-secondary" id="btnStopSearch" disabled>停止</button>
                </div>
              </div>
            </div>

            <div class="form-row align-items-center">
              <div class="col-auto mb-2">
                <label class="mb-0">目录</label>
              </div>
              <div class="col mb-2">
                <div class="input-group">
                  <input type="text" class="form-control" id="searchDir" value="" placeholder="/www/wwwroot/...">
                  <div class="input-group-append">
                    <button type="button" class="btn btn-outline-secondary" id="btnUseCurrentDir" title="使用当前目录"><i class="fas fa-folder"></i></button>
                  </div>
                </div>
              </div>
              <div class="col-auto mb-2">
                <div class="custom-control custom-checkbox">
                  <input type="checkbox" class="custom-control-input" id="searchIncludeSubdir" checked>
                  <label class="custom-control-label" for="searchIncludeSubdir">包含子目录</label>
                </div>
              </div>
            </div>

            <div class="form-row align-items-center">
              <div class="col-auto mb-2">
                <label class="mb-0">文件后缀</label>
              </div>
              <div class="col mb-2">
                <input type="text" class="form-control" id="searchSuffix" placeholder="选择或填写后缀类型，使用逗号分隔">
              </div>
              <div class="col-auto mb-2">
                <label class="mb-0">修改时间</label>
              </div>
              <div class="col-auto mb-2" style="min-width: 160px;">
                <select class="form-control" id="searchMtime">
                  <option value="0">不限制时间</option>
                  <option value="1">最近1天</option>
                  <option value="7">最近7天</option>
                  <option value="30">最近30天</option>
                </select>
              </div>
              <div class="col-auto mb-2">
                <label class="mb-0">文件大小</label>
              </div>
              <div class="col-auto mb-2" style="min-width: 170px;">
                <select class="form-control" id="searchSize">
                  <option value="10485760">0 ~ 10MB</option>
                  <option value="1048576">0 ~ 1MB</option>
                  <option value="102400">0 ~ 100KB</option>
                  <option value="10240">0 ~ 10KB</option>
                  <option value="0">不限制</option>
                </select>
              </div>
            </div>

            <div class="border rounded" style="min-height: 360px;">
              <div id="searchResultEmpty" class="text-center text-muted" style="padding: 120px 20px;">
                <div style="font-size: 18px;">键入查找内容以在文件中查询</div>
                <div style="font-size: 12px; margin-top: 8px;">筛选的选项可以有效地缩短搜索时间</div>
              </div>
              <div id="searchResultWrap" style="display:none;">
                <div class="d-flex justify-content-between align-items-center px-3 py-2 border-bottom">
                  <div class="text-muted" id="searchResultSummary">正在搜索...</div>
                  <button type="button" class="btn btn-link btn-sm" id="btnClearSearchResult">清空结果</button>
                </div>
                <div style="max-height: 420px; overflow:auto;">
                  <table class="table table-sm mb-0">
                    <thead>
                      <tr>
                        <th>文件</th>
                        <th style="width: 120px;">大小</th>
                        <th style="width: 180px;">修改时间</th>
                        <th style="width: 100px;">操作</th>
                      </tr>
                    </thead>
                    <tbody id="searchResultBody"></tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
          </div>
        </div>
      </div>
    </div>
    
    <div id="toastContainer"></div>
<input type="file" id="uploadFileInput" multiple style="display:none">
<input type="file" id="uploadFolderInput" webkitdirectory directory multiple style="display:none">
    
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/bootstrap.bundle.min.js"></script>
    <script>
(function() {
    var currentRelativePath = '/';
    var fileListData = [];
    var lastNavigateTime = 0;
    var navigateCooldown = 500; // 500ms 冷却时间
    var currentContextPath = null;
    var clipboardAction = null, clipboardFiles = [];
    var favorites = JSON.parse(localStorage.getItem('fileFavorites') || '[]');
    var currentSearchXhr = null;
    var siteInfo = {
        root_path: '<?php echo addslashes($site_root); ?>',
        domain: '<?php echo addslashes($user['user']); ?>'
    };
    
    // 标准化路径
    function normalizePath(path) {
        var normalizedPath = path || '/';
        if (!normalizedPath.startsWith('/')) {
            normalizedPath = '/' + normalizedPath;
        }
        normalizedPath = normalizedPath.replace(/\/+$/, '');
        if (normalizedPath === '') {
            normalizedPath = '/';
        }
        return normalizedPath;
    }
    
    // 文件列表缓存（优化版）
    var fileCache = {};
    var cacheExpireTime = 5 * 60 * 1000; // 5分钟缓存过期时间
    var cacheRefreshInterval = 30 * 1000; // 30秒后台刷新间隔
    var cacheRefreshTimers = {}; // 缓存刷新定时器
    
    // 获取缓存数据（优先使用缓存，后台异步刷新）
    function getCachedFiles(path) {
        var normalizedPath = normalizePath(path);
        var cacheData = fileCache[normalizedPath];
        var now = Date.now();
        
        if (cacheData && (now - cacheData.time) < cacheExpireTime) {
            console.log('使用缓存数据:', normalizedPath, '文件数:', cacheData.files.length);
            
            // 触发后台异步刷新
            refreshCacheInBackground(normalizedPath);
            
            return cacheData.files;
        }
        
        return null;
    }
    
    // 后台异步刷新缓存
    function refreshCacheInBackground(path) {
        // 如果已经有刷新任务在进行，不重复刷新
        if (cacheRefreshTimers[path]) {
            console.log('缓存刷新中，跳过:', path);
            return;
        }
        
        // 延迟刷新，避免频繁请求
        cacheRefreshTimers[path] = setTimeout(function() {
            console.log('后台刷新缓存:', path);
            
            $.ajax({
                type: 'POST',
                url: 'api/api_router.php',
                data: { action: 'getfiles', dir: path },
                dataType: 'json',
                timeout: 10000, // 10秒超时
                success: function(d) {
                    var files = d.files || (d.data && d.data.files) || [];
                    var now = Date.now();
                    
                    // 更新缓存
                    fileCache[path] = {
                        files: files,
                        time: now
                    };
                    
                    console.log('缓存刷新完成:', path, '文件数:', files.length);
                    
                    // 如果当前正在查看这个目录，更新显示
                    if (normalizePath(currentRelativePath) === path) {
                        renderList(files);
                        updateFileStats(files);
                    }
                },
                error: function() {
                    console.log('缓存刷新失败:', path);
                },
                complete: function() {
                    delete cacheRefreshTimers[path];
                }
            });
        }, cacheRefreshInterval);
    }
    
    // 清除指定路径的缓存
    function clearCache(path) {
        if (!path) {
            // 清除所有缓存
            fileCache = {};
            console.log('已清除所有缓存');
            return;
        }
        
        // 标准化路径
        var normalizedPath = path || '/';
        if (!normalizedPath.startsWith('/')) {
            normalizedPath = '/' + normalizedPath;
        }
        normalizedPath = normalizedPath.replace(/\/+$/, '');
        if (normalizedPath === '') {
            normalizedPath = '/';
        }
        
        console.log('清除缓存，原始路径:', path, '标准化路径:', normalizedPath);
        console.log('清除前缓存键:', Object.keys(fileCache));
        
        // 清除指定路径的缓存
        if (fileCache[normalizedPath]) {
            delete fileCache[normalizedPath];
            console.log('已清除缓存:', normalizedPath);
        }
        
        // 清除父目录的缓存（因为子目录变化会影响父目录的显示）
        var parts = normalizedPath.split('/').filter(function(p) { return p; });
        for (var i = parts.length - 1; i >= 0; i--) {
            var parentPath = '/' + parts.slice(0, i).join('/');
            if (fileCache[parentPath]) {
                delete fileCache[parentPath];
                console.log('已清除父目录缓存:', parentPath);
            }
        }
        
        // 清除根目录缓存（确保根目录也能刷新）
        if (normalizedPath !== '/' && fileCache['/']) {
            delete fileCache['/'];
            console.log('已清除根目录缓存: /');
        }
        
        console.log('清除缓存后，剩余缓存:', Object.keys(fileCache));
    }
    
    // 上传队列
    var uploadQueue = [];
    var uploadType = 'file'; // 'file' 或 'folder'
    var isUploading = false;
    
    function showToast(msg, type) {
        type = type || 'info';
        var el = document.createElement('div');
        el.className = 'bt-toast ' + type;
        var safeMsg = $('<div>').text(msg).html();
        el.innerHTML = '<i class="fas fa-' + (type === 'success' ? 'check-circle' : type === 'error' ? 'times-circle' : 'info-circle') + '"></i> ' + safeMsg;
        document.getElementById('toastContainer').appendChild(el);
        setTimeout(function() {
            el.style.opacity = '0';
            setTimeout(function() { el.remove(); }, 300);
        }, 2500);
    }

    // 文件类型分类和颜色定义
    var FILE_TYPES = {
        // 压缩包 - 紫色
        archive: {
            exts: ['zip', 'tar', 'gz', 'tgz', 'bz2', '7z', 'rar', 'xz', 'lz', 'lzma'],
            icon: 'fa-file-archive',
            colorClass: 'file-type-archive'
        },
        // 图片文件 - 绿色
        image: {
            exts: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'ico', 'tiff', 'tif', 'psd', 'ai', 'eps'],
            icon: 'fa-file-image',
            colorClass: 'file-type-image'
        },
        // 文档文件 - 蓝色
        document: {
            exts: ['txt', 'md', 'doc', 'docx', 'pdf', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp', 'rtf', 'csv'],
            icon: 'fa-file-alt',
            colorClass: 'file-type-document'
        },
        // 代码文件 - 青色
        code: {
            exts: ['html', 'htm', 'css', 'js', 'json', 'php', 'py', 'java', 'c', 'cpp', 'h', 'hpp', 'cs', 'go', 'rs', 'rb', 'swift', 'kt', 'ts', 'jsx', 'tsx', 'vue', 'sql', 'xml', 'yaml', 'yml', 'ini', 'conf', 'sh', 'bash', 'ps1', 'bat', 'cmd'],
            icon: 'fa-file-code',
            colorClass: 'file-type-code'
        }
    };

    // 获取文件图标和颜色类
    function getFileIcon(name, isDir) {
        if (isDir) {
            return { icon: 'fa-folder', colorClass: 'file-type-folder' };
        }
        var ext = (name || '').split('.').pop().toLowerCase();

        // 检查各类型
        for (var type in FILE_TYPES) {
            if (FILE_TYPES[type].exts.indexOf(ext) !== -1) {
                return { icon: FILE_TYPES[type].icon, colorClass: FILE_TYPES[type].colorClass };
            }
        }

        // 默认返回普通文件
        return { icon: 'fa-file', colorClass: 'file-type-default' };
    }

    function handleFileUpload(files) {
        if (!files.length) return;

        var formData = new FormData();
        for (var i = 0; i < files.length; i++) {
            formData.append('files[]', files[i]);
        }
        formData.append('path', currentRelativePath);

        showToast('开始上传 ' + files.length + ' 个文件...', 'info');

        $.ajax({
            url: '/user/ajax.php?action=upload&t=' + new Date().getTime(),
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            dataType: 'json',
            success: function(res) {
                if (res.status) {
                    showToast(res.msg || '上传成功！', 'success');
                    clearCache(currentRelativePath);
                    loadFiles(); // 刷新列表
                } else {
                    showToast(res.msg || '上传失败', 'error');
                }
            },
            error: function() {
                showToast('上传请求失败', 'error');
            }
        });
    }

    // 处理文件夹上传
    function handleFolderUpload(files) {
        if (!files.length) return;
        
        // 获取文件夹名称（从第一个文件的路径推断）
        var firstFile = files[0];
        var webkitRelativePath = firstFile.webkitRelativePath || '';
        var folderName = webkitRelativePath.split('/')[0];
        
        if (!folderName) {
            showToast('无法获取文件夹名称', 'error');
            return;
        }
        
        showToast('开始上传文件夹: ' + folderName + ' (' + files.length + ' 个文件)...', 'info');
        
        var formData = new FormData();
        for (var i = 0; i < files.length; i++) {
            formData.append('files[]', files[i]);
            formData.append('relativePaths[]', files[i].webkitRelativePath || '');
        }
        formData.append('path', currentRelativePath);
        formData.append('folderName', folderName);
        formData.append('isFolder', '1');
        
        $.ajax({
            url: '/user/ajax.php?action=upload&t=' + new Date().getTime(),
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            dataType: 'json',
            success: function(res) {
                if (res.status) {
                    showToast(res.msg || '文件夹上传成功！', 'success');
                    clearCache(currentRelativePath);
                    loadFiles();
                } else {
                    showToast(res.msg || '上传失败', 'error');
                }
            },
            error: function() {
                showToast('上传请求失败', 'error');
            }
        });
    }
    
    // URL链接下载
    function downloadFromUrl() {
        var urls = $('#downloadUrlInput').val().trim();
        var path = $('#downloadUrlPath').val();
        var filename = $('#downloadUrlFilename').val().trim();
        
        if (!urls) {
            showToast('请输入下载链接', 'error');
            return;
        }
        
        var urlList = urls.split('\n').filter(function(url) {
            return url.trim() !== '';
        });
        
        if (urlList.length === 0) {
            showToast('请输入有效的下载链接', 'error');
            return;
        }
        
        var $btn = $('#btnConfirmDownloadUrl');
        $btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> 下载中...');
        
        showToast('开始下载 ' + urlList.length + ' 个文件...', 'info');
        
        $.ajax({
            url: 'api/api_router.php',
            type: 'POST',
            data: {
                action: 'downloadurl',
                urls: JSON.stringify(urlList),
                path: path,
                filename: filename
            },
            dataType: 'json',
            success: function(d) {
                $btn.prop('disabled', false).html('<i class="fas fa-download"></i> 开始下载');
                if (d.code === 'success' || d.status === true) {
                    showToast('下载任务已提交', 'success');
                    $('#modalDownloadUrl').modal('hide');
                    // 延迟刷新列表
                    setTimeout(function() {
                        loadFiles();
                    }, 2000);
                } else {
                    showToast(d.msg || '下载失败', 'error');
                }
            },
            error: function() {
                $btn.prop('disabled', false).html('<i class="fas fa-download"></i> 开始下载');
                showToast('下载请求失败', 'error');
            }
        });
    }
    
    // 打开上传弹窗
    function openUploadModal(type) {
        uploadType = type || 'file';
        uploadQueue = [];
        isUploading = false;
        
        // 设置下拉菜单文字
        $('#uploadDropdownText').text(uploadType === 'file' ? '上传文件' : '上传文件夹');
        
        // 设置目标路径 - 只显示相对路径，不暴露服务器完整路径
        var displayPath = currentRelativePath || '/';
        if (!displayPath.startsWith('/')) displayPath = '/' + displayPath;
        $('#uploadTargetPath').text(displayPath);
        
        // 重置列表
        renderUploadList();
        $('#btnStartUpload').prop('disabled', true).html('<i class="fas fa-upload"></i> 开始上传');
        
        $('#modalUpload').modal('show');
    }
    
    // 添加文件到上传队列
    function addFilesToQueue(files, type) {
        if (!files || !files.length) return;
        
        uploadType = type || 'file';
        
        for (var i = 0; i < files.length; i++) {
            var file = files[i];
            var fileObj = {
                id: Date.now() + '_' + i,
                file: file,
                name: file.name,
                size: file.size,
                path: file.webkitRelativePath || file.name,
                status: 'pending', // pending, uploading, success, error
                progress: 0
            };
            uploadQueue.push(fileObj);
        }
        
        renderUploadList();
        $('#btnStartUpload').prop('disabled', false);
    }
    
    // 渲染上传列表
    function renderUploadList() {
        var $body = $('#uploadListBody');
        
        $body.empty();
        
        if (uploadQueue.length === 0) {
            $body.html('<div class="upload-empty">暂无文件，请点击"上传文件"选择要上传的文件</div>');
            return;
        }
        
        uploadQueue.forEach(function(item, index) {
            var sizeText = formatSize(item.size);
            var statusHtml = '';
            var actionHtml = '';
            
            if (item.status === 'pending') {
                statusHtml = '<span class="status-text">等待上传</span>';
                actionHtml = '<button type="button" class="btn btn-sm btn-link text-danger" onclick="removeFromUploadQueue(' + index + ')" style="padding: 0;">取消</button>';
            } else if (item.status === 'uploading') {
                statusHtml = '<div class="progress"><div class="progress-bar" style="width:' + item.progress + '%"></div></div><span class="status-text">' + item.progress + '%</span>';
                actionHtml = '<span class="text-muted">-</span>';
            } else if (item.status === 'success') {
                statusHtml = '<span class="status-text success"><i class="fas fa-check-circle"></i> 成功</span>';
                actionHtml = '<span class="text-muted">-</span>';
            } else if (item.status === 'error') {
                var errorMsg = item.errorMsg || '失败';
                statusHtml = '<span class="status-text error" title="' + errorMsg + '"><i class="fas fa-times-circle"></i> ' + errorMsg + '</span>';
                actionHtml = '<button type="button" class="btn btn-sm btn-link text-danger" onclick="removeFromUploadQueue(' + index + ')" style="padding: 0;">删除</button>';
            }
            
            // 获取文件路径显示（如果有子目录）
            var filePath = item.path;
            var displayName = item.name;
            var pathPrefix = '';
            if (filePath && filePath !== item.name && filePath.indexOf('/') !== -1) {
                var lastSlash = filePath.lastIndexOf('/');
                if (lastSlash > 0) {
                    pathPrefix = filePath.substring(0, lastSlash);
                    displayName = filePath;
                }
            }
            
            var iconInfo = getFileIcon(item.name, false);
            var html = '<div class="upload-item" data-id="' + item.id + '">' +
                '<div class="filename"><i class="fas ' + iconInfo.icon + ' ' + iconInfo.colorClass + '"></i><span title="' + $('<div>').text(item.path).html() + '">' + $('<div>').text(displayName).html() + '</span></div>' +
                '<div class="size">' + sizeText + '</div>' +
                '<div class="status">' + statusHtml + '</div>' +
                '<div class="actions">' + actionHtml + '</div>' +
                '</div>';
            $body.append(html);
        });
    }
    
    // 从队列中移除
    window.removeFromUploadQueue = function(index) {
        if (isUploading) return;
        uploadQueue.splice(index, 1);
        renderUploadList();
        if (uploadQueue.length === 0) {
            $('#btnStartUpload').prop('disabled', true);
        }
    };
    
    // 开始上传 - 使用原来的上传方式
    function startUpload() {
        if (isUploading || uploadQueue.length === 0) return;
        
        isUploading = true;
        $('#btnStartUpload').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> 上传中...');
        
        // 准备文件
        var files = [];
        var relativePaths = [];
        
        uploadQueue.forEach(function(item) {
            files.push(item.file);
            relativePaths.push(item.path || '');
        });
        
        // 使用原来的上传方式
        if (uploadType === 'folder') {
            // 文件夹上传
            var formData = new FormData();
            for (var i = 0; i < files.length; i++) {
                formData.append('files[]', files[i]);
                formData.append('relativePaths[]', relativePaths[i]);
            }
            formData.append('path', currentRelativePath);
            
            // 获取文件夹名称
            var folderName = relativePaths[0] ? relativePaths[0].split('/')[0] : '';
            formData.append('folderName', folderName);
            formData.append('isFolder', '1');
            
            $.ajax({
                url: '/user/ajax.php?action=upload&t=' + new Date().getTime(),
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                dataType: 'json',
                success: function(res) {
                    isUploading = false;
                    $('#btnStartUpload').prop('disabled', false).html('<i class="fas fa-upload"></i> 开始上传');
                    
                    if (res.status) {
                        showToast(res.msg || '上传成功！', 'success');
                        $('#modalUpload').modal('hide');
                        
                        console.log('文件夹上传响应:', res);
                        
                        // 清除所有缓存，确保文件列表刷新
                        console.log('文件夹上传成功，清除所有缓存');
                        clearCache();
                        
                        // 延迟加载文件列表，确保服务器处理完成
                        setTimeout(function() {
                            console.log('延迟加载文件列表');
                            loadFiles();
                        }, 1500);
                    } else {
                        showToast(res.msg || '上传失败', 'error');
                        // 标记所有文件为失败
                        uploadQueue.forEach(function(item) {
                            item.status = 'error';
                            item.errorMsg = res.msg || '上传失败';
                        });
                        renderUploadList();
                    }
                },
                error: function() {
                    isUploading = false;
                    $('#btnStartUpload').prop('disabled', false).html('<i class="fas fa-upload"></i> 开始上传');
                    showToast('上传请求失败', 'error');
                    uploadQueue.forEach(function(item) {
                        item.status = 'error';
                        item.errorMsg = '请求失败';
                    });
                    renderUploadList();
                }
            });
        } else {
            // 单文件上传
            var formData = new FormData();
            for (var i = 0; i < files.length; i++) {
                formData.append('files[]', files[i]);
            }
            formData.append('path', currentRelativePath);
            
            $.ajax({
                url: '/user/ajax.php?action=upload&t=' + new Date().getTime(),
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                dataType: 'json',
                success: function(res) {
                    isUploading = false;
                    $('#btnStartUpload').prop('disabled', false).html('<i class="fas fa-upload"></i> 开始上传');
                    
                    console.log('上传响应:', res);
                    
                    if (res.status) {
                        showToast(res.msg || '上传成功！', 'success');
                        $('#modalUpload').modal('hide');
                        
                        // 清除所有缓存，确保文件列表刷新
                        console.log('上传成功，清除所有缓存');
                        clearCache();
                        
                        // 延迟加载文件列表，确保服务器处理完成
                        setTimeout(function() {
                            console.log('延迟加载文件列表');
                            loadFiles();
                        }, 1500);
                    } else {
                        showToast(res.msg || '上传失败', 'error');
                        uploadQueue.forEach(function(item) {
                            item.status = 'error';
                            item.errorMsg = res.msg || '上传失败';
                        });
                        renderUploadList();
                    }
                },
                error: function() {
                    isUploading = false;
                    $('#btnStartUpload').prop('disabled', false).html('<i class="fas fa-upload"></i> 开始上传');
                    showToast('上传请求失败', 'error');
                    uploadQueue.forEach(function(item) {
                        item.status = 'error';
                        item.errorMsg = '请求失败';
                    });
                    renderUploadList();
                }
            });
        }
    }

    function formatSize(bytes) {
        if (!bytes || bytes <= 0) return '0 B';
        var units = ['B','KB','MB','GB','TB'];
        var i = 0;
        while (bytes >= 1024 && i < units.length - 1) {
            bytes /= 1024; i++;
        }
        // 如果是整数，不显示小数
        if (bytes === Math.floor(bytes)) {
            return bytes + ' ' + units[i];
        }
        return bytes.toFixed(2) + ' ' + units[i];
    }

    function formatTime(ts) {
        if (!ts) return '-';
        if (typeof ts === 'string' && ts.indexOf('-') !== -1) return ts;
        var d = new Date(ts * 1000);
        return d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0') +
               ' ' + String(d.getHours()).padStart(2,'0') + ':' + String(d.getMinutes()).padStart(2,'0') + ':' + String(d.getSeconds()).padStart(2,'0');
    }

    function updatePathDisplay() {
        var p = (currentRelativePath || '/');
        if (!p.startsWith('/')) p = '/' + p;
        p = p.replace(/\/+$/, '');
        if (p === '') p = '/';
        if (!p.endsWith('/')) p += '/';
        document.getElementById('btPathInput').value = p;
    }

    function loadFiles(forceReload) {
        updatePathDisplay();

        // 标准化当前路径用于缓存
        var cacheKey = normalizePath(currentRelativePath);
        console.log('loadFiles: currentRelativePath=' + currentRelativePath + ', cacheKey=' + cacheKey + ', forceReload=' + forceReload);

        // 优先使用缓存数据（除非强制刷新）
        if (!forceReload) {
            var cachedFiles = getCachedFiles(cacheKey);
            if (cachedFiles) {
                fileListData = cachedFiles;
                renderList(cachedFiles);
                // 在后台静默刷新缓存
                refreshCacheInBackground(cacheKey);
                return;
            }
        }

        // 显示加载动画
        document.getElementById('fileTableBody').innerHTML =
            '<tr><td colspan="6" class="bt-loading"><i class="fas fa-spinner fa-spin"></i><p>加载中...</p></td></tr>';

        $.ajax({
            type: 'POST',
            url: 'api/api_router.php',
            data: { action: 'getfiles', dir: currentRelativePath },
            dataType: 'json',
            timeout: 10000, // 10秒超时，更快响应
            success: function(d) {
                console.log('AJAX success, files count:', (d.files || (d.data && d.data.files) || []).length);
                var files = d.files || (d.data && d.data.files) || [];
                fileListData = files;
                
                // 保存到缓存
                fileCache[cacheKey] = {
                    files: files,
                    time: Date.now()
                };
                
                console.log('保存到缓存:', cacheKey, '文件数:', files.length);
                
                // 清理过期缓存（保留最近20个目录的缓存）
                var cacheKeys = Object.keys(fileCache);
                if (cacheKeys.length > 20) {
                    cacheKeys.sort(function(a, b) {
                        return fileCache[a].time - fileCache[b].time;
                    });
                    for (var i = 0; i < cacheKeys.length - 20; i++) {
                        delete fileCache[cacheKeys[i]];
                    }
                }
                
                if (d.code === 'success' || d.status === true) {
                    renderList(files);
                } else {
                    console.log('AJAX error:', d.msg || d.code || d.status);
                    $('#fileTableBody').html(
                        '<tr><td colspan="6" class="bt-empty"><i class="fas fa-exclamation-triangle"></i><p>' +
                        (d.msg || '加载失败：' + (d.code || d.status)) + '</p></td></tr>'
                    );
                }
            },
            error: function(xhr, status, error) {
                var msg = '加载失败';
                if (status === 'timeout') msg = '请求超时，请重试';
                else if (status === 'error') msg = '服务器错误：' + (xhr.status || '未知');
                else if (status === 'abort') msg = '请求被取消';
                else if (status === 'parsererror') msg = '数据解析错误';
                $('#fileTableBody').html(
                    '<tr><td colspan="6" class="bt-empty"><i class="fas fa-times-circle"></i><p>' + msg + '</p></td></tr>'
                );
            }
        });
    }

    function renderList(files) {
        if (!files || !files.length) {
            $('#fileTableBody').html(
                '<tr><td colspan="6" class="bt-empty"><i class="fas fa-folder-open"></i><p>此目录为空</p></td></tr>'
            );
            updateFileStats([]);
            return;
        }
        var html = '';
        files.forEach(function(f, idx) {
                var isDir = f.is_dir || f.type === 'dir';
            var path = f.path || '';
            var name = f.name || path.split('/').pop();
            var iconInfo = getFileIcon(name, isDir);
            var icon = iconInfo.icon;
            var colorClass = iconInfo.colorClass;
            var perm = (f.perm || f.permissions || '-');
            var owner = (f.owner || '');
            var size = isDir ? '-' : formatSize(f.size || 0);
            var mtime = formatTime(f.mtime || f.modified);
            var pathEsc = path.replace(/"/g,'&quot;');
            var nameEsc = $('<div>').text(name).html();
            var permEsc = $('<div>').text(perm).html();
            var ownerEsc = $('<div>').text(owner).html();

            html += '<tr class="bt-row" data-index="' + idx + '" data-path="' + pathEsc + '" data-isdir="' + (isDir ? '1':'0') + '">';
            html += '<td class="td-check"><input type="checkbox" class="file-cb" value="' + pathEsc + '" onclick="event.stopPropagation()"></td>';
            html += '<td class="td-name"><i class="fas ' + icon + ' ' + colorClass + '"></i><span class="file-name">' + nameEsc + '</span></td>';
            html += '<td><span style="font-family:monospace;font-size:12px;">' + permEsc + '</span>' +
                    (owner ? '/' + '<span style="font-size:12px;">' + ownerEsc + '</span>' : '') + '</td>';
            html += '<td>' + size + '</td>';
            html += '<td>' + mtime + '</td>';
            html += '<td class="td-op">';
            
            // 判断是否为压缩包
            var ext = name.split('.').pop().toLowerCase();
            var isArchive = FILE_TYPES.archive.exts.indexOf(ext) !== -1;
            
            if (isArchive) {
                // 压缩包显示：解压、下载、重命名、权限、删除
                html += '<a href="javascript:void(0)" class="op-link" data-op="unzip">解压</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="download">下载</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="rename">重命名</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="chmod">权限</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="delete">删除</a>';
            } else if (isDir) {
                // 目录显示：打开、重命名、权限、删除
                html += '<a href="javascript:void(0)" class="op-link" data-op="open">打开</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="rename">重命名</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="chmod">权限</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="delete">删除</a>';
            } else {
                // 普通文件显示：打开、下载、在线编辑、重命名、权限、删除
                html += '<a href="javascript:void(0)" class="op-link" data-op="open">打开</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="download">下载</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="edit">在线编辑</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="rename">重命名</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="chmod">权限</a>';
                html += '<a href="javascript:void(0)" class="op-link" data-op="delete">删除</a>';
            }
            html += '</td></tr>';
            });
        $('#fileTableBody').html(html);
        
        // 更新统计信息
        updateFileStats(files);
    }
    
    // 更新统计信息
    function updateFileStats(files) {
        var dirCount = 0;
        var fileCount = 0;
        var totalSize = 0;

        if (files && files.length) {
            files.forEach(function(f) {
                var isDir = f.is_dir || f.type === 'dir';
                if (isDir) {
                    dirCount++;
                } else {
                    fileCount++;
                    totalSize += parseInt(f.size || 0);
                }
            });
        }

        $('#statsDirCount').text(dirCount);
        $('#statsFileCount').text(fileCount);
        $('#statsTotalSize').text(formatSize(totalSize));
        $('#statsTotalCount').text(files ? files.length : 0);

        // 异步获取当前目录的真实总大小（包括子目录）
        loadRealDirSize();
    }

    // 异步加载目录真实大小
    function loadRealDirSize() {
        $.ajax({
            type: 'POST',
            url: 'api/api_router.php',
            data: { action: 'getdirsize', dir: currentRelativePath },
            dataType: 'json',
            success: function(d) {
                console.log('getDirSize返回:', d);
                if (d.code === 'success' || d.status === true) {
                    var realSize = parseInt(d.size || 0);
                    console.log('获取到真实大小:', realSize, '格式化后:', formatSize(realSize));
                    if (realSize > 0) {
                        $('#statsTotalSize').text(formatSize(realSize));
                    }
                }
            },
            error: function(xhr, status, error) {
                console.log('getDirSize请求失败:', status, error);
            }
        });
    }

    function navigateTo(path) {
        var now = Date.now();
        if (now - lastNavigateTime < navigateCooldown) {
            return;
        }
        lastNavigateTime = now;
        
        if (path === '..') {
            if (currentRelativePath === '/' || currentRelativePath === '') return;
            var parts = currentRelativePath.split('/');
            parts.pop();
            var up = parts.join('/');
            if (!up) up = '/';
            currentRelativePath = up;
        } else {
            if (currentRelativePath === '/') currentRelativePath = '';
            // 使用normalizePath进行路径拼接，避免重复斜杠
            currentRelativePath = normalizePath(currentRelativePath + '/' + path);
        }
        loadFiles();
    }
    
    function openFile(path, isDir) {
        if (isDir) {
            var p = (path || '').toString().trim();
            if (!p) return;
            currentRelativePath = p;
            loadFiles();
            return;
        }
        // 默认在线编辑
        $('#editFilePath').val(path);
        $.post('api/api_router.php', { action: 'getfilecontent', path: path }, function(d) {
            if (d.code === 'success' || d.status === true) {
                $('#editFileContent').val(d.content || d.data || '');
                $('#modalEdit').modal('show');
            } else {
                showToast(d.msg || '读取失败', 'error');
            }
        }, 'json').fail(function() {
            showToast('读取失败', 'error');
        });
    }

    function saveFile() {
        var path = $('#editFilePath').val();
        var content = $('#editFileContent').val();
        $.post('api/api_router.php', { action: 'savefile', path: path, content: content }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('保存成功', 'success');
                $('#modalEdit').modal('hide');
                clearCache(currentRelativePath);
                loadFiles();
            } else {
                showToast(d.msg || '保存失败', 'error');
            }
        }, 'json').fail(function() {
            showToast('保存失败', 'error');
        });
    }

    function createDir() {
        var name = $('#newDirName').val().trim();
        if (!name) { showToast('请输入目录名称', 'error'); return; }
        
        // 乐观更新：立即在UI中添加目录
        var cacheKey = normalizePath(currentRelativePath);
        var cacheData = fileCache[cacheKey];
        
        // 使用normalizePath进行路径拼接，避免重复斜杠
        var newDirPath = normalizePath(currentRelativePath + '/' + name);
        
        var newDir = {
            name: name,
            path: newDirPath,
            size: 0,
            modified: new Date().toISOString().slice(0, 19).replace('T', ' '),
            mtime: Math.floor(Date.now() / 1000),
            type: 'dir',
            is_dir: true,
            perm: '0755',
            owner: 'www'
        };
        
        if (cacheData && cacheData.files) {
            cacheData.files.unshift(newDir); // 添加到开头
            
            // 同步更新全局fileListData
            fileListData = cacheData.files;
            
            // 立即更新UI
            renderList(cacheData.files);
            updateFileStats(cacheData.files);
            
            console.log('乐观更新：已在UI中添加目录', newDirPath);
        }
        
        // 后台异步执行创建操作
        $.post('api/api_router.php', { action: 'createfolder', dir: currentRelativePath, name: name }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('创建成功', 'success');
                $('#modalNewDir').modal('hide');
                // 清除缓存，确保数据一致性
                clearCache(currentRelativePath);
            } else {
                showToast(d.msg || '创建失败', 'error');
                // 回滚：从UI中移除目录
                if (cacheData && cacheData.files) {
                    var dirIndex = cacheData.files.findIndex(function(f) {
                        return normalizePath(f.path) === newDirPath;
                    });
                    if (dirIndex !== -1) {
                        cacheData.files.splice(dirIndex, 1);
                        fileListData = cacheData.files;
                        renderList(cacheData.files);
                        updateFileStats(cacheData.files);
                        console.log('回滚：已从UI移除目录', newDirPath);
                    }
                }
            }
        }, 'json').fail(function() {
            showToast('创建失败', 'error');
            // 回滚：从UI中移除目录
            if (cacheData && cacheData.files) {
                var dirIndex = cacheData.files.findIndex(function(f) {
                    return normalizePath(f.path) === newDirPath;
                });
                if (dirIndex !== -1) {
                    cacheData.files.splice(dirIndex, 1);
                    fileListData = cacheData.files;
                    renderList(cacheData.files);
                    updateFileStats(cacheData.files);
                    console.log('回滚：已从UI移除目录', newDirPath);
                }
            }
        });
    }

    function createFile() {
        var name = $('#newFileName').val().trim();
        if (!name) { showToast('请输入文件名称', 'error'); return; }
        
        // 乐观更新：立即在UI中添加文件
        var cacheKey = normalizePath(currentRelativePath);
        var cacheData = fileCache[cacheKey];
        
        // 使用normalizePath进行路径拼接，避免重复斜杠
        var newFilePath = normalizePath(currentRelativePath + '/' + name);
        
        var newFile = {
            name: name,
            path: newFilePath,
            size: 0,
            modified: new Date().toISOString().slice(0, 19).replace('T', ' '),
            mtime: Math.floor(Date.now() / 1000),
            type: 'file',
            is_dir: false,
            perm: '0644',
            owner: 'www'
        };
        
        if (cacheData && cacheData.files) {
            // 先添加目录，再添加文件
            var dirCount = cacheData.files.filter(function(f) { return f.is_dir; }).length;
            cacheData.files.splice(dirCount, 0, newFile);
            
            // 同步更新全局fileListData
            fileListData = cacheData.files;
            
            // 立即更新UI
            renderList(cacheData.files);
            updateFileStats(cacheData.files);
            
            console.log('乐观更新：已在UI中添加文件', newFilePath);
        }
        
        // 后台异步执行创建操作
        $.post('api/api_router.php', { action: 'createfile', dir: currentRelativePath, name: name, content: '' }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('创建成功', 'success');
                $('#modalNewFile').modal('hide');
                // 清除缓存，确保数据一致性
                clearCache(currentRelativePath);
            } else {
                showToast(d.msg || '创建失败', 'error');
                // 回滚：从UI中移除文件
                if (cacheData && cacheData.files) {
                    var fileIndex = cacheData.files.findIndex(function(f) {
                        return normalizePath(f.path) === newFilePath;
                    });
                    if (fileIndex !== -1) {
                        cacheData.files.splice(fileIndex, 1);
                        fileListData = cacheData.files;
                        renderList(cacheData.files);
                        updateFileStats(cacheData.files);
                        console.log('回滚：已从UI移除文件', newFilePath);
                    }
                }
            }
        }, 'json').fail(function() {
            showToast('创建失败', 'error');
            // 回滚：从UI中移除文件
            if (cacheData && cacheData.files) {
                var fileIndex = cacheData.files.findIndex(function(f) {
                    return normalizePath(f.path) === newFilePath;
                });
                if (fileIndex !== -1) {
                    cacheData.files.splice(fileIndex, 1);
                    fileListData = cacheData.files;
                    renderList(cacheData.files);
                    updateFileStats(cacheData.files);
                    console.log('回滚：已从UI移除文件', newFilePath);
                }
            }
        });
    }

    function renameFile(path) {
        var oldName = path.split('/').pop();
        var newName = prompt('输入新名称', oldName);
        if (!newName || newName === oldName) return;
        
        // 乐观更新：立即在UI中更新文件名
        var normalizedPath = normalizePath(path);
        var cacheKey = normalizePath(currentRelativePath);
        var cacheData = fileCache[cacheKey];
        var renamedFile = null;
        var oldPath = null;
        
        if (cacheData && cacheData.files) {
            var fileIndex = cacheData.files.findIndex(function(f) {
                return normalizePath(f.path) === normalizedPath;
            });
            
            if (fileIndex !== -1) {
                renamedFile = cacheData.files[fileIndex];
                oldPath = renamedFile.path;
                
                // 更新文件名和路径
                var pathParts = path.split('/');
                pathParts.pop();
                var parentPath = pathParts.join('/');
                
                // 使用normalizePath进行路径拼接，避免重复斜杠
                var newPath = normalizePath(parentPath + '/' + newName);
                
                renamedFile.name = newName;
                renamedFile.path = newPath;
                
                // 同步更新全局fileListData
                fileListData = cacheData.files;
                
                // 立即更新UI
                renderList(cacheData.files);
                
                console.log('乐观更新：已在UI中重命名文件', oldPath, '->', newPath);
            }
        }
        
        // 后台异步执行重命名操作
        $.post('api/api_router.php', { action: 'renamefile', path: path, newName: newName }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('重命名成功', 'success');
                // 清除缓存，确保数据一致性
                clearCache(currentRelativePath);
            } else {
                showToast(d.msg || '重命名失败', 'error');
                // 回滚：恢复文件名到UI
                if (renamedFile && cacheData && oldPath) {
                    renamedFile.name = oldName;
                    renamedFile.path = oldPath;
                    fileListData = cacheData.files;
                    renderList(cacheData.files);
                    console.log('回滚：已恢复文件名到UI', oldPath);
                }
            }
        }, 'json').fail(function() {
            showToast('重命名失败', 'error');
            // 回滚：恢复文件名到UI
            if (renamedFile && cacheData && oldPath) {
                renamedFile.name = oldName;
                renamedFile.path = oldPath;
                fileListData = cacheData.files;
                renderList(cacheData.files);
                console.log('回滚：已恢复文件名到UI', oldPath);
            }
        });
    }

    function deleteFile(path) {
        if (!confirm('确定要删除吗？')) return;
        
        // 乐观更新：立即从UI中移除文件
        var normalizedPath = normalizePath(path);
        var cacheKey = normalizePath(currentRelativePath);
        var cacheData = fileCache[cacheKey];
        var removedFile = null;
        
        if (cacheData && cacheData.files) {
            var fileIndex = cacheData.files.findIndex(function(f) {
                return normalizePath(f.path) === normalizedPath;
            });
            
            if (fileIndex !== -1) {
                removedFile = cacheData.files[fileIndex];
                cacheData.files.splice(fileIndex, 1);
                
                // 同步更新全局fileListData
                fileListData = cacheData.files;
                
                // 立即更新UI
                renderList(cacheData.files);
                updateFileStats(cacheData.files);
                
                console.log('乐观更新：已从UI移除文件', path);
            }
        }
        
        // 后台异步执行删除操作
        console.log('发送删除请求，路径:', path);
        $.post('api/api_router.php', { action: 'deletefile', path: path }, function(d) {
            console.log('删除响应:', d);
            if (d.code === 'success' || d.status === true) {
                // 如果文件已经被删除，显示不同的提示
                if (d.already_deleted) {
                    showToast('文件已不存在，已从列表移除', 'success');
                } else {
                    showToast('删除成功', 'success');
                }
                // 清除所有缓存，确保数据一致性
                fileCache = {};
                console.log('已清除所有缓存');
                // 强制重新加载文件列表
                loadFiles(currentRelativePath, true);
            } else {
                showToast(d.msg || '删除失败', 'error');
                // 回滚：恢复文件到UI
                if (removedFile && cacheData) {
                    cacheData.files.push(removedFile);
                    fileListData = cacheData.files;
                    renderList(cacheData.files);
                    updateFileStats(cacheData.files);
                    console.log('回滚：已恢复文件到UI', path);
                }
            }
        }, 'json').fail(function() {
            showToast('删除失败', 'error');
            // 回滚：恢复文件到UI
            if (removedFile && cacheData) {
                cacheData.files.push(removedFile);
                fileListData = cacheData.files;
                renderList(cacheData.files);
                updateFileStats(cacheData.files);
                console.log('回滚：已恢复文件到UI', path);
            }
        });
    }

    function unzipFile(path) {
        var fileName = path.split('/').pop();
        $('#unzipFilePath').val(path);
        $('#unzipFileName').text(fileName);
        $('#unzipTargetDir').val('');

        // 加载目录列表供选择
        loadUnzipDirList();

        $('#modalUnzip').modal('show');
    }

    // 加载解压目标目录列表
    function loadUnzipDirList() {
        var html = '';
        var currentDir = currentRelativePath === '/' ? '' : currentRelativePath;

        // 从当前文件列表中提取子目录
        var subDirs = [];
        if (fileListData && fileListData.length > 0) {
            fileListData.forEach(function(f) {
                if (f.is_dir || f.type === 'dir') {
                    var dirName = f.name || (f.path ? f.path.split('/').pop() : '');
                    if (dirName) {
                        subDirs.push(dirName);
                    }
                }
            });
        }

        // 添加子目录选项
        if (subDirs.length > 0) {
            subDirs.forEach(function(dirName) {
                var fullPath = currentRelativePath === '/' ? '/' + dirName : currentRelativePath + '/' + dirName;
                html += '<div class="unzip-dir-item" data-path="' + fullPath + '" style="padding: 6px 8px; cursor: pointer; border-radius: 3px; display: flex; align-items: center; gap: 8px;">';
                html += '<i class="fas fa-folder" style="color: #FF9800; width: 16px;"></i>';
                html += '<span>' + dirName + '</span>';
                html += '</div>';
            });
        } else {
            html += '<div class="text-muted" style="padding: 12px; text-align: center;">当前目录下没有子目录</div>';
        }

        $('#unzipDirList').html(html);

        // 绑定点击事件
        $('#unzipDirList .unzip-dir-item').off('click').on('click', function() {
            var selectedPath = $(this).data('path');
            $('#unzipTargetDir').val(selectedPath);

            // 高亮选中项
            $('#unzipDirList .unzip-dir-item').css('background', '');
            $(this).css('background', '#e6f7ff');
        });
    }

    function doUnzip() {
        var path = $('#unzipFilePath').val();
        // path是相对路径（如 /123456.a116.vip.zip 或 /folder/file.zip）
        // 需要分离目录和文件名
        var lastSlashIndex = path.lastIndexOf('/');
        var sourceDir, file;

        if (lastSlashIndex === 0) {
            // 根目录下的文件，如 /filename.zip
            sourceDir = '/';
            file = path.substring(1);
        } else if (lastSlashIndex > 0) {
            // 子目录下的文件，如 /folder/filename.zip
            sourceDir = path.substring(0, lastSlashIndex);
            file = path.substring(lastSlashIndex + 1);
        } else {
            // 没有斜杠，只有文件名
            sourceDir = '/';
            file = path;
        }

        // 确保sourceDir以/开头
        if (!sourceDir.startsWith('/')) {
            sourceDir = '/' + sourceDir;
        }

        // 获取用户选择的目标解压目录
        var targetDir = $('#unzipTargetDir').val().trim();

        // 如果没有选择目标目录，则使用源文件所在目录
        if (!targetDir) {
            targetDir = sourceDir;
        }

        // 确保targetDir以/开头
        if (!targetDir.startsWith('/')) {
            targetDir = '/' + targetDir;
        }

        console.log('解压文件:', file, '从:', sourceDir, '到:', targetDir);

        $.post('api/api_router.php', { action: 'unzip', dir: sourceDir, file: file, target_dir: targetDir }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('解压成功', 'success');
                $('#modalUnzip').modal('hide');
                // 如果解压到当前目录，刷新当前目录；否则刷新目标目录
                if (targetDir === currentRelativePath || (targetDir === '/' && currentRelativePath === '/')) {
                    clearCache(currentRelativePath);
                    loadFiles();
                } else {
                    // 跳转到目标目录查看解压结果
                    currentRelativePath = targetDir;
                    clearCache(targetDir);
                    loadFiles();
                }
            } else {
                showToast(d.msg || '解压失败', 'error');
            }
        }, 'json').fail(function() {
            showToast('解压失败', 'error');
        });
    }

    // 权限设置相关函数
    function chmodFile(path) {
        $('#chmodFilePath').val(path);
        
        // 从文件列表中获取当前权限
        var currentMode = '755';
        var currentOwner = 'www';
        fileListData.forEach(function(f) {
            if (f.path === path || f.name === path.split('/').pop()) {
                var perm = f.perm || f.permissions || '';
                if (perm) {
                    var match = perm.match(/(\d{3,4})/);
                    if (match) currentMode = match[1];
                }
                if (f.owner) currentOwner = f.owner;
            }
        });
        
        // 设置输入框值
        $('#chmodModeInput').val(currentMode);
        $('#chmodOwnerSelect').val(currentOwner);
        
        // 根据数字权限设置checkbox
        setChmodCheckboxes(currentMode);
        
        $('#modalChmod').modal('show');
    }
    
    // 根据数字权限设置checkbox状态
    function setChmodCheckboxes(mode) {
        mode = parseInt(mode, 10);
        if (isNaN(mode)) mode = 755;
        
        var owner = Math.floor(mode / 100) % 10;
        var group = Math.floor(mode / 10) % 10;
        var public = mode % 10;
        
        // 所有者权限
        $('#chmodOwnerRead').prop('checked', owner & 4);
        $('#chmodOwnerWrite').prop('checked', owner & 2);
        $('#chmodOwnerExec').prop('checked', owner & 1);
        
        // 用户组权限
        $('#chmodGroupRead').prop('checked', group & 4);
        $('#chmodGroupWrite').prop('checked', group & 2);
        $('#chmodGroupExec').prop('checked', group & 1);
        
        // 公共权限
        $('#chmodPublicRead').prop('checked', public & 4);
        $('#chmodPublicWrite').prop('checked', public & 2);
        $('#chmodPublicExec').prop('checked', public & 1);
    }
    
    // 根据checkbox计算数字权限
    function getChmodMode() {
        var owner = 0, group = 0, public = 0;
        
        if ($('#chmodOwnerRead').is(':checked')) owner += 4;
        if ($('#chmodOwnerWrite').is(':checked')) owner += 2;
        if ($('#chmodOwnerExec').is(':checked')) owner += 1;
        
        if ($('#chmodGroupRead').is(':checked')) group += 4;
        if ($('#chmodGroupWrite').is(':checked')) group += 2;
        if ($('#chmodGroupExec').is(':checked')) group += 1;
        
        if ($('#chmodPublicRead').is(':checked')) public += 4;
        if ($('#chmodPublicWrite').is(':checked')) public += 2;
        if ($('#chmodPublicExec').is(':checked')) public += 1;
        
        return owner * 100 + group * 10 + public;
    }
    
    // 执行权限修改
    function doChmod() {
        var path = $('#chmodFilePath').val();
        var mode = $('#chmodModeInput').val();
        var owner = $('#chmodOwnerSelect').val();
        var recursive = $('#chmodRecursive').is(':checked') ? 1 : 0;
        
        if (!mode || !/^\d{3,4}$/.test(mode)) {
            showToast('请输入有效的权限值(如 755)', 'error');
            return;
        }
        
        $.post('api/api_router.php', { 
            action: 'chmodfile', 
            path: path, 
            mode: mode,
            owner: owner,
            recursive: recursive
        }, function(d) {
            if (d.code === 'success' || d.status === true) {
                showToast('权限修改成功', 'success');
                $('#modalChmod').modal('hide');
                clearCache(currentRelativePath);
                loadFiles();
            } else {
                showToast(d.msg || '修改失败', 'error');
            }
        }, 'json').fail(function() {
            showToast('修改失败', 'error');
        });
    }

    function doSearchContent() {
        openSearchContentModal();
    }

    function openSearchContentModal() {
        var relDir = (currentRelativePath || '/');
        if (!relDir.startsWith('/')) relDir = '/' + relDir;
        if (!relDir.endsWith('/')) relDir += '/';
        $('#searchDir').val(relDir);
        $('#searchKeyword').val('');
        $('#searchMode').val('content');
        setToggleButton($('#toggleIgnore'), false);
        setToggleButton($('#toggleMatchCase'), false);
        setToggleButton($('#toggleWholeWord'), false);
        setToggleButton($('#toggleRegex'), false);
        $('#searchIncludeSubdir').prop('checked', true);
        $('#searchSuffix').val('');
        $('#searchMtime').val('0');
        $('#searchSize').val('10485760');
        resetSearchResult();
        $('#modalSearchContent').modal('show');
        setTimeout(function(){ $('#searchKeyword').trigger('focus'); }, 150);
    }

    function setToggleButton($btn, on) {
        $btn.attr('data-value', on ? '1' : '0');
        if (on) $btn.addClass('btn-secondary text-white').removeClass('btn-outline-secondary');
        else $btn.removeClass('btn-secondary text-white').addClass('btn-outline-secondary');
    }

    function resetSearchResult() {
        $('#searchResultWrap').hide();
        $('#searchResultEmpty').show();
        $('#searchResultBody').empty();
        $('#searchResultSummary').text('');
    }

    function showSearchLoading() {
        $('#searchResultEmpty').hide();
        $('#searchResultWrap').show();
        $('#searchResultSummary').text('正在搜索...');
        $('#searchResultBody').html('<tr><td colspan="4" class="text-center text-muted" style="padding: 24px;"><i class="fas fa-spinner fa-spin mr-1"></i> 正在搜索...</td></tr>');
    }

    function showSearchResult(list, summaryText) {
        $('#searchResultEmpty').hide();
        $('#searchResultWrap').show();
        $('#searchResultSummary').text(summaryText || '');
        var html = '';
        (list || []).forEach(function(item) {
            var path = item.path || '';
            var name = item.name || (path ? path.split('/').pop() : '');
            var isDir = item.is_dir === true || item.is_dir === 1 || item.is_dir === '1' || item.type === 'dir';
            var size = isDir ? '-' : formatSize(item.size || 0);
            var mtime = formatTime(item.mtime || item.modified);
            var safePath = path.replace(/"/g, '&quot;');
            var safeName = $('<div>').text(name).html();
            html += '<tr>' +
                '<td class="text-truncate" style="max-width:520px;" title="' + safePath + '">' + safeName + '<div class="text-muted" style="font-size:12px;">' + safePath + '</div></td>' +
                '<td>' + size + '</td>' +
                '<td>' + mtime + '</td>' +
                '<td><button type="button" class="btn btn-sm btn-primary" data-open="' + safePath + '" data-isdir="' + (isDir ? '1' : '0') + '">打开</button></td>' +
                '</tr>';
        });
        if (!html) {
            html = '<tr><td colspan="4" class="text-center text-muted" style="padding: 24px;">未找到匹配结果</td></tr>';
        }
        $('#searchResultBody').html(html);
    }

    function executeSearch() {
        var keyword = ($('#searchKeyword').val() || '').trim();
        if (!keyword) {
            showToast('请输入搜索内容', 'error');
            return;
        }
        var dir = ($('#searchDir').val() || '').trim();
        if (!dir) {
            showToast('请输入目录', 'error');
            return;
        }

        // 使用normalizePath进行路径标准化
        dir = normalizePath(dir);
        
        var mode = $('#searchMode').val() || 'content';
        var includeSubdir = $('#searchIncludeSubdir').is(':checked') ? 1 : 0;
        var suffix = ($('#searchSuffix').val() || '').trim();
        var mtimeDays = parseInt($('#searchMtime').val() || '0', 10) || 0;
        var sizeMax = parseInt($('#searchSize').val() || '0', 10) || 0;
        var ignore = ($('#toggleIgnore').attr('data-value') === '1') ? 1 : 0;
        var matchCase = ($('#toggleMatchCase').attr('data-value') === '1') ? 1 : 0;
        var wholeWord = ($('#toggleWholeWord').attr('data-value') === '1') ? 1 : 0;
        var regex = ($('#toggleRegex').attr('data-value') === '1') ? 1 : 0;

        if (ignore) {
            matchCase = 0;
            setToggleButton($('#toggleMatchCase'), false);
        }

        if (currentSearchXhr && currentSearchXhr.readyState !== 4) {
            try { currentSearchXhr.abort(); } catch (e) {}
        }

        $('#btnExecuteSearch').prop('disabled', true).text('搜索中...');
        $('#btnStopSearch').prop('disabled', false);
        showSearchLoading();

        var payload = {
            action: 'searchfiles',
            path: dir,
            keyword: keyword,
            content: mode === 'content' ? 1 : 0,
            include_subdir: includeSubdir,
            suffixes: suffix,
            mtime_days: mtimeDays,
            size_max: sizeMax,
            ignore_case: ignore,
            match_case: matchCase ? 'true' : 'false',
            whole_word: wholeWord ? 'true' : 'false',
            regex: regex ? 'true' : 'false'
        };

        currentSearchXhr = $.ajax({
            url: 'api/api_router.php',
            type: 'POST',
            data: payload,
            dataType: 'json',
            timeout: 60000
        }).done(function(d) {
            try {
                var list = d.files || d.data || [];
                var checked = d.checked || 0;
                var limited = d.limit_reached ? true : false;
                var summary = '共找到 ' + (list.length || 0) + ' 个结果';
                if (mode === 'content') {
                    summary += '，已检查 ' + checked + ' 个文件' + (limited ? '（已达上限）' : '');
                }
                showSearchResult(list, summary);
            } catch (e) {
                showSearchResult([], '结果解析失败');
            }
        }).fail(function(xhr, status) {
            var msg = '搜索失败';
            if (status === 'timeout') msg = '搜索超时，请缩小范围或取消包含子目录';
            if (status === 'abort') msg = '已停止搜索';
            if (xhr && xhr.responseJSON && xhr.responseJSON.msg) msg = xhr.responseJSON.msg;
            showSearchResult([], msg);
        }).always(function() {
            $('#btnExecuteSearch').prop('disabled', false).text('搜索');
            $('#btnStopSearch').prop('disabled', true);
            currentSearchXhr = null;
        });
    }

    function toggleBatchPaste() {
        var n = $('#fileTableBody .file-cb:checked').length;
        // 目前只根据剪贴板是否有内容来显示粘贴按钮
        if (clipboardFiles.length > 0) {
            $('#btPaste').css('display', 'inline-flex');
            $('#btPasteCount').text(clipboardFiles.length);
        } else {
            $('#btPaste').hide();
        }
    }

    function doPaste() {
        if (!clipboardFiles.length) { showToast('剪贴板为空', 'error'); return; }
        
        // 使用normalizePath进行路径标准化
        var targetDir = normalizePath(currentRelativePath);
        var prefix = targetDir === '/' ? '/' : targetDir + '/';
        var promises = clipboardFiles.map(function(src) {
            var name = src.split('/').pop();
            var dest = prefix + name;
            var fd = new FormData();
            fd.append('action', clipboardAction === 'copy' ? 'copyfile' : 'movefile');
            fd.append('source', src);
            fd.append('target', dest);
            return fetch('api/api_router.php', { method: 'POST', body: fd });
        });
        Promise.all(promises).then(function(resps) {
            return Promise.all(resps.map(function(r) { return r.json(); }));
        }).then(function(results) {
            var fail = results.filter(function(r) { return r.code !== 'success' && r.status !== true; });
            if (!fail.length) {
                clipboardAction = null;
                clipboardFiles = [];
                toggleBatchPaste();
                clearCache(currentRelativePath);
                loadFiles();
                showToast('粘贴成功', 'success');
                    } else {
                clearCache(currentRelativePath);
                loadFiles();
            }
        }).catch(function() {
            showToast('粘贴失败', 'error');
        });
    }

    function renderFavorites() {
        var ul = document.getElementById('btFavoritesList');
        if (!ul) return;
        ul.innerHTML = '';
        if (!favorites.length) {
            var emptyLi = document.createElement('li');
            emptyLi.style.color = '#909399';
            emptyLi.style.cursor = 'default';
            emptyLi.textContent = '暂无收藏';
            ul.appendChild(emptyLi);
            return;
        }
        favorites.forEach(function(p) {
            var safePath = p.replace(/"/g, '&quot;');
            var li = document.createElement('li');
            var icon = document.createElement('i');
            icon.className = 'fas fa-folder';
            li.appendChild(icon);
            var textNode = document.createTextNode(' ' + (p.split("/").pop() || p) + ' ');
            li.appendChild(textNode);
            var btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'btn btn-link btn-sm p-0 ml-1';
            btn.style.fontSize = '11px';
            btn.setAttribute('data-remove', safePath);
            btn.textContent = '移除';
            li.appendChild(btn);
            li.onclick = function(e) {
                var remove = e.target.getAttribute('data-remove');
                if (remove) {
                    favorites = favorites.filter(function(x) { return x !== remove; });
                    localStorage.setItem('fileFavorites', JSON.stringify(favorites));
                    renderFavorites();
                } else {
                    currentRelativePath = p || '/';
                    loadFiles();
                }
            };
            ul.appendChild(li);
        });
    }

    function doSearch() {
        var kw = $('#btSearchInput').val().trim();
        if (!kw) { loadFiles(); return; }
        $.post('api/api_router.php', { action: 'searchfiles', path: currentRelativePath, keyword: kw }, function(d) {
                if (d.code === 'success' || d.status === true) {
                renderList(d.files || d.data || []);
                } else {
                showToast(d.msg || '搜索失败', 'error');
            }
        }, 'json').fail(function() {
            showToast('搜索失败', 'error');
        });
    }

    function bindEvents() {
        $('#btPathRefresh').on('click', function() {
            clearCache(currentRelativePath);
            loadFiles();
        });
        $('#btPathBack').on('click', function() { navigateTo('..'); });
        $('#btSearchBtn').on('click', doSearch);
        $('#btSearchInput').on('keydown', function(e) { if (e.key === 'Enter') doSearch(); });
        $('#btSearchContent').on('click', doSearchContent);
        $('#btnExecuteSearch').on('click', executeSearch);
        $('#btnStopSearch').on('click', function() {
            if (currentSearchXhr && currentSearchXhr.readyState !== 4) {
                try { currentSearchXhr.abort(); } catch (e) {}
            }
        });
        $('#searchKeyword').on('keydown', function(e){ if (e.key === 'Enter') executeSearch(); });
        $('#btnUseCurrentDir').on('click', function(){
            var relDir = (currentRelativePath || '/');
            if (!relDir.startsWith('/')) relDir = '/' + relDir;
            if (!relDir.endsWith('/')) relDir += '/';
            $('#searchDir').val(relDir);
        });
        $('#toggleIgnore').on('click', function(){ setToggleButton($(this), $(this).attr('data-value') !== '1'); });
        $('#toggleMatchCase').on('click', function(){ setToggleButton($(this), $(this).attr('data-value') !== '1'); });
        $('#toggleWholeWord').on('click', function(){ setToggleButton($(this), $(this).attr('data-value') !== '1'); });
        $('#toggleRegex').on('click', function(){ setToggleButton($(this), $(this).attr('data-value') !== '1'); });
        $('#btnClearSearchResult').on('click', resetSearchResult);
        $('#searchResultBody').on('click', 'button[data-open]', function(){
            var p = $(this).attr('data-open');
            if (!p) return;
            var isDir = $(this).attr('data-isdir') === '1';
            openFile(p, isDir);
        });

        $('#modalSearchContent').on('hidden.bs.modal', function(){
            if (currentSearchXhr && currentSearchXhr.readyState !== 4) {
                try { currentSearchXhr.abort(); } catch (e) {}
            }
            $('#btnExecuteSearch').prop('disabled', false).text('搜索');
            $('#btnStopSearch').prop('disabled', true);
            currentSearchXhr = null;
        });

        $('#btNewDir').on('click', function() { $('#newDirName').val(''); $('#modalNewDir').modal('show'); });
        $('#btNewFile').on('click', function() { $('#newFileName').val(''); $('#modalNewFile').modal('show'); });
        $('#btnConfirmNewDir').on('click', createDir);
        $('#btnConfirmNewFile').on('click', createFile);
        $('#btnSaveFile').on('click', saveFile);
        $('#btnConfirmUnzip').on('click', doUnzip);
        $('#btnConfirmChmod').on('click', doChmod);
        $('#btnConfirmDownloadUrl').on('click', downloadFromUrl);
        
        // 权限checkbox联动
        $('.chmod-checkbox input').on('change', function() {
            var mode = getChmodMode();
            $('#chmodModeInput').val(mode);
        });
        
        // 数字权限输入框联动
        $('#chmodModeInput').on('input', function() {
            var mode = $(this).val();
            if (/^\d{3,4}$/.test(mode)) {
                setChmodCheckboxes(mode);
            }
        });

        // 导航栏下拉菜单点击切换
        function initDropdownMenus() {
            // 使用原生 JavaScript 绑定事件，避免 jQuery 事件冲突
            document.querySelectorAll('.bt-nav-dropdown > button').forEach(function(btn) {
                btn.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    var dropdown = this.closest('.bt-nav-dropdown');
                    var isShown = dropdown.classList.contains('show');
                    
                    // 关闭所有下拉菜单
                    document.querySelectorAll('.bt-nav-dropdown').forEach(function(d) {
                        d.classList.remove('show');
                    });
                    
                    // 切换当前下拉菜单
                    if (!isShown) {
                        dropdown.classList.add('show');
                    }
                });
            });
            
            // 菜单项点击后关闭菜单
            document.querySelectorAll('.bt-nav-dropdown li').forEach(function(li) {
                li.addEventListener('click', function(e) {
                    e.stopPropagation();
                    this.closest('.bt-nav-dropdown').classList.remove('show');
                });
            });
        }
        
        // 初始化下拉菜单
        initDropdownMenus();
        
        // 点击其他地方关闭下拉菜单
        document.addEventListener('click', function(e) {
            if (!e.target.closest('.bt-nav-dropdown')) {
                document.querySelectorAll('.bt-nav-dropdown').forEach(function(d) {
                    d.classList.remove('show');
                });
            }
        });
        
        // 上传文件 - 打开弹窗
        $('#btUploadFile').on('click', function() {
            openUploadModal('file');
        });
        
        // 上传文件夹 - 打开弹窗
        $('#btUploadFolder').on('click', function() {
            openUploadModal('folder');
        });
        
        // URL链接下载
        $('#btDownloadUrl').on('click', function() {
            $('#downloadUrlInput').val('');
            $('#downloadUrlFilename').val('');
            var displayPath = currentRelativePath || '/';
            if (!displayPath.startsWith('/')) displayPath = '/' + displayPath;
            $('#downloadUrlPath').val(displayPath);
            $('#modalDownloadUrl').modal('show');
        });
        
        // 上传弹窗 - 下拉菜单切换
        $('#uploadDropdownBtn').on('click', function(e) {
            e.stopPropagation();
            $(this).closest('.upload-dropdown').toggleClass('show');
        });
        
        // 点击其他地方关闭上传弹窗下拉菜单
        $(document).on('click.closeUploadDropdown', function(e) {
            if (!$(e.target).closest('.upload-dropdown').length) {
                $('.upload-dropdown').removeClass('show');
            }
        });
        
        // 上传弹窗 - 选择文件菜单
        $('#uploadMenuFile').on('click', function(e) {
            e.stopPropagation();
            $('#uploadDropdownText').text('上传文件');
            uploadType = 'file';
            $('.upload-dropdown').removeClass('show');
            $('#uploadFileInput').click();
        });
        
        // 上传弹窗 - 选择文件夹菜单
        $('#uploadMenuFolder').on('click', function(e) {
            e.stopPropagation();
            $('#uploadDropdownText').text('上传文件夹');
            uploadType = 'folder';
            $('.upload-dropdown').removeClass('show');
            $('#uploadFolderInput').click();
        });
        
        // 清空列表按钮
        $('#btnClearList').on('click', function() {
            if (isUploading) return;
            uploadQueue = [];
            renderUploadList();
            $('#btnStartUpload').prop('disabled', true);
        });
        
        // 文件选择变化
        $('#uploadFileInput').on('change', function(e) {
            addFilesToQueue(e.target.files, 'file');
            $(this).val('');
        });
        
        // 文件夹选择变化
        $('#uploadFolderInput').on('change', function(e) {
            addFilesToQueue(e.target.files, 'folder');
            $(this).val('');
        });
        
        // 开始上传按钮
        $('#btnStartUpload').on('click', function() {
            startUpload();
        });

        // 双击文件/目录名称
        $('#fileTableBody').on('dblclick', '.file-name', function(e) {
            e.stopPropagation();
            var $tr = $(this).closest('.bt-row');
            var path = $tr.data('path');
            var isDir = $tr.data('isdir') === 1 || $tr.data('isdir') === '1';
            openFile(path, isDir);
        });

        $('#fileTableBody').on('click', '.op-link', function(e) {
            e.preventDefault();
            e.stopPropagation();
            var $a = $(this);
            var op = $a.data('op');
            var $tr = $a.closest('.bt-row');
            var path = $tr.data('path');
            var isDir = $tr.data('isdir') === 1 || $tr.data('isdir') === '1';
            switch (op) {
                case 'open': openFile(path, isDir); break;
                case 'download':
                    if (!isDir) {
                        // 使用隐藏的 iframe 下载
                        var downloadUrl = 'api/api_router.php?action=downloadfile&path=' + encodeURIComponent(path);
                        console.log('下载URL:', downloadUrl);
                        var iframe = document.createElement('iframe');
                        iframe.style.display = 'none';
                        iframe.src = downloadUrl;
                        document.body.appendChild(iframe);
                        setTimeout(function() {
                            document.body.removeChild(iframe);
                        }, 5000);
                    }
                    break;
                case 'edit': if (!isDir) openFile(path, false); break;
                case 'rename': renameFile(path); break;
                case 'chmod': chmodFile(path); break;
                case 'delete': deleteFile(path); break;
                case 'unzip': unzipFile(path); break;
            }
        });

        // 全选
        $('#btSelectAll').on('change', function() {
            var checked = this.checked;
            $('#fileTableBody .file-cb').prop('checked', checked);
            toggleBatchPaste();
        });

        var dropzone = $('.bt-dropzone');
        var fileBody = $('.bt-table-wrap'); // 拖拽区域改为外层容器
        var dropTimer;

        // 使用 document 来捕获全局的拖拽事件
        $(document).on('dragenter', function(e) {
            var target = $(e.target);
            // 只有当拖拽进入文件列表区域时才显示提示
            if (fileBody.is(target) || fileBody.has(target).length > 0) {
                e.preventDefault();
                e.stopPropagation();
                dropzone.css('display', 'flex');
                clearTimeout(dropTimer);
            }
        });

        $(document).on('dragover', function(e) {
            var target = $(e.target);
            if (fileBody.is(target) || fileBody.has(target).length > 0) {
                e.preventDefault();
                e.stopPropagation();
            }
        });

        // 当鼠标离开窗口时隐藏
        $(document).on('dragleave', function(e) {
            if (e.originalEvent.clientX === 0 && e.originalEvent.clientY === 0) {
                dropzone.hide();
            }
        });

        fileBody.on('dragleave', function(e) {
            e.preventDefault();
            e.stopPropagation();
            // 使用定时器以防止在子元素之间移动时闪烁
            dropTimer = setTimeout(function() {
                dropzone.hide();
            }, 100);
        });

        fileBody.on('drop', function(e) {
            e.preventDefault();
            e.stopPropagation();
            dropzone.hide();
            var files = e.originalEvent.dataTransfer.files;
            if (!files.length) return;
            
            handleFileUpload(files);
        });


        $('#fileTableBody').on('change', '.file-cb', function() {
            toggleBatchPaste();
        });

        $('#btBatchCopy').on('click', function() {
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { arr.push(this.value); });
            if (!arr.length) { showToast('请先选择文件', 'error'); return; }
            clipboardAction = 'copy';
            clipboardFiles = arr;
            toggleBatchPaste();
            showToast('已复制 ' + arr.length + ' 项', 'success');
        });

        $('#btBatchCut').on('click', function() {
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { arr.push(this.value); });
            if (!arr.length) { showToast('请先选择文件', 'error'); return; }
            clipboardAction = 'cut';
            clipboardFiles = arr;
            toggleBatchPaste();
            showToast('已剪切 ' + arr.length + ' 项', 'success');
        });

        $('#btBatchZip').on('click', function() {
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { 
                var path = $(this).closest('tr').data('path');
                if (path) arr.push(path);
            });
            if (!arr.length) { showToast('请先选择要压缩的项', 'error'); return; }
            
            // 显示批量压缩弹窗
            $('#batchZipCount').text(arr.length);
            $('#batchZipName').val('archive_' + new Date().getTime() + '.zip');
            var displayPath = currentRelativePath || '/';
            if (!displayPath.startsWith('/')) displayPath = '/' + displayPath;
            $('#batchZipPath').val(displayPath);
            $('#modalBatchZip').modal('show');
        });
        
        // 确认批量压缩
        $('#btnConfirmBatchZip').on('click', function() {
            var zipName = $('#batchZipName').val().trim();
            if (!zipName) {
                showToast('请输入压缩文件名', 'error');
                return;
            }
            
            // 确保有扩展名
            if (!/\.(zip|tar\.gz|tar)$/i.test(zipName)) {
                zipName += '.zip';
            }
            
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { 
                var path = $(this).closest('tr').data('path');
                if (path) arr.push(path);
            });
            
            if (!arr.length) {
                showToast('没有选择任何文件', 'error');
                return;
            }
            
            var $btn = $(this);
            $btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> 压缩中...');
            
            // 提取文件名（相对于当前目录）
            var fileNames = arr.map(function(fullPath) {
                return fullPath.split('/').pop();
            });
            
            // 调试输出
            console.log('压缩请求参数:', {
                action: 'zip',
                dir: currentRelativePath,
                files: fileNames,
                zipname: zipName
            });
            
            $.post('api/api_router.php', { 
                action: 'zip', 
                dir: currentRelativePath, 
                files: JSON.stringify(fileNames),
                zipname: zipName
            }, function(d) {
                console.log('压缩响应:', d);
                $btn.prop('disabled', false).html('<i class="fas fa-file-archive"></i> 开始压缩');
                if (d.code === 'success' || d.status === true) {
                    showToast('压缩成功', 'success');
                    $('#modalBatchZip').modal('hide');
                    clearCache(currentRelativePath);
                    loadFiles();
                } else {
                    showToast(d.msg || '压缩失败', 'error');
                }
            }, 'json').fail(function() {
                $btn.prop('disabled', false).html('<i class="fas fa-file-archive"></i> 开始压缩');
                showToast('压缩失败', 'error');
            });
        });

        $('#btBatchUnzip').on('click', function() {
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { arr.push(this.value); });
            if (!arr.length) { showToast('请先选择要解压的文件', 'error'); return; }
            // 过滤压缩文件
            var zipFiles = arr.filter(function(f) {
                var ext = f.split('.').pop().toLowerCase();
                return ['zip', 'tar', 'gz', '7z', 'rar'].indexOf(ext) !== -1;
            });
            if (zipFiles.length === 0) { showToast('请选择压缩文件（zip/tar/gz/7z/rar）', 'error'); return; }
            if (!confirm('确定解压选中的 ' + zipFiles.length + ' 个压缩文件吗？')) return;
            var successCount = 0;
            var failCount = 0;
            var deferreds = [];
            zipFiles.forEach(function(path) {
                var lastSlashIndex = path.lastIndexOf('/');
                var dir, file;
                
                if (lastSlashIndex === 0) {
                    dir = '/';
                    file = path.substring(1);
                } else if (lastSlashIndex > 0) {
                    dir = path.substring(0, lastSlashIndex);
                    file = path.substring(lastSlashIndex + 1);
                } else {
                    dir = '/';
                    file = path;
                }
                
                if (!dir.startsWith('/')) { dir = '/' + dir; }
                
                var deferred = $.post('api/api_router.php', { action: 'unzip', dir: dir, file: file }, function(d) {
                    if (d.code === 'success' || d.status === true) { successCount++; } else { failCount++; }
                }, 'json').fail(function() { failCount++; });
                deferreds.push(deferred);
            });
            $.when.apply($, deferreds).done(function() {
                showToast('解压完成！成功: ' + successCount + ' 个，失败: ' + failCount + ' 个', successCount > failCount ? 'success' : 'error');
                clearCache(currentRelativePath);
                loadFiles();
            });
        });

        $('#btBatchPaste').on('click', function() {
            if (!clipboardFiles.length) { showToast('剪贴板为空', 'error'); return; }
            doPaste();
        });

        $('#btBatchChmod').on('click', function() {
            var first = $('#fileTableBody .file-cb:checked').first();
            if (!first.length) { showToast('请先选择文件', 'error'); return; }
            chmodFile(first.val());
        });

        $('#btBatchDel').on('click', function() {
            var arr = [];
            $('#fileTableBody .file-cb:checked').each(function() { arr.push(this.value); });
            if (!arr.length) { showToast('请先选择文件', 'error'); return; }
            if (!confirm('确定删除选中的 ' + arr.length + ' 项？')) return;
            $.post('api/api_router.php', { action: 'deletefiles', files: JSON.stringify(arr) }, function(d) {
                if (d.code === 'success' || d.status === true) {
                    showToast('已删除', 'success');
                    clipboardFiles = [];
                    toggleBatchPaste();
                    clearCache(currentRelativePath);
                    loadFiles();
                } else {
                    showToast(d.msg || '删除失败', 'error');
                }
            }, 'json').fail(function() {
                showToast('删除失败', 'error');
            });
        });

        $('#btPaste').on('click', function() {
            doPaste();
        });

        // 右键菜单
        $('#fileTableBody').on('contextmenu', '.bt-row', function(e) {
            e.preventDefault();
            var $tr = $(this);
            $('#fileTableBody .bt-row').removeClass('selected');
            $tr.addClass('selected');
            currentContextPath = $tr.data('path');
            $('#ctxMenu').css({ top: e.clientY + 'px', left: e.clientX + 'px' }).show();
        });
        $(document).on('click.closeContextMenu', function() {
            $('#ctxMenu').hide();
        });
        $('#ctxMenu').on('click', 'li[data-id]', function(e) {
            var id = $(this).data('id');
            var path = currentContextPath;
            if (!path) return;
            // 从 fileListData 中查找对应的文件/目录信息
            var isDir = false;
            for (var i = 0; i < fileListData.length; i++) {
                if (fileListData[i].path === path) {
                    isDir = fileListData[i].is_dir || fileListData[i].type === 'dir';
                    break;
                }
            }
            var fileName = path.split('/').pop();
            var ext = fileName.split('.').pop().toLowerCase();
            var isZip = (ext === 'zip' || ext === 'tar' || ext === 'gz' || ext === '7z' || ext === 'rar');
            
            switch (id) {
                case 'open': openFile(path, isDir); break;
                case 'download': 
                    // 使用隐藏的 iframe 下载，避免浏览器拦截
                    var downloadUrl = 'api/api_router.php?action=downloadfile&path=' + encodeURIComponent(path);
                    var iframe = document.createElement('iframe');
                    iframe.style.display = 'none';
                    iframe.src = downloadUrl;
                    document.body.appendChild(iframe);
                    setTimeout(function() {
                        document.body.removeChild(iframe);
                    }, 5000);
                    break;
                case 'rename': renameFile(path); break;
                case 'chmod': chmodFile(path); break;
                case 'zip': 
                    if (!confirm('确定压缩 ' + fileName + ' 吗？')) return;
                    // 只传递文件名
                    $.post('api/api_router.php', { action: 'zip', dir: currentRelativePath, files: JSON.stringify([fileName]) }, function(d) {
                        if (d.code === 'success' || d.status === true) {
                            showToast('压缩成功', 'success');
                            loadFiles();
                        } else {
                            showToast(d.msg || '压缩失败', 'error');
                        }
                    }, 'json');
                    break;
                case 'unzip': 
                    if (!isZip) {
                        showToast('请选择压缩文件(zip/tar/gz)', 'error');
                        return;
                    }
                    unzipFile(path);
                    break;
                case 'del': deleteFile(path); break;
            }
            $('#ctxMenu').hide();
        });
    }

    $(function() {
        updatePathDisplay();
        renderFavorites();
        bindEvents();
        loadFiles();
        toggleBatchPaste();
    });
})();
    </script>

</body>
</html>
