# main0814.py # 项目入口文件:创建 FastAPI 应用、注册路由、创建数据库表 import os from fastapi import FastAPI from pathlib import Path from fastapi.responses import FileResponse, HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles from sqlalchemy.exc import IntegrityError, SQLAlchemyError from api import workspace_api, ai_api from starlette.middleware.cors import CORSMiddleware from api import student_api, advisor_api, employment_api, score_api, class_api, teacher_api from init_db import init_all, drop_tables from database import engine from sqlalchemy import text from service.web_auth import install_web_auth # 2. 创建 FastAPI 实例 app = FastAPI( title="FastAPI + SQLAlchemy 分层架构(MySQL)", description="用户管理示例,演示分层架构和 MySQL 集成", version="1.0.0" ) # 3. 添加跨域中间件(允许前端跨域请求) app.add_middleware( CORSMiddleware, allow_origins=[value.strip() for value in os.getenv("CORS_ORIGINS", "*").split(",") if value.strip()], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) install_web_auth(app) # 4. 注册子路由 # prefix 为路由前缀,所有用户接口都以 /api/users 开头 app.include_router( student_api.router, prefix="/api/studentsManagement", tags=["学生管理 (文涛,浩霖)"] ) # app.include_router( class_api.router, prefix="/api/studentsManagement", tags=["班级管理 (薛炎)"] ) # app.include_router( teacher_api.router, prefix="/api/studentsManagement", tags=["老师管理 (广龙)"] ) # app.include_router( advisor_api.router, prefix="/api/studentsManagement", tags=["顾问管理 (子镜)"] ) # app.include_router( score_api.router, prefix="/api/studentsManagement", tags=["成绩管理 (广湘)"] ) app.include_router( employment_api.router, prefix="/api/studentsManagement", tags=["就业管理 (周兴)"] ) # 5. 前端及聚合查询接口 app.include_router(workspace_api.router, prefix="/api/studentsManagement") app.include_router(ai_api.router, prefix="/api/studentsManagement") FRONTEND_DIR = Path(__file__).resolve().parent / "frontend" app.mount("/static", StaticFiles(directory=FRONTEND_DIR), name="frontend") @app.exception_handler(IntegrityError) async def integrity_error(request, error): return JSONResponse(status_code=409, content={"detail": "保存失败:学号、手机号、名称或学生就业记录已存在,或关联记录不存在。请检查后重试。"}) @app.exception_handler(SQLAlchemyError) async def database_error(request, error): return JSONResponse(status_code=503, content={"detail": "数据库暂时不可用,请检查 MySQL 服务和表结构。"}) # 根路径直接打开前端页面,API 文档仍位于 /docs。 @app.get("/") async def root(): if os.getenv("AUTH_ENABLED", "").lower() in {"1", "true", "yes", "on"}: html = (FRONTEND_DIR / "index.html").read_text(encoding="utf-8") actions = ''' ''' return HTMLResponse(html.replace("", actions), headers={"Cache-Control": "no-store"}) return FileResponse(FRONTEND_DIR / "index.html") @app.get("/healthz", include_in_schema=False) def healthz(): with engine.connect() as connection: connection.execute(text("SELECT 1")) return {"status": "ok"} # 6. 如果直接运行此文件,启动 uvicorn 服务器 if __name__ == "__main__": # drop_tables() init_all(True, False) import uvicorn uvicorn.run( "main:app", # 指定应用位置(模块名:应用变量名) host=os.getenv("APP_HOST", "127.0.0.1"), # 默认仅本机访问,不依赖 Wi-Fi / 局域网 IP port=int(os.getenv("APP_PORT", "8004")), # 可通过环境变量调整端口 reload=True # 开发模式,代码变动自动重启 )