main.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import json as _json
  2. from fastapi import FastAPI, Request
  3. from fastapi.middleware.cors import CORSMiddleware
  4. from fastapi.responses import JSONResponse
  5. from starlette.middleware.base import BaseHTTPMiddleware
  6. from app.config import get_settings
  7. settings = get_settings()
  8. class DecryptMiddleware(BaseHTTPMiddleware):
  9. async def dispatch(self, request: Request, call_next):
  10. encrypt_key = request.headers.get("encrypt-key")
  11. if encrypt_key and request.method in ("POST", "PUT"):
  12. try:
  13. from app.utils.crypto import try_decrypt_request
  14. body = await request.body()
  15. decrypted = try_decrypt_request(encrypt_key, body.decode())
  16. request._body = _json.dumps(decrypted).encode()
  17. except Exception:
  18. pass
  19. return await call_next(request)
  20. def create_app() -> FastAPI:
  21. app = FastAPI(
  22. title="CRM 后端 API",
  23. version="1.0.0",
  24. docs_url="/swagger-ui/index.html",
  25. openapi_url="/v3/api-docs",
  26. )
  27. app.add_middleware(
  28. CORSMiddleware,
  29. allow_origins=["*"],
  30. allow_credentials=True,
  31. allow_methods=["*"],
  32. allow_headers=["*"],
  33. )
  34. app.add_middleware(DecryptMiddleware)
  35. from app.routers.auth import router as auth_router
  36. from app.routers.system import router as system_router
  37. from app.routers.crm.customer import (
  38. router as crm_customer_router,
  39. follow_router as crm_follow_router,
  40. tag_router as crm_tag_router,
  41. pool_statistics_router as crm_pool_stats_router,
  42. pool_rule_router as crm_pool_rule_router,
  43. )
  44. from app.routers.crm.clue import (
  45. router as crm_clue_router,
  46. follow_router as crm_clue_follow_router,
  47. )
  48. from app.routers.crm.contact import router as crm_contact_router
  49. from app.routers.crm.opportunity import (
  50. router as crm_opportunity_router,
  51. follow_router as crm_opportunity_follow_router,
  52. product_router as crm_opportunity_product_router,
  53. stage_log_router as crm_stage_log_router,
  54. )
  55. from app.routers.crm.product import (
  56. router as crm_product_router,
  57. category_router as crm_product_category_router,
  58. tag_router as crm_product_tag_router,
  59. tag_relation_router as crm_product_tag_relation_router,
  60. attachment_router as crm_product_attachment_router,
  61. price_router as crm_product_price_router,
  62. price_history_router as crm_product_price_history_router,
  63. stock_router as crm_product_stock_router,
  64. )
  65. from app.routers.crm.quote import (
  66. router as crm_quote_router,
  67. product_router as crm_quote_product_router,
  68. approval_router as crm_quote_approval_router,
  69. )
  70. from app.routers.crm.contract import router as crm_contract_router
  71. from app.routers.crm.payment import (
  72. router as crm_payment_router,
  73. plan_router as crm_payment_plan_router,
  74. collection_router as crm_payment_collection_router,
  75. )
  76. from app.routers.crm.invoice import (
  77. router as crm_invoice_router,
  78. info_router as crm_invoice_info_router,
  79. item_router as crm_invoice_item_router,
  80. )
  81. from app.routers.crm.visit import (
  82. router as crm_visit_router,
  83. plan_router as crm_visit_plan_router,
  84. problem_router as crm_visit_problem_router,
  85. )
  86. from app.routers.crm.supplier import router as crm_supplier_router
  87. app.include_router(auth_router, prefix="/auth", tags=["认证"])
  88. app.include_router(system_router, prefix="/system", tags=["系统管理"])
  89. app.include_router(crm_customer_router, prefix="/crm/customer", tags=["客户管理"])
  90. app.include_router(crm_follow_router, prefix="/crm/customer/follow", tags=["客户跟进"])
  91. app.include_router(crm_tag_router, prefix="/crm/customer/tag", tags=["客户标签"])
  92. app.include_router(crm_pool_stats_router, prefix="/crm/customer/pool/statistics", tags=["公海池统计"])
  93. app.include_router(crm_pool_rule_router, prefix="/crm/customer/pool/rule", tags=["公海池规则"])
  94. app.include_router(crm_clue_router, prefix="/crm/clue", tags=["线索管理"])
  95. app.include_router(crm_clue_follow_router, prefix="/crm/clue/follow", tags=["线索跟进"])
  96. app.include_router(crm_contact_router, prefix="/crm/contact", tags=["联系人管理"])
  97. app.include_router(crm_opportunity_router, prefix="/crm/opportunity", tags=["商机管理"])
  98. app.include_router(crm_opportunity_follow_router, prefix="/crm/opportunity/follow", tags=["商机跟进"])
  99. app.include_router(crm_opportunity_product_router, prefix="/crm/opportunity/product", tags=["商机产品"])
  100. app.include_router(crm_stage_log_router, prefix="/crm/opportunity/stageLog", tags=["商机阶段日志"])
  101. app.include_router(crm_product_router, prefix="/crm/product", tags=["产品管理"])
  102. app.include_router(crm_product_category_router, prefix="/crm/product/category", tags=["产品分类"])
  103. app.include_router(crm_product_tag_router, prefix="/crm/product/tag", tags=["产品标签"])
  104. app.include_router(crm_product_tag_relation_router, prefix="/crm/product/tagRelation", tags=["产品标签关联"])
  105. app.include_router(crm_product_attachment_router, prefix="/crm/product/attachment", tags=["产品附件"])
  106. app.include_router(crm_product_price_router, prefix="/crm/product/price", tags=["产品价格"])
  107. app.include_router(crm_product_price_history_router, prefix="/crm/product/price/history", tags=["产品价格历史"])
  108. app.include_router(crm_product_stock_router, prefix="/crm/product/stock", tags=["产品库存"])
  109. app.include_router(crm_quote_router, prefix="/crm/quote", tags=["报价管理"])
  110. app.include_router(crm_quote_product_router, prefix="/crm/quote/product", tags=["报价产品"])
  111. app.include_router(crm_quote_approval_router, prefix="/crm/quote/approval", tags=["报价审批"])
  112. app.include_router(crm_contract_router, prefix="/crm/contract", tags=["合同管理"])
  113. app.include_router(crm_payment_router, prefix="/crm/payment", tags=["回款管理"])
  114. app.include_router(crm_payment_plan_router, prefix="/crm/payment/plan", tags=["回款计划"])
  115. app.include_router(crm_payment_collection_router, prefix="/crm/payment/collection", tags=["催收管理"])
  116. app.include_router(crm_invoice_router, prefix="/crm/invoice", tags=["发票管理"])
  117. app.include_router(crm_invoice_info_router, prefix="/crm/invoiceInfo", tags=["开票信息"])
  118. app.include_router(crm_invoice_item_router, prefix="/crm/invoice/item", tags=["发票明细"])
  119. app.include_router(crm_visit_router, prefix="/crm/visit", tags=["回访管理"])
  120. app.include_router(crm_visit_plan_router, prefix="/crm/visit/plan", tags=["回访计划"])
  121. app.include_router(crm_visit_problem_router, prefix="/crm/visit/problem", tags=["回访问题"])
  122. app.include_router(crm_supplier_router, prefix="/crm/supplierInfo", tags=["供应商管理"])
  123. @app.get("/resource/sse")
  124. async def sse_endpoint(Authorization: str = "", clientid: str = ""):
  125. from starlette.responses import StreamingResponse
  126. async def event_generator():
  127. yield "event: heartbeat\ndata: \n\n"
  128. return StreamingResponse(event_generator(), media_type="text/event-stream")
  129. @app.get("/resource/sse/close")
  130. def sse_close():
  131. return {"code": 200, "msg": "ok"}
  132. @app.get("/resource/oss/listByIds/{oss_id}")
  133. def list_oss_by_ids(oss_id: str):
  134. from app.database import SessionLocal
  135. from app.models.system import SysOss
  136. db = SessionLocal()
  137. try:
  138. ids = []
  139. for part in str(oss_id).split(","):
  140. part = part.strip()
  141. if part.isdigit():
  142. ids.append(int(part))
  143. if not ids:
  144. return {"code": 200, "msg": "操作成功", "data": []}
  145. rows = db.query(SysOss).filter(SysOss.oss_id.in_(ids)).all()
  146. return {"code": 200, "msg": "操作成功", "data": [{
  147. "ossId": o.oss_id,
  148. "fileName": o.file_name,
  149. "originalName": o.original_name,
  150. "fileSuffix": o.file_suffix,
  151. "url": o.url,
  152. "size": getattr(o, "size", ""),
  153. } for o in rows]}
  154. finally:
  155. db.close()
  156. @app.get("/health")
  157. def health_check():
  158. return {"code": 200, "msg": "ok"}
  159. @app.exception_handler(Exception)
  160. async def global_exception_handler(request, exc):
  161. return JSONResponse(
  162. status_code=200,
  163. content={"code": 500, "msg": str(exc), "data": None},
  164. )
  165. from app.scheduler import start_scheduler
  166. start_scheduler()
  167. return app
  168. app = create_app()
  169. if __name__ == "__main__":
  170. import uvicorn
  171. uvicorn.run(
  172. "app.main:app",
  173. host=settings.APP_HOST,
  174. port=settings.APP_PORT,
  175. reload=settings.DEBUG,
  176. )