from __future__ import annotations import uuid from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from . import config from .db import Base, engine from .routers import ai, board, custom, export, focus, projects, staff, weekly from .schema_patch import ensure_columns Base.metadata.create_all(bind=engine) _patch = ensure_columns(engine, Base.metadata) if _patch: print(f"[ok] 已补齐数据库字段:{', '.join(_patch)}") # 每次进程启动换一个值;热加载重启后前端据此自动刷新 BOOT_ID = uuid.uuid4().hex app = FastAPI(title="部门关键任务追踪看板", version="1.0.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) api = FastAPI(title="部门关键任务追踪看板 API") api.include_router(board.router, prefix="", tags=["board"]) api.include_router(projects.router, prefix="", tags=["projects"]) api.include_router(ai.router, prefix="", tags=["ai"]) api.include_router(custom.router, prefix="", tags=["custom"]) api.include_router(export.router, prefix="", tags=["export"]) api.include_router(staff.router, prefix="", tags=["staff"]) api.include_router(weekly.router, prefix="", tags=["weekly"]) api.include_router(focus.router, prefix="", tags=["focus"]) app.mount("/api", api) WEB_DIR = config.BASE_DIR / "web" app.mount("/static", StaticFiles(directory=str(WEB_DIR)), name="static") # 前端零构建、文件名不带版本号,浏览器会启发式缓存 index.html / app.js / styles.css, # 改完界面看不到新版。no-cache 不做新鲜度缓存、只带 ETag 回源校验(未变更时返回 304)。 @app.middleware("http") async def no_cache_frontend(request, call_next): response = await call_next(request) if request.url.path == "/" or request.url.path.startswith("/static/"): response.headers["Cache-Control"] = "no-cache" return response @app.get("/health") def health(): return { "ok": True, "db": config.DATABASE_URL.split("://")[0], "dev": config.DEV, "boot": BOOT_ID, } @app.get("/") def index(): return FileResponse(str(WEB_DIR / "index.html"))