From 815e8df10b7142b0a7c91d2007f29c3aa100e4f5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 24 Apr 2026 15:51:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(material):=20=E6=96=B0=E5=A2=9E=20H5=20?= =?UTF-8?q?=E5=A4=A7=E7=B1=BB/=E7=A7=8D=E7=B1=BB=E8=81=9A=E5=90=88?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- backend/apps/material/views.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/apps/material/views.py b/backend/apps/material/views.py index b35ccba..6149457 100644 --- a/backend/apps/material/views.py +++ b/backend/apps/material/views.py @@ -7,6 +7,7 @@ from openpyxl import Workbook from openpyxl.worksheet.datavalidation import DataValidation from openpyxl.styles import Alignment, Border, Font, PatternFill, Side from openpyxl.utils import get_column_letter +from django.db.models import Count from rest_framework import generics, status from rest_framework.decorators import api_view, action from rest_framework.permissions import IsAuthenticated @@ -483,6 +484,37 @@ class MaterialViewSet(ModelViewSet): return Response(result) + @action(detail=False, methods=['get'], url_path='categories-by-major') + def categories_by_major(self, request): + major = request.query_params.get('major_category') + if not major: + return Response({"detail": "major_category 参数必填"}, status=status.HTTP_400_BAD_REQUEST) + qs = (Material.objects + .filter(major_category=major, status='approved') + .exclude(material_category__isnull=True) + .exclude(material_category__exact='') + .values('material_category') + .annotate(count=Count('id')) + .order_by('material_category')) + data = [{"value": row['material_category'], "count": row['count']} for row in qs] + return Response(data) + + @action(detail=False, methods=['get'], url_path='subcategories-by-category') + def subcategories_by_category(self, request): + major = request.query_params.get('major_category') + category = request.query_params.get('material_category') + if not major or not category: + return Response({"detail": "major_category 和 material_category 均必填"}, status=status.HTTP_400_BAD_REQUEST) + qs = (Material.objects + .filter(major_category=major, material_category=category, status='approved') + .exclude(material_subcategory__isnull=True) + .exclude(material_subcategory__exact='') + .values('material_subcategory') + .annotate(count=Count('id')) + .order_by('material_subcategory')) + data = [{"value": row['material_subcategory'], "count": row['count']} for row in qs] + return Response(data) + class MaterialCategoryViewSet(ModelViewSet): """