Kaynağa Gözat

feat(图表): 优化图表显示并添加数据标签

- 为所有图表系列添加数据标签显示,提高数据可读性
- 统一饼图标签格式为"{b}\n{c} ({d}%)"
- 优化排名组件支持并列排名计算
- 调整图表标签字体大小和位置
- 修复数据字段从count改为totalCount的引用
- 优化图表网格和布局配置
huoyi 1 ay önce
ebeveyn
işleme
97d3e28b3d

+ 14 - 5
src/views/blockingData/blockingDataScreen/components/ModuleBrigadeOne.vue

@@ -221,7 +221,8 @@ const multiLineChartOption = (xAxisData, series) => ({
221
     symbolSize: 6,
221
     symbolSize: 6,
222
     data: s.data,
222
     data: s.data,
223
     itemStyle: { color: s.color },
223
     itemStyle: { color: s.color },
224
-    lineStyle: { color: s.color }
224
+    lineStyle: { color: s.color },
225
+    label: { show: true, position: 'top', fontSize: 9, color: s.color }
225
   }))
226
   }))
226
 })
227
 })
227
 
228
 
@@ -231,7 +232,13 @@ const horizontalBarChartOption = (data, color) => ({
231
   grid: { left: '20%', top: '15%', right: '5%', bottom: '15%', containLabel: true },
232
   grid: { left: '20%', top: '15%', right: '5%', bottom: '15%', containLabel: true },
232
   xAxis: { type: 'value', axisLine: { lineStyle: { color: '#999' } }, axisLabel: { fontSize: 10, color: '#666' }, splitLine: { lineStyle: { color: '#eee' } } },
233
   xAxis: { type: 'value', axisLine: { lineStyle: { color: '#999' } }, axisLabel: { fontSize: 10, color: '#666' }, splitLine: { lineStyle: { color: '#eee' } } },
233
   yAxis: { type: 'category', data: data.map(d => d.name), axisLine: { lineStyle: { color: '#999' } }, axisLabel: { fontSize: 10, color: '#666' } },
234
   yAxis: { type: 'category', data: data.map(d => d.name), axisLine: { lineStyle: { color: '#999' } }, axisLabel: { fontSize: 10, color: '#666' } },
234
-  series: [{ type: 'bar', data: data.map(d => d.value), itemStyle: { color: color }, barWidth: 15 }]
235
+  series: [{ 
236
+    type: 'bar', 
237
+    data: data.map(d => d.value), 
238
+    itemStyle: { color: color }, 
239
+    barWidth: 15,
240
+    label: { show: true, position: 'right', fontSize: 10, color: color }
241
+  }]
235
 })
242
 })
236
 
243
 
237
 const barLineChartOption = (xAxisData, barData, lineData) => ({
244
 const barLineChartOption = (xAxisData, barData, lineData) => ({
@@ -249,7 +256,8 @@ const barLineChartOption = (xAxisData, barData, lineData) => ({
249
       type: 'bar',
256
       type: 'bar',
250
       data: barData,
257
       data: barData,
251
       itemStyle: { color: '#3b82f6' },
258
       itemStyle: { color: '#3b82f6' },
252
-      barWidth: 20
259
+      barWidth: 20,
260
+      label: { show: true, position: 'top', fontSize: 9, color: '#3b82f6' }
253
     },
261
     },
254
     {
262
     {
255
       name: '平均查堵件数',
263
       name: '平均查堵件数',
@@ -259,7 +267,8 @@ const barLineChartOption = (xAxisData, barData, lineData) => ({
259
       symbolSize: 6,
267
       symbolSize: 6,
260
       data: lineData,
268
       data: lineData,
261
       itemStyle: { color: '#ec4899' },
269
       itemStyle: { color: '#ec4899' },
262
-      lineStyle: { color: '#ec4899' }
270
+      lineStyle: { color: '#ec4899' },
271
+      label: { show: true, position: 'top', fontSize: 9, color: '#ec4899' }
263
     }
272
     }
264
   ]
273
   ]
265
 })
274
 })
