<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>软件更新管理系统</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
            overflow: hidden;
        }
        
        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }
        
        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
        }
        
        .content {
            padding: 30px;
        }
        
        .upload-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 25px;
            margin-bottom: 20px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.05);
            border-left: 5px solid;
        }
        
        .network-section {
            border-left-color: #667eea;
        }
        
        .compute-section {
            border-left-color: #00b09b;
        }
        
        .monitor-section {
            border-left-color: #ff416c;
        }
        
        .upload-section h2 {
            color: #333;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid;
        }
        
        .network-section h2 {
            border-bottom-color: #667eea;
        }
        
        .compute-section h2 {
            border-bottom-color: #00b09b;
        }
        
        .monitor-section h2 {
            border-bottom-color: #ff416c;
        }
        
        .section-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }
        
        .section-tag {
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 0.8em;
            font-weight: 600;
            color: white;
        }
        
        .network-tag {
            background: #667eea;
        }
        
        .compute-tag {
            background: #00b09b;
        }
        
        .monitor-tag {
            background: #ff416c;
        }
        
        .file-input-container {
            margin-bottom: 20px;
        }
        
        .file-input-label {
            display: inline-block;
            padding: 12px 24px;
            color: white;
            border-radius: 6px;
            cursor: pointer;
            font-weight: 600;
            transition: all 0.3s ease;
        }
        
        .network-upload-btn {
            background: #667eea;
        }
        
        .compute-upload-btn {
            background: #00b09b;
        }
        
        .monitor-upload-btn {
            background: #ff416c;
        }
        
        .file-input-label:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        
        .network-upload-btn:hover {
            background: #5a6fd8;
        }
        
        .compute-upload-btn:hover {
            background: #009688;
        }
        
        .monitor-upload-btn:hover {
            background: #ff2b55;
        }
        
        .file-input {
            display: none;
        }
        
        .file-name {
            margin-left: 15px;
            color: #666;
            font-style: italic;
        }
        
        .selected-file {
            margin-top: 15px;
            padding: 15px;
            background: #e9ecef;
            border-radius: 8px;
            border-left: 4px solid;
        }
        
        .network-file {
            border-left-color: #667eea;
        }
        
        .compute-file {
            border-left-color: #00b09b;
        }
        
        .monitor-file {
            border-left-color: #ff416c;
        }
        
        .selected-file h4 {
            margin-bottom: 5px;
            color: #333;
        }
        
        .selected-file p {
            color: #666;
            font-size: 0.9em;
        }
        
        .output-container {
            height: 400px;
            overflow-y: auto;
            background: #1e1e1e;
            border-radius: 8px;
            padding: 20px;
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 14px;
            color: #d4d4d4;
            line-height: 1.5;
        }
        
        .output-container::-webkit-scrollbar {
            width: 8px;
        }
        
        .output-container::-webkit-scrollbar-track {
            background: #2d2d2d;
        }
        
        .output-container::-webkit-scrollbar-thumb {
            background: #555;
            border-radius: 4px;
        }
        
        .button-group {
            display: flex;
            gap: 10px;
            margin-top: 20px;
            flex-wrap: wrap;
        }
        
        button {
            padding: 12px 24px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-weight: 600;
            transition: all 0.3s ease;
            font-size: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
        }
        
        .update-btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }
        
        .compute-update-btn {
            background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%);
            color: white;
        }
        
        .monitor-update-btn {
            background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
            color: white;
        }
        
        .stop-btn {
            background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
            color: white;
        }
        
        .clear-btn {
            background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
            color: white;
        }
        
        .log-btn {
            background: linear-gradient(135deg, #ff9800 0%, #ff5722 100%);
            color: white;
        }
        
        .compute-log-btn {
            background: linear-gradient(135deg, #4caf50 0%, #2e7d32 100%);
            color: white;
        }
        
        .monitor-log-btn {
            background: linear-gradient(135deg, #9c27b0 0%, #6a1b9a 100%);
            color: white;
        }
        
        button:hover:not(:disabled) {
            transform: translateY(-2px);
            box-shadow: 0 7px 14px rgba(0,0,0,0.1);
        }
        
        button:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }
        
        .status-indicator {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 10px 20px;
            border-radius: 20px;
            font-weight: 600;
            margin-bottom: 20px;
            background: #f8f9fa;
            border: 1px solid #dee2e6;
        }
        
        .status-running {
            background: #d4edda;
            border-color: #c3e6cb;
            color: #155724;
        }
        
        .status-stopped {
            background: #f8d7da;
            border-color: #f5c6cb;
            color: #721c24;
        }
        
        .status-idle {
            background: #fff3cd;
            border-color: #ffeeba;
            color: #856404;
        }
        
        .status-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            animation: pulse 2s infinite;
        }
        
        .running-dot {
            background: #28a745;
        }
        
        .stopped-dot {
            background: #dc3545;
        }
        
        .idle-dot {
            background: #ffc107;
        }
        
        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }
        
        .loading {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        .network-loading {
            border-top-color: #667eea;
        }
        
        .compute-loading {
            border-top-color: #00b09b;
        }
        
        .monitor-loading {
            border-top-color: #ff416c;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .info-box {
            background: #e7f3ff;
            border-radius: 8px;
            padding: 15px;
            margin-bottom: 20px;
            border-left: 4px solid #2196F3;
        }
        
        .info-box h3 {
            color: #1976D2;
            margin-bottom: 10px;
        }
        
        .info-box ul {
            padding-left: 20px;
            color: #555;
        }
        
        .info-box li {
            margin-bottom: 5px;
        }
        
        .upload-icon {
            font-size: 1.2em;
        }
        
        .software-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .software-card {
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.05);
            border: 1px solid #dee2e6;
        }
        
        .software-card h3 {
            color: #333;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid;
        }
        
        .network-card h3 {
            border-bottom-color: #667eea;
        }
        
        .compute-card h3 {
            border-bottom-color: #00b09b;
        }
        
        .monitor-card h3 {
            border-bottom-color: #ff416c;
        }
        
        .software-info {
            margin-bottom: 15px;
            color: #666;
            font-size: 0.9em;
        }
        
        .current-version {
            background: #e9ecef;
            padding: 8px 12px;
            border-radius: 4px;
            font-family: monospace;
            margin-top: 10px;
        }
        
        .tabs {
            display: flex;
            border-bottom: 1px solid #dee2e6;
            margin-bottom: 20px;
        }
        
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            border-bottom: 3px solid transparent;
            transition: all 0.3s ease;
        }
        
        .tab:hover {
            background: #f8f9fa;
        }
        
        .tab.active {
            border-bottom-color: #667eea;
            color: #667eea;
            font-weight: 600;
        }
        
        .tab-content {
            display: none;
        }
        
        .tab-content.active {
            display: block;
        }
        
        .log-info {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 12px 15px;
            margin-top: 15px;
            border-radius: 6px;
            font-size: 0.9em;
        }
        
        .log-info h4 {
            color: #856404;
            margin-bottom: 5px;
        }
        
        .log-info ul {
            padding-left: 20px;
            color: #856404;
        }
        
        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 15px 20px;
            background: white;
            border-radius: 8px;
            box-shadow: 0 5px 20px rgba(0,0,0,0.2);
            display: flex;
            align-items: center;
            gap: 10px;
            z-index: 1000;
            animation: slideIn 0.3s ease;
            border-left: 4px solid;
        }
        
        .notification-success {
            border-left-color: #28a745;
        }
        
        .notification-error {
            border-left-color: #dc3545;
        }
        
        .notification-info {
            border-left-color: #17a2b8;
        }
        
        @keyframes slideIn {
            from {
                transform: translateX(100%);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }
        
        .close-notification {
            background: none;
            border: none;
            font-size: 1.2em;
            cursor: pointer;
            color: #666;
            padding: 0;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .close-notification:hover {
            color: #333;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>软件更新管理系统</h1>
            <p>统一管理网络解析、计算、画面监控软件的更新和日志</p>
        </div>
        
        <div class="content">
            <div id="statusIndicator" class="status-indicator status-idle">
                <span class="status-dot idle-dot"></span>
                <span id="statusText">就绪 - 等待操作</span>
                <span id="currentFile" style="margin-left: auto; font-weight: normal; color: #666;"></span>
            </div>
            
            <div class="info-box">
                <h3>使用说明</h3>
                <ul>
                    <li>选择对应软件类型的更新文件，点击更新按钮</li>
                    <li>支持的文件类型: .tar.gz, .tgz</li>
                    <li>处理过程实时显示在下方输出区域</li>
                    <li>不同软件使用不同的颜色标识，便于区分</li>
                    <li>点击"下载日志"按钮可以下载软件的所有日志文件</li>
                </ul>
            </div>
            
            <div class="tabs">
                <div class="tab active" data-tab="network">网络解析软件</div>
                <div class="tab" data-tab="compute">计算软件</div>
                <div class="tab" data-tab="monitor">画面监控软件</div>
            </div>
            
            <!-- 网络解析软件更新 -->
            <div id="network-tab" class="tab-content active">
                <div class="upload-section network-section">
                    <h2>网络解析软件更新</h2>
                    <div class="file-input-container">
                        <label for="networkFileInput" class="file-input-label network-upload-btn">
                            <span class="upload-icon">📁</span> 选择网络软件更新文件
                        </label>
                        <input type="file" id="networkFileInput" class="file-input" accept=".tar.gz,.tgz">
                        <span id="networkFileName" class="file-name">未选择文件</span>
                    </div>
                    
                    <div id="networkFileInfo" class="selected-file network-file" style="display: none;">
                        <h4>已选择网络软件文件:</h4>
                        <p id="networkFileInfoText"></p>
                    </div>
                    
                    <div class="log-info">
                        <h4>日志文件说明:</h4>
                        <ul>
                            <li>支持下载所有.log文件为ZIP包</li>
                        </ul>
                    </div>
                    
                    <div class="button-group">
                        <button id="networkUpdateBtn" class="update-btn" disabled>
                            <span>更新网络软件</span>
                        </button>
                        <button id="stopBtn" class="stop-btn" disabled>
                            <span>🛑</span> 停止处理
                        </button>
                        <button id="clearBtn" class="clear-btn">
                            <span>🗑️</span> 清空输出
                        </button>
                        <button id="networkLogBtn" class="log-btn">
                            <span>📋</span> 下载日志
                        </button>
                    </div>
                </div>
            </div>
            
            <!-- 计算软件更新 -->
            <div id="compute-tab" class="tab-content">
                <div class="upload-section compute-section">
                    <h2>计算软件更新</h2>
                    <div class="file-input-container">
                        <label for="computeFileInput" class="file-input-label compute-upload-btn">
                            <span class="upload-icon">📁</span> 选择计算软件更新文件
                        </label>
                        <input type="file" id="computeFileInput" class="file-input" accept=".tar.gz,.tgz">
                        <span id="computeFileName" class="file-name">未选择文件</span>
                    </div>
                    
                    <div id="computeFileInfo" class="selected-file compute-file" style="display: none;">
                        <h4>已选择计算软件文件:</h4>
                        <p id="computeFileInfoText"></p>
                    </div>
                    
                    <div class="log-info">
                        <h4>日志文件说明:</h4>
                        <ul>
                            <li>支持下载所有.log文件为ZIP包</li>
                        </ul>
                    </div>
                    
                    <div class="button-group">
                        <button id="computeUpdateBtn" class="compute-update-btn" disabled>
                            <span>更新计算软件</span>
                        </button>
                        <button id="stopBtnCompute" class="stop-btn" disabled>
                            <span>🛑</span> 停止处理
                        </button>
                        <button id="clearBtnCompute" class="clear-btn">
                            <span>🗑️</span> 清空输出
                        </button>
                        <button id="computeLogBtn" class="compute-log-btn">
                            <span>📋</span> 下载日志
                        </button>
                    </div>
                </div>
            </div>
            
            <!-- 画面监控软件更新 -->
            <div id="monitor-tab" class="tab-content">
                <div class="upload-section monitor-section">
                    <h2>画面监控软件更新</h2>
                    <div class="file-input-container">
                        <label for="monitorFileInput" class="file-input-label monitor-upload-btn">
                            <span class="upload-icon">📁</span> 选择监控软件更新文件
                        </label>
                        <input type="file" id="monitorFileInput" class="file-input" accept=".tar.gz,.tgz">
                        <span id="monitorFileName" class="file-name">未选择文件</span>
                    </div>
                    
                    <div id="monitorFileInfo" class="selected-file monitor-file" style="display: none;">
                        <h4>已选择监控软件文件:</h4>
                        <p id="monitorFileInfoText"></p>
                    </div>
                    
                    <div class="log-info">
                        <h4>日志文件说明:</h4>
                        <ul>
                            <li>支持下载所有.log文件为ZIP包</li>
                        </ul>
                    </div>
                    
                    <div class="button-group">
                        <button id="monitorUpdateBtn" class="monitor-update-btn" disabled>
                            <span>更新监控软件</span>
                        </button>
                        <button id="stopBtnMonitor" class="stop-btn" disabled>
                            <span>🛑</span> 停止处理
                        </button>
                        <button id="clearBtnMonitor" class="clear-btn">
                            <span>🗑️</span> 清空输出
                        </button>
                        <button id="monitorLogBtn" class="monitor-log-btn">
                            <span>📋</span> 下载日志
                        </button>
                    </div>
                </div>
            </div>
            
            <div class="upload-section">
                <h2>执行输出</h2>
                <div id="output" class="output-container">
                    选择软件更新文件并点击更新按钮开始处理...
                </div>
            </div>
        </div>
    </div>

    <div id="notificationContainer" style="display: none;"></div>

    <script>
        let selectedFiles = {
            network: null,
            compute: null,
            monitor: null
        };
        
        let isRunning = false;
        let eventSource = null;
        let uploadInProgress = false;
        let currentSoftware = 'network';

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 标签页切换
            document.querySelectorAll('.tab').forEach(tab => {
                tab.addEventListener('click', () => {
                    const tabId = tab.dataset.tab;
                    switchTab(tabId);
                });
            });

            // 网络软件事件监听
            document.getElementById('networkFileInput').addEventListener('change', (e) => handleFileSelect(e, 'network'));
            document.getElementById('networkUpdateBtn').addEventListener('click', () => uploadAndExecute('network'));
            document.getElementById('networkLogBtn').addEventListener('click', () => downloadLogs('network'));
            
            // 计算软件事件监听
            document.getElementById('computeFileInput').addEventListener('change', (e) => handleFileSelect(e, 'compute'));
            document.getElementById('computeUpdateBtn').addEventListener('click', () => uploadAndExecute('compute'));
            document.getElementById('computeLogBtn').addEventListener('click', () => downloadLogs('compute'));
            
            // 监控软件事件监听
            document.getElementById('monitorFileInput').addEventListener('change', (e) => handleFileSelect(e, 'monitor'));
            document.getElementById('monitorUpdateBtn').addEventListener('click', () => uploadAndExecute('monitor'));
            document.getElementById('monitorLogBtn').addEventListener('click', () => downloadLogs('monitor'));

            // 停止按钮事件监听（共用）
            document.getElementById('stopBtn').addEventListener('click', stopExecution);
            document.getElementById('stopBtnCompute').addEventListener('click', stopExecution);
            document.getElementById('stopBtnMonitor').addEventListener('click', stopExecution);
            
            // 清空按钮事件监听
            document.getElementById('clearBtn').addEventListener('click', clearOutput);
            document.getElementById('clearBtnCompute').addEventListener('click', clearOutput);
            document.getElementById('clearBtnMonitor').addEventListener('click', clearOutput);
            
            // 检查初始状态
            checkStatus();
        });

        // 切换标签页
        function switchTab(tabId) {
            // 更新标签页
            document.querySelectorAll('.tab').forEach(tab => {
                tab.classList.remove('active');
            });
            document.querySelector(`.tab[data-tab="${tabId}"]`).classList.add('active');
            
            // 更新内容
            document.querySelectorAll('.tab-content').forEach(content => {
                content.classList.remove('active');
            });
            document.getElementById(`${tabId}-tab`).classList.add('active');
            
            currentSoftware = tabId;
        }

        // 处理文件选择
        function handleFileSelect(event, softwareType) {
            const file = event.target.files[0];
            if (file) {
                selectedFiles[softwareType] = file;
                
                // 更新UI
                document.getElementById(`${softwareType}FileName`).textContent = file.name;
                document.getElementById(`${softwareType}FileInfoText`).textContent = 
                    `${file.name} (${formatFileSize(file.size)})`;
                document.getElementById(`${softwareType}FileInfo`).style.display = 'block';
                document.getElementById(`${softwareType}UpdateBtn`).disabled = false;
                
                updateStatus('idle', `已选择${getSoftwareName(softwareType)}文件: ${file.name}`);
            }
        }

        // 获取软件名称
        function getSoftwareName(softwareType) {
            const names = {
                network: '网络解析软件',
                compute: '计算软件',
                monitor: '画面监控软件'
            };
            return names[softwareType] || '软件';
        }

        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }

        // 下载日志文件
        // 下载日志文件
        async function downloadLogs(softwareType) {
            try {
                // 显示加载状态
                const logBtn = document.getElementById(`${softwareType}LogBtn`);
                const originalText = logBtn.innerHTML;
                logBtn.innerHTML = '<span class="loading"></span> 正在下载...';
                logBtn.disabled = true;
                
                // 发送下载请求
                const response = await fetch(`/download_logs?software=${softwareType}`, {
                    method: 'GET'
                });
                
                if (response.ok) {
                    // 检查响应类型
                    const contentType = response.headers.get('content-type');
                    
                    if (contentType && contentType.includes('application/zip')) {
                        // 获取文件名
                        const contentDisposition = response.headers.get('content-disposition');
                        let filename = `${softwareType}_logs.zip`;
                        
                        if (contentDisposition) {
                            const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/i.exec(contentDisposition);
                            if (matches && matches[1]) {
                                filename = matches[1].replace(/['"]/g, '');
                            }
                        }
                        
                        // 创建blob并下载
                        const blob = await response.blob();
                        
                        // 检查blob是否有效
                        if (blob.size === 0) {
                            throw new Error('下载的文件为空');
                        }
                        
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        a.download = filename;
                        document.body.appendChild(a);
                        a.click();
                        
                        // 清理
                        setTimeout(() => {
                            document.body.removeChild(a);
                            window.URL.revokeObjectURL(url);
                        }, 100);
                        
                        // 显示成功通知
                        showNotification(`${getSoftwareName(softwareType)}日志下载成功`, 'success');
                        updateStatus('idle', `${getSoftwareName(softwareType)}日志已下载`);
                        
                    } else {
                        // 尝试解析JSON错误响应
                        try {
                            const errorData = await response.json();
                            throw new Error(errorData.message || '下载失败：服务器返回错误');
                        } catch (jsonError) {
                            // 如果不是JSON，可能是HTML错误页面
                            const text = await response.text();
                            if (text.includes('<!doctype') || text.includes('<html')) {
                                throw new Error('服务器错误：返回了HTML页面而非文件');
                            } else {
                                throw new Error(`下载失败：${text.substring(0, 100)}`);
                            }
                        }
                    }
                } else {
                    // 处理HTTP错误
                    let errorMessage = `HTTP错误: ${response.status}`;
                    
                    try {
                        const errorData = await response.json();
                        errorMessage = errorData.message || errorMessage;
                    } catch (e) {
                        // 如果不是JSON，尝试获取文本
                        const text = await response.text();
                        if (text) {
                            errorMessage = `服务器错误: ${text.substring(0, 200)}`;
                        }
                    }
                    
                    throw new Error(errorMessage);
                }
            } catch (error) {
                console.error('下载日志失败:', error);
                
                // 更详细的错误处理
                let userMessage = `下载失败: ${error.message}`;
                
                if (error.message.includes('Network Error') || error.message.includes('Failed to fetch')) {
                    userMessage = '网络连接失败，请检查服务器状态';
                } else if (error.message.includes('HTML')) {
                    userMessage = '服务器配置错误，请检查后端服务';
                }
                
                showNotification(userMessage, 'error');
                updateStatus('idle', '日志下载失败');
                
                // 显示调试信息（仅开发环境）
                if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
                    console.debug('下载失败详情:', {
                        softwareType,
                        error: error.message,
                        stack: error.stack
                    });
                }
            } finally {
                // 恢复按钮状态
                const logBtn = document.getElementById(`${softwareType}LogBtn`);
                logBtn.innerHTML = '<span>📋</span> 下载日志';
                logBtn.disabled = false;
            }
        }

        // 显示通知
        function showNotification(message, type = 'info') {
            const notificationContainer = document.getElementById('notificationContainer');
            
            const notification = document.createElement('div');
            notification.className = `notification notification-${type}`;
            
            const messageSpan = document.createElement('span');
            messageSpan.textContent = message;
            
            const closeBtn = document.createElement('button');
            closeBtn.className = 'close-notification';
            closeBtn.innerHTML = '×';
            closeBtn.onclick = () => notification.remove();
            
            notification.appendChild(messageSpan);
            notification.appendChild(closeBtn);
            
            notificationContainer.appendChild(notification);
            notificationContainer.style.display = 'block';
            
            // 3秒后自动移除
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.remove();
                }
                if (notificationContainer.children.length === 0) {
                    notificationContainer.style.display = 'none';
                }
            }, 3000);
        }

        // 上传并执行
        async function uploadAndExecute(softwareType) {
            const file = selectedFiles[softwareType];
            if (!file || isRunning || uploadInProgress) return;
            
            uploadInProgress = true;
            currentSoftware = softwareType;
            updateStatus('running', `正在上传${getSoftwareName(softwareType)}...`);
            
            try {
                const formData = new FormData();
                formData.append('file', file);
                formData.append('software_type', softwareType);
                
                const response = await fetch('/upload', {
                    method: 'POST',
                    body: formData
                });
                
                const data = await response.json();
                
                if (data.success) {
                    // 清除输出
                    document.getElementById('output').innerHTML = '';
                    
                    // 开始接收SSE流
                    startEventStream();
                    
                    // 更新按钮状态
                    document.getElementById(`${softwareType}UpdateBtn`).disabled = true;
                    document.getElementById(`${softwareType}LogBtn`).disabled = true;
                    document.getElementById('stopBtn').disabled = false;
                    document.getElementById('stopBtnCompute').disabled = false;
                    document.getElementById('stopBtnMonitor').disabled = false;
                    
                    updateStatus('running', `正在处理${getSoftwareName(softwareType)}: ${data.filename}`);
                } else {
                    alert(data.message);
                    updateStatus('idle', `${getSoftwareName(softwareType)}上传失败`);
                }
            } catch (error) {
                console.error('上传失败:', error);
                alert('上传失败: ' + error.message);
                updateStatus('idle', '上传失败');
            } finally {
                uploadInProgress = false;
            }
        }

        // 开始事件流
        function startEventStream() {
            if (eventSource) {
                eventSource.close();
            }
            
            eventSource = new EventSource('/stream');
            
            eventSource.onmessage = function(event) {
                const data = JSON.parse(event.data);
                const outputDiv = document.getElementById('output');
                
                // 根据软件类型添加颜色标识
                let outputHtml = '';
                if (data.output) {
                    const color = getSoftwareColor(currentSoftware);
                    outputHtml = `<span style="color: ${color}">[${getSoftwareName(currentSoftware)}] </span>${data.output}`;
                } else {
                    outputHtml = data.output;
                }
                
                outputDiv.innerHTML += outputHtml;
                
                // 自动滚动到底部
                outputDiv.scrollTop = outputDiv.scrollHeight;
                
                // 检查是否结束
                if (data.output && data.output.includes('处理完成')) {
                    stopEventStream();
                    isRunning = false;
                    updateStatus('idle', '处理完成');
                    
                    // 重新启用当前软件的更新按钮和日志按钮
                    document.getElementById(`${currentSoftware}UpdateBtn`).disabled = false;
                    document.getElementById(`${currentSoftware}LogBtn`).disabled = false;
                    document.getElementById('stopBtn').disabled = true;
                    document.getElementById('stopBtnCompute').disabled = true;
                    document.getElementById('stopBtnMonitor').disabled = true;
                    
                    showNotification(`${getSoftwareName(currentSoftware)}更新完成`, 'success');
                }
            };
            
            eventSource.onerror = function(error) {
                console.error('EventSource错误:', error);
                stopEventStream();
                updateStatus('idle', '连接错误');
                
                // 重新启用按钮
                document.getElementById(`${currentSoftware}UpdateBtn`).disabled = false;
                document.getElementById(`${currentSoftware}LogBtn`).disabled = false;
                document.getElementById('stopBtn').disabled = true;
                document.getElementById('stopBtnCompute').disabled = true;
                document.getElementById('stopBtnMonitor').disabled = true;
                
                showNotification('连接中断，处理可能未完成', 'error');
            };
        }

        // 获取软件颜色
        function getSoftwareColor(softwareType) {
            const colors = {
                network: '#667eea',
                compute: '#00b09b',
                monitor: '#ff416c'
            };
            return colors[softwareType] || '#d4d4d4';
        }

        // 停止事件流
        function stopEventStream() {
            if (eventSource) {
                eventSource.close();
                eventSource = null;
            }
        }

        // 停止执行
        async function stopExecution() {
            if (!isRunning) return;
            
            try {
                const response = await fetch('/stop');
                const data = await response.json();
                
                if (data.success) {
                    isRunning = false;
                    updateStatus('idle', '已停止');
                    stopEventStream();
                    
                    // 更新按钮状态
                    document.getElementById(`${currentSoftware}UpdateBtn`).disabled = false;
                    document.getElementById(`${currentSoftware}LogBtn`).disabled = false;
                    document.getElementById('stopBtn').disabled = true;
                    document.getElementById('stopBtnCompute').disabled = true;
                    document.getElementById('stopBtnMonitor').disabled = true;
                    
                    const color = getSoftwareColor(currentSoftware);
                    document.getElementById('output').innerHTML += 
                        `<br><span style="color: ${color}">[${getSoftwareName(currentSoftware)}] </span>` +
                        '<span style="color: orange;">用户手动停止处理</span><br>';
                    
                    showNotification('处理已停止', 'info');
                }
            } catch (error) {
                console.error('停止失败:', error);
                showNotification('停止失败', 'error');
            }
        }

        // 清空输出
        async function clearOutput() {
            try {
                const response = await fetch('/clear_output', {
                    method: 'POST'
                });
                const data = await response.json();
                
                if (data.success) {
                    document.getElementById('output').innerHTML = '输出已清空<br>';
                    showNotification('输出已清空', 'info');
                }
            } catch (error) {
                console.error('清空输出失败:', error);
                showNotification('清空输出失败', 'error');
            }
        }

        // 检查状态
        async function checkStatus() {
            try {
                const response = await fetch('/status');
                const data = await response.json();
                
                if (data.is_running) {
                    isRunning = true;
                    updateStatus('running', '正在处理中...');
                    
                    // 根据服务器返回的软件类型禁用对应按钮
                    const runningSoftware = data.software_type || 'network';
                    document.getElementById(`${runningSoftware}UpdateBtn`).disabled = true;
                    document.getElementById(`${runningSoftware}LogBtn`).disabled = true;
                    document.getElementById('stopBtn').disabled = false;
                    document.getElementById('stopBtnCompute').disabled = false;
                    document.getElementById('stopBtnMonitor').disabled = false;
                    
                    currentSoftware = runningSoftware;
                    startEventStream();
                } else {
                    updateStatus('idle', '就绪 - 等待上传文件');
                }
            } catch (error) {
                console.error('检查状态失败:', error);
            }
        }

        // 更新状态指示器
        function updateStatus(status, message) {
            const indicator = document.getElementById('statusIndicator');
            const statusText = document.getElementById('statusText');
            const statusDot = indicator.querySelector('.status-dot');
            
            // 移除所有状态类
            indicator.classList.remove('status-running', 'status-stopped', 'status-idle');
            statusDot.classList.remove('running-dot', 'stopped-dot', 'idle-dot');
            
            // 添加新状态类
            if (status === 'running') {
                indicator.classList.add('status-running');
                statusDot.classList.add('running-dot');
                isRunning = true;
            } else if (status === 'stopped') {
                indicator.classList.add('status-stopped');
                statusDot.classList.add('stopped-dot');
                isRunning = false;
            } else {
                indicator.classList.add('status-idle');
                statusDot.classList.add('idle-dot');
                isRunning = false;
            }
            
            statusText.textContent = message;
        }
    </script>
</body>
</html>