Преглед изворни кода

fix抽问抽答准确率排名的bug

simonlll пре 2 месеци
родитељ
комит
80519af056

+ 25 - 0
airport-exam/src/main/java/com/sundot/airport/exam/dto/AccuracyStatisticsDTO.java

@@ -103,11 +103,26 @@ public class AccuracyStatisticsDTO implements Serializable {
103 103
     private RankingInfo teamInDeptRanking;
104 104
 
105 105
     /**
106
+     * 班组在大队中的排名
107
+     */
108
+    private RankingInfo teamInBrigadeRanking;
109
+
110
+    /**
106 111
      * 班组在站级中的排名
107 112
      */
108 113
     private RankingInfo teamInSiteRanking;
109 114
 
110 115
     /**
116
+     * 主管在大队中的排名
117
+     */
118
+    private RankingInfo deptInBrigadeRanking;
119
+
120
+    /**
121
+     * 大队在站级中的排名
122
+     */
123
+    private RankingInfo brigadeInSiteRanking;
124
+
125
+    /**
111 126
      * 主管内Top班组
112 127
      */
113 128
     private java.util.List<RankingItem> topTeamsInDept;
@@ -128,6 +143,16 @@ public class AccuracyStatisticsDTO implements Serializable {
128 143
     private java.util.List<RankingItem> bottomDepts;
129 144
 
130 145
     /**
146
+     * 大队正确率排名列表(站长视角)
147
+     */
148
+    private java.util.List<RankingItem> brigadeRankingList;
149
+
150
+    /**
151
+     * 本大队内Top班组(大队长视角)
152
+     */
153
+    private java.util.List<RankingItem> topTeamsInBrigade;
154
+
155
+    /**
131 156
      * 站级内Top班组
132 157
      */
133 158
     private java.util.List<RankingItem> topTeamsInSite;

+ 517 - 40
airport-exam/src/main/java/com/sundot/airport/exam/service/impl/AccuracyStatisticsServiceImpl.java

@@ -14,7 +14,9 @@ import com.sundot.airport.common.enums.HomePageQueryEnum;
14 14
 import com.sundot.airport.common.exception.ServiceException;
15 15
 import com.sundot.airport.common.enums.DeptType;
16 16
 import com.sundot.airport.common.enums.MedalTypeEnum;
17
+import com.sundot.airport.common.enums.RoleTypeEnum;
17 18
 import com.sundot.airport.common.enums.TimeRangeEnum;
19
+import com.sundot.airport.common.core.domain.entity.SysRole;
18 20
 import com.sundot.airport.common.utils.DateUtils;
19 21
 import com.sundot.airport.common.utils.SecurityUtils;
20 22
 import com.sundot.airport.exam.domain.DailyTask;
@@ -66,14 +68,21 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
66 68
 
67 69
     @Override
68 70
     public AccuracyStatisticsDTO getAccuracyStatistics(AccuracyStatisticsQueryDTO query) {
69
-        // 获取当前用户信息
71
+        // 获取当前用户信息(从登录信息中获取,确保包含角色信息)
70 72
         Long currentUserId = SecurityUtils.getUserId();
71 73
         Long currentDeptId = SecurityUtils.getDeptId();
72
-        SysUser currentUser = userService.selectUserById(currentUserId);
74
+        SysUser currentUser = SecurityUtils.getLoginUser().getUser();
75
+
76
+        // 调试日志
77
+        log.info("getAccuracyStatistics - currentUserId: {}, currentDeptId: {}", currentUserId, currentDeptId);
78
+        log.info("getAccuracyStatistics - currentUser: {}", currentUser != null ? currentUser.getUserName() : "null");
79
+        log.info("getAccuracyStatistics - currentUser.getRoles(): {}", currentUser != null ? currentUser.getRoles() : "null");
73 80
 
74 81
         AccuracyStatisticsDTO result = new AccuracyStatisticsDTO();
75 82
 
76
-        // 设置用户角色
83
+        // 获取用户角色
84
+        String roleKey = getUserRoleKey(currentUser);
85
+        log.info("getAccuracyStatistics - roleKey: {}", roleKey);
77 86
         if (currentUser != null && currentUser.getRoles() != null && !currentUser.getRoles().isEmpty()) {
78 87
             result.setUserRole(currentUser.getRoles().get(0).getRoleName());
79 88
         }
@@ -95,21 +104,445 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
95 104
         // 检查是否有待完成任务
96 105
         checkPendingTask(result, currentUserId);
97 106
 
98
-        // 计算个人正确率
99
-        calculatePersonalAccuracy(result, currentUserId, startDate, endDate);
107
+        // 根据角色返回不同的数据
108
+        if (RoleTypeEnum.SecurityCheck.getCode().equals(roleKey)) {
109
+            // 安检员
110
+            calculateSecurityCheckData(result, currentUserId, hierarchy, startDate, endDate);
111
+        } else if (RoleTypeEnum.banzuzhang.getCode().equals(roleKey)) {
112
+            // 班组长
113
+            calculateTeamLeaderData(result, currentUserId, hierarchy, startDate, endDate);
114
+        } else if (RoleTypeEnum.kezhang.getCode().equals(roleKey)) {
115
+            // 主管
116
+            calculateManagerData(result, currentUserId, hierarchy, startDate, endDate);
117
+        } else if (RoleTypeEnum.jingli.getCode().equals(roleKey) || RoleTypeEnum.xingzheng.getCode().equals(roleKey)) {
118
+            // 大队长(经理/行政)
119
+            calculateBrigadeLeaderData(result, hierarchy, startDate, endDate);
120
+        } else if (RoleTypeEnum.test.getCode().equals(roleKey)) {
121
+            // 站长
122
+            calculateStationLeaderData(result, hierarchy, startDate, endDate);
123
+        } else {
124
+            // 其他角色:返回基本数据
125
+            calculatePersonalAccuracy(result, currentUserId, startDate, endDate);
126
+            calculateLevelAvgAccuracy(result, hierarchy, startDate, endDate);
127
+        }
128
+
129
+        return result;
130
+    }
131
+
132
+    /**
133
+     * 获取用户的角色Key
134
+     */
135
+    private String getUserRoleKey(SysUser user) {
136
+        if (user == null || user.getRoles() == null || user.getRoles().isEmpty()) {
137
+            return null;
138
+        }
139
+        // 按优先级返回角色:站长 > 大队长 > 主管 > 班组长 > 安检员
140
+        List<String> roleKeys = user.getRoles().stream().map(SysRole::getRoleKey).collect(Collectors.toList());
141
+        if (roleKeys.contains(RoleTypeEnum.test.getCode())) {
142
+            return RoleTypeEnum.test.getCode();
143
+        }
144
+        if (roleKeys.contains(RoleTypeEnum.jingli.getCode())) {
145
+            return RoleTypeEnum.jingli.getCode();
146
+        }
147
+        if (roleKeys.contains(RoleTypeEnum.xingzheng.getCode())) {
148
+            return RoleTypeEnum.xingzheng.getCode();
149
+        }
150
+        if (roleKeys.contains(RoleTypeEnum.kezhang.getCode())) {
151
+            return RoleTypeEnum.kezhang.getCode();
152
+        }
153
+        if (roleKeys.contains(RoleTypeEnum.banzuzhang.getCode())) {
154
+            return RoleTypeEnum.banzuzhang.getCode();
155
+        }
156
+        if (roleKeys.contains(RoleTypeEnum.SecurityCheck.getCode())) {
157
+            return RoleTypeEnum.SecurityCheck.getCode();
158
+        }
159
+        return user.getRoles().get(0).getRoleKey();
160
+    }
161
+
162
+    /**
163
+     * 安检员数据计算
164
+     * 正确率:本人、班平均、主管平均、大队平均、站平均
165
+     * 排名:班组排名、主管排名、大队排名、全站排名(个人排名)
166
+     */
167
+    private void calculateSecurityCheckData(AccuracyStatisticsDTO result, Long userId, DeptHierarchy hierarchy, Date startDate, Date endDate) {
168
+        // 个人正确率
169
+        calculatePersonalAccuracy(result, userId, startDate, endDate);
170
+
171
+        // 班平均、主管平均、大队平均、站平均
172
+        if (hierarchy.teamId != null) {
173
+            result.setTeamAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.teamId, startDate, endDate));
174
+        }
175
+        if (hierarchy.managerId != null) {
176
+            result.setDeptAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.managerId, startDate, endDate));
177
+        }
178
+        if (hierarchy.brigadeId != null) {
179
+            result.setBrigadeAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.brigadeId, startDate, endDate));
180
+        }
181
+        if (hierarchy.stationId != null) {
182
+            result.setSiteAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.stationId, startDate, endDate));
183
+        }
184
+
185
+        // 个人在各层级的排名
186
+        calculatePersonalRankings(result, userId, hierarchy, startDate, endDate);
187
+    }
188
+
189
+    /**
190
+     * 班组长数据计算
191
+     * 正确率:班平均、主管平均、大队平均、站平均
192
+     * 排名:主管排名、大队排名、全站排名(班组排名)
193
+     */
194
+    private void calculateTeamLeaderData(AccuracyStatisticsDTO result, Long userId, DeptHierarchy hierarchy, Date startDate, Date endDate) {
195
+        // 班平均、主管平均、大队平均、站平均
196
+        if (hierarchy.teamId != null) {
197
+            result.setTeamAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.teamId, startDate, endDate));
198
+        }
199
+        if (hierarchy.managerId != null) {
200
+            result.setDeptAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.managerId, startDate, endDate));
201
+        }
202
+        if (hierarchy.brigadeId != null) {
203
+            result.setBrigadeAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.brigadeId, startDate, endDate));
204
+        }
205
+        if (hierarchy.stationId != null) {
206
+            result.setSiteAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.stationId, startDate, endDate));
207
+        }
208
+
209
+        // 班组在主管中的排名
210
+        if (hierarchy.teamId != null && hierarchy.managerId != null) {
211
+            List<TeamAccuracyInfo> teamsInManager = calculateTeamAccuraciesUnderDept(hierarchy.managerId, startDate, endDate);
212
+            if (!teamsInManager.isEmpty()) {
213
+                result.setTeamInDeptRanking(findTeamRanking(hierarchy.teamId, teamsInManager));
214
+            }
215
+        }
216
+
217
+        // 班组在大队中的排名
218
+        if (hierarchy.teamId != null && hierarchy.brigadeId != null) {
219
+            List<TeamAccuracyInfo> teamsInBrigade = calculateTeamAccuraciesUnderDept(hierarchy.brigadeId, startDate, endDate);
220
+            if (!teamsInBrigade.isEmpty()) {
221
+                result.setTeamInBrigadeRanking(findTeamRanking(hierarchy.teamId, teamsInBrigade));
222
+            }
223
+        }
224
+
225
+        // 班组在全站中的排名
226
+        if (hierarchy.teamId != null && hierarchy.stationId != null) {
227
+            List<TeamAccuracyInfo> teamsInStation = calculateTeamAccuraciesUnderDept(hierarchy.stationId, startDate, endDate);
228
+            if (!teamsInStation.isEmpty()) {
229
+                result.setTeamInSiteRanking(findTeamRanking(hierarchy.teamId, teamsInStation));
230
+            }
231
+        }
232
+    }
233
+
234
+    /**
235
+     * 主管数据计算
236
+     * 正确率:主管平均、大队平均、站平均
237
+     * 排名:大队排名、全站排名(主管排名)
238
+     */
239
+    private void calculateManagerData(AccuracyStatisticsDTO result, Long userId, DeptHierarchy hierarchy, Date startDate, Date endDate) {
240
+        // 主管平均、大队平均、站平均
241
+        if (hierarchy.managerId != null) {
242
+            result.setDeptAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.managerId, startDate, endDate));
243
+        }
244
+        if (hierarchy.brigadeId != null) {
245
+            result.setBrigadeAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.brigadeId, startDate, endDate));
246
+        }
247
+        if (hierarchy.stationId != null) {
248
+            result.setSiteAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.stationId, startDate, endDate));
249
+        }
250
+
251
+        // 主管在大队中的排名
252
+        if (hierarchy.managerId != null && hierarchy.brigadeId != null) {
253
+            List<TeamAccuracyInfo> managersInBrigade = calculateManagerAccuraciesUnderBrigade(hierarchy.brigadeId, startDate, endDate);
254
+            if (!managersInBrigade.isEmpty()) {
255
+                result.setDeptInBrigadeRanking(findTeamRanking(hierarchy.managerId, managersInBrigade));
256
+            }
257
+        }
258
+
259
+        // 主管在全站中的排名
260
+        if (hierarchy.managerId != null && hierarchy.stationId != null) {
261
+            List<TeamAccuracyInfo> managersInStation = calculateManagerAccuraciesUnderStation(hierarchy.stationId, startDate, endDate);
262
+            if (!managersInStation.isEmpty()) {
263
+                result.setDeptInSiteRanking(findTeamRanking(hierarchy.managerId, managersInStation));
264
+            }
265
+        }
266
+    }
267
+
268
+    /**
269
+     * 大队长数据计算
270
+     * 正确率:大队平均、站平均
271
+     * 本大队抽问抽答正确率前三的班组
272
+     * 全站排名:大队排名/全站大队数总和
273
+     */
274
+    private void calculateBrigadeLeaderData(AccuracyStatisticsDTO result, DeptHierarchy hierarchy, Date startDate, Date endDate) {
275
+        // 大队平均、站平均
276
+        if (hierarchy.brigadeId != null) {
277
+            result.setBrigadeAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.brigadeId, startDate, endDate));
278
+        }
279
+        if (hierarchy.stationId != null) {
280
+            result.setSiteAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.stationId, startDate, endDate));
281
+        }
282
+
283
+        // 本大队抽问抽答正确率前三的班组
284
+        if (hierarchy.brigadeId != null) {
285
+            List<TeamAccuracyInfo> teamsInBrigade = calculateTeamAccuraciesUnderDept(hierarchy.brigadeId, startDate, endDate);
286
+            if (!teamsInBrigade.isEmpty()) {
287
+                List<AccuracyStatisticsDTO.RankingItem> topTeams = convertToTeamRankingItems(teamsInBrigade, 3, true, hierarchy.brigadeId);
288
+                result.setTopTeamsInBrigade(topTeams);
289
+            }
290
+        }
291
+
292
+        // 大队在全站中的排名
293
+        if (hierarchy.brigadeId != null && hierarchy.stationId != null) {
294
+            List<TeamAccuracyInfo> brigadesInStation = calculateBrigadeAccuraciesUnderStation(hierarchy.stationId, startDate, endDate);
295
+            if (!brigadesInStation.isEmpty()) {
296
+                result.setBrigadeInSiteRanking(findTeamRanking(hierarchy.brigadeId, brigadesInStation));
297
+            }
298
+        }
299
+    }
300
+
301
+    /**
302
+     * 站长数据计算
303
+     * 全站抽问抽答正确率
304
+     * 一二三大队排名(大队正确率排名)
305
+     * 主管正确率排名:正序前三名和倒序后三名
306
+     * 班组正确率排名:正序前三名和倒序后三名
307
+     */
308
+    private void calculateStationLeaderData(AccuracyStatisticsDTO result, DeptHierarchy hierarchy, Date startDate, Date endDate) {
309
+        // 全站平均正确率
310
+        if (hierarchy.stationId != null) {
311
+            result.setSiteAvgAccuracy(calculateDeptAvgAccuracy(hierarchy.stationId, startDate, endDate));
312
+        }
313
+
314
+        // 大队正确率排名列表
315
+        if (hierarchy.stationId != null) {
316
+            List<TeamAccuracyInfo> brigadesInStation = calculateBrigadeAccuraciesUnderStation(hierarchy.stationId, startDate, endDate);
317
+            if (!brigadesInStation.isEmpty()) {
318
+                List<AccuracyStatisticsDTO.RankingItem> brigadeRankingList = new ArrayList<>();
319
+                for (int i = 0; i < brigadesInStation.size(); i++) {
320
+                    TeamAccuracyInfo info = brigadesInStation.get(i);
321
+                    AccuracyStatisticsDTO.RankingItem item = new AccuracyStatisticsDTO.RankingItem();
322
+                    item.setId(info.deptId);
323
+                    item.setName(info.deptName);
324
+                    item.setAccuracy(info.accuracy);
325
+                    item.setRank(i + 1);
326
+                    brigadeRankingList.add(item);
327
+                }
328
+                result.setBrigadeRankingList(brigadeRankingList);
329
+            }
330
+
331
+            // 主管正确率排名:正序前三名和倒序后三名
332
+            List<TeamAccuracyInfo> managersInStation = calculateManagerAccuraciesUnderStation(hierarchy.stationId, startDate, endDate);
333
+            if (!managersInStation.isEmpty()) {
334
+                result.setTopDepts(convertToManagerRankingItems(managersInStation, 3, true));
335
+                result.setBottomDepts(convertToManagerRankingItems(managersInStation, 3, false));
336
+            }
337
+
338
+            // 班组正确率排名:正序前三名和倒序后三名
339
+            List<TeamAccuracyInfo> teamsInStation = calculateTeamAccuraciesUnderDept(hierarchy.stationId, startDate, endDate);
340
+            if (!teamsInStation.isEmpty()) {
341
+                result.setTopTeamsInSite(convertToTeamRankingItemsWithBrigade(teamsInStation, 3, true));
342
+                result.setBottomTeamsInSite(convertToTeamRankingItemsWithBrigade(teamsInStation, 3, false));
343
+            }
344
+        }
345
+    }
346
+
347
+    /**
348
+     * 计算大队下所有主管的正确率
349
+     */
350
+    private List<TeamAccuracyInfo> calculateManagerAccuraciesUnderBrigade(Long brigadeId, Date startDate, Date endDate) {
351
+        List<TeamAccuracyInfo> result = new ArrayList<>();
352
+
353
+        // 查询大队下所有主管
354
+        List<SysDept> allDepts = deptService.selectDeptInfoAll(new SysDept());
355
+
356
+        for (SysDept dept : allDepts) {
357
+            if (!"0".equals(dept.getDelFlag())) {
358
+                continue;
359
+            }
360
+            if (!StrUtil.equals(DeptType.MANAGER.getCode(), dept.getDeptType())) {
361
+                continue;
362
+            }
363
+
364
+            // 检查是否属于该大队
365
+            if (brigadeId.equals(dept.getParentId())) {
366
+                TeamAccuracyInfo info = new TeamAccuracyInfo();
367
+                info.deptId = dept.getDeptId();
368
+                info.deptName = dept.getDeptName();
369
+
370
+                DeptHierarchy h = getDeptHierarchy(dept.getDeptId());
371
+                List<Long> teamIds = getTeamIdsUnderDept(dept.getDeptId(), h);
372
+
373
+                if (!teamIds.isEmpty()) {
374
+                    long[] counts = calculateAccuracyCountsForTeams(teamIds, startDate, endDate);
375
+                    if (counts[1] > 0) {
376
+                        info.accuracy = BigDecimal.valueOf(counts[0])
377
+                                .multiply(BigDecimal.valueOf(100))
378
+                                .divide(BigDecimal.valueOf(counts[1]), 2, RoundingMode.HALF_UP);
379
+                    } else {
380
+                        info.accuracy = BigDecimal.ZERO;
381
+                    }
382
+                } else {
383
+                    info.accuracy = BigDecimal.ZERO;
384
+                }
385
+                result.add(info);
386
+            }
387
+        }
388
+
389
+        // 按正确率降序排序
390
+        result.sort((a, b) -> b.accuracy.compareTo(a.accuracy));
391
+
392
+        return result;
393
+    }
394
+
395
+    /**
396
+     * 计算站级下所有大队的正确率
397
+     */
398
+    private List<TeamAccuracyInfo> calculateBrigadeAccuraciesUnderStation(Long stationId, Date startDate, Date endDate) {
399
+        List<TeamAccuracyInfo> result = new ArrayList<>();
400
+
401
+        // 查询站级下所有大队
402
+        List<SysDept> allDepts = deptService.selectDeptInfoAll(new SysDept());
403
+
404
+        for (SysDept dept : allDepts) {
405
+            if (!"0".equals(dept.getDelFlag())) {
406
+                continue;
407
+            }
408
+            if (!StrUtil.equals(DeptType.BRIGADE.getCode(), dept.getDeptType())) {
409
+                continue;
410
+            }
411
+
412
+            // 检查是否属于该站级
413
+            if (stationId.equals(dept.getParentId())) {
414
+                TeamAccuracyInfo info = new TeamAccuracyInfo();
415
+                info.deptId = dept.getDeptId();
416
+                info.deptName = dept.getDeptName();
417
+
418
+                DeptHierarchy h = getDeptHierarchy(dept.getDeptId());
419
+                List<Long> teamIds = getTeamIdsUnderDept(dept.getDeptId(), h);
420
+
421
+                if (!teamIds.isEmpty()) {
422
+                    long[] counts = calculateAccuracyCountsForTeams(teamIds, startDate, endDate);
423
+                    if (counts[1] > 0) {
424
+                        info.accuracy = BigDecimal.valueOf(counts[0])
425
+                                .multiply(BigDecimal.valueOf(100))
426
+                                .divide(BigDecimal.valueOf(counts[1]), 2, RoundingMode.HALF_UP);
427
+                    } else {
428
+                        info.accuracy = BigDecimal.ZERO;
429
+                    }
430
+                } else {
431
+                    info.accuracy = BigDecimal.ZERO;
432
+                }
433
+                result.add(info);
434
+            }
435
+        }
436
+
437
+        // 按正确率降序排序
438
+        result.sort((a, b) -> b.accuracy.compareTo(a.accuracy));
439
+
440
+        return result;
441
+    }
100 442
 
