community

This commit is contained in:
jeremygan2021
2026-02-11 14:58:28 +08:00
parent 1100143a6e
commit 7e4d2a9579
17 changed files with 685 additions and 0 deletions

155
backend/community/models.py Normal file
View File

@@ -0,0 +1,155 @@
from django.db import models
from shop.models import WeChatUser, ESP32Config, Order, Service, VCCourse, ServiceOrder
class Activity(models.Model):
"""
社区活动模型
"""
title = models.CharField(max_length=100, verbose_name="活动标题")
description = models.TextField(verbose_name="活动详情")
banner = models.ImageField(upload_to='activities/banners/', verbose_name="活动Banner图")
start_time = models.DateTimeField(verbose_name="开始时间")
end_time = models.DateTimeField(verbose_name="结束时间")
location = models.CharField(max_length=100, verbose_name="活动地点")
max_participants = models.IntegerField(default=50, verbose_name="最大报名人数")
is_active = models.BooleanField(default=True, verbose_name="是否启用")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
def __str__(self):
return self.title
class Meta:
verbose_name = "社区活动"
verbose_name_plural = "社区活动管理"
class ActivitySignup(models.Model):
"""
活动报名记录
"""
STATUS_CHOICES = (
('pending', '审核中'),
('confirmed', '报名成功'),
('cancelled', '已取消'),
)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='signups', verbose_name="活动")
user = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='activity_signups', verbose_name="报名用户")
signup_time = models.DateTimeField(auto_now_add=True, verbose_name="报名时间")
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='confirmed', verbose_name="状态")
def __str__(self):
return f"{self.user.nickname} - {self.activity.title}"
class Meta:
verbose_name = "活动报名"
verbose_name_plural = "活动报名管理"
unique_together = ('activity', 'user')
class Topic(models.Model):
"""
论坛帖子/主题
"""
title = models.CharField(max_length=200, verbose_name="标题")
content = models.TextField(verbose_name="内容", help_text="支持Markdown格式支持插入图片")
author = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='topics', verbose_name="作者")
# 关联对象:硬件、服务、课程
related_product = models.ForeignKey(ESP32Config, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联硬件")
related_service = models.ForeignKey(Service, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联服务")
related_course = models.ForeignKey(VCCourse, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联课程")
view_count = models.IntegerField(default=0, verbose_name="浏览量")
is_pinned = models.BooleanField(default=False, verbose_name="置顶")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="发布时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
def __str__(self):
return self.title
@property
def is_verified_owner(self):
"""
判断作者是否为关联项目(硬件/服务/课程的已购用户Verified Owner
"""
# 1. 验证硬件
if self.related_product:
if Order.objects.filter(
wechat_user=self.author,
config=self.related_product,
status__in=['paid', 'shipped']
).exists():
return True
# 2. 验证课程
if self.related_course:
if Order.objects.filter(
wechat_user=self.author,
course=self.related_course,
status__in=['paid', 'shipped']
).exists():
return True
# 3. 验证服务
if self.related_service:
# ServiceOrder 模型中没有 direct link to WeChatUser (only phone/name),
# 但我们假设通过手机号或未来关联来验证,目前先检查 ServiceOrder 是否有对应记录。
# 由于 ServiceOrder 目前设计没有直接关联 WeChatUser 字段,我们暂时尝试通过名字或后续改进。
# 经检查 shop/models.py, ServiceOrder 确实只有 customer_name/phone_number.
# 这里为了严谨,我们暂时仅对有关联的进行检查,或者需要改进 ServiceOrder。
# 鉴于当前任务范围,如果 ServiceOrder 没有 user 字段,我们可能无法精确验证,
# 除非我们假设用户填写的手机号与微信用户关联。
# *修正*: 为了快速实现,我们先跳过 ServiceOrder 的精确验证,或者仅仅返回 False
# 等待后续 ServiceOrder 添加 wechat_user 字段。
pass
return False
class Meta:
verbose_name = "论坛帖子"
verbose_name_plural = "论坛帖子管理"
ordering = ['-is_pinned', '-created_at']
class Reply(models.Model):
"""
帖子回复
"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='replies', verbose_name="所属帖子")
content = models.TextField(verbose_name="回复内容", help_text="支持Markdown格式")
author = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='replies', verbose_name="回复者")
reply_to = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='children', verbose_name="回复楼层")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="回复时间")
def __str__(self):
return f"回复: {self.topic.title}"
class Meta:
verbose_name = "帖子回复"
verbose_name_plural = "帖子回复管理"
ordering = ['created_at']
class TopicMedia(models.Model):
"""
论坛多媒体资源(图片/视频/文件)
"""
MEDIA_TYPE_CHOICES = (
('image', '图片'),
('video', '视频'),
('file', '文件'),
)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='media', verbose_name="所属帖子", null=True, blank=True)
reply = models.ForeignKey(Reply, on_delete=models.CASCADE, related_name='media', verbose_name="所属回复", null=True, blank=True)
file = models.FileField(upload_to='community/media/', verbose_name="文件")
media_type = models.CharField(max_length=10, choices=MEDIA_TYPE_CHOICES, default='image', verbose_name="媒体类型")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
def __str__(self):
return f"{self.media_type} - {self.file.name}"
class Meta:
verbose_name = "论坛媒体资源"
verbose_name_plural = "论坛媒体资源管理"