from django.contrib.auth.models import UserManager from django.db import models from django.contrib.auth.models import AbstractUser from apps.utils.models import ParentModel, CommonADModel, CommonAModel, CommonBModel, BaseModel, SoftDeletableManagerMixin from django_celery_beat.models import IntervalSchedule, CrontabSchedule class DataFilter(models.IntegerChoices): ALL = 10, '全部' SAMELEVE_AND_BELOW = 30, '同级及以下' THISLEVEL_AND_BELOW = 40, '本级及以下' THISLEVEL = 50, '本级' MYSELF = 60, '仅本人' class Permission(ParentModel, BaseModel): """ TN:功能权限:模块,页面,接口 """ PERM_TYPE_MODULE = 10 PERM_TYPE_PAGE = 20 PERM_TYPE_API = 30 menu_type_choices = ( (PERM_TYPE_MODULE, '模块'), (PERM_TYPE_PAGE, '页面'), (PERM_TYPE_API, '接口') ) name = models.CharField('名称', max_length=30) type = models.PositiveSmallIntegerField( '类型', choices=menu_type_choices, default=30) sort = models.PositiveSmallIntegerField('排序标记', default=1) codes = models.JSONField('权限标识', default=list, null=True, blank=True) route_name = models.CharField('路由名称', max_length=30, null=True, blank=True) icon = models.CharField('图标', max_length=30, null=True, blank=True) path = models.CharField('路由', max_length=100, null=True, blank=True) component = models.CharField('组件', max_length=100, null=True, blank=True) is_hidden = models.BooleanField('是否隐藏', default=False) is_fullpage = models.BooleanField('是否全屏', default=False) def __str__(self): return self.name class Meta: verbose_name = '功能权限表' verbose_name_plural = verbose_name ordering = ['sort'] class Dept(ParentModel, CommonAModel): """ TN:部门 """ name = models.CharField('名称', max_length=60) type = models.CharField('类型', max_length=20, default='dept') sort = models.PositiveSmallIntegerField('排序标记', default=1) third_info = models.JSONField('三方系统信息', default=dict) class Meta: verbose_name = '部门' verbose_name_plural = verbose_name ordering = ['sort'] def __str__(self): return self.name class Role(CommonADModel): """ TN:角色 """ name = models.CharField('名称', max_length=32) code = models.CharField('角色标识', max_length=32, null=True, blank=True) perms = models.ManyToManyField( Permission, blank=True, verbose_name='功能权限', related_name='role_perms') description = models.CharField('描述', max_length=50, blank=True, null=True) class Meta: verbose_name = '角色' verbose_name_plural = verbose_name ordering = ['code'] def __str__(self): return self.name class Post(CommonADModel): """ TN:职位/岗位 """ name = models.CharField('名称', max_length=32) code = models.CharField('岗位标识', max_length=32, null=True, blank=True) description = models.CharField('描述', max_length=50, blank=True, null=True) min_hour = models.PositiveSmallIntegerField('最小在岗时间', default=0) max_hour = models.PositiveSmallIntegerField('最长在岗时间', default=12) class Meta: verbose_name = '职位/岗位' verbose_name_plural = verbose_name ordering = ['create_time'] def __str__(self): return self.name class PostRole(BaseModel): """TN: 岗位角色关系""" data_range = models.PositiveSmallIntegerField('数据权限范围', choices=DataFilter.choices, default=DataFilter.THISLEVEL_AND_BELOW) post = models.ForeignKey(Post, verbose_name='关联岗位', on_delete=models.CASCADE) role = models.ForeignKey(Role, verbose_name='关联角色', on_delete=models.CASCADE) class SoftDeletableUserManager(SoftDeletableManagerMixin, UserManager): pass class User(AbstractUser, CommonBModel): """ TN:用户 """ type = models.CharField('账号类型', max_length=10, default='employee') name = models.CharField('姓名', max_length=20, null=True, blank=True) phone = models.CharField('手机号', max_length=11, null=True, blank=True) avatar = models.CharField( '头像', default='/media/default/avatar.png', max_length=100, null=True, blank=True) superior = models.ForeignKey( 'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管') post = models.ForeignKey(Post, verbose_name='主要岗位', on_delete=models.SET_NULL, null=True, blank=True) posts = models.ManyToManyField( Post, through='system.userpost', related_name='user_posts') depts = models.ManyToManyField(Dept, through='system.userpost') roles = models.ManyToManyField(Role, verbose_name='关联角色') # 关联账号 secret = models.CharField('密钥', max_length=100, null=True, blank=True) wx_openid = models.CharField( '微信公众号OpenId', max_length=100, null=True, blank=True) wx_nickname = models.CharField( '微信昵称', max_length=100, null=True, blank=True) wx_headimg = models.CharField( '微信头像', max_length=100, null=True, blank=True) wxmp_openid = models.CharField( '微信小程序OpenId', max_length=100, null=True, blank=True) objects = SoftDeletableUserManager() class Meta: verbose_name = '用户信息' verbose_name_plural = verbose_name ordering = ['create_time'] def __str__(self): return self.username class UserPost(BaseModel): """ TN:用户岗位关系表 """ name = models.CharField('名称', max_length=20, null=True, blank=True) user = models.ForeignKey( User, on_delete=models.CASCADE, related_name='up_user') post = models.ForeignKey( Post, on_delete=models.CASCADE, related_name='up_post') dept = models.ForeignKey( Dept, on_delete=models.CASCADE, related_name='up_dept') sort = models.PositiveSmallIntegerField('排序', default=1) class Meta: verbose_name = '用户岗位关系表' verbose_name_plural = verbose_name ordering = ['sort', 'create_time'] unique_together = ('user', 'post', 'dept') class DictType(ParentModel, CommonAModel): """ TN:数据字典类型 """ name = models.CharField('名称', max_length=30) code = models.CharField('标识', max_length=30) class Meta: verbose_name = '字典类型' verbose_name_plural = verbose_name ordering = ['-create_time'] def __str__(self): return self.name class Dictionary(ParentModel, CommonAModel): """ TN:数据字典 """ name = models.CharField('名称', max_length=60) value = models.CharField('值', max_length=10, null=True, blank=True) code = models.CharField('标识', max_length=30, null=True, blank=True) description = models.TextField('描述', blank=True, null=True) type = models.ForeignKey( DictType, on_delete=models.CASCADE, verbose_name='类型') sort = models.PositiveSmallIntegerField('排序', default=1) is_used = models.BooleanField('是否有效', default=True) class Meta: verbose_name = '字典' verbose_name_plural = verbose_name unique_together = ('name', 'is_used', 'type') ordering = ['sort'] def __str__(self): return self.name class File(CommonAModel): """ TN:文件存储表,业务表根据具体情况选择是否外键关联 """ FILE_TYPE_DOC = 10 FILE_TYPE_VIDEO = 20 FILE_TYPE_AUDIO = 30 FILE_TYPE_PIC = 40 FILE_TYPE_OTHER = 50 name = models.CharField('名称', max_length=100, null=True, blank=True) size = models.IntegerField('文件大小', default=1, null=True, blank=True) file = models.FileField('文件', upload_to='%Y/%m/%d/') type_choices = ( (FILE_TYPE_DOC, '文档'), (FILE_TYPE_VIDEO, '视频'), (FILE_TYPE_AUDIO, '音频'), (FILE_TYPE_PIC, '图片'), (FILE_TYPE_OTHER, '其它') ) mime = models.CharField('文件格式', max_length=120, null=True, blank=True) type = models.CharField('文件类型', max_length=50, choices=type_choices, default='文档') path = models.CharField('地址', max_length=200, null=True, blank=True) class Meta: verbose_name = '文件库' verbose_name_plural = verbose_name def __str__(self): return self.name class MySchedule(CommonAModel): """TN: 常用周期""" MS_TYPE = ( (10, '间隔'), (20, '定时') ) name = models.CharField('名称', max_length=200) type = models.PositiveSmallIntegerField('周期类型', default=10) interval = models.ForeignKey( IntervalSchedule, on_delete=models.PROTECT, null=True, blank=True) crontab = models.ForeignKey( CrontabSchedule, on_delete=models.PROTECT, null=True, blank=True)