101
-        // 计算各层级平均正确率
102
-        calculateLevelAvgAccuracy(result, hierarchy, startDate, endDate);
443
+    /**
444
+     * 将班组排名转换为带大队名称的格式
445
+     */
446
+    private List<AccuracyStatisticsDTO.RankingItem> convertToTeamRankingItems(List<TeamAccuracyInfo> rankings, int limit, boolean fromTop, Long brigadeId) {
447
+        List<AccuracyStatisticsDTO.RankingItem> result = new ArrayList<>();
103 448
 
104
-        // 计算个人在各层级的排名
105
-        calculatePersonalRankings(result, currentUserId, hierarchy, startDate, endDate);
449
+        if (rankings.isEmpty()) {
450
+            return result;
451
+        }
106 452
 
107
-        // 计算班组/部门级别排名
108
-        calculateTeamAndDeptRankings(result, hierarchy, startDate, endDate);
453
+        int size = rankings.size();
454
+        int actualLimit = Math.min(limit, size);
455
+
456
+        if (fromTop) {
457
+            for (int i = 0; i < actualLimit; i++) {
458
+                TeamAccuracyInfo info = rankings.get(i);
459
+                AccuracyStatisticsDTO.RankingItem item = new AccuracyStatisticsDTO.RankingItem();
460
+                item.setId(info.deptId);
461
+                item.setName(info.deptName);
462
+                item.setAccuracy(info.accuracy);
463
+                item.setRank(i + 1);
464
+                result.add(item);
465
+            }
466
+        } else {
467
+            for (int i = size - actualLimit; i < size; i++) {
468
+                TeamAccuracyInfo info = rankings.get(i);
469
+                AccuracyStatisticsDTO.RankingItem item = new AccuracyStatisticsDTO.RankingItem();
470
+                item.setId(info.deptId);
471
+                item.setName(info.deptName);
472
+                item.setAccuracy(info.accuracy);
473
+                item.setRank(i + 1);
474
+                result.add(item);
475
+            }
476
+        }
109 477
 
110 478
         return result;
111 479
     }
