Browse Source

feat(home-new): 新增绩效分析和质控分析组件及接口

添加绩效分析(PerformanceAnalysis)和质控分析(QualityControlAnalysis)组件,实现以下功能:
1. 绩效分析展示总分、查获效率等指标
2. 质控分析包含查获数据TOP3、问题分布和培训正确率
3. 新增5个API接口获取相关数据
4. 在首页根据角色权限动态加载组件
huoyi 1 month ago
parent
commit
5fac64562f

+ 43 - 0
src/api/home-new/home-new.js

@@ -88,3 +88,46 @@ export function getHomeReportWhole(params) {
88 88
     params: params
89 89
   })
90 90
 }
91
+
92
+//绩效指标列表
93
+export function getMetrics(data) {
94
+  return request({
95
+    url: '/item/performance/metrics',
96
+    method: 'post',
97
+    data: data
98
+  })
99
+}
100
+
101
+//质控活动-问题分布统计
102
+export function getCheckProblemDistribution(query) {
103
+  return request({
104
+    url: '/system/analysisReport/checkProblemDistribution',
105
+    method: 'get',
106
+    params: query
107
+  })
108
+}
109
+
110
+//培训测试正确率分析
111
+export function getAccuracyAnalysis(query) {
112
+  return request({
113
+    url: '/exam/quiz/accuracy-analysis',
114
+    method: 'get',
115
+    params: query
116
+  })
117
+}
118
+//查询全站查获违禁品 TOP3
119
+export function getProhibitedTop3(query) {
120
+  return request({
121
+    url: '/item/performance/prohibited-top3',
122
+    method: 'get',
123
+    params: query
124
+  })
125
+}
126
+//查询隐匿重点部位 Top1
127
+export function getConcealmentPositionTop1(query) {
128
+  return request({
129
+    url: '/item/performance/concealment-position-top1',
130
+    method: 'get',
131
+    params: query
132
+  })
133
+}

+ 158 - 0
src/pages/home-new/components/performanceAnalysis.vue

@@ -0,0 +1,158 @@
1
+<template>
2
+    <div class="performance-analysis-container">
3
+        <div class="section-title">绩效分析</div>
4
+
5
+        <div class="cards-container">
6
+            <div v-for="(item, index) in performanceData" :key="index" class="card-item">
7
+                <div class="card-header">
8
+                    <div class="card-title">{{ item.name }}数据明细</div>
9
+                    <image :src="getTrophyIcon(item.rank)" class="trophy-icon"></image>
10
+                </div>
11
+                <div class="card-content">
12
+                    <div class="data-item">
13
+                        <div class="data-value">{{ item.totalScore || '0.0' }}</div>
14
+                        <div class="data-label">总分</div>
15
+                    </div>
16
+                    <div class="divider"></div>
17
+                    <div class="data-item">
18
+                        <div class="data-value">{{ item.seizureEfficiency || '0.0' }}</div>
19
+                        <div class="data-label">查获效率</div>
20
+                    </div>
21
+                    <div class="data-item">
22
+                        <div class="data-value">{{ item.inspectionPassRate || '0.0' }}</div>
23
+                        <div class="data-label">巡检合格率</div>
24
+                    </div>
25
+                    <div class="data-item">
26
+                        <div class="data-value">{{ item.trainingScore || '0.0' }}</div>
27
+                        <div class="data-label">培训得分</div>
28
+                    </div>
29
+                </div>
30
+            </div>
31
+        </div>
32
+    </div>
33
+</template>
34
+
35
+<script>
36
+export default {
37
+    name: 'PerformanceAnalysis',
38
+    data() {
39
+        return {
40
+            trophyImages: {
41
+                one: '/static/images/icon/one.png',
42
+                two: '/static/images/icon/two.png',
43
+                three: '/static/images/icon/three.png'
44
+            }
45
+        }
46
+    },
47
+    props: {
48
+        performanceData: {
49
+            type: Array,
50
+            default: () => []
51
+        }
52
+    },
53
+    watch: {
54
+        // performanceData: {
55
+        //     handler(newVal) {
56
+        //         console.log('绩效数据已更新:', newVal);
57
+                
58
+        //     },
59
+        //     immediate: true,
60
+        //     deep: true
61
+        // }
62
+    },
63
+    methods: {
64
+        getTrophyIcon(rank) {
65
+            switch(rank) {
66
+                case 1:
67
+                    return this.trophyImages.one;
68
+                case 2:
69
+                    return this.trophyImages.two;
70
+                case 3:
71
+                    return this.trophyImages.three;
72
+                default:
73
+                    return ''; // 没有奖杯图标
74
+            }
75
+        }
76
+    }
77
+}
78
+</script>
79
+
80
+<style lang="scss" scoped>
81
+.performance-analysis-container {
82
+    background: #FFFFFF;
83
+    border-radius: 20rpx;
84
+    padding: 30rpx;
85
+    margin-bottom: 70rpx;
86
+    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
87
+}
88
+
89
+.section-title {
90
+    font-size: 32rpx;
91
+    font-weight: bold;
92
+    color: #333333;
93
+    margin-bottom: 30rpx;
94
+}
95
+
96
+.cards-container {
97
+    display: flex;
98
+    flex-direction: column;
99
+    gap: 30rpx;
100
+}
101
+
102
+.card-item {
103
+    background: #EFF2FE;
104
+    border-radius: 30rpx;
105
+    padding: 20rpx;
106
+}
107
+
108
+
109
+
110
+.card-header {
111
+    display: flex;
112
+    justify-content: space-between;
113
+    align-items: center;
114
+    margin-bottom: 30rpx;
115
+}
116
+
117
+.card-title {
118
+    font-size: 30rpx;
119
+    font-weight: bold;
120
+    color: #333333;
121
+}
122
+
123
+.trophy-icon {
124
+    width: 45rpx;
125
+    height: 45rpx;
126
+}
127
+
128
+.card-content {
129
+    display: flex;
130
+    align-items: center;
131
+    gap: 30rpx;
132
+}
133
+
134
+.data-item {
135
+    flex: 1;
136
+    display: flex;
137
+    flex-direction: column;
138
+    align-items: center;
139
+}
140
+
141
+.data-value {
142
+    font-size: 36rpx;
143
+    font-weight: bold;
144
+    color: #333333;
145
+    margin-bottom: 8rpx;
146
+}
147
+
148
+.data-label {
149
+    font-size: 24rpx;
150
+    color: #666666;
151
+}
152
+
153
+.divider {
154
+    width: 2rpx;
155
+    height: 80rpx;
156
+    background: #CCD3EF;
157
+}
158
+</style>

