forked from pu8crm6xf/analysiscode
parent
0c5fb9f7e4
commit
55d117d840
@ -0,0 +1,235 @@
|
||||
|
||||
# 基于多agent协同的军工Python代码合规性检查系统 - FortifyCode
|
||||
|
||||
## 🎯 系统特色
|
||||
|
||||
### 核心功能
|
||||
- **多 Agent 协同检查**: 集成 pylint、flake8、bandit 三大专业工具
|
||||
- **项目导入管理**: 支持 GitHub、Gitee 仓库导入和本地文件上传
|
||||
- **实时检查报告**: 详细的代码质量、安全漏洞、合规性分析
|
||||
- **军事级安全**: 专门针对军事代码的特殊安全要求
|
||||
|
||||
### 技术架构
|
||||
- **前端**: HTML5 + CSS3 + JavaScript (ES6+)
|
||||
- **后端**: Flask + SQLAlchemy + MySQL
|
||||
- **代码检查**: pylint + flake8 + bandit
|
||||
- **版本控制**: Git 集成支持
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 环境要求
|
||||
- Python 3.8+
|
||||
- MySQL 5.7+
|
||||
- Node.js (可选,用于前端开发)
|
||||
|
||||
### 安装步骤
|
||||
|
||||
1. **克隆项目**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd FortifyCode
|
||||
```
|
||||
|
||||
2. **安装 Python 依赖**
|
||||
```bash
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. **安装代码检查工具**
|
||||
```bash
|
||||
pip install pylint flake8 bandit
|
||||
```
|
||||
|
||||
4. **配置数据库**
|
||||
```bash
|
||||
# 启动 MySQL 服务
|
||||
# 创建数据库用户 (可选)
|
||||
mysql -u root -p
|
||||
SOURCE database_init.sql
|
||||
```
|
||||
|
||||
5. **启动系统**
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
6. **访问系统**
|
||||
- 前端界面: http://localhost:3000 (或直接打开 index.html)
|
||||
- 后端API: http://localhost:5000
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
FortifyCode/
|
||||
├── index.html # 主页面
|
||||
├── css/
|
||||
│ └── style.css # 样式文件
|
||||
├── js/
|
||||
│ └── app.js # 前端逻辑
|
||||
├── backend/
|
||||
│ ├── app.py # Flask 后端服务
|
||||
│ ├── config.py # 配置文件
|
||||
│ ├── start.py # 启动脚本
|
||||
│ ├── requirements.txt # Python 依赖
|
||||
│ └── database_init.sql # 数据库初始化脚本
|
||||
├── uploads/ # 文件上传目录
|
||||
├── projects/ # 项目存储目录
|
||||
├── reports/ # 检查报告目录
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 数据库配置
|
||||
在 `backend/config.py` 中修改数据库连接信息:
|
||||
```python
|
||||
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://用户名:密码@localhost/fortifycode'
|
||||
```
|
||||
|
||||
### 工具配置
|
||||
在 `backend/app.py` 中修改工具配置:
|
||||
```python
|
||||
TOOLS_CONFIG = {
|
||||
'pylint': {
|
||||
'command': 'pylint',
|
||||
'args': ['--output-format=json', '--reports=no'],
|
||||
'enabled': True
|
||||
},
|
||||
# ... 其他工具配置
|
||||
}
|
||||
```
|
||||
|
||||
## 📖 使用指南
|
||||
|
||||
### 1. 项目管理
|
||||
- **新建项目**: 点击"新建项目"按钮,选择项目来源
|
||||
- GitHub/Gitee: 输入仓库 URL
|
||||
- 文件上传: 选择本地文件或文件夹
|
||||
- **项目列表**: 查看所有项目的基本信息和检查状态
|
||||
- **项目搜索**: 使用搜索框快速查找项目
|
||||
|
||||
### 2. 代码检查
|
||||
- **快捷检查**: 在仪表板直接上传文件进行快速检查
|
||||
- **项目检查**: 在项目详情页面运行完整的代码检查
|
||||
- **检查历史**: 查看项目的所有检查记录
|
||||
|
||||
### 3. 报告查看
|
||||
- **检查结果**: 查看详细的代码问题列表
|
||||
- **问题分类**: 按错误、警告、信息分类查看
|
||||
- **修复建议**: 获取具体的问题修复建议
|
||||
|
||||
### 4. 系统设置
|
||||
- **Agent配置**: 配置各个检查工具的参数
|
||||
- **检查规则**: 自定义代码风格和安全规则
|
||||
- **通知设置**: 配置检查完成通知
|
||||
|
||||
## 🛡️ 安全特性
|
||||
|
||||
### 军事级安全要求
|
||||
- **敏感信息检测**: 自动识别硬编码密码、API密钥等
|
||||
- **安全漏洞扫描**: SQL注入、XSS、CSRF等安全漏洞检测
|
||||
- **合规性检查**: 军事代码规范合规性验证
|
||||
- **访问控制**: 用户权限管理和操作日志记录
|
||||
|
||||
### 数据安全
|
||||
- **文件隔离**: 每个项目独立存储,避免数据泄露
|
||||
- **临时文件清理**: 自动清理检查过程中的临时文件
|
||||
- **数据加密**: 敏感数据加密存储
|
||||
|
||||
## 🔍 检查工具说明
|
||||
|
||||
### pylint
|
||||
- **功能**: Python 代码质量检查
|
||||
- **检查项**: 代码风格、错误检测、复杂度分析
|
||||
- **输出**: JSON 格式的结构化报告
|
||||
|
||||
### flake8
|
||||
- **功能**: Python 代码风格检查
|
||||
- **检查项**: PEP8 规范、语法错误、未使用变量
|
||||
- **输出**: 文本格式的详细报告
|
||||
|
||||
### bandit
|
||||
- **功能**: Python 安全漏洞扫描
|
||||
- **检查项**: 安全漏洞、敏感信息泄露、危险函数调用
|
||||
- **输出**: JSON 格式的安全报告
|
||||
|
||||
## 📊 报告格式
|
||||
|
||||
### 检查结果结构
|
||||
```json
|
||||
{
|
||||
"total_issues": 25,
|
||||
"error_count": 5,
|
||||
"warning_count": 15,
|
||||
"info_count": 5,
|
||||
"tools_status": {
|
||||
"pylint": "completed",
|
||||
"flake8": "completed",
|
||||
"bandit": "completed"
|
||||
},
|
||||
"all_issues": [
|
||||
{
|
||||
"file": "src/database.py",
|
||||
"line": 45,
|
||||
"type": "error",
|
||||
"severity": "high",
|
||||
"message": "SQL注入风险",
|
||||
"rule": "B608"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🚨 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **MySQL 连接失败**
|
||||
- 检查 MySQL 服务是否启动
|
||||
- 验证用户名和密码是否正确
|
||||
- 确认数据库是否存在
|
||||
|
||||
2. **代码检查工具未找到**
|
||||
- 运行 `pip install pylint flake8 bandit`
|
||||
- 检查 PATH 环境变量
|
||||
- 使用绝对路径配置工具
|
||||
|
||||
3. **文件上传失败**
|
||||
- 检查 uploads 目录权限
|
||||
- 确认文件大小限制
|
||||
- 验证文件格式是否支持
|
||||
|
||||
4. **前端页面无法访问**
|
||||
- 检查文件路径是否正确
|
||||
- 确认浏览器支持现代 JavaScript
|
||||
- 查看浏览器控制台错误信息
|
||||
|
||||
### 日志查看
|
||||
系统日志输出在控制台,包含:
|
||||
- 请求处理日志
|
||||
- 错误信息
|
||||
- 检查进度信息
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
1. Fork 项目
|
||||
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
|
||||
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
||||
5. 打开 Pull Request
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
|
||||
|
||||
## 📞 支持
|
||||
|
||||
如有问题或建议,请:
|
||||
- 提交 Issue
|
||||
- 发送邮件至项目维护者
|
||||
- 查看项目文档
|
||||
|
||||
---
|
||||
|
||||
**FortifyCode** - 让代码更安全,让开发更放心 🛡️
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
||||
多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>
|
||||
@ -0,0 +1,70 @@
|
||||
-- 设置字符集
|
||||
SET NAMES utf8mb4;
|
||||
SET CHARACTER SET utf8mb4;
|
||||
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS fortifycode CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 使用数据库
|
||||
USE fortifycode;
|
||||
|
||||
-- 创建项目表
|
||||
CREATE TABLE IF NOT EXISTS project (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
description TEXT,
|
||||
source_type VARCHAR(50) NOT NULL COMMENT 'github, gitee, upload',
|
||||
source_url VARCHAR(500),
|
||||
local_path VARCHAR(500),
|
||||
language VARCHAR(50) DEFAULT 'python',
|
||||
status VARCHAR(50) DEFAULT 'active' COMMENT 'active, archived, deleted',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
created_by VARCHAR(100) DEFAULT 'admin',
|
||||
INDEX idx_name (name),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
|
||||
-- 创建代码检查表
|
||||
CREATE TABLE IF NOT EXISTS code_check (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
project_id INT NOT NULL,
|
||||
check_type VARCHAR(50) NOT NULL COMMENT 'pylint, flake8, bandit, combined',
|
||||
status VARCHAR(50) DEFAULT 'pending' COMMENT 'pending, running, completed, failed',
|
||||
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at TIMESTAMP NULL,
|
||||
total_files INT DEFAULT 0,
|
||||
total_issues INT DEFAULT 0,
|
||||
error_count INT DEFAULT 0,
|
||||
warning_count INT DEFAULT 0,
|
||||
info_count INT DEFAULT 0,
|
||||
report_path VARCHAR(500),
|
||||
summary TEXT,
|
||||
FOREIGN KEY (project_id) REFERENCES project(id) ON DELETE CASCADE,
|
||||
INDEX idx_project_id (project_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_started_at (started_at)
|
||||
);
|
||||
|
||||
-- 创建检查结果表
|
||||
CREATE TABLE IF NOT EXISTS check_result (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
check_id INT NOT NULL,
|
||||
file_path VARCHAR(500) NOT NULL,
|
||||
line_number INT,
|
||||
column_number INT,
|
||||
issue_type VARCHAR(50) NOT NULL COMMENT 'error, warning, info',
|
||||
severity VARCHAR(20) DEFAULT 'medium' COMMENT 'high, medium, low',
|
||||
rule_id VARCHAR(100),
|
||||
message TEXT NOT NULL,
|
||||
suggestion TEXT,
|
||||
FOREIGN KEY (check_id) REFERENCES code_check(id) ON DELETE CASCADE,
|
||||
INDEX idx_check_id (check_id),
|
||||
INDEX idx_issue_type (issue_type),
|
||||
INDEX idx_severity (severity)
|
||||
);
|
||||
|
||||
-- 字符集设置正确
|
||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,92 @@
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS df2_0 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
|
||||
USE df2_0;
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for users
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE `users` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`password` varchar(100) NOT NULL COMMENT '密码',
|
||||
`name` varchar(50) NOT NULL COMMENT '姓名',
|
||||
`gender` varchar(10) NOT NULL COMMENT '性别',
|
||||
`unit` varchar(100) NOT NULL COMMENT '单位',
|
||||
`role` varchar(20) NOT NULL DEFAULT 'user' COMMENT '角色',
|
||||
`contact` varchar(50) DEFAULT NULL COMMENT '联系方式',
|
||||
`last_login` datetime DEFAULT NULL COMMENT '最后登录时间',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for dues
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `dues`;
|
||||
CREATE TABLE `dues` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL COMMENT '用户ID',
|
||||
`due_amount` decimal(10,2) NOT NULL COMMENT '应缴金额',
|
||||
`actual_amount` decimal(10,2) NOT NULL COMMENT '实缴金额',
|
||||
`payment_type` varchar(20) NOT NULL COMMENT '缴费类型',
|
||||
`payment_date` date NOT NULL COMMENT '缴费日期',
|
||||
`status` varchar(20) NOT NULL COMMENT '状态',
|
||||
`remark` text COMMENT '备注',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
CONSTRAINT `dues_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='党费记录表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for payment_types
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `payment_types`;
|
||||
CREATE TABLE `payment_types` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`type_code` varchar(20) NOT NULL COMMENT '类型代码',
|
||||
`type_name` varchar(50) NOT NULL COMMENT '类型名称',
|
||||
`description` varchar(200) DEFAULT NULL COMMENT '描述',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `type_code` (`type_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='缴费类型表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_logs
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `system_logs`;
|
||||
CREATE TABLE `system_logs` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL COMMENT '用户ID',
|
||||
`action` varchar(50) NOT NULL COMMENT '操作类型',
|
||||
`description` text NOT NULL COMMENT '操作描述',
|
||||
`ip_address` varchar(50) DEFAULT NULL COMMENT 'IP地址',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
CONSTRAINT `system_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统日志表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of users
|
||||
-- ----------------------------
|
||||
INSERT INTO `users` VALUES (1, 'admin', 'a123', '张三', '男', '系统管理部', 'admin', 'admin@example.com', NOW(), NOW(), NOW());
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of payment_types
|
||||
-- ----------------------------
|
||||
INSERT INTO `payment_types` VALUES
|
||||
(1, 'monthly', '月度缴费', '每月固定党费缴纳', NOW()),
|
||||
(2, 'special', '特殊党费', '特殊时期或特殊用途的党费缴纳', NOW()),
|
||||
(3, 'other', '其他', '其他类型的党费缴纳', NOW());
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@ -0,0 +1,5 @@
|
||||
Flask==2.0.1
|
||||
Flask-Cors==3.0.10
|
||||
PyMySQL==1.0.2
|
||||
python-dotenv==0.19.0
|
||||
Werkzeug==2.0.1
|
||||
@ -0,0 +1,165 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>新增党费记录</title>
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.form-container {
|
||||
max-width: 800px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.required-label::after {
|
||||
content: "*";
|
||||
color: red;
|
||||
margin-left: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="form-container">
|
||||
<h2 class="mb-4">新增党费记录</h2>
|
||||
|
||||
<!-- 新增记录表单 -->
|
||||
<form id="addForm">
|
||||
<!-- 姓名 -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">姓名</label>
|
||||
<input type="text" class="form-control" id="name" required>
|
||||
</div>
|
||||
|
||||
<!-- ID -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">ID</label>
|
||||
<input type="text" class="form-control" id="userId" required>
|
||||
</div>
|
||||
|
||||
<!-- 性别 -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">性别</label>
|
||||
<div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="gender" id="male" value="男" required>
|
||||
<label class="form-check-label" for="male">男</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="gender" id="female" value="女">
|
||||
<label class="form-check-label" for="female">女</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 单位 -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">单位</label>
|
||||
<input type="text" class="form-control" id="unit" required>
|
||||
</div>
|
||||
|
||||
<!-- 金额组 -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label required-label">应缴金额(元)</label>
|
||||
<input type="number" class="form-control" id="dueAmount" min="0" step="0.01" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label required-label">实缴金额(元)</label>
|
||||
<input type="number" class="form-control" id="actualAmount" min="0" step="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 缴费类型 -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">缴费类型</label>
|
||||
<select class="form-select" id="paymentType" required>
|
||||
<option value="">请选择</option>
|
||||
<option value="monthly">月度缴费</option>
|
||||
<option value="special">特殊党费</option>
|
||||
<option value="other">其他</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 缴费日期 -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required-label">缴费日期</label>
|
||||
<input type="date" class="form-control" id="paymentDate" required>
|
||||
</div>
|
||||
|
||||
<!-- 备注 -->
|
||||
<div class="mb-4">
|
||||
<label class="form-label">备注</label>
|
||||
<textarea class="form-control" id="remark" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="d-flex justify-content-end gap-2">
|
||||
<button type="button" class="btn btn-secondary" onclick="goBack()">取消</button>
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
<script>
|
||||
// 返回管理主页
|
||||
function goBack() {
|
||||
window.location.href = "{{ url_for('admin_main') }}";
|
||||
}
|
||||
|
||||
// 表单提交处理
|
||||
$('#addForm').submit(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// 表单验证
|
||||
const due = parseFloat($('#dueAmount').val());
|
||||
const actual = parseFloat($('#actualAmount').val());
|
||||
|
||||
if (actual > due) {
|
||||
alert('实缴金额不能超过应缴金额');
|
||||
return;
|
||||
}
|
||||
|
||||
// 自动计算状态
|
||||
const status = actual >= due ? '已交齐' : '未交齐';
|
||||
|
||||
// 构建数据对象
|
||||
const formData = {
|
||||
userId: $('#userId').val(),
|
||||
dueAmount: due,
|
||||
actualAmount: actual,
|
||||
paymentType: $('#paymentType').val(),
|
||||
paymentDate: $('#paymentDate').val(),
|
||||
remark: $('#remark').val(),
|
||||
status: status
|
||||
};
|
||||
|
||||
// 发送请求
|
||||
$.ajax({
|
||||
url: '/api/dues',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(formData),
|
||||
success: function() {
|
||||
alert('提交成功!');
|
||||
goBack();
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert(`提交失败:${xhr.responseJSON?.message || '服务器错误'}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 输入验证
|
||||
$('#dueAmount, #actualAmount').on('input', function() {
|
||||
const value = parseFloat($(this).val());
|
||||
if (value < 0) {
|
||||
$(this).val(0);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,264 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<!-- 基础元信息 -->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>党费管理系统 - 管理后台</title>
|
||||
|
||||
<!-- 引入Bootstrap CSS框架 -->
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 引入Font Awesome图标库 -->
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
|
||||
<!-- 自定义样式 -->
|
||||
<style>
|
||||
/* 状态显示样式 */
|
||||
.status-paid { color: #28a745; } /* 已交齐状态绿色 */
|
||||
.status-unpaid { color: #dc3545; } /* 未交齐状态红色 */
|
||||
.operation-btns { margin: 20px 0; gap: 10px; } /* 操作按钮容器边距+间隔 */
|
||||
.search-box { max-width: 300px; } /* 搜索框宽度限制 */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar navbar-dark bg-primary">
|
||||
<div class="container-fluid">
|
||||
<!-- 系统Logo -->
|
||||
<a class="navbar-brand" href="#">
|
||||
<i class="fas fa-home me-2"></i>党费管理系统
|
||||
</a>
|
||||
|
||||
<!-- 功能导航区 -->
|
||||
<div class="d-flex">
|
||||
<!-- 统计分析按钮 -->
|
||||
<button class="btn btn-outline-light me-2" onclick="window.location.href='{{ url_for('stats_page') }}'">
|
||||
<i class="fas fa-chart-bar me-1"></i>统计分析
|
||||
</button>
|
||||
<!-- 导入导出按钮 -->
|
||||
<button class="btn btn-outline-light me-2" onclick="window.location.href='{{ url_for('data_handle_page') }}'">
|
||||
<i class="fas fa-file-import me-1"></i>数据导入/导出
|
||||
</button>
|
||||
<!-- 退出登录按钮 -->
|
||||
<button class="btn btn-outline-light" onclick="logout()">
|
||||
<i class="fas fa-sign-out-alt me-1"></i>退出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 数据管理区 -->
|
||||
<div class="container mt-4">
|
||||
<!-- 操作按钮组 -->
|
||||
<div class="operation-btns d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<button class="btn btn-primary me-2" style="box-shadow: 0 2px 4px rgba(0,0,0,0.1);" onclick="window.location.href='{{ url_for('add_record_page') }}'">
|
||||
<i class="fas fa-plus me-1"></i>新增记录
|
||||
</button>
|
||||
<button class="btn btn-danger me-2" style="box-shadow: 0 2px 4px rgba(0,0,0,0.1);" onclick="deleteSelected()">
|
||||
<i class="fas fa-trash me-1"></i>删除记录
|
||||
</button>
|
||||
<button class="btn btn-warning" onclick="editSelected()">
|
||||
<i class="fas fa-edit me-1"></i>修改记录
|
||||
</button>
|
||||
</div>
|
||||
<!-- 搜索框 -->
|
||||
<div class="search-box">
|
||||
<div class="input-group">
|
||||
<input type="text" id="searchInput" class="form-control" placeholder="输入姓名或ID">
|
||||
<button class="btn btn-primary" onclick="searchRecords()">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th><input type="checkbox" id="selectAll"></th>
|
||||
<th>姓名</th>
|
||||
<th>ID</th>
|
||||
<th>性别</th>
|
||||
<th>单位</th>
|
||||
<th>应缴金额</th>
|
||||
<th>实缴金额</th>
|
||||
<th>缴费日期</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="dataBody">
|
||||
<!-- 数据通过JavaScript动态加载 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 引入jQuery库 -->
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 初始化数据存储
|
||||
let currentData = [];
|
||||
|
||||
// 数据加载函数
|
||||
// function loadData() {
|
||||
// $.get('/api/dues', data => {
|
||||
// currentData = data;
|
||||
// renderTable(data);
|
||||
// }).fail(() => {
|
||||
// alert('加载数据失败,请刷新页面重试');
|
||||
// });
|
||||
// }
|
||||
function loadData() {
|
||||
$.ajax({
|
||||
url: '/api/dues',
|
||||
method: 'GET',
|
||||
success: function(data){
|
||||
currentData = data;
|
||||
renderTable(data);
|
||||
},
|
||||
error :function(xhr, status, error){
|
||||
alert('加载数据失败:' + error + '。请刷新页面重试');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 表格渲染函数
|
||||
function renderTable(data) {
|
||||
const tbody = $('#dataBody').empty();//表格体
|
||||
data.forEach(item => {
|
||||
// 动态计算状态
|
||||
const status = item.actual_amount >= item.due_amount ?
|
||||
'<span class="status-paid">已交齐</span>' :
|
||||
'<span class="status-unpaid">未交齐</span>';
|
||||
|
||||
// 构建表格行
|
||||
tbody.append(`
|
||||
<tr data-id="${item.id}">
|
||||
<td><input type="checkbox" class="rowCheck"></td>
|
||||
<td>${item.name}</td>
|
||||
<td>${item.user_id}</td>
|
||||
<td>${item.gender || '-'}</td>
|
||||
<td>${item.unit}</td>
|
||||
<td>¥${item.due_amount.toFixed(2)}</td>
|
||||
<td>¥${item.actual_amount.toFixed(2)}</td>
|
||||
<td>${new Date(item.payment_date).toLocaleDateString()}</td>
|
||||
<td>${status}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-info me-1" onclick="viewDetail('${item.user_id}')">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-warning me-1" onclick="editRecord('${item.id}')">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteRecord('${item.id}')">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
// 全选/取消全选
|
||||
$('#selectAll').change(function() {
|
||||
$('.rowCheck').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
// 查看详情
|
||||
function viewDetail(id) {
|
||||
window.location.href = `{{ url_for('user_detail') }}?id=${id}`;
|
||||
}
|
||||
|
||||
// 编辑记录
|
||||
function editRecord(id) {
|
||||
window.location.href = `{{ url_for('revise_page') }}?id=${id}`;
|
||||
}
|
||||
|
||||
// 删除记录
|
||||
function deleteRecord(id) {
|
||||
//console.log(id);
|
||||
if (confirm('确定要删除这条记录吗?')) {
|
||||
$.ajax({
|
||||
url: `/api/dues/${id}`,
|
||||
method: 'DELETE',
|
||||
success: () => {
|
||||
alert('删除成功');
|
||||
loadData();
|
||||
},
|
||||
error: () => alert('删除失败')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 删除选中记录
|
||||
function deleteSelected() {
|
||||
const selected = $('.rowCheck:checked').length;
|
||||
if (selected === 0) {
|
||||
alert('请选择要删除的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirm(`确定要删除选中的${selected}条记录吗?`)) {
|
||||
const ids = [];
|
||||
$('.rowCheck:checked').each(function() {
|
||||
ids.push($(this).closest('tr').data('id'));
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
Promise.all(ids.map(id =>
|
||||
$.ajax({
|
||||
url: `/api/dues/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
)).then(() => {
|
||||
alert('删除成功');
|
||||
loadData();
|
||||
}).catch(() => alert('删除失败'));
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑选中记录
|
||||
function editSelected() {
|
||||
const selected = $('.rowCheck:checked');
|
||||
if (selected.length !== 1) {
|
||||
alert('请选择一条记录进行编辑');
|
||||
return;
|
||||
}
|
||||
const id = selected.closest('tr').data('id');
|
||||
editRecord(id);
|
||||
}
|
||||
|
||||
// 搜索记录
|
||||
function searchRecords() {
|
||||
const keyword = $('#searchInput').val().toLowerCase();
|
||||
if (!keyword) {
|
||||
renderTable(currentData);
|
||||
return;
|
||||
}
|
||||
|
||||
const filtered = currentData.filter(item =>
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.user_id.toString().includes(keyword)
|
||||
);
|
||||
renderTable(filtered);
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
function logout() {
|
||||
if (confirm('确定要退出登录吗?')) {
|
||||
window.location.href = '/logout';
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时初始化数据
|
||||
$(document).ready(() => loadData());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>党费管理系统 - 仪表板</title>
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.sidebar { /* 调整为与导航栏协调的深蓝色 */
|
||||
min-height: 100vh;
|
||||
background-color: #0d6efd; /* 与导航栏同色 */
|
||||
padding-top: 20px;
|
||||
}
|
||||
.sidebar .nav-link {
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.sidebar .nav-link:hover {
|
||||
background-color: #495057;
|
||||
}
|
||||
.sidebar .nav-link.active {
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
.main-content {
|
||||
padding: 20px;
|
||||
}
|
||||
.stat-card { /* 优化卡片样式 */
|
||||
border-radius: 12px; /* 更大圆角 */
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1); /* 更明显阴影 */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- 侧边栏 -->
|
||||
<div class="col-md-2 sidebar">
|
||||
<h3 class="text-white text-center mb-4">党费管理系统</h3>
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">
|
||||
<i class="fas fa-home me-2"></i>首页
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="fas fa-users me-2"></i>学生管理
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="fas fa-money-bill me-2"></i>党费管理
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="fas fa-cog me-2"></i>系统设置
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item mt-5">
|
||||
<a class="nav-link" href="#" id="logoutBtn">
|
||||
<i class="fas fa-sign-out-alt me-2"></i>退出登录
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="col-md-10 main-content">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>仪表板</h2>
|
||||
<div class="user-info">
|
||||
<span id="username"></span>
|
||||
<span class="ms-2">|</span>
|
||||
<span id="role" class="ms-2"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card bg-primary text-white">
|
||||
<h3>总学生数</h3>
|
||||
<h2 id="totalStudents">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card bg-success text-white">
|
||||
<h3>本月缴费</h3>
|
||||
<h2 id="monthlyPayment">¥0</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card bg-warning text-white">
|
||||
<h3>待缴费</h3>
|
||||
<h2 id="pendingPayment">¥0</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-card bg-info text-white">
|
||||
<h3>已缴费</h3>
|
||||
<h2 id="paidAmount">¥0</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最近活动 -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">最近活动</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>时间</th>
|
||||
<th>学生</th>
|
||||
<th>活动</th>
|
||||
<th>金额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="recentActivities">
|
||||
<!-- 动态填充数据 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// 检查登录状态
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
window.location.href = '/login';
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
$.ajax({
|
||||
url: '/api/user',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: function(response) {
|
||||
$('#username').text(response.username);
|
||||
$('#role').text(response.role === 'admin' ? '管理员' : '普通用户');
|
||||
},
|
||||
error: function() {
|
||||
localStorage.removeItem('token');
|
||||
window.location.href = '/login';
|
||||
}
|
||||
});
|
||||
|
||||
// 退出登录
|
||||
$('#logoutBtn').click(function(e) {
|
||||
e.preventDefault();
|
||||
localStorage.removeItem('token');
|
||||
window.location.href = '/login';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,154 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- 声明文档类型为HTML5 -->
|
||||
<html lang="zh-CN">
|
||||
<!-- 指定文档语言为中文 -->
|
||||
<head>
|
||||
<!-- 基础元信息设置 -->
|
||||
<meta charset="UTF-8">
|
||||
<!-- 设置字符编码为UTF-8 -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- 响应式视口设置 -->
|
||||
<title>党费管理系统 - 登录</title>
|
||||
<!-- 页面标题 -->
|
||||
|
||||
<!-- 引入Bootstrap 5 CSS框架 -->
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- 自定义样式 -->
|
||||
<style>
|
||||
/* 页面整体样式 */
|
||||
body {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); /* 渐变背景 */
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/* 登录容器样式 */
|
||||
.login-container {
|
||||
max-width: 400px;
|
||||
margin: 100px auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
/* 系统标题样式 */
|
||||
.login-title {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
/* 表单标签样式 */
|
||||
.form-label {
|
||||
font-weight: 500; /* 中等字重标签 */
|
||||
}
|
||||
/* 登录按钮样式 */
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
background-color: #0d6efd; /* 统一使用Bootstrap主蓝色 */
|
||||
border: none;
|
||||
padding: 12px;
|
||||
color: white;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* 添加轻微阴影 */
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: #0b5ed7; /* 更柔和的悬停色 */
|
||||
color: white;
|
||||
transform: translateY(-1px); /* 悬停微抬效果 */
|
||||
}
|
||||
/* 错误消息样式 */
|
||||
.error-msg {
|
||||
color: #dc3545; /* 错误提示红色 */
|
||||
font-size: 0.9em; /* 较小字号 */
|
||||
margin-top: 5px; /* 顶部边距 */
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="login-container">
|
||||
<h2 class="login-title">党费管理系统</h2>
|
||||
<form id="loginForm">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">用户名</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">密码</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" class="btn btn-primary">登录</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="window.location.href='{{ url_for('register_page') }}'">注册</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 引入jQuery库 -->
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 页面加载完成后执行
|
||||
$(document).ready(function() {
|
||||
// 表单提交处理
|
||||
$('#loginForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// 清除之前的错误信息
|
||||
$('.error-msg').hide();
|
||||
|
||||
// 表单验证
|
||||
let isValid = true;
|
||||
const username = $('#username').val().trim();
|
||||
const password = $('#password').val().trim();
|
||||
|
||||
if (!username) {
|
||||
$('#usernameError').text('请输入用户名').show();
|
||||
isValid = false;
|
||||
}
|
||||
if (!password) {
|
||||
$('#passwordError').text('请输入密码').show();
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// 发送登录请求
|
||||
$.ajax({
|
||||
url: '/login',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
username: username,
|
||||
password: password
|
||||
}),
|
||||
success: function(response) {
|
||||
if (response.status === 'success') {
|
||||
// 登录成功,根据角色跳转
|
||||
if (response.role === 'admin') {
|
||||
window.location.href = '/admin_main';
|
||||
} else {
|
||||
window.location.href = '/user_main';
|
||||
}
|
||||
} else {
|
||||
$('#generalError').text(response.message).show();
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
$('#generalError').text('登录失败,请稍后重试').show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 输入框获得焦点时清除错误信息
|
||||
$('input').on('focus', function() {
|
||||
$(this).siblings('.error-msg').hide();
|
||||
$('#generalError').hide();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,259 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>统计分析</title>
|
||||
<!-- 引入Bootstrap -->
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- 引入Chart.js -->
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
|
||||
<!-- 引入jQuery -->
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
<style>
|
||||
.card { margin-bottom: 20px; }
|
||||
.stats-value { font-size: 1.2em; font-weight: bold; }
|
||||
.chart-container { position: relative; height: 300px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 主容器 -->
|
||||
<div class="container mt-4">
|
||||
<!-- 时间范围选择 -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">时间范围选择</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label>开始日期</label>
|
||||
<input type="date" id="startDate" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label>结束日期</label>
|
||||
<input type="date" id="endDate" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label> </label>
|
||||
<button class="btn btn-primary w-100" onclick="calculateStats()">统计</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 基础统计卡片 -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">基础统计</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p>总记录数:<span class="stats-value" id="totalCount">-</span></p>
|
||||
<p>总金额:<span class="stats-value" id="totalAmount">-</span></p>
|
||||
<p>平均金额:<span class="stats-value" id="avgAmount">-</span></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p>已交齐人数:<span class="stats-value" id="paidCount">-</span></p>
|
||||
<p>未交齐人数:<span class="stats-value" id="unpaidCount">-</span></p>
|
||||
<p>缴纳率:<span class="stats-value" id="paymentRate">-</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未缴纳统计卡片 -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">未缴纳人员统计</div>
|
||||
<div class="card-body">
|
||||
<button class="btn btn-danger mb-3" onclick="getUnpaidList()">统计未缴纳人员</button>
|
||||
<div id="unpaidList" class="mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 按单位统计图表 -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">按单位统计</div>
|
||||
<div class="card-body">
|
||||
<div class="chart-container">
|
||||
<canvas id="unitChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按月统计图表 -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">按月统计</div>
|
||||
<div class="card-body">
|
||||
<div class="chart-container">
|
||||
<canvas id="monthlyChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 图表实例
|
||||
let unitChart = null;
|
||||
let monthlyChart = null;
|
||||
|
||||
// 格式化金额
|
||||
function formatAmount(amount) {
|
||||
return '¥' + amount.toFixed(2);
|
||||
}
|
||||
|
||||
// 时间范围统计函数
|
||||
function calculateStats() {
|
||||
const start = $('#startDate').val();
|
||||
const end = $('#endDate').val();
|
||||
|
||||
if (!start || !end) {
|
||||
alert('请选择开始和结束日期');
|
||||
return;
|
||||
}
|
||||
|
||||
// 请求统计接口
|
||||
$.get(`/api/stats?start=${start}&end=${end}`)
|
||||
.done(data => {
|
||||
// 更新基础统计
|
||||
const basic = data.basic;
|
||||
$('#totalCount').text(basic.total_count);
|
||||
$('#totalAmount').text(formatAmount(basic.total_amount));
|
||||
$('#avgAmount').text(formatAmount(basic.avg_amount));
|
||||
$('#paidCount').text(basic.paid_count);
|
||||
$('#unpaidCount').text(basic.unpaid_count);
|
||||
$('#paymentRate').text(((basic.paid_count / basic.total_count) * 100).toFixed(1) + '%');
|
||||
|
||||
// 更新单位统计图表
|
||||
updateUnitChart(data.by_unit);
|
||||
|
||||
// 更新月度统计图表
|
||||
updateMonthlyChart(data.by_month);
|
||||
})
|
||||
.fail(() => {
|
||||
alert('获取统计数据失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 更新单位统计图表
|
||||
function updateUnitChart(unitData) {
|
||||
const ctx = document.getElementById('unitChart').getContext('2d');
|
||||
|
||||
if (unitChart) {
|
||||
unitChart.destroy();
|
||||
}
|
||||
|
||||
unitChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: unitData.map(item => item.unit),
|
||||
datasets: [{
|
||||
label: '缴纳金额',
|
||||
data: unitData.map(item => item.total_amount),
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return '¥' + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 更新月度统计图表
|
||||
function updateMonthlyChart(monthlyData) {
|
||||
const ctx = document.getElementById('monthlyChart').getContext('2d');
|
||||
|
||||
if (monthlyChart) {
|
||||
monthlyChart.destroy();
|
||||
}
|
||||
|
||||
monthlyChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: monthlyData.map(item => item.month),
|
||||
datasets: [{
|
||||
label: '缴纳金额',
|
||||
data: monthlyData.map(item => item.total_amount),
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
tension: 0.1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return '¥' + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 未缴纳人员统计
|
||||
function getUnpaidList() {
|
||||
$.get('/api/unpaid')
|
||||
.done(data => {
|
||||
let html = `<p>未缴纳人数: ${data.count}</p><ul class="list-group">`;
|
||||
data.users.forEach(user => {
|
||||
html += `<li class="list-group-item">
|
||||
${user.name} (${user.id}) - ${user.unit}
|
||||
</li>`;
|
||||
});
|
||||
html += '</ul>';
|
||||
$('#unpaidList').html(html);
|
||||
})
|
||||
.fail(() => {
|
||||
alert('获取未缴纳人员列表失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 页面加载时设置默认日期范围(当前月份)
|
||||
$(document).ready(function() {
|
||||
const now = new Date();
|
||||
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
|
||||
$('#startDate').val(firstDay.toISOString().split('T')[0]);
|
||||
$('#endDate').val(lastDay.toISOString().split('T')[0]);
|
||||
|
||||
// 自动加载统计数据
|
||||
calculateStats();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,278 @@
|
||||
{
|
||||
"total_issues": 29,
|
||||
"error_count": 0,
|
||||
"warning_count": 29,
|
||||
"info_count": 0,
|
||||
"tools_status": {
|
||||
"pylint": "completed",
|
||||
"flake8": "completed",
|
||||
"bandit": "completed"
|
||||
},
|
||||
"all_issues": [
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 15,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Line too long (153/100)",
|
||||
"rule": "C0301",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 48,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Trailing whitespace",
|
||||
"rule": "C0303",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 51,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Trailing whitespace",
|
||||
"rule": "C0303",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 15,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Constant name \"very_long_variable_name_that_exceeds_the_recommended_line_length_limit\" doesn't conform to UPPER_CASE naming style",
|
||||
"rule": "C0103",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 38,
|
||||
"column": 13,
|
||||
"type": "warning",
|
||||
"message": "Use of eval",
|
||||
"rule": "W0123",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 52,
|
||||
"column": 4,
|
||||
"type": "warning",
|
||||
"message": "Missing function or method docstring",
|
||||
"rule": "C0116",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 46,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Too few public methods (1/2)",
|
||||
"rule": "R0903",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 8,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Unused import os",
|
||||
"rule": "W0611",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 9,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Unused import sys",
|
||||
"rule": "W0611",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 11,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Unused import subprocess",
|
||||
"rule": "W0611",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 12,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Unused urlparse imported from urllib.parse",
|
||||
"rule": "W0611",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 8,
|
||||
"type": "warning",
|
||||
"message": "1: F401 'os' imported but unused",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 9,
|
||||
"type": "warning",
|
||||
"message": "1: F401 'sys' imported but unused",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 11,
|
||||
"type": "warning",
|
||||
"message": "1: F401 'subprocess' imported but unused",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 12,
|
||||
"type": "warning",
|
||||
"message": "1: F401 'urllib.parse.urlparse' imported but unused",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 15,
|
||||
"type": "warning",
|
||||
"message": "80: E501 line too long (153 > 79 characters)",
|
||||
"rule": "80:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 17,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 25,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 31,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 35,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 41,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 46,
|
||||
"type": "warning",
|
||||
"message": "1: E302 expected 2 blank lines, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 48,
|
||||
"type": "warning",
|
||||
"message": "1: W293 blank line contains whitespace",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 51,
|
||||
"type": "warning",
|
||||
"message": "1: W293 blank line contains whitespace",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C",
|
||||
"line": 0,
|
||||
"column": 56,
|
||||
"type": "warning",
|
||||
"message": "1: E305 expected 2 blank lines after class or function definition, found 1",
|
||||
"rule": "1:",
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 11,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Consider possible security implications associated with the subprocess module.",
|
||||
"rule": "B404",
|
||||
"severity": "low",
|
||||
"confidence": "HIGH"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 21,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Possible SQL injection vector through string-based query construction.",
|
||||
"rule": "B608",
|
||||
"severity": "medium",
|
||||
"confidence": "LOW"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 38,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Use of possibly insecure function - consider using safer ast.literal_eval.",
|
||||
"rule": "B307",
|
||||
"severity": "medium",
|
||||
"confidence": "HIGH"
|
||||
},
|
||||
{
|
||||
"file": "C:\\Users\\51736\\AppData\\Local\\Temp\\tmpj1y1hh_8\\test_sample.py",
|
||||
"line": 43,
|
||||
"column": 0,
|
||||
"type": "warning",
|
||||
"message": "Possible hardcoded password: 'admin123'",
|
||||
"rule": "B105",
|
||||
"severity": "low",
|
||||
"confidence": "MEDIUM"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,5 @@
|
||||
Flask==2.3.3
|
||||
Flask-CORS==4.0.0
|
||||
PyMySQL==1.1.0
|
||||
GitPython==3.1.40
|
||||
Werkzeug==2.3.7
|
||||
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">×</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
Loading…
Reference in new issue