from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Integer, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, validates from app.core.base_model import MappedBase class PackageModel(MappedBase): """ 套餐模型 - 定义租户可用的功能套餐 """ __tablename__: str = "platform_package" __table_args__: dict[str, str] = {"comment": "租户套餐表"} id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="主键ID") name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True, comment="套餐名称") code: Mapped[str] = mapped_column(String(100), nullable=False, unique=True, comment="套餐编码") status: Mapped[str] = mapped_column( String(10), nullable=False, default="0", comment="状态(0:正常 1:禁用)" ) sort: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="排序") description: Mapped[str | None] = mapped_column( String(255), nullable=True, default=None, comment="描述" ) create_time: Mapped[datetime] = mapped_column( DateTime, default=datetime.now, nullable=False, comment="创建时间" ) update_time: Mapped[datetime] = mapped_column( DateTime, default=datetime.now, onupdate=datetime.now, nullable=False, comment="更新时间" ) @validates("name") def validate_name(self, key: str, name: str) -> str: if not name or not name.strip(): raise ValueError("套餐名称不能为空") return name @validates("code") def validate_code(self, key: str, code: str) -> str: if not code or not code.strip(): raise ValueError("套餐编码不能为空") if not code.isalnum(): raise ValueError("套餐编码只能包含字母和数字") return code class PackageMenuModel(MappedBase): """ 套餐-菜单关联表 — 定义套餐包含的菜单资源 """ __tablename__: str = "platform_package_menu" __table_args__ = ( UniqueConstraint("package_id", "menu_id", name="uq_package_menu"), {"comment": "套餐菜单关联表"}, ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="主键ID") package_id: Mapped[int] = mapped_column( Integer, ForeignKey("platform_package.id", ondelete="CASCADE", onupdate="CASCADE"), nullable=False, index=True, comment="套餐ID", ) menu_id: Mapped[int] = mapped_column( Integer, ForeignKey("sys_menu.id", ondelete="CASCADE", onupdate="CASCADE"), nullable=False, index=True, comment="菜单ID", )