Files
project-panel/routes_project.py
hz4th_coder bb19141edc fix: 修复Web服务监控区域状态显示问题
后端 status 字段从字符串改为结构化对象 {status, ports: {port: {running}}}
前端期望的是 p.status.status 和 p.status.ports[port].running,之前的字符串格式导致:
- 所有服务状态始终显示「未知」
- 所有端口始终显示红色(已停止)
2026-06-01 17:08:09 +08:00

242 lines
8.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()
# 添加状态信息(结构化对象,前端期望 status.status 和 status.ports
for project in projects:
ports = project.get('ports', [])
port_statuses = {}
for p in ports:
port_statuses[str(p)] = {'running': check_port(p)}
running_count = sum(1 for ps in port_statuses.values() if ps['running'])
if running_count == len(ports) and len(ports) > 0:
overall = 'running'
elif running_count > 0:
overall = 'partial'
else:
overall = 'stopped'
project['status'] = {
'status': overall,
'ports': port_statuses
}
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', [])
# 添加状态(结构化对象,前端期望 status.status 和 status.ports
for service in services:
ports = service.get('ports', [])
port_statuses = {}
for p in ports:
port_statuses[str(p)] = {'running': check_port(p)}
running_count = sum(1 for ps in port_statuses.values() if ps['running'])
if running_count == len(ports) and len(ports) > 0:
overall = 'running'
elif running_count > 0:
overall = 'partial'
else:
overall = 'stopped'
service['status'] = {
'status': overall,
'ports': port_statuses
}
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})