mat/backend/apps/statistics/views.py

199 lines
6.8 KiB
Python

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.db.models import Count
from apps.material.models import Material
from apps.factory.models import Factory
def _build_brochure_url(request, brochure_field):
if brochure_field and request:
return request.build_absolute_uri(brochure_field.url)
return None
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def overview_statistics(request):
"""
数据总览统计
"""
# 只有管理员可访问
if request.user.role != 'admin':
return Response({"detail": "无权访问"}, status=403)
approved_materials = Material.objects.filter(status='approved')
# 材料总数
total_materials = approved_materials.count()
# 材料种类(材料子类数量)
total_material_categories = approved_materials.values('material_subcategory').distinct().count()
# 品牌数(工厂数)
total_brands = Factory.objects.count()
# 按专业类别的材料数量分布
major_category_stats = approved_materials.values('major_category').annotate(
count=Count('id')
).order_by('-count')
# 按材料子类的材料数量分布
material_subcategory_stats = approved_materials.values('material_subcategory').annotate(
count=Count('id')
).order_by('-count')[:10]
# 按所属品牌的材料数量分布
brand_stats = approved_materials.values('factory__factory_name').annotate(
count=Count('id')
).order_by('-count')
# 按地区的工厂数量分布
region_stats = Factory.objects.values('province', 'city').annotate(
count=Count('id')
).order_by('-count')
# 应用案例列表
cases_list = []
for item in approved_materials.filter(cases__isnull=False).exclude(cases='')[:10]:
cases_list.append({
'id': item.id,
'name': item.name,
'cases': item.cases,
'factory_name': item.factory.factory_name if item.factory else None,
'brochure_url': _build_brochure_url(request, item.brochure),
})
return Response({
'total_materials': total_materials,
'total_material_categories': total_material_categories,
'total_brands': total_brands,
'major_category_stats': list(major_category_stats),
'material_subcategory_stats': list(material_subcategory_stats),
'brand_stats': list(brand_stats),
'region_stats': list(region_stats),
'cases_list': cases_list,
})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def material_statistics(request):
"""
材料库统计
"""
if request.user.role != 'admin':
return Response({"detail": "无权访问"}, status=403)
material_subcategory = request.query_params.get('material_subcategory')
queryset = Material.objects.filter(status='approved')
if material_subcategory:
queryset = queryset.filter(material_subcategory=material_subcategory)
subcategories = list(Material.objects.filter(status='approved').values_list(
'material_subcategory', flat=True
).distinct())
def _level_counts(qs, field):
raw = qs.values(field).annotate(count=Count('id'))
mapping = {item[field]: item['count'] for item in raw if item[field] is not None}
return [mapping.get(1, 0), mapping.get(2, 0), mapping.get(3, 0)]
star_stats = {
'quality_level': _level_counts(queryset, 'quality_level'),
'durability_level': _level_counts(queryset, 'durability_level'),
'eco_level': _level_counts(queryset, 'eco_level'),
'carbon_level': _level_counts(queryset, 'carbon_level'),
'score_level': _level_counts(queryset, 'score_level'),
}
# 竞争优势与替代材料对比(优势为多选)
advantage_replace_counter = {}
for material in queryset:
advantages = material.advantage or []
for adv in advantages:
key = (adv, material.replace_type)
advantage_replace_counter[key] = advantage_replace_counter.get(key, 0) + 1
advantage_replace_stats = [
{'advantage': key[0], 'replace_type': key[1], 'count': count}
for key, count in advantage_replace_counter.items()
]
# 应用场景对比(多选)
application_scene_counter = {}
for material in queryset:
scenes = material.application_scene or []
for scene in scenes:
application_scene_counter[scene] = application_scene_counter.get(scene, 0) + 1
application_scene_stats = [
{'application_scene': key, 'count': count}
for key, count in application_scene_counter.items()
]
# 材料列表
materials_list = []
for item in queryset[:20]:
materials_list.append({
'id': item.id,
'name': item.name,
'material_category': item.material_category,
'material_subcategory': item.material_subcategory,
'factory_name': item.factory.factory_name if item.factory else None,
'brochure_url': _build_brochure_url(request, item.brochure),
})
return Response({
'levels': [1, 2, 3],
'subcategories': subcategories,
'star_stats': star_stats,
'advantage_replace_stats': advantage_replace_stats,
'application_scene_stats': application_scene_stats,
'materials_list': materials_list,
'advantage_choices': Material.ADVANTAGE_CHOICES,
'replace_type_choices': Material.REPLACE_TYPE_CHOICES,
'application_scene_choices': Material.APPLICATION_SCENE_CHOICES,
})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def factory_statistics(request):
"""
工厂库统计
"""
if request.user.role != 'admin':
return Response({"detail": "无权访问"}, status=403)
region_stats = list(Factory.objects.values('province', 'city').annotate(
count=Count('id')
).order_by('-count'))
factory_category_stats = []
approved_materials = Material.objects.filter(status='approved')
for factory in Factory.objects.all():
material_categories = approved_materials.filter(factory=factory).values(
'material_category'
).annotate(
count=Count('id')
)
factory_category_stats.append({
'factory_id': factory.id,
'factory_name': factory.factory_name,
'categories': list(material_categories),
'total_materials': approved_materials.filter(factory=factory).count()
})
factories_list = list(Factory.objects.values(
'id', 'factory_name', 'factory_short_name', 'province', 'city', 'website'
))
return Response({
'region_stats': region_stats,
'factory_category_stats': factory_category_stats,
'factories_list': factories_list,
})