112 480
 
481
+    /**
482
+     * 将班组排名转换为带大队名称的格式(站长视角)
483
+     * 格式如"一大队张三班组"
484
+     */
485
+    private List<AccuracyStatisticsDTO.RankingItem> convertToTeamRankingItemsWithBrigade(List<TeamAccuracyInfo> rankings, int limit, boolean fromTop) {
486
+        List<AccuracyStatisticsDTO.RankingItem> result = new ArrayList<>();
487
+
488
+        if (rankings.isEmpty()) {
489
+            return result;
490
+        }
491
+
492
+        int size = rankings.size();
493
+        int actualLimit = Math.min(limit, size);
494
+
495
+        if (fromTop) {
496
+            for (int i = 0; i < actualLimit; i++) {
497
+                TeamAccuracyInfo info = rankings.get(i);
498
+                AccuracyStatisticsDTO.RankingItem item = new AccuracyStatisticsDTO.RankingItem();
499
+                item.setId(info.deptId);
500
+                item.setName(getTeamDisplayNameWithBrigade(info.deptId, info.deptName));
501
+                item.setAccuracy(info.accuracy);
502
+                item.setRank(i + 1);
503
+                result.add(item);
504
+            }
505
+        } else {
506
+            for (int i = size - actualLimit; i < size; i++) {
507
+                TeamAccuracyInfo info = rankings.get(i);
508
+                AccuracyStatisticsDTO.RankingItem item = new AccuracyStatisticsDTO.RankingItem();
509
+                item.setId(info.deptId);
510
+                item.setName(getTeamDisplayNameWithBrigade(info.deptId, info.deptName));
511
+                item.setAccuracy(info.accuracy);
512
+                item.setRank(i + 1);
513
+                result.add(item);
514
+            }
515
+        }
516
+
517
+        return result;
518
+    }
519
+
520
+    /**
521
+     * 获取班组显示名称,格式为"大队名+班组名",如"一大队张三班组"
522
+     */
523
+    private String getTeamDisplayNameWithBrigade(Long teamId, String teamName) {
524
+        SysDept teamDept = deptService.selectDeptById(teamId);
525
+        if (teamDept == null) {
526
+            return teamName;
527
+        }
528
+        // 获取班组所属的主管
529
+        Long managerId = teamDept.getParentId();
530
+        if (managerId != null) {
531
+            SysDept managerDept = deptService.selectDeptById(managerId);
532
+            if (managerDept != null) {
533
+                // 获取主管所属的大队
534
+                Long brigadeId = managerDept.getParentId();
535
+                if (brigadeId != null) {
536
+                    SysDept brigadeDept = deptService.selectDeptById(brigadeId);
537
+                    if (brigadeDept != null && StrUtil.equals(DeptType.BRIGADE.getCode(), brigadeDept.getDeptType())) {
538
+                        return brigadeDept.getDeptName() + teamName;
539
+                    }
540
+                }
541
+            }
542
+        }
543
+        return teamName;
544
+    }
545
+
113 546
     @Override