+ 281 - 0
src/pages/home-new/components/qualityControlAnalysis.vue

@@ -0,0 +1,281 @@
1
+<template>
2
+    <div class="quality-control-container">
3
+        <div class="section-title">质控分析</div>
4
+
5
+        <div class="data-block">
6
+            <div class="block-title-row">
7
+                <div class="block-title">查获数据TOP3</div>
8
+            </div>
9
+            <div class="data-grid" v-if="prohibitedTop3 && prohibitedTop3.length > 0">
10
+                <div v-for="(item, index) in prohibitedTop3" :key="index" class="data-item">
11
+                    <div class="item-label">{{ item.categoryName }}总数</div>
12
+                    <div class="item-value">{{ item.quantity }}</div>
13
+                    <div class="item-ratio">占比<span class="ratio-highlight">{{ item.percentage }}%</span></div>
14
+                </div>
15
+            </div>
16
+            <div v-else class="no-data-text">暂无查获数据</div>
17
+            <div class="note-text" v-if="prohibitedTop3Desc">注:{{ prohibitedTop3Desc }}</div>
18
+        </div>
19
+
20
+        <div class="data-block">
21
+            <div class="block-title-row">
22
+                <div class="block-title">质控发现问题</div>
23
+                <div class="total-count">总数:<span class="count-highlight">{{ checkProblemDistributionTotal }}</span>
24
+                </div>
25
+            </div>
26
+            <div class="data-grid" v-if="checkProblemDistribution && checkProblemDistribution.length > 0">
27
+                <div v-for="(item, index) in checkProblemDistribution" :key="index" class="data-item">
28
+                    <div class="item-label">{{ item.name }}类总数</div>
29
+                    <div class="item-value">{{ item.total }}</div>
30
+                    <div class="item-ratio">占比<span class="ratio-highlight">{{ item.percentage }}%</span></div>
31
+                </div>
32
+            </div>
33
+            <div v-else class="no-data-text">暂未发现问题</div>
34
+            <div class="note-text" v-if="checkProblemDistributionDesc">注:{{ checkProblemDistributionDesc }}</div>
35
+        </div>
36
+
37
+        <div class="data-block">
38
+            <div class="block-title-row">
39
+                <div class="block-title">培训测试正确率分析</div>
40
+                <div class="total-count">平均正确率:<span class="count-highlight">{{ avgCorrectRate }}%</span></div>
41
+            </div>
42
+            <div class="data-grid" v-if="accuracyAnalysis && accuracyAnalysis.length > 0">
43
+                <div v-for="(item, index) in accuracyAnalysis" :key="index" class="data-item">
44
+                    <div class="item-label">{{ item.categoryName }}</div>
45
+                    <div class="item-value" :class="getValueClass(item.color)">{{ item.correctRate }}%</div>
46
+                    <div class="item-status" :class="getValueClass(item.color)">{{ item.label }}</div>
47
+                </div>
48
+            </div>
49
+            <div v-else class="no-data-text">暂无培训测试数据</div>
50
+            <div class="note-text" v-if="accuracyAnalysisDesc">注:{{ accuracyAnalysisDesc }}</div>
51
+        </div>
52
+    </div>
53
+</template>
54
+
55
+<script>
56
+
57
+export default {
58
+    name: 'QualityControlAnalysis',
59
+    data() {
60
+        return {
61
+            checkProblemDistribution: [],
62
+            checkProblemDistributionTotal: 0,
63
+            checkProblemDistributionDesc: '',
64
+            avgCorrectRate: 0,
65
+            accuracyAnalysisDesc: '',
66
+            accuracyAnalysis: [],
67
+            prohibitedTop3: [],
68
+            prohibitedTop3Desc: ''
69
+        }
70
+    },
71
+    props: {
72
+        checkProblemDistributionData: {
73
+            type: Object,
74
+            default: () => ({})
75
+        },
76
+        accuracyAnalysisData: {
77
+            type: Object,
78
+            default: () => ({})
79
+        },
80
+        prohibitedTop3Data: {
81
+            type: Array,
82
+            default: () => ([])
83
+        },
84
+        concealmentPositionTop1Data: {
85
+            type: Array,
86
+            default: () => ([])
87
+        },
88
+    },
89
+    watch: {
90
+        // 监听checkProblemDistributionData变化,重新计算数据
91
+        checkProblemDistributionData: {
92
+            handler(newVal) {
93
+                this.calculateCheckProblemDistribution();
94
+            },
95
+            deep: true,
96
+            immediate: true
97
+        },
98
+        accuracyAnalysisData: {
99
+            handler(newVal) {
100
+                this.calculateAccuracyAnalysis();
101
+            },
102
+            deep: true,
103
+            immediate: true
104
+        },
105
+        prohibitedTop3Data: {
106
+            handler(newVal) {
107
+                this.calculateProhibitedTop3();
108
+            },
109
+            deep: true,
110
+            immediate: true
111
+        },
112
+        concealmentPositionTop1Data: {
113
+            handler(newVal) {
114
+                this.calculateProhibitedTop1();
115
+            },
116
+            deep: true,
117
+            immediate: true
118
+        }
119
+    },
120
+    methods: {
121
+        calculateProhibitedTop1() {
122
+            let str = this.concealmentPositionTop1Data.map(item => `${item.checkPositionNameOne}/${item.checkPositionNameTwo}`).join('/');
123
+
124
+            this.prohibitedTop3Desc = str ? `隐匿重点部位以[${str}]为主` : "";
125
+        },
126
+        calculateAccuracyAnalysis() {
127
+            const { avgCorrectRate, note, categoryList } = this.accuracyAnalysisData || [];
128
+            this.avgCorrectRate = avgCorrectRate;
129
+            this.accuracyAnalysisDesc = note;
130
+            this.accuracyAnalysis = categoryList
131
+        },
132
+
133
+        // 计算违禁品TOP3数据
134
+        calculateProhibitedTop3() {
135
+
136
+            this.prohibitedTop3 = this.prohibitedTop3Data || [];
137
+        },
138
+
139
+        // 根据颜色获取值对应的CSS类
140
+        getValueClass(color) {
141
+            if (color === 'green') return 'value-green';
142
+            if (color === 'red') return 'value-red';
143
+            return '';
144
+        },
145
+
146
+
147
+        // 计算检查问题分布数据
148
+        calculateCheckProblemDistribution() {
149
+
150
+            const { checkProblemDistributionItemDtoList, desc } = this.checkProblemDistributionData || [];
151
+            this.checkProblemDistributionDesc = desc;
152
+            // 计算总问题数
153
+            this.checkProblemDistributionTotal = (checkProblemDistributionItemDtoList || []).reduce((sum, item) => sum + (item.total || 0), 0);
154
+
155
+            // 计算每个项目的百分比
156
+            this.checkProblemDistribution = (checkProblemDistributionItemDtoList || []).map(item => ({
157
+                ...item,
158
+                percentage: this.checkProblemDistributionTotal > 0 ?
159
+                    ((item.total / this.checkProblemDistributionTotal) * 100).toFixed(2) : '0.00'
160
+            }));
161
+        }
162
+    }
163
+}
164
+</script>
165
+
166
+<style lang="scss" scoped>
167
+.quality-control-container {
168
+    background: #FFFFFF;
169
+    border-radius: 20rpx;
170
+    padding: 30rpx;
171
+    margin-bottom: 30rpx;
172
+    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
173
+}
174
+
175
+.section-title {
176
+    font-size: 34rpx;
177
+    font-weight: bold;
178
+    color: #333333;
179
+    margin-bottom: 30rpx;
180
+}
181
+
182
+.data-block {
183
+    background: #EFF2FE;
184
+    border-radius: 15rpx;
185
+    padding: 25rpx;
186
+    margin-bottom: 25rpx;
187
+
188
+    &:last-child {
189
+        margin-bottom: 0;
190
+    }
191
+}
192
+
193
+.block-title-row {
194
+    display: flex;
195
+    justify-content: space-between;
196
+    align-items: center;
197
+    margin-bottom: 25rpx;
198
+}
199
+
200
+.block-title {
201
+    font-size: 30rpx;
202
+    font-weight: bold;
203
+    color: #333333;
204
+}
205
+
206
+.total-count {
207
+    font-size: 26rpx;
208
+    color: #666666;
209
+}
210
+
211
+.count-highlight {
212
+    color: #1890FF;
213
+    font-weight: bold;
214
+}
215
+
216
+.data-grid {
217
+    display: grid;
218
+    grid-template-columns: repeat(3, 1fr);
219
+    gap: 20rpx;
220
+    margin-bottom: 20rpx;
221
+}
222
+
223
+.data-item {
224
+    display: flex;
225
+    flex-direction: column;
226
+    align-items: center;
227
+    text-align: center;
228
+}
229
+
230
+.item-label {
231
+    font-size: 24rpx;
232
+    color: #666666;
233
+    margin-bottom: 8rpx;
234
+}
235
+
236
+.item-value {
237
+    font-size: 34rpx;
238
+    font-weight: bold;
239
+    color: #333333;
240
+    margin-bottom: 8rpx;
241
+}
242
+
243
+.value-green {
244
+    color: #00AE41 !important;
245
+}
246
+
247
+.value-red {
248
+    color: #F96060 !important;
249
+}
250
+
251
+.item-ratio {
252
+    font-size: 24rpx;
253
+    color: #666666;
254
+}
255
+
256
+.ratio-highlight {
257
+    color: #F96060;
258
+    font-weight: bold;
259
+}
260
+
261
+.item-status {
262
+    font-size: 24rpx;
263
+    color: #666666;
264
+}
265
+
266
+
267
+
268
+.note-text {
269
+    font-size: 24rpx;
270
+    color: #F96060;
271
+    line-height: 1.6;
272
+}
273
+
274
+.no-data-text {
275
+    font-size: 28rpx;
276
+    color: #999999;
277
+    text-align: center;
278
+    padding: 40rpx 0;
279
+    font-style: italic;
280
+}
281
+</style>

