"""角色、权限及其关联模型(RBAC 标准五表的后四张)。 权限与角色是多对多:一个权限(如「计提参数配置」)可授予多个角色, 因此关联必须独立成表,不能把 role_id 塞进 permissions 表。 """ from datetime import datetime from typing import TYPE_CHECKING from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, UniqueConstraint, text from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import BIGINT_UNSIGNED, TINYINT_TYPE, Base, TimestampMixin, mysql_table_args if TYPE_CHECKING: from app.models.user import UserRole class Role(Base, TimestampMixin): """角色表。本期仅 admin / user 两个角色,数据随迁移脚本初始化。""" __tablename__ = "roles" __table_args__ = mysql_table_args("角色表") id: Mapped[int] = mapped_column( BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID" ) role_code: Mapped[str] = mapped_column( String(32), nullable=False, unique=True, comment="角色编码:admin系统管理员 user普通用户" ) role_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="角色名称") description: Mapped[str | None] = mapped_column(String(255), comment="角色说明") sort_order: Mapped[int] = mapped_column( Integer, nullable=False, server_default="0", comment="显示排序" ) status: Mapped[int] = mapped_column( TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0禁用" ) user_roles: Mapped[list["UserRole"]] = relationship(back_populates="role") class Permission(Base, TimestampMixin): """权限表。 perm_type 区分菜单/按钮/接口三类,parent_id 支撑树形结构。 本期只建表不填数据 —— 具体权限清单待需求澄清后确定。 """ __tablename__ = "permissions" __table_args__ = mysql_table_args("权限表") id: Mapped[int] = mapped_column( BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID" ) perm_code: Mapped[str] = mapped_column( String(128), nullable=False, unique=True, comment="权限编码,如 system:user:create" ) perm_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="权限名称") perm_type: Mapped[int] = mapped_column( TINYINT_TYPE, nullable=False, server_default="1", comment="类型:1菜单 2按钮 3接口" ) parent_id: Mapped[int | None] = mapped_column( BIGINT_UNSIGNED, ForeignKey("permissions.id", ondelete="CASCADE"), comment="父权限ID(permissions.id),顶级为空", ) sort_order: Mapped[int] = mapped_column( Integer, nullable=False, server_default="0", comment="显示排序" ) status: Mapped[int] = mapped_column( TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0禁用" ) class RolePermission(Base): """角色-权限关联表。""" __tablename__ = "role_permissions" __table_args__ = mysql_table_args( "角色权限关联表", UniqueConstraint( "role_id", "permission_id", name="uk_role_permissions_role_id_permission_id" ), Index("idx_role_permissions_permission_id", "permission_id"), ) id: Mapped[int] = mapped_column( BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID" ) role_id: Mapped[int] = mapped_column( BIGINT_UNSIGNED, ForeignKey("roles.id", ondelete="CASCADE"), nullable=False, comment="角色ID(roles.id)", ) permission_id: Mapped[int] = mapped_column( BIGINT_UNSIGNED, ForeignKey("permissions.id", ondelete="CASCADE"), nullable=False, comment="权限ID(permissions.id)", ) create_time: Mapped[datetime] = mapped_column( DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"), comment="创建时间" )