{"id":314,"url":"https:\/\/web.daaee.cn\/.\/2026\/backup.php","title":"\u6587\u4ef6\u5907\u4efd\u7cfb\u7edf","content":"<!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<\/title>\n    <style>\n        \/* \u4fdd\u7559\u539f\u6709\u6837\u5f0f\uff0c\u65b0\u589e\u6837\u5f0f\u5728\u4e0b\u9762 *\/\n        \n        .exclude-panel {\n            background: #f8f9fa;\n            padding: 20px;\n            border-radius: 8px;\n            margin-bottom: 20px;\n            border-left: 4px solid #ff9800;\n        }\n        \n        .exclude-panel h3 {\n            color: #ff9800;\n            margin-bottom: 15px;\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n        }\n        \n        .exclude-rules {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n            gap: 15px;\n            margin-bottom: 15px;\n        }\n        \n        .rule-category {\n            background: white;\n            padding: 15px;\n            border-radius: 6px;\n            border: 1px solid #ddd;\n        }\n        \n        .rule-category h4 {\n            margin-bottom: 10px;\n            color: #333;\n            font-size: 14px;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n        }\n        \n        .rule-items {\n            font-size: 13px;\n            line-height: 1.4;\n            color: #666;\n        }\n        \n        .rule-item {\n            display: inline-block;\n            background: #e3f2fd;\n            padding: 3px 8px;\n            margin: 2px;\n            border-radius: 3px;\n            font-family: monospace;\n        }\n        \n        .excluded-files {\n            max-height: 200px;\n            overflow-y: auto;\n            background: white;\n            padding: 10px;\n            border-radius: 6px;\n            border: 1px solid #ddd;\n            font-size: 12px;\n        }\n        \n        .excluded-file {\n            padding: 3px 5px;\n            border-bottom: 1px solid #eee;\n            font-family: monospace;\n        }\n        \n        .excluded-file:last-child {\n            border-bottom: none;\n        }\n        \n        .toggle-btn {\n            background: #ff9800;\n            color: white;\n            border: none;\n            padding: 5px 10px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 12px;\n        }\n        \n        .toggle-btn:hover {\n            background: #f57c00;\n        }\n        \n        .config-form {\n            background: white;\n            padding: 20px;\n            border-radius: 8px;\n            margin-bottom: 20px;\n            border: 1px solid #ddd;\n        }\n        \n        .form-group {\n            margin-bottom: 15px;\n        }\n        \n        .form-group label {\n            display: block;\n            margin-bottom: 5px;\n            font-weight: bold;\n            color: #333;\n        }\n        \n        .form-control {\n            width: 100%;\n            padding: 8px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            font-size: 14px;\n        }\n        \n        .form-control:focus {\n            outline: none;\n            border-color: #667eea;\n            box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);\n        }\n        \n        .form-text {\n            font-size: 12px;\n            color: #666;\n            margin-top: 5px;\n        }\n        \n        .modal {\n            display: none;\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            background: rgba(0, 0, 0, 0.5);\n            z-index: 1000;\n            justify-content: center;\n            align-items: center;\n        }\n        \n        .modal-content {\n            background: white;\n            padding: 30px;\n            border-radius: 10px;\n            max-width: 500px;\n            width: 90%;\n            max-height: 80vh;\n            overflow-y: auto;\n        }\n        \n        .modal-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 20px;\n        }\n        \n        .modal-close {\n            background: none;\n            border: none;\n            font-size: 24px;\n            cursor: pointer;\n            color: #666;\n        }\n        \n        .modal-close:hover {\n            color: #333;\n        }\n        \n        .modal-buttons {\n            display: flex;\n            justify-content: flex-end;\n            gap: 10px;\n            margin-top: 20px;\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n        <header>\n            <h1>\ud83d\udcc1 \u6587\u4ef6\u5907\u4efd\u7cfb\u7edf<\/h1>\n            <p>\u5b89\u5168\u3001\u53ef\u9760\u7684\u81ea\u52a8\u5316\u6587\u4ef6\u5907\u4efd\u89e3\u51b3\u65b9\u6848<\/p>\n        <\/header>\n        \n        <div class=\"content\">\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=\"showConfig()\" id=\"configBtn\">\u914d\u7f6e<\/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=\"spinner\" id=\"spinner\"><\/div>\n        <\/div>\n        \n        <footer>\n            <p>\u00a9 2023 \u6587\u4ef6\u5907\u4efd\u7cfb\u7edf | \u517c\u5bb9 PHP 5.3 - PHP 8.x<\/p>\n            <p>\u5f53\u524d\u5907\u4efd\u76ee\u5f55: \/mnt\/sda1\/www\/2026<\/p>\n            <p>API\u5730\u5740: https:\/\/zgyzty.com\/assets\/sapi.php<\/p>\n            <p>\u9ed8\u8ba4\u6392\u9664: config.php, backup.php, api.php \u7b49\u7cfb\u7edf\u6587\u4ef6<\/p>\n        <\/footer>\n    <\/div>\n    \n    <!-- \u914d\u7f6e\u6a21\u6001\u6846 -->\n    <div class=\"modal\" id=\"configModal\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">\n                <h2>\u5907\u4efd\u914d\u7f6e<\/h2>\n                <button class=\"modal-close\" onclick=\"hideConfig()\">&times;<\/button>\n            <\/div>\n            \n            <div class=\"config-form\">\n                <div class=\"form-group\">\n                    <label>\u626b\u63cf\u76ee\u5f55:<\/label>\n                    <input type=\"text\" class=\"form-control\" id=\"configScanDir\" value=\".\">\n                    <div class=\"form-text\">\u8981\u5907\u4efd\u7684\u76ee\u5f55\u8def\u5f84<\/div>\n                <\/div>\n                \n                <div class=\"form-group\">\n                    <label>\u6392\u9664\u76ee\u5f55 (\u7528\u9017\u53f7\u5206\u9694):<\/label>\n                    <textarea class=\"form-control\" id=\"configExcludeDirs\" rows=\"3\">.git, vendor, node_modules, backups<\/textarea>\n                    <div class=\"form-text\">\u6392\u9664\u7684\u76ee\u5f55\u540d\uff0c\u5982 .git, vendor \u7b49<\/div>\n                <\/div>\n                \n                <div class=\"form-group\">\n                    <label>\u6392\u9664\u6587\u4ef6 (\u7528\u9017\u53f7\u5206\u9694):<\/label>\n                    <textarea class=\"form-control\" id=\"configExcludeFiles\" rows=\"3\">config.php, backup.php, api.php, backup_status.json, backup_errors.json, curlog.txt<\/textarea>\n                    <div class=\"form-text\">\u6392\u9664\u7684\u6587\u4ef6\u540d\uff0c\u652f\u6301\u901a\u914d\u7b26\u5982 *.php<\/div>\n                <\/div>\n                \n                <div class=\"form-group\">\n                    <label>\u6392\u9664\u6269\u5c55\u540d (\u7528\u9017\u53f7\u5206\u9694):<\/label>\n                    <textarea class=\"form-control\" id=\"configExcludeExtensions\" rows=\"3\">tmp, log, cache<\/textarea>\n                    <div class=\"form-text\">\u6392\u9664\u7684\u6587\u4ef6\u6269\u5c55\u540d\uff0c\u5982 tmp, log \u7b49<\/div>\n                <\/div>\n                \n                <div class=\"modal-buttons\">\n                    <button class=\"btn\" onclick=\"saveConfig()\">\u4fdd\u5b58\u914d\u7f6e<\/button>\n                    <button class=\"btn btn-stop\" onclick=\"hideConfig()\">\u53d6\u6d88<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n    \n    <script>\n        let isBackupRunning = false;\n        let autoBackupEnabled = false;\n        let backupInterval;\n        let logEntries = [];\n        \n        \/\/ \u52a0\u8f7d\u7edf\u8ba1\u4fe1\u606f\n        function loadStats() {\n            fetch('backup.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('backup.php?action=exclude_rules')\n                .then(response => response.json())\n                .then(rules => {\n                    let excludedFilesHtml = '';\n                    if (data.excluded_files && data.excluded_files.length > 0) {\n                        data.excluded_files.slice(0, 20).forEach(file => {\n                            excludedFilesHtml += `<div class=\"excluded-file\">${file}<\/div>`;\n                        });\n                        if (data.excluded_files.length > 20) {\n                            excludedFilesHtml += `<div class=\"excluded-file\">... \u8fd8\u6709 ${data.excluded_files.length - 20} \u4e2a\u6587\u4ef6<\/div>`;\n                        }\n                    } else {\n                        excludedFilesHtml = '<div class=\"excluded-file\">\u65e0\u88ab\u6392\u9664\u6587\u4ef6<\/div>';\n                    }\n                    \n                    const excludeHtml = `\n                        <h3>\n                            \ud83d\udee1\ufe0f \u6392\u9664\u89c4\u5219\n                            <button class=\"toggle-btn\" onclick=\"toggleExcludeDetails()\">\u67e5\u770b\u8be6\u60c5<\/button>\n                        <\/h3>\n                        <div class=\"exclude-rules\">\n                            <div class=\"rule-category\">\n                                <h4>\u6392\u9664\u76ee\u5f55<\/h4>\n                                <div class=\"rule-items\">\n                                    ${rules['\u6392\u9664\u76ee\u5f55'].map(dir => `<span class=\"rule-item\">${dir}<\/span>`).join('')}\n                                <\/div>\n                            <\/div>\n                            <div class=\"rule-category\">\n                                <h4>\u6392\u9664\u6587\u4ef6<\/h4>\n                                <div class=\"rule-items\">\n                                    ${rules['\u6392\u9664\u6587\u4ef6'].map(file => `<span class=\"rule-item\">${file}<\/span>`).join('')}\n                                <\/div>\n                            <\/div>\n                            <div class=\"rule-category\">\n                                <h4>\u6392\u9664\u6269\u5c55\u540d<\/h4>\n                                <div class=\"rule-items\">\n                                    ${rules['\u6392\u9664\u6269\u5c55\u540d'].map(ext => `<span class=\"rule-item\">.${ext}<\/span>`).join('')}\n                                <\/div>\n                            <\/div>\n                        <\/div>\n                        <div id=\"excludeDetails\" style=\"display:none\">\n                            <h4>\u88ab\u6392\u9664\u7684\u6587\u4ef6 (${data.excluded_count}\u4e2a):<\/h4>\n                            <div class=\"excluded-files\">\n                                ${excludedFilesHtml}\n                            <\/div>\n                        <\/div>\n                    `;\n                    document.getElementById('excludePanel').innerHTML = excludeHtml;\n                });\n        }\n        \n        \/\/ \u5207\u6362\u6392\u9664\u8be6\u60c5\u663e\u793a\n        function toggleExcludeDetails() {\n            const details = document.getElementById('excludeDetails');\n            const button = document.querySelector('.toggle-btn');\n            if (details.style.display === 'none') {\n                details.style.display = 'block';\n                button.textContent = '\u9690\u85cf\u8be6\u60c5';\n            } else {\n                details.style.display = 'none';\n                button.textContent = '\u67e5\u770b\u8be6\u60c5';\n            }\n        }\n        \n        \/\/ \u663e\u793a\u914d\u7f6e\u6a21\u6001\u6846\n        function showConfig() {\n            document.getElementById('configModal').style.display = 'flex';\n        }\n        \n        \/\/ \u9690\u85cf\u914d\u7f6e\u6a21\u6001\u6846\n        function hideConfig() {\n            document.getElementById('configModal').style.display = 'none';\n        }\n        \n        \/\/ \u4fdd\u5b58\u914d\u7f6e\n        function saveConfig() {\n            const config = {\n                scan_dir: document.getElementById('configScanDir').value,\n                exclude_dirs: document.getElementById('configExcludeDirs').value.split(',').map(s => s.trim()).filter(s => s),\n                exclude_files: document.getElementById('configExcludeFiles').value.split(',').map(s => s.trim()).filter(s => s),\n                exclude_extensions: document.getElementById('configExcludeExtensions').value.split(',').map(s => s.trim()).filter(s => s)\n            };\n            \n            \/\/ \u8fd9\u91cc\u5e94\u8be5\u5c06\u914d\u7f6e\u4fdd\u5b58\u5230\u670d\u52a1\u5668\n            \/\/ \u7531\u4e8e\u662f\u5355\u6587\u4ef6\u7cfb\u7edf\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7URL\u53c2\u6570\u4f20\u9012\n            alert('\u914d\u7f6e\u5df2\u66f4\u65b0\uff0c\u8bf7\u5237\u65b0\u9875\u9762\u5e94\u7528\u65b0\u914d\u7f6e\u3002\\n\u6ce8\u610f\uff1a\u9700\u8981\u91cd\u65b0\u626b\u63cf\u6587\u4ef6\u5217\u8868\u3002');\n            hideConfig();\n            \n            \/\/ \u91cd\u65b0\u52a0\u8f7d\u9875\u9762\u5e76\u91cd\u7f6e\u626b\u63cf\n            setTimeout(() => {\n                window.location.href = 'backup.php?reset=1';\n            }, 1000);\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); \/\/ \u6dfb\u52a0\u5230\u5f00\u5934\n            \n            \/\/ \u9650\u5236\u65e5\u5fd7\u6570\u91cf\n            if (logEntries.length > 50) {\n                logEntries = logEntries.slice(0, 50);\n            }\n            \n            \/\/ \u66f4\u65b0\u65e5\u5fd7\u663e\u793a\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('\u6ce8\u610f\uff1aconfig.php, backup.php, api.php \u7b49\u7cfb\u7edf\u6587\u4ef6\u5df2\u88ab\u6392\u9664', '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('backup.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);\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); \/\/ 5\u79d2\u540e\u91cd\u8bd5\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                \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) {\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            `;\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            addLogEntry(`\ud83d\udeab \u7cfb\u7edf\u6587\u4ef6 (config.php, backup.php, api.php) \u5df2\u88ab\u6392\u9664\uff0c\u4e0d\u4f1a\u5907\u4efd`, 'info');\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>\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                <p><strong>\u5907\u6ce8:<\/strong> \u7cfb\u7edf\u6587\u4ef6\u5df2\u88ab\u6392\u9664\uff0c\u4e0d\u4f1a\u5907\u4efd<\/p>\n            `;\n            \n            \/\/ \u91cd\u7f6e\u8fdb\u5ea6\u6761\n            document.getElementById('progressBar').style.width = '100%';\n            document.getElementById('progressText').textContent = '100%';\n            \n            \/\/ \u5982\u679c\u542f\u7528\u4e86\u81ea\u52a8\u5907\u4efd\uff0c\u63d0\u793a\u7528\u6237\n            if (autoBackupEnabled) {\n                addLogEntry('\u81ea\u52a8\u5907\u4efd\u5df2\u5b8c\u6210\u4e00\u8f6e\uff0c\u7b49\u5f85\u4e0b\u6b21\u8ba1\u5212\u6267\u884c', 'info');\n            }\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('backup.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            loadStats();\n            addLogEntry('\u7cfb\u7edf\u5c31\u7eea\uff0c\u53ef\u4ee5\u5f00\u59cb\u5907\u4efd', 'info');\n            addLogEntry('\u6ce8\u610f\uff1aconfig.php, backup.php, api.php \u7b49\u7cfb\u7edf\u6587\u4ef6\u9ed8\u8ba4\u88ab\u6392\u9664', 'info');\n            \n            \/\/ \u68c0\u67e5\u662f\u5426\u6709\u5f85\u5907\u4efd\u6587\u4ef6\n            fetch('backup.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                        addLogEntry(`\u68c0\u6d4b\u5230 ${data.excluded_count} \u4e2a\u88ab\u6392\u9664\u6587\u4ef6`, 'info');\n                    }\n                });\n        };\n    <\/script>\n<\/body>\n<\/html>"}