+ 168 - 3
src/pages/home-new/index.vue

@@ -57,6 +57,17 @@
57 57
             <!-- TotalDetail组件 -->
58 58
             <TotalDetail :homePageWholeData="homePageWholeData" :start-date="startDate" :end-date="endDate"
59 59
                 :time-range="selectedTimeRange" :selectedRole="selectedRole" />
60
+
61
+
62
+            <!-- QualityControlAnalysis组件 -->
63
+            <QualityControlAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
64
+                :checkProblemDistributionData="checkProblemDistributionData"
65
+                :accuracyAnalysisData="accuracyAnalysisData" :prohibitedTop3Data="prohibitedTop3Data"
66
+                :concealmentPositionTop1Data="concealmentPositionTop1Data" />
67
+
68
+            <!-- PerformanceAnalysis组件 -->
69
+            <PerformanceAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
70
+                :performanceData="performanceData" />
60 71
         </div>
61 72
     </view>
62 73
 </template>
@@ -64,6 +75,8 @@
64 75
 <script>
65 76
 import HomeContainer from "@/components/HomeContainer.vue";
66 77
 import UserInfo from "@/components/UserInfo.vue";
78
+import QualityControlAnalysis from "@/pages/home-new/components/qualityControlAnalysis.vue";
79
+import PerformanceAnalysis from "@/pages/home-new/components/performanceAnalysis.vue";
67 80
 import HeadTitle from "@/components/HeadTitle.vue";
