初始提交

This commit is contained in:
2025-11-15 17:37:48 +08:00
commit ec563fc407
7 changed files with 2162 additions and 0 deletions

593
js/main.js Normal file
View File

@@ -0,0 +1,593 @@
/**
* 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 = `
<span>${file}</span>
<span style="color: #27ae60;">✓</span>
`;
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 = `
<div>
<div class="remote-name">${name} (${info.type})</div>
<div class="remote-url">${info.url}</div>
</div>
`;
remoteList.appendChild(remoteItem);
});
} else {
remoteList.innerHTML = '<div class="loading">暂无远程仓库</div>';
}
} 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 = '<option value="">暂无分支</option>';
}
} 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 = '<div class="loading">暂无文件</div>';
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();
});