Files
chengshishouce/city-manual/backend/regions/models.py

215 lines
7.0 KiB
Python
Raw Normal View History

from django.db import models
from django.utils import timezone
class Region(models.Model):
"""版块/区域表 - 省市区乡镇村层级结构"""
LEVEL_CHOICES = [
('province', '省级'),
('city', '市级'),
('county', '县级'),
('town', '镇级'),
('village', '村级'),
]
name = models.CharField('名称', max_length=100)
level = models.CharField('级别', max_length=20, choices=LEVEL_CHOICES)
parent = models.ForeignKey(
'self',
null=True,
blank=True,
on_delete=models.CASCADE,
related_name='children',
verbose_name='上级区域'
)
code = models.CharField('行政区划代码', max_length=20, blank=True)
description = models.TextField('描述', blank=True)
created_at = models.DateTimeField('创建时间', auto_now_add=True)
updated_at = models.DateTimeField('更新时间', auto_now=True)
is_active = models.BooleanField('是否启用', default=True)
class Meta:
verbose_name = '区域'
verbose_name_plural = '区域'
ordering = ['level', 'name']
def __str__(self):
return f"{self.name} ({self.get_level_display()})"
def get_full_path(self):
"""获取完整路径"""
path = [self.name]
current = self.parent
while current:
path.append(current.name)
current = current.parent
return ' > '.join(reversed(path))
class ModeratorApplication(models.Model):
"""版主申请表"""
STATUS_CHOICES = [
('pending', '待审核'),
('approved', '已通过'),
('rejected', '已拒绝'),
('cancelled', '已取消'),
]
applicant = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='moderator_applications',
verbose_name='申请者'
)
region = models.ForeignKey(
Region,
on_delete=models.CASCADE,
related_name='moderator_applications',
verbose_name='申请区域'
)
application_reason = models.TextField('申请理由', blank=True)
support_count = models.PositiveIntegerField('支持人数', default=0)
required_support = models.PositiveIntegerField('所需支持人数', default=10)
deadline = models.DateTimeField('截止时间')
status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='pending')
reviewer = models.ForeignKey(
'users.User',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='reviewed_applications',
verbose_name='审核人'
)
reviewed_at = models.DateTimeField('审核时间', null=True, blank=True)
review_comment = models.TextField('审核意见', blank=True)
created_at = models.DateTimeField('申请时间', auto_now_add=True)
class Meta:
verbose_name = '版主申请'
verbose_name_plural = '版主申请'
ordering = ['-created_at']
def __str__(self):
return f"{self.applicant.username} 申请 {self.region.name} 版主"
def is_expired(self):
return timezone.now() > self.deadline
def auto_cancel_if_failed(self):
"""如果截止且支持人数不足,自动取消"""
if self.is_expired() and self.status == 'pending' and self.support_count < self.required_support:
self.status = 'cancelled'
self.save()
return True
return False
class ModeratorSupport(models.Model):
"""版主申请支持表"""
supporter = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='moderator_supports',
verbose_name='支持者'
)
application = models.ForeignKey(
ModeratorApplication,
on_delete=models.CASCADE,
related_name='supports',
verbose_name='申请'
)
created_at = models.DateTimeField('支持时间', auto_now_add=True)
class Meta:
verbose_name = '支持记录'
verbose_name_plural = '支持记录'
unique_together = ['supporter', 'application']
def __str__(self):
return f"{self.supporter.username} 支持 {self.application}"
class ModeratorPermission(models.Model):
"""版主权限表"""
RANK_CHOICES = [
('general', '将军'), # 省级
('colonel', '校官'), # 市级
('lieutenant', '尉官'), # 县级
('soldier', '士兵'), # 镇村级
]
STATUS_CHOICES = [
('active', '正常'),
('restricted', '限制'),
('revoked', '取消'),
]
moderator = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='moderator_permissions',
verbose_name='版主'
)
region = models.ForeignKey(
Region,
on_delete=models.CASCADE,
related_name='moderator_permissions',
verbose_name='管辖区域'
)
rank = models.CharField('军衔', max_length=20, choices=RANK_CHOICES)
status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='active')
created_at = models.DateTimeField('授权时间', auto_now_add=True)
restricted_until = models.DateTimeField('限制截止时间', null=True, blank=True)
class Meta:
verbose_name = '版主权限'
verbose_name_plural = '版主权限'
unique_together = ['moderator', 'region']
def __str__(self):
return f"{self.moderator.username} - {self.region.name} ({self.get_rank_display()})"
def can_moderate(self, content_region):
"""判断是否可以审核某个区域的内容"""
if self.status != 'active':
return False
# 检查是否在管辖范围内
current = content_region
while current:
if current.id == self.region.id:
return True
current = current.parent
return False
class PermissionRestriction(models.Model):
"""权限限制表"""
operator = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='permission_restrictions_made',
verbose_name='操作者'
)
restricted_moderator = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='permission_restrictions',
verbose_name='被限制版主'
)
restriction_type = models.CharField('限制类型', max_length=20, choices=[
('partial', '部分限制'),
('full', '完全限制'),
])
started_at = models.DateTimeField('限制开始时间', auto_now_add=True)
ended_at = models.DateTimeField('限制结束时间', null=True, blank=True)
reason = models.TextField('限制原因', blank=True)
class Meta:
verbose_name = '权限限制'
verbose_name_plural = '权限限制'
ordering = ['-started_at']
def __str__(self):
return f"{self.restricted_moderator.username} 被限制 ({self.restriction_type})"