feat: 城市手册后端完成 - 用户/区域/内容/服务/审核系统
This commit is contained in:
214
city-manual/backend/regions/models.py
Normal file
214
city-manual/backend/regions/models.py
Normal file
@@ -0,0 +1,214 @@
|
||||
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})"
|
||||
Reference in New Issue
Block a user