Files
FastapiAdmin/backend/app/api/v1/module_system/tenant/schema.py
T
zhangtao 53d2a9d13e chore: cleanup old frontend code and update project configs
This commit removes the deprecated frontend/web-old directory, updates various project configuration files including tsconfig, vite config, environment variables, and backend data models. It also fixes several API paths, adds tenant awareness to multiple models, and makes minor UI adjustments.
2026-05-27 01:12:03 +08:00

187 lines
6.9 KiB
Python

from fastapi import Query
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from app.common.enums import QueueEnum
from app.core.base_schema import BaseSchema
from app.core.validator import DateTimeStr
class TenantCreateSchema(BaseModel):
"""新增租户"""
name: str = Field(..., max_length=100, description="租户名称")
code: str = Field(..., max_length=100, description="租户编码")
status: str = Field(default="0", description="状态(0:正常 1:禁用)")
description: str | None = Field(default=None, max_length=255, description="描述")
start_time: DateTimeStr | None = Field(default=None, description="开始时间")
end_time: DateTimeStr | None = Field(default=None, description="结束时间")
contact_name: str | None = Field(default=None, max_length=64, description="联系人姓名")
contact_phone: str | None = Field(default=None, max_length=20, description="联系人电话")
contact_email: str | None = Field(default=None, max_length=128, description="联系人邮箱")
address: str | None = Field(default=None, max_length=255, description="地址")
domain: str | None = Field(default=None, max_length=255, description="域名")
logo_url: str | None = Field(default=None, max_length=500, description="Logo URL")
sort: int = Field(default=0, description="排序")
@field_validator("name")
@classmethod
def _validate_name(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("名称不能为空")
return v
@field_validator("code")
@classmethod
def _validate_code(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("编码不能为空")
if not v.isalnum():
raise ValueError("编码只能包含字母和数字")
return v
@model_validator(mode="after")
def _validate_time_range(self):
if self.start_time and self.end_time and self.start_time > self.end_time:
raise ValueError("结束时间不能早于开始时间")
return self
class TenantUpdateSchema(BaseModel):
"""更新租户"""
name: str | None = Field(default=None, max_length=100, description="租户名称")
code: str | None = Field(default=None, max_length=100, description="租户编码")
status: str | None = Field(default=None, description="状态(0:正常 1:禁用)")
description: str | None = Field(default=None, max_length=255, description="描述")
start_time: DateTimeStr | None = Field(default=None, description="开始时间")
end_time: DateTimeStr | None = Field(default=None, description="结束时间")
contact_name: str | None = Field(default=None, max_length=64, description="联系人姓名")
contact_phone: str | None = Field(default=None, max_length=20, description="联系人电话")
contact_email: str | None = Field(default=None, max_length=128, description="联系人邮箱")
address: str | None = Field(default=None, max_length=255, description="地址")
domain: str | None = Field(default=None, max_length=255, description="域名")
logo_url: str | None = Field(default=None, max_length=500, description="Logo URL")
sort: int | None = Field(default=None, description="排序")
@field_validator("code")
@classmethod
def _validate_code(cls, v: str | None) -> str | None:
if v is None:
return v
v = v.strip()
if not v.isalnum():
raise ValueError("编码只能包含字母和数字")
return v
@model_validator(mode="after")
def _validate_time_range(self):
if self.start_time and self.end_time and self.start_time > self.end_time:
raise ValueError("结束时间不能早于开始时间")
return self
class TenantOutSchema(TenantCreateSchema, BaseSchema):
"""租户响应"""
model_config = ConfigDict(from_attributes=True)
class TenantQueryParam:
"""租户查询参数"""
def __init__(
self,
name: str | None = Query(None, description="租户名称"),
code: str | None = Query(None, description="租户编码"),
status: str | None = Query(None, description="状态"),
created_time: list[DateTimeStr] | None = Query(
None,
description="创建时间范围",
examples=["2025-01-01 00:00:00", "2025-12-31 23:59:59"],
),
) -> None:
if name:
self.name = (QueueEnum.like.value, name)
if code:
self.code = (QueueEnum.like.value, code)
if status:
self.status = (QueueEnum.eq.value, status)
if created_time and len(created_time) == 2:
self.created_time = (QueueEnum.between.value, (created_time[0], created_time[1]))
class TenantUserAddSchema(BaseModel):
"""向租户添加用户"""
user_id: int = Field(..., description="用户ID")
role: str = Field(default="member", description="租户内角色(owner/admin/member)")
is_default: int = Field(default=0, description="是否默认租户(0:否 1:是)")
class TenantUserOutSchema(BaseModel):
"""租户用户响应"""
model_config = ConfigDict(from_attributes=True)
id: int = Field(..., description="关联ID")
user_id: int = Field(..., description="用户ID")
tenant_id: int = Field(..., description="租户ID")
role: str = Field(..., description="租户内角色")
is_default: int = Field(..., description="是否默认租户")
create_time: DateTimeStr | None = Field(default=None, description="创建时间")
username: str = Field(default="", description="用户名")
name: str = Field(default="", description="用户姓名")
# ============ P1: 配额管理 ============
class TenantQuotaOutSchema(BaseModel):
"""租户配额响应"""
model_config = ConfigDict(from_attributes=True)
id: int
tenant_id: int
max_users: int
max_roles: int
max_storage_mb: int
max_depts: int
class TenantQuotaUpdateSchema(BaseModel):
"""租户配额更新"""
max_users: int | None = Field(default=None, ge=0, description="最大用户数")
max_roles: int | None = Field(default=None, ge=0, description="最大角色数")
max_storage_mb: int | None = Field(default=None, ge=0, description="最大存储(MB)")
max_depts: int | None = Field(default=None, ge=0, description="最大部门数")
# ============ P1: 租户配置 ============
class TenantConfigItem(BaseModel):
"""单个配置项"""
config_key: str = Field(..., description="配置键")
config_value: str = Field(..., description="配置值")
config_type: str = Field(default="string", description="配置类型")
class TenantConfigOutSchema(TenantConfigItem):
"""租户配置响应"""
model_config = ConfigDict(from_attributes=True)
id: int
tenant_id: int
# ============ P1: 租户菜单 ============
class TenantMenuSetSchema(BaseModel):
"""批量设置租户菜单权限"""
menu_ids: list[int] = Field(..., description="菜单ID列表")