199 lines
6.8 KiB
Python
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,
|
|
})
|