114 547
     public AccuracyStatisticsDTO getUserAccuracyStatistics(Long userId, AccuracyStatisticsQueryDTO query) {
115 548
         SysUser user = userService.selectUserById(userId);
@@ -119,7 +552,8 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
119 552
 
120 553
         AccuracyStatisticsDTO result = new AccuracyStatisticsDTO();
121 554
 
122
-        // 设置用户角色
555
+        // 获取用户角色
556
+        String roleKey = getUserRoleKey(user);
123 557
         if (user.getRoles() != null && !user.getRoles().isEmpty()) {
124 558
             result.setUserRole(user.getRoles().get(0).getRoleName());
125 559
         }
@@ -141,17 +575,27 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
141 575
         // 检查是否有待完成任务
142 576
         checkPendingTask(result, userId);
143 577
 
144
-        // 计算个人正确率
145
-        calculatePersonalAccuracy(result, userId, startDate, endDate);
146
-
147
-        // 计算各层级平均正确率
148
-        calculateLevelAvgAccuracy(result, hierarchy, startDate, endDate);
149
-
150
-        // 计算个人在各层级的排名
151
-        calculatePersonalRankings(result, userId, hierarchy, startDate, endDate);
152
-
153
-        // 计算班组/部门级别排名
154
-        calculateTeamAndDeptRankings(result, hierarchy, startDate, endDate);
578
+        // 根据角色返回不同的数据
579
+        if (RoleTypeEnum.SecurityCheck.getCode().equals(roleKey)) {
580
+            // 安检员
581
+            calculateSecurityCheckData(result, userId, hierarchy, startDate, endDate);
582
+        } else if (RoleTypeEnum.banzuzhang.getCode().equals(roleKey)) {
583
+            // 班组长
584
+            calculateTeamLeaderData(result, userId, hierarchy, startDate, endDate);
585
+        } else if (RoleTypeEnum.kezhang.getCode().equals(roleKey)) {
586
+            // 主管
587
+            calculateManagerData(result, userId, hierarchy, startDate, endDate);
588
+        } else if (RoleTypeEnum.jingli.getCode().equals(roleKey) || RoleTypeEnum.xingzheng.getCode().equals(roleKey)) {
589
+            // 大队长(经理/行政)
590
+            calculateBrigadeLeaderData(result, hierarchy, startDate, endDate);
591
+        } else if (RoleTypeEnum.test.getCode().equals(roleKey)) {
592
+            // 站长
593
+            calculateStationLeaderData(result, hierarchy, startDate, endDate);
594
+        } else {
595
+            // 其他角色:返回基本数据
596
+            calculatePersonalAccuracy(result, userId, startDate, endDate);
597
+            calculateLevelAvgAccuracy(result, hierarchy, startDate, endDate);
598
+        }
155 599
 
156 600
         return result;
157 601
     }
