import asyncio from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from app.config import settings from app.database import Base, engine from app import models # noqa: F401 from app.services.auto_submit import auto_submit_overdue_loop from app.services.qrcode_batch_tasks import qrcode_batch_task_loop from app.routers import ( attendance_points, auth, clock, dashboard, devices, equipment, monitor, notices, people, products, reconciliation, reports, reviews, usage_stats, work_schedule, ) def create_app() -> FastAPI: app = FastAPI( title="嘉恒智能报工后端服务", version="0.1.0", description="FastAPI service for 嘉恒智能报工小程序", ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) settings.upload_path.mkdir(parents=True, exist_ok=True) app.mount("/uploads", StaticFiles(directory=str(settings.upload_path)), name="uploads") def background_tasks_enabled() -> bool: if settings.background_tasks_enabled is not None: return settings.background_tasks_enabled return settings.app_env == "production" @app.on_event("startup") async def startup() -> None: if settings.auto_create_tables: Base.metadata.create_all(bind=engine) app.state.auto_submit_task = None app.state.qrcode_batch_task = None if background_tasks_enabled(): app.state.auto_submit_task = asyncio.create_task(auto_submit_overdue_loop()) app.state.qrcode_batch_task = asyncio.create_task(qrcode_batch_task_loop()) @app.on_event("shutdown") async def shutdown() -> None: task = getattr(app.state, "auto_submit_task", None) if task: task.cancel() try: await task except asyncio.CancelledError: pass task = getattr(app.state, "qrcode_batch_task", None) if task: task.cancel() try: await task except asyncio.CancelledError: pass @app.get("/health") def health() -> dict[str, str]: return {"status": "ok"} app.include_router(auth.router) app.include_router(attendance_points.router) app.include_router(people.router) app.include_router(products.router) app.include_router(clock.router) app.include_router(reports.router) app.include_router(reviews.router) app.include_router(dashboard.router) app.include_router(devices.router) app.include_router(equipment.router) app.include_router(monitor.router) app.include_router(notices.router) app.include_router(reconciliation.router) app.include_router(work_schedule.router) app.include_router(usage_stats.router) return app app = create_app()