From c6ba742f9dd58425dabdc8a742ddd3c0c8aeed82 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 13 Mar 2026 13:00:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9C=81=E5=B8=82=E5=8C=BA=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E6=96=87=E5=AD=97=E3=80=81=E5=B7=A5=E5=8E=82=E5=85=B3?= =?UTF-8?q?=E8=81=94=E7=94=A8=E6=88=B7=E8=B4=A6=E5=8F=B7=E3=80=81=E5=A4=A7?= =?UTF-8?q?=E5=B1=8F=E5=9B=BE=E8=A1=A8=E4=B8=BB=E9=A2=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 省市区字段改为存储文字名称而非编码 - 工厂序列化器新增usernames字段,列表和详情页展示关联用户账号 - 地区分布统计改为仅按省份聚合 - 新增ECharts screen-dark主题,统一配色和字号 - 大屏卡片背景由纯黑改为深蓝渐变 Made-with: Cursor --- backend/apps/factory/serializers.py | 19 ++++-- backend/apps/statistics/views.py | 6 +- frontend/src/styles/screen.css | 14 ++-- frontend/src/utils/chartTheme.js | 47 ++++++++++++++ frontend/src/views/FactoryDetail.vue | 1 + frontend/src/views/FactoryManage.vue | 10 ++- frontend/src/views/screen/ScreenFactories.vue | 21 +++--- frontend/src/views/screen/ScreenMaterials.vue | 41 ++++++------ frontend/src/views/screen/ScreenOverview.vue | 64 +++++++++---------- 9 files changed, 145 insertions(+), 78 deletions(-) create mode 100644 frontend/src/utils/chartTheme.js 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 @@ + + +