Files
fonrey/apps/permission/models/staff_perm.py
ishenwei 79c3cf2924 feat(models): add Chinese verbose_name to all 74 models (Phase 4.0)
为所有 Django 模型添加 Meta.verbose_name 和 verbose_name_plural(中文表名),
覆盖 10 个 app 的全部 74 个业务模型。

Phase 4.0 范围:
- 仅 Meta 类级别中文名(用于 Django Admin、drf-spectacular OpenAPI title、错误信息)
- 字段级 verbose_name= 和 help_text= 留待 Phase 4.1(待 PM 补全 DATA_MODEL 后同步)

变更:
- 20 个 models 文件改动(每个模型 +2 行)
- 8 个 0002/0003 迁移文件(Meta options 变更)
- apps/tenant/migrations/0001_initial.py(之前漏生成的 tenant 模型迁移)

manage.py check: 0 issues。
2026-04-29 19:10:38 +08:00

209 lines
6.6 KiB
Python

from django.db import models
from core.enums import (
PermissionChangeAction,
PermissionChangeTargetType,
PermissionDataScopeType,
PermissionOverrideMode,
)
from core.models.base import TimeStampedModel, UUIDPrimaryKeyModel
class StaffRole(UUIDPrimaryKeyModel):
staff = models.ForeignKey(
"org.Staff",
on_delete=models.CASCADE,
related_name="staff_roles",
)
role = models.ForeignKey(
"fonrey_permission.Role",
on_delete=models.PROTECT,
related_name="staff_links",
)
is_primary = models.BooleanField(default=False)
assigned_at = models.DateTimeField(auto_now_add=True)
assigned_by = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="staff_role_assignments_made",
)
valid_from = models.DateField(null=True, blank=True)
valid_until = models.DateField(null=True, blank=True)
class Meta:
db_table = "staff_roles"
verbose_name = "员工角色"
verbose_name_plural = "员工角色"
constraints = [
models.UniqueConstraint(
fields=["staff", "role"],
name="uq_staff_roles",
),
models.UniqueConstraint(
fields=["staff"],
condition=models.Q(is_primary=True),
name="uq_staff_roles_primary",
),
]
indexes = [
models.Index(fields=["role"], name="idx_staff_roles_role"),
]
def __str__(self) -> str:
marker = " [primary]" if self.is_primary else ""
return f"{self.staff_id}{self.role_id}{marker}"
class StaffPermissionOverride(UUIDPrimaryKeyModel):
staff = models.ForeignKey(
"org.Staff",
on_delete=models.CASCADE,
related_name="permission_overrides",
)
permission_def = models.ForeignKey(
"fonrey_permission.PermissionDef",
on_delete=models.PROTECT,
related_name="staff_overrides",
)
value = models.JSONField()
override_mode = models.CharField(
max_length=10,
choices=PermissionOverrideMode.choices,
default=PermissionOverrideMode.REPLACE,
)
reason = models.TextField(blank=True, default="")
modified_by = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="staff_overrides_modified",
)
modified_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "staff_permission_overrides"
verbose_name = "个人权限覆盖"
verbose_name_plural = "个人权限覆盖"
constraints = [
models.UniqueConstraint(
fields=["staff", "permission_def"],
name="uq_staff_overrides",
),
]
indexes = [
models.Index(fields=["staff"], name="idx_staff_overrides_staff"),
]
class StaffDataScope(UUIDPrimaryKeyModel):
staff = models.ForeignKey(
"org.Staff",
on_delete=models.CASCADE,
related_name="data_scopes",
)
scope_type = models.CharField(
max_length=20,
choices=PermissionDataScopeType.choices,
)
org_unit = models.ForeignKey(
"org.OrgUnit",
null=True,
blank=True,
on_delete=models.PROTECT,
related_name="data_scope_grants",
)
is_readable = models.BooleanField(default=True)
is_writable = models.BooleanField(default=False)
granted_by = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="data_scopes_granted",
)
granted_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField(null=True, blank=True)
reason = models.TextField(blank=True, default="")
class Meta:
db_table = "staff_data_scopes"
verbose_name = "员工数据范围"
verbose_name_plural = "员工数据范围"
indexes = [
models.Index(fields=["staff"], name="idx_data_scopes_staff"),
models.Index(fields=["org_unit"], name="idx_data_scopes_org"),
models.Index(
fields=["expires_at"],
name="idx_data_scopes_expires",
condition=models.Q(expires_at__isnull=False),
),
]
class PermissionChangeLog(UUIDPrimaryKeyModel):
target_type = models.CharField(
max_length=30,
choices=PermissionChangeTargetType.choices,
)
target_id = models.UUIDField()
staff = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="permission_change_logs_affecting",
)
role = models.ForeignKey(
"fonrey_permission.Role",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="change_logs",
)
permission_code = models.CharField(max_length=150, blank=True, default="")
action = models.CharField(max_length=20, choices=PermissionChangeAction.choices)
old_value = models.JSONField(null=True, blank=True)
new_value = models.JSONField(null=True, blank=True)
operator = models.ForeignKey(
"org.Staff",
on_delete=models.PROTECT,
related_name="permission_changes_operated",
)
operator_ip = models.GenericIPAddressField(null=True, blank=True)
user_agent = models.TextField(blank=True, default="")
reason = models.TextField(blank=True, default="")
operated_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "permission_change_logs"
verbose_name = "权限变更流水"
verbose_name_plural = "权限变更流水"
ordering = ["-operated_at"]
indexes = [
models.Index(
fields=["staff", "-operated_at"],
name="idx_perm_log_staff",
condition=models.Q(staff__isnull=False),
),
models.Index(
fields=["role", "-operated_at"],
name="idx_perm_log_role",
condition=models.Q(role__isnull=False),
),
models.Index(
fields=["target_type", "target_id", "-operated_at"],
name="idx_perm_log_target",
),
models.Index(
fields=["operator", "-operated_at"],
name="idx_perm_log_operator",
),
models.Index(fields=["-operated_at"], name="idx_perm_log_time"),
]
def delete(self, *args, **kwargs):
raise NotImplementedError("PermissionChangeLog is append-only and cannot be deleted.")