@@ -276,7 +285,7 @@ const pieChartOption = (data, colors) => ({
276
     radius: '65%',
285
     radius: '65%',
277
     center: ['50%', '55%'],
286
     center: ['50%', '55%'],
278
     data: data,
287
     data: data,
279
-    label: { show: true, formatter: '{b}', fontSize: 10 }
288
+    label: { show: true, formatter: '{b}\n{c} ({d}%)', fontSize: 10 }
280
   }]
289
   }]
281
 })
290
 })
282
 
291
 

+ 5 - 4
src/views/blockingData/blockingDataScreen/components/ModuleBrigadeTwo.vue

@@ -173,7 +173,7 @@ const fetchData = async () => {
173
       supervisorRes.value.data.slice(0, 10).forEach(item => {
173
       supervisorRes.value.data.slice(0, 10).forEach(item => {
174
         rankData1.push({
174
         rankData1.push({
175
           name: item.supervisorName || item.name || '',
175
           name: item.supervisorName || item.name || '',
176
-          value: item.count || item.value || 0
176
+          value: item.totalCount || item.value || 0
177
         })
177
         })
178
       })
178
       })
179
     }
179
     }
@@ -183,7 +183,7 @@ const fetchData = async () => {
183
       teamRes.value.data.slice(0, 10).forEach(item => {
183
       teamRes.value.data.slice(0, 10).forEach(item => {
184
         rankData2.push({
184
         rankData2.push({
185
           name: item.teamLeaderName || item.name || '',
185
           name: item.teamLeaderName || item.name || '',
186
-          value: item.count || item.value || 0
186
+          value: item.totalCount || item.value || 0
187
         })
187
         })
188
       })
188
       })
189
     }
189
     }
@@ -193,7 +193,7 @@ const fetchData = async () => {
193
       userRes.value.data.slice(0, 10).forEach(item => {
193
       userRes.value.data.slice(0, 10).forEach(item => {
194
         rankData3.push({
194
         rankData3.push({
195
           name: item.userName || item.name || '',
195
           name: item.userName || item.name || '',
196
-          value: item.count || item.value || 0
196
+          value: item.totalCount || item.value || 0
197
         })
197
         })
198
       })
198
       })
199
     }
199
     }
@@ -401,7 +401,8 @@ const multiSeriesBarChartOption = (xAxisData, series) => ({
401
     type: 'bar',
401
     type: 'bar',
402
     data: s.data,
402
     data: s.data,
403
     itemStyle: { color: s.color },
403
     itemStyle: { color: s.color },
404
-    barWidth: 15
404
+    barWidth: 15,
405
+    label: { show: true, position: 'top', fontSize: 9, color: s.color }
405
   }))
406
   }))
406
 })
407
 })
407
 
408
 

+ 76 - 61
src/views/blockingData/blockingDataScreen/components/ModuleOne.vue

@@ -23,7 +23,7 @@
23
             <div class="stat-left">
23
             <div class="stat-left">
24
               <div class="stat-label">总查堵万分率</div>
24
               <div class="stat-label">总查堵万分率</div>
25
               <div class="stat-content">
25
               <div class="stat-content">
26
-                <div class="stat-value">{{ totalBlockedRate }}</div>
26
+                <div class="stat-value">{{ totalBlockedRate.toFixed(2) }}</div>
27
                 <div class="stat-unit">‱</div>
27
                 <div class="stat-unit">‱</div>
28
               </div>
28
               </div>
29
             </div>
29
             </div>
@@ -453,14 +453,15 @@ const loadData = async () => {
453
               borderColor: '#fff',
453
               borderColor: '#fff',
454
               borderWidth: 2
454
               borderWidth: 2
455
             },
455
             },
456
-            // label: {
457
-            //   show: true,
458
-            //   position: 'center'
459
-            // },
456
+            label: {
457
+              show: true,
458
+              formatter: '{b}\n{c} ({d}%)',
459
+              fontSize: 10
460
+            },
460
             emphasis: {
461
             emphasis: {
461
               label: {
462
               label: {
462
                 show: true,
463
                 show: true,
463
-                fontSize: '18',
464
+                fontSize: '14',
464
                 fontWeight: 'bold'
465
                 fontWeight: 'bold'
465
               }
466
               }
466
             },
467
             },
