from rest_framework import serializers, status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from basic_info import models as basic_models from basic_info.models import FrontendPage, FrontendPageTypeEnum class CustomerEmployeeBindingSerializer(serializers.Serializer): """客户员工绑定序列化器""" customer_name = serializers.CharField(max_length=100, help_text='客户名称') employee_name = serializers.CharField(max_length=100, help_text='员工姓名') class CustomerEmployeeBindingView(APIView): """ 客户员工可见性绑定 API 将指定员工添加到指定客户的可见员工列表中。 POST /api/v2/customers/bind-employee/ """ permission_classes = [IsAuthenticated] def post(self, request): serializer = CustomerEmployeeBindingSerializer(data=request.data) serializer.is_valid(raise_exception=True) employee_name = serializer.validated_data['employee_name'] customer_name = serializer.validated_data['customer_name'] # 查询员工 employees = basic_models.Employee.objects.filter(name=employee_name) if employees.count() == 0: return Response( {'error': f'未找到名为 "{employee_name}" 的员工'}, status=status.HTTP_400_BAD_REQUEST ) if employees.count() > 1: return Response( {'error': f'找到多个名为 "{employee_name}" 的员工({employees.count()} 个),请使用更精确的标识'}, status=status.HTTP_403_FORBIDDEN ) # 查询客户 customers = basic_models.Customer.objects.filter(name=customer_name) if customers.count() == 0: return Response( {'error': f'未找到名为 "{customer_name}" 的客户'}, status=status.HTTP_400_BAD_REQUEST ) if customers.count() > 1: return Response( {'error': f'找到多个名为 "{customer_name}" 的客户({customers.count()} 个),请使用更精确的标识'}, status=status.HTTP_403_FORBIDDEN ) # 建立绑定关系 employee = employees.first() customer = customers.first() # 检查是否已经绑定 if customer.visible_employees.filter(id=employee.id).exists(): return Response( { 'message': f'员工 "{employee_name}" 已在客户 "{customer_name}" 的可见列表中', 'customer_id': customer.id, 'employee_id': employee.id, }, status=status.HTTP_200_OK ) # 添加绑定 customer.visible_employees.add(employee) return Response( { 'message': f'成功将员工 "{employee_name}" 添加到客户 "{customer_name}" 的可见列表', 'customer_id': customer.id, 'customer_name': customer.name, 'employee_id': employee.id, 'employee_name': employee.name, }, status=status.HTTP_201_CREATED ) class FrontendPageSerializer(serializers.ModelSerializer): """前端页面序列化器""" parent_key = serializers.CharField(source='parent.key', read_only=True, allow_null=True) class Meta: model = FrontendPage fields = ['key', 'label', 'page_type', 'parent_key', 'sort_order'] class MyVisiblePagesView(APIView): """ 获取当前登录用户的可见页面 API 根据当前登录用户关联的员工岗位,返回其可见的前端页面列表。 授予主菜单会自动包含其所有子菜单。 GET /api/v2/me/visible-pages/ 响应示例: { "employee_id": 1, "employee_name": "张三", "position_id": 2, "position_title": "生产主管", "visible_pages": [ {"key": "production", "label": "生产管理", "page_type": "main", "parent_key": null, "sort_order": 100}, {"key": "production-kanban", "label": "生产看板", "page_type": "sub", "parent_key": "production", "sort_order": 101} ], "visible_keys": ["production", "production-kanban", "printing-order-list"] } """ permission_classes = [IsAuthenticated] def get(self, request): # 从 request.user 获取关联的员工 user = request.user # 检查用户是否关联员工 if not hasattr(user, 'employee'): return Response({ 'employee_id': None, 'employee_name': None, 'position_id': None, 'position_title': None, 'visible_pages': [], 'visible_keys': [], }) employee = user.employee # 检查员工是否有岗位 if not employee.position: return Response({ 'employee_id': employee.id, 'employee_name': employee.name, 'position_id': None, 'position_title': None, 'visible_pages': [], 'visible_keys': [], }) # 获取岗位直接授予的页面 granted_pages = employee.position.visible_pages.filter(is_active=True).select_related('parent') # 计算所有可见页面(含子菜单继承) visible_pages = [] visible_keys = set() for page in granted_pages: visible_pages.append(page) visible_keys.add(page.key) # 如果是主菜单,自动包含所有子菜单 if page.page_type == FrontendPageTypeEnum.MAIN: children = page.children.filter(is_active=True).select_related('parent') for child in children: if child.key not in visible_keys: visible_pages.append(child) visible_keys.add(child.key) # 按 sort_order 排序 visible_pages.sort(key=lambda p: (p.sort_order, p.id)) return Response({ 'employee_id': employee.id, 'employee_name': employee.name, 'position_id': employee.position.id, 'position_title': employee.position.title, 'visible_pages': FrontendPageSerializer(visible_pages, many=True).data, 'visible_keys': sorted(visible_keys), })