Files
Demo1/js/main.js
2025-11-15 17:37:48 +08:00

593 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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();
});