@@ -496,7 +497,8 @@ const loadData = async () => {
496
           const item = luggageDataList.find(d => d.brigadeName === brigade)
497
           const item = luggageDataList.find(d => d.brigadeName === brigade)
497
           return item ? item.t1PassengerLuggageCount : 0
498
           return item ? item.t1PassengerLuggageCount : 0
498
         }),
499
         }),
499
-        itemStyle: { color: '#3b82f6' }
500
+        itemStyle: { color: '#3b82f6' },
501
+        label: { show: true, position: 'top', fontSize: 10, color: '#3b82f6' }
500
       },
502
       },
501
       {
503
       {
502
         name: 'T2旅检行李数',
504
         name: 'T2旅检行李数',
@@ -505,7 +507,8 @@ const loadData = async () => {
505
           const item = luggageDataList.find(d => d.brigadeName === brigade)
507
           const item = luggageDataList.find(d => d.brigadeName === brigade)
506
           return item ? item.t2PassengerLuggageCount : 0
508
           return item ? item.t2PassengerLuggageCount : 0
507
         }),
509
         }),
508
-        itemStyle: { color: '#22c55e' }
510
+        itemStyle: { color: '#22c55e' },
511
+        label: { show: true, position: 'top', fontSize: 10, color: '#22c55e' }
509
       },
512
       },
510
       {
513
       {
511
         name: 'T1行检行李数',
514
         name: 'T1行检行李数',
@@ -514,7 +517,8 @@ const loadData = async () => {
514
           const item = luggageDataList.find(d => d.brigadeName === brigade)
517
           const item = luggageDataList.find(d => d.brigadeName === brigade)
515
           return item ? item.t1CargoLuggageCount : 0
518
           return item ? item.t1CargoLuggageCount : 0
516
         }),
519
         }),
517
-        itemStyle: { color: '#f97316' }
520
+        itemStyle: { color: '#f97316' },
521
+        label: { show: true, position: 'top', fontSize: 10, color: '#f97316' }
518
       },
522
       },
519
       {
523
       {
520
         name: 'T2行检行李数',
524
         name: 'T2行检行李数',
@@ -523,7 +527,8 @@ const loadData = async () => {
523
           const item = luggageDataList.find(d => d.brigadeName === brigade)
527
           const item = luggageDataList.find(d => d.brigadeName === brigade)
524
           return item ? item.t2CargoLuggageCount : 0
528
           return item ? item.t2CargoLuggageCount : 0
525
         }),
529
         }),
526
-        itemStyle: { color: '#ec4899' }
530
+        itemStyle: { color: '#ec4899' },
531
+        label: { show: true, position: 'top', fontSize: 10, color: '#ec4899' }
527
       }
532
       }
528
     ]
533
     ]
529
     
534
     
@@ -540,7 +545,8 @@ const loadData = async () => {
540
         itemStyle: { color: '#3b82f6' },
545
         itemStyle: { color: '#3b82f6' },
541
         lineStyle: { width: 3 },
546
         lineStyle: { width: 3 },
542
         symbol: 'circle',
547
         symbol: 'circle',
543
-        symbolSize: 8
548
+        symbolSize: 8,
549
+        label: { show: true, position: 'top', fontSize: 10, color: '#3b82f6' }
544
       },
550
       },
