from rest_framework import serializers from .models import Activity, ActivitySignup, Topic, Reply, TopicMedia, Announcement from shop.serializers import WeChatUserSerializer, ESP32ConfigSerializer, ServiceSerializer, VCCourseSerializer from .utils import get_current_wechat_user class ActivitySerializer(serializers.ModelSerializer): display_banner_url = serializers.ReadOnlyField() signup_form_config = serializers.SerializerMethodField() current_signups = serializers.IntegerField(read_only=True) has_signed_up = serializers.SerializerMethodField() is_signed_up = serializers.SerializerMethodField() my_signup_status = serializers.SerializerMethodField() class Meta: model = Activity fields = '__all__' def get_has_signed_up(self, obj): return self.get_is_signed_up(obj) def get_my_signup_status(self, obj): request = self.context.get('request') if not request: return None user = get_current_wechat_user(request) if user: # Return the status of the non-cancelled signup signup = obj.signups.filter(user=user).exclude(status='cancelled').first() return signup.status if signup else None return None def get_is_signed_up(self, obj): request = self.context.get('request') if not request: return False user = get_current_wechat_user(request) if user: # Check if there is a valid signup (only confirmed counts) return obj.signups.filter(user=user, status='confirmed').exists() return False def get_signup_form_config(self, obj): # 1. 优先使用 JSON 配置 if obj.signup_form_config: return obj.signup_form_config # 2. 否则根据开关生成默认配置 config = [] if obj.ask_name: config.append({"name": "name", "label": "姓名", "type": "text", "required": True}) if obj.ask_phone: config.append({"name": "phone", "label": "手机号", "type": "number", "required": True}) if obj.ask_wechat: config.append({"name": "wechat", "label": "微信号", "type": "text", "required": True}) if obj.ask_company: config.append({"name": "company", "label": "公司/机构", "type": "text", "required": False}) return config class ActivitySignupSerializer(serializers.ModelSerializer): activity_info = serializers.SerializerMethodField() class Meta: model = ActivitySignup fields = ['id', 'activity', 'activity_info', 'user', 'signup_time', 'status', 'signup_info'] read_only_fields = ['signup_time', 'status', 'user'] def get_activity_info(self, obj): return ActivitySerializer(obj.activity).data class TopicMediaSerializer(serializers.ModelSerializer): url = serializers.SerializerMethodField() class Meta: model = TopicMedia fields = ['id', 'file', 'file_url', 'url', 'media_type', 'created_at'] def get_url(self, obj): if obj.file: return obj.file.url return obj.file_url class ReplySerializer(serializers.ModelSerializer): author_info = WeChatUserSerializer(source='author', read_only=True) media = TopicMediaSerializer(many=True, read_only=True) media_ids = serializers.ListField( child=serializers.IntegerField(), write_only=True, required=False ) like_count = serializers.IntegerField(source='likes.count', read_only=True) is_liked = serializers.SerializerMethodField() class Meta: model = Reply fields = ['id', 'topic', 'content', 'author', 'author_info', 'reply_to', 'media', 'created_at', 'media_ids', 'is_pinned', 'like_count', 'is_liked'] read_only_fields = ['author', 'created_at'] def get_is_liked(self, obj): request = self.context.get('request') if not request: return False user = get_current_wechat_user(request) if user: return obj.likes.filter(id=user.id).exists() return False def create(self, validated_data): media_ids = validated_data.pop('media_ids', []) reply = super().create(validated_data) if media_ids: TopicMedia.objects.filter(id__in=media_ids).update(reply=reply) return reply class TopicSerializer(serializers.ModelSerializer): author_info = WeChatUserSerializer(source='author', read_only=True) replies = ReplySerializer(many=True, read_only=True) media = TopicMediaSerializer(many=True, read_only=True) is_verified_owner = serializers.BooleanField(read_only=True) like_count = serializers.IntegerField(source='likes.count', read_only=True) is_liked = serializers.SerializerMethodField() product_info = ESP32ConfigSerializer(source='related_product', read_only=True) service_info = ServiceSerializer(source='related_service', read_only=True) course_info = VCCourseSerializer(source='related_course', read_only=True) media_ids = serializers.ListField( child=serializers.IntegerField(), write_only=True, required=False ) class Meta: model = Topic fields = [ 'id', 'title', 'category', 'status', 'content', 'author', 'author_info', 'related_product', 'product_info', 'related_service', 'service_info', 'related_course', 'course_info', 'view_count', 'is_pinned', 'created_at', 'updated_at', 'is_verified_owner', 'replies', 'media', 'media_ids', 'like_count', 'is_liked' ] read_only_fields = ['author', 'view_count', 'created_at', 'updated_at', 'is_verified_owner', 'status'] def get_is_liked(self, obj): request = self.context.get('request') if not request: return False user = get_current_wechat_user(request) if user: return obj.likes.filter(id=user.id).exists() return False def create(self, validated_data): media_ids = validated_data.pop('media_ids', []) topic = super().create(validated_data) if media_ids: TopicMedia.objects.filter(id__in=media_ids).update(topic=topic) return topic class AnnouncementSerializer(serializers.ModelSerializer): display_image_url = serializers.ReadOnlyField() class Meta: model = Announcement fields = '__all__' class AdminActivitySerializer(serializers.ModelSerializer): signup_form_config = serializers.JSONField(required=False) description = serializers.CharField( style={'base_template': 'textarea.html'}, help_text="活动详情内容,支持 Markdown 格式。如果需要插入图片,请先调用媒体上传接口获取 URL。" ) class Meta: model = Activity fields = '__all__' read_only_fields = ['author', 'created_at', 'current_signups'] class AdminTopicSerializer(serializers.ModelSerializer): content = serializers.CharField( style={'base_template': 'textarea.html'}, help_text="帖子内容,支持 Markdown 格式。如果需要插入图片,请先调用媒体上传接口获取 URL。" ) class Meta: model = Topic fields = '__all__' read_only_fields = ['author', 'created_at', 'updated_at', 'view_count', 'is_verified_owner']