Files
2026-09-21 17:30:02 +08:00

122 lines
4.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 = '''<button type="button" class="button subtle" id="sign-out">退出登录</button>
<script>document.getElementById('sign-out').addEventListener('click',async function(){
this.disabled=true;try{const base=new URL('.',document.baseURI);
const response=await fetch(new URL('auth/logout',base),{method:'POST',credentials:'same-origin'});
if(!response.ok)throw new Error();location.replace(new URL('login',base).href);
}catch(error){this.disabled=false;this.textContent='退出失败,请重试';}});</script>'''
return HTMLResponse(html.replace("<!--AUTH_ACTIONS-->", 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 # 开发模式,代码变动自动重启
)