/** * Git文件上传工具 - 主要JavaScript功能 * 支持文件上传、Git操作、文件管理等功能 */ class GitUploader { constructor() { this.selectedFiles = new Set(); this.init(); } // 初始化 init() { this.setupEventListeners(); this.checkGitStatus(); this.loadFileList(); this.showRemotes(); // 加载远程仓库列表 this.loadBranches(); // 加载分支列表 } // 设置事件监听器 setupEventListeners() { // 文件上传相关 const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); uploadArea.addEventListener('click', () => fileInput.click()); uploadArea.addEventListener('dragover', this.handleDragOver.bind(this)); uploadArea.addEventListener('dragleave', this.handleDragLeave.bind(this)); uploadArea.addEventListener('drop', this.handleDrop.bind(this)); fileInput.addEventListener('change', this.handleFileSelect.bind(this)); // Git操作相关 document.getElementById('gitAdd').addEventListener('click', () => this.gitOperation('add')); document.getElementById('gitCommit').addEventListener('click', () => this.gitOperation('commit')); document.getElementById('gitPush').addEventListener('click', () => this.gitOperation('push')); document.getElementById('gitStatusBtn').addEventListener('click', () => this.gitOperation('status')); document.getElementById('gitLog').addEventListener('click', () => this.gitOperation('log')); // 远程仓库相关 document.getElementById('addRemote').addEventListener('click', () => this.addRemote()); document.getElementById('showRemotes').addEventListener('click', () => this.showRemotes()); // 分支管理相关 document.getElementById('createBranch').addEventListener('click', () => this.createBranch()); document.getElementById('switchBranch').addEventListener('click', () => this.switchBranch()); document.getElementById('deleteBranch').addEventListener('click', () => this.deleteBranch()); document.getElementById('refreshBranches').addEventListener('click', () => this.loadBranches()); // 文件列表相关 document.getElementById('refreshFiles').addEventListener('click', () => this.loadFileList()); document.getElementById('selectAllFiles').addEventListener('click', () => this.selectAllFiles()); document.getElementById('deselectAllFiles').addEventListener('click', () => this.deselectAllFiles()); } // 拖拽处理 handleDragOver(e) { e.preventDefault(); document.getElementById('uploadArea').classList.add('dragover'); } handleDragLeave(e) { e.preventDefault(); document.getElementById('uploadArea').classList.remove('dragover'); } handleDrop(e) { e.preventDefault(); document.getElementById('uploadArea').classList.remove('dragover'); const files = Array.from(e.dataTransfer.files); this.uploadFiles(files); } handleFileSelect(e) { const files = Array.from(e.target.files); this.uploadFiles(files); } // 文件上传 async uploadFiles(files) { if (files.length === 0) return; const formData = new FormData(); formData.append('action', 'upload'); files.forEach(file => { formData.append('files[]', file); }); try { this.showMessage('正在上传文件...', 'info'); const response = await fetch('index.php', { method: 'POST', body: formData }); const result = await response.json(); if (result.success) { this.showMessage(`成功上传 ${result.files.length} 个文件`, 'success'); this.displayUploadedFiles(result.files); this.loadFileList(); // 重新加载文件列表 } else { this.showMessage(result.message || '上传失败', 'error'); } } catch (error) { this.showMessage('上传出错: ' + error.message, 'error'); } } // 显示已上传的文件 displayUploadedFiles(files) { const container = document.getElementById('uploadedFiles'); container.innerHTML = ''; files.forEach(file => { const fileItem = document.createElement('div'); fileItem.className = 'file-item success fade-in'; fileItem.innerHTML = ` ${file} `; container.appendChild(fileItem); }); } // 检查Git状态 async checkGitStatus() { try { const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'action=check_git' }); const result = await response.json(); const indicator = document.getElementById('gitIndicator'); const statusText = document.getElementById('gitStatusText'); if (result.success && result.hasGit) { indicator.classList.add('active'); statusText.textContent = 'Git仓库已初始化'; } else { indicator.classList.remove('active'); statusText.textContent = 'Git仓库未初始化'; // 自动初始化Git仓库 if (confirm('Git仓库未初始化,是否现在初始化?')) { await this.initGitRepo(); } } } catch (error) { this.showMessage('检查Git状态失败: ' + error.message, 'error'); } } // 初始化Git仓库 async initGitRepo() { try { const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'action=init_git' }); const result = await response.json(); if (result.success) { this.showMessage('Git仓库初始化成功', 'success'); this.checkGitStatus(); // 重新检查状态 } else { this.showMessage('Git仓库初始化失败', 'error'); } } catch (error) { this.showMessage('初始化Git仓库失败: ' + error.message, 'error'); } } // Git操作 async gitOperation(operation) { const commitMessage = document.getElementById('commitMessage').value || '自动提交'; const selectedFiles = Array.from(this.selectedFiles); const remoteName = document.getElementById('remoteName').value || 'origin'; const branchSelect = document.getElementById('branchSelect'); const currentBranch = branchSelect ? branchSelect.value : 'main'; const params = new URLSearchParams(); params.append('action', 'git_operation'); params.append('operation', operation); if (operation === 'commit') { params.append('message', commitMessage); } if (operation === 'push') { params.append('remote', remoteName); params.append('branch', currentBranch); // 使用当前选择的分支 } if (operation === 'add' && selectedFiles.length > 0) { selectedFiles.forEach(file => { params.append('files[]', file); }); } try { this.showMessage(`正在执行 Git ${operation}...`, 'info'); const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const result = await response.json(); if (result.success) { this.showMessage(`Git ${operation} 执行成功`, 'success'); this.displayGitOutput(result.output); if (operation === 'add' || operation === 'commit') { this.loadFileList(); // 重新加载文件列表 } } else { this.showMessage(`Git ${operation} 执行失败: ${result.message || '未知错误'}`, 'error'); this.displayGitOutput(result.output || []); } } catch (error) { this.showMessage(`Git ${operation} 执行出错: ${error.message}`, 'error'); } } // 显示Git输出 displayGitOutput(output) { const outputElement = document.getElementById('gitOutput'); if (output && output.length > 0) { outputElement.textContent = output.join('\n'); } else { outputElement.textContent = '暂无输出'; } outputElement.scrollTop = outputElement.scrollHeight; } // 添加远程仓库 async addRemote() { const name = document.getElementById('remoteName').value.trim(); const url = document.getElementById('remoteUrl').value.trim(); if (!name || !url) { this.showMessage('请输入远程仓库名称和地址', 'error'); return; } const params = new URLSearchParams(); params.append('action', 'add_remote'); params.append('name', name); params.append('url', url); try { this.showMessage('正在添加远程仓库...', 'info'); const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const result = await response.json(); if (result.success) { this.showMessage('远程仓库添加成功', 'success'); document.getElementById('remoteUrl').value = ''; // 清空输入框 this.showRemotes(); // 刷新远程仓库列表 } else { this.showMessage('添加远程仓库失败: ' + (result.message || '未知错误'), 'error'); } } catch (error) { this.showMessage('添加远程仓库出错: ' + error.message, 'error'); } } // 显示远程仓库列表 async showRemotes() { try { const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'action=get_remotes' }); const result = await response.json(); const remoteList = document.getElementById('remoteList'); if (result.success && result.remotes && Object.keys(result.remotes).length > 0) { remoteList.innerHTML = ''; Object.entries(result.remotes).forEach(([name, info]) => { const remoteItem = document.createElement('div'); remoteItem.className = 'remote-item'; remoteItem.innerHTML = `
${name} (${info.type})
${info.url}
`; remoteList.appendChild(remoteItem); }); } else { remoteList.innerHTML = '
暂无远程仓库
'; } } catch (error) { this.showMessage('获取远程仓库列表失败: ' + error.message, 'error'); } } // 加载分支列表 async loadBranches() { try { const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'action=get_branches' }); const result = await response.json(); const branchSelect = document.getElementById('branchSelect'); if (result.success && result.branches) { branchSelect.innerHTML = ''; result.branches.forEach(branch => { const option = document.createElement('option'); option.value = branch.name; option.textContent = branch.name + (branch.current ? ' (当前)' : '') + (branch.remote ? ' (远程)' : ''); if (branch.current) { option.selected = true; } branchSelect.appendChild(option); }); } else { branchSelect.innerHTML = ''; } } catch (error) { this.showMessage('获取分支列表失败: ' + error.message, 'error'); } } // 创建新分支 async createBranch() { const branchName = document.getElementById('newBranchName').value.trim(); if (!branchName) { this.showMessage('请输入分支名称', 'error'); return; } const params = new URLSearchParams(); params.append('action', 'create_branch'); params.append('branch_name', branchName); try { this.showMessage('正在创建分支...', 'info'); const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const result = await response.json(); if (result.success) { this.showMessage('分支创建成功', 'success'); document.getElementById('newBranchName').value = ''; // 清空输入框 this.loadBranches(); // 重新加载分支列表 this.displayGitOutput(result.output); } else { this.showMessage('创建分支失败: ' + (result.message || '未知错误'), 'error'); this.displayGitOutput(result.output || []); } } catch (error) { this.showMessage('创建分支出错: ' + error.message, 'error'); } } // 切换分支 async switchBranch() { const branchSelect = document.getElementById('branchSelect'); const branchName = branchSelect.value; if (!branchName) { this.showMessage('请选择要切换的分支', 'error'); return; } const params = new URLSearchParams(); params.append('action', 'switch_branch'); params.append('branch_name', branchName); try { this.showMessage('正在切换分支...', 'info'); const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const result = await response.json(); if (result.success) { this.showMessage('分支切换成功', 'success'); this.loadBranches(); // 重新加载分支列表 this.loadFileList(); // 重新加载文件列表 this.displayGitOutput(result.output); } else { this.showMessage('切换分支失败: ' + (result.message || '未知错误'), 'error'); this.displayGitOutput(result.output || []); } } catch (error) { this.showMessage('切换分支出错: ' + error.message, 'error'); } } // 删除分支 async deleteBranch() { const branchSelect = document.getElementById('branchSelect'); const branchName = branchSelect.value; if (!branchName) { this.showMessage('请选择要删除的分支', 'error'); return; } if (!confirm(`确定要删除分支 "${branchName}" 吗?`)) { return; } const params = new URLSearchParams(); params.append('action', 'delete_branch'); params.append('branch_name', branchName); params.append('force', 'false'); // 默认不强制删除 try { this.showMessage('正在删除分支...', 'info'); const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const result = await response.json(); if (result.success) { this.showMessage('分支删除成功', 'success'); this.loadBranches(); // 重新加载分支列表 this.displayGitOutput(result.output); } else { this.showMessage('删除分支失败: ' + (result.message || '未知错误'), 'error'); this.displayGitOutput(result.output || []); if (confirm('是否强制删除该分支?')) { params.set('force', 'true'); const forceResponse = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params }); const forceResult = await forceResponse.json(); if (forceResult.success) { this.showMessage('分支强制删除成功', 'success'); this.loadBranches(); this.displayGitOutput(forceResult.output); } } } } catch (error) { this.showMessage('删除分支出错: ' + error.message, 'error'); } } // 加载文件列表 async loadFileList() { try { const response = await fetch('index.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'action=get_files' }); const result = await response.json(); if (result.success) { this.displayFileList(result.files); } else { this.showMessage('加载文件列表失败', 'error'); } } catch (error) { this.showMessage('加载文件列表出错: ' + error.message, 'error'); } } // 显示文件列表 displayFileList(files) { const container = document.getElementById('fileList'); if (files.length === 0) { container.innerHTML = '
暂无文件
'; return; } container.innerHTML = ''; files.forEach(file => { const fileItem = document.createElement('div'); fileItem.className = 'file-checkbox'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `file-${this.escapeId(file)}`; checkbox.value = file; checkbox.checked = this.selectedFiles.has(file); checkbox.addEventListener('change', (e) => { if (e.target.checked) { this.selectedFiles.add(file); } else { this.selectedFiles.delete(file); } }); const label = document.createElement('label'); label.htmlFor = checkbox.id; label.className = 'file-path'; label.textContent = file; label.style.cursor = 'pointer'; label.style.flex = '1'; fileItem.appendChild(checkbox); fileItem.appendChild(label); container.appendChild(fileItem); }); } // 全选文件 selectAllFiles() { const checkboxes = document.querySelectorAll('#fileList input[type="checkbox"]'); checkboxes.forEach(checkbox => { checkbox.checked = true; this.selectedFiles.add(checkbox.value); }); } // 取消全选 deselectAllFiles() { const checkboxes = document.querySelectorAll('#fileList input[type="checkbox"]'); checkboxes.forEach(checkbox => { checkbox.checked = false; this.selectedFiles.delete(checkbox.value); }); } // 工具方法:转义ID escapeId(str) { return str.replace(/[^a-zA-Z0-9]/g, '_'); } // 显示消息 showMessage(message, type = 'info') { // 创建消息元素 const messageElement = document.createElement('div'); messageElement.className = `message ${type} fade-in`; messageElement.textContent = message; // 添加到页面顶部 const container = document.querySelector('.container'); container.insertBefore(messageElement, container.firstChild); // 3秒后自动移除 setTimeout(() => { messageElement.remove(); }, 3000); } } // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', () => { new GitUploader(); });