""" 主页面蓝图:首页、home、图片工作台、品牌页、静态文件、Logo """ import os from flask import Blueprint, send_file, render_template_string from app_common import ( get_db, _render_html, _is_session_user_valid, login_required, admin_required, STATIC_DIR, BASE_DIR, ASSETS_DIR ) from flask import redirect, url_for, session from flask import Flask, request, Response, stream_with_context import requests from config import base_url,version,JAVA_API_BASE main_bp = Blueprint('main', __name__) def _resolve_asset_filename(filename): """Resolve hashed Vite assets without maintaining hardcoded alias tables.""" safe_name = os.path.basename(filename) asset_dirs = [ ASSETS_DIR, os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')), ] for asset_dir in asset_dirs: exact_path = os.path.join(asset_dir, safe_name) if os.path.isfile(exact_path): return safe_name base_name, ext = os.path.splitext(safe_name) if not base_name or not ext: return safe_name parts = base_name.split('-') if len(parts) < 2: return safe_name asset_names = [] for asset_dir in asset_dirs: try: asset_names.extend(os.listdir(asset_dir)) except OSError: continue if not asset_names: return safe_name for prefix_length in range(len(parts) - 1, 0, -1): prefix = '-'.join(parts[:prefix_length]) matches = [ asset_name for asset_name in asset_names if asset_name.endswith(ext) and asset_name.startswith(prefix) ] if len(matches) == 1: return matches[0] return safe_name @main_bp.route('/') def index(): if session.get('user_id') and _is_session_user_valid(): return redirect(url_for('main.home')) return redirect(url_for('auth.login')) @main_bp.route('/home') @login_required def home(): try: conn = get_db() with conn.cursor() as cur: cur.execute("SELECT username, is_admin FROM users WHERE id = %s", (session['user_id'],)) row = cur.fetchone() conn.close() return _render_html('home.html', username=row.get('username', ''), is_admin=bool(row.get('is_admin')), user_id=session.get('user_id'),baseUrl=base_url,version=version) except Exception: return _render_html('home.html', username=session.get('username', ''), is_admin=False, user_id=session.get('user_id'),baseUrl=base_url,version=version) @main_bp.route('/image') @login_required def wb(): return _render_html('index.html') @main_bp.route('/brand') @login_required def brand_page(): candidate_paths = [ os.path.join(BASE_DIR, 'web_source', 'brand.html'), os.path.abspath(os.path.join(BASE_DIR, '..', 'web_source', 'brand.html')), ] for candidate_path in candidate_paths: if not os.path.isfile(candidate_path): continue try: with open(candidate_path, 'rb') as f: raw = f.read() try: from html_crypto import decrypt content = decrypt(raw).decode('utf-8') except Exception: if raw[:7] == b'gAAAAAB': raise content = raw.decode('utf-8', errors='replace') return render_template_string(content, user_id=session.get('user_id')) except Exception: continue return _render_html('brand.html', user_id=session.get('user_id')) @main_bp.route('/brand/legacy') @login_required def brand_page_legacy(): legacy_path = os.path.join(BASE_DIR, 'web_source', 'templates_backup', 'brand.html') if not os.path.isfile(legacy_path): return '', 404 with open(legacy_path, 'rb') as f: content = f.read().decode('utf-8', errors='replace') content = content.replace( '
', '
', 1, ) content = content.replace('height: calc(100vh - 56px);', 'height: 100vh;', 1) return render_template_string(content, user_id=session.get('user_id')) @main_bp.route('/static/') def serve_static(filename): """提供 static 目录及子目录下的静态文件访问。""" filepath = os.path.normpath(os.path.join(STATIC_DIR, filename)) static_abs = os.path.abspath(STATIC_DIR) file_abs = os.path.abspath(filepath) if not file_abs.startswith(static_abs) or not os.path.isfile(file_abs): return '', 404 return send_file(file_abs, as_attachment=False) @main_bp.route('/assets/') def serve_assets(filename): """提供 static 目录及子目录下的静态文件访问。""" filename = _resolve_asset_filename(filename) candidate_dirs = [ os.path.abspath(ASSETS_DIR), os.path.abspath(os.path.join(BASE_DIR, 'new_web_source', 'assets')), os.path.abspath(os.path.join(BASE_DIR, '..', 'new_web_source', 'assets')), ] for static_abs in candidate_dirs: filepath = os.path.normpath(os.path.join(static_abs, filename)) file_abs = os.path.abspath(filepath) if not file_abs.startswith(static_abs): continue if os.path.isfile(file_abs): return send_file(file_abs, as_attachment=False) return '', 404 @main_bp.route('/new_web_source/') def serve_new_web_source(filename): """提供 static 目录及子目录下的静态文件访问。""" filepath = os.path.normpath(os.path.join("new_web_source", filename)) static_abs = os.path.abspath("new_web_source") file_abs = os.path.abspath(filepath) if not file_abs.startswith(static_abs) or not os.path.isfile(file_abs): return '', 404 return send_file(file_abs, as_attachment=False) @main_bp.route('/logo.jpg', methods=['GET']) def get_logo_image(): return send_file(os.path.join(BASE_DIR, "logo.jpg"), mimetype='image/jpeg') @main_bp.route('/newApi/', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']) def proxy(path): target_url = f"{JAVA_API_BASE}/{path}" # 复制请求参数 params = request.args.to_dict() # 处理请求头 headers = {} for key, value in request.headers: if key.lower() in ['host', 'content-length', 'connection']: continue headers[key] = value ignore_url = [f"{JAVA_API_BASE}/api/delete-brand/tasks/batch", f"{JAVA_API_BASE}/api/delete-brand/history", f"{JAVA_API_BASE}/api/product-risk-resolve/tasks/batch", ] if target_url not in ignore_url: try: print("=============================") print("target_url:",target_url) print("params:",params) print("data:",request.get_data()) print("=============================") except Exception as e: print("打印失败",e) try: # 使用流式请求 req = requests.request( method=request.method, url=target_url, params=params, headers=headers, data=request.get_data() if request.get_data() else None, cookies=request.cookies, stream=True, # 启用流式传输 timeout=30 ) # 流式响应 def generate(): for chunk in req.iter_content(chunk_size=8192): if chunk: yield chunk # 构建响应 response = Response(stream_with_context(generate()), status=req.status_code) # 复制响应头 for key, value in req.headers.items(): if key.lower() not in ['content-encoding', 'content-length', 'transfer-encoding', 'connection']: response.headers[key] = value return response except requests.exceptions.Timeout: print("后端服务超时") return Response("后端服务超时", status=504) except requests.exceptions.ConnectionError: print("无法连接到后端服务") return Response("无法连接到后端服务", status=502) except Exception as e: print(f"代理请求失败: {e}") return Response(f"代理错误: {str(e)}", status=500)