合并部分前端和后端 #2

Merged
pu8crm6xf merged 2 commits from guoning into main 2 months ago

51
src/.gitignore vendored

@ -0,0 +1,51 @@
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# 项目特定
projects_data/
out/
*.log
# 临时文件
*.tmp
*.temp
temp_*.py
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# 环境变量
.env
.env.local

@ -0,0 +1,267 @@
# FortifyCode - 基于多Agent协同的军工Python代码合规性检查系统
## 项目简介
FortifyCode 是一个集成了多个代码质量检查工具Pylint、Flake8、Bandit的 Web 应用,专为军工 Python 代码合规性检查而设计。
## 功能特性
- ✅ **多工具协同检查**:整合 Pylint、Flake8、Bandit 三大代码检查工具
- ✅ **可视化界面**:直观的 Web 界面,实时显示检查进度和结果
- ✅ **项目管理**:支持创建、管理多个代码检查项目
- ✅ **文件浏览器**:在线浏览和编辑项目文件
- ✅ **智能分类**:自动分类错误、警告和信息级别的问题
- ✅ **多种来源**:支持 GitHub、Gitee 克隆或直接文件上传
## 技术栈
### 前端
- HTML5 + CSS3 + JavaScript (原生)
- Font Awesome 图标库
- 响应式设计
### 后端
- Node.js + Express
- Multer (文件上传)
- CORS (跨域支持)
### 代码检查工具
- **Pylint**: Python 代码质量和风格检查
- **Flake8**: PEP 8 编码规范检查
- **Bandit**: 安全漏洞扫描
## 系统要求
- Node.js >= 14.0
- Python >= 3.7
- npm 或 yarn 包管理器
## 安装步骤
### 1. 克隆项目
```bash
git clone <repository-url>
cd FortifyCode_guoning/src
```
### 2. 安装 Node.js 依赖
```bash
npm install
```
### 3. 安装 Python 检查工具
```bash
pip install pylint flake8 bandit
```
或者使用 requirements.txt如果提供
```bash
pip install -r requirements.txt
```
## 运行项目
### Windows 系统
双击运行 `start_server.bat` 或在命令行中执行:
```cmd
start_server.bat
```
### Linux/Mac 系统
```bash
chmod +x start_server.sh
./start_server.sh
```
### 手动启动
```bash
node backend.js
```
## 访问系统
启动成功后,在浏览器中访问:
- **前端界面**: http://localhost:5000
- **API 接口**: http://localhost:5000/api
## 使用说明
### 快捷代码检查
1. 点击上传区域或拖拽 Python 文件(.py, .pyx, .pyi
2. 点击"开始检查"按钮
3. 等待检查完成,查看结果
### 项目管理
1. 进入"项目管理"页面
2. 点击"新建项目"
3. 选择项目来源GitHub、Gitee 或文件上传)
4. 填写项目信息并创建
5. 在项目详情页面进行代码检查和文件管理
### 查看检查结果
检查完成后,结果会显示在页面下方,包括:
- 问题总数统计
- 错误、警告、信息分类
- 具体问题位置(文件、行号、列号)
- 问题描述和修复建议
## API 接口文档
### 文件上传
```
POST /api/upload
Content-Type: multipart/form-data
参数:
- files: 文件数组
响应:
{
"success": true,
"data": {
"temp_path": "临时目录路径",
"files": ["文件列表"]
}
}
```
### 代码检查
```
POST /api/check
Content-Type: application/json
参数:
{
"temp_path": "临时目录路径"
}
响应:
{
"success": true,
"data": {
"tools_status": {...},
"all_issues": [...],
"total_issues": 数量,
"error_count": 数量,
"warning_count": 数量,
"info_count": 数量
}
}
```
### 项目管理
```
GET /api/projects - 获取所有项目
POST /api/projects - 创建新项目
GET /api/projects/:id - 获取项目详情
DELETE /api/projects/:id - 删除项目
POST /api/projects/:id/check - 运行项目检查
```
更多 API 详情请查看 `view/API.md`
## 项目结构
```
src/
├── backend.js # 后端服务器主文件
├── frontend/ # 前端文件
│ ├── index.html # 主页面
│ ├── css/
│ │ └── style.css # 样式文件
│ └── js/
│ └── app.js # 前端逻辑
├── projects_data/ # 项目数据存储目录(自动创建)
├── out/ # 检查报告输出目录
├── start_server.bat # Windows 启动脚本
├── start_server.sh # Linux/Mac 启动脚本
├── package.json # Node.js 依赖配置
└── README.md # 本文档
```
## 常见问题
### Q: 提示找不到 Python 模块?
A: 确保已正确安装 pylint、flake8 和 bandit
```bash
pip install pylint flake8 bandit
```
### Q: 端口 5000 被占用?
A: 修改 `backend.js` 中的 PORT 变量,或设置环境变量:
```bash
PORT=8080 node backend.js
```
### Q: 文件上传失败?
A: 检查以下几点:
- 文件大小不超过 100MB
- 文件格式为 .py, .pyx, .pyi
- 临时目录有写入权限
### Q: 检查工具报错?
A: 确保 Python 和检查工具在系统 PATH 中:
```bash
python -m pylint --version
python -m flake8 --version
python -m bandit --version
```
## 开发说明
### 修改端口
编辑 `backend.js`
```javascript
const PORT = process.env.PORT || 5000; // 修改为其他端口
```
### 添加新的检查工具
`backend.js``TOOL_CONFIG` 中添加配置:
```javascript
newtool: {
command: '命令',
args: (filePath) => `参数 ${filePath}`,
parseResult: (stdout) => {
// 解析逻辑
return issues;
}
}
```
## 贡献指南
欢迎提交 Issue 和 Pull Request
## 许可证
本项目采用 MIT 许可证。
## 联系方式
如有问题或建议,请联系项目维护者。
---
**注意**: 本系统用于代码质量检查,不应替代人工代码审查。建议结合实际项目需求和编码规范使用。