545
       {
551
       {
546
         name: 'T2旅检查堵数',
552
         name: 'T2旅检查堵数',
@@ -553,7 +559,8 @@ const loadData = async () => {
553
         itemStyle: { color: '#22c55e' },
559
         itemStyle: { color: '#22c55e' },
554
         lineStyle: { width: 3 },
560
         lineStyle: { width: 3 },
555
         symbol: 'circle',
561
         symbol: 'circle',
556
-        symbolSize: 8
562
+        symbolSize: 8,
563
+        label: { show: true, position: 'top', fontSize: 10, color: '#22c55e' }
557
       },
564
       },
558
       {
565
       {
559
         name: 'T1行检查堵数',
566
         name: 'T1行检查堵数',
@@ -566,7 +573,8 @@ const loadData = async () => {
566
         itemStyle: { color: '#f97316' },
573
         itemStyle: { color: '#f97316' },
567
         lineStyle: { width: 3 },
574
         lineStyle: { width: 3 },
568
         symbol: 'circle',
575
         symbol: 'circle',
569
-        symbolSize: 8
576
+        symbolSize: 8,
577
+        label: { show: true, position: 'top', fontSize: 10, color: '#f97316' }
570
       },
578
       },
571
       {
579
       {
572
         name: 'T2行检查堵数',
580
         name: 'T2行检查堵数',
@@ -579,7 +587,8 @@ const loadData = async () => {
579
         itemStyle: { color: '#ec4899' },
587
         itemStyle: { color: '#ec4899' },
580
         lineStyle: { width: 3 },
588
         lineStyle: { width: 3 },
581
         symbol: 'circle',
589
         symbol: 'circle',
582
-        symbolSize: 8
590
+        symbolSize: 8,
591
+        label: { show: true, position: 'top', fontSize: 10, color: '#ec4899' }
583
       }
592
       }
584
     ]
593
     ]
585
     
594
     
@@ -602,23 +611,25 @@ const loadData = async () => {
602
         }
611
         }
603
       },
612
       },
604
       legend: {
613
       legend: {
614
+       
605
         data: [
615
         data: [
606
           'T1旅检行李数', 'T2旅检行李数', 'T1行检行李数', 'T2行检行李数',
616
           'T1旅检行李数', 'T2旅检行李数', 'T1行检行李数', 'T2行检行李数',
607
           'T1旅检查堵数', 'T2旅检查堵数', 'T1行检查堵数', 'T2行检查堵数'
617
           'T1旅检查堵数', 'T2旅检查堵数', 'T1行检查堵数', 'T2行检查堵数'
608
         ]
618
         ]
609
       },
619
       },
610
       grid: {
620
       grid: {
621
+       top: '80',
611
         left: '3%',
622
         left: '3%',
612
         right: '4%',
623
         right: '4%',
613
-        bottom: '3%',
624
+         bottom: '1%',
614
         containLabel: true
625
         containLabel: true
615
       },
626
       },
616
       xAxis: {
627
       xAxis: {
617
         type: 'category',
628
         type: 'category',
618
         data: brigadeNames,
629
         data: brigadeNames,
619
-        axisLabel: {
620
-          rotate: 45
621
-        }
630
+        // axisLabel: {
631
+        //   rotate: 45
632
+        // }
622
       },
633
       },
623
       yAxis: [
634
       yAxis: [
624
         {
635
         {
@@ -674,13 +685,13 @@ const loadData = async () => {
674
         const found = groupedData[type].find(d => d.missCheckItem === item)
685
         const found = groupedData[type].find(d => d.missCheckItem === item)
675
         return found ? found.count : 0
686
         return found ? found.count : 0
676
       })
687
       })
688
+      const color = ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6'][index % 6]
677
       return {
689
       return {
678
         name: type,
690
         name: type,
679
         type: 'bar',
691
         type: 'bar',
680
         data: data,
692
         data: data,
681
-        itemStyle: {
682
-          color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6'][index % 6]
683
-        }
693
+        itemStyle: { color: color },
694
+        label: { show: true, position: 'top', fontSize: 10, color: color }
684
       }
695
       }
685
     })
696
     })
686
     
697
     
@@ -785,23 +796,19 @@ const loadData = async () => {
785
           type: 'bar',
796
           type: 'bar',
786
           yAxisIndex: 0,
797
           yAxisIndex: 0,
787
           data: timePeriodData.map(d => d.totalLuggageCount),
798
           data: timePeriodData.map(d => d.totalLuggageCount),
788
-          itemStyle: {
789
-            color: '#3b82f6'
790
-          }
799
+          itemStyle: { color: '#3b82f6' },
800
+          label: { show: true, position: 'top', fontSize: 10, color: '#3b82f6' }
791
         },
801
         },
