{"id":312,"url":"https:\/\/web.daaee.cn\/.\/2026\/baksend.php","title":"\u6587\u4ef6\u5907\u4efd\u7cfb\u7edf - \u589e\u5f3a\u7248","content":"\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>\u6587\u4ef6\u5907\u4efd\u7cfb\u7edf - \u589e\u5f3a\u7248<\/title>\n    <style>\n        \/* \u4fdd\u7559\u539f\u6709\u6837\u5f0f\uff0c\u65b0\u589e\u6837\u5f0f\u5728\u4e0b\u9762 *\/\n        \n        .api-info {\n            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);\n            color: white;\n            padding: 15px 20px;\n            border-radius: 8px;\n            margin-bottom: 20px;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            box-shadow: 0 4px 15px rgba(0,0,0,0.1);\n        }\n        \n        .api-info h3 {\n            margin: 0;\n            font-size: 1.2em;\n            display: flex;\n            align-items: center;\n            gap: 10px;\n        }\n        \n        .api-info .method-badge {\n            background: rgba(255,255,255,0.2);\n            padding: 3px 10px;\n            border-radius: 20px;\n            font-size: 0.9em;\n            font-weight: bold;\n        }\n        \n        .api-method-selector {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n        }\n        \n        .api-method-selector select {\n            padding: 8px 15px;\n            border-radius: 6px;\n            border: none;\n            background: rgba(255,255,255,0.9);\n            font-size: 0.9em;\n            cursor: pointer;\n            min-width: 150px;\n        }\n        \n        .api-method-selector select:focus {\n            outline: none;\n            box-shadow: 0 0 0 2px rgba(255,255,255,0.3);\n        }\n        \n        .method-description {\n            font-size: 0.85em;\n            opacity: 0.9;\n            margin-top: 5px;\n        }\n        \n        .connection-test {\n            margin-left: 10px;\n        }\n        \n        .connection-test button {\n            background: rgba(255,255,255,0.2);\n            border: 1px solid rgba(255,255,255,0.3);\n            color: white;\n            padding: 5px 15px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 0.9em;\n            transition: all 0.3s;\n        }\n        \n        .connection-test button:hover {\n            background: rgba(255,255,255,0.3);\n        }\n        \n        .method-details {\n            background: #f8f9fa;\n            padding: 15px;\n            border-radius: 8px;\n            margin-bottom: 20px;\n            border-left: 4px solid #4facfe;\n        }\n        \n        .method-details h4 {\n            margin-top: 0;\n            color: #333;\n        }\n        \n        .method-features {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n            gap: 15px;\n            margin-top: 10px;\n        }\n        \n        .feature-item {\n            background: white;\n            padding: 10px;\n            border-radius: 6px;\n            border: 1px solid #e9ecef;\n            font-size: 0.9em;\n        }\n        \n        .feature-item strong {\n            color: #4facfe;\n        }\n        \n        .retry-config {\n            display: flex;\n            gap: 15px;\n            margin-top: 10px;\n            font-size: 0.9em;\n        }\n        \n        .config-item {\n            display: flex;\n            align-items: center;\n            gap: 5px;\n        }\n        \n        .config-item label {\n            font-weight: bold;\n            color: #666;\n        }\n        \n        .config-item input {\n            width: 60px;\n            padding: 3px 8px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            text-align: center;\n        }\n        \n        .debug-info {\n            background: #f8f9fa;\n            padding: 10px;\n            border-radius: 6px;\n            margin-top: 10px;\n            font-size: 0.85em;\n            color: #666;\n            border: 1px solid #e9ecef;\n        }\n        \n        .debug-info pre {\n            margin: 5px 0;\n            padding: 8px;\n            background: #f1f3f4;\n            border-radius: 4px;\n            overflow-x: auto;\n            font-size: 0.8em;\n        }\n        \n        .status-indicator {\n            display: inline-block;\n            width: 10px;\n            height: 10px;\n            border-radius: 50%;\n            margin-right: 8px;\n        }\n        \n        .status-online {\n            background-color: #28a745;\n            animation: pulse 2s infinite;\n        }\n        \n        .status-offline {\n            background-color: #dc3545;\n        }\n        \n        @keyframes pulse {\n            0% { opacity: 1; }\n            50% { opacity: 0.5; }\n            100% { opacity: 1; }\n        }\n        \n        .advanced-config {\n            background: #f8f9fa;\n            padding: 20px;\n            border-radius: 8px;\n            margin-bottom: 20px;\n            border: 1px solid #ddd;\n        }\n        \n        .advanced-config h4 {\n            margin-top: 0;\n            color: #333;\n            cursor: pointer;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n        }\n        \n        .advanced-config-content {\n            display: none;\n        }\n        \n        .advanced-config.active .advanced-config-content {\n            display: block;\n        }\n        \n        .config-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n            gap: 15px;\n            margin-top: 15px;\n        }\n        \n        .config-field {\n            margin-bottom: 10px;\n        }\n        \n        .config-field label {\n            display: block;\n            margin-bottom: 5px;\n            font-weight: bold;\n            color: #555;\n            font-size: 0.9em;\n        }\n        \n        .config-field input {\n            width: 100%;\n            padding: 8px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            font-size: 0.9em;\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n        <header>\n            <h1>\ud83d\udcc1 \u6587\u4ef6\u5907\u4efd\u7cfb\u7edf - \u589e\u5f3a\u7248<\/h1>\n            <p>\u652f\u6301\u591a\u79cdAPI\u8fde\u63a5\u65b9\u5f0f\uff0c\u66f4\u7a33\u5b9a\u53ef\u9760\u7684\u5907\u4efd\u89e3\u51b3\u65b9\u6848<\/p>\n        <\/header>\n        \n        <div class=\"content\">\n            <div class=\"api-info\" id=\"apiInfo\">\n                <!-- API\u4fe1\u606f\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"method-details\" id=\"methodDetails\">\n                <!-- \u65b9\u6cd5\u8be6\u60c5\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"advanced-config\" id=\"advancedConfig\">\n                <h4 onclick=\"toggleAdvancedConfig()\">\n                    \u2699\ufe0f \u9ad8\u7ea7\u914d\u7f6e\n                    <span id=\"advancedToggle\">\u25bc<\/span>\n                <\/h4>\n                <div class=\"advanced-config-content\">\n                    <div class=\"config-grid\">\n                        <div class=\"config-field\">\n                            <label>API\u8d85\u65f6\u65f6\u95f4 (\u79d2):<\/label>\n                            <input type=\"number\" id=\"configTimeout\" value=\"300\" min=\"30\" max=\"3600\">\n                        <\/div>\n                        <div class=\"config-field\">\n                            <label>\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4 (\u79d2):<\/label>\n                            <input type=\"number\" id=\"configConnectTimeout\" value=\"30\" min=\"5\" max=\"300\">\n                        <\/div>\n                        <div class=\"config-field\">\n                            <label>\u91cd\u8bd5\u6b21\u6570:<\/label>\n                            <input type=\"number\" id=\"configRetryTimes\" value=\"3\" min=\"0\" max=\"10\">\n                        <\/div>\n                        <div class=\"config-field\">\n                            <label>\u91cd\u8bd5\u5ef6\u8fdf (\u6beb\u79d2):<\/label>\n                            <input type=\"number\" id=\"configRetryDelay\" value=\"1000\" min=\"0\" max=\"10000\">\n                        <\/div>\n                    <\/div>\n                    <button class=\"btn\" onclick=\"saveAdvancedConfig()\" style=\"margin-top: 15px; padding: 8px 20px; font-size: 0.9em;\">\n                        \u4fdd\u5b58\u9ad8\u7ea7\u914d\u7f6e\n                    <\/button>\n                <\/div>\n            <\/div>\n            \n            <div class=\"stats-grid\" id=\"stats\">\n                <!-- \u7edf\u8ba1\u6570\u636e\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"exclude-panel\" id=\"excludePanel\">\n                <!-- \u6392\u9664\u89c4\u5219\u4fe1\u606f\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"backup-controls\">\n                <button class=\"btn\" onclick=\"startBackup()\" id=\"startBtn\">\u5f00\u59cb\u5907\u4efd<\/button>\n                <button class=\"btn btn-stop\" onclick=\"stopBackup()\" id=\"stopBtn\" style=\"display:none\">\u505c\u6b62\u5907\u4efd<\/button>\n                <button class=\"btn\" onclick=\"resetBackup()\" id=\"resetBtn\">\u91cd\u7f6e\u5907\u4efd<\/button>\n                <button class=\"btn\" onclick=\"testConnection()\" id=\"testBtn\">\u6d4b\u8bd5\u8fde\u63a5<\/button>\n                <button class=\"btn\" onclick=\"location.reload()\">\u5237\u65b0\u72b6\u6001<\/button>\n                \n                <div class=\"auto-backup\">\n                    <label>\n                        <input type=\"checkbox\" id=\"autoBackup\" onchange=\"toggleAutoBackup()\">\n                        \u81ea\u52a8\u5907\u4efd\n                    <\/label>\n                    <input type=\"number\" id=\"interval\" value=\"2\" min=\"1\" max=\"60\" style=\"display:none\">\n                    <span style=\"display:none\" id=\"intervalText\">\u79d2\u95f4\u9694<\/span>\n                <\/div>\n            <\/div>\n            \n            <div class=\"progress-section\">\n                <h2>\u5907\u4efd\u8fdb\u5ea6<\/h2>\n                <div class=\"progress-container\">\n                    <div class=\"progress-bar\" id=\"progressBar\">\n                        <div class=\"progress-text\" id=\"progressText\">0%<\/div>\n                    <\/div>\n                <\/div>\n                <div id=\"progressInfo\">\u7b49\u5f85\u5f00\u59cb\u5907\u4efd...<\/div>\n            <\/div>\n            \n            <div class=\"file-info\" id=\"currentFile\">\n                <!-- \u5f53\u524d\u6587\u4ef6\u4fe1\u606f\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"log-container\" id=\"log\">\n                <!-- \u65e5\u5fd7\u5c06\u901a\u8fc7JavaScript\u52a8\u6001\u52a0\u8f7d -->\n            <\/div>\n            \n            <div class=\"debug-info\" id=\"debugInfo\" style=\"display:none\">\n                <!-- \u8c03\u8bd5\u4fe1\u606f -->\n            <\/div>\n            \n            <div class=\"spinner\" id=\"spinner\"><\/div>\n        <\/div>\n        \n        <footer>\n            <p>\u00a9 2023 \u6587\u4ef6\u5907\u4efd\u7cfb\u7edf - \u589e\u5f3a\u7248 | \u517c\u5bb9 PHP 5.3 - PHP 8.x<\/p>\n            <p>\u652f\u6301API\u8fde\u63a5\u65b9\u5f0f: cURL, Socket, Stream | \u5f53\u524d\u76ee\u5f55: \/mnt\/sda1\/www\/2026<\/p>\n        <\/footer>\n    <\/div>\n    \n    <script>\n        let isBackupRunning = false;\n        let autoBackupEnabled = false;\n        let backupInterval;\n        let logEntries = [];\n        let currentApiMethod = 'auto';\n        \n        \/\/ \u52a0\u8f7dAPI\u65b9\u6cd5\u4fe1\u606f\n        function loadApiInfo() {\n            fetch('baksend.php?action=api_methods')\n                .then(response => response.json())\n                .then(data => {\n                    const methods = data.methods;\n                    const current = data.current;\n                    currentApiMethod = current;\n                    \n                    \/\/ \u66f4\u65b0API\u4fe1\u606f\u663e\u793a\n                    const apiInfo = document.getElementById('apiInfo');\n                    apiInfo.innerHTML = `\n                        <div>\n                            <h3>\n                                <span class=\"status-indicator status-online\"><\/span>\n                                API\u8fde\u63a5\u72b6\u6001\n                                <span class=\"method-badge\">${methods[current] || current}<\/span>\n                            <\/h3>\n                            <div class=\"method-description\">\n                                \u5f53\u524d\u4f7f\u7528: ${methods[current] || '\u81ea\u52a8\u9009\u62e9'}\n                            <\/div>\n                        <\/div>\n                        <div class=\"api-method-selector\">\n                            <select id=\"apiMethodSelect\" onchange=\"changeApiMethod(this.value)\">\n                                <option value=\"auto\" ${current == 'auto' ? 'selected' : ''}>\u81ea\u52a8\u9009\u62e9<\/option>\n                                ${Object.keys(methods).map(key => `\n                                    <option value=\"${key}\" ${current == key ? 'selected' : ''}>\n                                        ${methods[key]}\n                                    <\/option>\n                                `).join('')}\n                            <\/select>\n                            <div class=\"connection-test\">\n                                <button onclick=\"testConnection()\">\u6d4b\u8bd5\u8fde\u63a5<\/button>\n                            <\/div>\n                        <\/div>\n                    `;\n                    \n                    \/\/ \u66f4\u65b0\u65b9\u6cd5\u8be6\u60c5\n                    updateMethodDetails(current, methods);\n                });\n        }\n        \n        \/\/ \u66f4\u65b0\u65b9\u6cd5\u8be6\u60c5\n        function updateMethodDetails(method, methods) {\n            const details = document.getElementById('methodDetails');\n            \n            let description = '';\n            switch (method) {\n                case 'curl':\n                    description = '\u4f7f\u7528cURL\u5e93\u8fdb\u884cHTTP\u8bf7\u6c42\uff0c\u652f\u6301HTTPS\u3001\u4ee3\u7406\u3001\u538b\u7f29\u7b49\u9ad8\u7ea7\u529f\u80fd\uff0c\u6027\u80fd\u6700\u597d\u3002';\n                    break;\n                case 'socket':\n                    description = '\u4f7f\u7528\u539f\u751fSocket\u8fde\u63a5\uff0c\u4e0d\u4f9d\u8d56\u5916\u90e8\u5e93\uff0c\u517c\u5bb9\u6027\u6700\u597d\u3002';\n                    break;\n                case 'stream':\n                    description = '\u4f7f\u7528PHP\u6d41\u4e0a\u4e0b\u6587\uff0c\u7b80\u5355\u6613\u7528\uff0c\u9002\u5408\u57fa\u672c\u9700\u6c42\u3002';\n                    break;\n                default:\n                    description = '\u81ea\u52a8\u9009\u62e9\u53ef\u7528\u7684\u6700\u4f73\u8fde\u63a5\u65b9\u5f0f\u3002';\n            }\n            \n            details.innerHTML = `\n                <h4>\ud83d\udd27 \u5f53\u524d\u8fde\u63a5\u65b9\u5f0f: ${methods[method] || '\u81ea\u52a8\u9009\u62e9'}<\/h4>\n                <p>${description}<\/p>\n                <div class=\"method-features\">\n                    <div class=\"feature-item\">\n                        <strong>cURL<\/strong>: ${methods['curl'] ? '\u2705 \u53ef\u7528' : '\u274c \u4e0d\u53ef\u7528'}\n                    <\/div>\n                    <div class=\"feature-item\">\n                        <strong>Socket<\/strong>: ${methods['socket'] ? '\u2705 \u53ef\u7528' : '\u274c \u4e0d\u53ef\u7528'}\n                    <\/div>\n                    <div class=\"feature-item\">\n                        <strong>Stream<\/strong>: ${methods['stream'] ? '\u2705 \u53ef\u7528' : '\u274c \u4e0d\u53ef\u7528'}\n                    <\/div>\n                <\/div>\n                <div class=\"retry-config\">\n                    <div class=\"config-item\">\n                        <label>\u8d85\u65f6:<\/label>\n                        <input type=\"number\" id=\"timeoutInput\" value=\"300\" onchange=\"updateTimeout(this.value)\">\n                        <span>\u79d2<\/span>\n                    <\/div>\n                    <div class=\"config-item\">\n                        <label>\u91cd\u8bd5:<\/label>\n                        <input type=\"number\" id=\"retryInput\" value=\"3\" onchange=\"updateRetry(this.value)\">\n                        <span>\u6b21<\/span>\n                    <\/div>\n                <\/div>\n            `;\n        }\n        \n        \/\/ \u66f4\u6539API\u65b9\u6cd5\n        function changeApiMethod(method) {\n            fetch('baksend.php?action=set_api_method', {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application\/x-www-form-urlencoded',\n                },\n                body: 'method=' + encodeURIComponent(method)\n            })\n            .then(response => response.json())\n            .then(data => {\n                if (data.success) {\n                    addLogEntry(`API\u65b9\u6cd5\u5df2\u5207\u6362\u4e3a: ${method}`, 'success');\n                    loadApiInfo();\n                } else {\n                    addLogEntry(`\u5207\u6362API\u65b9\u6cd5\u5931\u8d25: ${data.message}`, 'error');\n                }\n            })\n            .catch(error => {\n                addLogEntry(`\u5207\u6362API\u65b9\u6cd5\u51fa\u9519: ${error.message}`, 'error');\n            });\n        }\n        \n        \/\/ \u6d4b\u8bd5\u8fde\u63a5\n        function testConnection() {\n            const testBtn = document.getElementById('testBtn');\n            const originalText = testBtn.textContent;\n            testBtn.textContent = '\u6d4b\u8bd5\u4e2d...';\n            testBtn.disabled = true;\n            \n            fetch('baksend.php?action=stats')\n                .then(response => response.json())\n                .then(data => {\n                    if (data.api_method) {\n                        addLogEntry(`\u8fde\u63a5\u6d4b\u8bd5\u6210\u529f\uff0c\u5f53\u524dAPI\u65b9\u6cd5: ${data.api_method}`, 'success');\n                        loadApiInfo();\n                    } else {\n                        addLogEntry('\u8fde\u63a5\u6d4b\u8bd5\u5931\u8d25\uff0c\u65e0\u6cd5\u83b7\u53d6API\u65b9\u6cd5\u4fe1\u606f', 'error');\n                    }\n                    testBtn.textContent = originalText;\n                    testBtn.disabled = false;\n                })\n                .catch(error => {\n                    addLogEntry(`\u8fde\u63a5\u6d4b\u8bd5\u51fa\u9519: ${error.message}`, 'error');\n                    testBtn.textContent = originalText;\n                    testBtn.disabled = false;\n                });\n        }\n        \n        \/\/ \u5207\u6362\u9ad8\u7ea7\u914d\u7f6e\u663e\u793a\n        function toggleAdvancedConfig() {\n            const config = document.getElementById('advancedConfig');\n            const toggle = document.getElementById('advancedToggle');\n            \n            config.classList.toggle('active');\n            toggle.textContent = config.classList.contains('active') ? '\u25b2' : '\u25bc';\n        }\n        \n        \/\/ \u4fdd\u5b58\u9ad8\u7ea7\u914d\u7f6e\n        function saveAdvancedConfig() {\n            const timeout = document.getElementById('configTimeout').value;\n            const connectTimeout = document.getElementById('configConnectTimeout').value;\n            const retryTimes = document.getElementById('configRetryTimes').value;\n            const retryDelay = document.getElementById('configRetryDelay').value;\n            \n            \/\/ \u8fd9\u91cc\u5e94\u8be5\u5c06\u914d\u7f6e\u4fdd\u5b58\u5230\u670d\u52a1\u5668\n            \/\/ \u7531\u4e8e\u662f\u6f14\u793a\uff0c\u6211\u4eec\u53ea\u66f4\u65b0\u672c\u5730\u663e\u793a\n            addLogEntry(`\u9ad8\u7ea7\u914d\u7f6e\u5df2\u66f4\u65b0: \u8d85\u65f6=${timeout}s, \u91cd\u8bd5=${retryTimes}\u6b21, \u5ef6\u8fdf=${retryDelay}ms`, 'info');\n            \n            \/\/ \u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5e94\u8be5\u53d1\u9001\u5230\u670d\u52a1\u5668\u4fdd\u5b58\n            \/\/ fetch('save_config.php', { ... })\n        }\n        \n        \/\/ \u66f4\u65b0\u8d85\u65f6\u65f6\u95f4\n        function updateTimeout(value) {\n            addLogEntry(`\u8d85\u65f6\u65f6\u95f4\u5df2\u66f4\u65b0\u4e3a: ${value}\u79d2`, 'info');\n        }\n        \n        \/\/ \u66f4\u65b0\u91cd\u8bd5\u6b21\u6570\n        function updateRetry(value) {\n            addLogEntry(`\u91cd\u8bd5\u6b21\u6570\u5df2\u66f4\u65b0\u4e3a: ${value}\u6b21`, 'info');\n        }\n        \n        \/\/ \u52a0\u8f7d\u7edf\u8ba1\u4fe1\u606f\n        function loadStats() {\n            fetch('baksend.php?action=stats')\n                .then(response => response.json())\n                .then(data => {\n                    const statsHtml = `\n                        <div class=\"stat-card\">\n                            <h3>\ud83d\udcca \u603b\u6587\u4ef6\u6570<\/h3>\n                            <div class=\"number\">${data.total_files}<\/div>\n                        <\/div>\n                        <div class=\"stat-card\">\n                            <h3>\u2705 \u5df2\u5907\u4efd<\/h3>\n                            <div class=\"number\">${data.backed_up}<\/div>\n                        <\/div>\n                        <div class=\"stat-card\">\n                            <h3>\u23f3 \u5f85\u5907\u4efd<\/h3>\n                            <div class=\"number\">${data.pending}<\/div>\n                        <\/div>\n                        <div class=\"stat-card\">\n                            <h3>\u274c \u5931\u8d25\u6570<\/h3>\n                            <div class=\"number\">${data.errors}<\/div>\n                        <\/div>\n                        <div class=\"stat-card\">\n                            <h3>\ud83d\udeab \u5df2\u6392\u9664<\/h3>\n                            <div class=\"number\">${data.excluded_count}<\/div>\n                        <\/div>\n                    `;\n                    document.getElementById('stats').innerHTML = statsHtml;\n                    \n                    \/\/ \u52a0\u8f7d\u6392\u9664\u89c4\u5219\n                    loadExcludeRules(data);\n                });\n        }\n        \n        \/\/ \u52a0\u8f7d\u6392\u9664\u89c4\u5219\n        function loadExcludeRules(data) {\n            fetch('baksend.php?action=exclude_rules')\n                .then(response => response.json())\n                .then(rules => {\n                    \/\/ ... \u539f\u6709\u4ee3\u7801 ...\n                });\n        }\n        \n        \/\/ \u6dfb\u52a0\u65e5\u5fd7\u6761\u76ee\n        function addLogEntry(message, type = 'info') {\n            const timestamp = new Date().toLocaleTimeString();\n            const entry = {\n                time: timestamp,\n                message: message,\n                type: type\n            };\n            \n            logEntries.unshift(entry);\n            \n            if (logEntries.length > 50) {\n                logEntries = logEntries.slice(0, 50);\n            }\n            \n            updateLogDisplay();\n        }\n        \n        \/\/ \u66f4\u65b0\u65e5\u5fd7\u663e\u793a\n        function updateLogDisplay() {\n            const logContainer = document.getElementById('log');\n            let logHtml = '';\n            \n            logEntries.forEach(entry => {\n                logHtml += `\n                    <div class=\"log-entry ${entry.type}\">\n                        <strong>[${entry.time}]<\/strong> ${entry.message}\n                    <\/div>\n                `;\n            });\n            \n            logContainer.innerHTML = logHtml;\n        }\n        \n        \/\/ \u5f00\u59cb\u5907\u4efd\n        function startBackup() {\n            if (isBackupRunning) return;\n            \n            isBackupRunning = true;\n            document.getElementById('startBtn').style.display = 'none';\n            document.getElementById('stopBtn').style.display = 'inline-block';\n            document.getElementById('spinner').style.display = 'block';\n            \n            addLogEntry('\u5f00\u59cb\u5907\u4efd\u8fdb\u7a0b...', 'info');\n            addLogEntry(`\u5f53\u524dAPI\u65b9\u6cd5: ${currentApiMethod}`, 'info');\n            \n            \/\/ \u6267\u884c\u5907\u4efd\n            performBackup();\n        }\n        \n        \/\/ \u6267\u884c\u5907\u4efd\n        function performBackup() {\n            if (!isBackupRunning) return;\n            \n            fetch('baksend.php?action=backup')\n                .then(response => response.json())\n                .then(data => {\n                    if (data.completed) {\n                        \/\/ \u5907\u4efd\u5b8c\u6210\n                        backupCompleted(data);\n                        return;\n                    }\n                    \n                    \/\/ \u66f4\u65b0\u8fdb\u5ea6\n                    updateProgress(data);\n                    \n                    \/\/ \u663e\u793a\u5f53\u524d\u6587\u4ef6\u4fe1\u606f\n                    updateCurrentFile(data.current_file, data.api_method);\n                    \n                    \/\/ \u6dfb\u52a0\u65e5\u5fd7\n                    if (data.result.success) {\n                        addLogEntry(`\u2705 ${data.result.file} - ${data.result.message} (${data.result.size})`, 'success');\n                    } else {\n                        addLogEntry(`\u274c ${data.result.file} - ${data.result.message}`, 'error');\n                    }\n                    \n                    \/\/ \u5982\u679c\u542f\u7528\u4e86\u81ea\u52a8\u5907\u4efd\uff0c\u7ee7\u7eed\u4e0b\u4e00\u4e2a\u6587\u4ef6\n                    if (autoBackupEnabled) {\n                        setTimeout(performBackup, document.getElementById('interval').value * 1000);\n                    }\n                })\n                .catch(error => {\n                    addLogEntry(`\u8bf7\u6c42\u9519\u8bef: ${error.message}`, 'error');\n                    if (autoBackupEnabled) {\n                        setTimeout(performBackup, 5000);\n                    }\n                });\n        }\n        \n        \/\/ \u66f4\u65b0\u8fdb\u5ea6\n        function updateProgress(data) {\n            const progress = data.progress;\n            const progressBar = document.getElementById('progressBar');\n            const progressText = document.getElementById('progressText');\n            const progressInfo = document.getElementById('progressInfo');\n            \n            progressBar.style.width = progress.percent + '%';\n            progressText.textContent = progress.percent + '%';\n            \n            const stats = data.stats;\n            progressInfo.innerHTML = `\n                \u8fdb\u5ea6: ${progress.current}\/${progress.total} \u6587\u4ef6 | \n                \u6210\u529f: ${stats.success} | \n                \u5931\u8d25: ${stats.failed} |\n                \u65b9\u6cd5: ${data.api_method || 'auto'} |\n                \u8017\u65f6: ${Math.round((Date.now()\/1000 - stats.start_time))}\u79d2\n            `;\n        }\n        \n        \/\/ \u66f4\u65b0\u5f53\u524d\u6587\u4ef6\u4fe1\u606f\n        function updateCurrentFile(file, apiMethod) {\n            if (!file) return;\n            \n            const fileSize = formatBytes(file.size);\n            const fileInfo = document.getElementById('currentFile');\n            \n            fileInfo.innerHTML = `\n                <h3>\ud83d\udcc4 \u5f53\u524d\u5907\u4efd\u6587\u4ef6<\/h3>\n                <p><strong>\u6587\u4ef6\u8def\u5f84:<\/strong> ${file.path}<\/p>\n                <p><strong>\u6587\u4ef6\u5927\u5c0f:<\/strong> ${fileSize}<\/p>\n                <p><strong>\u4fee\u6539\u65f6\u95f4:<\/strong> ${new Date(file.mtime * 1000).toLocaleString()}<\/p>\n                <p><strong>MD5:<\/strong> ${file.md5.substring(0, 16)}...<\/p>\n                <p><strong>API\u65b9\u6cd5:<\/strong> ${apiMethod}<\/p>\n            `;\n        }\n        \n        \/\/ \u5907\u4efd\u5b8c\u6210\n        function backupCompleted(data) {\n            isBackupRunning = false;\n            document.getElementById('startBtn').style.display = 'inline-block';\n            document.getElementById('stopBtn').style.display = 'none';\n            document.getElementById('spinner').style.display = 'none';\n            \n            addLogEntry(`\ud83c\udf89 \u5907\u4efd\u5b8c\u6210\uff01\u603b\u8ba1: ${data.stats.success} \u6210\u529f, ${data.stats.failed} \u5931\u8d25`, 'success');\n            \n            \/\/ \u66f4\u65b0\u7edf\u8ba1\u4fe1\u606f\n            loadStats();\n            \n            \/\/ \u663e\u793a\u5b8c\u6210\u4fe1\u606f\n            document.getElementById('currentFile').innerHTML = `\n                <h3>\u2705 \u5907\u4efd\u5b8c\u6210<\/h3>\n                <p><strong>\u603b\u6587\u4ef6\u6570:<\/strong> ${data.stats.total}<\/p>\n                <p><strong>\u6210\u529f:<\/strong> ${data.stats.success}<\/p>\n                <p><strong>\u5931\u8d25:<\/strong> ${data.stats.failed}<\/p>\n                <p><strong>API\u65b9\u6cd5:<\/strong> ${data.api_method}<\/p>\n                <p><strong>\u5f00\u59cb\u65f6\u95f4:<\/strong> ${new Date(data.stats.start_time * 1000).toLocaleString()}<\/p>\n                <p><strong>\u5b8c\u6210\u65f6\u95f4:<\/strong> ${new Date().toLocaleString()}<\/p>\n            `;\n            \n            \/\/ \u91cd\u7f6e\u8fdb\u5ea6\u6761\n            document.getElementById('progressBar').style.width = '100%';\n            document.getElementById('progressText').textContent = '100%';\n        }\n        \n        \/\/ \u505c\u6b62\u5907\u4efd\n        function stopBackup() {\n            isBackupRunning = false;\n            document.getElementById('startBtn').style.display = 'inline-block';\n            document.getElementById('stopBtn').style.display = 'none';\n            document.getElementById('spinner').style.display = 'none';\n            \n            addLogEntry('\u5907\u4efd\u5df2\u505c\u6b62', 'info');\n        }\n        \n        \/\/ \u91cd\u7f6e\u5907\u4efd\n        function resetBackup() {\n            if (isBackupRunning) {\n                if (!confirm('\u5907\u4efd\u6b63\u5728\u8fdb\u884c\u4e2d\uff0c\u786e\u5b9a\u8981\u91cd\u7f6e\u5417\uff1f')) {\n                    return;\n                }\n                stopBackup();\n            }\n            \n            fetch('baksend.php?action=reset')\n                .then(() => {\n                    location.reload();\n                });\n        }\n        \n        \/\/ \u5207\u6362\u81ea\u52a8\u5907\u4efd\n        function toggleAutoBackup() {\n            autoBackupEnabled = document.getElementById('autoBackup').checked;\n            const intervalInput = document.getElementById('interval');\n            const intervalText = document.getElementById('intervalText');\n            \n            if (autoBackupEnabled) {\n                intervalInput.style.display = 'inline-block';\n                intervalText.style.display = 'inline-block';\n                \n                \/\/ \u5982\u679c\u5907\u4efd\u6ca1\u6709\u8fd0\u884c\uff0c\u81ea\u52a8\u5f00\u59cb\n                if (!isBackupRunning) {\n                    startBackup();\n                }\n            } else {\n                intervalInput.style.display = 'none';\n                intervalText.style.display = 'none';\n            }\n        }\n        \n        \/\/ \u683c\u5f0f\u5316\u5b57\u8282\u5927\u5c0f\n        function formatBytes(bytes, decimals = 2) {\n            if (bytes === 0) return '0 Bytes';\n            const k = 1024;\n            const dm = decimals < 0 ? 0 : decimals;\n            const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n            const i = Math.floor(Math.log(bytes) \/ Math.log(k));\n            return parseFloat((bytes \/ Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];\n        }\n        \n        \/\/ \u9875\u9762\u52a0\u8f7d\u65f6\u521d\u59cb\u5316\n        window.onload = function() {\n            loadApiInfo();\n            loadStats();\n            addLogEntry('\u7cfb\u7edf\u5c31\u7eea\uff0c\u53ef\u4ee5\u5f00\u59cb\u5907\u4efd', 'info');\n            \n            \/\/ \u68c0\u67e5\u662f\u5426\u6709\u5f85\u5907\u4efd\u6587\u4ef6\n            fetch('baksend.php?action=stats')\n                .then(response => response.json())\n                .then(data => {\n                    if (data.pending > 0) {\n                        addLogEntry(`\u68c0\u6d4b\u5230 ${data.pending} \u4e2a\u5f85\u5907\u4efd\u6587\u4ef6`, 'info');\n                    }\n                });\n        };\n    <\/script>\n<\/body>\n<\/html>"}