68 81
 import Notice from "@/pages/home/components/notice.vue";
69 82
 import SelectTag from "@/components/select-tag/select-tag.vue";
@@ -73,7 +86,7 @@ import { getUserProfile, getAppListByRoleId, getAppList } from "@/api/system/use
73 86
 import { getAttendanceList } from "@/api/attendance/attendance"
74 87
 import { getUnreadCount } from "@/api/check/checkTask"
75 88
 import { checkRolePermission } from "@/utils/common.js";
76
-import { getHomePage, getSeizureReport, getAttendanceStats, getAccuracyStatistics, getSeizureRanking, getCheckRanking, getHomePageWhole, selectUserListByRoleKey } from "@/api/home-new/home-new";
89
+import { getHomePage, getSeizureReport, getAttendanceStats, getAccuracyStatistics, getSeizureRanking, getCheckRanking, getHomePageWhole, selectUserListByRoleKey, getMetrics, getCheckProblemDistribution, getAccuracyAnalysis, getProhibitedTop3, getConcealmentPositionTop1 } from "@/api/home-new/home-new";
77 90
 // 导入uni-datetime-picker组件
78 91
 import uniDatetimePicker from "@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
79 92
 
@@ -86,6 +99,8 @@ export default {
86 99
         SelectTag,
87 100
         TypeDetail,
88 101
         TotalDetail,
102
+        QualityControlAnalysis,
103
+        PerformanceAnalysis,
89 104
         uniDatetimePicker
90 105
     },