@@ -551,20 +995,28 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
551 995
 
552 996
     /**
553 997
      * 计算用户在指定部门范围内的排名
998
+     * 如果用户没有答题记录,将其视为正确率0排在最后
554 999
      */
555 1000
     private AccuracyStatisticsDTO.RankingInfo calculateUserRankingInDept(Long userId, Long deptId, Date startDate, Date endDate) {
556 1001
         DeptHierarchy hierarchy = getDeptHierarchy(deptId);
557 1002
         List<Long> teamIds = getTeamIdsUnderDept(deptId, hierarchy);
558 1003
 
1004
+        AccuracyStatisticsDTO.RankingInfo rankingInfo = new AccuracyStatisticsDTO.RankingInfo();
1005
+
559 1006
         if (teamIds.isEmpty()) {
560
-            return null;
1007
+            rankingInfo.setRank(1);
1008
+            rankingInfo.setTotal(1);
1009
+            return rankingInfo;
561 1010
         }
562 1011
 
563 1012
         // 获取这些班组下所有用户的正确率
564 1013
         List<UserAccuracyInfo> userAccuracies = calculateUserAccuraciesInTeams(teamIds, startDate, endDate);
565 1014
 
566 1015
         if (userAccuracies.isEmpty()) {
567
-            return null;
1016
+            // 没有任何人答题,当前用户排第1
1017
+            rankingInfo.setRank(1);
1018
+            rankingInfo.setTotal(1);
1019
+            return rankingInfo;
568 1020
         }
569 1021
 
570 1022
         // 按正确率降序排序
@@ -579,9 +1031,15 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
579 1031
             }
