"""FastAPI 应用入口""" from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from app.database import init_database from app.routes import regimes, accounts, strategies, matches, match # 前端构建产物目录(生产部署时由 PM2 单端口托管) FRONTEND_DIST = Path(__file__).resolve().parent.parent.parent / "frontend" / "dist" app = FastAPI( title="加密货币前置匹配系统", description="大盘-周期-阶段-强弱-方向-账户-策略前置匹配(纯本地,无登录)", version="1.0.0", ) # 允许前端跨域(本地开发) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 注册 API 路由 app.include_router(regimes.router) app.include_router(accounts.router) app.include_router(strategies.router) app.include_router(matches.router) app.include_router(match.router) @app.on_event("startup") def on_startup(): """启动时初始化数据库""" init_database() @app.get("/api/health") def health(): return {"status": "ok", "message": "加密货币前置匹配系统运行中"} def _mount_frontend(): """生产环境:托管 Vue 前端静态资源,支持 SPA 路由""" if not FRONTEND_DIST.exists(): return assets_dir = FRONTEND_DIST / "assets" if assets_dir.exists(): app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") @app.get("/") async def serve_index(): return FileResponse(FRONTEND_DIST / "index.html") @app.get("/{path:path}") async def serve_spa(path: str): # API 路径不走 SPA 回退 if path.startswith("api"): return {"detail": "Not Found"} file = FRONTEND_DIST / path if file.is_file(): return FileResponse(file) return FileResponse(FRONTEND_DIST / "index.html") _mount_frontend()