""" BusinessObject API ViewSet """ from rest_framework import viewsets, filters, status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.pagination import LimitOffsetPagination from django_filters.rest_framework import DjangoFilterBackend from django_filters import rest_framework as django_filters from stateflow import models, services from stateflow.serializers import ( BusinessObjectListSerializer, BusinessObjectDetailSerializer, BusinessObjectCreateUpdateSerializer, StateListSerializer, ) class BusinessObjectFilterSet(django_filters.FilterSet): """业务对象过滤器""" name = django_filters.CharFilter(lookup_expr='icontains') process_name = django_filters.CharFilter(field_name='process__name', lookup_expr='icontains') overall_status = django_filters.ChoiceFilter( choices=[ ('not_started', '未开始'), ('in_progress', '进行中'), ('completed', '已完成') ], method='filter_overall_status' ) content_type_str = django_filters.CharFilter(method='filter_content_type') has_content_object = django_filters.BooleanFilter(method='filter_has_content_object') def filter_overall_status(self, queryset, name, value): """过滤整体状态""" business_object_ids = [] for obj in queryset: if services.get_overall_status(obj) == value: business_object_ids.append(obj.id) return queryset.filter(id__in=business_object_ids) def filter_content_type(self, queryset, name, value): """通过 app_label.model 字符串过滤""" try: from django.contrib.contenttypes.models import ContentType app_label, model = value.split('.') content_type = ContentType.objects.get(app_label=app_label, model=model) return queryset.filter(content_type=content_type) except: return queryset.none() def filter_has_content_object(self, queryset, name, value): """过滤是否有关联对象""" if value: return queryset.exclude(content_type__isnull=True) else: return queryset.filter(content_type__isnull=True) class Meta: model = models.BusinessObject fields = ['name', 'process', 'process_name', 'overall_status', 'content_type_str', 'has_content_object'] class BusinessObjectViewSet(viewsets.ModelViewSet): """ 业务对象 CRUD 接口 业务对象是流程的实例,可以选择性地关联到实际的业务模型(如订单、工单等) list: 获取业务对象列表 retrieve: 获取业务对象详情(包含时间线和日志) create: 创建业务对象 update: 更新业务对象 partial_update: 部分更新业务对象 destroy: 删除业务对象 查询参数: - name: 按名称模糊查询 - process: 按流程ID过滤 - process_name: 按流程名称模糊查询 - overall_status: 按整体状态过滤 (not_started/in_progress/completed) - content_type_str: 按关联对象类型过滤,格式: app_label.model - has_content_object: 是否有关联对象 (true/false) - search: 全文搜索(名称和描述) - ordering: 排序字段 """ queryset = models.BusinessObject.objects.all() pagination_class = LimitOffsetPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_class = BusinessObjectFilterSet search_fields = ['name', 'description'] ordering_fields = ['id', 'name', 'created_at', 'updated_at'] ordering = ['-created_at'] def get_serializer_class(self): """根据动作选择序列化器""" if self.action == 'list': return BusinessObjectListSerializer elif self.action in ['create', 'update', 'partial_update']: return BusinessObjectCreateUpdateSerializer else: # retrieve return BusinessObjectDetailSerializer def get_queryset(self): """优化查询""" queryset = super().get_queryset() if self.action == 'list': queryset = queryset.select_related('process', 'content_type') elif self.action == 'retrieve': queryset = queryset.select_related('process', 'content_type').prefetch_related( 'state_logs__state', 'state_logs__completed_by', 'process__process_nodes__state' ) return queryset @action(detail=True, methods=['post']) def advance(self, request, pk=None): """推进到下一个状态""" business_object = self.get_object() user = request.user success, message = services.advance_to_next_state(business_object, user) if success: return Response({ 'success': True, 'message': message, 'business_object': BusinessObjectDetailSerializer(business_object).data }) else: return Response({ 'success': False, 'message': message }, status=status.HTTP_400_BAD_REQUEST) @action(detail=True, methods=['post']) def reset(self, request, pk=None): """重置进度""" business_object = self.get_object() services.reset_business_object_progress(business_object) return Response({ 'success': True, 'message': '进度已重置', 'business_object': BusinessObjectDetailSerializer(business_object).data }) @action(detail=True, methods=['get']) def timeline(self, request, pk=None): """获取状态时间线""" business_object = self.get_object() timeline = services.get_business_object_state_timeline(business_object) timeline_data = [ { '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 ] return Response(timeline_data)