Files
django-vue3-admin-gd/backend/system/models.py
2025-07-01 16:34:18 +08:00

280 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.contrib.auth.models import AbstractUser
from django.db import models
from backend import settings
from utils.models import CoreModel, CommonStatus
from utils.utils import validate_mobile
# 菜单类型枚举
class MenuType(models.TextChoices):
CATALOG = 'catalog', '目录'
MENU = 'menu', '菜单'
BUTTON = 'button', '按钮'
EMBEDDED = 'embedded', '内嵌页面'
LINK = 'link', '外部链接'
# 菜单元数据模型(单独存储元数据,避免 JSONField
class MenuMeta(CoreModel):
title = models.CharField(max_length=200, verbose_name='标题')
icon = models.CharField(max_length=100, blank=True, verbose_name='图标')
order = models.IntegerField(default=0, verbose_name='排序')
affix_tab = models.BooleanField(default=False, verbose_name='固定标签页')
badge = models.CharField(max_length=50, blank=True, verbose_name='徽章文本')
badge_type = models.CharField(max_length=20, blank=True, verbose_name='徽章类型')
badge_variants = models.CharField(max_length=20, blank=True, verbose_name='徽章样式')
iframe_src = models.URLField(blank=True, verbose_name='内嵌页面URL')
link = models.URLField(blank=True, verbose_name='外部链接')
def __str__(self):
return self.title
class Meta:
db_table = 'system_menu_meta'
verbose_name = '菜单元数据'
verbose_name_plural = '菜单元数据'
class Dept(CoreModel):
pid = models.ForeignKey(
"self",
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="children",
verbose_name="父部门 ID"
)
name = models.CharField(max_length=100, verbose_name="部门名称")
status = models.SmallIntegerField(
choices=CommonStatus.choices,
default=CommonStatus.DISABLED,
verbose_name="部门状态"
)
create_time = models.DateTimeField(
auto_now_add=True,
verbose_name="创建时间",
# 若数据中时间需自动解析,可在保存时处理:
# default=timezone.now # 或通过数据导入时赋值
)
sort = models.IntegerField(
default=0,
verbose_name="显示排序",
help_text="数值越小越靠前"
)
leader = models.CharField(
null=True,
blank=True,
max_length=20,
verbose_name="负责人"
)
phone = models.CharField(
max_length=20,
blank=True,
null=True,
verbose_name="联系电话"
)
email = models.EmailField(
blank=True,
null=True,
verbose_name="邮箱"
)
remark = models.TextField(blank=True, verbose_name="备注")
class Meta:
verbose_name = "部门管理"
verbose_name_plural = verbose_name
ordering = ["-create_time"] # 按创建时间倒序排列
# 主菜单模型
class Menu(CoreModel):
pid = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='children',
verbose_name='父菜单'
)
name = models.CharField(max_length=100, verbose_name='菜单名称')
status = models.IntegerField(choices=CommonStatus.choices, default=CommonStatus.ENABLED, verbose_name='状态')
type = models.CharField(choices=MenuType.choices, max_length=20, verbose_name='菜单类型')
sort = models.IntegerField(
default=0,
verbose_name="显示排序",
help_text="数值越小越靠前"
)
path = models.CharField(max_length=200, blank=True, verbose_name='路由路径')
component = models.CharField(max_length=200, blank=True, verbose_name='组件路径')
auth_code = models.CharField(max_length=100, blank=True, verbose_name='权限编码')
meta = models.OneToOneField(MenuMeta, on_delete=models.CASCADE, verbose_name='元数据')
def __str__(self):
return self.name
class Meta:
verbose_name = '菜单'
verbose_name_plural = '菜单管理'
ordering = ['meta__order', 'id']
class Role(CoreModel):
name = models.CharField(
max_length=100,
verbose_name='角色名称'
)
status = models.IntegerField(
choices=CommonStatus.choices,
default=CommonStatus.ENABLED,
verbose_name='角色状态'
)
sort = models.IntegerField(
default=0,
verbose_name="显示排序",
help_text="数值越小越靠前"
)
remark = models.TextField(
blank=True,
verbose_name='备注'
)
# 与菜单权限的多对多关联(假设菜单模型为 Menu权限字段为 auth_code
permissions = models.ManyToManyField(
'Menu', # 引用之前设计的 Menu 模型
through='RolePermission',
verbose_name='关联权限'
)
class Meta:
verbose_name = '角色管理'
verbose_name_plural = verbose_name
ordering = ["-create_time"] # 按创建时间倒序排列
def __str__(self):
return self.name
# 中间表:角色与权限的关联(可扩展字段如权限生效时间)
class RolePermission(CoreModel):
role = models.ForeignKey(
Role,
on_delete=models.CASCADE,
verbose_name='角色'
)
menu = models.ForeignKey(
'Menu',
on_delete=models.CASCADE,
verbose_name='菜单/权限'
)
# 可选:记录权限关联时间
create_time = models.DateTimeField(
auto_now_add=True,
verbose_name='权限关联时间'
)
class Meta:
db_table = 'system_role_permission'
verbose_name = '角色权限关联'
verbose_name_plural = verbose_name
class DictType(CoreModel):
"""字典类型表"""
name = models.CharField(max_length=100, default='', verbose_name='字典名称')
type = models.CharField(max_length=100, default='', verbose_name='字典类型', db_index=True)
status = models.IntegerField(
choices=CommonStatus.choices,
default=CommonStatus.ENABLED,
verbose_name='状态'
)
deleted_time = models.DateTimeField(null=True, blank=True, verbose_name='删除时间')
class Meta:
verbose_name = '字典类型'
verbose_name_plural = '字典类型'
db_table = 'system_dict_type'
ordering = ['-id']
def __str__(self):
return self.name
class DictData(CoreModel):
"""字典数据表"""
sort = models.IntegerField(default=0, verbose_name='字典排序')
label = models.CharField(max_length=100, default='', verbose_name='字典标签')
value = models.CharField(max_length=100, default='', verbose_name='字典键值')
dict_type = models.ForeignKey(
DictType,
on_delete=models.CASCADE,
related_name='dict_data',
verbose_name='字典类型'
)
status = models.IntegerField(
choices=CommonStatus.choices,
default=CommonStatus.ENABLED,
verbose_name='状态'
)
color_type = models.CharField(max_length=100, blank=True, default='', verbose_name='颜色类型')
css_class = models.CharField(max_length=100, blank=True, default='', verbose_name='css 样式')
class Meta:
verbose_name = '字典数据'
verbose_name_plural = '字典数据'
db_table = 'system_dict_data'
ordering = ['sort', 'id']
def __str__(self):
return self.label
class Post(CoreModel):
code = models.CharField(max_length=64, db_comment='岗位编码')
name = models.CharField(max_length=50, db_comment='岗位名称')
sort = models.IntegerField(default=0, db_comment='显示顺序')
status = models.IntegerField(
choices=CommonStatus.choices,
default=CommonStatus.ENABLED,
verbose_name='状态'
)
class Meta:
db_table = 'system_post'
verbose_name = '岗位信息表'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class User(AbstractUser, CoreModel):
mobile = models.CharField(max_length=11, null=True, validators=[validate_mobile], db_comment="手机号")
nickname = models.CharField(max_length=50, blank=True, null=True, db_comment="昵称")
gender = models.SmallIntegerField(blank=True, null=True, default=0, db_comment='性别')
language = models.CharField('语言', max_length=20, blank=True, null=True, db_comment="语言")
city = models.CharField('城市', max_length=20, blank=True, null=True, db_comment="城市")
province = models.CharField('省份', max_length=50, blank=True, null=True, db_comment="省份")
country = models.CharField('国家', max_length=50, blank=True, null=True, db_comment="国家")
avatar_url = models.URLField('头像', blank=True, null=True, db_comment="头像")
dept = models.ManyToManyField(
'Dept', blank=True, verbose_name='部门', db_constraint=False,
related_name='users'
)
role = models.ManyToManyField(
'Role', blank=True, verbose_name='角色', db_constraint=False,
related_name='users'
)
post = models.ManyToManyField(
'Post', blank=True, verbose_name='岗位', db_constraint=False,
related_name='users'
)
status = models.IntegerField(
choices=CommonStatus.choices,
default=CommonStatus.ENABLED,
verbose_name='状态'
)
login_ip = models.GenericIPAddressField(blank=True, null=True, db_comment="最后登录IP")
class Meta:
verbose_name = '用户数据'
verbose_name_plural = verbose_name
db_table = 'system_users'
@property
def get_role_name(self):
return [role.name for role in self.role.all()]