91 106
     data() {
@@ -140,6 +155,16 @@ export default {
140 155
             accuracyStatistics: {},
141 156
             homePageWholeData: [],
142 157
             subTitleText: '',
158
+            // 绩效分析数据
159
+            performanceData: [],
160
+            // 检查问题分布数据
161
+            checkProblemDistributionData: {},
162
+            // 类型详情数据
163
+            accuracyAnalysisData: {},
164
+            // 违禁品TOP3数据
165
+            prohibitedTop3Data: [],
166
+            // 隐匿重点部位TOP1数据
167
+            concealmentPositionTop1Data: [],
143 168
         }
144 169
     },
145 170
     computed: {
@@ -400,7 +425,12 @@ export default {
400 425
                     this.fetchAccuracyStatistics(), // 抽问抽答数据
401 426
                     this.getRank(),                // 排名数据
402 427
                     this.getHomePageWholeData(),   // 首页整体数据
403
-                    this.getTodayOnDutyKeZhang()   // 今日上岗科长信息
428
+                    this.getTodayOnDutyKeZhang(),   // 今日上岗科长信息
429
+                    this.getPerformanceData(),     // 绩效分析数据
430
+                    this.getCheckProblemDistributionData(), // 检查问题分布数据
431
+                    this.getAccuracyAnalysis(),    // 正确率分析数据
432
+                    this.getProhibitedTop3Data(),  // 违禁品TOP3数据
433
+                    this.getConcealmentPositionTop1Data() // 隐匿重点部位TOP1数据
404 434
                 ]);
405 435
 
406 436
                 // 检查每个接口的请求结果
@@ -412,7 +442,12 @@ export default {
412 442
                         'fetchAccuracyStatistics',
413 443
                         'getRank',
414 444
                         'getHomePageWholeData',
415
-                        'getTodayOnDutyKeZhang'
445
+                        'getTodayOnDutyKeZhang',
446
+                        'getPerformanceData',
447
+                        'getCheckProblemDistribution',
448
+                        'getAccuracyAnalysis',
449
+                        'getProhibitedTop3Data',
450
+                        'getConcealmentPositionTop1Data'
416 451
                     ];
417 452
 
418 453
                     if (result.status === 'rejected') {
@@ -428,7 +463,137 @@ export default {
428 463
                 throw error;
429 464
             }
430 465
         },
