添加前端代码

guoning
g_miss_n 2 months ago
parent 0c5fb9f7e4
commit 55d117d840

@ -0,0 +1,151 @@
# 代码检查功能使用说明
## 功能概述
FortifyCode 系统现在支持真实的代码质量检查集成了三个主要的Python代码分析工具
- **pylint**: 代码质量分析工具
- **flake8**: 代码风格检查工具
- **bandit**: 安全漏洞检测工具
## 使用方法
### 1. 启动系统
```bash
# 启动后端服务
cd FortifyCode/backend
python app.py
# 访问前端界面
# 打开浏览器访问 http://localhost:5000
```
### 2. 上传代码文件
1. 在仪表板页面,点击"拖拽文件到此处或点击上传"区域
2. 选择要检查的Python文件支持 .py, .pyx, .pyi 格式)
3. 系统会显示已选择的文件数量
### 3. 开始检查
1. 点击"开始检查"按钮
2. 系统会显示检查进度:
- 正在上传文件...
- 开始代码检查...
- 处理检查结果...
- 检查完成!
### 4. 查看结果
检查完成后,系统会显示:
- **结果摘要**: 显示错误、警告、信息的总数统计
- **问题列表**: 详细列出每个发现的问题
- **工具状态**: 显示各个Agentpylint、flake8、bandit的执行状态
### 5. 问题详情
对于每个发现的问题,可以:
- **查看详情**: 点击"查看详情"按钮查看问题的详细信息
- **修复建议**: 点击"修复建议"按钮获取具体的修复建议
## 检查规则
### pylint 检查项
- 代码风格问题
- 潜在的逻辑错误
- 代码复杂度
- 命名规范
### flake8 检查项
- 行长度限制
- 导入顺序
- 未使用的变量
- 语法错误
### bandit 检查项
- SQL注入风险
- 硬编码密码
- 不安全的函数调用
- 安全配置问题
## 项目管理功能
### 新建项目
1. 在项目管理页面点击"新建项目"按钮
2. 填写项目信息:
- 项目名称(必填)
- 项目描述(可选)
- 项目来源GitHub、Gitee 或文件上传
- 如果选择 Git 来源,需要提供仓库 URL
3. 点击"创建项目"完成创建
### 删除项目
1. 在项目卡片上点击"删除"按钮
2. 在项目详情页面点击"删除项目"按钮
3. 确认删除操作(此操作不可撤销)
4. 系统将删除:
- 项目信息和配置
- 所有检查历史记录
- 所有检查结果数据
- 项目本地文件
### 项目操作
- **查看详情**:点击项目卡片或"查看详情"按钮
- **运行检查**:在项目列表或详情页面点击"运行检查"按钮
- **搜索项目**:使用搜索框按项目名称或描述搜索
### 文件管理功能
#### 文件浏览器
在项目详情页面,您可以:
- **浏览文件**:点击文件夹进入目录,点击文件打开编辑
- **查看文件信息**:显示文件大小、修改时间等信息
- **文件类型识别**:不同文件类型显示不同颜色的图标
#### 代码编辑器
- **打开文件**:点击文件即可在编辑器中打开
- **编辑代码**:支持语法高亮和实时编辑
- **保存文件**:使用 Ctrl+S 快捷键或点击保存按钮
- **关闭编辑器**:点击关闭按钮(如有未保存更改会提示)
#### 文件操作
- **上传文件**:点击"上传文件"按钮选择本地文件上传
- **新建文件**:点击"新建文件"按钮创建新文件
- **新建文件夹**:点击"新建文件夹"按钮创建新目录
- **下载文件**通过API直接下载项目文件
#### 支持的编辑功能
- 实时文件内容编辑
- 自动保存提示
- 键盘快捷键支持Ctrl+S 保存)
- 文件修改状态跟踪
- 多文件类型支持Python、JavaScript、CSS、HTML等
## 测试文件
系统包含一个测试文件 `test_sample.py`,其中包含各种常见的代码问题,可以用来测试检查功能。
## 注意事项
1. 确保系统已安装所需的Python包
```bash
pip install pylint flake8 bandit
```
2. 检查过程可能需要一些时间,特别是对于大型项目
3. 检查结果会保存到 `reports/` 目录下,文件名格式为 `check_{check_id}_{timestamp}.json`
4. 临时上传的文件会在检查完成后自动清理
## 故障排除
如果检查失败,请检查:
1. 后端服务是否正常运行
2. 是否安装了所有必需的Python包
3. 上传的文件是否为有效的Python文件
4. 查看浏览器控制台的错误信息

@ -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** - 让代码更安全,让开发更放心 🛡️

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;

@ -0,0 +1,69 @@
# 党费管理系统
这是一个基于Flask的党费管理系统用于管理党员的党费缴纳情况。
## 功能特点
- 用户登录和权限管理
- 党费记录管理(添加、修改、删除)
- 数据统计和分析
- 数据导入导出
- 响应式界面设计
## 系统要求
- Python 3.7+
- MySQL 5.7+
- 现代浏览器Chrome、Firefox、Safari等
## 安装步骤
1. 克隆项目到本地
2. 创建虚拟环境:
```bash
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
```
3. 安装依赖:
```bash
pip install -r requirements.txt
```
4. 创建数据库:
```bash
mysql -u root -p < manage.sql
```
5. 修改数据库配置:
在server.py中修改DB_CONFIG配置
## 运行系统
```bash
python server.py
```
访问 http://localhost:5000 即可使用系统
## 默认账号
- 管理员账号admin
- 密码a123
## 使用说明
1. 管理员功能:
- 管理所有用户的党费记录
- 查看统计数据
- 导入导出数据
- 管理用户信息
2. 普通用户功能:
- 查看个人党费记录
- 修改个人信息
- 查看缴费状态
## 注意事项
- 请定期备份数据库
- 及时更新系统密码
- 定期检查系统日志

