feat: 更新项目服务、工具函数和模板
This commit is contained in:
@@ -68,9 +68,11 @@ def register_project_routes(app):
|
||||
|
||||
if project.get('start_cmds'):
|
||||
for name, info in project['start_cmds'].items():
|
||||
log_message(f"[API-START] 项目={project_id} 命令={info['cmd']} 目录={cwd}")
|
||||
run_command(info['cmd'], cwd, project_id, f'start-{name}')
|
||||
else:
|
||||
cmd = project.get('start_cmd', 'python3 app.py')
|
||||
log_message(f"[API-START] 项目={project_id} 命令={cmd} 目录={cwd}")
|
||||
run_command(cmd, cwd, project_id, 'start')
|
||||
|
||||
return jsonify({'message': '服务启动中...'})
|
||||
@@ -128,7 +130,9 @@ def register_project_routes(app):
|
||||
'directory': data.get('directory', ''),
|
||||
'start_cmd': data.get('start_cmd', ''),
|
||||
'stop_cmd': data.get('stop_cmd', ''),
|
||||
'log_file': data.get('log_file', ''),
|
||||
'health_url': data.get('health_url', ''),
|
||||
'admin_url': data.get('admin_url', ''),
|
||||
'description': data.get('description', ''),
|
||||
'git_repo': data.get('git_repo', ''),
|
||||
'version': data.get('version', 'v1.0.0')
|
||||
@@ -152,7 +156,7 @@ def register_project_routes(app):
|
||||
return jsonify({'error': '项目不存在'}), 404
|
||||
|
||||
# 更新字段
|
||||
for key in ['name', 'ports', 'directory', 'start_cmd', 'stop_cmd', 'health_url', 'description', 'git_repo', 'version']:
|
||||
for key in ['name', 'ports', 'directory', 'log_file', 'start_cmd', 'stop_cmd', 'health_url', 'admin_url', 'description', 'git_repo', 'version']:
|
||||
if key in data:
|
||||
project[key] = data[key]
|
||||
|
||||
@@ -162,6 +166,55 @@ def register_project_routes(app):
|
||||
|
||||
return jsonify({'message': '项目更新成功'})
|
||||
|
||||
@app.route('/api/projects/<project_id>/log')
|
||||
def api_project_log(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
|
||||
|
||||
lines = request.args.get('lines', 200, type=int)
|
||||
lines = max(1, min(lines, 5000)) # 限制 1-5000 行
|
||||
|
||||
log_file = project.get('log_file', '')
|
||||
if not log_file:
|
||||
# 默认:项目目录下的 logs/app.log
|
||||
cwd = project.get('directory', '')
|
||||
if cwd:
|
||||
from config import WORKSPACE_DIR
|
||||
import os
|
||||
abs_dir = cwd if cwd.startswith('/') else os.path.join(WORKSPACE_DIR, cwd)
|
||||
log_file = os.path.join(abs_dir, 'logs', 'app.log')
|
||||
|
||||
# 支持相对路径和绝对路径
|
||||
import os
|
||||
if not log_file.startswith('/'):
|
||||
cwd = project.get('directory', '')
|
||||
if cwd:
|
||||
from config import WORKSPACE_DIR
|
||||
abs_dir = cwd if cwd.startswith('/') else os.path.join(WORKSPACE_DIR, cwd)
|
||||
log_file = os.path.join(abs_dir, log_file)
|
||||
|
||||
if not os.path.exists(log_file):
|
||||
return jsonify({'log': f'日志文件不存在: {log_file}'})
|
||||
|
||||
try:
|
||||
# 读取最后 N 行(高效方式)
|
||||
with open(log_file, 'r', encoding='utf-8', errors='replace') as f:
|
||||
all_lines = f.readlines()
|
||||
tail_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
|
||||
content = ''.join(tail_lines)
|
||||
|
||||
return jsonify({
|
||||
'log': content if content else '(日志为空)',
|
||||
'file': log_file,
|
||||
'total_lines': len(all_lines),
|
||||
'shown_lines': len(tail_lines)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'读取日志失败: {str(e)}'}), 500
|
||||
|
||||
@app.route('/api/projects/<project_id>', methods=['DELETE'])
|
||||
def api_delete_project(project_id):
|
||||
"""删除项目"""
|
||||
|
||||
Reference in New Issue
Block a user