Files
menchuang/src/huamenchuang/main.py
T
HHY f7a555dd6c feat: 前后端全量开发 v0.2
后端:
- 客户模块 CRUD+搜索 (api/services/repositories 分层)
- 合同模块: FG单号规则/意向单转正式单/订单创建自动快照客户信息
- 优化下料: FFD首递减装箱算法(利用率统计/余料/未排入清单)
前端 (Vue3+TS+Element Plus):
- 7页面: 登录/工作台/订单中心/合同/客户/样板库/优化下料
- 自研二维窗型画布渲染器: 解析drawing_data渲染玻璃区域/外框/
  扇开向标记/尺寸标注, 支持缩放平移复位
- 样板库与订单联动(用此样板下单自动带图纸)
- axios统一envelope拦截/登录守卫/付费墙提示
工程:
- SPA history 回退路由, 构建产物挂载后端
- 全接口回归 6/6 通过
2026-09-20 08:46:04 -07:00

87 lines
3.1 KiB
Python
Raw 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.
"""应用入口:FastAPI 装配、异常处理、静态资源挂载、开发服务器。"""
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.staticfiles import StaticFiles
from huamenchuang.api.router import api_router
from huamenchuang.core.database import init_db
from huamenchuang.core.deps import ModuleLockedError, NotAuthedError
from huamenchuang.core.response import fail, ok, paywall
app = FastAPI(title="华门窗云平台", version="0.1.0")
@app.on_event("startup")
async def startup() -> None:
await init_db()
@app.exception_handler(NotAuthedError)
async def auth_handler(request: Request, exc: NotAuthedError):
return _json({"code": 401, "message": str(exc), "data": "", "other_data": "", "other_data2": ""})
@app.exception_handler(ModuleLockedError)
async def module_locked_handler(request: Request, exc: ModuleLockedError):
return _json(paywall(exc.module))
@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
"""参数校验失败 → 422 语义 envelope(列出字段,不泄漏内部细节)。"""
fields = [f"{'.'.join(str(x) for x in e['loc'][1:])}" for e in exc.errors()]
return _json(fail(f"参数错误: {', '.join(fields)}"))
@app.exception_handler(Exception)
async def unhandled_handler(request: Request, exc: Exception):
"""兜底异常:统一 500 envelope(不回栈信息)。"""
return _json(fail("服务器内部错误,请稍后再试"))
def _json(payload: dict):
from fastapi.responses import JSONResponse
return JSONResponse(payload)
@api_router.get("/health", tags=["系统"])
async def health():
return ok(data={"status": "up"}, message="ok")
app.include_router(api_router)
from fastapi.responses import FileResponse # noqa: E402
# 静态资源:样板平面图(data/windoor-images)
_imgdir = Path(__file__).resolve().parents[2] / "data" / "windoor-images"
if _imgdir.exists():
app.mount("/static/windoor-images", StaticFiles(directory=str(_imgdir)), name="windoor-images")
# 前端构建产物挂载(前后端规范:构建到后端目录)+ history 路由回退
_dist = Path(__file__).resolve().parents[2] / "frontend" / "dist"
if _dist.exists():
app.mount("/assets", StaticFiles(directory=str(_dist / "assets")), name="assets")
@app.get("/{full_path:path}", include_in_schema=False)
async def spa_fallback(full_path: str):
"""非 API/静态路径一律返回 index.html(前端 history 模式)。"""
if full_path.startswith(("api/", "static/")):
return JSONResponse(
{"code": 0, "message": "接口不存在", "data": "", "other_data": "", "other_data2": ""})
target = _dist / full_path
if full_path and target.is_file():
return FileResponse(target)
return FileResponse(_dist / "index.html")
def main() -> None:
import uvicorn
uvicorn.run("huamenchuang.main:app", host="0.0.0.0", port=8000, reload=True)
if __name__ == "__main__":
main()