""" 系统设置域 Pydantic V2 Schemas 部门树 / 角色(含 JSONB menu_keys)/ 用户管理 """ from __future__ import annotations import uuid from datetime import datetime from pydantic import BaseModel, Field # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # 部门树 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class DeptNode(BaseModel): id: uuid.UUID parent_id: uuid.UUID | None = None name: str sort_order: int = 0 status: int = 1 children: list[DeptNode] = Field(default_factory=list) model_config = {"from_attributes": True} # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # 角色 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class RoleCreate(BaseModel): role_name: str = Field(..., min_length=1, max_length=50) data_scope: str = Field( default="self", pattern=r"^(all|dept_and_sub|self)$" ) menu_keys: list[str] = Field( default_factory=list, description="前端路由 name 数组,JSONB 存储", examples=[["CustomerList", "OrderList", "ProductList"]], ) description: str | None = Field(default=None, max_length=255) status: int = Field(default=1, ge=0, le=1) class RoleUpdate(BaseModel): role_name: str | None = Field(default=None, min_length=1, max_length=50) data_scope: str | None = Field(default=None, pattern=r"^(all|dept_and_sub|self)$") menu_keys: list[str] | None = None description: str | None = Field(default=None, max_length=255) status: int | None = Field(default=None, ge=0, le=1) class RoleResponse(BaseModel): id: uuid.UUID role_name: str data_scope: str menu_keys: list[str] = Field(default_factory=list) description: str | None = None status: int = 1 created_at: datetime model_config = {"from_attributes": True} # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # 用户/员工 # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class UserCreate(BaseModel): username: str = Field(..., min_length=2, max_length=50) password: str = Field(..., min_length=6, max_length=128, description="明文密码,后端 bcrypt 哈希后存储") real_name: str | None = Field(default=None, max_length=50) phone: str | None = Field(default=None, max_length=20) email: str | None = Field(default=None, max_length=100) dept_id: uuid.UUID | None = None role_id: uuid.UUID | None = None status: int = Field(default=1, ge=0, le=1) class UserUpdate(BaseModel): real_name: str | None = Field(default=None, max_length=50) phone: str | None = Field(default=None, max_length=20) email: str | None = Field(default=None, max_length=100) dept_id: uuid.UUID | None = None role_id: uuid.UUID | None = None status: int | None = Field(default=None, ge=0, le=1) class UserResetPassword(BaseModel): new_password: str = Field(..., min_length=6, max_length=128) class UserResponse(BaseModel): id: uuid.UUID username: str real_name: str | None = None phone: str | None = None email: str | None = None dept_id: uuid.UUID | None = None dept_name: str | None = None role_id: uuid.UUID | None = None role_name: str | None = None data_scope: str | None = None status: int = 1 last_login_at: datetime | None = None created_at: datetime model_config = {"from_attributes": True} class UserListResponse(BaseModel): total: int items: list[UserResponse] page: int size: int