144 lines
5.2 KiB
Python
144 lines
5.2 KiB
Python
# =============================================================================
|
||
# 企微IT智能服务台 — 统一响应格式工具
|
||
# =============================================================================
|
||
# 说明:定义所有 API 的统一响应格式和异常处理
|
||
# 格式:{code: 0, data: {}, message: "success"}
|
||
# code=0 表示成功,非0表示错误(1000+通用/2000+企微/3000+业务)
|
||
# =============================================================================
|
||
|
||
from typing import Any, Dict, Optional
|
||
|
||
from fastapi import Request
|
||
from fastapi.responses import JSONResponse
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 统一响应函数
|
||
# --------------------------------------------------------------------------
|
||
def success_response(data: Any = None, message: str = "success") -> Dict[str, Any]:
|
||
"""构建成功响应。
|
||
|
||
所有 API 成功时都应使用此函数返回统一格式。
|
||
|
||
Args:
|
||
data: 业务数据(可以是字典、列表、None等)
|
||
message: 成功消息(默认 "success")
|
||
|
||
Returns:
|
||
Dict[str, Any]: 统一格式的响应字典
|
||
示例: {"code": 0, "data": {...}, "message": "success"}
|
||
"""
|
||
return {
|
||
"code": 0,
|
||
"data": data,
|
||
"message": message,
|
||
}
|
||
|
||
|
||
def error_response(code: int, message: str, data: Any = None) -> Dict[str, Any]:
|
||
"""构建错误响应。
|
||
|
||
所有 API 错误时都应使用此函数返回统一格式。
|
||
|
||
Args:
|
||
code: 错误码(1000+通用/2000+企微/3000+业务)
|
||
message: 错误消息
|
||
data: 附加数据(可选,如验证错误详情)
|
||
|
||
Returns:
|
||
Dict[str, Any]: 统一格式的错误响应字典
|
||
示例: {"code": 1001, "data": null, "message": "参数错误"}
|
||
"""
|
||
return {
|
||
"code": code,
|
||
"data": data,
|
||
"message": message,
|
||
}
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 业务异常类
|
||
# --------------------------------------------------------------------------
|
||
class AppException(Exception):
|
||
"""业务异常基类。
|
||
|
||
在业务逻辑中抛出此异常,全局异常处理器会自动转换为统一响应格式。
|
||
避免在每个路由函数中重复写 try/except 和响应构造代码。
|
||
|
||
Attributes:
|
||
code: 错误码
|
||
message: 错误消息
|
||
data: 附加数据
|
||
"""
|
||
|
||
def __init__(self, code: int, message: str, data: Any = None):
|
||
"""初始化业务异常。
|
||
|
||
Args:
|
||
code: 错误码
|
||
message: 错误消息
|
||
data: 附加数据
|
||
"""
|
||
self.code = code
|
||
self.message = message
|
||
self.data = data
|
||
super().__init__(self.message)
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 预定义错误常量
|
||
# --------------------------------------------------------------------------
|
||
# 错误码规范:
|
||
# 0 = 成功
|
||
# 1000+ = 通用错误(参数错误、未授权等)
|
||
# 2000+ = 企微 API 错误
|
||
# 3000+ = 业务逻辑错误
|
||
|
||
# --- 通用错误 (1000+) ---
|
||
ERR_PARAMS = AppException(1001, "参数错误")
|
||
ERR_UNAUTHORIZED = AppException(1002, "未授权")
|
||
ERR_NOT_FOUND = AppException(1003, "资源不存在")
|
||
ERR_FORBIDDEN = AppException(1004, "无权限访问")
|
||
ERR_INTERNAL = AppException(1005, "服务器内部错误")
|
||
|
||
# --- 企微 API 错误 (2000+) ---
|
||
ERR_WECOM_TOKEN = AppException(2001, "企微 access_token 获取失败")
|
||
ERR_WECOM_SEND = AppException(2002, "企微消息发送失败")
|
||
ERR_WECOM_DECRYPT = AppException(2003, "企微消息解密失败")
|
||
ERR_WECOM_ENCRYPT = AppException(2004, "企微消息加密失败")
|
||
ERR_WECOM_VERIFY = AppException(2005, "企微回调签名验证失败")
|
||
ERR_WECOM_USER_INFO = AppException(2006, "企微用户信息获取失败")
|
||
|
||
# --- 业务逻辑错误 (3000+) ---
|
||
ERR_AGENT_OFFLINE = AppException(3001, "坐席不在线")
|
||
ERR_CONVERSATION_RESOLVED = AppException(3002, "会话已结单")
|
||
ERR_CONVERSATION_NOT_FOUND = AppException(3003, "会话不存在")
|
||
ERR_AGENT_NOT_FOUND = AppException(3004, "坐席不存在")
|
||
ERR_AGENT_BUSY = AppException(3005, "坐席已满负荷,无法接单")
|
||
ERR_DUPLICATE_ASSIGN = AppException(3006, "会话已分配坐席")
|
||
ERR_GRAB_NO_AGENT = AppException(3011, "该会话尚未分配坐席,请使用接单功能")
|
||
ERR_GRAB_SELF = AppException(3012, "不能接手自己的会话")
|
||
ERR_GRAB_NOT_SERVING = AppException(3013, "只能接手服务中的会话")
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 全局异常处理器
|
||
# --------------------------------------------------------------------------
|
||
async def app_exception_handler(request: Request, exc: AppException) -> JSONResponse:
|
||
"""AppException 全局异常处理器。
|
||
|
||
当业务逻辑抛出 AppException 时,FastAPI 自动调用此处理器,
|
||
将异常转换为统一响应格式返回给前端。
|
||
|
||
Args:
|
||
request: 请求对象(FastAPI 自动传入)
|
||
exc: 业务异常对象(FastAPI 自动传入)
|
||
|
||
Returns:
|
||
JSONResponse: 统一格式的错误响应
|
||
"""
|
||
return JSONResponse(
|
||
status_code=200, # 业务错误仍返回 HTTP 200,通过 code 区分
|
||
content=error_response(exc.code, exc.message, exc.data),
|
||
)
|