feat: 初始化考培练系统项目

- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
111
2026-01-24 19:33:28 +08:00
commit 998211c483
1197 changed files with 228429 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
"""基础响应模式"""
from typing import Generic, TypeVar, Optional, Any, List
from pydantic import BaseModel, Field
from datetime import datetime
DataT = TypeVar("DataT")
class ResponseModel(BaseModel, Generic[DataT]):
"""
统一响应格式模型
"""
code: int = Field(default=200, description="响应状态码")
message: str = Field(default="success", description="响应消息")
data: Optional[DataT] = Field(default=None, description="响应数据")
request_id: Optional[str] = Field(default=None, description="请求ID")
class BaseSchema(BaseModel):
"""基础模式"""
class Config:
from_attributes = True # Pydantic V2
json_encoders = {datetime: lambda v: v.isoformat()}
class TimestampMixin(BaseModel):
"""时间戳混入"""
created_at: datetime
updated_at: datetime
class IDMixin(BaseModel):
"""ID混入"""
id: int
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
@property
def limit(self) -> int:
"""计算限制数量"""
return self.page_size
class PaginatedResponse(BaseModel, Generic[DataT]):
"""分页响应模型"""
items: list[DataT] = Field(default_factory=list, description="数据列表")
total: int = Field(default=0, description="总数量")
page: int = Field(default=1, description="当前页码")
page_size: int = Field(default=20, description="每页数量")
pages: int = Field(default=1, description="总页数")
@classmethod
def create(cls, items: list[DataT], total: int, page: int, page_size: int):
"""创建分页响应"""
pages = (total + page_size - 1) // page_size if page_size > 0 else 1
return cls(
items=items, total=total, page=page, page_size=page_size, pages=pages
)