This commit is contained in:
2026-02-12 20:50:01 +08:00
parent d049f682f5
commit 414d3334fd
82 changed files with 1835 additions and 422 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 6.0.1 on 2026-02-12 12:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('community', '0007_announcement'),
]
operations = [
migrations.AddField(
model_name='activity',
name='signup_form_config',
field=models.JSONField(blank=True, default=list, help_text='配置报名时需要收集的信息JSON格式例如[{"name": "phone", "label": "手机号", "type": "text", "required": true}]', verbose_name='报名表单配置'),
),
migrations.AddField(
model_name='activitysignup',
name='signup_info',
field=models.JSONField(blank=True, default=dict, verbose_name='报名信息'),
),
]

View File

@@ -14,6 +14,12 @@ class Activity(models.Model):
location = models.CharField(max_length=100, verbose_name="活动地点")
max_participants = models.IntegerField(default=50, verbose_name="最大报名人数")
is_active = models.BooleanField(default=True, verbose_name="是否启用")
signup_form_config = models.JSONField(
default=list,
verbose_name="报名表单配置",
blank=True,
help_text='配置报名时需要收集的信息JSON格式例如[{"name": "phone", "label": "手机号", "type": "text", "required": true}]'
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
def clean(self):
@@ -55,6 +61,11 @@ class ActivitySignup(models.Model):
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="报名时间")
signup_info = models.JSONField(
default=dict,
verbose_name="报名信息",
blank=True
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='confirmed', verbose_name="状态")
def __str__(self):

View File

@@ -10,10 +10,12 @@ class ActivitySerializer(serializers.ModelSerializer):
fields = '__all__'
class ActivitySignupSerializer(serializers.ModelSerializer):
activity_info = ActivitySerializer(source='activity', read_only=True)
class Meta:
model = ActivitySignup
fields = ['id', 'activity', 'user', 'signup_time', 'status']
read_only_fields = ['signup_time', 'status']
fields = ['id', 'activity', 'activity_info', 'user', 'signup_time', 'status', 'signup_info']
read_only_fields = ['signup_time', 'status', 'user']
class TopicMediaSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField()

View File

@@ -36,8 +36,26 @@ class ActivityViewSet(viewsets.ReadOnlyModelViewSet):
if activity.signups.count() >= activity.max_participants:
return Response({'error': '活动名额已满'}, status=400)
# Get signup info
signup_info = request.data.get('signup_info', {})
# Basic validation
if activity.signup_form_config:
required_fields = [f['name'] for f in activity.signup_form_config if f.get('required')]
for field in required_fields:
# Simple check: field exists and is not empty string (if it's a string)
val = signup_info.get(field)
if val is None or (isinstance(val, str) and not val.strip()):
# Try to find label for better error message
label = next((f['label'] for f in activity.signup_form_config if f['name'] == field), field)
return Response({'error': f'请填写: {label}'}, status=400)
signup = ActivitySignup.objects.create(activity=activity, user=user)
signup = ActivitySignup.objects.create(
activity=activity,
user=user,
signup_info=signup_info
)
serializer = ActivitySignupSerializer(signup)
return Response(serializer.data, status=201)