""" Stateflow 序列化器 """ from rest_framework import serializers from django.db import transaction from django.contrib.contenttypes.models import ContentType from stateflow import models class StateParameterSerializer(serializers.ModelSerializer): """状态参数序列化器""" attachment_url = serializers.SerializerMethodField(read_only=True) class Meta: model = models.StateParameter fields = ['id', 'key', 'value', 'attachment', 'attachment_url', 'description', 'is_required', 'is_image_path'] read_only_fields = ['id', 'attachment_url'] def get_attachment_url(self, obj): """获取附件的完整 URL""" if obj.attachment: request = self.context.get('request') if request: return request.build_absolute_uri(obj.attachment.url) return obj.attachment.url return None class StateListSerializer(serializers.ModelSerializer): """状态列表序列化器(不包含参数)""" class Meta: model = models.State fields = ['id', 'name', 'description', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] class StateDetailSerializer(serializers.ModelSerializer): """状态详情序列化器(包含参数)""" parameters = StateParameterSerializer(many=True, read_only=True) class Meta: model = models.State fields = ['id', 'name', 'description', 'parameters', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] class StateCreateUpdateSerializer(serializers.ModelSerializer): """状态创建/更新序列化器""" parameter_ids = serializers.ListField( child=serializers.IntegerField(), required=False, write_only=True, help_text="参数ID列表" ) parameters = StateParameterSerializer(many=True, read_only=True) class Meta: model = models.State fields = ['name', 'description', 'parameter_ids', 'parameters'] def validate_parameter_ids(self, value): """验证参数ID是否存在""" if value: existing_ids = set(models.StateParameter.objects.filter(id__in=value).values_list('id', flat=True)) invalid_ids = set(value) - existing_ids if invalid_ids: raise serializers.ValidationError(f"参数ID不存在: {invalid_ids}") return value @transaction.atomic def create(self, validated_data): parameter_ids = validated_data.pop('parameter_ids', []) state = models.State.objects.create(**validated_data) # 关联参数(多对多) if parameter_ids: state.parameters.set(parameter_ids) return state @transaction.atomic def update(self, instance, validated_data): parameter_ids = validated_data.pop('parameter_ids', None) # 更新基本字段 instance.name = validated_data.get('name', instance.name) instance.description = validated_data.get('description', instance.description) instance.save() # 如果提供了参数ID列表,更新关联 if parameter_ids is not None: instance.parameters.set(parameter_ids) return instance # Process 序列化器 class ProcessNodeSerializer(serializers.ModelSerializer): """流程节点序列化器""" state_id = serializers.IntegerField(source='state.id', read_only=True) state_name = serializers.CharField(source='state.name', read_only=True) class Meta: model = models.ProcessNode fields = ['id', 'state_id', 'state_name', 'order'] read_only_fields = ['id'] class ProcessNodeCreateSerializer(serializers.Serializer): """流程节点创建序列化器""" state_id = serializers.IntegerField(help_text="状态ID") order = serializers.IntegerField(help_text="排序号", min_value=0) def validate_state_id(self, value): """验证状态是否存在""" try: models.State.objects.get(id=value) except models.State.DoesNotExist: raise serializers.ValidationError(f"状态ID {value} 不存在") return value class ProcessListSerializer(serializers.ModelSerializer): """流程列表序列化器(不包含节点)""" node_count = serializers.IntegerField(read_only=True, help_text="节点数量") class Meta: model = models.Process fields = ['id', 'name', 'description', 'node_count', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] class ProcessDetailSerializer(serializers.ModelSerializer): """流程详情序列化器(包含节点)""" nodes = ProcessNodeSerializer(source='process_nodes', many=True, read_only=True) class Meta: model = models.Process fields = ['id', 'name', 'description', 'nodes', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] class ProcessCreateUpdateSerializer(serializers.ModelSerializer): """流程创建/更新序列化器""" nodes = ProcessNodeCreateSerializer(many=True, required=False, help_text="流程节点列表") class Meta: model = models.Process fields = ['name', 'description', 'nodes'] @transaction.atomic def create(self, validated_data): nodes_data = validated_data.pop('nodes', []) process = models.Process.objects.create(**validated_data) # 创建节点 for node_data in nodes_data: models.ProcessNode.objects.create( process=process, state_id=node_data['state_id'], order=node_data['order'] ) return process @transaction.atomic def update(self, instance, validated_data): nodes_data = validated_data.pop('nodes', None) # 更新基本字段 instance.name = validated_data.get('name', instance.name) instance.description = validated_data.get('description', instance.description) instance.save() # 如果提供了节点数据,更新节点 if nodes_data is not None: # 删除旧节点 instance.process_nodes.all().delete() # 创建新节点 for node_data in nodes_data: models.ProcessNode.objects.create( process=instance, state_id=node_data['state_id'], order=node_data['order'] ) return instance # BusinessObject 序列化器 class StateLogParameterRecordSerializer(serializers.ModelSerializer): """状态流转参数记录序列化器""" class Meta: model = models.StateLogParameterRecord fields = ['id', 'state_log', 'parameters', 'created_at', 'remark'] read_only_fields = ['id', 'created_at'] class StateFlowRecordSerializer(serializers.ModelSerializer): """状态流转记录序列化器(只读)""" state_name = serializers.CharField(source='state.name', read_only=True) completed_by_username = serializers.CharField(source='completed_by.username', read_only=True) class Meta: model = models.StateFlowRecord fields = [ 'id', 'state', 'state_name', 'completed_at', 'completed_by', 'completed_by_username', 'is_cancelled', 'cancelled_at' ] read_only_fields = ['id', 'completed_at', 'is_cancelled', 'cancelled_at'] class StateFlowRecordWithParametersSerializer(serializers.ModelSerializer): """状态流转记录序列化器(包含参数摘要)""" state_name = serializers.CharField(source='state.name', read_only=True) completed_by_username = serializers.CharField(source='completed_by.username', read_only=True) parameters_summary = serializers.SerializerMethodField(read_only=True) class Meta: model = models.StateFlowRecord fields = [ 'id', 'state', 'state_name', 'completed_at', 'completed_by', 'completed_by_username', 'is_cancelled', 'cancelled_at', 'parameters_summary' ] read_only_fields = ['id', 'completed_at', 'is_cancelled', 'cancelled_at'] def get_parameters_summary(self, obj): """获取参数摘要""" return obj.get_all_parameters_summary() class BusinessObjectListSerializer(serializers.ModelSerializer): """业务对象列表序列化器""" process_name = serializers.CharField(source='process.name', read_only=True) current_state_name = serializers.SerializerMethodField() overall_status = serializers.SerializerMethodField() progress_percentage = serializers.SerializerMethodField() # 关联对象信息 content_type_name = serializers.SerializerMethodField() class Meta: model = models.BusinessObject fields = [ 'id', 'name', 'process', 'process_name', 'current_state_name', 'overall_status', 'progress_percentage', 'content_type', 'object_id', 'content_type_name', 'description', 'created_at', 'updated_at' ] def get_current_state_name(self, obj): from . import services state = services.get_business_object_current_state(obj) return state.name if state else None def get_overall_status(self, obj): from . import services return services.get_overall_status(obj) def get_progress_percentage(self, obj): from . import services return round(services.get_progress_percentage(obj), 2) def get_content_type_name(self, obj): if obj.content_type: return f"{obj.content_type.app_label}.{obj.content_type.model}" return None class BusinessObjectDetailSerializer(serializers.ModelSerializer): """业务对象详情序列化器""" process_detail = ProcessDetailSerializer(source='process', read_only=True) current_state = serializers.SerializerMethodField() overall_status = serializers.SerializerMethodField() progress_percentage = serializers.SerializerMethodField() timeline = serializers.SerializerMethodField() state_logs = StateFlowRecordSerializer(many=True, read_only=True) # 关联对象信息 content_type_name = serializers.SerializerMethodField() class Meta: model = models.BusinessObject fields = [ 'id', 'name', 'process', 'process_detail', 'current_state', 'overall_status', 'progress_percentage', 'timeline', 'state_logs', 'content_type', 'object_id', 'content_type_name', 'description', 'created_at', 'updated_at' ] def get_current_state(self, obj): from . import services state = services.get_business_object_current_state(obj) if state: return StateListSerializer(state).data return None def get_overall_status(self, obj): from . import services return services.get_overall_status(obj) def get_progress_percentage(self, obj): from . import services return round(services.get_progress_percentage(obj), 2) def get_timeline(self, obj): from . import services timeline = services.get_business_object_state_timeline(obj) return [ { 'state': StateListSerializer(item['state']).data, 'status': item['status'], 'order': item['order'], 'completed_at': item['completed_at'], 'completed_by': item['completed_by'].username if item['completed_by'] else None, 'cancelled_at': item['cancelled_at'], 'is_cancelled': item['is_cancelled'], } for item in timeline ] def get_content_type_name(self, obj): if obj.content_type: return f"{obj.content_type.app_label}.{obj.content_type.model}" return None class BusinessObjectCreateUpdateSerializer(serializers.ModelSerializer): """业务对象创建/更新序列化器""" # 支持通过 app_label.model 字符串指定 content_type content_type_str = serializers.CharField( write_only=True, required=False, allow_null=True, help_text="格式: app_label.model, 例如: basic_info.order" ) class Meta: model = models.BusinessObject fields = [ 'name', 'process', 'description', 'content_type', 'object_id', 'content_type_str' ] extra_kwargs = { 'content_type': {'required': False, 'allow_null': True}, 'object_id': {'required': False, 'allow_null': True}, } def validate(self, attrs): """验证 content_type 和 object_id 的一致性""" content_type = attrs.get('content_type') content_type_str = attrs.get('content_type_str') object_id = attrs.get('object_id') # 如果提供了 content_type_str,解析并设置 content_type if content_type_str: try: app_label, model = content_type_str.split('.') content_type = ContentType.objects.get(app_label=app_label, model=model) attrs['content_type'] = content_type except (ValueError, ContentType.DoesNotExist): raise serializers.ValidationError({ 'content_type_str': f'无效的 content_type 格式: {content_type_str}' }) # 验证:如果提供了 content_type,必须提供 object_id if content_type and not object_id: raise serializers.ValidationError({ 'object_id': '提供了关联对象类型,必须同时提供对象ID' }) # 验证:如果提供了 object_id,必须提供 content_type if object_id and not content_type: raise serializers.ValidationError({ 'content_type': '提供了对象ID,必须同时提供关联对象类型' }) # 移除临时字段 attrs.pop('content_type_str', None) return attrs @transaction.atomic def create(self, validated_data): return models.BusinessObject.objects.create(**validated_data) @transaction.atomic def update(self, instance, validated_data): for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() return instance