580 1032
         }
581 1033
 
582
-        AccuracyStatisticsDTO.RankingInfo rankingInfo = new AccuracyStatisticsDTO.RankingInfo();
583
-        rankingInfo.setRank(rank > 0 ? rank : null);
584
-        rankingInfo.setTotal(userAccuracies.size());
1034
+        // 如果找不到当前用户,说明该用户没有答题记录,排在最后(正确率为0)
1035
+        if (rank == 0) {
1036
+            rank = userAccuracies.size() + 1;
1037
+            rankingInfo.setRank(rank);
1038
+            rankingInfo.setTotal(userAccuracies.size() + 1);
1039
+        } else {
1040
+            rankingInfo.setRank(rank);
1041
+            rankingInfo.setTotal(userAccuracies.size());
1042
+        }
585 1043
         return rankingInfo;
586 1044
     }
587 1045
 
@@ -1089,16 +1547,19 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
1089 1547
                 continue;
1090 1548
             }
1091 1549
 
1550
+            TeamAccuracyInfo info = new TeamAccuracyInfo();
1551
+            info.deptId = teamId;
1552
+            info.deptName = teamDept.getDeptName();
1553
+
1092 1554
             long[] counts = calculateAccuracyCountsForTeams(Collections.singletonList(teamId), startDate, endDate);
