// 全局变量
let uploadedFiles = [];
let isChecking = false;
let checkProgress = 0;
let currentProject = null;
let projects = [];
// API 基础URL
const API_BASE_URL = 'http://localhost:5000/api';
// DOM 元素
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const progressContainer = document.getElementById('progressContainer');
const progressFill = document.getElementById('progressFill');
const progressText = document.getElementById('progressText');
const startCheckBtn = document.getElementById('startCheckBtn');
const stopCheckBtn = document.getElementById('stopCheckBtn');
const resultsSection = document.getElementById('resultsSection');
const resultsContent = document.getElementById('resultsContent');
// 页面切换功能
const navLinks = document.querySelectorAll('.nav-link');
const pageContents = document.querySelectorAll('.page-content');
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const targetPage = link.getAttribute('href').substring(1);
showPage(targetPage);
// 更新导航状态
navLinks.forEach(l => l.classList.remove('active'));
link.classList.add('active');
});
});
function showPage(pageId) {
pageContents.forEach(page => {
page.classList.remove('active');
});
const targetPage = document.getElementById(pageId + '-page');
if (targetPage) {
targetPage.classList.add('active');
// 根据页面加载相应数据
switch(pageId) {
case 'dashboard':
loadDashboardData();
break;
case 'projects':
loadProjects();
break;
}
}
}
// 文件上传处理
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', handleDragOver);
uploadArea.addEventListener('dragleave', handleDragLeave);
uploadArea.addEventListener('drop', handleDrop);
fileInput.addEventListener('change', handleFileSelect);
function handleDragOver(e) {
e.preventDefault();
uploadArea.classList.add('dragover');
}
function handleDragLeave(e) {
e.preventDefault();
uploadArea.classList.remove('dragover');
}
function handleDrop(e) {
e.preventDefault();
uploadArea.classList.remove('dragover');
const files = Array.from(e.dataTransfer.files);
processFiles(files);
}
function handleFileSelect(e) {
const files = Array.from(e.target.files);
processFiles(files);
}
function processFiles(files) {
const validFiles = files.filter(file =>
file.name.endsWith('.py') ||
file.name.endsWith('.pyx') ||
file.name.endsWith('.pyi')
);
if (validFiles.length === 0) {
alert('请选择有效的 Python 文件!');
return;
}
uploadedFiles = validFiles;
updateUploadArea();
startCheckBtn.style.display = 'inline-block';
}
function updateUploadArea() {
if (uploadedFiles.length > 0) {
uploadArea.innerHTML = `
已选择 ${uploadedFiles.length} 个文件
${uploadedFiles.map(f => f.name).join(', ')}
`;
}
}
// 开始检查
startCheckBtn.addEventListener('click', startCheck);
stopCheckBtn.addEventListener('click', stopCheck);
async function startCheck() {
if (uploadedFiles.length === 0) {
alert('请先上传文件!');
return;
}
isChecking = true;
startCheckBtn.style.display = 'none';
stopCheckBtn.style.display = 'inline-block';
progressContainer.style.display = 'block';
resultsSection.style.display = 'none';
// 更新 Agent 状态
updateAgentStatus('working');
try {
// 第一步:上传文件
updateProgress(10, '正在上传文件...');
const uploadResult = await uploadFiles();
if (!uploadResult || !uploadResult.success) {
throw new Error(uploadResult?.error || '文件上传失败');
}
// 第二步:开始代码检查
updateProgress(30, '开始代码检查...');
const checkResult = await runCodeCheck(uploadResult.data.temp_path);
if (!checkResult || !checkResult.success) {
throw new Error(checkResult?.error || '代码检查失败');
}
// 第三步:处理检查结果
updateProgress(90, '处理检查结果...');
await processCheckResults(checkResult.data);
// 第四步:完成检查
updateProgress(100, '检查完成!');
completeCheck();
} catch (error) {
console.error('检查过程出错:', error);
alert('检查失败:' + error.message);
stopCheck();
}
}
function stopCheck() {
isChecking = false;
startCheckBtn.style.display = 'inline-block';
stopCheckBtn.style.display = 'none';
progressContainer.style.display = 'none';
// 更新 Agent 状态
updateAgentStatus('idle');
}
function updateAgentStatus(status) {
const agentItems = document.querySelectorAll('.agent-item');
agentItems.forEach(item => {
const badge = item.querySelector('.agent-status-badge');
badge.className = `agent-status-badge status-${status}`;
badge.textContent = status === 'working' ? '工作中' :
status === 'completed' ? '完成' : '空闲';
});
}
// 更新进度条
function updateProgress(progress, text) {
progressFill.style.width = progress + '%';
progressText.textContent = text;
}
// 上传文件到服务器
async function uploadFiles() {
try {
if (uploadedFiles.length === 0) {
throw new Error('没有选择要上传的文件');
}
const formData = new FormData();
uploadedFiles.forEach(file => {
formData.append('files', file);
});
const response = await fetch(`${API_BASE_URL}/upload`, {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
} catch (error) {
console.error('上传文件时发生错误:', error);
return {
success: false,
error: error.message || '网络连接失败,请检查后端服务是否正常运行'
};
}
}
// 运行代码检查
async function runCodeCheck(tempPath) {
try {
const response = await fetch(`${API_BASE_URL}/check`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
temp_path: tempPath
})
});
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
} catch (error) {
console.error('代码检查时发生错误:', error);
return {
success: false,
error: error.message || '代码检查失败,请检查后端服务是否正常运行'
};
}
}
// 处理检查结果
async function processCheckResults(data) {
// 更新统计信息
updateStatistics(data);
// 更新工具状态
updateToolsStatus(data.tools_status);
// 显示检查结果
displayResults(data.all_issues);
// 更新Agent状态
updateAgentStatus('completed');
}
// 更新统计信息
function updateStatistics(data) {
// 更新仪表板上的统计数据
const totalFilesElement = document.getElementById('totalFiles');
const complianceRateElement = document.getElementById('complianceRate');
const pendingIssuesElement = document.getElementById('pendingIssues');
const highRiskIssuesElement = document.getElementById('highRiskIssues');
if (totalFilesElement) {
// 这里可以计算实际检查的文件数
totalFilesElement.textContent = uploadedFiles.length;
}
if (pendingIssuesElement) {
pendingIssuesElement.textContent = data.warning_count || 0;
}
if (highRiskIssuesElement) {
highRiskIssuesElement.textContent = data.error_count || 0;
}
if (complianceRateElement) {
const totalIssues = data.total_issues || 0;
const complianceRate = totalIssues === 0 ? 100 : Math.max(0, 100 - (totalIssues * 2));
complianceRateElement.textContent = complianceRate.toFixed(1) + '%';
}
console.log('检查结果统计:', {
total_issues: data.total_issues,
error_count: data.error_count,
warning_count: data.warning_count,
info_count: data.info_count
});
}
// 更新工具状态
function updateToolsStatus(toolsStatus) {
const agentItems = document.querySelectorAll('.agent-item');
const toolNames = ['pylint', 'flake8', 'bandit'];
agentItems.forEach((item, index) => {
const badge = item.querySelector('.agent-status-badge');
const toolName = toolNames[index];
const status = toolsStatus && toolsStatus[toolName] ? toolsStatus[toolName] : 'error';
badge.className = `agent-status-badge status-${status}`;
switch(status) {
case 'completed':
badge.textContent = '完成';
break;
case 'error':
badge.textContent = '错误';
break;
case 'timeout':
badge.textContent = '超时';
break;
default:
badge.textContent = '空闲';
}
});
}
// 查看问题详情
function viewIssueDetail(rule, message) {
const detailModal = document.createElement('div');
detailModal.className = 'modal';
detailModal.style.display = 'block';
detailModal.innerHTML = `
`;
document.body.appendChild(detailModal);
}
// 显示修复建议
function showFixSuggestion(rule, message) {
const suggestions = {
'B608': '使用参数化查询替代字符串拼接,例如使用 cursor.execute("SELECT * FROM table WHERE id = %s", (user_id,))',
'E501': '将长行拆分为多行,使用括号或反斜杠进行换行',
'C0114': '为函数添加文档字符串,描述函数的功能、参数和返回值',
'W0613': '移除未使用的参数,或使用下划线前缀表示故意未使用的参数',
'default': '请参考相关代码规范文档,确保代码符合军事项目标准'
};
const suggestion = suggestions[rule] || suggestions['default'];
const suggestionModal = document.createElement('div');
suggestionModal.className = 'modal';
suggestionModal.style.display = 'block';
suggestionModal.innerHTML = `
`;
document.body.appendChild(suggestionModal);
}
// 模拟检查函数已被真实的API调用替代
function completeCheck() {
isChecking = false;
startCheckBtn.style.display = 'inline-block';
stopCheckBtn.style.display = 'none';
progressContainer.style.display = 'none';
// 更新 Agent 状态
updateAgentStatus('completed');
// 显示结果区域
resultsSection.style.display = 'block';
}
function showResults() {
resultsSection.style.display = 'block';
// 结果现在通过 processCheckResults 函数处理
}
function displayResults(results) {
resultsContent.innerHTML = '';
if (!results || results.length === 0) {
resultsContent.innerHTML = `
`;
return;
}
// 添加结果摘要
const summaryHtml = createResultsSummary(results);
resultsContent.innerHTML = summaryHtml;
// 添加具体问题列表
const issuesContainer = document.createElement('div');
issuesContainer.style.marginTop = '20px';
results.forEach(result => {
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
// 根据问题类型确定图标和样式
const iconClass = result.type === 'error' ? 'times' :
result.type === 'warning' ? 'exclamation-triangle' : 'info-circle';
// 格式化文件路径,只显示文件名
const fileName = result.file ? result.file.split('/').pop() : '未知文件';
const location = `${fileName}:${result.line}:${result.column || 0}`;
resultItem.innerHTML = `
${result.message || '代码问题'}
规则: ${result.rule || '未知规则'} |
严重程度: ${result.severity || 'medium'}
${result.confidence ? ` | 置信度: ${result.confidence}` : ''}
${location}
`;
issuesContainer.appendChild(resultItem);
});
resultsContent.appendChild(issuesContainer);
}
// 创建结果摘要
function createResultsSummary(results) {
const errorCount = results.filter(r => r.type === 'error').length;
const warningCount = results.filter(r => r.type === 'warning').length;
const infoCount = results.filter(r => r.type === 'info').length;
const totalCount = results.length;
return `
`;
}
// 结果过滤
const filterTabs = document.querySelectorAll('.filter-tab[data-filter]');
filterTabs.forEach(tab => {
tab.addEventListener('click', () => {
filterTabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
const filter = tab.dataset.filter;
filterResults(filter);
});
});
function filterResults(filter) {
const resultItems = document.querySelectorAll('.result-item');
resultItems.forEach(item => {
if (filter === 'all') {
item.style.display = 'flex';
} else {
const icon = item.querySelector('.result-icon');
const hasClass = icon.classList.contains(filter);
item.style.display = hasClass ? 'flex' : 'none';
}
});
}
// 项目管理功能
async function loadProjects() {
try {
const response = await fetch(`${API_BASE_URL}/projects`);
const data = await response.json();
if (data.success) {
projects = data.data;
displayProjects(projects);
} else {
console.error('加载项目失败:', data.error);
// 显示模拟数据
displayMockProjects();
}
} catch (error) {
console.error('加载项目失败:', error);
// 显示模拟数据
displayMockProjects();
}
}
function displayProjects(projects) {
const projectsGrid = document.getElementById('projectsGrid');
if (!projectsGrid) return;
projectsGrid.innerHTML = '';
projects.forEach(project => {
const projectCard = document.createElement('div');
projectCard.className = 'project-card';
projectCard.addEventListener('click', () => showProjectDetail(project));
const statusText = project.status === 'active' ? '进行中' :
project.status === 'completed' ? '已完成' : '待处理';
const latestCheck = project.latest_check;
const totalIssues = latestCheck ? latestCheck.total_issues : 0;
const errorCount = latestCheck ? latestCheck.error_count : 0;
const lastCheckDate = latestCheck && latestCheck.completed_at ?
new Date(latestCheck.completed_at).toLocaleDateString() : '从未检查';
projectCard.innerHTML = `
`;
projectsGrid.appendChild(projectCard);
});
}
function displayMockProjects() {
const mockProjects = [
{
id: 1,
name: '军事指挥系统',
description: '基于Python的军事指挥控制系统,包含用户管理、权限控制、数据加密等模块',
status: 'active',
source_type: 'github',
source_url: 'https://github.com/example/military-command-system.git',
created_at: '2024-01-15T10:30:00Z',
latest_check: {
status: 'completed',
total_issues: 12,
error_count: 3,
warning_count: 7,
info_count: 2,
completed_at: '2024-01-15T14:20:00Z'
}
},
{
id: 2,
name: '安全通信模块',
description: '军用安全通信协议实现,支持端到端加密和身份验证',
status: 'completed',
source_type: 'gitee',
source_url: 'https://gitee.com/example/secure-communication.git',
created_at: '2024-01-14T09:15:00Z',
latest_check: {
status: 'completed',
total_issues: 3,
error_count: 0,
warning_count: 2,
info_count: 1,
completed_at: '2024-01-14T16:45:00Z'
}
},
{
id: 3,
name: '数据分析平台',
description: '军事数据分析和可视化平台,支持实时数据处理和报告生成',
status: 'pending',
source_type: 'upload',
source_url: '',
created_at: '2024-01-13T14:20:00Z',
latest_check: {
status: 'completed',
total_issues: 28,
error_count: 8,
warning_count: 15,
info_count: 5,
completed_at: '2024-01-13T18:30:00Z'
}
}
];
displayProjects(mockProjects);
}
// 项目搜索功能
const projectSearch = document.getElementById('projectSearch');
if (projectSearch) {
projectSearch.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
const filteredProjects = projects.filter(project =>
project.name.toLowerCase().includes(searchTerm) ||
(project.description && project.description.toLowerCase().includes(searchTerm))
);
displayProjects(filteredProjects);
});
}
// 新建项目功能
const createProjectBtn = document.getElementById('createProjectBtn');
const createProjectModal = document.getElementById('createProjectModal');
const cancelCreateProject = document.getElementById('cancelCreateProject');
const confirmCreateProject = document.getElementById('confirmCreateProject');
const closeModal = document.querySelector('.close');
if (createProjectBtn) {
createProjectBtn.addEventListener('click', () => {
createProjectModal.style.display = 'block';
});
}
if (cancelCreateProject) {
cancelCreateProject.addEventListener('click', () => {
createProjectModal.style.display = 'none';
});
}
if (closeModal) {
closeModal.addEventListener('click', () => {
createProjectModal.style.display = 'none';
});
}
// 项目来源类型切换
const sourceTypeRadios = document.querySelectorAll('input[name="source_type"]');
const gitUrlGroup = document.getElementById('gitUrlGroup');
const fileUploadGroup = document.getElementById('fileUploadGroup');
sourceTypeRadios.forEach(radio => {
radio.addEventListener('change', (e) => {
if (e.target.value === 'upload') {
gitUrlGroup.style.display = 'none';
fileUploadGroup.style.display = 'block';
} else {
gitUrlGroup.style.display = 'block';
fileUploadGroup.style.display = 'none';
}
});
});
// 文件上传选择反馈
const fileUploadInput = document.getElementById('fileUpload');
if (fileUploadInput) {
fileUploadInput.addEventListener('change', (e) => {
const files = e.target.files;
if (files.length > 0) {
// 显示选择的文件信息
const fileInfo = document.createElement('div');
fileInfo.className = 'file-info';
fileInfo.style.cssText = `
margin-top: 10px;
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
border-left: 4px solid #28a745;
`;
let fileList = '';
for (let i = 0; i < Math.min(files.length, 5); i++) {
fileList += `• ${files[i].webkitRelativePath || files[i].name}
`;
}
if (files.length > 5) {
fileList += `... 还有 ${files.length - 5} 个文件
`;
}
fileInfo.innerHTML = `
已选择 ${files.length} 个文件
${fileList}
`;
// 移除之前的文件信息
const existingInfo = fileUploadGroup.querySelector('.file-info');
if (existingInfo) {
existingInfo.remove();
}
fileUploadGroup.appendChild(fileInfo);
}
});
}
// 确认创建项目
if (confirmCreateProject) {
confirmCreateProject.addEventListener('click', async () => {
const form = document.getElementById('createProjectForm');
const formData = new FormData(form);
const projectData = {
name: formData.get('name'),
description: formData.get('description'),
source_type: formData.get('source_type'),
source_url: formData.get('source_url')
};
if (!projectData.name) {
alert('请输入项目名称!');
return;
}
if (projectData.source_type !== 'upload' && !projectData.source_url) {
alert('请输入Git URL!');
return;
}
// 检查文件上传
const fileInput = document.getElementById('fileUpload');
const files = fileInput.files;
if (projectData.source_type === 'upload' && files.length === 0) {
alert('请选择要上传的文件或文件夹!');
return;
}
try {
// 第一步:创建项目
const response = await fetch(`${API_BASE_URL}/projects`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(projectData)
});
const data = await response.json();
if (data.success) {
// 第二步:如果是文件上传方式,上传文件到项目
if (projectData.source_type === 'upload' && files.length > 0) {
const uploadFormData = new FormData();
for (let i = 0; i < files.length; i++) {
uploadFormData.append('files', files[i]);
}
const uploadResponse = await fetch(`${API_BASE_URL}/projects/${data.data.id}/upload-files`, {
method: 'POST',
body: uploadFormData
});
const uploadData = await uploadResponse.json();
if (uploadData.success) {
alert(`项目创建成功!已上传 ${uploadData.uploaded_count} 个文件。`);
} else {
alert(`项目创建成功,但文件上传失败:${uploadData.error}`);
}
} else {
alert('项目创建成功!');
}
createProjectModal.style.display = 'none';
form.reset();
loadProjects(); // 重新加载项目列表
} else {
alert('项目创建失败:' + data.error);
}
} catch (error) {
console.error('创建项目失败:', error);
alert('项目创建失败,请检查网络连接!');
}
});
}
// 显示项目详情
function showProjectDetail(project) {
currentProject = project;
// 更新页面标题
document.getElementById('projectDetailTitle').textContent = project.name;
document.getElementById('projectDetailSubtitle').textContent = project.description || '查看项目信息和运行代码检查';
// 显示项目信息
const projectInfoContent = document.getElementById('projectInfoContent');
projectInfoContent.innerHTML = `
${project.name}
${project.description || '暂无描述'}
${project.source_type === 'github' ? 'GitHub' :
project.source_type === 'gitee' ? 'Gitee' : '文件上传'}
${project.source_url || '无'}
${new Date(project.created_at).toLocaleString()}
${project.status === 'active' ? '进行中' :
project.status === 'completed' ? '已完成' : '待处理'}
`;
// 显示检查历史
displayCheckHistory(project);
// 加载文件浏览器
loadProjectFiles();
// 切换到项目详情页面
showPage('project-detail');
}
// 显示检查历史
function displayCheckHistory(project) {
const checkHistoryContent = document.getElementById('checkHistoryContent');
// 模拟检查历史数据
const mockChecks = [
{
id: 1,
check_type: 'combined',
status: 'completed',
started_at: '2024-01-15T14:20:00Z',
completed_at: '2024-01-15T14:25:00Z',
total_issues: 12,
error_count: 3,
warning_count: 7,
info_count: 2
},
{
id: 2,
check_type: 'combined',
status: 'completed',
started_at: '2024-01-14T10:15:00Z',
completed_at: '2024-01-14T10:20:00Z',
total_issues: 15,
error_count: 5,
warning_count: 8,
info_count: 2
}
];
checkHistoryContent.innerHTML = '';
mockChecks.forEach(check => {
const checkItem = document.createElement('div');
checkItem.className = 'check-history-item';
checkItem.innerHTML = `
${check.check_type} 检查
${new Date(check.started_at).toLocaleString()} -
发现问题: ${check.total_issues} (错误: ${check.error_count}, 警告: ${check.warning_count})
`;
checkHistoryContent.appendChild(checkItem);
});
}
// 运行项目检查
async function runProjectCheck(projectId) {
try {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/check`, {
method: 'POST'
});
const data = await response.json();
if (data.success) {
alert('检查已开始,请稍候查看结果!');
// 刷新项目详情
if (currentProject && currentProject.id === projectId) {
showProjectDetail(currentProject);
}
} else {
alert('检查启动失败:' + data.error);
}
} catch (error) {
console.error('运行检查失败:', error);
alert('检查启动失败,请检查网络连接!');
}
}
// 删除项目
async function deleteProject(projectId, projectName) {
// 显示确认对话框
showDeleteConfirmDialog(projectId, projectName);
}
// 显示删除确认对话框
function showDeleteConfirmDialog(projectId, projectName) {
const confirmModal = document.createElement('div');
confirmModal.className = 'modal';
confirmModal.style.display = 'block';
confirmModal.innerHTML = `
确定要删除项目吗?
"${projectName}"
此操作将删除:
- 项目信息和配置
- 所有检查历史记录
- 所有检查结果数据
- 项目本地文件
`;
document.body.appendChild(confirmModal);
}
// 确认删除项目
async function confirmDeleteProject(projectId, projectName) {
try {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}`, {
method: 'DELETE'
});
const data = await response.json();
if (data.success) {
// 显示成功消息
showSuccessMessage('项目删除成功!');
// 重新加载项目列表
loadProjects();
// 如果当前查看的是被删除的项目,返回项目列表页面
if (currentProject && currentProject.id === projectId) {
showPage('projects');
}
} else {
showErrorMessage('项目删除失败:' + data.error);
}
} catch (error) {
console.error('删除项目失败:', error);
showErrorMessage('删除项目失败,请检查网络连接!');
}
}
// 显示成功消息
function showSuccessMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
border-radius: 6px;
padding: 15px 20px;
z-index: 3000;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: flex;
align-items: center;
gap: 10px;
`;
messageDiv.innerHTML = `
${message}
`;
document.body.appendChild(messageDiv);
setTimeout(() => {
messageDiv.remove();
}, 3000);
}
// 显示错误消息
function showErrorMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
border-radius: 6px;
padding: 15px 20px;
z-index: 3000;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: flex;
align-items: center;
gap: 10px;
`;
messageDiv.innerHTML = `
${message}
`;
document.body.appendChild(messageDiv);
setTimeout(() => {
messageDiv.remove();
}, 5000);
}
// 查看检查结果
function viewCheckResults(checkId) {
// 模拟检查结果数据
const mockResults = [
{
id: 1,
file_path: 'src/database.py',
line_number: 45,
column_number: 12,
issue_type: 'error',
severity: 'high',
rule_id: 'B608',
message: 'SQL注入风险:使用字符串拼接构建SQL查询',
suggestion: '建议使用参数化查询或ORM'
},
{
id: 2,
file_path: 'src/utils.py',
line_number: 23,
column_number: 1,
issue_type: 'warning',
severity: 'medium',
rule_id: 'E501',
message: '行长度超过120字符限制',
suggestion: '建议将长行拆分为多行'
}
];
const checkResultsContent = document.getElementById('checkResultsContent');
checkResultsContent.innerHTML = '';
mockResults.forEach(result => {
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
${result.message}
${result.suggestion}
${result.file_path}:${result.line_number}:${result.column_number}
`;
checkResultsContent.appendChild(resultItem);
});
// 显示检查结果面板
document.getElementById('checkResultsPanel').style.display = 'block';
}
// 返回项目列表
const backToProjectsBtn = document.getElementById('backToProjectsBtn');
if (backToProjectsBtn) {
backToProjectsBtn.addEventListener('click', () => {
showPage('projects');
});
}
// 运行检查按钮
const runCheckBtn = document.getElementById('runCheckBtn');
if (runCheckBtn) {
runCheckBtn.addEventListener('click', () => {
if (currentProject) {
runProjectCheck(currentProject.id);
}
});
}
// 删除项目按钮
const deleteProjectBtn = document.getElementById('deleteProjectBtn');
if (deleteProjectBtn) {
deleteProjectBtn.addEventListener('click', () => {
if (currentProject) {
deleteProject(currentProject.id, currentProject.name);
}
});
}
// 仪表板数据加载
function loadDashboardData() {
// 这里可以加载真实的统计数据
// 目前使用模拟数据
console.log('加载仪表板数据');
}
// 文件浏览器相关变量
let currentFilePath = '';
let currentFileContent = '';
let isFileModified = false;
// 加载项目文件
async function loadProjectFiles(path = '') {
if (!currentProject) return;
try {
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files?path=${encodeURIComponent(path)}`);
const data = await response.json();
if (data.success) {
displayFileTree(data.data);
updateCurrentPath(path);
} else {
showErrorMessage('加载文件列表失败:' + data.error);
}
} catch (error) {
console.error('加载文件列表失败:', error);
showErrorMessage('加载文件列表失败,请检查网络连接!');
}
}
// 显示文件树
function displayFileTree(files) {
const fileTree = document.getElementById('fileTree');
fileTree.innerHTML = '';
if (files.length === 0) {
fileTree.innerHTML = '此目录为空
';
return;
}
files.forEach(file => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
fileItem.onclick = () => handleFileClick(file);
const iconClass = getFileIconClass(file.name, file.is_directory);
fileItem.innerHTML = `
${file.name}
${file.is_directory ? '' : formatFileSize(file.size)}
`;
fileTree.appendChild(fileItem);
});
}
// 获取文件图标类
function getFileIconClass(fileName, isDirectory) {
if (isDirectory) return 'folder';
const ext = fileName.split('.').pop().toLowerCase();
switch (ext) {
case 'py': return 'python';
case 'js': return 'js';
case 'css': return 'css';
case 'html': case 'htm': return 'html';
default: return 'file';
}
}
// 格式化文件大小
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(1)) + ' ' + sizes[i];
}
// 处理文件点击
function handleFileClick(file) {
if (file.is_directory) {
// 如果是目录,进入目录
loadProjectFiles(file.path);
} else {
// 如果是文件,打开文件
openFile(file.path);
}
}
// 打开文件
async function openFile(filePath) {
if (!currentProject) return;
try {
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files/content?path=${encodeURIComponent(filePath)}`);
const data = await response.json();
if (data.success) {
currentFilePath = filePath;
currentFileContent = data.data.content;
isFileModified = false;
// 显示代码编辑器
showCodeEditor(filePath, data.data.content);
} else {
showErrorMessage('打开文件失败:' + data.error);
}
} catch (error) {
console.error('打开文件失败:', error);
showErrorMessage('打开文件失败,请检查网络连接!');
}
}
// 显示代码编辑器
function showCodeEditor(filePath, content) {
const editorPanel = document.getElementById('codeEditorPanel');
const editor = document.getElementById('codeEditor');
const editorTitle = document.getElementById('editorTitle');
const currentFilePathSpan = document.getElementById('currentFilePath');
editor.value = content;
editorTitle.textContent = `编辑文件 - ${filePath.split('/').pop()}`;
currentFilePathSpan.textContent = filePath;
editorPanel.style.display = 'block';
// 监听内容变化
editor.oninput = () => {
isFileModified = true;
};
}
// 更新当前路径显示
function updateCurrentPath(path) {
const currentPathSpan = document.getElementById('currentPath');
currentPathSpan.textContent = path || '/';
}
// 保存文件
async function saveFile() {
if (!currentProject || !currentFilePath) return;
const editor = document.getElementById('codeEditor');
const content = editor.value;
try {
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files/content`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
path: currentFilePath,
content: content
})
});
const data = await response.json();
if (data.success) {
isFileModified = false;
showSuccessMessage('文件保存成功!');
} else {
showErrorMessage('保存文件失败:' + data.error);
}
} catch (error) {
console.error('保存文件失败:', error);
showErrorMessage('保存文件失败,请检查网络连接!');
}
}
// 关闭编辑器
function closeEditor() {
if (isFileModified) {
const confirmed = confirm('文件已修改,确定要关闭吗?未保存的更改将丢失。');
if (!confirmed) return;
}
const editorPanel = document.getElementById('codeEditorPanel');
editorPanel.style.display = 'none';
currentFilePath = '';
currentFileContent = '';
isFileModified = false;
}
// 页面加载动画
document.addEventListener('DOMContentLoaded', () => {
const fadeElements = document.querySelectorAll('.fade-in');
fadeElements.forEach((element, index) => {
setTimeout(() => {
element.style.opacity = '1';
element.style.transform = 'translateY(0)';
}, index * 200);
});
// 默认显示仪表板页面
showPage('dashboard');
// 初始化各个页面
loadProjects();
// 绑定文件浏览器事件
bindFileBrowserEvents();
});
// 绑定文件浏览器事件
function bindFileBrowserEvents() {
// 保存文件按钮
const saveFileBtn = document.getElementById('saveFileBtn');
if (saveFileBtn) {
saveFileBtn.addEventListener('click', saveFile);
}
// 关闭编辑器按钮
const closeEditorBtn = document.getElementById('closeEditorBtn');
if (closeEditorBtn) {
closeEditorBtn.addEventListener('click', closeEditor);
}
// 上传文件按钮
const uploadFileBtn = document.getElementById('uploadFileBtn');
if (uploadFileBtn) {
uploadFileBtn.addEventListener('click', showUploadDialog);
}
// 新建文件按钮
const createFileBtn = document.getElementById('createFileBtn');
if (createFileBtn) {
createFileBtn.addEventListener('click', showCreateFileDialog);
}
// 新建文件夹按钮
const createFolderBtn = document.getElementById('createFolderBtn');
if (createFolderBtn) {
createFolderBtn.addEventListener('click', showCreateFolderDialog);
}
// 键盘快捷键
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
if (currentFilePath) {
saveFile();
}
}
});
}
// 显示上传文件对话框
function showUploadDialog() {
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.onchange = (e) => {
const files = Array.from(e.target.files);
if (files.length > 0) {
uploadProjectFiles(files);
}
};
input.click();
}
// 上传文件到项目
async function uploadProjectFiles(files) {
if (!currentProject) return;
const currentPath = document.getElementById('currentPath').textContent;
const targetPath = currentPath === '/' ? '' : currentPath;
for (const file of files) {
const formData = new FormData();
formData.append('file', file);
formData.append('path', targetPath);
try {
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files/upload`, {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
showSuccessMessage(`文件 ${file.name} 上传成功!`);
} else {
showErrorMessage(`文件 ${file.name} 上传失败:${data.error}`);
}
} catch (error) {
console.error('上传文件失败:', error);
showErrorMessage(`文件 ${file.name} 上传失败,请检查网络连接!`);
}
}
// 刷新文件列表
loadProjectFiles(targetPath);
}
// 显示新建文件对话框
function showCreateFileDialog() {
const fileName = prompt('请输入文件名(包含扩展名):');
if (fileName) {
createFile(fileName);
}
}
// 创建文件
async function createFile(fileName) {
if (!currentProject) return;
const currentPath = document.getElementById('currentPath').textContent;
const filePath = currentPath === '/' ? fileName : `${currentPath}/${fileName}`;
try {
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files/content`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
path: filePath,
content: ''
})
});
const data = await response.json();
if (data.success) {
showSuccessMessage('文件创建成功!');
loadProjectFiles(currentPath);
} else {
showErrorMessage('文件创建失败:' + data.error);
}
} catch (error) {
console.error('创建文件失败:', error);
showErrorMessage('创建文件失败,请检查网络连接!');
}
}
// 显示新建文件夹对话框
function showCreateFolderDialog() {
const folderName = prompt('请输入文件夹名称:');
if (folderName) {
createFolder(folderName);
}
}
// 创建文件夹
async function createFolder(folderName) {
if (!currentProject) return;
const currentPath = document.getElementById('currentPath').textContent;
const folderPath = currentPath === '/' ? folderName : `${currentPath}/${folderName}`;
try {
// 通过创建一个隐藏文件来创建文件夹
const response = await fetch(`${API_BASE_URL}/projects/${currentProject.id}/files/content`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
path: `${folderPath}/.gitkeep`,
content: ''
})
});
const data = await response.json();
if (data.success) {
showSuccessMessage('文件夹创建成功!');
loadProjectFiles(currentPath);
} else {
showErrorMessage('文件夹创建失败:' + data.error);
}
} catch (error) {
console.error('创建文件夹失败:', error);
showErrorMessage('创建文件夹失败,请检查网络连接!');
}
}
// 通知功能
const notification = document.querySelector('.notification');
if (notification) {
notification.addEventListener('click', () => {
alert('您有 3 条新通知:\n1. 检查任务已完成\n2. 发现 5 个高危漏洞\n3. 系统维护通知');
});
}
// 点击模态框外部关闭
window.addEventListener('click', (e) => {
const modal = document.getElementById('createProjectModal');
if (e.target === modal) {
modal.style.display = 'none';
}
});