792
         {
802
         {
793
           name: '查堵万分率',
803
           name: '查堵万分率',
794
           type: 'line',
804
           type: 'line',
795
           yAxisIndex: 1,
805
           yAxisIndex: 1,
796
           data: timePeriodData.map(d => d.blockRate),
806
           data: timePeriodData.map(d => d.blockRate),
797
-          itemStyle: {
798
-            color: '#ec4899'
799
-          },
800
-          lineStyle: {
801
-            width: 3
802
-          },
807
+          itemStyle: { color: '#ec4899' },
808
+          lineStyle: { width: 3 },
803
           symbol: 'circle',
809
           symbol: 'circle',
804
-          symbolSize: 8
810
+          symbolSize: 8,
811
+          label: { show: true, position: 'top', fontSize: 10, color: '#ec4899' }
805
         }
812
         }
806
       ]
813
       ]
807
     })
814
     })
@@ -878,23 +885,19 @@ const loadData = async () => {
878
           type: 'bar',
885
           type: 'bar',
879
           yAxisIndex: 0,
886
           yAxisIndex: 0,
880
           data: dailyLuggageData.map(d => d.totalLuggageCount),
887
           data: dailyLuggageData.map(d => d.totalLuggageCount),
881
-          itemStyle: {
882
-            color: '#3b82f6'
883
-          }
888
+          itemStyle: { color: '#3b82f6' },
889
+          label: { show: true, position: 'top', fontSize: 10, color: '#3b82f6' }
884
         },
890
         },
885
         {
891
         {
886
           name: '查堵万分率',
892
           name: '查堵万分率',
887
           type: 'line',
893
           type: 'line',
888
           yAxisIndex: 1,
894
           yAxisIndex: 1,
889
           data: dailyLuggageData.map(d => d.blockRate),
895
           data: dailyLuggageData.map(d => d.blockRate),
890
-          itemStyle: {
891
-            color: '#ec4899'
892
-          },
893
-          lineStyle: {
894
-            width: 3
895
-          },
896
+          itemStyle: { color: '#ec4899' },
897
+          lineStyle: { width: 3 },
896
           symbol: 'circle',
898
           symbol: 'circle',
897
-          symbolSize: 8
899
+          symbolSize: 8,
900
+          label: { show: true, position: 'top', fontSize: 10, color: '#ec4899' }
898
         }
901
         }
899
       ]
902
       ]
900
     })
903
     })