1093 1555
             if (counts[1] > 0) {
1094
-                TeamAccuracyInfo info = new TeamAccuracyInfo();
1095
-                info.deptId = teamId;
1096
-                info.deptName = teamDept.getDeptName();
1097 1556
                 info.accuracy = BigDecimal.valueOf(counts[0])
1098 1557
                         .multiply(BigDecimal.valueOf(100))
1099 1558
                         .divide(BigDecimal.valueOf(counts[1]), 2, RoundingMode.HALF_UP);
1100
-                result.add(info);
1559
+            } else {
1560
+                info.accuracy = BigDecimal.ZERO;
1101 1561
             }
1562
+            result.add(info);
1102 1563
         }
1103 1564
 
1104 1565
         // 按正确率降序排序
@@ -1138,21 +1599,26 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
1138 1599
                 continue;
1139 1600
             }
1140 1601
 
1602
+            TeamAccuracyInfo info = new TeamAccuracyInfo();
1603
+            info.deptId = managerId;
1604
+            info.deptName = managerDept.getDeptName();
1605
+
1141 1606
             DeptHierarchy h = getDeptHierarchy(managerId);
1142 1607
             List<Long> teamIds = getTeamIdsUnderDept(managerId, h);
1143 1608
 
1144 1609
             if (!teamIds.isEmpty()) {
1145 1610
                 long[] counts = calculateAccuracyCountsForTeams(teamIds, startDate, endDate);
1146 1611
                 if (counts[1] > 0) {
1147
-                    TeamAccuracyInfo info = new TeamAccuracyInfo();
1148
-                    info.deptId = managerId;
1149
-                    info.deptName = managerDept.getDeptName();
1150 1612
                     info.accuracy = BigDecimal.valueOf(counts[0])
1151 1613
                             .multiply(BigDecimal.valueOf(100))
1152 1614
                             .divide(BigDecimal.valueOf(counts[1]), 2, RoundingMode.HALF_UP);
1153
-                    result.add(info);
1615
+                } else {
1616
+                    info.accuracy = BigDecimal.ZERO;
1154 1617
                 }
1618
+            } else {
1619
+                info.accuracy = BigDecimal.ZERO;
1155 1620
             }
