diff --git a/backend/apps/factory/serializers.py b/backend/apps/factory/serializers.py index 00d70c4..2868a95 100644 --- a/backend/apps/factory/serializers.py +++ b/backend/apps/factory/serializers.py @@ -7,25 +7,32 @@ class FactorySerializer(serializers.ModelSerializer): 工厂序列化器 """ material_count = serializers.SerializerMethodField() + usernames = serializers.SerializerMethodField() class Meta: model = Factory fields = ['id', 'dealer_name', 'product_category', 'factory_name', 'brand', 'province', 'city', 'district', - 'address', 'website', 'created_at', 'updated_at', 'material_count'] - read_only_fields = ['id', 'created_at', 'updated_at', 'material_count'] + 'address', 'website', 'created_at', 'updated_at', + 'material_count', 'usernames'] + read_only_fields = ['id', 'created_at', 'updated_at', 'material_count', 'usernames'] def get_material_count(self, obj): - """ - 获取工厂的材料数量 - """ return obj.materials.count() + def get_usernames(self, obj): + return list(obj.users.values_list('username', flat=True)) + class FactoryListSerializer(serializers.ModelSerializer): """ 工厂列表序列化器(简化版) """ + usernames = serializers.SerializerMethodField() + class Meta: model = Factory - fields = ['id', 'factory_name', 'brand', 'province', 'city', 'dealer_name'] + fields = ['id', 'factory_name', 'brand', 'province', 'city', 'dealer_name', 'usernames'] + + def get_usernames(self, obj): + return list(obj.users.values_list('username', flat=True)) diff --git a/backend/apps/statistics/views.py b/backend/apps/statistics/views.py index 5dbbd9b..5fdbf29 100644 --- a/backend/apps/statistics/views.py +++ b/backend/apps/statistics/views.py @@ -48,8 +48,8 @@ def overview_statistics(request): count=Count('id') ).order_by('-count') - # 按地区的工厂数量分布 - region_stats = Factory.objects.values('province', 'city').annotate( + # 按省份的工厂数量分布 + region_stats = Factory.objects.values('province').annotate( count=Count('id') ).order_by('-count') @@ -167,7 +167,7 @@ def factory_statistics(request): if request.user.role != 'admin': return Response({"detail": "无权访问"}, status=403) - region_stats = list(Factory.objects.values('province', 'city').annotate( + region_stats = list(Factory.objects.values('province').annotate( count=Count('id') ).order_by('-count')) diff --git a/frontend/src/styles/screen.css b/frontend/src/styles/screen.css index ea82301..cb632eb 100644 --- a/frontend/src/styles/screen.css +++ b/frontend/src/styles/screen.css @@ -1,4 +1,4 @@ -.screen-body { +.screen-body { margin: 0; background: radial-gradient(circle at top left, #203450 0%, #0c1422 45%, #070b12 100%); color: #e6edf5; @@ -101,11 +101,11 @@ } .screen-card { - background: rgba(7, 14, 24, 0.92); - border: 1px solid rgba(159, 226, 255, 0.18); + background: linear-gradient(145deg, rgba(20, 38, 62, 0.88), rgba(12, 24, 44, 0.92)); + border: 1px solid rgba(159, 226, 255, 0.12); border-radius: 18px; padding: 16px; - box-shadow: 0 14px 40px rgba(0, 0, 0, 0.45); + box-shadow: 0 14px 40px rgba(0, 0, 0, 0.35); position: relative; overflow: hidden; } @@ -147,9 +147,9 @@ .stat-card { padding: 16px; border-radius: 14px; - background: linear-gradient(140deg, rgba(78, 134, 184, 0.35), rgba(8, 18, 28, 0.9)); - border: 1px solid rgba(255, 255, 255, 0.06); - box-shadow: inset 0 0 20px rgba(159, 226, 255, 0.08); + background: linear-gradient(140deg, rgba(78, 134, 184, 0.3), rgba(16, 30, 52, 0.85)); + border: 1px solid rgba(159, 226, 255, 0.1); + box-shadow: inset 0 0 20px rgba(159, 226, 255, 0.06); } .stat-card .label { diff --git a/frontend/src/utils/chartTheme.js b/frontend/src/utils/chartTheme.js new file mode 100644 index 0000000..b4ea8a0 --- /dev/null +++ b/frontend/src/utils/chartTheme.js @@ -0,0 +1,47 @@ +import * as echarts from 'echarts' + +const COLORS = [ + '#36d6fc', '#7b6cf6', '#f5a623', '#5dd9a7', + '#f06292', '#4fc3f7', '#ffd54f', '#9575cd', + '#4db6ac', '#ff8a65' +] + +const TEXT = '#c9d7e6' +const AXIS = 'rgba(180, 200, 220, 0.55)' +const SPLIT = 'rgba(159, 226, 255, 0.06)' + +echarts.registerTheme('screen-dark', { + color: COLORS, + backgroundColor: 'transparent', + textStyle: { color: TEXT, fontSize: 14 }, + title: { textStyle: { color: TEXT, fontSize: 16 } }, + legend: { + textStyle: { color: TEXT, fontSize: 13 } + }, + tooltip: { + backgroundColor: 'rgba(12, 22, 38, 0.92)', + borderColor: 'rgba(54, 214, 252, 0.25)', + textStyle: { color: '#e6edf5', fontSize: 13 } + }, + categoryAxis: { + axisLine: { lineStyle: { color: AXIS } }, + axisTick: { lineStyle: { color: AXIS } }, + axisLabel: { color: TEXT, fontSize: 13 }, + splitLine: { lineStyle: { color: SPLIT } } + }, + valueAxis: { + axisLine: { lineStyle: { color: AXIS } }, + axisTick: { lineStyle: { color: AXIS } }, + axisLabel: { color: TEXT, fontSize: 13 }, + splitLine: { lineStyle: { color: SPLIT } } + }, + line: { + smooth: true, + symbolSize: 6 + }, + pie: { + label: { color: TEXT, fontSize: 13 } + } +}) + +export const THEME = 'screen-dark' diff --git a/frontend/src/views/FactoryDetail.vue b/frontend/src/views/FactoryDetail.vue index 25a2a6b..12b9d1d 100644 --- a/frontend/src/views/FactoryDetail.vue +++ b/frontend/src/views/FactoryDetail.vue @@ -13,6 +13,7 @@ {{ formatRegion(factory.province, factory.city, factory.district) }} {{ factory.address }} {{ factory.website }} + {{ (factory.usernames || []).join('、') || '-' }} {{ factory.material_count }} diff --git a/frontend/src/views/FactoryManage.vue b/frontend/src/views/FactoryManage.vue index 875275b..3e86f10 100644 --- a/frontend/src/views/FactoryManage.vue +++ b/frontend/src/views/FactoryManage.vue @@ -8,6 +8,11 @@ + + +