466
+        // 获取检查问题分布数据
467
+        async getCheckProblemDistributionData() {
468
+            return new Promise((resolve, reject) => {
469
+                const { startDate, endDate } = this.calculateDateRange(this.selectedTimeRange);
470
+
471
+                const params = {
472
+                    startDate: startDate,
473
+                    endDate: endDate
474
+                };
475
+
476
+                getCheckProblemDistribution(params).then(res => {
477
+                    if (res && res.data) {
478
+                        console.log('检查问题分布数据:', res.data);
479
+                        this.checkProblemDistributionData = res.data;
480
+                        resolve(res.data);
481
+                    } else {
482
+                        this.checkProblemDistributionData = {};
483
+                        resolve(null);
484
+                    }
485
+                }).catch(error => {
486
+                    console.error('获取检查问题分布数据失败:', error);
487
+                    this.checkProblemDistributionData = {};
488
+                    reject(error);
489
+                });
490
+            });
491
+        },
492
+
493
+        // 获取正确率分析数据
494
+        getAccuracyAnalysis() {
495
+            return new Promise((resolve, reject) => {
496
+                const { startDate, endDate } = this.calculateDateRange(this.selectedTimeRange);
497
+
498
+                const params = {
499
+                    startDate: startDate,
500
+                    endDate: endDate
501
+                };
502
+
503
+                getAccuracyAnalysis(params).then(res => {
504
+                    if (res && res.data) {
505
+                        console.log('正确率分析数据:', res.data);
506
+                        this.accuracyAnalysisData = res.data;
507
+                        resolve(res.data);
508
+                    } else {
509
+                        resolve(null);
510
+                    }
511
+                }).catch(error => {
512
+                    console.error('获取正确率分析数据失败:', error);
513
+                    reject(error);
514
+                });
515
+            });
516
+        },
517
+        // 获取绩效分析数据
518
+        getPerformanceData() {
519
+            return new Promise((resolve, reject) => {
520
+                const { startDate, endDate } = this.calculateDateRange(this.selectedTimeRange);
431 521
 
522
+                const params = {
523
+                    startTime: startDate,
524
+                    endTime: endDate,
525
+                    sortField: 'totalScore',
526
+                    dimension: '3'
527
+                };
528
+
529
+                getMetrics(params).then(res => {
530
+
531
+                    if (res && res.data) {
532
+                        this.performanceData = res.data;
533
+                        resolve(res.data);
534
+                    } else {
535
+                        resolve([]);
536
+                    }
537
+                }).catch(error => {
538
+                    console.error('获取绩效数据失败:', error);
539
+                    reject(error);
540
+                });
541
+            });
542
+        },
543
+
544
+        // 获取违禁品TOP3数据
545
+        getProhibitedTop3Data() {
546
+            return new Promise((resolve, reject) => {
547
+                const { startDate, endDate } = this.calculateDateRange(this.selectedTimeRange);
548
+
549
+                const params = {
550
+                    startDate: startDate,
551
+                    endDate: endDate
552
+                };
553
+
554
+                getProhibitedTop3(params).then(res => {
555
+                    if (res && res.data) {
556
+                        console.log('违禁品TOP3数据:', res.data);
557
+                        this.prohibitedTop3Data = res.data;
558
+                        resolve(res.data);
559
+                    } else {
560
+                        this.prohibitedTop3Data = {};
561
+                        resolve(null);
562
+                    }
563
+                }).catch(error => {
564
+                    console.error('获取违禁品TOP3数据失败:', error);
565
+                    this.prohibitedTop3Data = {};
566
+                    reject(error);
567
+                });
568
+            });
569
+        },
570
+
571
+        // 获取隐匿重点部位TOP1数据
572
+        getConcealmentPositionTop1Data() {
573
+            return new Promise((resolve, reject) => {
574
+                const { startDate, endDate } = this.calculateDateRange(this.selectedTimeRange);
575
+
576
+                const params = {
577
+                    startDate: startDate,
578
+                    endDate: endDate
579
+                };
580
+
581
+                getConcealmentPositionTop1(params).then(res => {
582
+                    if (res && res.data) {
583
+                        console.log('隐匿重点部位TOP1数据:', res.data);
584
+                        this.concealmentPositionTop1Data = res.data;
585
+                        resolve(res.data);
586
+                    } else {
587
+                        this.concealmentPositionTop1Data = [];
588
+                        resolve(null);
589
+                    }
590
+                }).catch(error => {
591
+                    console.error('获取隐匿重点部位TOP1数据失败:', error);
592
+                    this.concealmentPositionTop1Data = [];
593
+                    reject(error);
594
+                });
595
+            });
596
+        },
432 597
         getRank() {
433 598
             return new Promise((resolve, reject) => {
434 599
                 let params = {};