from flask import Blueprint, render_template, jsonify, send_file, request import os from loguru import logger file_browser_bp = Blueprint('file_browser', __name__) @file_browser_bp.route('/file_browser') def file_browser(): """文件浏览器页面""" return render_template('file_browser.html') @file_browser_bp.route('/api/list_files') def list_files(): """获取指定目录下的文件列表""" try: path = request.args.get('path', '') # 获取项目根目录 project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 构建完整路径 full_path = os.path.join(project_root, path) # 安全检查:确保路径在项目根目录内 if not os.path.abspath(full_path).startswith(project_root): return jsonify({"success": False, "message": "访问被拒绝:路径超出项目范围"}) if not os.path.exists(full_path): return jsonify({"success": False, "message": "目录不存在"}) # 需要隐藏的目录列表 hidden_dirs = { '__pycache__', '.git', '.idea', '.venv', 'venv', 'env', 'node_modules', '.vscode', '.pytest_cache', '.coverage', 'htmlcov', 'dist', 'build', '.eggs', '*.egg-info' } items = [] for item in os.listdir(full_path): # 跳过隐藏文件和目录 if item.startswith('.'): continue item_path = os.path.join(full_path, item) is_dir = os.path.isdir(item_path) # 跳过隐藏目录 if is_dir and item in hidden_dirs: continue items.append({ "name": item, "is_dir": is_dir, "size": os.path.getsize(item_path) if not is_dir else 0, "modified": os.path.getmtime(item_path) }) # 对文件列表进行排序:目录在前,同类型按名称排序 items.sort(key=lambda x: (not x["is_dir"], x["name"].lower())) return jsonify({ "success": True, "data": { "items": items, "current_path": path } }) except Exception as e: logger.error(f"列出文件失败: {e}") return jsonify({"success": False, "message": str(e)}) @file_browser_bp.route('/api/download_file') def download_file(): """下载指定文件""" try: path = request.args.get('path', '') # 获取项目根目录 project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 构建完整路径 full_path = os.path.join(project_root, path) # 安全检查:确保路径在项目根目录内 if not os.path.abspath(full_path).startswith(project_root): return jsonify({"success": False, "message": "访问被拒绝:路径超出项目范围"}) if not os.path.exists(full_path): return jsonify({"success": False, "message": "文件不存在"}) if os.path.isdir(full_path): return jsonify({"success": False, "message": "不能下载目录"}) return send_file( full_path, as_attachment=True, download_name=os.path.basename(full_path) ) except Exception as e: logger.error(f"下载文件失败: {e}") return jsonify({"success": False, "message": str(e)})