feat(permission): extract PermissionDef into shared apps.permission_def

Move PermissionDef out of TENANT_APPS into a new SHARED app so all
tenants read a single global definition table in public schema.

- new app apps.permission_def (label=fonrey_permission_def)
- db_table preserved as permission_defs (no rename)
- FK refs updated: fonrey_permission.PermissionDef -> fonrey_permission_def.PermissionDef
- migrations: permission_def/0001_initial creates table in public,
  permission/0004 drops the now-orphan table from tenant schemas
This commit is contained in:
2026-04-30 12:45:44 +08:00
parent 5dedd19c0a
commit b9245cd891
11 changed files with 88 additions and 4 deletions

View File

@@ -1,4 +1,3 @@
from apps.permission.models.permission_def import PermissionDef
from apps.permission.models.role import Role, RolePermission
from apps.permission.models.staff_perm import (
PermissionChangeLog,
@@ -9,7 +8,6 @@ from apps.permission.models.staff_perm import (
__all__ = [
"PermissionChangeLog",
"PermissionDef",
"Role",
"RolePermission",
"StaffDataScope",

View File

@@ -1,117 +0,0 @@
from django.contrib.postgres.fields import ArrayField
from django.db import models
from core.enums import PermissionModule, PermissionValueType
from core.models.base import TimeStampedModel
class PermissionDef(TimeStampedModel):
code = models.CharField(
max_length=150,
unique=True,
verbose_name="权限编码",
help_text='规则:{module}.{sub_module}.{action}[.{qualifier}]',
)
module = models.CharField(
max_length=50,
choices=PermissionModule.choices,
verbose_name="一级模块",
help_text="home/property/new_house/client/transaction/data/marketing/hr/contract/trinet/system/mobile/smart_store/recharge",
)
sub_module = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="二级模块",
help_text='如「二手&租赁」「商圈精耕」',
)
group_name = models.CharField(
max_length=100,
verbose_name="分组标题",
help_text='如「私客基础权限」「联系人基础权限」',
)
name = models.CharField(
max_length=200,
verbose_name="显示名称",
)
description = models.TextField(
blank=True,
default="",
verbose_name="权限作用描述",
)
value_type = models.CharField(
max_length=20,
choices=PermissionValueType.choices,
verbose_name="权限值类型",
help_text="BOOLEAN=开关型 / SCOPE=范围型 / INTEGER=数值型",
)
scope_choices = models.JSONField(
default=list,
blank=True,
verbose_name="可选范围",
help_text='仅 SCOPE 类型有效,可选枚举 code 列表,如 ["none","self","store","company"]',
)
integer_min = models.IntegerField(
null=True,
blank=True,
verbose_name="最小值",
help_text="仅 INTEGER 类型有效",
)
integer_max = models.IntegerField(
null=True,
blank=True,
verbose_name="最大值",
help_text="仅 INTEGER 类型有效NULL=无上限(业务上 0 通常代表不限制)",
)
default_value = models.JSONField(
default=dict,
verbose_name="默认值",
help_text='系统最小默认值,格式 {"v": <value>}',
)
max_allowed_categories = ArrayField(
models.CharField(max_length=50),
default=list,
blank=True,
verbose_name="可配置角色类别",
help_text="允许配置此权限的角色类别列表,空数组=所有类别均可",
)
sort_order = models.PositiveIntegerField(
default=0,
verbose_name="排序顺序",
help_text="分组内排序",
)
is_active = models.BooleanField(
default=True,
verbose_name="是否启用",
help_text="下线权限项置 FALSE历史记录保留",
)
is_deprecated = models.BooleanField(
default=False,
verbose_name="是否废弃",
help_text="不再推荐使用但保持兼容",
)
version = models.PositiveIntegerField(
default=1,
verbose_name="定义版本",
help_text="变更时递增,用于缓存失效",
)
class Meta:
db_table = "permission_defs"
verbose_name = "权限定义"
verbose_name_plural = "权限定义"
indexes = [
models.Index(
fields=["module", "sub_module", "sort_order"],
name="idx_perm_defs_module",
condition=models.Q(is_active=True),
),
models.Index(
fields=["is_active"],
name="idx_perm_defs_active",
condition=models.Q(is_active=True),
),
]
def __str__(self) -> str:
return f"{self.code} ({self.value_type})"

View File

@@ -91,7 +91,7 @@ class RolePermission(TimeStampedModel):
help_text="稀疏存储:角色删除时级联清理权限值",
)
permission_def = models.ForeignKey(
"fonrey_permission.PermissionDef",
"fonrey_permission_def.PermissionDef",
on_delete=models.PROTECT,
related_name="role_assignments",
verbose_name="权限定义",

View File

@@ -86,7 +86,7 @@ class StaffPermissionOverride(UUIDPrimaryKeyModel):
help_text="员工删除时级联删除覆盖记录",
)
permission_def = models.ForeignKey(
"fonrey_permission.PermissionDef",
"fonrey_permission_def.PermissionDef",
on_delete=models.PROTECT,
related_name="staff_overrides",
verbose_name="被覆盖权限项",