1621
+            result.add(info);
1156 1622
         }
1157 1623
 
1158 1624
         // 按正确率降序排序
@@ -1163,10 +1629,15 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
1163 1629
 
1164 1630
     /**
1165 1631
      * 在排名列表中查找指定部门的排名
1632
+     * 如果部门不在列表中(无答题记录),将其视为正确率0排在最后
1166 1633
      */
1167 1634
     private AccuracyStatisticsDTO.RankingInfo findTeamRanking(Long deptId, List<TeamAccuracyInfo> rankings) {
1635
+        AccuracyStatisticsDTO.RankingInfo rankingInfo = new AccuracyStatisticsDTO.RankingInfo();
1636
+
1168 1637
         if (rankings.isEmpty()) {
1169
-            return null;
1638
+            rankingInfo.setRank(1);
1639
+            rankingInfo.setTotal(1);
1640
+            return rankingInfo;
1170 1641
         }
1171 1642
 
1172 1643
         int rank = 0;
@@ -1177,9 +1648,15 @@ public class AccuracyStatisticsServiceImpl implements IAccuracyStatisticsService
1177 1648
             }
1178 1649
         }
1179 1650
 
1180
-        AccuracyStatisticsDTO.RankingInfo rankingInfo = new AccuracyStatisticsDTO.RankingInfo();
1181
-        rankingInfo.setRank(rank > 0 ? rank : null);
1182
-        rankingInfo.setTotal(rankings.size());
1651
+        // 如果找不到,说明该部门没有答题记录,排在最后(正确率为0)
1652
+        if (rank == 0) {
1653
+            rank = rankings.size() + 1;
1654
+            rankingInfo.setRank(rank);
1655
+            rankingInfo.setTotal(rankings.size() + 1);
1656
+        } else {
1657
+            rankingInfo.setRank(rank);
1658
+            rankingInfo.setTotal(rankings.size());
1659
+        }
1183 1660
         return rankingInfo;
1184 1661
     }
1185 1662