@@ -935,14 +938,11 @@ const loadData = async () => {
935
           name: 'AI复查图像数',
938
           name: 'AI复查图像数',
936
           type: 'line',
939
           type: 'line',
937
           data: aiImageData.map(d => d.totalBlockedCount),
940
           data: aiImageData.map(d => d.totalBlockedCount),
938
-          itemStyle: {
939
-            color: '#14b8a6'
940
-          },
941
-          lineStyle: {
942
-            width: 3
943
-          },
941
+          itemStyle: { color: '#14b8a6' },
942
+          lineStyle: { width: 3 },
944
           symbol: 'circle',
943
           symbol: 'circle',
945
           symbolSize: 8,
944
           symbolSize: 8,
945
+          label: { show: true, position: 'top', fontSize: 10, color: '#14b8a6' },
946
           areaStyle: {
946
           areaStyle: {
947
             color: {
947
             color: {
948
               type: 'linear',
948
               type: 'linear',
@@ -1002,14 +1002,11 @@ const loadData = async () => {
1002
           name: 'AI漏判图像数',
1002
           name: 'AI漏判图像数',
1003
           type: 'line',
1003
           type: 'line',
1004
           data: aiMissData.map(d => d.totalBlockedCount),
1004
           data: aiMissData.map(d => d.totalBlockedCount),
1005
-          itemStyle: {
1006
-            color: '#ef4444'
1007
-          },
1008
-          lineStyle: {
1009
-            width: 3
1010
-          },
1005
+          itemStyle: { color: '#ef4444' },
1006
+          lineStyle: { width: 3 },
1011
           symbol: 'circle',
1007
           symbol: 'circle',
1012
           symbolSize: 8,
1008
           symbolSize: 8,
1009
+          label: { show: true, position: 'top', fontSize: 10, color: '#ef4444' },
1013
           areaStyle: {
1010
           areaStyle: {
1014
             color: {
1011
             color: {
1015
               type: 'linear',
1012
               type: 'linear',
@@ -1059,15 +1056,13 @@ const loadData = async () => {
1059
         {
1056
         {
1060
           name: 'AI误判图像数',
1057
           name: 'AI误判图像数',
1061
           type: 'line',
1058
           type: 'line',
1059
+
1062
           data: aiErrorData.map(d => d.totalBlockedCount),
1060
           data: aiErrorData.map(d => d.totalBlockedCount),
1063
-          itemStyle: {
1064
-            color: '#f97316'
1065
-          },
1066
-          lineStyle: {
1067
-            width: 3
1068
-          },
1061
+          itemStyle: { color: '#f97316' },
1062
+          lineStyle: { width: 3 },
1069
           symbol: 'circle',
1063
           symbol: 'circle',
1070
           symbolSize: 8,
1064
           symbolSize: 8,
1065
+          label: { show: true, position: 'top', fontSize: 10, color: '#f97316' },
1071
           areaStyle: {
1066
           areaStyle: {
1072
             color: {
1067
             color: {
1073
               type: 'linear',
1068
               type: 'linear',
@@ -1094,6 +1089,10 @@ const loadData = async () => {
1094
 
1089
 
1095
 // 折线图配置(总表)
1090
 // 折线图配置(总表)
1096
 const lineChartOption = (data, color, title, xAxisData = []) => ({
1091
 const lineChartOption = (data, color, title, xAxisData = []) => ({
1092
+  tooltip: {
1093
+    trigger: 'axis',
1094
+    axisPointer: { type: 'line' }
1095
+  },
1097
   grid: {
1096
   grid: {
1098
     left: '10%',
1097
     left: '10%',
1099
     top: '15%',
1098
     top: '15%',
@@ -1121,12 +1120,22 @@ const lineChartOption = (data, color, title, xAxisData = []) => ({
1121
     symbolSize: 6,
1120
     symbolSize: 6,
1122
     data: data,
1121
     data: data,
1123
     itemStyle: { color: color },
1122
     itemStyle: { color: color },
1124
-    lineStyle: { color: color }
1123
+    lineStyle: { color: color },
1124
+    label: {
1125
+      show: true,
1126
+      position: 'top',
1127
+      fontSize: 10,
1128
+      color: color
1129
+    }
1125
   }]
1130
   }]
1126
 })
1131
 })
1127
 
1132
 
1128
 // 多折线图配置(大队对比)
1133
 // 多折线图配置(大队对比)
1129
 const multiLineChartOption = (dataList, colors, legends, xAxisData = []) => ({
1134
 const multiLineChartOption = (dataList, colors, legends, xAxisData = []) => ({
1135
+  tooltip: {
1136
+    trigger: 'axis',
1137
+    axisPointer: { type: 'line' }
1138
+  },
1130
   grid: {
1139
   grid: {
1131
     left: '10%',
1140
     left: '10%',
1132
     top: '15%',
1141
     top: '15%',
@@ -1159,7 +1168,13 @@ const multiLineChartOption = (dataList, colors, legends, xAxisData = []) => ({
1159
     symbolSize: 6,
1168
     symbolSize: 6,
1160
     data: data,
1169
     data: data,
1161
     itemStyle: { color: colors[index] },
1170
     itemStyle: { color: colors[index] },
1162
-    lineStyle: { color: colors[index] }
1171
+    lineStyle: { color: colors[index] },
1172
+    label: {
1173
+      show: true,
1174
+      position: 'top',
1175
+      fontSize: 10,
1176
+      color: colors[index]
1177
+    }
1163
   }))
1178
   }))
1164
 })
1179
 })
1165
 
1180
 

+ 5 - 5
src/views/blockingData/blockingDataScreen/components/ModuleThree.vue

@@ -67,7 +67,7 @@ const loadData = async () => {
67
 
67
 
68
     // 查堵-人员自测漏检次数(总累积)
68
     // 查堵-人员自测漏检次数(总累积)
69
     const selfTestData = selfTestRes?.value?.data || []
69
     const selfTestData = selfTestRes?.value?.data || []
70
-    
70
+
71
     if (selfTestData.length > 0) {
71
     if (selfTestData.length > 0) {
72
       setOption1(ringPieOption(
72
       setOption1(ringPieOption(
73
         selfTestData.map(item => ({
73
         selfTestData.map(item => ({
@@ -114,8 +114,8 @@ const ringPieOption = (data, colors, centerOffset = ['50%', '55%']) => ({
114
     data: data,
114
     data: data,
115
     label: {
115
     label: {
116
       show: true,
116
       show: true,
117
-      formatter: '{b}\n{c}%',
118
-      fontSize: 11
117
+      formatter: '{b}\n{c} ({d}%)',
118
+      fontSize: 10
119
     },
119
     },
120
     labelLine: {
120
     labelLine: {
121
       show: true,
121
       show: true,
@@ -135,7 +135,7 @@ onMounted(() => {
135
   height: 100%;
135
   height: 100%;
136
   display: flex;
136
   display: flex;
137
   gap: 10px;
137
   gap: 10px;
138
-  
138
+
139
 }
139
 }
140
 
140
 
141
 .chart-card {
141
 .chart-card {
@@ -152,7 +152,7 @@ onMounted(() => {
152
 }
152
 }
153
 
153
 
154
 .chart-title {
154
 .chart-title {
155
- font-size: 17px;
155
+  font-size: 17px;
156
   color: black;
156
   color: black;
157
   margin-bottom: 5px;
157
   margin-bottom: 5px;
158
   text-align: left;
158
   text-align: left;

+ 8 - 18
src/views/blockingData/blockingDataScreen/components/ModuleTwo.vue

@@ -225,7 +225,8 @@ const loadData = async () => {
225
         itemStyle: {
225
         itemStyle: {
226
           color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6'][tenureLevels.indexOf(level) % 5]
226
           color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6'][tenureLevels.indexOf(level) % 5]
227
         },
227
         },
228
-        barWidth: 15
228
+        barWidth: 15,
229
+        label: { show: true, position: 'top', fontSize: 9 }
229
       }))
230
       }))
230
 
231
 
231
       setOption6({
232
       setOption6({
@@ -263,7 +264,8 @@ const loadData = async () => {
263
           itemStyle: {
264
           itemStyle: {
264
             color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6'][index % 6]
265
             color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6'][index % 6]
265
           },
266
           },
266
-          barWidth: 20
267
+          barWidth: 20,
268
+          label: { show: true, position: 'top', fontSize: 9 }
267
         }
269
         }
268
       })
270
       })
269
 
271
 
@@ -321,7 +323,7 @@ const pieOption = (data, colors, isRing = false) => ({
321
     data: data,
323
     data: data,
322
     label: {
324
     label: {
323
       show: true,
325
       show: true,
324
-      formatter: '{b}\n{c}%',
326
+      formatter: '{b}\n{c} ({d}%)',
325
       fontSize: 10
327
       fontSize: 10
326
     }
328
     }
327
   }]
329
   }]
@@ -337,24 +339,12 @@ const barOption = (data, colors) => ({
337
     itemStyle: {
339
     itemStyle: {
338
       color: (params) => colors[params.dataIndex % colors.length]
340
       color: (params) => colors[params.dataIndex % colors.length]
339
     },
341
     },
340
-    barWidth: 15
342
+    barWidth: 15,
343
+    label: { show: true, position: 'right', fontSize: 10 }
341
   }]
344
   }]
342
 })
345
 })
343
 
346
 
344
-const stackBarOption = (data, colors) => ({
345
-  grid: { left: '15%', top: '10%', right: '5%', bottom: '15%', containLabel: true },
346
-  xAxis: { type: 'category', data: ['安检二大队', '安检三大队', '安检一大队'], axisLabel: { fontSize: 9 } },
347
-  yAxis: { type: 'value', axisLabel: { fontSize: 9 } },
348
-  legend: { top: 0, right: 10, textStyle: { fontSize: 9 } },
349
-  series: data.map((d, i) => ({
350
-    name: d.name,
351
-    type: 'bar',
352
-    stack: 'total',
353
-    data: d.data,
354
-    itemStyle: { color: colors[i] },
355
-    barWidth: 25
356
-  }))
357
-})
347
+
358
 
348
 
359
 onMounted(() => {
349
 onMounted(() => {
360
   loadData()
350
   loadData()

+ 33 - 10
src/views/blockingData/blockingDataScreen/components/RankList.vue

@@ -6,12 +6,12 @@
6
       <span class="header-count">{{ headerCount }}</span>
6
       <span class="header-count">{{ headerCount }}</span>
7
     </div>
7
     </div>
8
     <div class="rank-list-body">
8
     <div class="rank-list-body">
9
-      <div v-for="(item, index) in rankData" :key="index" class="rank-item" :class="getItemClass(index)">
10
-        <span class="rank-number" :class="'rank-number-' + getRankClass(index)">NO.{{ index + 1 }}</span>
9
+      <div v-for="(item, index) in rankedData" :key="index" class="rank-item" :class="getItemClass(item.rank, index)">
10
+        <span class="rank-number" :class="'rank-number-' + getRankClass(item.rank)">NO.{{ item.rank }}</span>
11
         <div class="rank-info">
11
         <div class="rank-info">
12
           <span class="rank-name">{{ item.name }}</span>
12
           <span class="rank-name">{{ item.name }}</span>
13
           <div class="rank-bar">
13
           <div class="rank-bar">
14
-            <div class="rank-bar-fill" :class="'rank-bar-fill-' + getRankClass(index)" :style="{ width: getProgressWidth(item.value, maxValue) + '%' }"></div>
14
+            <div class="rank-bar-fill" :class="'rank-bar-fill-' + getRankClass(item.rank)" :style="{ width: getProgressWidth(item.value, maxValue) + '%' }"></div>
15
           </div>
15
           </div>
16
         </div>
16
         </div>
17
         <span class="rank-count">{{ item.value }}</span>
17
         <span class="rank-count">{{ item.value }}</span>
@@ -51,10 +51,33 @@ const maxValue = computed(() => {
51
   return Math.max(...props.rankData.map(item => item.value))
51
   return Math.max(...props.rankData.map(item => item.value))
52
 })
52
 })
53
 
53
 
54
-const getRankClass = (index) => {
55
-  if (index === 0) return 'first'
56
-  if (index === 1) return 'second'
57
-  if (index === 2) return 'third'
54
+// 计算并列排名(中国式排名:并列后下一个排名+1)
55
+const rankedData = computed(() => {
56
+  if (props.rankData.length === 0) return []
57
+  
58
+  // 按value降序排序
59
+  const sorted = [...props.rankData].sort((a, b) => b.value - a.value)
60
+  
61
+  let currentRank = 1
62
+  let previousValue = null
63
+  
64
+  return sorted.map((item) => {
65
+    // 如果当前value小于前一个value,排名+1
66
+    if (previousValue !== null && item.value < previousValue) {
67
+      currentRank++
68
+    }
69
+    previousValue = item.value
70
+    return {
71
+      ...item,
72
+      rank: currentRank
73
+    }
74
+  })
75
+})
76
+
77
+const getRankClass = (rank) => {
78
+  if (rank === 1) return 'first'
79
+  if (rank === 2) return 'second'
80
+  if (rank === 3) return 'third'
58
   return 'default'
81
   return 'default'
59
 }
82
 }
60
 
83
 
@@ -62,9 +85,9 @@ const getProgressWidth = (value, max) => {
62
   return (value / max) * 100
85
   return (value / max) * 100
63
 }
86
 }
64
 
87
 
65
-const getItemClass = (index) => {
66
-  const baseClass = 'rank-item rank-item-' + getRankClass(index)
67
-  if (index < 3) return baseClass
88
+const getItemClass = (rank, index) => {
89
+  const baseClass = 'rank-item rank-item-' + getRankClass(rank)
90
+  if (rank <= 3) return baseClass
68
   const isGray = (index - 3) % 2 === 0
91
   const isGray = (index - 3) % 2 === 0
69
   return baseClass + (isGray ? ' rank-item-gray' : '')
92
   return baseClass + (isGray ? ' rank-item-gray' : '')
70
 }
93
 }