78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
from __future__ import annotations
|
||
|
||
import uuid
|
||
|
||
from fastapi import Depends, FastAPI
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
from fastapi.responses import FileResponse
|
||
from fastapi.staticfiles import StaticFiles
|
||
|
||
from . import config, security
|
||
from .db import Base, SessionLocal, engine
|
||
from .routers import ai, auth, board, custom, export, focus, projects, rbac, 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)}")
|
||
|
||
# 内置角色 + 管理员账号(只在缺失时补,不会覆盖已改过的密码/权限)
|
||
with SessionLocal() as _db:
|
||
for _note in security.ensure_seed(_db):
|
||
print(f"[ok] {_note}")
|
||
|
||
# 每次进程启动换一个值;热加载重启后前端据此自动刷新
|
||
BOOT_ID = uuid.uuid4().hex
|
||
|
||
app = FastAPI(title="部门关键任务追踪看板", version="1.0.0")
|
||
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"],
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
# 所有 /api 接口先过 RBAC 总闸(登录 + 菜单权限),登录接口自身除外
|
||
api = FastAPI(title="部门关键任务追踪看板 API", dependencies=[Depends(security.guard)])
|
||
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"])
|
||
api.include_router(auth.router, prefix="", tags=["auth"])
|
||
api.include_router(rbac.router, prefix="", tags=["rbac"])
|
||
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"))
|