Files
project-panel/routes_project.py
hz4th_coder 69edd1c63e refactor: 模块化重构 v3.4.0
🎯 重构目标:
- 将 3700+ 行单文件拆分为多个模块
- 清晰的职责分离,便于维护和扩展

📁 模块结构:
- config.py: 配置常量和路径
- database.py: 数据库操作
- utils.py: 工具函数(日志、进程、cron等)
- routes_cron.py: Cron管理API
- routes_system.py: 系统监控API
- routes_config.py: 配置管理API
- routes_email.py: 邮件通知API
- routes_project.py: 项目管理API
- templates.py: HTML模板
- app.py: 主入口文件

 优势:
- 易于维护:每个模块职责明确
- 易于扩展:新增功能只需添加对应模块
- 易于测试:模块独立,便于单元测试
- 易于理解:新人能快速上手

📝 更新 README.md,详细说明项目结构和API接口
2026-06-01 12:30:24 +08:00

212 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""
项目管理 API 路由
"""
import json
from flask import jsonify, request
from config import PROJECTS_FILE
from utils import (
log_message, load_projects, load_projects_full, save_projects,
check_port, stop_process, run_command
)
def register_project_routes(app):
"""注册项目管理相关路由"""
@app.route('/api/projects')
def api_projects():
"""获取项目列表"""
projects = load_projects()
# 添加状态信息
for project in projects:
ports = project.get('ports', [])
project['status'] = 'running' if all(check_port(p) for p in ports) else 'stopped'
return jsonify({
'projects': projects,
'server': load_projects_full().get('server', {})
})
@app.route('/api/projects/<project_id>/start', methods=['POST'])
def api_start(project_id):
projects = load_projects()
project = next((p for p in projects if p['id'] == project_id), None)
if not project:
return jsonify({'error': '项目不存在'}), 404
if project['type'] != 'web':
return jsonify({'error': '只有Web服务支持启动'}), 400
cwd = project.get('directory', '')
if not cwd:
return jsonify({'error': '项目目录未配置'}), 400
from config import WORKSPACE_DIR
import os
cwd = os.path.join(WORKSPACE_DIR, cwd) if not cwd.startswith('/') else cwd
if not os.path.exists(cwd):
return jsonify({'error': f'目录不存在: {cwd}'}), 400
if project.get('start_cmds'):
for name, info in project['start_cmds'].items():
run_command(info['cmd'], cwd, project_id, f'start-{name}')
else:
cmd = project.get('start_cmd', 'python3 app.py')
run_command(cmd, cwd, project_id, 'start')
return jsonify({'message': '服务启动中...'})
@app.route('/api/projects/<project_id>/stop', methods=['POST'])
def api_stop(project_id):
projects = load_projects()
project = next((p for p in projects if p['id'] == project_id), None)
if not project:
return jsonify({'error': '项目不存在'}), 404
if project['type'] != 'web':
return jsonify({'error': '只有Web服务支持停止'}), 400
ports = project.get('ports', [])
stopped = 0
for port in ports:
stopped += stop_process(port)
return jsonify({'message': f'已停止 {stopped} 个进程'})
@app.route('/api/projects/<project_id>/restart', methods=['POST'])
def api_restart(project_id):
"""重启服务"""
# 先停止
api_stop(project_id)
# 等待1秒
import time
time.sleep(1)
# 再启动
return api_start(project_id)
@app.route('/api/projects/add', methods=['POST'])
def api_add_project():
"""添加新项目"""
data = request.get_json()
if not data.get('id') or not data.get('name') or not data.get('ports'):
return jsonify({'error': '缺少必要字段'}), 400
projects = load_projects()
# 检查ID是否已存在
if any(p['id'] == data['id'] for p in projects):
return jsonify({'error': '项目ID已存在'}), 400
# 添加项目
project = {
'id': data['id'],
'name': data['name'],
'type': data.get('type', 'web'),
'ports': data['ports'],
'directory': data.get('directory', ''),
'start_cmd': data.get('start_cmd', ''),
'stop_cmd': data.get('stop_cmd', ''),
'health_url': data.get('health_url', ''),
'description': data.get('description', ''),
'git_repo': data.get('git_repo', ''),
'version': data.get('version', 'v1.0.0')
}
projects.append(project)
save_projects(projects)
log_message(f"添加项目: {project['name']}")
return jsonify({'message': '项目添加成功', 'project': project})
@app.route('/api/projects/<project_id>', methods=['PUT'])
def api_update_project(project_id):
"""更新项目配置"""
data = request.get_json()
projects = load_projects()
project = next((p for p in projects if p['id'] == project_id), None)
if not project:
return jsonify({'error': '项目不存在'}), 404
# 更新字段
for key in ['name', 'ports', 'directory', 'start_cmd', 'stop_cmd', 'health_url', 'description', 'git_repo', 'version']:
if key in data:
project[key] = data[key]
save_projects(projects)
log_message(f"更新项目: {project['name']}")
return jsonify({'message': '项目更新成功'})
@app.route('/api/projects/<project_id>', methods=['DELETE'])
def api_delete_project(project_id):
"""删除项目"""
projects = load_projects()
project = next((p for p in projects if p['id'] == project_id), None)
if not project:
return jsonify({'error': '项目不存在'}), 404
projects = [p for p in projects if p['id'] != project_id]
save_projects(projects)
log_message(f"删除项目: {project['name']}")
return jsonify({'message': '项目删除成功'})
@app.route('/api/external-services')
def api_external_services():
"""获取外部服务列表"""
data = load_projects_full()
services = data.get('external_services', [])
# 添加状态
for service in services:
ports = service.get('ports', [])
service['status'] = 'running' if all(check_port(p) for p in ports) else 'stopped'
return jsonify({'services': services})
@app.route('/api/external-services/add', methods=['POST'])
def api_add_external_service():
"""添加外部服务"""
data = request.get_json()
if not data.get('id') or not data.get('name') or not data.get('ports'):
return jsonify({'error': '缺少必要字段'}), 400
full_data = load_projects_full()
services = full_data.get('external_services', [])
# 检查ID是否已存在
if any(s['id'] == data['id'] for s in services):
return jsonify({'error': '服务ID已存在'}), 400
# 添加服务
service = {
'id': data['id'],
'name': data['name'],
'type': 'external',
'ports': data['ports'],
'health_url': data.get('health_url', ''),
'description': data.get('description', '')
}
services.append(service)
full_data['external_services'] = services
with open(PROJECTS_FILE, 'w', encoding='utf-8') as f:
json.dump(full_data, f, ensure_ascii=False, indent=2)
log_message(f"添加外部服务: {service['name']}")
return jsonify({'message': '服务添加成功', 'service': service})