@ -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,692 @@
# Flask框架相关模块导入
from flask import (
Flask, # Flask应用主类用于创建Web应用实例
request, # 请求对象,用于获取客户端请求数据
jsonify, # 将Python对象转换为JSON响应
render_template,# 渲染HTML模板
session, # 会话管理,用于存储用户会话数据
redirect, # 重定向响应
url_for # 生成URL
)
# Flask-CORS用于处理跨域请求
from flask_cors import CORS
# PyMySQL用于MySQL数据库连接和操作
import pymysql
# json模块用于JSON数据处理
import json
# datetime用于处理日期和时间
from datetime import datetime
# os模块用于操作系统相关功能
import os
# functools.wraps用于保留被装饰函数的元数据
from functools import wraps
# decimal模块用于处理Decimal类型
import decimal
# 创建Flask应用实例
app = Flask(__name__)
# 启用CORS支持允许跨域请求
CORS(app)
# 设置会话密钥用于加密session数据
app.secret_key = os.urandom(24)
# 数据库连接配置
DB_CONFIG = {
'host': 'localhost', # 数据库主机地址
'user': 'root', # 数据库用户名
'password': '123456', # 数据库密码
'db': 'df2_0', # 数据库名称
'charset': 'utf8mb4' # 字符集设置,支持中文
}
# 获取数据库连接的函数
def get_db():
"""
创建并返回数据库连接
使用PyMySQL连接MySQL数据库
"""
return pymysql.connect(**DB_CONFIG)
# 登录验证装饰器
def login_required(f):
"""
登录验证装饰器
用于保护需要登录才能访问的路由
"""
@wraps(f) # 保留被装饰函数的元数据
def decorated_function(*args, **kwargs):
# 检查session中是否存在user_id
if 'user_id' not in session:
# 如果未登录,重定向到登录页面
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
# 根路径路由处理
@app.route('/')
def index():
"""
根路径处理函数
根据用户登录状态和角色重定向到相应页面
"""
if 'user_id' in session:
if session['role'] == 'admin':
return redirect(url_for('admin_main'))
else:
return redirect(url_for('user_main'))
return redirect(url_for('login'))
# 登录路由处理
@app.route('/login', methods=['GET', 'POST'])
def login():
"""
登录处理函数
GET: 返回登录页面
POST: 处理登录请求
"""
if request.method == 'GET':
return render_template('login.html')
try:
# 获取POST请求中的JSON数据
data = request.get_json()
if not data:
return jsonify({'status': 'error', 'message': '无效的请求数据'}), 400
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({'status': 'error', 'message': '用户名和密码不能为空'}), 400
# 连接数据库验证用户信息
conn = get_db()
try:
with conn.cursor() as cursor:
# 使用参数化查询防止SQL注入
sql = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(sql, (username, password))
user = cursor.fetchone()
if user:
# 登录成功设置session
session['user_id'] = user[0] # 用户ID
session['role'] = user[6] # 用户角色
return jsonify({'status': 'success', 'role': user[6]})
return jsonify({'status': 'error', 'message': '用户名或密码错误'}), 401
finally:
conn.close()
except Exception as e:
print(f"Login error: {e}")
return jsonify({'status': 'error', 'message': '服务器内部错误'}), 500
# 注册页面路由
@app.route('/register', methods=['GET'])
def register_page():
"""
渲染注册页面
"""
return render_template('register.html')
# 处理注册请求的API
@app.route('/api/register', methods=['POST'])
def register_user():
"""
处理用户注册请求
将新用户添加到数据库
"""
data = request.get_json()
username = data.get('username')
password = data.get('password')
name = data.get('name')
gender = data.get('gender')
unit = data.get('unit')
role = data.get('role', 'user') # 默认角色为user
# 简单的数据验证
if not all([username, password, name, gender, unit, role]):
return jsonify({'status': 'error', 'message': '所有字段均为必填项'}), 400
conn = get_db()
try:
with conn.cursor() as cursor:
# 检查用户名是否已存在
sql_check_user = "SELECT id FROM users WHERE username = %s"
cursor.execute(sql_check_user, (username,))
existing_user = cursor.fetchone()
if existing_user:
return jsonify({'status': 'error', 'message': f'用户名 "{username}" 已存在'}), 409 # 409 Conflict
# 插入新用户到 users 表
# 注意:这里直接存储明文密码,生产环境中应使用密码哈希函数
sql_insert_user = """INSERT INTO users (username, password, name, gender, unit, role)
VALUES (%s, %s, %s, %s, %s, %s)"""
cursor.execute(sql_insert_user, (username, password, name, gender, unit, role))
conn.commit()
return jsonify({'status': 'success', 'message': '用户注册成功'}), 201 # 201 Created
except pymysql.Error as e:
conn.rollback()
print(f"Database error during registration: {e}")
return jsonify({'status': 'error', 'message': f'数据库错误: {e}'}), 500
except Exception as e:
conn.rollback()
print(f"An unexpected error occurred during registration: {e}")
return jsonify({'status': 'error', 'message': f'服务器内部错误: {e}'}), 500
finally:
conn.close()
# 管理员主页路由
@app.route('/admin_main')
@login_required
def admin_main():
"""
管理员主页处理函数
验证用户是否为管理员
"""
if session['role'] != 'admin':
return redirect(url_for('user_main'))
return render_template('admin_main.html')
# 新增党费记录页面路由
@app.route('/add_record')
@login_required
def add_record_page():
"""
渲染新增党费记录页面
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403 # 返回403 Forbidden
return render_template('add.html')
# 编辑党费记录页面路由
@app.route('/revise')
@login_required
def revise_page():
"""
渲染新增党费记录页面
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403 # 返回403 Forbidden
return render_template('revise.html')
# 用户主页路由
@app.route('/user_main')
@login_required #登陆验证
def user_main():
"""
普通用户主页处理函数
"""
return render_template('user_main.html')
# 用户详情页路由
@app.route('/user_detail')
@login_required #登陆验证
def user_detail():
"""
普通用户详情页处理函数
"""
return render_template('user_detail.html')
# 获取用户信息的API
@app.route('/api/user', methods=['GET'])
@login_required
def get_user_info():
"""
获取当前登录用户信息的API
返回用户详细信息
"""
if 'user_id' not in session:
return jsonify({'error': '未登录'}), 401
try:
conn = get_db()
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
sql = "SELECT * FROM users WHERE id = %s"
cursor.execute(sql, (session['user_id'],))
user = cursor.fetchone()
if not user:
return jsonify({'error': '用户不存在'}), 404
return jsonify(user)
finally:
if conn:
conn.close()
# 获取党费记录列表的API
@app.route('/api/dues', methods=['GET'])
@login_required
def get_dues():
"""
获取党费记录列表的API
管理员可查看所有记录普通用户只能查看自己的记录
支持按日期范围筛选
"""
conn = get_db()
try:
start_date = request.args.get('start')
end_date = request.args.get('end')
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
if session['role'] == 'admin':
base_sql = "SELECT d.*, u.name, u.unit, u.gender FROM dues d JOIN users u ON d.user_id = u.id"
params = []
if start_date and end_date:
base_sql += " WHERE payment_date BETWEEN %s AND %s"
params = [start_date, end_date]
cursor.execute(base_sql, params)
else:
base_sql = "SELECT d.*, u.name, u.unit, u.gender FROM dues d JOIN users u ON d.user_id = u.id WHERE d.user_id = %s"
params = [session['user_id']]
if start_date and end_date:
base_sql += " AND payment_date BETWEEN %s AND %s"
params.extend([start_date, end_date])
cursor.execute(base_sql, params)
dues = cursor.fetchall()
# 转换 Decimal 类型为 float使其可 JSON 序列化
for row in dues:
for key, value in row.items():
if isinstance(value, decimal.Decimal): # 检查是否是Decimal类型
row[key] = float(value) # 转换为float
return jsonify(dues)
except Exception as e:
print(f"Error fetching dues: {e}")
# 返回一个包含错误信息的 JSON 响应,并附带适当的状态码
return jsonify({'status': 'error', 'message': '获取党费记录失败'}), 500
finally:
conn.close()
# 添加党费记录的API
@app.route('/api/dues', methods=['POST'])
@login_required
def add_due():
"""
添加党费记录的API
仅管理员可操作
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403 # 返回403 Forbidden
data = request.get_json()
user_id = data.get('userId')
due_amount = data.get('dueAmount')
actual_amount = data.get('actualAmount')
payment_type = data.get('paymentType')
payment_date = data.get('paymentDate')
remark = data.get('remark', '')
# 验证必填字段
if not all([user_id, due_amount, actual_amount, payment_type, payment_date is not None]): # 确保payment_date不为None
return jsonify({'status': 'error', 'message': '缺少必填字段'}), 400 # 返回400 Bad Request
# 验证金额是有效的数字
try:
due_amount = float(due_amount)
actual_amount = float(actual_amount)
if due_amount < 0 or actual_amount < 0:
return jsonify({'status': 'error', 'message': '金额不能为负数'}), 400
except ValueError:
return jsonify({'status': 'error', 'message': '金额格式不正确'}), 400
# 验证payment_date格式 (可选,取决于前端发送的格式)
try:
datetime.strptime(payment_date, '%Y-%m-%d') # 假设前端发送的是'YYYY-MM-DD'格式
except ValueError:
return jsonify({'status': 'error', 'message': '日期格式不正确应为YYYY-MM-DD'}), 400
conn = get_db()
try:
with conn.cursor() as cursor:
# 1. 验证用户是否存在
sql_check_user = "SELECT id FROM users WHERE id = %s"
cursor.execute(sql_check_user, (user_id,))
user_exists = cursor.fetchone()
if not user_exists:
return jsonify({'status': 'error', 'message': f'用户ID {user_id} 不存在'}), 404 # 返回404 Not Found
# 2. 计算状态
status = '已交齐' if actual_amount >= due_amount else '未交齐'
# 3. 插入党费记录
sql_insert_due = """INSERT INTO dues (user_id, due_amount, actual_amount, payment_type,
payment_date, status, remark) VALUES (%s, %s, %s, %s, %s, %s, %s)"""
cursor.execute(sql_insert_due, (
user_id,
due_amount,
actual_amount,
payment_type,
payment_date,
status,
remark
))
conn.commit()
return jsonify({'status': 'success', 'message': '党费记录添加成功'}), 201 # 返回201 Created
except pymysql.Error as e:
conn.rollback() # 发生错误回滚事务
print(f"Database error: {e}")
return jsonify({'status': 'error', 'message': f'数据库错误: {e}'}), 500 # 返回500 Internal Server Error
except Exception as e:
conn.rollback()
print(f"An unexpected error occurred: {e}")
return jsonify({'status': 'error', 'message': f'服务器内部错误: {e}'}), 500
finally:
conn.close()
#删除党费记录的API
@app.route('/api/dues/<int:due_id>', methods=['DELETE'])
@login_required
def delete_due(due_id):
"""
修改党费记录的API
仅管理员可操作
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'})
data = request.get_json()
conn = get_db()
try:
with conn.cursor() as cursor:
sql = """DELETE FROM dues WHERE id = %s"""
cursor.execute(sql, (due_id))
conn.commit()
return jsonify({'status': 'success'})
finally:
conn.close()
# 修改党费记录的API
@app.route('/api/dues/<int:due_id>', methods=['PUT'])
@login_required
def update_due(due_id):
"""
修改党费记录的API
仅管理员可操作
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'})
data = request.get_json()
conn = get_db()
try:
with conn.cursor() as cursor:
sql = """UPDATE dues SET due_amount = %s, actual_amount = %s,
payment_type = %s, payment_date = %s, status = %s, remark = %s
WHERE id = %s"""
cursor.execute(sql, (
data['dueAmount'],
data['actualAmount'],
data['paymentType'],
data['paymentDate'],
'已交齐' if data['actualAmount'] >= data['dueAmount'] else '未交齐',
data.get('remark', ''),
due_id
))
conn.commit()
return jsonify({'status': 'success'})
finally:
conn.close()
# 获取统计数据的API
@app.route('/api/stats', methods=['GET'])
@login_required
def get_stats():
"""
获取统计数据的API
仅管理员可访问
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403
start_date = request.args.get('start')
end_date = request.args.get('end')
conn = get_db()
try:
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
# 基础统计
sql = """
SELECT
COUNT(*) as total_count,
SUM(actual_amount) as total_amount,
AVG(actual_amount) as avg_amount,
COUNT(CASE WHEN status = '已交齐' THEN 1 END) as paid_count,
COUNT(CASE WHEN status = '未交齐' THEN 1 END) as unpaid_count
FROM dues
WHERE payment_date BETWEEN %s AND %s
"""
cursor.execute(sql, (start_date, end_date))
basic_stats = cursor.fetchone()
# 按单位统计
sql = """
SELECT
u.unit,
COUNT(*) as count,
SUM(d.actual_amount) as total_amount,
COUNT(CASE WHEN d.status = '已交齐' THEN 1 END) as paid_count
FROM dues d
JOIN users u ON d.user_id = u.id
WHERE d.payment_date BETWEEN %s AND %s
GROUP BY u.unit
"""
cursor.execute(sql, (start_date, end_date))
unit_stats = cursor.fetchall()
# 按月份统计
sql = """
SELECT
DATE_FORMAT(payment_date, '%%Y-%%m') as month,
COUNT(*) as count,
SUM(actual_amount) as total_amount
FROM dues
WHERE payment_date BETWEEN %s AND %s
GROUP BY DATE_FORMAT(payment_date, '%%Y-%%m')
ORDER BY month
"""
cursor.execute(sql, (start_date, end_date))
monthly_stats = cursor.fetchall()
# 转换 Decimal 类型为 float
for key, value in basic_stats.items():
if isinstance(value, decimal.Decimal):
basic_stats[key] = float(value)
for stat in unit_stats:
for key, value in stat.items():
if isinstance(value, decimal.Decimal):
stat[key] = float(value)
for stat in monthly_stats:
for key, value in stat.items():
if isinstance(value, decimal.Decimal):
stat[key] = float(value)
return jsonify({
'basic': basic_stats,
'by_unit': unit_stats,
'by_month': monthly_stats
})
except Exception as e:
print(f"Error fetching stats: {e}")
return jsonify({'status': 'error', 'message': '获取统计数据失败'}), 500
finally:
conn.close()
# 获取未缴纳人员列表的API
@app.route('/api/unpaid', methods=['GET'])
@login_required
def get_unpaid():
"""
获取未缴纳人员列表的API
仅管理员可访问
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'})
conn = get_db()
try:
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
sql = """SELECT u.* FROM users u
LEFT JOIN dues d ON u.id = d.user_id
WHERE d.id IS NULL OR d.status = '未交齐'"""
cursor.execute(sql)
users = cursor.fetchall()
return jsonify({'count': len(users), 'users': users})
finally:
conn.close()
# 导入数据的API
@app.route('/api/import', methods=['POST'])
@login_required
def import_data():
"""
批量导入党费数据的API
仅管理员可操作
通过姓名匹配用户ID
"""
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'})
data = request.get_json()
if not data or not isinstance(data, list):
return jsonify({'status': 'error', 'message': '无效的导入数据格式'})
conn = get_db()
try:
with conn.cursor() as cursor:
# 创建用户姓名到ID的映射
cursor.execute("SELECT id, name FROM users")
user_map = {row[1]: row[0] for row in cursor.fetchall()}
success_count = 0
failed_records = []
for idx, item in enumerate(data):
try:
# 验证必要字段
if not all(k in item for k in ['name', 'date', 'due', 'actual']):
failed_records.append(f"{idx+1}行: 缺少必要字段")
continue
# 获取用户ID
user_id = user_map.get(item['name'])
if not user_id:
failed_records.append(f"{idx+1}行: 用户'{item['name']}'不存在")
continue
# 验证数据格式
due_amount = float(item['due'])
actual_amount = float(item['actual'])
if due_amount < 0 or actual_amount < 0:
failed_records.append(f"{idx+1}行: 金额不能为负数")
continue
# 验证日期格式
try:
datetime.strptime(item['date'], '%Y-%m-%d')
except ValueError:
failed_records.append(f"{idx+1}行: 日期格式不正确应为YYYY-MM-DD")
continue
# 插入记录
status = '已交齐' if actual_amount >= due_amount else '未交齐'
sql = """INSERT INTO dues (user_id, due_amount, actual_amount,
payment_type, payment_date, status)
VALUES (%s, %s, %s, 'monthly', %s, %s)"""
cursor.execute(sql, (
user_id,
due_amount,
actual_amount,
item['date'],
status
))
success_count += 1
except Exception as e:
failed_records.append(f"{idx+1}行: 处理失败 - {str(e)}")
conn.commit()
result = {
'status': 'success',
'success_count': success_count,
'failed_count': len(failed_records)
}
if failed_records:
result['failed_details'] = failed_records
return jsonify(result)
finally:
conn.close()
# 退出登录路由
@app.route('/logout')
def logout():
"""
退出登录处理函数
清除session数据并重定向到登录页面
"""
session.clear()
return redirect(url_for('login'))
# 统计分析页面路由
@app.route('/stats')
@login_required
def stats_page():
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403
return render_template('stats.html')
# 数据导入/导出页面路由
@app.route('/data_handle')
@login_required
def data_handle_page():
if session['role'] != 'admin':
return jsonify({'status': 'error', 'message': '权限不足'}), 403
return render_template('data_handle.html')
# 获取单条党费记录的API
@app.route('/api/dues/<int:due_id>', methods=['GET'])
@login_required
def get_due(due_id):
"""
获取单条党费记录的API
管理员可查看所有记录普通用户只能查看自己的记录
"""
conn = get_db()
try:
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
if session['role'] == 'admin':
sql = """SELECT d.*, u.name, u.unit, u.gender
FROM dues d
JOIN users u ON d.user_id = u.id
WHERE d.id = %s"""
cursor.execute(sql, (due_id,))
else:
sql = """SELECT d.*, u.name, u.unit, u.gender
FROM dues d
JOIN users u ON d.user_id = u.id
WHERE d.id = %s AND d.user_id = %s"""
cursor.execute(sql, (due_id, session['user_id']))
due = cursor.fetchone()
if not due:
return jsonify({'status': 'error', 'message': '记录不存在'}), 404
# 转换 Decimal 类型为 float
for key, value in due.items():
if isinstance(value, decimal.Decimal):
due[key] = float(value)
return jsonify(due)
except Exception as e:
print(f"Error fetching due record: {e}")
return jsonify({'status': 'error', 'message': '获取记录失败'}), 500
finally:
conn.close()
# 主程序入口
if __name__ == '__main__':
# 启动Flask应用开启调试模式
app.run(debug=True)

@ -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,252 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数据导入导出</title>
<!-- 引入Bootstrap样式表 -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<style>
/* 定义操作区样式 */
.section-box {
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
}
/* 定义表格滚动容器 */
.preview-table {
max-height: 400px;
overflow-y: auto;
}
/* 定义数据错误高亮样式 */
.highlight {
background-color: #fff3cd !important;
}
</style>
</head>
<body>
<div class="container py-4">
<!-- 导出操作区 -->
<div class="section-box">
<h4 class="mb-4">数据导出</h4>
<!-- 时间选择组件 -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<label>开始日期</label>
<input type="date" id="exportStart" class="form-control">
</div>
<div class="col-md-3">
<label>结束日期</label>
<input type="date" id="exportEnd" class="form-control">
</div>
<div class="col-md-2">
<!-- 查询按钮 -->
<button class="btn btn-primary mt-4" onclick="loadExportData()">查询</button>
</div>
</div>
<!-- 导出数据表格 -->
<div class="preview-table">
<table class="table table-hover">
<thead>
<tr>
<!-- 全选复选框 -->
<th>
<input type="checkbox" id="exportSelectAll">
</th>
<th>姓名</th>
<th>缴费日期</th>
<th>应缴金额</th>
<th>实缴金额</th>
<th>状态</th>
</tr>
</thead>
<tbody id="exportDataBody"></tbody>
</table>
</div>
<!-- 导出选中数据按钮 -->
<button class="btn btn-success mt-3" onclick="exportSelected()">
<i class="fas fa-download me-2"></i>导出选中数据
</button>
</div>
<!-- 导入操作区 -->
<div class="section-box">
<h4 class="mb-4">数据导入</h4>
<!-- CSV文件上传组件 -->
<div class="mb-4">
<input type="file" id="csvInput" class="form-control" accept=".csv">
<small class="text-muted">请选择CSV格式文件字段顺序姓名,缴费日期,应缴金额,实缴金额</small>
</div>
<!-- 导入数据预览表格 -->
<div class="preview-table">
<table class="table" id="importPreview">
<thead>
<tr>
<th>姓名</th>
<th>缴费日期</th>
<th>应缴金额</th>
<th>实缴金额</th>
<th>状态</th>
</tr>
</thead>
<tbody id="importDataBody"></tbody>
</table>
</div>
<!-- 确认导入按钮 -->
<button class="btn btn-primary mt-3" onclick="confirmImport()">
<i class="fas fa-upload me-2"></i>确认导入
</button>
</div>
</div>
<!-- 引入jQuery库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script>
// 定义导出数据存储数组
let exportData = [];
// 定义导入数据存储数组
let importData = [];
// 加载导出数据函数
function loadExportData() {
const start = $('#exportStart').val();
const end = $('#exportEnd').val();
// 发送AJAX请求获取数据
$.get(`/api/dues?start=${start}&end=${end}`, data => {
exportData = data;
renderExportTable(data);
});
}
// 渲染导出数据表格函数
function renderExportTable(data) {
const tbody = $('#exportDataBody').empty();
data.forEach(item => {
// 根据实缴金额判断状态
const status = item.actual >= item.due ?
'已交齐' : '未交齐';
// 动态生成表格行
tbody.append(`
<tr>
<td><input type="checkbox" class="export-check"></td>
<td>${item.name}</td>
<td>${item.payment_date}</td>
<td>${item.due_amount}</td>
<td>${item.actual_amount}</td>
<td>${status}</td>
</tr>
`);
});
}
// 全选功能实现
$('#exportSelectAll').change(function() {
$('.export-check').prop('checked', this.checked);
});
// 导出选中数据函数
function exportSelected() {
const selected = [];
$('.export-check:checked').each(function() {
const index = $(this).closest('tr').index();
selected.push(exportData[index]);
});
if(selected.length === 0) return alert('请选择要导出的记录');
// 生成CSV内容
const csvContent = [
['姓名', '缴费日期', '应缴金额', '实缴金额', '状态'].join(','),
...selected.map(item => [
`"${item.name}"`,
item.payment_date,
item.due_amount,
item.actual_amount,
item.actual >= item.due ? '已交齐' : '未交齐'
].join(','))
].join('\n');
// 创建下载链接
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `党费数据_${new Date().toISOString().slice(0,10)}.csv`;
link.click();
}
// CSV文件解析函数
$('#csvInput').change(function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
const text = e.target.result;
importData = parseCSV(text);
renderImportPreview(importData);
};
reader.readAsText(file, 'UTF-8');
});
// CSV解析逻辑
function parseCSV(text) {
const rows = text.split('\n').filter(row => row.trim() !== '');
return rows.slice(1).map(row => {
const [name, date, due, actual] = row.split(',').map(f => f.replace(/"/g, ''));
return {
name: name.trim(),
date: date.trim(),
due: parseFloat(due),
actual: parseFloat(actual)
};
});
}
// 渲染导入预览表格
function renderImportPreview(data) {
const tbody = $('#importDataBody').empty();
data.forEach(item => {
const isValid = !isNaN(item.due) && !isNaN(item.actual);
tbody.append(`
<tr class="${isValid ? '' : 'table-danger'}">
<td>${item.name}</td>
<td>${item.date}</td>
<td>${item.due}</td>
<td>${item.actual}</td>
<td>${isValid ? '有效' : '数据错误'}</td>
</tr>
`);
});
}
// 确认导入函数
function confirmImport() {
const validData = importData.filter(item =>
!isNaN(item.due) && !isNaN(item.actual));
if(validData.length === 0) return alert('没有有效数据可导入');
// 发送导入请求
$.ajax({
url: '/api/import',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(validData),
success: () => {
alert(`成功导入${validData.length}条记录`);
$('#csvInput').val('');
$('#importDataBody').empty();
}
});
}
</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,183 @@
<!DOCTYPE html>
<html lang="zh-CN">
<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">
<style>
body {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); /* 与登录页统一渐变背景 */
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.register-container {
max-width: 500px;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.system-title {
color: #c00;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
.form-label {
font-weight: 500;
}
.register-btn {
width: 100%;
background-color: #0d6efd; /* 统一使用Bootstrap主蓝色 */
border: none;
padding: 12px;
color: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* 添加阴影 */
}
.register-btn: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="register-container">
<h2 class="system-title">用户注册</h2>
<form id="registerForm">
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" name="username" required>
<div id="usernameError" class="error-msg"></div>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" required>
<div id="passwordError" class="error-msg"></div>
</div>
<div class="mb-3">
<label for="name" class="form-label">姓名</label>
<input type="text" class="form-control" id="name" name="name" required>
<div id="nameError" class="error-msg"></div>
</div>
<div class="mb-3">
<label class="form-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 id="genderError" class="error-msg"></div>
</div>
<div class="mb-3">
<label for="unit" class="form-label">单位</label>
<input type="text" class="form-control" id="unit" name="unit" required>
<div id="unitError" class="error-msg"></div>
</div>
<div class="mb-3">
<label for="role" class="form-label">角色</label>
<select class="form-select" id="role" name="role" required>
<option value="">请选择</option>
<option value="user">普通用户</option>
<option value="admin">管理员</option> {#-- 管理员角色通常应限制注册 --#}
</select>
<div id="roleError" class="error-msg"></div>
</div>
<div class="mb-3">
<label for="name" class="form-label">联系方式</label>
<input type="text" class="form-control" id="contact" name="contact" required>
<div id="contactError" class="error-msg"></div>
</div>
<div class="d-grid mb-3">
<button type="submit" class="btn register-btn">注册</button>
</div>
<div class="text-center">
<a href="{{ url_for('login') }}">已有账号?去登录</a>
</div>
<!-- 通用错误消息显示区域 -->
<div id="generalError" class="error-msg mt-3"></div>
</form>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#registerForm').on('submit', function(e) {//为submit事件绑定一个函数
e.preventDefault();//阻止submit事件的默认行为刷新或跳转页面
$('.error-msg').hide();
let isValid = true;//let声明块级变量isValid只在花括号内有效用于标记表单验证通过
const username = $('#username').val().trim();//读取id=username的输入框内的内容.trim删除字符串的无用字符如首尾的空格、换行符
const password = $('#password').val().trim();
const name = $('#name').val().trim();
const gender = $('input[name="gender"]:checked').val();
const unit = $('#unit').val().trim();
const role = $('#role').val();
const contact = $('#contact').val().trim();
//验证
if (!username) { $('#usernameError').text('请输入用户名').show(); isValid = false; }
if (!password) { $('#passwordError').text('请输入密码').show(); isValid = false; }
if (!name) { $('#nameError').text('请输入姓名').show(); isValid = false; }
if (!gender) { $('#genderError').text('请选择性别').show(); isValid = false; }
if (!unit) { $('#unitError').text('请输入单位').show(); isValid = false; }
if (!role) { $('#roleError').text('请选择角色').show(); isValid = false; }
if (!contact) { $('#contact').text('请输入联系方式').show; isValid = false; }
if (!isValid) return;//任何一项验证不通过,则终止表单提交
$.ajax({//jQuery库下面是连接配置
url: '/api/register',//后端接口的路径
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
username: username,
password: password,
name: name,
gender: gender,
unit: unit,
role: role,
contact: contact
}),
success: function(response) {//response 是服务器返回的解析后的 JSON 数据。
if (response.status === 'success') {
alert('注册成功!请返回登录页面。');
window.location.href = "{{ url_for('login') }}"; // 注册成功后跳转到登录页
} else {
$('#generalError').text(response.message).show();
}
},
error: function(xhr) {//xhr是XMLHttpRequest 对象
const errorMsg = xhr.responseJSON?.message || '注册失败,请稍后重试';//.?操作符解释:如果 xhr.responseJSON 为 null 或 undefined例如服务器未返回 JSON直接访问 xhr.responseJSON.message 会报错,但 ?. 会返回 undefined 而不报错。
$('#generalError').text(errorMsg).show();
}
});
});
$('input, select').on('focus', function() {//选择所有input、select元素绑定focus事件用户点击或Tab到输入框时触发
$(this).siblings('.error-msg').hide();
$(this).parent().siblings('.error-msg').hide(); // For radio buttons
$('#generalError').hide();
});
});
</script>
</body>
</html>

@ -0,0 +1,201 @@
<!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样式 -->
<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; /* 上下边距2rem水平居中 */
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="editForm">
<!-- 隐藏域存储原始ID -->
<input type="hidden" id="originalId">
<!-- 姓名输入 -->
<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>
<!-- 引入jQuery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script>
// 页面加载完成后执行
$(document).ready(function() {
// 从URL参数获取记录ID
const urlParams = new URLSearchParams(window.location.search);
const recordId = urlParams.get('id');
if (!recordId) { // 如果缺少ID参数
alert('无效的记录ID');
goBack();
return;
}
// 加载原始记录数据
$.get(`/api/dues/${recordId}`)
.done(data => {
// 填充表单数据
$('#originalId').val(data.id); // 存储原始ID
$('#name').val(data.name);
$('#userId').val(data.user_id);
$(`input[name='gender'][value='${data.gender}']`).prop('checked', true);
$('#unit').val(data.unit);
$('#dueAmount').val(data.due_amount);
$('#actualAmount').val(data.actual_amount);
$('#paymentType').val(data.payment_type);
$('#paymentDate').val(data.payment_date.split('T')[0]); // 转换日期格式
$('#remark').val(data.remark);
})
.fail(() => {
alert('加载记录失败');
goBack();
});
});
// 返回管理主页
function goBack() {
window.location.href = "/admin_main";
}
// 表单提交处理
$('#editForm').submit(function(e) {
e.preventDefault(); // 阻止默认提交行为
// 获取表单数据
const formData = {
dueAmount: parseFloat($('#dueAmount').val()),
actualAmount: parseFloat($('#actualAmount').val()),
paymentType: $('#paymentType').val(),
paymentDate: $('#paymentDate').val(),
remark: $('#remark').val()
};
// 验证实缴金额
if (formData.actualAmount < 0) {
alert('实缴金额不能为负数');
return;
}
// 发送更新请求
$.ajax({
url: `/api/dues/${$('#originalId').val()}`,
method: 'PUT',
contentType: 'application/json',
data: JSON.stringify(formData),
success: () => {
alert('修改成功!');
goBack();
},
error: (xhr) => {
alert(`修改失败:${xhr.responseJSON?.message || '服务器错误'}`);
}
});
});
// 金额输入验证
$('#dueAmount, #actualAmount').on('input', function() {
let value = parseFloat($(this).val());
if (value < 0) $(this).val(0); //
if ($(this).val() > 1000000) $(this).val(1000000); // 限制最大值
});
</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>&nbsp;</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>

@ -0,0 +1,152 @@
<!DOCTYPE html>
<html>
<head>
<title>用户详情</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入Bootstrap和jQuery -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<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>
<style>
.user-info-item {
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.user-info-item:last-child {
border-bottom: none;
}
.loading-spinner {
display: none;
text-align: center;
padding: 20px;
}
.error-message {
display: none;
color: #dc3545;
padding: 20px;
text-align: center;
}
</style>
</head>
<body>
<!-- 内容容器 -->
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>用户详细信息</h2>
<a href="{{ url_for('admin_main') }}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> 返回
</a>
</div>
<!-- 加载提示 -->
<div id="loadingSpinner" class="loading-spinner">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载用户信息...</p>
</div>
<!-- 错误提示 -->
<div id="errorMessage" class="error-message">
<div class="alert alert-danger" role="alert">
加载用户信息失败,请稍后重试
</div>
</div>
<!-- 用户信息卡片 -->
<div id="userInfo" class="card shadow-sm">
<!-- 动态内容将在此加载 -->
</div>
</div>
<script>
// 用户数据加载函数
function loadUserData() {
const urlParams = new URLSearchParams(window.location.search);//解析和操作url参数、window.location.search返回URL 中问号(?)后的查询字符串,例如 ?id=123。
const userId = urlParams.get('id');//获取URL中的id参数值
if (!userId) {
showError('未找到用户ID');
return;
}
// 显示加载状态
$('#loadingSpinner').show();
$('#userInfo').hide();
$('#errorMessage').hide();
// 请求用户数据
$.ajax({
url: `/api/user?id=${userId}`,
method: 'GET',
success: function(data) {
// 构建详情卡片
$('#userInfo').html(`
<div class="card-body">
<div class="row">
<div class="col-md-3 text-center mb-3">
<div class="avatar-placeholder bg-primary text-white rounded-circle d-flex align-items-center justify-content-center mx-auto" style="width: 100px; height: 100px; font-size: 2.5rem;">
${data.name.charAt(0)}
</div>
</div>
<div class="col-md-9">
<h4 class="card-title mb-4">${data.name}</h4>
<div class="user-info-item">
<strong>用户ID</strong> ${data.id}
</div>
<div class="user-info-item">
<strong>性别:</strong> ${data.gender}
</div>
<div class="user-info-item">
<strong>所属单位:</strong> ${data.unit}
</div>
<div class="user-info-item">
<strong>联系方式:</strong> ${data.contact}
</div>
<div class="user-info-item">
<strong>最后登录时间:</strong> ${formatDate(data.last_login)}
</div>
</div>
</div>
</div>
`);
$('#userInfo').show();
},
error: function(xhr, status, error) {
showError('加载用户信息失败:' + error);
},
complete: function() {
$('#loadingSpinner').hide();
}
});
}
// 显示错误信息
function showError(message) {
$('#errorMessage').html(`
<div class="alert alert-danger" role="alert">
${message}
</div>
`).show();
}
// 格式化日期
function formatDate(dateString) {
if (!dateString) return '暂无记录';
const date = new Date(dateString);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
// 页面加载时执行
$(document).ready(loadUserData);
</script>
</body>
</html>

@ -0,0 +1,161 @@
<!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样式 -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<!-- 自定义样式 -->
<style>
.function-area {
margin-top: 2rem;
padding: 1.5rem;
border: 1px solid #dee2e6;
border-radius: 8px;
}
.record-table {
margin-top: 1.5rem;
}
.status-paid { color: #28a745; } /* 已缴费状态绿色 */
.status-unpaid { color: #dc3545; } /* 未缴费状态红色 */
</style>
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-dark bg-primary"> /* 统一导航栏颜色为Bootstrap主蓝色 */
<div class="container-fluid">
<span class="navbar-brand">党员缴费系统</span>
<div class="d-flex align-items-center">
<!-- 当前用户显示 -->
<span class="text-white me-3" id="currentUser"></span>
<!-- 退出登录按钮 -->
<button class="btn btn-outline-light" onclick="logout()">退出登录</button>
</div>
</div>
</nav>
<div class="container">
<!-- 功能操作区 -->
<div class="function-area">
<div class="d-grid gap-3">
<!-- 缴费按钮 -->
<button class="btn btn-lg btn-primary" style="box-shadow: 0 2px 4px rgba(0,0,0,0.1);" onclick="gotoPayment()"> /* 调整按钮颜色并添加阴影 */
<i class="fas fa-money-bill-wave me-2"></i>立即缴费
</button>
<!-- 个人信息管理按钮 -->
<button class="btn btn-lg btn-secondary" style="box-shadow: 0 2px 4px rgba(0,0,0.1);" onclick="gotoProfile()"> /* 调整按钮颜色为辅助色 */
<i class="fas fa-user-edit me-2"></i>修改个人信息
</button>
<!-- 缴费记录查询按钮 -->
<button class="btn btn-lg btn-info" style="box-shadow: 0 2px 4px rgba(0,0,0.1);" onclick="loadRecords()"> /* 保持信息色并添加阴影 */
<i class="fas fa-file-invoice me-2"></i>查看缴费记录
</button>
</div>
</div>
<!-- 缴费记录显示区 -->
<div class="record-table">
<table class="table table-hover">
<thead class="table-dark">
<tr>
<th>缴费日期</th>
<th>应缴金额</th>
<th>实缴金额</th>
<th>缴费类型</th>
<th>状态</th>
</tr>
</thead>
<tbody id="paymentRecords">
<!-- 动态加载数据 -->
</tbody>
</table>
</div>
</div>
<!-- 引入依赖库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script>
// 页面初始化
$(document).ready(function() {
// 从sessionStorage获取登录信息
const userData = JSON.parse(sessionStorage.getItem('user'));
// 验证登录状态
// if (!userData || !userData.id) {
// alert('请先登录');
// window.location.href = 'login.html';
// return;
// }
// 显示当前用户
$('#currentUser').text(`${userData.name}${userData.id}`);
});
// 跳转缴费页面
function gotoPayment() {
window.location.href = 'payment.html';
}
// 跳转个人信息修改
function gotoProfile() {
window.location.href = 'profile.html';
}
// 加载缴费记录
function loadRecords() {
const user = JSON.parse(sessionStorage.getItem('user'));
$.ajax({
url: `/api/payments?userId=${user.id}`,
method: 'GET',
success: function(data) {
renderRecords(data);
},
error: function() {
alert('获取记录失败');
}
});
}
// 渲染缴费记录
function renderRecords(data) {
const tbody = $('#paymentRecords').empty();
data.forEach(item => {
const status = item.actual >= item.due ?
'<span class="status-paid">已交齐</span>' :
'<span class="status-unpaid">未交齐</span>';
tbody.append(`
<tr>
<td>${new Date(item.date).toLocaleDateString()}</td>
<td>¥${item.due.toFixed(2)}</td>
<td>¥${item.actual.toFixed(2)}</td>
<td>${typeMapping[item.type]}</td>
<td>${status}</td>
</tr>
`);
});
}
// 缴费类型映射
const typeMapping = {
monthly: '月度缴费',
special: '特殊党费',
other: '其他'
};
// 退出登录
function logout() {
sessionStorage.removeItem('user');
window.location.href = 'login.html';
}
</script>
</body>
</html>

@ -0,0 +1,630 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>军事代码合规性检查系统 - 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="#reports" 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">军事代码合规性检查系统</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>
<span class="filter-tab">C++</span>
<span class="filter-tab">Java</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>
<button class="btn btn-secondary" id="importProjectBtn">
<i class="fas fa-upload"></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>
</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="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 id="reports-page" class="page-content">
<div class="page-header fade-in">
<h1 class="page-title">检查报告</h1>
<p class="page-subtitle">查看详细的代码检查报告和分析结果</p>
</div>
<div class="reports-container">
<div class="reports-filters">
<div class="filter-group">
<label>时间范围:</label>
<select class="filter-select" id="timeRange">
<option value="7">最近7天</option>
<option value="30">最近30天</option>
<option value="90">最近90天</option>
</select>
</div>
<div class="filter-group">
<label>项目:</label>
<select class="filter-select" id="projectFilter">
<option value="all">全部项目</option>
</select>
</div>
<div class="filter-group">
<label>严重程度:</label>
<select class="filter-select" id="severityFilter">
<option value="all">全部</option>
<option value="high">高危</option>
<option value="medium">中危</option>
<option value="low">低危</option>
</select>
</div>
</div>
<div class="reports-content">
<div class="reports-summary">
<div class="summary-card">
<h3>检查概览</h3>
<div class="summary-stats">
<div class="summary-item">
<span class="summary-label">总检查次数</span>
<span class="summary-value" id="totalChecks">156</span>
</div>
<div class="summary-item">
<span class="summary-label">发现问题</span>
<span class="summary-value" id="totalIssues">342</span>
</div>
<div class="summary-item">
<span class="summary-label">已修复</span>
<span class="summary-value" id="fixedIssues">298</span>
</div>
<div class="summary-item">
<span class="summary-label">修复率</span>
<span class="summary-value" id="fixRate">87.1%</span>
</div>
</div>
</div>
</div>
<div class="reports-list" id="reportsList">
<!-- 报告列表将通过 JavaScript 动态生成 -->
</div>
</div>
</div>
</div>
<!-- 系统设置页面 -->
<div id="settings-page" class="page-content">
<div class="page-header fade-in">
<h1 class="page-title">系统设置</h1>
<p class="page-subtitle">配置系统参数和检查规则</p>
</div>
<div class="settings-container">
<div class="settings-tabs">
<div class="settings-tab active" data-tab="general">常规设置</div>
<div class="settings-tab" data-tab="agents">Agent配置</div>
<div class="settings-tab" data-tab="rules">检查规则</div>
<div class="settings-tab" data-tab="security">安全设置</div>
</div>
<div class="settings-content">
<!-- 常规设置 -->
<div id="general-settings" class="settings-panel active">
<div class="settings-section">
<h3>基本配置</h3>
<div class="setting-item">
<label>系统名称</label>
<input type="text" value="军事代码合规性检查系统" class="setting-input">
</div>
<div class="setting-item">
<label>检查超时时间(秒)</label>
<input type="number" value="300" class="setting-input">
</div>
<div class="setting-item">
<label>最大文件大小MB</label>
<input type="number" value="100" class="setting-input">
</div>
</div>
<div class="settings-section">
<h3>通知设置</h3>
<div class="setting-item">
<label>
<input type="checkbox" checked> 检查完成时发送通知
</label>
</div>
<div class="setting-item">
<label>
<input type="checkbox" checked> 发现高危漏洞时发送通知
</label>
</div>
</div>
</div>
<!-- Agent配置 -->
<div id="agents-settings" class="settings-panel">
<div class="settings-section">
<h3>Agent配置</h3>
<div class="agent-config-list">
<div class="agent-config-item">
<div class="agent-config-header">
<h4>pylint Agent</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="agent-config-details">
<div class="setting-item">
<label>检查级别</label>
<select class="setting-select">
<option value="basic">基础</option>
<option value="standard" selected>标准</option>
<option value="strict">严格</option>
</select>
</div>
<div class="setting-item">
<label>超时时间(秒)</label>
<input type="number" value="60" class="setting-input">
</div>
</div>
</div>
<div class="agent-config-item">
<div class="agent-config-header">
<h4>flake8 Agent</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="agent-config-details">
<div class="setting-item">
<label>检查级别</label>
<select class="setting-select">
<option value="basic">基础</option>
<option value="standard" selected>标准</option>
<option value="strict">严格</option>
</select>
</div>
<div class="setting-item">
<label>超时时间(秒)</label>
<input type="number" value="45" class="setting-input">
</div>
</div>
</div>
<div class="agent-config-item">
<div class="agent-config-header">
<h4>bandit Agent</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="agent-config-details">
<div class="setting-item">
<label>检查级别</label>
<select class="setting-select">
<option value="basic">基础</option>
<option value="standard" selected>标准</option>
<option value="strict">严格</option>
</select>
</div>
<div class="setting-item">
<label>超时时间(秒)</label>
<input type="number" value="90" class="setting-input">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 检查规则 -->
<div id="rules-settings" class="settings-panel">
<div class="settings-section">
<h3>代码风格规则</h3>
<div class="rules-list">
<div class="rule-item">
<div class="rule-header">
<h4>行长度限制</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="rule-details">
<label>最大行长度:</label>
<input type="number" value="120" class="setting-input">
</div>
</div>
<div class="rule-item">
<div class="rule-header">
<h4>函数复杂度检查</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="rule-details">
<label>最大复杂度:</label>
<input type="number" value="10" class="setting-input">
</div>
</div>
<div class="rule-item">
<div class="rule-header">
<h4>命名规范检查</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
</div>
</div>
</div>
<div class="settings-section">
<h3>安全规则</h3>
<div class="rules-list">
<div class="rule-item">
<div class="rule-header">
<h4>SQL注入检查</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
</div>
<div class="rule-item">
<div class="rule-header">
<h4>硬编码密码检查</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
</div>
<div class="rule-item">
<div class="rule-header">
<h4>敏感信息泄露检查</h4>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- 安全设置 -->
<div id="security-settings" class="settings-panel">
<div class="settings-section">
<h3>访问控制</h3>
<div class="setting-item">
<label>会话超时时间(分钟)</label>
<input type="number" value="30" class="setting-input">
</div>
<div class="setting-item">
<label>
<input type="checkbox" checked> 启用双因素认证
</label>
</div>
<div class="setting-item">
<label>
<input type="checkbox"> 记录所有操作日志
</label>
</div>
</div>
<div class="settings-section">
<h3>数据安全</h3>
<div class="setting-item">
<label>
<input type="checkbox" checked> 自动删除临时文件
</label>
</div>
<div class="setting-item">
<label>文件保留时间(天)</label>
<input type="number" value="30" class="setting-input">
</div>
</div>
</div>
</div>
<div class="settings-actions">
<button class="btn btn-primary">保存设置</button>
<button class="btn btn-secondary">重置默认</button>
</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>

@ -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"
}
]
}

@ -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">&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
Loading…
Cancel
Save