// 全局变量 let socket = null; let currentModalType = ''; let selectedItem = null; let currentPath = ''; let searchResults = []; // 初始化Socket连接 document.addEventListener('DOMContentLoaded', function() { socket = io(); // 监听发送输出 socket.on('send_output', function(data) { const output = document.getElementById('send-output'); output.textContent += data.message; output.scrollTop = output.scrollHeight; }); // 监听发送状态 socket.on('send_status', function(data) { document.getElementById('send-status').textContent = data.status; }); // 监听接收输出 socket.on('receive_output', function(data) { const output = document.getElementById('receive-output'); output.textContent += data.message; output.scrollTop = output.scrollHeight; }); // 监听接收状态 socket.on('receive_status', function(data) { document.getElementById('receive-status').textContent = data.status; }); // 监听文件路径输入变化 const filePathInput = document.getElementById('send-file-path'); filePathInput.addEventListener('input', updateFileInfo); filePathInput.addEventListener('change', updateFileInfo); // 初始更新文件信息 updateFileInfo(); }); // 更新文件信息 function updateFileInfo() { const filePath = document.getElementById('send-file-path').value.trim(); const fileSizeElement = document.getElementById('file-size'); const fileMtimeElement = document.getElementById('file-mtime'); const fileStatusElement = document.getElementById('file-status'); if (!filePath) { fileSizeElement.textContent = '-'; fileMtimeElement.textContent = '-'; fileStatusElement.textContent = '未选择'; fileStatusElement.className = 'file-status-unknown'; return; } // 检查文件是否存在 fetch('/check/file', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ file_path: filePath }) }) .then(response => { const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { return response.text().then(text => { throw new Error('服务器返回了非JSON响应'); }); } return response.json(); }) .then(data => { if (data.status === 'success') { fileSizeElement.textContent = formatFileSize(data.size); fileMtimeElement.textContent = new Date(data.mtime * 1000).toLocaleString(); fileStatusElement.textContent = '文件有效'; fileStatusElement.className = 'file-status-valid'; } else { fileSizeElement.textContent = '-'; fileMtimeElement.textContent = '-'; fileStatusElement.textContent = '文件不存在或无法访问'; fileStatusElement.className = 'file-status-invalid'; } }) .catch(error => { console.error('检查文件错误:', error); fileSizeElement.textContent = '-'; fileMtimeElement.textContent = '-'; fileStatusElement.textContent = '检查失败'; fileStatusElement.className = 'file-status-invalid'; }); } // 手动浏览文件 function browseFileManually() { currentModalType = 'send'; currentPath = document.getElementById('send-file-path').value || '/'; const filePath = document.getElementById('send-file-path').value; if (filePath) { try { const dirPath = require('path').dirname(filePath); if (require('fs').existsSync(dirPath)) { currentPath = dirPath; } } catch (e) { // 忽略错误,使用默认路径 } } fetchFileList(currentPath, 'file'); document.getElementById('file-browser-modal').style.display = 'block'; } // 显示指定界面 function showScreen(screenId) { document.querySelectorAll('.screen').forEach(screen => { screen.classList.remove('active'); }); document.getElementById(screenId).classList.add('active'); } // 发送连接 function sendConnect() { const key = document.getElementById('send-key').value; fetch('/send/connect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key: key }) }) .then(response => response.json()) .then(data => { if (data.status === 'success') { document.getElementById('send-connect-btn').disabled = true; document.getElementById('send-stop-btn').disabled = false; // 3秒后启用发送文件按钮 setTimeout(() => { document.getElementById('send-file-btn').disabled = false; }, 3000); } else { alert('错误: ' + data.message); } }) .catch(error => { console.error('Error:', error); alert('连接失败: ' + error); }); } // 发送文件 function sendFile() { const filePath = document.getElementById('send-file-path').value; const key = document.getElementById('send-key').value; const parts = key.split('|'); const psk = parts.length >= 3 ? parts[2].trim() : ''; fetch('/send/file', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file_path: filePath, psk: psk }) }) .then(response => response.json()) .then(data => { if (data.status !== 'success') { alert('错误: ' + data.message); } }) .catch(error => { console.error('Error:', error); alert('发送失败: ' + error); }); } // 停止发送 function sendStop() { fetch('/send/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { if (data.status === 'success') { document.getElementById('send-connect-btn').disabled = false; document.getElementById('send-file-btn').disabled = true; document.getElementById('send-stop-btn').disabled = true; } }) .catch(error => { console.error('Error:', error); }); } // 接收连接 function receiveConnect() { const key = document.getElementById('receive-key').value; const savePath = document.getElementById('receive-save-path').value; fetch('/receive/connect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key: key, save_path: savePath }) }) .then(response => response.json()) .then(data => { if (data.status === 'success') { document.getElementById('receive-connect-btn').disabled = true; document.getElementById('receive-stop-btn').disabled = false; } else { alert('错误: ' + data.message); } }) .catch(error => { console.error('Error:', error); alert('连接失败: ' + error); }); } // 停止接收 function receiveStop() { fetch('/receive/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(data => { if (data.status === 'success') { document.getElementById('receive-connect-btn').disabled = false; document.getElementById('receive-stop-btn').disabled = true; } }) .catch(error => { console.error('Error:', error); }); } // 打开搜索模态框 function openSearchModal() { document.getElementById('file-search-modal').style.display = 'block'; document.getElementById('search-path').value = '/'; document.getElementById('search-keyword').value = '*'; document.getElementById('search-results-list').innerHTML = ''; document.getElementById('result-count').textContent = '0'; document.getElementById('search-select-btn').disabled = true; selectedItem = null; searchResults = []; } // 关闭搜索模态框 function closeSearchModal() { document.getElementById('file-search-modal').style.display = 'none'; } // 浏览搜索路径 function browseSearchPath() { currentModalType = 'search_path'; currentPath = document.getElementById('search-path').value || '/'; fetchFileList(currentPath, 'folder'); document.getElementById('file-browser-modal').style.display = 'block'; } // 开始搜索 function startSearch() { const searchPath = document.getElementById('search-path').value; const keyword = document.getElementById('search-keyword').value; const maxResults = document.getElementById('max-results').value; if (!keyword) { alert('请输入搜索关键词'); return; } // 显示加载状态 const resultsList = document.getElementById('search-results-list'); resultsList.innerHTML = '
搜索中...
'; fetch('/search/files', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ path: searchPath, pattern: keyword, max_results: parseInt(maxResults) }) }) .then(response => { const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { return response.text().then(text => { throw new Error(`服务器返回了非JSON响应: ${text.substring(0, 100)}...`); }); } return response.json(); }) .then(data => { if (data.status === 'success') { searchResults = data.results; displaySearchResults(data.results); document.getElementById('result-count').textContent = data.count; } else { alert('搜索失败: ' + data.message); resultsList.innerHTML = '
搜索失败
'; } }) .catch(error => { console.error('搜索错误:', error); alert('搜索失败: ' + error.message); resultsList.innerHTML = '
搜索错误
'; }); } // 显示搜索结果 function displaySearchResults(results) { const resultsList = document.getElementById('search-results-list'); resultsList.innerHTML = ''; if (results.length === 0) { resultsList.innerHTML = '
未找到匹配的文件
'; return; } results.forEach(result => { const div = document.createElement('div'); div.className = 'file-item'; const fileSize = formatFileSize(result.size || 0); div.innerHTML = `
📄 ${result.name}
${result.relative_path} ${fileSize}
`; div.dataset.path = result.path; div.addEventListener('click', function() { // 取消之前的选择 document.querySelectorAll('.file-item.selected').forEach(el => { el.classList.remove('selected'); }); // 选择当前项 this.classList.add('selected'); selectedItem = this; document.getElementById('search-select-btn').disabled = false; }); resultsList.appendChild(div); }); } // 格式化文件大小 function formatFileSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } // 选择搜索结果 function selectSearchResult() { if (!selectedItem) { alert('请先选择一个文件'); return; } const filePath = selectedItem.dataset.path; document.getElementById('send-file-path').value = filePath; closeSearchModal(); updateFileInfo(); // 更新文件信息显示 } // 获取文件列表 function fetchFileList(path, type) { fetch('/browse', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ path: path, type: type }) }) .then(response => { const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { return response.text().then(text => { throw new Error(`服务器返回了非JSON响应: ${text.substring(0, 100)}...`); }); } return response.json(); }) .then(data => { if (data.status === 'success') { currentPath = data.current_path; document.getElementById('current-path').textContent = currentPath; const fileList = document.getElementById('file-list'); fileList.innerHTML = ''; data.items.forEach(item => { const div = document.createElement('div'); div.className = 'file-item'; div.innerHTML = item.type === 'folder' ? `📁 ${item.name}` : `📄 ${item.name}`; div.dataset.path = item.path; div.dataset.type = item.type; div.addEventListener('click', function() { // 取消之前的选择 document.querySelectorAll('.file-item.selected').forEach(el => { el.classList.remove('selected'); }); // 选择当前项 this.classList.add('selected'); selectedItem = this; // 如果是文件夹,双击进入 this.addEventListener('dblclick', function() { if (item.type === 'folder') { if (currentModalType === 'search_path') { document.getElementById('search-path').value = item.path; closeModal(); } else { fetchFileList(item.path, type); } } }); }); fileList.appendChild(div); }); } else { alert('错误: ' + data.message); } }) .catch(error => { console.error('Error:', error); alert('获取文件列表失败: ' + error.message); }); } // 导航到上级目录 function navigateUp() { const parentPath = currentPath.split('/').slice(0, -1).join('/'); if (parentPath === '') { currentPath = '/'; } else { currentPath = parentPath; } const type = currentModalType === 'send' ? 'file' : 'folder'; fetchFileList(currentPath, type); } // 关闭模态框 function closeModal() { document.getElementById('file-browser-modal').style.display = 'none'; selectedItem = null; } // 选择文件或文件夹 function selectItem() { if (!selectedItem) { alert('请先选择一个项目'); return; } const path = selectedItem.dataset.path; const type = selectedItem.dataset.type; if (currentModalType === 'send') { if (type === 'file') { document.getElementById('send-file-path').value = path; closeModal(); updateFileInfo(); // 更新文件信息显示 } else { alert('请选择一个文件'); } } else if (currentModalType === 'folder') { document.getElementById('receive-save-path').value = path; closeModal(); } else if (currentModalType === 'search_path') { document.getElementById('search-path').value = path; closeModal(); } }