diff --git a/apps/permission/migrations/0004_alter_rolepermission_permission_def_and_more.py b/apps/permission/migrations/0004_alter_rolepermission_permission_def_and_more.py new file mode 100644 index 0000000..f8e3dbb --- /dev/null +++ b/apps/permission/migrations/0004_alter_rolepermission_permission_def_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.16 on 2026-04-30 04:44 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fonrey_permission_def', '0001_initial'), + ('fonrey_permission', '0003_alter_permissionchangelog_action_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='rolepermission', + name='permission_def', + field=models.ForeignKey(help_text='RESTRICT 防止删除仍被引用的权限项', on_delete=django.db.models.deletion.PROTECT, related_name='role_assignments', to='fonrey_permission_def.permissiondef', verbose_name='权限定义'), + ), + migrations.AlterField( + model_name='staffpermissionoverride', + name='permission_def', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='staff_overrides', to='fonrey_permission_def.permissiondef', verbose_name='被覆盖权限项'), + ), + migrations.DeleteModel( + name='PermissionDef', + ), + ] diff --git a/apps/permission/models/__init__.py b/apps/permission/models/__init__.py index 52be7c8..8d59fb9 100644 --- a/apps/permission/models/__init__.py +++ b/apps/permission/models/__init__.py @@ -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", diff --git a/apps/permission/models/role.py b/apps/permission/models/role.py index a86146f..77759da 100644 --- a/apps/permission/models/role.py +++ b/apps/permission/models/role.py @@ -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="权限定义", diff --git a/apps/permission/models/staff_perm.py b/apps/permission/models/staff_perm.py index 5d3e57a..d1f42d9 100644 --- a/apps/permission/models/staff_perm.py +++ b/apps/permission/models/staff_perm.py @@ -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="被覆盖权限项", diff --git a/apps/permission_def/__init__.py b/apps/permission_def/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/permission_def/apps.py b/apps/permission_def/apps.py new file mode 100644 index 0000000..a3f03f8 --- /dev/null +++ b/apps/permission_def/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class PermissionDefConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.permission_def" + label = "fonrey_permission_def" + verbose_name = "权限定义(全局共享)" diff --git a/apps/permission_def/migrations/0001_initial.py b/apps/permission_def/migrations/0001_initial.py new file mode 100644 index 0000000..6291ebc --- /dev/null +++ b/apps/permission_def/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.16 on 2026-04-30 04:41 + +import django.contrib.postgres.fields +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='PermissionDef', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('code', models.CharField(help_text='规则:{module}.{sub_module}.{action}[.{qualifier}]', max_length=150, unique=True, verbose_name='权限编码')), + ('module', models.CharField(choices=[('home', '首页'), ('property', '房源'), ('new_house', '新房'), ('client', '客源'), ('transaction', '交易'), ('data', '数据'), ('marketing', '营销'), ('hr', '人事OA'), ('contract', '合同'), ('trinet', '三网'), ('system', '系统'), ('mobile', '移动端'), ('smart_store', '智能门店'), ('recharge', '在线充值')], help_text='home/property/new_house/client/transaction/data/marketing/hr/contract/trinet/system/mobile/smart_store/recharge', max_length=50, verbose_name='一级模块')), + ('sub_module', models.CharField(blank=True, default='', help_text='如「二手&租赁」「商圈精耕」', max_length=50, verbose_name='二级模块')), + ('group_name', models.CharField(help_text='如「私客基础权限」「联系人基础权限」', max_length=100, verbose_name='分组标题')), + ('name', models.CharField(max_length=200, verbose_name='显示名称')), + ('description', models.TextField(blank=True, default='', verbose_name='权限作用描述')), + ('value_type', models.CharField(choices=[('boolean', '开关型'), ('scope', '范围型'), ('integer', '数值型')], help_text='BOOLEAN=开关型 / SCOPE=范围型 / INTEGER=数值型', max_length=20, verbose_name='权限值类型')), + ('scope_choices', models.JSONField(blank=True, default=list, help_text='仅 SCOPE 类型有效,可选枚举 code 列表,如 ["none","self","store","company"]', verbose_name='可选范围')), + ('integer_min', models.IntegerField(blank=True, help_text='仅 INTEGER 类型有效', null=True, verbose_name='最小值')), + ('integer_max', models.IntegerField(blank=True, help_text='仅 INTEGER 类型有效;NULL=无上限(业务上 0 通常代表不限制)', null=True, verbose_name='最大值')), + ('default_value', models.JSONField(default=dict, help_text='系统最小默认值,格式 {"v": }', verbose_name='默认值')), + ('max_allowed_categories', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text='允许配置此权限的角色类别列表,空数组=所有类别均可', size=None, verbose_name='可配置角色类别')), + ('sort_order', models.PositiveIntegerField(default=0, help_text='分组内排序', verbose_name='排序顺序')), + ('is_active', models.BooleanField(default=True, help_text='下线权限项置 FALSE,历史记录保留', verbose_name='是否启用')), + ('is_deprecated', models.BooleanField(default=False, help_text='不再推荐使用但保持兼容', verbose_name='是否废弃')), + ('version', models.PositiveIntegerField(default=1, help_text='变更时递增,用于缓存失效', verbose_name='定义版本')), + ], + options={ + 'verbose_name': '权限定义', + 'verbose_name_plural': '权限定义', + 'db_table': 'permission_defs', + 'indexes': [models.Index(condition=models.Q(('is_active', True)), fields=['module', 'sub_module', 'sort_order'], name='idx_perm_defs_module'), models.Index(condition=models.Q(('is_active', True)), fields=['is_active'], name='idx_perm_defs_active')], + }, + ), + ] diff --git a/apps/permission_def/migrations/__init__.py b/apps/permission_def/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/permission_def/models/__init__.py b/apps/permission_def/models/__init__.py new file mode 100644 index 0000000..f350a5a --- /dev/null +++ b/apps/permission_def/models/__init__.py @@ -0,0 +1,3 @@ +from apps.permission_def.models.permission_def import PermissionDef + +__all__ = ["PermissionDef"] diff --git a/apps/permission/models/permission_def.py b/apps/permission_def/models/permission_def.py similarity index 100% rename from apps/permission/models/permission_def.py rename to apps/permission_def/models/permission_def.py diff --git a/config/settings/base.py b/config/settings/base.py index db77187..04e6fe1 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -15,6 +15,7 @@ SHARED_APPS = [ "django_tenants", # MUST be first per django-tenants "apps.tenant", "apps.release", + "apps.permission_def", "shared", "django.contrib.contenttypes", "django.contrib.auth",