mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 12:52:26 +00:00
开源准备
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class UploadResponseSchema(BaseModel):
|
||||
"""
|
||||
上传响应模型
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
file_path: Optional[str] = Field(default=None, description='新文件映射路径')
|
||||
file_name: Optional[str] = Field(default=None, description='新文件名称')
|
||||
origin_name: Optional[str] = Field(default=None, description='原文件名称')
|
||||
file_url: Optional[str] = Field(default=None, description='新文件访问地址')
|
||||
|
||||
|
||||
class FileListResponseSchema(BaseModel):
|
||||
"""
|
||||
获取文件列表返回模型
|
||||
"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: Optional[str] = Field(default=None, description='文件名称')
|
||||
type: Optional[str] = Field(default=None, description='文件类型')
|
||||
size: Optional[int] = Field(default=None, description='文件大小')
|
||||
modified_time: Optional[str] = Field(default=None, description='文件修改时间')
|
||||
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
class CacheMonitorSchema(BaseModel):
|
||||
"""缓存监控信息模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
command_stats: List[Dict] = Field(default_factory=list, description='Redis命令统计信息')
|
||||
db_size: int = Field(default=0, description='Redis数据库中的Key总数')
|
||||
info: Dict[str, Any] = Field(default_factory=dict, description='Redis服务器信息')
|
||||
|
||||
|
||||
class CacheInfoSchema(BaseModel):
|
||||
"""缓存对象信息模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
cache_key: str = Field(default='', description='缓存键名')
|
||||
cache_name: str = Field(default='', description='缓存名称')
|
||||
cache_value: Any = Field(default=None, description='缓存值')
|
||||
remark: Optional[str] = Field(default=None, description='备注说明')
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
|
||||
from app.core.validator import DateTimeStr
|
||||
|
||||
|
||||
class OnlineOutSchema(BaseModel):
|
||||
"""
|
||||
在线用户对应pydantic模型
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
session_id: Optional[str] = Field(default=None, description='会话编号')
|
||||
user_id: Optional[int] = Field(default=None, description='用户ID')
|
||||
user_name: Optional[str] = Field(default=None, description='用户名')
|
||||
ipaddr: Optional[str] = Field(default=None, description='登陆IP地址')
|
||||
login_location: Optional[str] = Field(default=None, description='登录所属地')
|
||||
os: Optional[str] = Field(default=None, description='操作系统')
|
||||
browser: Optional[str] = Field(default=None, description='浏览器')
|
||||
login_time: Optional[DateTimeStr] = Field(default=None, description='登录时间')
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import List
|
||||
|
||||
|
||||
class CpuInfoSchema(BaseModel):
|
||||
"""CPU信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
cpu_num: int = Field(description="CPU核心数")
|
||||
used: float = Field(ge=0, le=100, description="CPU用户使用率(%)")
|
||||
sys: float = Field(ge=0, le=100, description="CPU系统使用率(%)")
|
||||
free: float = Field(ge=0, le=100, description="CPU空闲率(%)")
|
||||
|
||||
|
||||
class MemoryInfoSchema(BaseModel):
|
||||
"""内存信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
total: str = Field(description="内存总量")
|
||||
used: str = Field(description="已用内存")
|
||||
free: str = Field(description="剩余内存")
|
||||
usage: float = Field(ge=0, le=100, description="使用率(%)")
|
||||
|
||||
|
||||
class SysInfoSchema(BaseModel):
|
||||
"""系统信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
computer_ip: str = Field(description="服务器IP")
|
||||
computer_name: str = Field(description="服务器名称")
|
||||
os_arch: str = Field(description="系统架构")
|
||||
os_name: str = Field(description="操作系统")
|
||||
user_dir: str = Field(description="项目路径")
|
||||
|
||||
|
||||
class PyInfoSchema(BaseModel):
|
||||
"""Python运行信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: str = Field(description="Python名称")
|
||||
version: str = Field(description="Python版本")
|
||||
start_time: str = Field(description="启动时间")
|
||||
run_time: str = Field(description="运行时长")
|
||||
home: str = Field(description="安装路径")
|
||||
memory_used: str = Field(description="内存占用")
|
||||
memory_usage: float = Field(ge=0, le=100, description="内存使用率(%)")
|
||||
memory_total: str = Field(description="总内存")
|
||||
memory_free: str = Field(description="剩余内存")
|
||||
|
||||
|
||||
class DiskInfoSchema(BaseModel):
|
||||
"""磁盘信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
dir_name: str = Field(description="磁盘路径")
|
||||
sys_type_name: str = Field(description="文件系统类型")
|
||||
type_name: str = Field(description="磁盘类型")
|
||||
total: str = Field(description="总容量")
|
||||
used: str = Field(description="已用容量")
|
||||
free: str = Field(description="可用容量")
|
||||
usage: float = Field(ge=0, le=100, description="使用率(%)")
|
||||
|
||||
|
||||
class ServerMonitorSchema(BaseModel):
|
||||
"""服务器监控信息模型"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
cpu: CpuInfoSchema = Field(description="CPU信息")
|
||||
mem: MemoryInfoSchema = Field(description="内存信息")
|
||||
py: PyInfoSchema = Field(description="Python运行信息")
|
||||
sys: SysInfoSchema = Field(description="系统信息")
|
||||
disks: List[DiskInfoSchema] = Field(default_factory=list, description="磁盘信息")
|
||||
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional, Union
|
||||
from datetime import datetime
|
||||
from pydantic import ConfigDict, Field, BaseModel, model_validator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.v1.schemas.system.user_schema import UserOutSchema
|
||||
|
||||
|
||||
class AuthSchema(BaseModel):
|
||||
"""权限认证模型"""
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
user: Optional[UserOutSchema] = Field(default=None, description='用户信息')
|
||||
check_data_scope: bool = Field(default=True, description='是否检查数据权限')
|
||||
db: AsyncSession = Field(default=None, description='数据库会话')
|
||||
|
||||
|
||||
class JWTPayloadSchema(BaseModel):
|
||||
"""JWT载荷模型"""
|
||||
sub: str = Field(..., description='用户ID')
|
||||
is_refresh: bool = Field(default=False, description='是否刷新token')
|
||||
exp: Union[datetime, int] = Field(..., description='过期时间')
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_fields(cls, data):
|
||||
if not data.sub or len(data.sub.strip()) == 0:
|
||||
raise ValueError("用户ID不能为空")
|
||||
return data
|
||||
|
||||
|
||||
class JWTOutSchema(BaseModel):
|
||||
"""JWT响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
access_token: str = Field(..., min_length=1, description='访问token')
|
||||
refresh_token: str = Field(..., min_length=1, description='刷新token')
|
||||
token_type: str = Field(default='Bearer', description='token类型')
|
||||
expires_in: int = Field(..., gt=0, description='过期时间(秒)')
|
||||
|
||||
|
||||
class RefreshTokenPayloadSchema(BaseModel):
|
||||
"""刷新Token载荷模型"""
|
||||
refresh_token: str = Field(..., min_length=1, description='刷新token')
|
||||
|
||||
|
||||
class LogoutPayloadSchema(BaseModel):
|
||||
"""退出登录载荷模型"""
|
||||
token: str = Field(..., min_length=1, description='token')
|
||||
|
||||
|
||||
class CaptchaOutSchema(BaseModel):
|
||||
"""验证码响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
key: str = Field(..., min_length=1, description='验证码唯一标识')
|
||||
img_base: str = Field(..., min_length=1, description='Base64编码的验证码图片')
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class DeptCreateSchema(BaseModel):
|
||||
"""部门创建模型"""
|
||||
|
||||
name: str = Field(..., max_length=40, description="部门名称")
|
||||
order: int = Field(default=1, ge=0, description="显示顺序")
|
||||
available: bool = Field(default=True, description="是否启用(True:启用 False:禁用)")
|
||||
parent_id: Optional[int] = Field(default=None, ge=0, description="父部门ID")
|
||||
description: Optional[str] = Field(default=None, max_length=500, description="备注说明")
|
||||
|
||||
@classmethod
|
||||
@model_validator(mode='after')
|
||||
def validate_fields(cls, data):
|
||||
if not data.name or len(data.name.strip()) == 0:
|
||||
raise ValueError("部门名称不能为空")
|
||||
return data
|
||||
|
||||
|
||||
class DeptUpdateSchema(DeptCreateSchema):
|
||||
"""部门更新模型"""
|
||||
id: int = Field(..., gt=0, description="部门ID")
|
||||
|
||||
|
||||
class DeptOutSchema(DeptCreateSchema, BaseSchema):
|
||||
"""部门响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
parent_name: Optional[str] = Field(default=None, max_length=40, description="父部门名称")
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
from app.core.validator import menu_request_validator
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class MenuCreateSchema(BaseModel):
|
||||
"""菜单创建模型"""
|
||||
|
||||
name: str = Field(..., max_length=50, description="菜单名称")
|
||||
type: int = Field(..., ge=1, le=3, description="菜单类型(1:目录 2:菜单 3:按钮)")
|
||||
icon: Optional[str] = Field(default=None, max_length=100, description="菜单图标")
|
||||
order: int = Field(default=1, ge=0, description="显示顺序")
|
||||
permission: Optional[str] = Field(default=None, max_length=100, description="权限标识")
|
||||
route_name: Optional[str] = Field(default=None, max_length=100, description="路由名称")
|
||||
route_path: Optional[str] = Field(default=None, max_length=200, description="路由地址")
|
||||
component_path: Optional[str] = Field(default=None, max_length=255, description="组件路径")
|
||||
redirect: Optional[str] = Field(default=None, max_length=200, description="重定向地址")
|
||||
available: bool = Field(default=True, description="是否启用(True:启用 False:禁用)")
|
||||
cache: bool = Field(default=True, description="是否缓存(True:是 False:否)")
|
||||
hidden: bool = Field(default=False, description="是否隐藏(True:是 False:否)")
|
||||
parent_id: Optional[int] = Field(default=None, ge=0, description="父菜单ID")
|
||||
description: Optional[str] = Field(default=None, max_length=500, description="备注说明")
|
||||
|
||||
@classmethod
|
||||
@model_validator(mode='after')
|
||||
def validate_fields(cls, data):
|
||||
return menu_request_validator(data)
|
||||
|
||||
|
||||
class MenuUpdateSchema(MenuCreateSchema):
|
||||
"""菜单更新模型"""
|
||||
id: int = Field(..., gt=0, description="菜单ID")
|
||||
parent_name: Optional[str] = Field(default=None, max_length=50, description="父菜单名称")
|
||||
|
||||
|
||||
class MenuOutSchema(MenuCreateSchema, BaseSchema):
|
||||
"""菜单响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
parent_name: Optional[str] = Field(default=None, max_length=50, description="父菜单名称")
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class NoticeCreateSchema(BaseModel):
|
||||
"""公告通知创建模型"""
|
||||
notice_title: str = Field(..., max_length=50, description='公告标题')
|
||||
notice_type: int = Field(..., ge=1, le=2, description='公告类型(1通知 2公告)')
|
||||
notice_content: str = Field(..., description='公告内容')
|
||||
available: bool = Field(True, description="是否启用(True:启用 False:禁用)")
|
||||
description: Optional[str] = Field(None, max_length=255, description="公告描述")
|
||||
|
||||
|
||||
class NoticeUpdateSchema(NoticeCreateSchema):
|
||||
"""公告通知更新模型"""
|
||||
id: int = Field(..., gt=0, description="公告通知ID")
|
||||
|
||||
|
||||
class NoticeOutSchema(NoticeCreateSchema, BaseSchema):
|
||||
"""公告通知响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class OperationLogCreateSchema(BaseModel):
|
||||
"""日志创建模型"""
|
||||
request_path: Optional[str] = Field(default=None, description="请求路径")
|
||||
request_method: Optional[str] = Field(default=None, description="请求方法")
|
||||
request_payload: Optional[str] = Field(default=None, description="请求负载")
|
||||
request_ip: Optional[str] = Field(default=None, description="请求 IP 地址")
|
||||
request_os: Optional[str] = Field(default=None, description="请求操作系统")
|
||||
request_browser: Optional[str] = Field(default=None, description="请求浏览器")
|
||||
response_code: Optional[int] = Field(default=None, description="响应状态码")
|
||||
response_json: Optional[str] = Field(default=None, description="响应 JSON 数据")
|
||||
description: Optional[str] = Field(default=None, max_length=255, description="备注")
|
||||
creator_id: Optional[int] = Field(default=None, description="创建人ID")
|
||||
|
||||
|
||||
class OperationLogOutSchema(OperationLogCreateSchema, BaseSchema):
|
||||
"""日志响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class PositionCreateSchema(BaseModel):
|
||||
"""岗位创建模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: str = Field(..., max_length=40, description="岗位名称")
|
||||
order: Optional[int] = Field(default=1, ge=1, description='显示排序')
|
||||
available: bool = Field(default=True, description="是否启用(True:启用 False:禁用)")
|
||||
dept_id: Optional[int] = Field(None, gt=0, description="所属部门ID")
|
||||
description: Optional[str] = Field(None, description="备注说明")
|
||||
|
||||
|
||||
class PositionUpdateSchema(PositionCreateSchema):
|
||||
"""岗位更新模型"""
|
||||
id: int = Field(..., gt=0, description="岗位ID")
|
||||
|
||||
|
||||
class PositionOutSchema(PositionCreateSchema, BaseSchema):
|
||||
"""岗位信息响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
from app.api.v1.schemas.system.dept_schema import DeptOutSchema
|
||||
from app.api.v1.schemas.system.menu_schema import MenuOutSchema
|
||||
from app.core.base_schema import BaseSchema
|
||||
from app.core.validator import role_permission_request_validator
|
||||
|
||||
|
||||
class RoleCreateSchema(BaseModel):
|
||||
"""角色创建模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
name: str = Field(default=None, max_length=15, description="角色名称")
|
||||
order: Optional[int] = Field(default=1, ge=1, description='显示排序')
|
||||
data_scope: Optional[int] = Field(default=1, ge=1, le=5, description='数据权限范围')
|
||||
available: bool = Field(default=True, description="是否启用")
|
||||
description: Optional[str] = Field(None, max_length=255, description="角色描述")
|
||||
|
||||
|
||||
class RolePermissionSettingSchema(BaseModel):
|
||||
"""角色权限配置模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
data_scope: int = Field(default=1, ge=1, le=5, description='数据权限范围')
|
||||
role_ids: List[int] = Field(default_factory=list, description='角色ID列表')
|
||||
menu_ids: List[int] = Field(default_factory=list, description='菜单ID列表')
|
||||
dept_ids: List[int] = Field(default_factory=list, description='部门ID列表')
|
||||
|
||||
@classmethod
|
||||
@model_validator(mode='after')
|
||||
def validate_fields(cls, data):
|
||||
"""验证权限配置字段"""
|
||||
return role_permission_request_validator(data)
|
||||
|
||||
|
||||
class RoleUpdateSchema(RoleCreateSchema):
|
||||
"""角色更新模型"""
|
||||
id: int = Field(..., gt=0, description="角色ID")
|
||||
|
||||
|
||||
class RoleOutSchema(RoleCreateSchema, BaseSchema):
|
||||
"""角色信息响应模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
menus: List[MenuOutSchema] = Field(default_factory=list, description='角色菜单列表')
|
||||
depts: List[DeptOutSchema] = Field(default_factory=list, description='角色部门列表')
|
||||
@@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, ConfigDict, Field, EmailStr, field_validator
|
||||
|
||||
from app.api.v1.schemas.system.position_schema import PositionOutSchema
|
||||
from app.api.v1.schemas.system.role_schema import RoleOutSchema
|
||||
from app.api.v1.schemas.system.dept_schema import DeptOutSchema
|
||||
from app.core.validator import DateTimeStr, mobile_validator
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class CurrentUserUpdateSchema(BaseModel):
|
||||
"""基础用户信息"""
|
||||
name: str = Field(default=None, max_length=15, description="名称")
|
||||
mobile: Optional[str] = Field(default=None, description="手机号")
|
||||
email: Optional[EmailStr] = Field(default=None, description="邮箱")
|
||||
gender: Optional[int] = Field(default=1, description="性别") # 1:男 2:女
|
||||
avatar: Optional[str] = Field(default=None, description="头像")
|
||||
|
||||
@classmethod
|
||||
@field_validator("mobile")
|
||||
def validate_mobile(cls, value: Optional[str]):
|
||||
return mobile_validator(value)
|
||||
|
||||
|
||||
class UserRegisterSchema(CurrentUserUpdateSchema):
|
||||
"""注册"""
|
||||
name: str = Field(default=None, max_length=15, description="名称")
|
||||
mobile: Optional[str] = Field(default=None, description="手机号")
|
||||
email: Optional[EmailStr] = Field(default=None, description="邮箱")
|
||||
gender: Optional[int] = Field(default=1, description="性别") # 1:男 2:女
|
||||
username: str = Field(default=None, max_length=15, description="用户名")
|
||||
password: str = Field(default=None, max_length=128, description="密码哈希值")
|
||||
|
||||
|
||||
class UserForgetPasswordSchema(BaseModel):
|
||||
"""忘记密码"""
|
||||
username: str = Field(default=None, max_length=15, description="用户名")
|
||||
mobile: Optional[str] = Field(default=None, description="手机号")
|
||||
new_password: str = Field(default=None, max_length=128, description="新密码")
|
||||
|
||||
@classmethod
|
||||
@field_validator("mobile")
|
||||
def validate_mobile(cls, value: Optional[str]):
|
||||
return mobile_validator(value)
|
||||
|
||||
|
||||
class UserChangePasswordSchema(BaseModel):
|
||||
"""修改密码"""
|
||||
old_password: str = Field(default=None, max_length=128, description="旧密码")
|
||||
new_password: str = Field(default=None, max_length=128, description="新密码")
|
||||
|
||||
|
||||
class UserCreateSchema(CurrentUserUpdateSchema):
|
||||
"""新增"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
username: str = Field(default=None, max_length=15, description="用户名")
|
||||
password: Optional[str] = Field(default=None, max_length=128, description="密码哈希值")
|
||||
available: bool = Field(default=True, description="是否可用")
|
||||
is_superuser: bool = Field(default=False, description="是否超管")
|
||||
description: Optional[str] = Field(None, max_length=255, description="备注")
|
||||
|
||||
dept_id: Optional[int] = Field(default=None, description='部门ID')
|
||||
role_ids: Optional[List[int]] = Field(default=[], description='角色ID')
|
||||
position_ids: Optional[List[int]] = Field(default=[], description='岗位ID')
|
||||
|
||||
|
||||
class UserUpdateSchema(UserCreateSchema):
|
||||
"""更新"""
|
||||
id: int = Field(..., description="主键ID")
|
||||
|
||||
|
||||
class UserOutSchema(UserCreateSchema, BaseSchema):
|
||||
"""响应"""
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True)
|
||||
|
||||
last_login: Optional[DateTimeStr] = Field(default=None, description="最后登录时间")
|
||||
dept_name: Optional[str] = Field(default=None, description='部门名称')
|
||||
dept: Optional[DeptOutSchema] = Field(default=None, description='部门')
|
||||
roles: List[RoleOutSchema] = Field(default=[], description='角色')
|
||||
positions: List[PositionOutSchema] = Field(default=[], description='岗位')
|
||||
Reference in New Issue
Block a user