@ -0,0 +1,751 @@
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const { exec } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
// 创建Express应用
const app = express();
const PORT = process.env.PORT || 5000;
// 配置CORS
app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
// 解析JSON请求体
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 请求日志中间件
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
});
// 配置Multer文件上传
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const tempDir = path.join(os.tmpdir(), 'fortifycode_uploads');
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir, { recursive: true });
}
cb(null, tempDir);
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 100 * 1024 * 1024 }, // 100MB
fileFilter: (req, file, cb) => {
if (file.originalname.match(/\.(py|pyx|pyi)$/)) {
cb(null, true);
} else {
cb(new Error('只支持 Python 文件 (.py, .pyx, .pyi)'));
}
}
});
// 项目存储目录
const PROJECTS_DIR = path.join(__dirname, 'projects_data');
if (!fs.existsSync(PROJECTS_DIR)) {
fs.mkdirSync(PROJECTS_DIR, { recursive: true });
}
// 项目数据存储(简化版,生产环境应使用数据库)
let projects = [];
const PROJECTS_FILE = path.join(PROJECTS_DIR, 'projects.json');
// 加载项目数据
function loadProjects() {
try {
if (fs.existsSync(PROJECTS_FILE)) {
const data = fs.readFileSync(PROJECTS_FILE, 'utf8');
projects = JSON.parse(data);
console.log(`加载了 ${projects.length} 个项目`);
}
} catch (error) {
console.error('加载项目数据失败:', error);
projects = [];
}
}
// 保存项目数据
function saveProjects() {
try {
fs.writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2));
} catch (error) {
console.error('保存项目数据失败:', error);
}
}
// 初始化
loadProjects();
// 工具配置
const TOOL_CONFIG = {
bandit: {
command: 'python',
args: (filePath) => `-m bandit -r -f json ${filePath}`,
parseResult: (stdout) => {
try {
if (!stdout || stdout.trim() === '') return [];
const result = JSON.parse(stdout);
return (result.results || []).map(item => ({
file: item.filename,
line: item.line_number,
column: 0,
rule: item.test_id,
message: item.issue_text,
severity: item.issue_severity.toLowerCase(),
confidence: item.issue_confidence.toLowerCase(),
type: item.issue_severity === 'HIGH' ? 'error' : 'warning'
}));
} catch (e) {
console.error('Bandit解析失败:', e);
return [];
}
}
},
flake8: {
command: 'python',
args: (filePath) => `-m flake8 ${filePath}`,
parseResult: (stdout) => {
try {
if (!stdout || stdout.trim() === '') return [];
const lines = stdout.trim().split('\n').filter(line => line.trim());
const issues = [];
for (const line of lines) {
const match = line.match(/^(.+?):(\d+):(\d+):\s*([A-Z]\d+)\s*(.+)$/);
if (match) {
const code = match[4];
issues.push({
file: match[1],
line: parseInt(match[2]),
column: parseInt(match[3]),
rule: code,
message: match[5],
severity: code.startsWith('E') ? 'high' : 'medium',
type: code.startsWith('E') ? 'error' : 'warning'
});
}
}
return issues;
} catch (e) {
console.error('Flake8解析失败:', e);
return [];
}
}
},
pylint: {
command: 'python',
args: (filePath) => `-m pylint --output-format=json ${filePath}`,
parseResult: (stdout) => {
try {
if (!stdout || stdout.trim() === '') return [];
const result = JSON.parse(stdout);
return result.map(item => ({
file: item.path,
line: item.line,
column: item.column,
rule: item.symbol,
message: item.message,
severity: item.type === 'error' ? 'high' : item.type === 'warning' ? 'medium' : 'low',
type: item.type === 'error' ? 'error' : item.type === 'warning' ? 'warning' : 'info'
}));
} catch (e) {
console.error('Pylint解析失败:', e);
return [];
}
}
}
};
// 运行单个工具检查
async function runTool(tool, filePath) {
return new Promise((resolve) => {
const config = TOOL_CONFIG[tool];
if (!config) {
return resolve({ status: 'error', issues: [] });
}
const command = `${config.command} ${config.args(filePath)}`;
console.log(`执行命令: ${command}`);
exec(command, { shell: true, timeout: 60000 }, (error, stdout, stderr) => {
console.log(`${tool} 执行完成`);
try {
const issues = config.parseResult(stdout || '');
resolve({
status: 'completed',
issues: issues,
raw_output: stdout
});
} catch (e) {
console.error(`${tool} 处理结果失败:`, e);
resolve({
status: 'error',
issues: [],
error: e.message
});
}
});
});
}
// 运行代码检查
async function runCodeCheck(filePath) {
const tools = ['pylint', 'flake8', 'bandit'];
const toolsStatus = {};
const allIssues = [];
for (const tool of tools) {
try {
const result = await runTool(tool, filePath);
toolsStatus[tool] = result.status;
allIssues.push(...result.issues);
} catch (error) {
console.error(`${tool} 执行失败:`, error);
toolsStatus[tool] = 'error';
}
}
// 统计问题
const errorCount = allIssues.filter(i => i.type === 'error').length;
const warningCount = allIssues.filter(i => i.type === 'warning').length;
const infoCount = allIssues.filter(i => i.type === 'info').length;
return {
tools_status: toolsStatus,
all_issues: allIssues,
total_issues: allIssues.length,
error_count: errorCount,
warning_count: warningCount,
info_count: infoCount
};
}
// ==================== API 端点 ====================
// 健康检查
app.get('/api/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString()
});
});
// 文件上传端点
app.post('/api/upload', upload.array('files'), (req, res) => {
try {
if (!req.files || req.files.length === 0) {
return res.status(400).json({
success: false,
error: '没有上传文件'
});
}
// 创建临时目录
const tempDir = path.join(os.tmpdir(), `fortifycode_${Date.now()}`);
fs.mkdirSync(tempDir, { recursive: true });
// 复制文件到临时目录
req.files.forEach(file => {
const targetPath = path.join(tempDir, file.originalname);
fs.copyFileSync(file.path, targetPath);
// 删除原始上传文件
fs.unlinkSync(file.path);
});
res.json({
success: true,
data: {
temp_path: tempDir,
files: req.files.map(f => f.originalname)
}
});
} catch (error) {
console.error('文件上传失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 代码检查端点
app.post('/api/check', async (req, res) => {
try {
const { temp_path } = req.body;
if (!temp_path || !fs.existsSync(temp_path)) {
return res.status(400).json({
success: false,
error: '无效的临时路径'
});
}
// 获取所有Python文件
const files = fs.readdirSync(temp_path).filter(f => f.endsWith('.py'));
if (files.length === 0) {
return res.json({
success: true,
data: {
tools_status: { pylint: 'completed', flake8: 'completed', bandit: 'completed' },
all_issues: [],
total_issues: 0,
error_count: 0,
warning_count: 0,
info_count: 0
}
});
}
// 检查第一个文件(简化版,可以扩展为检查所有文件)
const firstFile = path.join(temp_path, files[0]);
const result = await runCodeCheck(firstFile);
// 清理临时文件
setTimeout(() => {
try {
fs.rmSync(temp_path, { recursive: true, force: true });
} catch (e) {
console.error('清理临时文件失败:', e);
}
}, 5000);
res.json({
success: true,
data: result
});
} catch (error) {
console.error('代码检查失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 获取所有项目
app.get('/api/projects', (req, res) => {
res.json({
success: true,
data: projects
});
});
// 创建新项目
app.post('/api/projects', (req, res) => {
try {
const { name, description, source_type, source_url } = req.body;
if (!name) {
return res.status(400).json({
success: false,
error: '项目名称不能为空'
});
}
const project = {
id: Date.now(),
name,
description: description || '',
source_type: source_type || 'upload',
source_url: source_url || '',
status: 'pending',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
latest_check: null
};
// 创建项目目录
const projectDir = path.join(PROJECTS_DIR, `project_${project.id}`);
fs.mkdirSync(projectDir, { recursive: true });
project.path = projectDir;
projects.push(project);
saveProjects();
res.json({
success: true,
data: project
});
} catch (error) {
console.error('创建项目失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 获取项目详情
app.get('/api/projects/:id', (req, res) => {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
res.json({
success: true,
data: project
});
});
// 删除项目
app.delete('/api/projects/:id', (req, res) => {
try {
const projectId = parseInt(req.params.id);
const projectIndex = projects.findIndex(p => p.id === projectId);
if (projectIndex === -1) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
const project = projects[projectIndex];
// 删除项目目录
if (project.path && fs.existsSync(project.path)) {
fs.rmSync(project.path, { recursive: true, force: true });
}
// 从列表中删除
projects.splice(projectIndex, 1);
saveProjects();
res.json({
success: true,
message: '项目删除成功'
});
} catch (error) {
console.error('删除项目失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 运行项目检查
app.post('/api/projects/:id/check', async (req, res) => {
try {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
// 获取项目中的所有Python文件
const projectPath = project.path;
const files = [];
function getAllPythonFiles(dir) {
const items = fs.readdirSync(dir);
items.forEach(item => {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
getAllPythonFiles(fullPath);
} else if (item.endsWith('.py')) {
files.push(fullPath);
}
});
}
getAllPythonFiles(projectPath);
if (files.length === 0) {
return res.json({
success: true,
data: {
check_id: Date.now(),
status: 'completed',
total_issues: 0,
message: '项目中没有Python文件'
}
});
}
// 检查第一个文件作为示例
const result = await runCodeCheck(files[0]);
// 更新项目的最新检查记录
project.latest_check = {
id: Date.now(),
status: 'completed',
started_at: new Date().toISOString(),
completed_at: new Date().toISOString(),
total_issues: result.total_issues,
error_count: result.error_count,
warning_count: result.warning_count,
info_count: result.info_count
};
project.status = 'completed';
project.updated_at = new Date().toISOString();
saveProjects();
res.json({
success: true,
data: {
check_id: project.latest_check.id,
...result
}
});
} catch (error) {
console.error('项目检查失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 上传文件到项目
app.post('/api/projects/:id/upload-files', upload.array('files'), (req, res) => {
try {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
if (!req.files || req.files.length === 0) {
return res.status(400).json({
success: false,
error: '没有上传文件'
});
}
// 复制文件到项目目录
let uploadedCount = 0;
req.files.forEach(file => {
const targetPath = path.join(project.path, file.originalname);
fs.copyFileSync(file.path, targetPath);
fs.unlinkSync(file.path);
uploadedCount++;
});
project.updated_at = new Date().toISOString();
saveProjects();
res.json({
success: true,
uploaded_count: uploadedCount
});
} catch (error) {
console.error('文件上传失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 获取项目文件列表
app.get('/api/projects/:id/files', (req, res) => {
try {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
const targetPath = req.query.path || '';
const fullPath = path.join(project.path, targetPath);
if (!fs.existsSync(fullPath)) {
return res.json({
success: true,
data: []
});
}
const items = fs.readdirSync(fullPath);
const files = items.map(item => {
const itemPath = path.join(fullPath, item);
const stat = fs.statSync(itemPath);
return {
name: item,
path: path.join(targetPath, item),
is_directory: stat.isDirectory(),
size: stat.size,
modified_at: stat.mtime.toISOString()
};
});
res.json({
success: true,
data: files
});
} catch (error) {
console.error('获取文件列表失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 获取文件内容
app.get('/api/projects/:id/files/content', (req, res) => {
try {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
const filePath = req.query.path;
if (!filePath) {
return res.status(400).json({
success: false,
error: '文件路径不能为空'
});
}
const fullPath = path.join(project.path, filePath);
if (!fs.existsSync(fullPath)) {
return res.status(404).json({
success: false,
error: '文件不存在'
});
}
const content = fs.readFileSync(fullPath, 'utf8');
res.json({
success: true,
data: {
path: filePath,
content: content
}
});
} catch (error) {
console.error('读取文件失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 保存文件内容
app.put('/api/projects/:id/files/content', (req, res) => {
try {
const projectId = parseInt(req.params.id);
const project = projects.find(p => p.id === projectId);
if (!project) {
return res.status(404).json({
success: false,
error: '项目不存在'
});
}
const { path: filePath, content } = req.body;
if (!filePath) {
return res.status(400).json({
success: false,
error: '文件路径不能为空'
});
}
const fullPath = path.join(project.path, filePath);
const dirPath = path.dirname(fullPath);
// 确保目录存在
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
fs.writeFileSync(fullPath, content || '');
res.json({
success: true,
message: '文件保存成功'
});
} catch (error) {
console.error('保存文件失败:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// 静态文件服务 - 前端
app.use(express.static(path.join(__dirname, 'frontend')));
// 默认路由 - 返回前端页面
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'frontend', 'index.html'));
});
// 404处理
app.use((req, res) => {
res.status(404).json({
success: false,
error: '接口不存在'
});
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error('服务器错误:', err);
res.status(500).json({
success: false,
error: err.message || '服务器内部错误'
});
});
// 启动服务器
app.listen(PORT, () => {
console.log('=================================');
console.log('FortifyCode 后端服务器已启动');
console.log(`服务器地址: http://localhost:${PORT}`);
console.log(`API 地址: http://localhost:${PORT}/api`);
console.log(`前端地址: http://localhost:${PORT}`);
console.log(`项目数据目录: ${PROJECTS_DIR}`);
console.log('=================================');
});
module.exports = app;

File diff suppressed because it is too large Load Diff

@ -0,0 +1,361 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>基于多agent协同的军工Python代码合规性检查系统 - FortifyCode</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- 顶部导航栏 -->
<nav class="navbar">
<div class="navbar-content">
<div class="logo">
<i class="fas fa-shield-alt"></i>
FortifyCode
</div>
<ul class="nav-menu">
<li><a href="#dashboard" class="nav-link active">仪表板</a></li>
<li><a href="#projects" class="nav-link">项目管理</a></li>
<li><a href="#rules" class="nav-link">规则集管理</a></li>
<li><a href="#settings" class="nav-link">配置中心</a></li>
</ul>
<div class="user-info">
<div class="notification">
<i class="fas fa-bell"></i>
<span class="notification-badge">3</span>
</div>
<div class="user-avatar">
<i class="fas fa-user-circle" style="font-size: 24px;"></i>
</div>
</div>
</div>
</nav>
<!-- 主内容区域 -->
<div class="main-content">
<!-- 仪表板页面 -->
<div id="dashboard-page" class="page-content active">
<!-- 页面标题 -->
<div class="page-header fade-in">
<h1 class="page-title">基于多agent协同的军工Python代码合规性检查系统</h1>
<p class="page-subtitle">基于多 Agent 协同的智能代码安全检测平台</p>
</div>
<!-- 统计卡片 -->
<div class="stats-grid fade-in">
<div class="stat-card">
<div class="stat-icon primary">
<i class="fas fa-code"></i>
</div>
<div class="stat-content">
<h3 id="totalFiles">1,247</h3>
<p>已检查文件</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon success">
<i class="fas fa-check-circle"></i>
</div>
<div class="stat-content">
<h3 id="complianceRate">98.5%</h3>
<p>合规率</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon warning">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div class="stat-content">
<h3 id="pendingIssues">23</h3>
<p>待修复问题</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon danger">
<i class="fas fa-bug"></i>
</div>
<div class="stat-content">
<h3 id="highRiskIssues">5</h3>
<p>高危漏洞</p>
</div>
</div>
</div>
<!-- 功能区域 -->
<div class="function-grid fade-in">
<!-- 代码上传和检查区域 -->
<div class="main-panel">
<div class="panel-header">
<h2 class="panel-title">快捷代码检查</h2>
<div class="filter-tabs">
<span class="filter-tab active">Python</span>
</div>
</div>
<div class="panel-content">
<div class="upload-area" id="uploadArea">
<div class="upload-icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<div class="upload-text">拖拽文件到此处或点击上传</div>
<div class="upload-hint">支持 .py, .pyx, .pyi 文件,最大 100MB</div>
<input type="file" class="file-input" id="fileInput" multiple accept=".py,.pyx,.pyi">
</div>
<div class="progress-container" id="progressContainer" style="display: none;">
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width: 0%;"></div>
</div>
<div class="progress-text" id="progressText">准备检查...</div>
</div>
<div style="margin-top: 20px; text-align: center;">
<button class="btn btn-primary" id="startCheckBtn" style="display: none;">
<i class="fas fa-play"></i> 开始检查
</button>
<button class="btn btn-secondary" id="stopCheckBtn" style="display: none;">
<i class="fas fa-stop"></i> 停止检查
</button>
</div>
</div>
</div>
<!-- 多Agent状态面板 -->
<div class="agent-status">
<div class="panel-header">
<h2 class="panel-title">Agent 状态</h2>
</div>
<div class="agent-list">
<div class="agent-item">
<div class="agent-avatar">A1</div>
<div class="agent-info">
<div class="agent-name">pylint Agent</div>
<span class="agent-status-badge status-idle">空闲</span>
</div>
</div>
<div class="agent-item">
<div class="agent-avatar">A2</div>
<div class="agent-info">
<div class="agent-name">flake8 Agent</div>
<span class="agent-status-badge status-idle">空闲</span>
</div>
</div>
<div class="agent-item">
<div class="agent-avatar">A3</div>
<div class="agent-info">
<div class="agent-name">bandit Agent</div>
<span class="agent-status-badge status-idle">空闲</span>
</div>
</div>
</div>
</div>
</div>
<!-- 检查结果区域 -->
<div class="results-section fade-in" id="resultsSection" style="display: none;">
<div class="results-header">
<h2 class="results-title">检查结果</h2>
<div class="filter-tabs">
<span class="filter-tab active" data-filter="all">全部</span>
<span class="filter-tab" data-filter="error">错误</span>
<span class="filter-tab" data-filter="warning">警告</span>
<span class="filter-tab" data-filter="info">信息</span>
</div>
</div>
<div class="results-content" id="resultsContent">
<!-- 结果项将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
<!-- 项目管理页面 -->
<div id="projects-page" class="page-content">
<div class="page-header fade-in">
<h1 class="page-title">项目管理</h1>
<p class="page-subtitle">管理您的代码检查项目和任务</p>
</div>
<div class="projects-container">
<div class="projects-header">
<div class="projects-actions">
<button class="btn btn-primary" id="createProjectBtn">
<i class="fas fa-plus"></i> 新建项目
</button>
</div>
<div class="projects-search">
<input type="text" placeholder="搜索项目..." class="search-input" id="projectSearch">
<i class="fas fa-search"></i>
</div>
</div>
<div class="projects-grid" id="projectsGrid">
<!-- 项目卡片将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
<!-- 项目详情页面 -->
<div id="project-detail-page" class="page-content">
<div class="page-header fade-in">
<div style="display: flex; align-items: center; gap: 15px;">
<button class="btn btn-secondary" id="backToProjectsBtn">
<i class="fas fa-arrow-left"></i> 返回项目列表
</button>
<div>
<h1 class="page-title" id="projectDetailTitle">项目详情</h1>
<p class="page-subtitle" id="projectDetailSubtitle">查看项目信息和运行代码检查</p>
</div>
</div>
</div>
<div class="project-detail-container">
<div class="project-info-panel">
<div class="panel-header">
<h2 class="panel-title">项目信息</h2>
<div class="project-actions">
<button class="btn btn-primary" id="runCheckBtn">
<i class="fas fa-play"></i> 运行检查
</button>
<button class="btn btn-secondary" id="editProjectBtn">
<i class="fas fa-edit"></i> 编辑项目
</button>
<button class="btn btn-danger" id="deleteProjectBtn">
<i class="fas fa-trash"></i> 删除项目
</button>
</div>
</div>
<div class="panel-content" id="projectInfoContent">
<!-- 项目信息将通过 JavaScript 动态生成 -->
</div>
</div>
<div class="check-history-panel">
<div class="panel-header">
<h2 class="panel-title">检查历史</h2>
</div>
<div class="panel-content" id="checkHistoryContent">
<!-- 检查历史将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
<!-- 文件浏览器面板 -->
<div class="file-browser-panel">
<div class="panel-header">
<div style="display: flex; align-items: center; gap: 15px;">
<h2 class="panel-title">文件浏览器</h2>
<div class="file-actions">
<button class="btn btn-primary" id="uploadFileBtn">
<i class="fas fa-upload"></i> 上传文件
</button>
<button class="btn btn-secondary" id="createFileBtn">
<i class="fas fa-plus"></i> 新建文件
</button>
<button class="btn btn-secondary" id="createFolderBtn">
<i class="fas fa-folder-plus"></i> 新建文件夹
</button>
</div>
</div>
<div class="file-path">
<span id="currentPath">/</span>
</div>
</div>
<div class="file-browser-content">
<div class="file-tree" id="fileTree">
<!-- 文件树将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
<!-- 代码编辑器面板 -->
<div class="code-editor-panel" id="codeEditorPanel" style="display: none;">
<div class="panel-header">
<div style="display: flex; align-items: center; gap: 15px;">
<h2 class="panel-title" id="editorTitle">代码编辑器</h2>
<div class="editor-actions">
<button class="btn btn-success" id="saveFileBtn">
<i class="fas fa-save"></i> 保存
</button>
<button class="btn btn-secondary" id="closeEditorBtn">
<i class="fas fa-times"></i> 关闭
</button>
</div>
</div>
<div class="file-info">
<span id="currentFilePath">未选择文件</span>
</div>
</div>
<div class="editor-content">
<textarea id="codeEditor" placeholder="选择文件开始编辑..."></textarea>
</div>
</div>
<!-- 检查结果详情 -->
<div class="check-results-panel" id="checkResultsPanel" style="display: none;">
<div class="panel-header">
<h2 class="panel-title">检查结果详情</h2>
<div class="filter-tabs">
<span class="filter-tab active" data-filter="all">全部</span>
<span class="filter-tab" data-filter="error">错误</span>
<span class="filter-tab" data-filter="warning">警告</span>
<span class="filter-tab" data-filter="info">信息</span>
</div>
</div>
<div class="panel-content" id="checkResultsContent">
<!-- 检查结果将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
</div>
<!-- 新建项目模态框 -->
<div id="createProjectModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>新建项目</h2>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<form id="createProjectForm">
<div class="form-group">
<label for="projectName">项目名称 *</label>
<input type="text" id="projectName" name="name" required>
</div>
<div class="form-group">
<label for="projectDescription">项目描述</label>
<textarea id="projectDescription" name="description" rows="3"></textarea>
</div>
<div class="form-group">
<label>项目来源 *</label>
<div class="source-type-tabs">
<input type="radio" id="sourceGithub" name="source_type" value="github" checked>
<label for="sourceGithub">GitHub</label>
<input type="radio" id="sourceGitee" name="source_type" value="gitee">
<label for="sourceGitee">Gitee</label>
<input type="radio" id="sourceUpload" name="source_type" value="upload">
<label for="sourceUpload">文件上传</label>
</div>
</div>
<div class="form-group" id="gitUrlGroup">
<label for="gitUrl">Git URL *</label>
<input type="url" id="gitUrl" name="source_url" placeholder="https://github.com/username/repository.git">
</div>
<div class="form-group" id="fileUploadGroup" style="display: none;">
<label for="fileUpload">选择文件或文件夹</label>
<input type="file" id="fileUpload" name="files" multiple webkitdirectory>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelCreateProject">取消</button>
<button type="button" class="btn btn-primary" id="confirmCreateProject">创建项目</button>
</div>
</div>
</div>
<script src="js/app.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
{
"name": "src",
"name": "fortifycode",
"version": "1.0.0",
"lockfileVersion": 2,
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/accepts": {

@ -1,11 +1,11 @@
{
"name": "src",
"name": "fortifycode",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "src",
"name": "fortifycode",
"version": "1.0.0",
"license": "ISC",
"dependencies": {

@ -1,12 +1,20 @@
{
"name": "src",
"name": "fortifycode",
"version": "1.0.0",
"description": "",
"main": "index.js",
"description": "基于多Agent协同的军工Python代码合规性检查系统",
"main": "backend.js",
"scripts": {
"start": "node backend.js",
"dev": "node backend.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"keywords": [
"code-quality",
"python",
"linter",
"security",
"compliance"
],
"author": "",
"license": "ISC",
"dependencies": {

@ -0,0 +1,11 @@
# FortifyCode Python 依赖
# 代码质量检查工具
pylint>=2.17.0
flake8>=6.0.0
bandit>=1.7.5
# 可选:增强功能
pycodestyle>=2.10.0
mccabe>=0.7.0

@ -0,0 +1,78 @@
@echo off
chcp 65001
echo ==========================================
echo FortifyCode 代码检查系统启动脚本
echo ==========================================
echo.
echo 正在检查 Node.js 环境...
where node >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [错误] 未找到 Node.js请先安装 Node.js
pause
exit /b 1
)
echo Node.js 版本:
node --version
echo.
echo 正在检查 Python 环境...
where python >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [错误] 未找到 Python请先安装 Python
pause
exit /b 1
)
echo Python 版本:
python --version
echo.
echo 正在检查依赖包...
if not exist "node_modules" (
echo [提示] 首次运行,正在安装 Node.js 依赖...
call npm install
if %ERRORLEVEL% NEQ 0 (
echo [错误] 依赖安装失败
pause
exit /b 1
)
)
echo.
echo 正在检查 Python 代码检查工具...
python -m pylint --version >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [警告] pylint 未安装,正在安装...
pip install pylint
)
python -m flake8 --version >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [警告] flake8 未安装,正在安装...
pip install flake8
)
python -m bandit --version >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [警告] bandit 未安装,正在安装...
pip install bandit
)
echo.
echo ==========================================
echo 启动服务器...
echo ==========================================
echo.
echo 服务器将在以下地址运行:
echo - 前端界面: http://localhost:5000
echo - API接口: http://localhost:5000/api
echo.
echo 按 Ctrl+C 停止服务器
echo.
node backend.js
pause

@ -0,0 +1,76 @@
#!/bin/bash
echo "=========================================="
echo "FortifyCode 代码检查系统启动脚本"
echo "=========================================="
echo ""
echo "正在检查 Node.js 环境..."
if ! command -v node &> /dev/null; then
echo "[错误] 未找到 Node.js请先安装 Node.js"
exit 1
fi
echo "Node.js 版本:"
node --version
echo ""
echo "正在检查 Python 环境..."
if ! command -v python &> /dev/null && ! command -v python3 &> /dev/null; then
echo "[错误] 未找到 Python请先安装 Python"
exit 1
fi
PYTHON_CMD="python"
if command -v python3 &> /dev/null; then
PYTHON_CMD="python3"
fi
echo "Python 版本:"
$PYTHON_CMD --version
echo ""
echo "正在检查依赖包..."
if [ ! -d "node_modules" ]; then
echo "[提示] 首次运行,正在安装 Node.js 依赖..."
npm install
if [ $? -ne 0 ]; then
echo "[错误] 依赖安装失败"
exit 1
fi
fi
echo ""
echo "正在检查 Python 代码检查工具..."
$PYTHON_CMD -m pylint --version &> /dev/null
if [ $? -ne 0 ]; then
echo "[警告] pylint 未安装,正在安装..."
pip install pylint
fi
$PYTHON_CMD -m flake8 --version &> /dev/null
if [ $? -ne 0 ]; then
echo "[警告] flake8 未安装,正在安装..."
pip install flake8
fi
$PYTHON_CMD -m bandit --version &> /dev/null
if [ $? -ne 0 ]; then
echo "[警告] bandit 未安装,正在安装..."
pip install bandit
fi
echo ""
echo "=========================================="
echo "启动服务器..."
echo "=========================================="
echo ""
echo "服务器将在以下地址运行:"
echo " - 前端界面: http://localhost:5000"
echo " - API接口: http://localhost:5000/api"
echo ""
echo "按 Ctrl+C 停止服务器"
echo ""
node backend.js

@ -0,0 +1,50 @@
"""
测试代码样例 - 用于测试 FortifyCode 系统
这个文件包含了各种常见的代码问题用于测试检查工具是否正常工作
包括代码风格问题安全问题代码质量问题等
"""
import os
import sys
# 缺少空行 (Flake8: E302)
def test_function():
"""测试函数"""
x=1+2 # 缺少空格 (Flake8: E225)
password = "hardcoded_password" # 硬编码密码 (Bandit: B105)
# SQL注入风险 (Bandit: B608)
query = "SELECT * FROM users WHERE id = " + str(x)
# 使用 eval 存在安全风险 (Bandit: B307)
result = eval("1 + 1")
# 行长度超过限制 (Flake8: E501)
very_long_variable_name = "这是一个非常非常非常非常非常非常非常非常非常非常长的字符串,用于测试行长度检查"
return result
# 缺少空行 (Flake8: E305)
class TestClass:
"""测试类"""
def __init__(self):
"""初始化方法"""
self.value = 42
def method(self, unused_param): # 未使用的参数 (Pylint: W0613)
"""测试方法"""
print(self.value) # 可以改用 logging
# 全局变量使用不当 (Pylint: C0103)
myVariable = "should_use_snake_case"
# 未使用的导入 (Pylint: W0611)
import json
# 主函数
if __name__ == "__main__":
test_function()
obj = TestClass()
obj.method("unused")

@ -0,0 +1,217 @@
# FortifyCode 快速开始指南
## 一键启动
### Windows 用户
双击运行 `start_server.bat` 文件
### Linux/Mac 用户
```bash
chmod +x start_server.sh
./start_server.sh
```
### 使用 npm
```bash
npm start
```
## 首次使用前的准备
### 1. 安装 Node.js
访问 https://nodejs.org/ 下载并安装 Node.js (推荐 LTS 版本)
验证安装:
```bash
node --version
npm --version
```
### 2. 安装 Python
访问 https://www.python.org/ 下载并安装 Python 3.7+
**重要**: 安装时勾选 "Add Python to PATH"
验证安装:
```bash
python --version
```
### 3. 安装项目依赖
#### Node.js 依赖
```bash
cd src
npm install
```
#### Python 代码检查工具
```bash
pip install -r requirements.txt
```
或手动安装:
```bash
pip install pylint flake8 bandit
```
## 启动服务器
选择以下任一方式:
### 方式 1: 使用启动脚本(推荐)
- Windows: 双击 `start_server.bat`
- Linux/Mac: 运行 `./start_server.sh`
### 方式 2: 使用 npm
```bash
npm start
```
### 方式 3: 直接运行
```bash
node backend.js
```
## 访问系统
启动成功后,浏览器访问:
```
http://localhost:5000
```
你会看到 FortifyCode 的主界面。
## 使用示例
### 示例 1: 快速检查单个文件
1. 准备一个 Python 文件,例如 `test.py`:
```python
import os
def test():
x=1+2
print(x)
test()
```
2. 在主页点击或拖拽文件到上传区域
3. 点击"开始检查"按钮
4. 查看检查结果
### 示例 2: 创建项目
1. 点击顶部导航栏的"项目管理"
2. 点击"新建项目"按钮
3. 填写项目信息:
- 项目名称: 我的第一个项目
- 项目描述: 测试项目
- 来源类型: 选择"文件上传"
4. 选择要上传的文件或文件夹
5. 点击"创建项目"
### 示例 3: 查看项目详情
1. 在项目列表中点击项目卡片
2. 查看项目信息和文件浏览器
3. 点击"运行检查"进行代码检查
4. 在"检查历史"中查看历史记录
## 常见问题快速解决
### ❌ 提示 "未找到 Node.js"
**解决**: 安装 Node.js 并确保添加到系统 PATH
### ❌ 提示 "未找到 Python"
**解决**: 安装 Python 并确保添加到系统 PATH
### ❌ 提示 "pylint 未安装"
**解决**:
```bash
pip install pylint
```
### ❌ 提示 "端口 5000 被占用"
**解决**:
- 方案 1: 关闭占用端口的程序
- 方案 2: 修改端口号
编辑 `backend.js` 第 10 行:
```javascript
const PORT = process.env.PORT || 8080; // 改为其他端口
```
### ❌ 上传文件失败
**解决**:
- 确保文件是 .py, .pyx, .pyi 格式
- 确保文件大小不超过 100MB
- 检查磁盘空间是否充足
## 系统架构
```
┌─────────────┐
│ 浏览器 │ http://localhost:5000
└──────┬──────┘
┌─────────────────────────────┐
│ Express 服务器 (Node.js) │
│ - 提供前端页面 │
│ - 处理API请求 │
│ - 文件管理 │
└──────┬──────────────────────┘
┌────────────────────────────┐
│ 代码检查工具 (Python) │
│ - Pylint (代码质量) │
│ - Flake8 (代码规范) │
│ - Bandit (安全检查) │
└────────────────────────────┘
```
## 功能概览
### 🏠 仪表板
- 查看系统统计信息
- 快捷文件上传和检查
- Agent 状态监控
### 📁 项目管理
- 创建和管理多个项目
- 支持 GitHub/Gitee 克隆
- 支持本地文件上传
### 📝 文件浏览器
- 浏览项目文件
- 在线编辑代码
- 文件上传和管理
### 🔍 代码检查
- 多工具协同检查
- 问题分类显示
- 修复建议提供
### 📊 检查报告
- 详细的问题列表
- 问题统计分析
- 历史记录查看
## 下一步
- 📖 阅读完整的 [README.md](README.md)
- 📚 查看 [API 文档](view/API.md)
- 🔧 了解 [军工软件Python编码指南](../doc/军工软件python编码指南.docx)
## 获取帮助
如果遇到问题:
1. 检查控制台输出的错误信息
2. 查看浏览器开发者工具的 Console 选项卡
3. 参考 README.md 中的"常见问题"部分
---
祝使用愉快! 🚀

@ -0,0 +1,405 @@
# FortifyCode 项目集成说明
## 修改概述
本次修改将前端界面与项目后端进行了完整集成,使系统能够正常运行。
## 主要修改内容
### 1. 创建完整的后端服务器 (`backend.js`)
**位置**: `src/backend.js`
**主要功能**:
- 运行在端口 5000与前端期望的端口一致
- 提供所有前端需要的 API 接口(添加了 `/api` 前缀)
- 集成三个代码检查工具Pylint、Flake8、Bandit
- 实现项目管理功能
- 实现文件上传和管理功能
- 提供静态文件服务(前端页面)
**新增 API 端点**:
```
GET /api/health - 健康检查
POST /api/upload - 文件上传
POST /api/check - 代码检查
GET /api/projects - 获取所有项目
POST /api/projects - 创建新项目
GET /api/projects/:id - 获取项目详情
DELETE /api/projects/:id - 删除项目
POST /api/projects/:id/check - 运行项目检查
POST /api/projects/:id/upload-files - 上传文件到项目
GET /api/projects/:id/files - 获取项目文件列表
GET /api/projects/:id/files/content - 获取文件内容
PUT /api/projects/:id/files/content - 保存文件内容
```
### 2. 修改前端 API 配置 (`frontend/js/app.js`)
**修改内容**:
```javascript
// 修改前
const API_BASE_URL = 'http://localhost:5000/api';
// 修改后
const API_BASE_URL = window.location.origin + '/api';
```
**优势**: 自动适配部署环境,无需手动修改配置
### 3. 创建启动脚本
#### Windows 启动脚本 (`start_server.bat`)
- 自动检查 Node.js 和 Python 环境
- 自动安装缺失的依赖
- 自动安装代码检查工具
- 提供友好的启动提示
#### Linux/Mac 启动脚本 (`start_server.sh`)
- 同上,适配 Unix 系统
### 4. 更新项目配置 (`package.json`)
**修改内容**:
- 更新项目名称和描述
- 添加启动脚本
- 设置正确的主入口文件
### 5. 创建文档
#### README.md
- 完整的项目说明
- 安装和使用指南
- API 文档
- 常见问题解答
#### 快速开始指南.md
- 快速上手教程
- 使用示例
- 问题排查
#### requirements.txt
- Python 依赖列表
- 便于一键安装
## 项目结构变化
### 之前的结构问题
```
src/
├── frontend/ # 前端代码
│ ├── index.html
│ ├── css/style.css
│ └── js/app.js # API指向 localhost:5000/api
├── view/
│ └── backend.js # 后端运行在 localhost:3000
│ # 只有 /check 端点,没有 /api 前缀
└── ...
❌ 问题:
1. 端口不匹配 (前端5000, 后端3000)
2. API路径不匹配 (前端需要/api前缀)
3. 缺少大量前端需要的API端点
```
### 修改后的结构
```
src/
├── backend.js # ✅ 新的完整后端服务器
│ # - 端口5000
│ # - /api 前缀
│ # - 所有必要的API端点
├── frontend/ # 前端代码(已集成)
│ ├── index.html
│ ├── css/style.css
│ └── js/app.js # ✅ API自动适配当前域名
├── start_server.bat # ✅ Windows启动脚本
├── start_server.sh # ✅ Linux/Mac启动脚本
├── package.json # ✅ 更新的配置
├── README.md # ✅ 完整文档
├── 快速开始指南.md # ✅ 快速入门
├── requirements.txt # ✅ Python依赖
├── projects_data/ # ✅ 项目数据目录(自动创建)
└── view/ # 旧的后端(保留,可选择性使用)
└── backend.js
✅ 优势:
1. 端口统一为5000
2. API路径统一
3. 功能完整
4. 易于部署和使用
```
## 技术实现细节
### 1. 代码检查工具集成
```javascript
// 工具配置
const TOOL_CONFIG = {
bandit: { ... }, // 安全漏洞检查
flake8: { ... }, // 代码规范检查
pylint: { ... } // 代码质量检查
};
// 执行检查
async function runCodeCheck(filePath) {
// 并行执行三个工具
// 收集和统一处理结果
// 返回统一格式的问题列表
}
```
### 2. 文件上传处理
```javascript
// 使用 Multer 中间件处理文件上传
const upload = multer({
storage: storage,
limits: { fileSize: 100 * 1024 * 1024 }, // 100MB
fileFilter: (req, file, cb) => {
// 只接受 Python 文件
if (file.originalname.match(/\.(py|pyx|pyi)$/)) {
cb(null, true);
}
}
});
```
### 3. 项目数据持久化
```javascript
// 使用 JSON 文件存储项目数据
// 生产环境建议使用数据库
const PROJECTS_FILE = path.join(PROJECTS_DIR, 'projects.json');
function saveProjects() {
fs.writeFileSync(PROJECTS_FILE, JSON.stringify(projects, null, 2));
}
```
### 4. CORS 配置
```javascript
// 允许跨域请求
app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
```
## 与原有项目的兼容性
### 保留的内容
1. **前端代码** (`frontend/`)
- 完全保留,只修改了 API_BASE_URL
- HTML、CSS、JavaScript 功能不变
2. **原后端** (`view/backend.js`)
- 保留不动,可作为参考
- 如需使用可独立运行在3000端口
3. **代码检查工具** (bandit-main, flake8-main, pylint-main)
- 保留不动
- 新后端通过 Python 命令调用这些工具
4. **文档和配置** (doc/, model/)
- 完全保留
### 新增的内容
1. `backend.js` - 完整的后端服务器
2. `start_server.bat` - Windows 启动脚本
3. `start_server.sh` - Linux/Mac 启动脚本
4. `README.md` - 项目文档
5. `快速开始指南.md` - 快速入门
6. `requirements.txt` - Python 依赖
7. `项目集成说明.md` - 本文档
## 使用说明
### 启动系统
**方式 1**: 使用启动脚本(推荐)
```cmd
# Windows
start_server.bat
# Linux/Mac
./start_server.sh
```
**方式 2**: 使用 npm
```bash
npm start
```
**方式 3**: 直接运行
```bash
node backend.js
```
### 访问系统
浏览器打开: http://localhost:5000
### 系统流程
```
1. 用户访问 http://localhost:5000
2. Express 服务器返回前端页面
3. 前端调用 /api/* 接口
4. 后端处理请求,调用 Python 检查工具
5. 返回检查结果给前端
6. 前端展示结果
```
## 测试建议
### 1. 环境测试
```bash
# 检查 Node.js
node --version
# 检查 Python
python --version
# 检查检查工具
python -m pylint --version
python -m flake8 --version
python -m bandit --version
```
### 2. 功能测试
1. **文件上传检查**
- 上传一个 Python 文件
- 检查是否正常显示结果
2. **项目管理**
- 创建一个新项目
- 上传文件到项目
- 运行项目检查
3. **文件浏览器**
- 浏览项目文件
- 编辑文件内容
- 保存文件
### 3. API 测试
使用 curl 或 Postman 测试 API 端点:
```bash
# 健康检查
curl http://localhost:5000/api/health
# 获取项目列表
curl http://localhost:5000/api/projects
```
## 部署建议
### 开发环境
- 使用 `node backend.js` 直接运行
- 使用 `nodemon` 实现自动重启
### 生产环境
- 使用 PM2 管理进程
- 配置反向代理Nginx/Apache
- 使用数据库替代 JSON 文件存储
- 添加用户认证和权限管理
## 后续优化建议
### 功能优化
1. **数据库集成**
- 使用 SQLite/MySQL/PostgreSQL 存储项目数据
- 更好的并发性能
2. **用户系统**
- 添加用户注册和登录
- 多用户项目隔离
3. **检查任务队列**
- 使用消息队列处理大量检查任务
- 支持异步检查和结果推送
4. **结果缓存**
- 缓存检查结果
- 避免重复检查相同代码
5. **Git 集成增强**
- 实际实现 GitHub/Gitee 克隆功能
- 支持分支和版本管理
### 性能优化
1. **并发处理**
- 多个文件并行检查
- Worker 线程池
2. **增量检查**
- 只检查变更的文件
- 智能差异分析
3. **前端优化**
- 代码分割和懒加载
- 虚拟滚动优化大量结果显示
## 常见问题
### Q: 为什么有两个 backend.js
A:
- `src/backend.js` - 新的完整后端(推荐使用)
- `src/view/backend.js` - 原有后端(保留作为参考)
建议使用新的 `src/backend.js`
### Q: 可以删除旧的 view/backend.js 吗?
A: 可以。新的 backend.js 已经包含了所有功能。但建议保留一段时间作为备份。
### Q: 如何修改端口?
A: 编辑 `backend.js` 第 10 行:
```javascript
const PORT = process.env.PORT || 5000;
```
或设置环境变量:
```bash
PORT=8080 node backend.js
```
### Q: Python 检查工具安装在哪里?
A: 通过 pip 安装到系统或虚拟环境。后端通过 Python 命令行调用这些工具。
## 总结
本次集成:
- ✅ 统一了前后端接口
- ✅ 完善了所有缺失的功能
- ✅ 提供了完整的文档和启动脚本
- ✅ 保持了代码的可维护性
- ✅ 易于部署和使用
现在可以直接运行 `start_server.bat`Windows`./start_server.sh`Linux/Mac来启动完整的系统。
---
集成完成时间: 2025年10月21日
Loading…
Cancel
Save