""" 通用响应格式 Schema ================== 与前端 ApiResponse 保持一致: { code: number; data: T; message: string } """ from typing import Any from pydantic import BaseModel, ConfigDict, Field class ApiResponse[T](BaseModel): """ 统一 API 响应格式 Attributes: code: HTTP 状态码(200 表示成功) data: 响应数据(泛型) message: 提示信息 """ code: int = Field(default=200, description="状态码,200 表示成功") data: T | None = Field(default=None, description="响应数据") message: str = Field(default="success", description="提示信息") model_config = ConfigDict( json_schema_extra={ "example": { "code": 200, "data": {}, "message": "success", } } ) class PaginatedData[T](BaseModel): """分页数据包装""" items: list[T] = Field(description="数据列表") total: int = Field(description="总数") page: int = Field(description="当前页码") page_size: int = Field(description="每页数量") has_more: bool = Field(description="是否有更多") class PaginationParams(BaseModel): """分页请求参数""" page: int = Field(default=1, ge=1, description="页码") page_size: int = Field(default=20, ge=1, le=100, description="每页数量") @property def offset(self) -> int: return (self.page - 1) * self.page_size class ApiErrorResponse(BaseModel): """错误响应格式""" code: int = Field(description="HTTP 状态码") message: str = Field(description="错误信息") error_code: str | None = Field(default=None, description="应用级错误码") detail: dict[str, Any] | None = Field(default=None, description="详细错误信息") def success_response[T](data: T | None = None, message: str = "success") -> ApiResponse[T]: """构造成功响应""" return ApiResponse(code=200, data=data, message=message) def error_response( code: int, message: str, detail: dict[str, Any] | None = None, *, error_code: str | None = None, ) -> ApiErrorResponse: """构造错误响应""" return ApiErrorResponse(code=code, message=message, error_code=error_code, detail=detail)