feat: 管理面板(登录认证+触发AI分析+统计+CLI改密码)
This commit is contained in:
+18
-1
@@ -7,16 +7,23 @@ from contextlib import asynccontextmanager
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from database import init_db
|
||||
from routes import stock, collections, shares, themes, core_stocks, fuyao, market_dashboard, ai_analysis
|
||||
from routes import stock, collections, shares, themes, core_stocks, fuyao, market_dashboard, ai_analysis, admin
|
||||
from services.daily_collector import collector_loop, cache_cleanup_loop
|
||||
from services.ai_collector import ai_analysis_loop
|
||||
from services.admin_auth import is_configured, set_password
|
||||
|
||||
load_dotenv()
|
||||
|
||||
DEFAULT_ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "!auvauv")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
init_db()
|
||||
# 首次启动自动设置默认管理密码
|
||||
if not is_configured():
|
||||
set_password(DEFAULT_ADMIN_PASSWORD)
|
||||
print(f"[admin] 已设置默认管理密码,请尽快修改: python3 admin_cli.py")
|
||||
collector_task = asyncio.create_task(collector_loop())
|
||||
cache_cleanup_task = asyncio.create_task(cache_cleanup_loop())
|
||||
ai_analysis_task = asyncio.create_task(ai_analysis_loop())
|
||||
@@ -50,6 +57,7 @@ app.include_router(core_stocks.router, prefix="/api/core-stocks")
|
||||
app.include_router(fuyao.router, prefix="/api/v2")
|
||||
app.include_router(market_dashboard.router, prefix="/api")
|
||||
app.include_router(ai_analysis.router, prefix="/api")
|
||||
app.include_router(admin.router, prefix="/api")
|
||||
|
||||
# 生产模式:后端同时托管前端静态文件
|
||||
# catch-all 路由在 API 路由之后注册,所以 API 优先级更高
|
||||
@@ -58,6 +66,15 @@ dist_path = os.path.join(os.path.dirname(__file__), "dist")
|
||||
# HTML 不缓存:保证 index.html 永远最新(引用的资源文件名带 hash,可长缓存)
|
||||
_NO_CACHE_HTML = {"Cache-Control": "no-cache, no-store, must-revalidate"}
|
||||
|
||||
# 管理面板:/admin → admin.html(在 SPA catch-all 之前)
|
||||
ADMIN_HTML = os.path.join(dist_path, "admin.html")
|
||||
|
||||
@app.get("/admin")
|
||||
async def serve_admin():
|
||||
if os.path.isfile(ADMIN_HTML):
|
||||
return FileResponse(ADMIN_HTML, media_type="text/html", headers=_NO_CACHE_HTML)
|
||||
return JSONResponse({"detail": "Admin panel not found"}, status_code=404)
|
||||
|
||||
if os.path.isdir(dist_path):
|
||||
@app.get("/{full_path:path}")
|
||||
async def serve_spa(full_path: str):
|
||||
|
||||
Reference in New Issue
Block a user