""" 管理后台数据模型 """ from datetime import datetime from typing import Optional, List, Any, Dict from pydantic import BaseModel, Field # ============================================ # 通用模型 # ============================================ class ResponseModel(BaseModel): """通用响应模型""" code: int = 0 message: str = "success" data: Optional[Any] = None class PaginationParams(BaseModel): """分页参数""" page: int = Field(default=1, ge=1) page_size: int = Field(default=20, ge=1, le=100) class PaginatedResponse(BaseModel): """分页响应""" items: List[Any] total: int page: int page_size: int total_pages: int # ============================================ # 认证相关 # ============================================ class AdminLoginRequest(BaseModel): """管理员登录请求""" username: str = Field(..., min_length=1, max_length=50) password: str = Field(..., min_length=6) class AdminLoginResponse(BaseModel): """管理员登录响应""" access_token: str token_type: str = "bearer" expires_in: int admin_user: "AdminUserInfo" class AdminUserInfo(BaseModel): """管理员信息""" id: int username: str email: Optional[str] full_name: Optional[str] role: str last_login_at: Optional[datetime] class AdminChangePasswordRequest(BaseModel): """修改密码请求""" old_password: str = Field(..., min_length=6) new_password: str = Field(..., min_length=6) # ============================================ # 租户相关 # ============================================ class TenantBase(BaseModel): """租户基础信息""" code: str = Field(..., min_length=2, max_length=20, pattern=r'^[a-z0-9_]+$') name: str = Field(..., min_length=1, max_length=100) display_name: Optional[str] = Field(None, max_length=200) domain: str = Field(..., min_length=1, max_length=200) logo_url: Optional[str] = None favicon_url: Optional[str] = None contact_name: Optional[str] = None contact_phone: Optional[str] = None contact_email: Optional[str] = None industry: str = Field(default="medical_beauty") remarks: Optional[str] = None class TenantCreate(TenantBase): """创建租户请求""" pass class TenantUpdate(BaseModel): """更新租户请求""" name: Optional[str] = Field(None, min_length=1, max_length=100) display_name: Optional[str] = Field(None, max_length=200) domain: Optional[str] = Field(None, min_length=1, max_length=200) logo_url: Optional[str] = None favicon_url: Optional[str] = None contact_name: Optional[str] = None contact_phone: Optional[str] = None contact_email: Optional[str] = None industry: Optional[str] = None status: Optional[str] = None expire_at: Optional[datetime] = None remarks: Optional[str] = None class TenantResponse(TenantBase): """租户响应""" id: int status: str expire_at: Optional[datetime] created_at: datetime updated_at: datetime config_count: int = 0 # 配置项数量 class Config: from_attributes = True class TenantListResponse(BaseModel): """租户列表响应""" items: List[TenantResponse] total: int page: int page_size: int # ============================================ # 配置相关 # ============================================ class ConfigTemplateResponse(BaseModel): """配置模板响应""" id: int config_group: str config_key: str display_name: str description: Optional[str] value_type: str default_value: Optional[str] is_required: bool is_secret: bool options: Optional[List[str]] sort_order: int class TenantConfigBase(BaseModel): """租户配置基础""" config_group: str config_key: str config_value: Optional[str] = None class TenantConfigCreate(TenantConfigBase): """创建租户配置请求""" pass class TenantConfigUpdate(BaseModel): """更新租户配置请求""" config_value: Optional[str] = None class TenantConfigResponse(TenantConfigBase): """租户配置响应""" id: int value_type: str is_encrypted: bool description: Optional[str] created_at: Optional[datetime] = None updated_at: Optional[datetime] = None # 从模板获取的额外信息 display_name: Optional[str] = None is_required: bool = False is_secret: bool = False class Config: from_attributes = True class TenantConfigGroupResponse(BaseModel): """租户配置分组响应""" group_name: str group_display_name: str configs: List[TenantConfigResponse] class ConfigBatchUpdate(BaseModel): """批量更新配置请求""" configs: List[TenantConfigCreate] # ============================================ # 提示词相关 # ============================================ class AIPromptBase(BaseModel): """AI提示词基础""" code: str = Field(..., min_length=1, max_length=50) name: str = Field(..., min_length=1, max_length=100) description: Optional[str] = None module: str system_prompt: str user_prompt_template: Optional[str] = None variables: Optional[List[str]] = None output_schema: Optional[Dict] = None model_recommendation: Optional[str] = None max_tokens: int = 4096 temperature: float = 0.7 class AIPromptCreate(AIPromptBase): """创建提示词请求""" pass class AIPromptUpdate(BaseModel): """更新提示词请求""" name: Optional[str] = Field(None, min_length=1, max_length=100) description: Optional[str] = None system_prompt: Optional[str] = None user_prompt_template: Optional[str] = None variables: Optional[List[str]] = None output_schema: Optional[Dict] = None model_recommendation: Optional[str] = None max_tokens: Optional[int] = None temperature: Optional[float] = None is_active: Optional[bool] = None class AIPromptResponse(AIPromptBase): """提示词响应""" id: int is_system: bool is_active: bool version: int created_at: datetime updated_at: datetime class Config: from_attributes = True class AIPromptVersionResponse(BaseModel): """提示词版本响应""" id: int prompt_id: int version: int system_prompt: str user_prompt_template: Optional[str] variables: Optional[List[str]] change_summary: Optional[str] created_at: datetime class Config: from_attributes = True class TenantPromptResponse(BaseModel): """租户自定义提示词响应""" id: int tenant_id: int prompt_id: int prompt_code: str prompt_name: str system_prompt: Optional[str] user_prompt_template: Optional[str] is_active: bool created_at: datetime updated_at: datetime class Config: from_attributes = True class TenantPromptUpdate(BaseModel): """更新租户自定义提示词""" system_prompt: Optional[str] = None user_prompt_template: Optional[str] = None is_active: Optional[bool] = None # ============================================ # 功能开关相关 # ============================================ class FeatureSwitchBase(BaseModel): """功能开关基础""" feature_code: str feature_name: str feature_group: Optional[str] = None is_enabled: bool = True config: Optional[Dict] = None description: Optional[str] = None class FeatureSwitchCreate(FeatureSwitchBase): """创建功能开关请求""" pass class FeatureSwitchUpdate(BaseModel): """更新功能开关请求""" is_enabled: Optional[bool] = None config: Optional[Dict] = None class FeatureSwitchResponse(FeatureSwitchBase): """功能开关响应""" id: int tenant_id: Optional[int] created_at: datetime updated_at: datetime class Config: from_attributes = True class FeatureSwitchGroupResponse(BaseModel): """功能开关分组响应""" group_name: str group_display_name: str features: List[FeatureSwitchResponse] # ============================================ # 操作日志相关 # ============================================ class OperationLogResponse(BaseModel): """操作日志响应""" id: int admin_username: Optional[str] tenant_code: Optional[str] operation_type: str resource_type: str resource_name: Optional[str] old_value: Optional[Dict] new_value: Optional[Dict] ip_address: Optional[str] created_at: datetime class Config: from_attributes = True # 更新前向引用 AdminLoginResponse.model_rebuild()