Ver código fonte

质控分析报告-勤务组织/风险隐患-部门或用户筛选功能

chenshudong 2 semanas atrás
pai
commit
1a51e0da4c
20 arquivos alterados com 1289 adições e 188 exclusões
  1. 12 1
      airport-admin/src/main/java/com/sundot/airport/web/controller/quality/ItemCategoryStatsController.java
  2. 218 31
      airport-admin/src/main/java/com/sundot/airport/web/controller/quality/QualificationLevelStatsController.java
  3. 183 8
      airport-admin/src/main/java/com/sundot/airport/web/controller/quality/SimpleAttendancePersonController.java
  4. 2 5
      airport-attendance/src/main/java/com/sundot/airport/attendance/calculator/AttendancePersonCountCalculator.java
  5. 28 11
      airport-attendance/src/main/java/com/sundot/airport/attendance/calculator/BrigadeAttendancePersonCountCalculator.java
  6. 1 1
      airport-common/src/main/java/com/sundot/airport/common/enums/IndicatorTypeEnum.java
  7. 25 0
      airport-common/src/main/java/com/sundot/airport/common/statistics/TimeDimensionParams.java
  8. 18 5
      airport-item/src/main/java/com/sundot/airport/item/domain/dto/QualificationLevelStatsDTO.java
  9. 13 0
      airport-item/src/main/java/com/sundot/airport/item/domain/home/SeizureReportDTO.java
  10. 84 28
      airport-item/src/main/java/com/sundot/airport/item/mapper/ItemCategoryStatsMapper.java
  11. 29 0
      airport-item/src/main/java/com/sundot/airport/item/mapper/SeizureReportMapper.java
  12. 165 16
      airport-item/src/main/java/com/sundot/airport/item/service/impl/ItemCategoryStatsServiceImpl.java
  13. 268 26
      airport-item/src/main/java/com/sundot/airport/item/service/impl/ItemLargeScreenServiceImpl.java
  14. 119 56
      airport-item/src/main/resources/mapper/item/ItemCategoryStatsMapper.xml
  15. 20 0
      airport-item/src/main/resources/mapper/item/ItemLargeScreenMapper.xml
  16. 59 0
      airport-item/src/main/resources/mapper/item/SeizureReportMapper.xml
  17. 8 0
      airport-system/src/main/java/com/sundot/airport/system/mapper/SysUserMapper.java
  18. 8 0
      airport-system/src/main/java/com/sundot/airport/system/service/ISysUserService.java
  19. 5 0
      airport-system/src/main/java/com/sundot/airport/system/service/impl/SysUserServiceImpl.java
  20. 24 0
      airport-system/src/main/resources/mapper/system/SysUserMapper.xml

+ 12 - 1
airport-admin/src/main/java/com/sundot/airport/web/controller/quality/ItemCategoryStatsController.java

@@ -96,6 +96,11 @@ public class ItemCategoryStatsController extends BaseController {
96 96
             dto.setStartDate(timeParams.getStartTime());
97 97
             dto.setEndDate(timeParams.getEndTime());
98 98
             dto.setInspectStationId(topSiteId);
99
+            // 设置大队、科室、班、人员筛选条件
100
+            dto.setInspectBrigadeId(params.getBrigadeId());
101
+            dto.setInspectDepartmentId(params.getDepartmentId());
102
+            dto.setInspectTeamId(params.getTeamId());
103
+            dto.setUserId(params.getUserId());
99 104
             List<ItemLargeScreenTimeSpanDto> result = itemLargeScreenService.appTimeSpan(dto);
100 105
             return AjaxResult.success("获取成功", result);
101 106
 
@@ -182,7 +187,7 @@ public class ItemCategoryStatsController extends BaseController {
182 187
 
183 188
 
184 189
     /**
185
-     * "各大队查获排名
190
+     * 各大队查获排名
186 191
      */
187 192
     @ApiOperation("获取各大队查获排名")
188 193
     @GetMapping("/brigade-ranking")
@@ -264,6 +269,12 @@ public class ItemCategoryStatsController extends BaseController {
264 269
         dto.setStartDate(timeParams.getStartTime());
265 270
         dto.setEndDate(timeParams.getEndTime());
266 271
 
272
+        // 设置大队、科室、班、人员筛选条件
273
+        dto.setInspectBrigadeId(params.getBrigadeId());
274
+        dto.setInspectDepartmentId(params.getDepartmentId());
275
+        dto.setInspectTeamId(params.getTeamId());
276
+        dto.setUserId(params.getUserId());
277
+
267 278
         return dto;
268 279
     }
269 280
 

+ 218 - 31
airport-admin/src/main/java/com/sundot/airport/web/controller/quality/QualificationLevelStatsController.java

@@ -11,12 +11,14 @@ import com.sundot.airport.system.domain.QualificationLevelConverter;
11 11
 import com.sundot.airport.system.domain.portrait.QualificationStats;
12 12
 import com.sundot.airport.system.mapper.portrait.QualificationLevelIndicatorMapper;
13 13
 import com.sundot.airport.system.service.ISysDeptService;
14
+import com.sundot.airport.system.service.ISysPostService;
14 15
 import com.sundot.airport.system.service.ISysUserService;
15 16
 import io.swagger.annotations.Api;
16 17
 import io.swagger.annotations.ApiOperation;
17 18
 import org.springframework.beans.factory.annotation.Autowired;
18 19
 import org.springframework.web.bind.annotation.GetMapping;
19 20
 import org.springframework.web.bind.annotation.RequestMapping;
21
+import org.springframework.web.bind.annotation.RequestParam;
20 22
 import org.springframework.web.bind.annotation.RestController;
21 23
 
22 24
 import java.math.BigDecimal;
@@ -49,6 +51,9 @@ public class QualificationLevelStatsController extends BaseController {
49 51
     @Autowired
50 52
     private ISysUserService sysUserService;
51 53
 
54
+    @Autowired
55
+    private ISysPostService sysPostService;
56
+
52 57
 
53 58
     /**
54 59
      * 固定的资质等级列表(初级、中级、高级)
@@ -58,25 +63,34 @@ public class QualificationLevelStatsController extends BaseController {
58 63
     );
59 64
 
60 65
     /**
61
-     * 获取饼状图数据(全站资质等级分布)
66
+     * 获取饼状图数据(资质等级分布)
67
+     * 支持按部门 ID、用户 ID 进行统计
62 68
      */
63 69
     @ApiOperation("获取饼状图数据")
64 70
     @GetMapping("/pie-chart")
65
-    public AjaxResult getPieChartData() {
71
+    public AjaxResult getPieChartData(
72
+            @RequestParam(required = false) Long deptId) {
66 73
 
67 74
         try {
68
-            Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(getDeptId()));
69
-            if (topSiteId == null) {
70
-                return AjaxResult.error("无法找到有效的站点信息");
75
+            List<Long> targetUserIds;
76
+
77
+            if (deptId != null) {
78
+                // 按部门(大队/科室/班组)统计
79
+                targetUserIds = getAllUserIdsUnderDept(deptId);
80
+            } else {
81
+                // 默认按全站统计
82
+                Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(getDeptId()));
83
+                if (topSiteId == null) {
84
+                    return AjaxResult.error("无法找到有效的站点信息");
85
+                }
86
+                targetUserIds = getAllUserIdsUnderSite(topSiteId);
71 87
             }
72 88
 
73
-            List<Long> siteUserIds = getAllUserIdsUnderSite(topSiteId);
74
-            if (siteUserIds.isEmpty()) {
89
+            if (targetUserIds.isEmpty()) {
75 90
                 return AjaxResult.success("获取成功", new QualificationLevelStatsDTO.PieChartData());
76 91
             }
77 92
 
78
-
79
-            QualificationLevelStatsDTO.PieChartData pieChart = calculatePieChartData(siteUserIds);
93
+            QualificationLevelStatsDTO.PieChartData pieChart = calculatePieChartData(targetUserIds);
80 94
             return AjaxResult.success("获取成功", pieChart);
81 95
 
82 96
         } catch (Exception e) {
@@ -86,19 +100,34 @@ public class QualificationLevelStatsController extends BaseController {
86 100
     }
87 101
 
88 102
     /**
89
-     * 获取柱状图数据(各大队资质等级分布)
103
+     * 获取柱状图数据(资质等级分布)
104
+     * 支持按大队ID、科室ID、班组ID、用户ID 进行统计
90 105
      */
91 106
     @ApiOperation("获取柱状图数据")
92 107
     @GetMapping("/bar-chart")
93
-    public AjaxResult getBarChartData() {
108
+    public AjaxResult getBarChartData(
109
+            @RequestParam(required = false) Long deptId,
110
+            @RequestParam(required = false) Long userId) {
94 111
 
95 112
         try {
96
-            Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(getDeptId()));
97
-            if (topSiteId == null) {
98
-                return AjaxResult.error("无法找到有效的站点信息");
113
+            QualificationLevelStatsDTO.BarChartData barChart;
114
+
115
+            // 优先处理用户 ID 参数
116
+            if (userId != null) {
117
+                // 按个人统计,返回该用户的资质等级
118
+                barChart = calculateBarChartDataForUser(userId);
119
+            } else if (deptId != null) {
120
+                // 按部门 ID 统计,根据部门类型决定返回逻辑
121
+                barChart = calculateBarChartDataForDept(deptId);
122
+            } else {
123
+                // 未传参,默认统计全站下各科室的分布
124
+                Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(getDeptId()));
125
+                if (topSiteId == null) {
126
+                    return AjaxResult.error("无法找到有效的站点信息");
127
+                }
128
+                barChart = calculateBarChartDataOptimized(topSiteId);
99 129
             }
100 130
 
101
-            QualificationLevelStatsDTO.BarChartData barChart = calculateBarChartDataOptimized(topSiteId);
102 131
             return AjaxResult.success("获取成功", barChart);
103 132
 
104 133
         } catch (Exception e) {
@@ -171,6 +200,176 @@ public class QualificationLevelStatsController extends BaseController {
171 200
     }
172 201
 
173 202
     /**
203
+     * 计算柱状图数据
204
+     * - 站级/大队级/科级:返回下属组织的资质等级统计
205
+     * - 班组:返回班组内每个员工的资质等级
206
+     */
207
+    private QualificationLevelStatsDTO.BarChartData calculateBarChartDataForDept(Long deptId) {
208
+        QualificationLevelStatsDTO.BarChartData barChart = new QualificationLevelStatsDTO.BarChartData();
209
+
210
+        SysDept sysDept = sysDeptService.selectDeptById(deptId);
211
+        if (sysDept == null) {
212
+            barChart.setBrigades(new ArrayList<>());
213
+            return barChart;
214
+        }
215
+
216
+        List<SysDept> targetDepts = new ArrayList<>();
217
+
218
+        // 根据部门类型决定查询逻辑
219
+        if (DeptTypeEnum.TEAMS.getCode().equals(sysDept.getDeptType())) {
220
+            // 班组级别:查询该班组下的所有用户,返回每个人的资质等级
221
+            return calculateBarChartDataForTeam(deptId);
222
+        } else {
223
+            // 站级/大队级/科级:查询该部门下的所有子部门
224
+            List<SysDept> children = sysDeptService.selectChildrenDeptById(deptId);
225
+            if (DeptTypeEnum.MANAGER.getCode().equals(sysDept.getDeptType())) {
226
+                targetDepts.addAll(children.stream()
227
+                        .filter(dept -> DeptTypeEnum.TEAMS.getCode().equals(dept.getDeptType()))
228
+                        .collect(Collectors.toList()));
229
+            } else if (DeptTypeEnum.BRIGADE.getCode().equals(sysDept.getDeptType())) {
230
+                targetDepts.addAll(children.stream()
231
+                        .filter(dept -> DeptTypeEnum.MANAGER.getCode().equals(dept.getDeptType()))
232
+                        .collect(Collectors.toList()));
233
+            } else if (DeptTypeEnum.STATION.getCode().equals(sysDept.getDeptType())) {
234
+                targetDepts.addAll(children.stream()
235
+                        .filter(dept -> DeptTypeEnum.BRIGADE.getCode().equals(dept.getDeptType()))
236
+                        .collect(Collectors.toList()));
237
+
238
+            }
239
+            if (targetDepts.isEmpty()) {
240
+                barChart.setBrigades(new ArrayList<>());
241
+                return barChart;
242
+            }
243
+        }
244
+
245
+        // 批量获取所有子部门的用户 ID
246
+        Map<Long, List<Long>> deptUserIdsMap = batchGetUserIdsByBrigades(targetDepts);
247
+
248
+        // 批量查询所有子部门的资质统计数据
249
+        Map<Long, List<QualificationStats>> deptStatsMap = batchQueryQualificationStats(deptUserIdsMap);
250
+
251
+        // 构建部门数据
252
+        List<QualificationLevelStatsDTO.BrigadeData> deptDataList = targetDepts.stream()
253
+                .map(dept -> {
254
+                    QualificationLevelStatsDTO.BrigadeData deptData = new QualificationLevelStatsDTO.BrigadeData();
255
+                    deptData.setDeptId(dept.getDeptId());
256
+                    deptData.setDeptName(dept.getDeptName());
257
+
258
+                    List<QualificationStats> deptStats = deptStatsMap.get(dept.getDeptId());
259
+                    if (deptStats != null && !deptStats.isEmpty()) {
260
+                        List<QualificationLevelStatsDTO.LevelCount> levelCounts = convertToLevelCounts(deptStats);
261
+                        deptData.setLevelCounts(levelCounts);
262
+                    } else {
263
+                        // 部门无用户或无统计数据,初始化为空数据
264
+                        List<QualificationLevelStatsDTO.LevelCount> emptyCounts = QUALIFICATION_LEVELS.stream()
265
+                                .map(level -> {
266
+                                    QualificationLevelStatsDTO.LevelCount count = new QualificationLevelStatsDTO.LevelCount();
267
+                                    count.setLevelName(level);
268
+                                    count.setCount(0);
269
+                                    return count;
270
+                                })
271
+                                .collect(Collectors.toList());
272
+                        deptData.setLevelCounts(emptyCounts);
273
+                    }
274
+
275
+                    return deptData;
276
+                })
277
+                .collect(Collectors.toList());
278
+
279
+        barChart.setBrigades(deptDataList);
280
+        return barChart;
281
+    }
282
+
283
+    /**
284
+     * 计算班组的柱状图数据(返回班组内每个员工的资质等级)
285
+     */
286
+    private QualificationLevelStatsDTO.BarChartData calculateBarChartDataForTeam(Long teamId) {
287
+        QualificationLevelStatsDTO.BarChartData barChart = new QualificationLevelStatsDTO.BarChartData();
288
+
289
+        // 获取班组下的所有用户
290
+        List<Long> userIds = getAllUserIdsUnderDept(teamId);
291
+
292
+        if (userIds.isEmpty()) {
293
+            barChart.setBrigades(new ArrayList<>());
294
+            return barChart;
295
+        }
296
+
297
+        // 查询每个用户的资质等级
298
+        List<QualificationLevelStatsDTO.BrigadeData> userDataList = new ArrayList<>();
299
+        for (Long uid : userIds) {
300
+            SysUser user = sysUserService.selectUserById(uid);
301
+            if (user == null || "2".equals(user.getDelFlag()) || "1".equals(user.getStatus())) {
302
+                continue; // 跳过已删除或停用的用户
303
+            }
304
+
305
+            // 查询该用户的资质等级
306
+            String level = qualificationLevelMapper.queryPersonalQualificationLevel(uid);
307
+            String displayLevel = convertToDisplayLevel(level);
308
+
309
+            QualificationLevelStatsDTO.BrigadeData userData = new QualificationLevelStatsDTO.BrigadeData();
310
+            userData.setDeptId(uid); // 使用用户 ID 作为标识
311
+            userData.setDeptName(user.getNickName() != null ? user.getNickName() : user.getUserName());
312
+            userData.setQualificationLevel(displayLevel); // 直接设置资质等级
313
+
314
+            userDataList.add(userData);
315
+        }
316
+
317
+        barChart.setBrigades(userDataList);
318
+        return barChart;
319
+    }
320
+
321
+    /**
322
+     * 计算个人的柱状图数据(返回单个用户的资质等级)
323
+     */
324
+    private QualificationLevelStatsDTO.BarChartData calculateBarChartDataForUser(Long userId) {
325
+        QualificationLevelStatsDTO.BarChartData barChart = new QualificationLevelStatsDTO.BarChartData();
326
+
327
+        SysUser user = sysUserService.selectUserById(userId);
328
+        if (user == null || "2".equals(user.getDelFlag()) || "1".equals(user.getStatus())) {
329
+            barChart.setBrigades(new ArrayList<>());
330
+            return barChart;
331
+        }
332
+
333
+        // 查询该用户的资质等级
334
+        String level = qualificationLevelMapper.queryPersonalQualificationLevel(userId);
335
+        String displayLevel = convertToDisplayLevel(level);
336
+
337
+        // 构建用户数据
338
+        QualificationLevelStatsDTO.BrigadeData userData = new QualificationLevelStatsDTO.BrigadeData();
339
+        userData.setDeptId(userId);
340
+        userData.setDeptName(user.getNickName() != null ? user.getNickName() : user.getUserName());
341
+        userData.setQualificationLevel(displayLevel); // 直接设置资质等级
342
+        userData.setSysPostList(sysPostService.selectPostListsByUserId(userId));
343
+
344
+        List<QualificationLevelStatsDTO.BrigadeData> departments = new ArrayList<>();
345
+        departments.add(userData);
346
+        barChart.setBrigades(departments);
347
+
348
+        return barChart;
349
+    }
350
+
351
+    /**
352
+     * 将数据库枚举值转换为显示名称
353
+     */
354
+    private String convertToDisplayLevel(String dbValue) {
355
+        if (dbValue == null || dbValue.trim().isEmpty()) {
356
+            return null;
357
+        }
358
+        switch (dbValue.toUpperCase()) {
359
+            case "LEVEL_FIVE":
360
+                return "初级";
361
+            case "LEVEL_FOUR":
362
+                return "中级";
363
+            case "LEVEL_ONE":
364
+            case "LEVEL_TWO":
365
+            case "LEVEL_THREE":
366
+                return "高级";
367
+            default:
368
+                return dbValue;
369
+        }
370
+    }
371
+
372
+    /**
174 373
      * 计算柱状图数据(各大队资质等级分布)
175 374
      */
176 375
     private QualificationLevelStatsDTO.BarChartData calculateBarChartDataOptimized(Long siteId) {
@@ -333,22 +532,10 @@ public class QualificationLevelStatsController extends BaseController {
333 532
      * 获取部门下的所有用户ID
334 533
      */
335 534
     private List<Long> getAllUserIdsUnderDept(Long deptId) {
336
-        List<Long> userIds = new ArrayList<>();
337
-
338
-        // 获取部门本身及其下属部门
339
-        List<SysDept> allDepts = sysDeptService.selectChildrenDeptById(deptId);
340
-        allDepts.add(0, sysDeptService.selectDeptById(deptId)); // 添加部门本身
341
-
342
-        // 获取各部门下的用户
343
-        for (SysDept dept : allDepts) {
344
-            List<Long> deptUserIds = sysUserService.selectUserByDeptId(dept.getDeptId()).stream()
345
-                    .map(SysUser::getUserId)
346
-                    .collect(Collectors.toList());
347
-            userIds.addAll(deptUserIds);
348
-        }
349
-
350
-        return userIds.stream().distinct().collect(Collectors.toList());
535
+        List<SysUser> sysUserList = sysUserService.selectUserByDeptId(deptId);
536
+        return sysUserList.stream()
537
+                .map(SysUser::getUserId)
538
+                .collect(Collectors.toList());
351 539
     }
352 540
 
353
-
354 541
 }

+ 183 - 8
airport-admin/src/main/java/com/sundot/airport/web/controller/quality/SimpleAttendancePersonController.java

@@ -45,19 +45,25 @@ public class SimpleAttendancePersonController {
45 45
 
46 46
     /**
47 47
      * 出勤人次分析
48
+     * 支持按大队ID、科室ID、班组ID、用户ID 进行统计
48 49
      */
49 50
     @ApiOperation("出勤人次分析")
50 51
     @PostMapping("/calculate")
51 52
     public List<AttendancePersonStatsDTO> calculateStatistics(@RequestBody IndicatorCalculationParams params) {
52 53
         List<AttendancePersonStatsDTO> results = new ArrayList<>();
53 54
 
54
-        // 获取当前用户所在站点ID
55
-        Long topSiteId = DeptUtils.getTopSiteId(deptService.selectDeptById(getDeptId()));
56
-        List<SysDept> brigadesUnderSite = getBrigadesUnderSite(topSiteId);
57
-        brigadesUnderSite.add(deptService.selectDeptById(topSiteId));
58
-        brigadesUnderSite.forEach(dept -> {
59
-            results.add(createAttendancePersonStats(dept, params));
60
-        });
55
+        if (params.getDeptId() != null || params.getUserId() != null) {
56
+            // 传入了部门 ID 或用户 ID,直接统计
57
+            results.add(createAttendancePersonStatsForParams(params));
58
+        } else {
59
+            // 未传入具体 ID,默认获取当前用户所在站点下的科室
60
+            Long topSiteId = DeptUtils.getTopSiteId(deptService.selectDeptById(getDeptId()));
61
+            List<SysDept> brigadeUnderSite = getBrigadesUnderSite(topSiteId);
62
+            brigadeUnderSite.add(deptService.selectDeptById(topSiteId));
63
+            brigadeUnderSite.forEach(dept -> {
64
+                results.add(createAttendancePersonStats(dept, params));
65
+            });
66
+        }
61 67
 
62 68
         return results;
63 69
     }
@@ -73,6 +79,13 @@ public class SimpleAttendancePersonController {
73 79
     @ApiOperation("出勤人次趋势数据")
74 80
     @PostMapping("/trend-data")
75 81
     public List<AttendanceTrendDataDTO> getTrendData(@RequestBody IndicatorCalculationParams params) {
82
+        // 根据传入参数决定统计策略
83
+        if (params.getDeptId() != null || params.getUserId() != null) {
84
+            // 传入了部门 ID 或用户 ID,返回简化版的趋势数据
85
+            return getSimpleTrendData(params);
86
+        }
87
+
88
+        // 默认按站点 + 三科模式统计
76 89
         List<AttendanceTrendDataDTO> results = new ArrayList<>();
77 90
 
78 91
         // 根据时间维度类型决定展示策略
@@ -94,6 +107,112 @@ public class SimpleAttendancePersonController {
94 107
     }
95 108
 
96 109
     /**
110
+     * 趋势数据(用于指定部门/个人的场景)
111
+     * 仅返回单条数据序列
112
+     */
113
+    private List<AttendanceTrendDataDTO> getSimpleTrendData(IndicatorCalculationParams params) {
114
+        List<AttendanceTrendDataDTO> results = new ArrayList<>();
115
+
116
+        // 根据时间维度类型决定展示策略
117
+        if (params.getMonth() != null) {
118
+            // 月度:展示当前月、上月、去年同期
119
+            results.addAll(generateSimpleMonthlyTrendData(params));
120
+        } else if (params.getQuarter() != null) {
121
+            // 季度:展示当前季度和去年同期
122
+            results.addAll(generateSimpleQuarterlyTrendData(params));
123
+        } else if (params.getYear() != null) {
124
+            // 年度:仅展示当前年和去年
125
+            results.addAll(generateSimpleYearlyTrendData(params));
126
+        } else {
127
+            // 默认按月度处理
128
+            results.addAll(generateSimpleMonthlyTrendData(params));
129
+        }
130
+
131
+        return results;
132
+    }
133
+
134
+    /**
135
+     * 月度趋势数据
136
+     */
137
+    private List<AttendanceTrendDataDTO> generateSimpleMonthlyTrendData(IndicatorCalculationParams params) {
138
+        List<AttendanceTrendDataDTO> results = new ArrayList<>();
139
+
140
+        // 计算当前月数据
141
+        AttendancePersonStatsDTO currentData = createAttendancePersonStatsForParams(params);
142
+
143
+        // 计算上月数据
144
+        IndicatorCalculationParams lastMonthParams = createLastMonthParams(params);
145
+        AttendancePersonStatsDTO lastMonthData = createAttendancePersonStatsForParams(lastMonthParams);
146
+
147
+        // 计算去年同期数据
148
+        IndicatorCalculationParams lastYearParams = createLastYearParams(params);
149
+        AttendancePersonStatsDTO lastYearData = createAttendancePersonStatsForParams(lastYearParams);
150
+
151
+        // 构造趋势数据点
152
+        results.add(createSimpleTrendDataPoint(getLastYearMonthLabel(params), lastYearData));
153
+        results.add(createSimpleTrendDataPoint(getLastMonthLabel(params), lastMonthData));
154
+        results.add(createSimpleTrendDataPoint(getMonthLabel(params), currentData));
155
+
156
+        return results;
157
+    }
158
+
159
+    /**
160
+     * 季度趋势数据
161
+     */
162
+    private List<AttendanceTrendDataDTO> generateSimpleQuarterlyTrendData(IndicatorCalculationParams params) {
163
+        List<AttendanceTrendDataDTO> results = new ArrayList<>();
164
+
165
+        // 计算当前季度数据
166
+        AttendancePersonStatsDTO currentData = createAttendancePersonStatsForParams(params);
167
+
168
+        // 计算上季度数据
169
+        IndicatorCalculationParams lastQuarterParams = createLastQuarterParams(params);
170
+        AttendancePersonStatsDTO lastQuarterData = createAttendancePersonStatsForParams(lastQuarterParams);
171
+
172
+        // 计算去年同期季度数据
173
+        IndicatorCalculationParams lastYearParams = createLastYearParams(params);
174
+        AttendancePersonStatsDTO lastYearData = createAttendancePersonStatsForParams(lastYearParams);
175
+
176
+        // 构造趋势数据点
177
+        results.add(createSimpleTrendDataPoint(getLastYearQuarterLabel(params), lastYearData));
178
+        results.add(createSimpleTrendDataPoint(getLastQuarterLabel(params), lastQuarterData));
179
+        results.add(createSimpleTrendDataPoint(getQuarterLabel(params), currentData));
180
+
181
+        return results;
182
+    }
183
+
184
+    /**
185
+     * 年度趋势数据
186
+     */
187
+    private List<AttendanceTrendDataDTO> generateSimpleYearlyTrendData(IndicatorCalculationParams params) {
188
+        List<AttendanceTrendDataDTO> results = new ArrayList<>();
189
+
190
+        // 计算当前年数据
191
+        AttendancePersonStatsDTO currentData = createAttendancePersonStatsForParams(params);
192
+
193
+        // 计算去年数据
194
+        IndicatorCalculationParams lastYearParams = createLastYearParams(params);
195
+        AttendancePersonStatsDTO lastYearData = createAttendancePersonStatsForParams(lastYearParams);
196
+
197
+        // 构造趋势数据点
198
+        results.add(createSimpleTrendDataPoint((params.getYear() - 1) + "年", lastYearData));
199
+        results.add(createSimpleTrendDataPoint(params.getYear() + "年", currentData));
200
+
201
+        return results;
202
+    }
203
+
204
+    /**
205
+     * 趋势数据点
206
+     */
207
+    private AttendanceTrendDataDTO createSimpleTrendDataPoint(String timeLabel, AttendancePersonStatsDTO stats) {
208
+        AttendanceTrendDataDTO data = new AttendanceTrendDataDTO();
209
+        data.setTimeLabel(timeLabel);
210
+        // 将单个统计值设置为 overall 字段
211
+        data.setOverall(stats.getCurrentValue() != null ? stats.getCurrentValue() : BigDecimal.ZERO);
212
+        return data;
213
+    }
214
+
215
+    /**
97 216
      * 生成月度趋势数据(同比+环比)
98 217
      * 展示:当前月、上月、去年同期
99 218
      */
@@ -288,7 +407,7 @@ public class SimpleAttendancePersonController {
288 407
 
289 408
 
290 409
     /**
291
-     * 创建出勤人次统计对象
410
+     * 创建出勤人次统计对象(根据部门实体)
292 411
      */
293 412
     private AttendancePersonStatsDTO createAttendancePersonStats(SysDept sysDept, IndicatorCalculationParams params) {
294 413
         AttendancePersonStatsDTO result = new AttendancePersonStatsDTO();
@@ -344,6 +463,56 @@ public class SimpleAttendancePersonController {
344 463
     }
345 464
 
346 465
     /**
466
+     * 创建出勤人次统计对象(根据参数直接计算)
467
+     * 支持按部门、班组、个人进行统计
468
+     */
469
+    private AttendancePersonStatsDTO createAttendancePersonStatsForParams(IndicatorCalculationParams params) {
470
+        AttendancePersonStatsDTO result = new AttendancePersonStatsDTO();
471
+
472
+        // 设置部门信息
473
+        if (params.getDeptId() != null) {
474
+            SysDept dept = deptService.selectDeptById(params.getDeptId());
475
+            if (dept != null) {
476
+                result.setDeptId(dept.getDeptId());
477
+                result.setDeptName(dept.getDeptName());
478
+                result.setDeptType(dept.getDeptType());
479
+            }
480
+        }
481
+
482
+        try {
483
+            IndicatorCalculationResult currentResult = multiModelIndicatorCalculator.calculateWithRatio(deptCalculator, params);
484
+
485
+            if ("SUCCESS".equals(currentResult.getStatus())) {
486
+                result.setCurrentValue(currentResult.getValue());
487
+                result.setBaselineValue(currentResult.getBaselineValue());
488
+
489
+                boolean showChainRatio = params.getChainRatio() != null && params.getChainRatio();
490
+                boolean showYearOnYear = params.getYearOnYear() != null && params.getYearOnYear();
491
+
492
+                if (params.getYear() != null && params.getQuarter() == null && params.getMonth() == null) {
493
+                    showChainRatio = false;
494
+                }
495
+
496
+                if (showYearOnYear && currentResult.getYearOnYearValue() != null) {
497
+                    result.setYearOnYearValue(currentResult.getYearOnYearValue());
498
+                    result.setYearOnYearDirection(getDirectionText(currentResult.getYearOnYearValue()));
499
+                    result.setYearOnYearTimeDimension((TimeDimensionParams) currentResult.getExtraInfo().get("yearOnYear"));
500
+                }
501
+
502
+                if (showChainRatio && currentResult.getChainRatioValue() != null) {
503
+                    result.setChainRatioValue(currentResult.getChainRatioValue());
504
+                    result.setChainRatioDirection(getDirectionText(currentResult.getChainRatioValue()));
505
+                    result.setChainTimeDimension((TimeDimensionParams) currentResult.getExtraInfo().get("chain"));
506
+                }
507
+            }
508
+        } catch (Exception e) {
509
+            throw new RuntimeException(e);
510
+        }
511
+
512
+        return result;
513
+    }
514
+
515
+    /**
347 516
      * 创建上月参数
348 517
      */
349 518
     private IndicatorCalculationParams createLastMonthParams(IndicatorCalculationParams originalParams) {
@@ -353,6 +522,8 @@ public class SimpleAttendancePersonController {
353 522
         params.setMonth(originalParams.getMonth());
354 523
         params.setStartTime(originalParams.getStartTime());
355 524
         params.setEndTime(originalParams.getEndTime());
525
+        params.setUserId(originalParams.getUserId());
526
+        params.setDeptId(originalParams.getDeptId());
356 527
         params.setChainRatio(false);
357 528
         params.setYearOnYear(false);
358 529
 
@@ -381,6 +552,8 @@ public class SimpleAttendancePersonController {
381 552
         params.setMonth(originalParams.getMonth());
382 553
         params.setStartTime(originalParams.getStartTime());
383 554
         params.setEndTime(originalParams.getEndTime());
555
+        params.setUserId(originalParams.getUserId());
556
+        params.setDeptId(originalParams.getDeptId());
384 557
         params.setChainRatio(false);
385 558
         params.setYearOnYear(false);
386 559
 
@@ -410,6 +583,8 @@ public class SimpleAttendancePersonController {
410 583
         params.setMonth(originalParams.getMonth());
411 584
         params.setStartTime(originalParams.getStartTime());
412 585
         params.setEndTime(originalParams.getEndTime());
586
+        params.setUserId(originalParams.getUserId());
587
+        params.setDeptId(originalParams.getDeptId());
413 588
         params.setChainRatio(false);
414 589
         params.setYearOnYear(false);
415 590
 

+ 2 - 5
airport-attendance/src/main/java/com/sundot/airport/attendance/calculator/AttendancePersonCountCalculator.java

@@ -38,11 +38,8 @@ public class AttendancePersonCountCalculator extends AbstractIndicatorCalculator
38 38
         // 查询考勤记录
39 39
         List<AttendanceRecord> records = attendanceRecordMapper.selectAttendanceRecordList(record);
40 40
 
41
-        // 返回出勤人次(去重后的用户数量)
42
-        return new BigDecimal(records.stream()
43
-                .map(AttendanceRecord::getUserId)
44
-                .distinct()
45
-                .count());
41
+        // 返回出勤人次
42
+        return new BigDecimal(records.size());
46 43
     }
47 44
 
48 45
     @Override

+ 28 - 11
airport-attendance/src/main/java/com/sundot/airport/attendance/calculator/BrigadeAttendancePersonCountCalculator.java

@@ -2,10 +2,13 @@ package com.sundot.airport.attendance.calculator;
2 2
 
3 3
 import com.sundot.airport.attendance.domain.AttendanceRecord;
4 4
 import com.sundot.airport.attendance.mapper.AttendanceRecordMapper;
5
+import com.sundot.airport.common.core.domain.entity.SysDept;
6
+import com.sundot.airport.common.enums.DeptTypeEnum;
5 7
 import com.sundot.airport.common.enums.IndicatorTypeEnum;
6 8
 import com.sundot.airport.common.statistics.AbstractIndicatorCalculator;
7 9
 import com.sundot.airport.common.statistics.IndicatorCalculationParams;
8 10
 import com.sundot.airport.common.statistics.TimeDimensionProcessor;
11
+import com.sundot.airport.system.mapper.SysDeptMapper;
9 12
 import org.springframework.beans.factory.annotation.Autowired;
10 13
 import org.springframework.stereotype.Component;
11 14
 
@@ -25,6 +28,9 @@ public class BrigadeAttendancePersonCountCalculator extends AbstractIndicatorCal
25 28
     @Autowired
26 29
     private TimeDimensionProcessor timeDimensionProcessor;
27 30
 
31
+    @Autowired
32
+    private SysDeptMapper sysDeptMapper;
33
+
28 34
     @Override
29 35
     public BigDecimal calculate(IndicatorCalculationParams params) {
30 36
 
@@ -32,31 +38,42 @@ public class BrigadeAttendancePersonCountCalculator extends AbstractIndicatorCal
32 38
 
33 39
         // 查询指定大队的出勤记录
34 40
         AttendanceRecord record = new AttendanceRecord();
35
-        if (params.getDeptId() != null) {
36
-            // 根据大队ID查询
37
-            record.setBrigadeCode(params.getDeptId().toString());
38
-        }
39 41
         record.setAttendanceDateStart(params.getStartTime());
40 42
         record.setAttendanceDateEnd(params.getEndTime());
41 43
 
44
+        // 根据传入参数决定查询维度:用户 ID > 部门 ID
45
+        if (params.getUserId() != null) {
46
+            // 按个人统计
47
+            record.setUserId(params.getUserId());
48
+        } else if (params.getDeptId() != null) {
49
+            // 按部门统计(大队、科室、班组等)
50
+            SysDept sysDept = sysDeptMapper.selectDeptById(params.getDeptId());
51
+            if (DeptTypeEnum.TEAMS.getCode().equals(sysDept.getDeptType())) {
52
+                record.setTeamCode(params.getDeptId().toString());
53
+            } else if (DeptTypeEnum.MANAGER.getCode().equals(sysDept.getDeptType())) {
54
+                record.setDepartmentCode(params.getDeptId().toString());
55
+            } else if (DeptTypeEnum.BRIGADE.getCode().equals(sysDept.getDeptType())) {
56
+                record.setBrigadeCode(params.getDeptId().toString());
57
+            } else if (DeptTypeEnum.STATION.getCode().equals(sysDept.getDeptType())) {
58
+                record.setStationCode(params.getDeptId().toString());
59
+            }
60
+        }
61
+
42 62
         // 查询考勤记录
43 63
         List<AttendanceRecord> records = attendanceRecordMapper.selectAttendanceRecordList(record);
44 64
 
45
-        // 返回大队出勤人次(去重后的用户数量)
46
-        return new BigDecimal(records.stream()
47
-                .map(AttendanceRecord::getUserId)
48
-                .distinct()
49
-                .count());
65
+        // 返回出勤人次
66
+        return new BigDecimal(records.size());
50 67
     }
51 68
 
52 69
     @Override
53 70
     public String getIndicatorType() {
54
-        return IndicatorTypeEnum.DEPARTMENT_ATTENDANCE_PERSONS.getCode();
71
+        return IndicatorTypeEnum.BRIGADE_ATTENDANCE_PERSONS.getCode();
55 72
     }
56 73
 
57 74
     @Override
58 75
     public String getIndicatorName() {
59
-        return IndicatorTypeEnum.DEPARTMENT_ATTENDANCE_PERSONS.getName();
76
+        return IndicatorTypeEnum.BRIGADE_ATTENDANCE_PERSONS.getName();
60 77
     }
61 78
 
62 79
     @Override

+ 1 - 1
airport-common/src/main/java/com/sundot/airport/common/enums/IndicatorTypeEnum.java

@@ -11,7 +11,7 @@ import lombok.Getter;
11 11
 @AllArgsConstructor
12 12
 public enum IndicatorTypeEnum {
13 13
     ATTENDANCE_PERSONS("attendance_persons", "出勤人次"),
14
-    DEPARTMENT_ATTENDANCE_PERSONS("department_attendance_persons", "科室出勤人次"),
14
+    BRIGADE_ATTENDANCE_PERSONS("brigade_attendance_persons", "大队出勤人次"),
15 15
     ;
16 16
 
17 17
     /**

+ 25 - 0
airport-common/src/main/java/com/sundot/airport/common/statistics/TimeDimensionParams.java

@@ -65,4 +65,29 @@ public class TimeDimensionParams {
65 65
      */
66 66
     @ApiModelProperty(value = "对比周期数")
67 67
     private Integer comparePeriods = 1;
68
+
69
+    /**
70
+     * 大队 ID
71
+     */
72
+    @ApiModelProperty(value = "大队 ID")
73
+    private Long brigadeId;
74
+
75
+    /**
76
+     * 科室 ID
77
+     */
78
+    @ApiModelProperty(value = "科室 ID")
79
+    private Long departmentId;
80
+
81
+    /**
82
+     * 班 ID
83
+     */
84
+    @ApiModelProperty(value = "班 ID")
85
+    private Long teamId;
86
+
87
+    /**
88
+     * 人员 ID
89
+     */
90
+    @ApiModelProperty(value = "人员 ID")
91
+    private Long userId;
92
+
68 93
 }

+ 18 - 5
airport-item/src/main/java/com/sundot/airport/item/domain/dto/QualificationLevelStatsDTO.java

@@ -1,5 +1,6 @@
1 1
 package com.sundot.airport.item.domain.dto;
2 2
 
3
+import com.sundot.airport.system.domain.SysPost;
3 4
 import io.swagger.annotations.ApiModel;
4 5
 import io.swagger.annotations.ApiModelProperty;
5 6
 import lombok.Data;
@@ -109,22 +110,34 @@ public class QualificationLevelStatsDTO implements Serializable {
109 110
         private static final long serialVersionUID = 1L;
110 111
 
111 112
         /**
112
-         * 大队ID
113
+         * 大队ID/用户ID
113 114
          */
114
-        @ApiModelProperty("大队ID")
115
+        @ApiModelProperty("大队ID/用户ID")
115 116
         private Long deptId;
116 117
 
117 118
         /**
118
-         * 大队名称
119
+         * 大队名称/用户姓名
119 120
          */
120
-        @ApiModelProperty("大队名称")
121
+        @ApiModelProperty("大队名称/用户姓名")
121 122
         private String deptName;
122 123
 
123 124
         /**
124
-         * 各等级人数数据
125
+         * 资质等级(个人查询时返回)
126
+         */
127
+        @ApiModelProperty("资质等级")
128
+        private String qualificationLevel;
129
+
130
+        /**
131
+         * 各等级人数数据(部门统计时返回)
125 132
          */
126 133
         @ApiModelProperty("各等级人数数据")
127 134
         private List<LevelCount> levelCounts;
135
+
136
+        /**
137
+         * 可上岗岗位
138
+         */
139
+        @ApiModelProperty("可上岗岗位")
140
+        private List<SysPost> sysPostList;
128 141
     }
129 142
 
130 143
     /**

+ 13 - 0
airport-item/src/main/java/com/sundot/airport/item/domain/home/SeizureReportDTO.java

@@ -76,4 +76,17 @@ public class SeizureReportDTO {
76 76
         private Integer rank;
77 77
     }
78 78
 
79
+    // 用于表示用户排名项的内部类
80
+    @Data
81
+    public static class UserRankingItem {
82
+        @ApiModelProperty("用户姓名")
83
+        private String userName;
84
+        @ApiModelProperty("查获数量")
85
+        private BigDecimal seizureCount;
86
+        @ApiModelProperty("当前排名")
87
+        private Integer currentRank;
88
+        @ApiModelProperty("当前占比")
89
+        private BigDecimal currentRatio;
90
+    }
91
+
79 92
 }

+ 84 - 28
airport-item/src/main/java/com/sundot/airport/item/mapper/ItemCategoryStatsMapper.java

@@ -17,93 +17,149 @@ public interface ItemCategoryStatsMapper {
17 17
     /**
18 18
      * 按一级分类统计全站查获数据
19 19
      *
20
-     * @param stationId 站点ID
21
-     * @param startTime 开始时间
22
-     * @param endTime   结束时间
20
+     * @param stationId    站点ID
21
+     * @param startTime    开始时间
22
+     * @param endTime      结束时间
23
+     * @param brigadeId    大队 ID(可选)
24
+     * @param departmentId 科室 ID(可选)
25
+     * @param teamId       班 ID(可选)
26
+     * @param userId       人员 ID(可选)
23 27
      * @return 分类统计数据列表
24 28
      */
25 29
     List<ItemCategoryStatsDTO.CategoryStat> selectStationCategoryStats(
26 30
             @Param("stationId") Long stationId,
27 31
             @Param("startTime") Date startTime,
28
-            @Param("endTime") Date endTime);
32
+            @Param("endTime") Date endTime,
33
+            @Param("brigadeId") Long brigadeId,
34
+            @Param("departmentId") Long departmentId,
35
+            @Param("teamId") Long teamId,
36
+            @Param("userId") Long userId);
29 37
 
30 38
     /**
31 39
      * 统计全站查获总量
32 40
      *
33
-     * @param stationId 站点ID
34
-     * @param startTime 开始时间
35
-     * @param endTime   结束时间
41
+     * @param stationId    站点ID
42
+     * @param startTime    开始时间
43
+     * @param endTime      结束时间
44
+     * @param brigadeId    大队 ID(可选)
45
+     * @param departmentId 科室 ID(可选)
46
+     * @param teamId       班 ID(可选)
47
+     * @param userId       人员 ID(可选)
36 48
      * @return 总查获数量
37 49
      */
38 50
     Long selectStationTotalQuantity(
39 51
             @Param("stationId") Long stationId,
40 52
             @Param("startTime") Date startTime,
41
-            @Param("endTime") Date endTime);
53
+            @Param("endTime") Date endTime,
54
+            @Param("brigadeId") Long brigadeId,
55
+            @Param("departmentId") Long departmentId,
56
+            @Param("teamId") Long teamId,
57
+            @Param("userId") Long userId);
42 58
 
43 59
     /**
44 60
      * 按部位统计隐匿夹带查获数据
45 61
      *
46
-     * @param stationId 站点ID
47
-     * @param startTime 开始时间
48
-     * @param endTime   结束时间
62
+     * @param stationId    站点ID
63
+     * @param startTime    开始时间
64
+     * @param endTime      结束时间
65
+     * @param brigadeId    大队 ID(可选)
66
+     * @param departmentId 科室 ID(可选)
67
+     * @param teamId       班 ID(可选)
68
+     * @param userId       人员 ID(可选)
49 69
      * @return 部位统计数据列表
50 70
      */
51 71
     List<ItemCategoryStatsDTO.CategoryStat> selectStationConcealmentPositionStats(
52 72
             @Param("stationId") Long stationId,
53 73
             @Param("startTime") Date startTime,
54
-            @Param("endTime") Date endTime);
74
+            @Param("endTime") Date endTime,
75
+            @Param("brigadeId") Long brigadeId,
76
+            @Param("departmentId") Long departmentId,
77
+            @Param("teamId") Long teamId,
78
+            @Param("userId") Long userId);
55 79
 
56 80
     /**
57 81
      * 统计全站隐匿夹带查获总量
58 82
      *
59
-     * @param stationId 站点ID
60
-     * @param startTime 开始时间
61
-     * @param endTime   结束时间
83
+     * @param stationId    站点ID
84
+     * @param startTime    开始时间
85
+     * @param endTime      结束时间
86
+     * @param brigadeId    大队 ID(可选)
87
+     * @param departmentId 科室 ID(可选)
88
+     * @param teamId       班 ID(可选)
89
+     * @param userId       人员 ID(可选)
62 90
      * @return 隐匿夹带总查获数量
63 91
      */
64 92
     Long selectStationConcealmentTotalQuantity(
65 93
             @Param("stationId") Long stationId,
66 94
             @Param("startTime") Date startTime,
67
-            @Param("endTime") Date endTime);
95
+            @Param("endTime") Date endTime,
96
+            @Param("brigadeId") Long brigadeId,
97
+            @Param("departmentId") Long departmentId,
98
+            @Param("teamId") Long teamId,
99
+            @Param("userId") Long userId);
68 100
 
69 101
     /**
70 102
      * 按岗位第二级分类统计查获数据
71 103
      *
72
-     * @param stationId 站点ID
73
-     * @param startTime 开始时间
74
-     * @param endTime   结束时间
104
+     * @param stationId    站点ID
105
+     * @param startTime    开始时间
106
+     * @param endTime      结束时间
107
+     * @param brigadeId    大队 ID(可选)
108
+     * @param departmentId 科室 ID(可选)
109
+     * @param teamId       班 ID(可选)
110
+     * @param userId       人员 ID(可选)
75 111
      * @return 岗位分类统计数据列表
76 112
      */
77 113
     List<ItemCategoryStatsDTO.CategoryStat> selectStationPostCategoryStats(
78 114
             @Param("stationId") Long stationId,
79 115
             @Param("startTime") Date startTime,
80
-            @Param("endTime") Date endTime);
116
+            @Param("endTime") Date endTime,
117
+            @Param("brigadeId") Long brigadeId,
118
+            @Param("departmentId") Long departmentId,
119
+            @Param("teamId") Long teamId,
120
+            @Param("userId") Long userId);
81 121
 
82 122
     /**
83 123
      * 统计全站岗位分类查获总量
84 124
      *
85
-     * @param stationId 站点ID
86
-     * @param startTime 开始时间
87
-     * @param endTime   结束时间
125
+     * @param stationId    站点ID
126
+     * @param startTime    开始时间
127
+     * @param endTime      结束时间
128
+     * @param brigadeId    大队 ID(可选)
129
+     * @param departmentId 科室 ID(可选)
130
+     * @param teamId       班 ID(可选)
131
+     * @param userId       人员 ID(可选)
88 132
      * @return 岗位分类总查获数量
89 133
      */
90 134
     Long selectStationPostCategoryTotalQuantity(
91 135
             @Param("stationId") Long stationId,
92 136
             @Param("startTime") Date startTime,
93
-            @Param("endTime") Date endTime);
137
+            @Param("endTime") Date endTime,
138
+            @Param("brigadeId") Long brigadeId,
139
+            @Param("departmentId") Long departmentId,
140
+            @Param("teamId") Long teamId,
141
+            @Param("userId") Long userId);
94 142
 
95 143
     /**
96 144
      * 查询全站通道排名前五数据
97 145
      *
98
-     * @param stationId 站点ID
99
-     * @param startTime 开始时间
100
-     * @param endTime   结束时间
146
+     * @param stationId    站点ID
147
+     * @param startTime    开始时间
148
+     * @param endTime      结束时间
149
+     * @param brigadeId    大队 ID(可选)
150
+     * @param departmentId 科室 ID(可选)
151
+     * @param teamId       班 ID(可选)
152
+     * @param userId       人员 ID(可选)
101 153
      * @return 通道排名数据列表(前五名)
102 154
      */
103 155
     List<ChannelRankingStatsDTO.ChannelRankingItem> selectTopFiveChannelRankings(
104 156
             @Param("stationId") Long stationId,
105 157
             @Param("startTime") Date startTime,
106
-            @Param("endTime") Date endTime);
158
+            @Param("endTime") Date endTime,
159
+            @Param("brigadeId") Long brigadeId,
160
+            @Param("departmentId") Long departmentId,
161
+            @Param("teamId") Long teamId,
162
+            @Param("userId") Long userId);
107 163
 
108 164
 
109 165
 }

+ 29 - 0
airport-item/src/main/java/com/sundot/airport/item/mapper/SeizureReportMapper.java

@@ -163,6 +163,35 @@ public interface SeizureReportMapper {
163 163
      */
164 164
     public List<SeizureReportDTO.BrigadeRankingItem> selectBrigadeRankings(@Param("deptId") Long deptId, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
165 165
 
166
+    /**
167
+     * 查询科室排名(根据大队 ID)
168
+     *
169
+     * @param brigadeId 大队 ID
170
+     * @param startDate 开始日期
171
+     * @param endDate   结束日期
172
+     * @return 班组排名列表
173
+     */
174
+    public List<SeizureReportDTO.DepartmentRankingItem> selectDepartmentRankingsByBrigadeId(@Param("brigadeId") Long brigadeId, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
175
+
176
+    /**
177
+     * 查询班组排名(根据科室 ID)
178
+     *
179
+     * @param departmentId 科室 ID
180
+     * @param startDate    开始日期
181
+     * @param endDate      结束日期
182
+     * @return 班组排名列表
183
+     */
184
+    public List<SeizureReportDTO.TeamRankingItem> selectTeamRankingsByDepartmentId(@Param("departmentId") Long departmentId, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
185
+
186
+    /**
187
+     * 查询用户排名(根据班组 ID)
188
+     *
189
+     * @param teamId    班组 ID
190
+     * @param startDate 开始日期
191
+     * @param endDate   结束日期
192
+     * @return 用户排名列表
193
+     */
194
+    public List<SeizureReportDTO.UserRankingItem> selectUserRankingsByTeamId(@Param("teamId") Long teamId, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
166 195
 
167 196
     /**
168 197
      * 查询排名前三的班组(不包含排名,排名在Java代码中计算)

+ 165 - 16
airport-item/src/main/java/com/sundot/airport/item/service/impl/ItemCategoryStatsServiceImpl.java

@@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
14 14
 import org.springframework.stereotype.Service;
15 15
 
16 16
 import java.math.BigDecimal;
17
+import java.util.ArrayList;
17 18
 import java.util.List;
18 19
 
19 20
 /**
@@ -45,13 +46,21 @@ public class ItemCategoryStatsServiceImpl implements IItemCategoryStatsService {
45 46
                 itemCategoryStatsMapper.selectStationCategoryStats(
46 47
                         stationId,
47 48
                         timeParams.getStartTime(),
48
-                        timeParams.getEndTime());
49
+                        timeParams.getEndTime(),
50
+                        params.getBrigadeId(),
51
+                        params.getDepartmentId(),
52
+                        params.getTeamId(),
53
+                        params.getUserId());
49 54
 
50 55
         // 查询总数量
51 56
         Long totalQuantity = itemCategoryStatsMapper.selectStationTotalQuantity(
52 57
                 stationId,
53 58
                 timeParams.getStartTime(),
54
-                timeParams.getEndTime());
59
+                timeParams.getEndTime(),
60
+                params.getBrigadeId(),
61
+                params.getDepartmentId(),
62
+                params.getTeamId(),
63
+                params.getUserId());
55 64
 
56 65
 
57 66
         result.setCategoryStats(categoryStats);
@@ -74,13 +83,21 @@ public class ItemCategoryStatsServiceImpl implements IItemCategoryStatsService {
74 83
                 itemCategoryStatsMapper.selectStationConcealmentPositionStats(
75 84
                         stationId,
76 85
                         timeParams.getStartTime(),
77
-                        timeParams.getEndTime());
86
+                        timeParams.getEndTime(),
87
+                        params.getBrigadeId(),
88
+                        params.getDepartmentId(),
89
+                        params.getTeamId(),
90
+                        params.getUserId());
78 91
 
79 92
         // 查询隐匿夹带总数量
80 93
         Long totalQuantity = itemCategoryStatsMapper.selectStationConcealmentTotalQuantity(
81 94
                 stationId,
82 95
                 timeParams.getStartTime(),
83
-                timeParams.getEndTime());
96
+                timeParams.getEndTime(),
97
+                params.getBrigadeId(),
98
+                params.getDepartmentId(),
99
+                params.getTeamId(),
100
+                params.getUserId());
84 101
 
85 102
         // 转换为部位统计格式并计算占比
86 103
         List<ConcealmentPositionStatsDTO.PositionStat> convertedStats = positionStats.stream()
@@ -140,13 +157,21 @@ public class ItemCategoryStatsServiceImpl implements IItemCategoryStatsService {
140 157
                 itemCategoryStatsMapper.selectStationPostCategoryStats(
141 158
                         stationId,
142 159
                         timeParams.getStartTime(),
143
-                        timeParams.getEndTime());
160
+                        timeParams.getEndTime(),
161
+                        params.getBrigadeId(),
162
+                        params.getDepartmentId(),
163
+                        params.getTeamId(),
164
+                        params.getUserId());
144 165
 
145 166
         // 查询岗位分类总数量
146 167
         Long totalQuantity = itemCategoryStatsMapper.selectStationPostCategoryTotalQuantity(
147 168
                 stationId,
148 169
                 timeParams.getStartTime(),
149
-                timeParams.getEndTime());
170
+                timeParams.getEndTime(),
171
+                params.getBrigadeId(),
172
+                params.getDepartmentId(),
173
+                params.getTeamId(),
174
+                params.getUserId());
150 175
 
151 176
         // 转换为岗位统计格式并计算占比
152 177
         List<PostCategoryStatsDTO.PostStat> convertedStats = postStats.stream()
@@ -190,7 +215,11 @@ public class ItemCategoryStatsServiceImpl implements IItemCategoryStatsService {
190 215
                 itemCategoryStatsMapper.selectTopFiveChannelRankings(
191 216
                         stationId,
192 217
                         timeParams.getStartTime(),
193
-                        timeParams.getEndTime());
218
+                        timeParams.getEndTime(),
219
+                        params.getBrigadeId(),
220
+                        params.getDepartmentId(),
221
+                        params.getTeamId(),
222
+                        params.getUserId());
194 223
 
195 224
         // 转换数据类型并设置查获数量
196 225
         List<ChannelRankingStatsDTO.ChannelRankingItem> convertedStats = channelRankings.stream()
@@ -213,15 +242,135 @@ public class ItemCategoryStatsServiceImpl implements IItemCategoryStatsService {
213 242
     public List<SeizureReportDTO.BrigadeRankingItem> getBrigadeRanking(Long topSiteId, TimeDimensionParams params) {
214 243
         // 计算时间范围
215 244
         TimeDimensionParams timeParams = timeDimensionProcessor.calculateTimeRange(params);
216
-        List<SeizureReportDTO.BrigadeRankingItem> brigadeRankings = seizureReportMapper.selectBrigadeRankings(topSiteId, timeParams.getStartTime(), timeParams.getEndTime());
217
-        //计算总查获数量
218
-        BigDecimal totalSeizureQuantity = brigadeRankings.stream().map(item -> item.getSeizureCount()).reduce(BigDecimal.ZERO, BigDecimal::add);
219
-        //计算排名和占比
220
-        brigadeRankings.forEach(item -> {
221
-            item.setCurrentRank(brigadeRankings.indexOf(item) + 1);
222
-            item.setCurrentRatio(totalSeizureQuantity.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : item.getSeizureCount().divide(totalSeizureQuantity, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
223
-        });
224
-        return brigadeRankings;
245
+
246
+        // 根据参数判断返回不同维度的排名
247
+        if (params.getTeamId() != null) {
248
+            // 传入班 ID,返回用户排名和占比
249
+            List<SeizureReportDTO.UserRankingItem> userRankings = seizureReportMapper.selectUserRankingsByTeamId(
250
+                    params.getTeamId(),
251
+                    timeParams.getStartTime(),
252
+                    timeParams.getEndTime());
253
+
254
+            // 计算总查获数量
255
+            BigDecimal totalSeizureQuantity = userRankings.stream()
256
+                    .map(SeizureReportDTO.UserRankingItem::getSeizureCount)
257
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
258
+
259
+            // 计算排名和占比
260
+            return convertUserRankingsToBrigadeRankings(userRankings, totalSeizureQuantity);
261
+        } else if (params.getDepartmentId() != null) {
262
+            // 传入科室 ID,返回班组排名和占比
263
+            List<SeizureReportDTO.TeamRankingItem> teamRankings = seizureReportMapper.selectTeamRankingsByDepartmentId(
264
+                    params.getDepartmentId(),
265
+                    timeParams.getStartTime(),
266
+                    timeParams.getEndTime());
267
+
268
+            // 计算总查获数量
269
+            BigDecimal totalSeizureQuantity = teamRankings.stream()
270
+                    .map(SeizureReportDTO.TeamRankingItem::getSeizureCount)
271
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
272
+
273
+            // 计算排名和占比
274
+            return convertTeamRankingsToBrigadeRankings(teamRankings, totalSeizureQuantity);
275
+        } else if (params.getBrigadeId() != null) {
276
+            // 传入大队 ID,返回科室排名和占比
277
+            List<SeizureReportDTO.DepartmentRankingItem> departmentRankings = seizureReportMapper.selectDepartmentRankingsByBrigadeId(
278
+                    params.getBrigadeId(),
279
+                    timeParams.getStartTime(),
280
+                    timeParams.getEndTime());
281
+
282
+            // 计算总查获数量
283
+            BigDecimal totalSeizureQuantity = departmentRankings.stream()
284
+                    .map(SeizureReportDTO.DepartmentRankingItem::getSeizureCount)
285
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
286
+
287
+            // 计算排名和占比
288
+            return convertDepartmentRankingsToBrigadeRankings(departmentRankings, totalSeizureQuantity);
289
+        } else {
290
+            // 返回大队排名和占比
291
+            List<SeizureReportDTO.BrigadeRankingItem> brigadeRankings = seizureReportMapper.selectBrigadeRankings(
292
+                    topSiteId,
293
+                    timeParams.getStartTime(),
294
+                    timeParams.getEndTime());
295
+
296
+            // 计算总查获数量
297
+            BigDecimal totalSeizureQuantity = brigadeRankings.stream()
298
+                    .map(item -> item.getSeizureCount())
299
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
300
+
301
+            // 计算排名和占比
302
+            for (int i = 0; i < brigadeRankings.size(); i++) {
303
+                SeizureReportDTO.BrigadeRankingItem item = brigadeRankings.get(i);
304
+                item.setCurrentRank(i + 1);
305
+                item.setCurrentRatio(totalSeizureQuantity.compareTo(BigDecimal.ZERO) == 0 ?
306
+                        BigDecimal.ZERO :
307
+                        item.getSeizureCount().divide(totalSeizureQuantity, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
308
+            }
309
+            return brigadeRankings;
310
+        }
311
+    }
312
+
313
+    /**
314
+     * 将用户排名列表转换为大队排名列表格式
315
+     */
316
+    private List<SeizureReportDTO.BrigadeRankingItem> convertUserRankingsToBrigadeRankings(
317
+            List<SeizureReportDTO.UserRankingItem> userRankings, BigDecimal totalSeizureQuantity) {
318
+
319
+        List<SeizureReportDTO.BrigadeRankingItem> result = new ArrayList<>();
320
+        for (int i = 0; i < userRankings.size(); i++) {
321
+            SeizureReportDTO.UserRankingItem userItem = userRankings.get(i);
322
+            SeizureReportDTO.BrigadeRankingItem deptItem = new SeizureReportDTO.BrigadeRankingItem();
323
+            deptItem.setBrigadeName(userItem.getUserName());
324
+            deptItem.setSeizureCount(userItem.getSeizureCount());
325
+            deptItem.setCurrentRank(i + 1);
326
+            deptItem.setCurrentRatio(totalSeizureQuantity.compareTo(BigDecimal.ZERO) == 0 ?
327
+                    BigDecimal.ZERO :
328
+                    userItem.getSeizureCount().divide(totalSeizureQuantity, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
329
+            result.add(deptItem);
330
+        }
331
+        return result;
332
+    }
333
+
334
+    /**
335
+     * 将班组排名列表转换为大队排名列表格式
336
+     */
337
+    private List<SeizureReportDTO.BrigadeRankingItem> convertTeamRankingsToBrigadeRankings(
338
+            List<SeizureReportDTO.TeamRankingItem> teamRankings, BigDecimal totalSeizureQuantity) {
339
+
340
+        List<SeizureReportDTO.BrigadeRankingItem> result = new ArrayList<>();
341
+        for (int i = 0; i < teamRankings.size(); i++) {
342
+            SeizureReportDTO.TeamRankingItem teamItem = teamRankings.get(i);
343
+            SeizureReportDTO.BrigadeRankingItem deptItem = new SeizureReportDTO.BrigadeRankingItem();
344
+            deptItem.setBrigadeName(teamItem.getTeamName());
345
+            deptItem.setSeizureCount(teamItem.getSeizureCount());
346
+            deptItem.setCurrentRank(i + 1);
347
+            deptItem.setCurrentRatio(totalSeizureQuantity.compareTo(BigDecimal.ZERO) == 0 ?
348
+                    BigDecimal.ZERO :
349
+                    teamItem.getSeizureCount().divide(totalSeizureQuantity, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
350
+            result.add(deptItem);
351
+        }
352
+        return result;
353
+    }
354
+
355
+    /**
356
+     * 将科室排名列表转换为大队排名列表格式
357
+     */
358
+    private List<SeizureReportDTO.BrigadeRankingItem> convertDepartmentRankingsToBrigadeRankings(
359
+            List<SeizureReportDTO.DepartmentRankingItem> departmentRankings, BigDecimal totalSeizureQuantity) {
360
+
361
+        List<SeizureReportDTO.BrigadeRankingItem> result = new ArrayList<>();
362
+        for (int i = 0; i < departmentRankings.size(); i++) {
363
+            SeizureReportDTO.DepartmentRankingItem teamItem = departmentRankings.get(i);
364
+            SeizureReportDTO.BrigadeRankingItem deptItem = new SeizureReportDTO.BrigadeRankingItem();
365
+            deptItem.setBrigadeName(teamItem.getDepartmentName());
366
+            deptItem.setSeizureCount(teamItem.getSeizureCount());
367
+            deptItem.setCurrentRank(i + 1);
368
+            deptItem.setCurrentRatio(totalSeizureQuantity.compareTo(BigDecimal.ZERO) == 0 ?
369
+                    BigDecimal.ZERO :
370
+                    teamItem.getSeizureCount().divide(totalSeizureQuantity, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
371
+            result.add(deptItem);
372
+        }
373
+        return result;
225 374
     }
226 375
 
227 376
     /**

+ 268 - 26
airport-item/src/main/java/com/sundot/airport/item/service/impl/ItemLargeScreenServiceImpl.java

@@ -8,6 +8,7 @@ import com.sundot.airport.common.core.domain.GroupedBoxPlotDataDto;
8 8
 import com.sundot.airport.common.core.domain.LargeScreenHomePageUserInfoSqlDto;
9 9
 import com.sundot.airport.common.core.domain.SysUsageReportDto;
10 10
 import com.sundot.airport.common.core.domain.SysUsageReportSeizureDto;
11
+import com.sundot.airport.common.core.domain.entity.SysDept;
11 12
 import com.sundot.airport.common.core.domain.entity.SysUser;
12 13
 import com.sundot.airport.common.dto.BaseCommonDto;
13 14
 import com.sundot.airport.item.domain.*;
@@ -15,6 +16,7 @@ import com.sundot.airport.item.mapper.ItemLargeScreenMapper;
15 16
 import com.sundot.airport.item.mapper.SeizureReportMapper;
16 17
 import com.sundot.airport.item.service.ItemLargeScreenService;
17 18
 import com.sundot.airport.item.service.SeizureDistributionService;
19
+import com.sundot.airport.system.service.ISysDeptService;
18 20
 import com.sundot.airport.system.service.ISysUserService;
19 21
 import org.springframework.beans.factory.annotation.Autowired;
20 22
 import org.springframework.stereotype.Service;
@@ -44,6 +46,8 @@ public class ItemLargeScreenServiceImpl implements ItemLargeScreenService {
44 46
     private SeizureDistributionService seizureDistributionService;
45 47
     @Autowired
46 48
     private SeizureReportMapper seizureReportMapper;
49
+    @Autowired
50
+    private ISysDeptService sysDeptService;
47 51
 
48 52
     /**
49 53
      * 移交公安情况
@@ -365,21 +369,51 @@ public class ItemLargeScreenServiceImpl implements ItemLargeScreenService {
365 369
                 .filter(java.util.Objects::nonNull)
366 370
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
367 371
 
368
-        // 3. 按大队分组统计
369
-        Map<String, List<ItemLargeScreenInfoDto>> groupedByBrigade = policeList.stream()
372
+        // 3. 根据参数判断分组和排序维度
373
+        List<ItemLargeScreenBrigadeRankDto> brigadeRankList;
374
+
375
+        if (dto.getUserId() != null) {
376
+            brigadeRankList = new ArrayList<>();
377
+        } else if (dto.getInspectTeamId() != null) {
378
+            // 传入了班 ID,按个人分组统计
379
+            brigadeRankList = groupAndRankByUser(policeList, totalQuantity);
380
+        } else if (dto.getInspectDepartmentId() != null) {
381
+            // 传入了科室 ID,按班组分组统计
382
+            brigadeRankList = groupAndRankByTeam(policeList, totalQuantity);
383
+        } else if (dto.getInspectBrigadeId() != null) {
384
+            // 默认(站级别),按科室分组统计
385
+            brigadeRankList = groupAndRankByDepartment(policeList, totalQuantity);
386
+        } else {
387
+            brigadeRankList = groupAndRankByBrigade(policeList, totalQuantity);
388
+        }
389
+
390
+        // 4. 构造返回结果
391
+        ItemLargeScreenPoliceStatsDto result = new ItemLargeScreenPoliceStatsDto();
392
+        result.setTotalQuantity(totalQuantity);
393
+        result.setBrigadeRankList(brigadeRankList);
394
+
395
+        return result;
396
+    }
397
+
398
+    /**
399
+     * 按大队分组统计并排序(站级别使用)
400
+     */
401
+    private List<ItemLargeScreenBrigadeRankDto> groupAndRankByBrigade(List<ItemLargeScreenInfoDto> dataList, BigDecimal totalQuantity) {
402
+        // 按科室分组
403
+        Map<String, List<ItemLargeScreenInfoDto>> groupedByBrigade = dataList.stream()
370 404
                 .collect(Collectors.groupingBy(item ->
371 405
                         item.getInspectBrigadeId() + "###" + item.getInspectBrigadeName()));
372 406
 
373
-        // 4. 转换为大队排名列表
374
-        List<ItemLargeScreenBrigadeRankDto> brigadeRankList = groupedByBrigade.entrySet().stream()
407
+        // 转换为科室排名列表
408
+        List<ItemLargeScreenBrigadeRankDto> rankList = groupedByBrigade.entrySet().stream()
375 409
                 .map(entry -> {
376 410
                     ItemLargeScreenBrigadeRankDto rankDto = new ItemLargeScreenBrigadeRankDto();
377 411
                     List<ItemLargeScreenInfoDto> items = entry.getValue();
378 412
 
379 413
                     if (!items.isEmpty()) {
380 414
                         ItemLargeScreenInfoDto firstItem = items.get(0);
381
-                        rankDto.setBrigadeId(firstItem.getInspectBrigadeId());
382
-                        rankDto.setBrigadeName(firstItem.getInspectBrigadeName());
415
+                        rankDto.setBrigadeId(firstItem.getInspectDepartmentId());
416
+                        rankDto.setBrigadeName(firstItem.getInspectDepartmentName());
383 417
 
384 418
                         // 计算该科室的查获总数量
385 419
                         BigDecimal deptQuantity = items.stream()
@@ -402,17 +436,159 @@ public class ItemLargeScreenServiceImpl implements ItemLargeScreenService {
402 436
                 .sorted(Comparator.comparing(ItemLargeScreenBrigadeRankDto::getQuantity).reversed())
403 437
                 .collect(Collectors.toList());
404 438
 
405
-        // 5. 设置排名
406
-        for (int i = 0; i < brigadeRankList.size(); i++) {
407
-            brigadeRankList.get(i).setRank(i + 1);
439
+        // 设置排名
440
+        for (int i = 0; i < rankList.size(); i++) {
441
+            rankList.get(i).setRank(i + 1);
408 442
         }
409 443
 
410
-        // 6. 构造返回结果
411
-        ItemLargeScreenPoliceStatsDto result = new ItemLargeScreenPoliceStatsDto();
412
-        result.setTotalQuantity(totalQuantity);
413
-        result.setBrigadeRankList(brigadeRankList);
444
+        return rankList;
445
+    }
414 446
 
415
-        return result;
447
+    /**
448
+     * 按科室分组统计并排序(大队级别使用)
449
+     */
450
+    private List<ItemLargeScreenBrigadeRankDto> groupAndRankByDepartment(List<ItemLargeScreenInfoDto> dataList, BigDecimal totalQuantity) {
451
+        // 按科室分组
452
+        Map<String, List<ItemLargeScreenInfoDto>> groupedByDepartment = dataList.stream()
453
+                .collect(Collectors.groupingBy(item ->
454
+                        item.getInspectDepartmentId() + "###" + item.getInspectDepartmentName()));
455
+
456
+        // 转换为科室排名列表
457
+        List<ItemLargeScreenBrigadeRankDto> rankList = groupedByDepartment.entrySet().stream()
458
+                .map(entry -> {
459
+                    ItemLargeScreenBrigadeRankDto rankDto = new ItemLargeScreenBrigadeRankDto();
460
+                    List<ItemLargeScreenInfoDto> items = entry.getValue();
461
+
462
+                    if (!items.isEmpty()) {
463
+                        ItemLargeScreenInfoDto firstItem = items.get(0);
464
+                        rankDto.setBrigadeId(firstItem.getInspectDepartmentId());
465
+                        rankDto.setBrigadeName(firstItem.getInspectDepartmentName());
466
+
467
+                        // 计算该科室的查获总数量
468
+                        BigDecimal deptQuantity = items.stream()
469
+                                .map(ItemLargeScreenInfoDto::getQuantity)
470
+                                .filter(java.util.Objects::nonNull)
471
+                                .reduce(BigDecimal.ZERO, BigDecimal::add);
472
+                        rankDto.setQuantity(deptQuantity);
473
+
474
+                        // 计算占比
475
+                        if (totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
476
+                            rankDto.setScale(deptQuantity.multiply(new BigDecimal("100"))
477
+                                    .divide(totalQuantity, 2, BigDecimal.ROUND_HALF_UP));
478
+                        } else {
479
+                            rankDto.setScale(BigDecimal.ZERO);
480
+                        }
481
+                    }
482
+
483
+                    return rankDto;
484
+                })
485
+                .sorted(Comparator.comparing(ItemLargeScreenBrigadeRankDto::getQuantity).reversed())
486
+                .collect(Collectors.toList());
487
+
488
+        // 设置排名
489
+        for (int i = 0; i < rankList.size(); i++) {
490
+            rankList.get(i).setRank(i + 1);
491
+        }
492
+
493
+        return rankList;
494
+    }
495
+
496
+    /**
497
+     * 按班组分组统计并排序
498
+     */
499
+    private List<ItemLargeScreenBrigadeRankDto> groupAndRankByTeam(List<ItemLargeScreenInfoDto> dataList, BigDecimal totalQuantity) {
500
+        // 按班组分组
501
+        Map<String, List<ItemLargeScreenInfoDto>> groupedByTeam = dataList.stream()
502
+                .collect(Collectors.groupingBy(item ->
503
+                        item.getInspectTeamId() + "###" + item.getInspectTeamName()));
504
+
505
+        // 转换为班组排名列表
506
+        List<ItemLargeScreenBrigadeRankDto> rankList = groupedByTeam.entrySet().stream()
507
+                .map(entry -> {
508
+                    ItemLargeScreenBrigadeRankDto rankDto = new ItemLargeScreenBrigadeRankDto();
509
+                    List<ItemLargeScreenInfoDto> items = entry.getValue();
510
+
511
+                    if (!items.isEmpty()) {
512
+                        ItemLargeScreenInfoDto firstItem = items.get(0);
513
+                        rankDto.setBrigadeId(firstItem.getInspectTeamId());
514
+                        rankDto.setBrigadeName(firstItem.getInspectTeamName());
515
+
516
+                        // 计算该班组的查获总数量
517
+                        BigDecimal teamQuantity = items.stream()
518
+                                .map(ItemLargeScreenInfoDto::getQuantity)
519
+                                .filter(java.util.Objects::nonNull)
520
+                                .reduce(BigDecimal.ZERO, BigDecimal::add);
521
+                        rankDto.setQuantity(teamQuantity);
522
+
523
+                        // 计算占比
524
+                        if (totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
525
+                            rankDto.setScale(teamQuantity.multiply(new BigDecimal("100"))
526
+                                    .divide(totalQuantity, 2, BigDecimal.ROUND_HALF_UP));
527
+                        } else {
528
+                            rankDto.setScale(BigDecimal.ZERO);
529
+                        }
530
+                    }
531
+
532
+                    return rankDto;
533
+                })
534
+                .sorted(Comparator.comparing(ItemLargeScreenBrigadeRankDto::getQuantity).reversed())
535
+                .collect(Collectors.toList());
536
+
537
+        // 设置排名
538
+        for (int i = 0; i < rankList.size(); i++) {
539
+            rankList.get(i).setRank(i + 1);
540
+        }
541
+
542
+        return rankList;
543
+    }
544
+
545
+    /**
546
+     * 按个人分组统计并排序
547
+     */
548
+    private List<ItemLargeScreenBrigadeRankDto> groupAndRankByUser(List<ItemLargeScreenInfoDto> dataList, BigDecimal totalQuantity) {
549
+        // 按个人分组
550
+        Map<String, List<ItemLargeScreenInfoDto>> groupedByUser = dataList.stream()
551
+                .collect(Collectors.groupingBy(item ->
552
+                        item.getInspectUserId() + "###" + item.getInspectUserName()));
553
+
554
+        // 转换为个人排名列表
555
+        List<ItemLargeScreenBrigadeRankDto> rankList = groupedByUser.entrySet().stream()
556
+                .map(entry -> {
557
+                    ItemLargeScreenBrigadeRankDto rankDto = new ItemLargeScreenBrigadeRankDto();
558
+                    List<ItemLargeScreenInfoDto> items = entry.getValue();
559
+
560
+                    if (!items.isEmpty()) {
561
+                        ItemLargeScreenInfoDto firstItem = items.get(0);
562
+                        rankDto.setBrigadeId(firstItem.getInspectUserId());
563
+                        rankDto.setBrigadeName(firstItem.getInspectUserName());
564
+
565
+                        // 计算个人的查获总数量
566
+                        BigDecimal userQuantity = items.stream()
567
+                                .map(ItemLargeScreenInfoDto::getQuantity)
568
+                                .filter(java.util.Objects::nonNull)
569
+                                .reduce(BigDecimal.ZERO, BigDecimal::add);
570
+                        rankDto.setQuantity(userQuantity);
571
+
572
+                        // 计算占比
573
+                        if (totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
574
+                            rankDto.setScale(userQuantity.multiply(new BigDecimal("100"))
575
+                                    .divide(totalQuantity, 2, BigDecimal.ROUND_HALF_UP));
576
+                        } else {
577
+                            rankDto.setScale(BigDecimal.ZERO);
578
+                        }
579
+                    }
580
+
581
+                    return rankDto;
582
+                })
583
+                .sorted(Comparator.comparing(ItemLargeScreenBrigadeRankDto::getQuantity).reversed())
584
+                .collect(Collectors.toList());
585
+
586
+        // 设置排名
587
+        for (int i = 0; i < rankList.size(); i++) {
588
+            rankList.get(i).setRank(i + 1);
589
+        }
590
+
591
+        return rankList;
416 592
     }
417 593
 
418 594
     /**
@@ -457,15 +633,48 @@ public class ItemLargeScreenServiceImpl implements ItemLargeScreenService {
457 633
         BigDecimal lowerBound = BigDecimal.ZERO;
458 634
         BigDecimal upperBound = BigDecimal.ZERO;
459 635
 
460
-        if (!boxPlotDataList.isEmpty()) {
461
-            BoxPlotDataDto boxPlotData = boxPlotDataList.get(0).getBoxPlotData();
462
-            lowerBound = boxPlotData.getLowerBound();
463
-            upperBound = boxPlotData.getUpperBound();
636
+        if (dto.getInspectBrigadeId() != null) {
637
+            // 根据 id 获取部门信息
638
+            SysDept dept = sysDeptService.selectDeptById(dto.getInspectBrigadeId());
639
+            if (Objects.isNull(dept)) {
640
+                return Collections.emptyList();
641
+            }
642
+
643
+            // 查找匹配的分组数据
644
+            Optional<GroupedBoxPlotDataDto> matchedGroup = boxPlotDataList.stream()
645
+                    .filter(grouped -> Objects.equals(grouped.getGroupName(), dept.getDeptName()))
646
+                    .findFirst();
647
+
648
+            if (matchedGroup.isPresent()) {
649
+                BoxPlotDataDto boxPlotData = matchedGroup.get().getBoxPlotData();
650
+                if (Objects.nonNull(boxPlotData)) {
651
+                    lowerBound = boxPlotData.getLowerBound();
652
+                    upperBound = boxPlotData.getUpperBound();
653
+                }
654
+            }
655
+        } else {
656
+            GroupedBoxPlotDataDto firstGroup = boxPlotDataList.get(0);
657
+            if (Objects.nonNull(firstGroup) && Objects.nonNull(firstGroup.getBoxPlotData())) {
658
+                BoxPlotDataDto boxPlotData = firstGroup.getBoxPlotData();
659
+                lowerBound = boxPlotData.getLowerBound();
660
+                upperBound = boxPlotData.getUpperBound();
661
+            }
464 662
         }
465 663
 
664
+
466 665
         // 3. 查询用户信息和查获数量
467
-        List<ItemLargeScreenHomePageSeizureReportSqlDto> seizureReportList = seizureReportMapper.homePageSeizureReport(dto);
468
-        List<LargeScreenHomePageUserInfoSqlDto> userInfoList = sysUserService.homePageUserInfo();
666
+        List<ItemLargeScreenHomePageSeizureReportSqlDto> seizureReportList;
667
+        List<LargeScreenHomePageUserInfoSqlDto> userInfoList;
668
+
669
+        if (dto.getInspectBrigadeId() != null) {
670
+            // 有大队 ID,查询大队数据
671
+            seizureReportList = seizureReportMapper.homePageSeizureReportBrigadeId(dto);
672
+            userInfoList = sysUserService.homePageUserInfoByBrigadeId(dto.getInspectBrigadeId());
673
+        } else {
674
+            // 无大队 ID,查询全站数据
675
+            seizureReportList = seizureReportMapper.homePageSeizureReport(dto);
676
+            userInfoList = sysUserService.homePageUserInfo();
677
+        }
469 678
 
470 679
         if (CollUtil.isEmpty(seizureReportList) || CollUtil.isEmpty(userInfoList)) {
471 680
             return Collections.emptyList();
@@ -519,15 +728,48 @@ public class ItemLargeScreenServiceImpl implements ItemLargeScreenService {
519 728
         BigDecimal lowerBound = BigDecimal.ZERO;
520 729
         BigDecimal upperBound = BigDecimal.ZERO;
521 730
 
522
-        if (!boxPlotDataList.isEmpty()) {
523
-            BoxPlotDataDto boxPlotData = boxPlotDataList.get(0).getBoxPlotData();
524
-            lowerBound = boxPlotData.getLowerBound();
525
-            upperBound = boxPlotData.getUpperBound();
731
+
732
+        if (dto.getInspectBrigadeId() != null) {
733
+            // 根据 id 获取部门信息
734
+            SysDept dept = sysDeptService.selectDeptById(dto.getInspectBrigadeId());
735
+            if (Objects.isNull(dept)) {
736
+                return result;
737
+            }
738
+
739
+            // 查找匹配的分组数据
740
+            Optional<GroupedBoxPlotDataDto> matchedGroup = boxPlotDataList.stream()
741
+                    .filter(grouped -> Objects.equals(grouped.getGroupName(), dept.getDeptName()))
742
+                    .findFirst();
743
+
744
+            if (matchedGroup.isPresent()) {
745
+                BoxPlotDataDto boxPlotData = matchedGroup.get().getBoxPlotData();
746
+                if (Objects.nonNull(boxPlotData)) {
747
+                    lowerBound = boxPlotData.getLowerBound();
748
+                    upperBound = boxPlotData.getUpperBound();
749
+                }
750
+            }
751
+        } else {
752
+            GroupedBoxPlotDataDto firstGroup = boxPlotDataList.get(0);
753
+            if (Objects.nonNull(firstGroup) && Objects.nonNull(firstGroup.getBoxPlotData())) {
754
+                BoxPlotDataDto boxPlotData = firstGroup.getBoxPlotData();
755
+                lowerBound = boxPlotData.getLowerBound();
756
+                upperBound = boxPlotData.getUpperBound();
757
+            }
526 758
         }
527 759
 
528 760
         // 3. 查询用户信息和查获数量
529
-        List<ItemLargeScreenHomePageSeizureReportSqlDto> seizureReportList = seizureReportMapper.homePageSeizureReport(dto);
530
-        List<LargeScreenHomePageUserInfoSqlDto> userInfoList = sysUserService.homePageUserInfo();
761
+        List<ItemLargeScreenHomePageSeizureReportSqlDto> seizureReportList;
762
+        List<LargeScreenHomePageUserInfoSqlDto> userInfoList;
763
+
764
+        if (dto.getInspectDepartmentId() != null) {
765
+            // 有大队 ID,查询大队数据
766
+            seizureReportList = seizureReportMapper.homePageSeizureReportBrigadeId(dto);
767
+            userInfoList = sysUserService.homePageUserInfoByBrigadeId(dto.getInspectBrigadeId());
768
+        } else {
769
+            // 无大队 ID,查询全站数据
770
+            seizureReportList = seizureReportMapper.homePageSeizureReport(dto);
771
+            userInfoList = sysUserService.homePageUserInfo();
772
+        }
531 773
 
532 774
         if (CollUtil.isEmpty(seizureReportList) || CollUtil.isEmpty(userInfoList)) {
533 775
             return result;

+ 119 - 56
airport-item/src/main/resources/mapper/item/ItemCategoryStatsMapper.xml

@@ -8,16 +8,25 @@
8 8
     <select id="selectStationCategoryStats"
9 9
             resultType="com.sundot.airport.item.domain.dto.ItemCategoryStatsDTO$CategoryStat">
10 10
         SELECT isi.category_code_one AS categoryCodeOne,
11
-               isi.category_name_one AS categoryNameOne,
12
-               SUM(isi.quantity)     AS quantity
11
+        isi.category_name_one AS categoryNameOne,
12
+        SUM(isi.quantity) AS quantity
13 13
         FROM item_seizure_record isr
14
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
14
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
15 15
         WHERE isr.inspect_station_id = #{stationId}
16
-          AND isr.seizure_time >= #{startTime}
17
-          AND isr.seizure_time &lt;= #{endTime}
18
-          AND isr.process_status = '3' -- 已归档状态
19
-          AND isi.category_code_one IS NOT NULL
20
-          AND isi.category_name_one IS NOT NULL
16
+        AND isr.seizure_time >= #{startTime}
17
+        AND isr.seizure_time &lt;= #{endTime}
18
+        AND isr.process_status = '3' -- 已归档状态
19
+        AND isi.category_code_one IS NOT NULL
20
+        AND isi.category_name_one IS NOT NULL
21
+        <if test="departmentId != null">
22
+            AND isr.inspect_department_id = #{departmentId}
23
+        </if>
24
+        <if test="teamId != null">
25
+            AND isr.inspect_team_id = #{teamId}
26
+        </if>
27
+        <if test="userId != null">
28
+            AND isr.inspect_user_id = #{userId}
29
+        </if>
21 30
         GROUP BY isi.category_code_one, isi.category_name_one
22 31
         ORDER BY quantity DESC
23 32
     </select>
@@ -26,28 +35,46 @@
26 35
     <select id="selectStationTotalQuantity" resultType="java.lang.Long">
27 36
         SELECT IFNULL(SUM(isi.quantity), 0)
28 37
         FROM item_seizure_record isr
29
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
38
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
30 39
         WHERE isr.inspect_station_id = #{stationId}
31
-          AND isr.seizure_time >= #{startTime}
32
-          AND isr.seizure_time &lt;= #{endTime}
33
-          AND isr.process_status = '3' -- 已归档状态
40
+        AND isr.seizure_time >= #{startTime}
41
+        AND isr.seizure_time &lt;= #{endTime}
42
+        AND isr.process_status = '3' -- 已归档状态
43
+        <if test="departmentId != null">
44
+            AND isr.inspect_department_id = #{departmentId}
45
+        </if>
46
+        <if test="teamId != null">
47
+            AND isr.inspect_team_id = #{teamId}
48
+        </if>
49
+        <if test="userId != null">
50
+            AND isr.inspect_user_id = #{userId}
51
+        </if>
34 52
     </select>
35 53
 
36 54
     <!-- 按部位统计隐匿夹带查获数据 -->
37 55
     <select id="selectStationConcealmentPositionStats"
38 56
             resultType="com.sundot.airport.item.domain.dto.ItemCategoryStatsDTO$CategoryStat">
39 57
         SELECT isi.check_position_code_two AS categoryCodeOne,
40
-               isi.check_position_name_two AS categoryNameOne,
41
-               SUM(isi.quantity)           AS quantity
58
+        isi.check_position_name_two AS categoryNameOne,
59
+        SUM(isi.quantity) AS quantity
42 60
         FROM item_seizure_record isr
43
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
61
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
44 62
         WHERE isr.inspect_station_id = #{stationId}
45
-          AND isr.seizure_time >= #{startTime}
46
-          AND isr.seizure_time &lt;= #{endTime}
47
-          AND isr.process_status = '3'      -- 已归档状态
48
-          AND isi.is_active_concealment = 1 -- 是否隐匿夹带为"是"
49
-          AND isi.check_position_code_two IS NOT NULL
50
-          AND isi.check_position_name_two IS NOT NULL
63
+        AND isr.seizure_time >= #{startTime}
64
+        AND isr.seizure_time &lt;= #{endTime}
65
+        AND isr.process_status = '3' -- 已归档状态
66
+        AND isi.is_active_concealment = 1 -- 是否隐匿夹带为"是"
67
+        AND isi.check_position_code_two IS NOT NULL
68
+        AND isi.check_position_name_two IS NOT NULL
69
+        <if test="departmentId != null">
70
+            AND isr.inspect_department_id = #{departmentId}
71
+        </if>
72
+        <if test="teamId != null">
73
+            AND isr.inspect_team_id = #{teamId}
74
+        </if>
75
+        <if test="userId != null">
76
+            AND isr.inspect_user_id = #{userId}
77
+        </if>
51 78
         GROUP BY isi.check_position_code_two, isi.check_position_name_two
52 79
         ORDER BY quantity DESC
53 80
     </select>
@@ -56,28 +83,46 @@
56 83
     <select id="selectStationConcealmentTotalQuantity" resultType="java.lang.Long">
57 84
         SELECT IFNULL(SUM(isi.quantity), 0)
58 85
         FROM item_seizure_record isr
59
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
86
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
60 87
         WHERE isr.inspect_station_id = #{stationId}
61
-          AND isr.seizure_time >= #{startTime}
62
-          AND isr.seizure_time &lt;= #{endTime}
63
-          AND isr.process_status = '3' -- 已归档状态
64
-          AND isi.is_active_concealment = 1 -- 是否隐匿夹带为"是"
88
+        AND isr.seizure_time >= #{startTime}
89
+        AND isr.seizure_time &lt;= #{endTime}
90
+        AND isr.process_status = '3' -- 已归档状态
91
+        AND isi.is_active_concealment = 1 -- 是否隐匿夹带为"是"
92
+        <if test="departmentId != null">
93
+            AND isr.inspect_department_id = #{departmentId}
94
+        </if>
95
+        <if test="teamId != null">
96
+            AND isr.inspect_team_id = #{teamId}
97
+        </if>
98
+        <if test="userId != null">
99
+            AND isr.inspect_user_id = #{userId}
100
+        </if>
65 101
     </select>
66 102
 
67 103
     <!-- 按岗位第二级分类统计查获数据 -->
68 104
     <select id="selectStationPostCategoryStats"
69 105
             resultType="com.sundot.airport.item.domain.dto.ItemCategoryStatsDTO$CategoryStat">
70
-        SELECT isr.check_method      AS categoryCodeOne,
71
-               isr.check_method_desc AS categoryNameOne,
72
-               SUM(isi.quantity)     AS quantity
106
+        SELECT isr.check_method AS categoryCodeOne,
107
+        isr.check_method_desc AS categoryNameOne,
108
+        SUM(isi.quantity) AS quantity
73 109
         FROM item_seizure_record isr
74
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
110
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
75 111
         WHERE isr.inspect_station_id = #{stationId}
76
-          AND isr.seizure_time >= #{startTime}
77
-          AND isr.seizure_time &lt;= #{endTime}
78
-          AND isr.process_status = '3' -- 已归档状态
79
-          AND isr.check_method IS NOT NULL
80
-          AND isr.check_method_desc IS NOT NULL
112
+        AND isr.seizure_time >= #{startTime}
113
+        AND isr.seizure_time &lt;= #{endTime}
114
+        AND isr.process_status = '3' -- 已归档状态
115
+        AND isr.check_method IS NOT NULL
116
+        AND isr.check_method_desc IS NOT NULL
117
+        <if test="departmentId != null">
118
+            AND isr.inspect_department_id = #{departmentId}
119
+        </if>
120
+        <if test="teamId != null">
121
+            AND isr.inspect_team_id = #{teamId}
122
+        </if>
123
+        <if test="userId != null">
124
+            AND isr.inspect_user_id = #{userId}
125
+        </if>
81 126
         GROUP BY isr.check_method, isr.check_method_desc
82 127
         ORDER BY quantity DESC
83 128
     </select>
@@ -86,33 +131,51 @@
86 131
     <select id="selectStationPostCategoryTotalQuantity" resultType="java.lang.Long">
87 132
         SELECT IFNULL(SUM(isi.quantity), 0)
88 133
         FROM item_seizure_record isr
89
-                 LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
134
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
90 135
         WHERE isr.inspect_station_id = #{stationId}
91
-          AND isr.seizure_time >= #{startTime}
92
-          AND isr.seizure_time &lt;= #{endTime}
93
-          AND isr.process_status = '3' -- 已归档状态
136
+        AND isr.seizure_time >= #{startTime}
137
+        AND isr.seizure_time &lt;= #{endTime}
138
+        AND isr.process_status = '3' -- 已归档状态
139
+        <if test="departmentId != null">
140
+            AND isr.inspect_department_id = #{departmentId}
141
+        </if>
142
+        <if test="teamId != null">
143
+            AND isr.inspect_team_id = #{teamId}
144
+        </if>
145
+        <if test="userId != null">
146
+            AND isr.inspect_user_id = #{userId}
147
+        </if>
94 148
     </select>
95 149
 
96 150
     <!-- 查询全站通道排名前五数据 -->
97 151
     <select id="selectTopFiveChannelRankings"
98 152
             resultType="com.sundot.airport.item.domain.dto.ChannelRankingStatsDTO$ChannelRankingItem">
99 153
         SELECT t.channelName,
100
-               t.seizureQuantity,
101
-               t.regionalName,
102
-               (@row_number := @row_number + 1) AS ranking
103
-        FROM (SELECT isr.channel_name  AS channelName,
104
-                     SUM(isi.quantity) AS seizureQuantity,
105
-                     isr.regional_name AS regionalName
106
-              FROM item_seizure_record isr
107
-                       LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
108
-              WHERE isr.inspect_station_id = #{stationId}
109
-                AND isr.seizure_time >= #{startTime}
110
-                AND isr.seizure_time &lt;= #{endTime}
111
-                AND isr.process_status = '3' -- 已归档状态
112
-                AND isr.channel_name IS NOT NULL
113
-                AND isr.regional_name IS NOT NULL
114
-              GROUP BY isr.channel_name, isr.regional_name
115
-              ORDER BY seizureQuantity DESC LIMIT 5) t
116
-                 CROSS JOIN (SELECT @row_number := 0) r
154
+        t.seizureQuantity,
155
+        t.regionalName,
156
+        (@row_number := @row_number + 1) AS ranking
157
+        FROM (SELECT isr.channel_name AS channelName,
158
+        SUM(isi.quantity) AS seizureQuantity,
159
+        isr.regional_name AS regionalName
160
+        FROM item_seizure_record isr
161
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
162
+        WHERE isr.inspect_station_id = #{stationId}
163
+        AND isr.seizure_time >= #{startTime}
164
+        AND isr.seizure_time &lt;= #{endTime}
165
+        AND isr.process_status = '3' -- 已归档状态
166
+        AND isr.channel_name IS NOT NULL
167
+        AND isr.regional_name IS NOT NULL
168
+        <if test="departmentId != null">
169
+            AND isr.inspect_department_id = #{departmentId}
170
+        </if>
171
+        <if test="teamId != null">
172
+            AND isr.inspect_team_id = #{teamId}
173
+        </if>
174
+        <if test="userId != null">
175
+            AND isr.inspect_user_id = #{userId}
176
+        </if>
177
+        GROUP BY isr.channel_name, isr.regional_name
178
+        ORDER BY seizureQuantity DESC LIMIT 5) t
179
+        CROSS JOIN (SELECT @row_number := 0) r
117 180
     </select>
118 181
 </mapper>

+ 20 - 0
airport-item/src/main/resources/mapper/item/ItemLargeScreenMapper.xml

@@ -74,6 +74,7 @@
74 74
         <if test="inspectBrigadeId != null">and isr.inspect_brigade_id = #{inspectBrigadeId}</if>
75 75
         <if test="inspectDepartmentId != null">and isr.inspect_department_id = #{inspectDepartmentId}</if>
76 76
         <if test="inspectTeamId != null">and isr.inspect_team_id = #{inspectTeamId}</if>
77
+        <if test="userId != null">and isr.inspect_user_id = #{userId}</if>
77 78
         and isr.process_status=3
78 79
         order by isr.seizure_time desc
79 80
     </select>
@@ -398,6 +399,7 @@
398 399
         <if test="inspectBrigadeId != null">and isr.inspect_brigade_id = #{inspectBrigadeId}</if>
399 400
         <if test="inspectDepartmentId != null">and isr.inspect_department_id = #{inspectDepartmentId}</if>
400 401
         <if test="inspectTeamId != null">and isr.inspect_team_id = #{inspectTeamId}</if>
402
+        <if test="userId != null">and isr.inspect_user_id = #{userId}</if>
401 403
         <if test="isPolice=='1' or isPolice==1 ">and isi.handling_method = 'TRANSFER_TO_AIRPORT_POLICE'</if>
402 404
         <if test="isConceal=='1' or  isConceal==1 ">and isi.is_active_concealment = 1</if>
403 405
         group by hours.hour
@@ -703,6 +705,15 @@
703 705
         <if test="inspectStationId != null">
704 706
             and isr.inspect_station_id = #{inspectStationId}
705 707
         </if>
708
+        <if test="inspectBrigadeId != null">
709
+            and isr.inspect_brigade_id = #{inspectBrigadeId}
710
+        </if>
711
+        <if test="inspectDepartmentId != null">
712
+            and isr.inspect_department_id = #{inspectDepartmentId}
713
+        </if>
714
+        <if test="inspectTeamId != null">
715
+            and isr.inspect_team_id = #{inspectTeamId}
716
+        </if>
706 717
         and isr.process_status = 3
707 718
         order by isr.seizure_time desc
708 719
     </select>
@@ -726,6 +737,15 @@
726 737
         <if test="inspectStationId != null">
727 738
             and isr.inspect_station_id = #{inspectStationId}
728 739
         </if>
740
+        <if test="inspectBrigadeId != null">
741
+            and isr.inspect_brigade_id = #{inspectBrigadeId}
742
+        </if>
743
+        <if test="inspectDepartmentId != null">
744
+            and isr.inspect_department_id = #{inspectDepartmentId}
745
+        </if>
746
+        <if test="inspectTeamId != null">
747
+            and isr.inspect_team_id = #{inspectTeamId}
748
+        </if>
729 749
         and isr.process_status = 3
730 750
         and isr.xray_operator_id is not null
731 751
         group by isr.xray_operator_id, isr.xray_operator_name

+ 59 - 0
airport-item/src/main/resources/mapper/item/SeizureReportMapper.xml

@@ -254,6 +254,65 @@
254 254
         ORDER BY seizureCount DESC
255 255
     </select>
256 256
 
257
+    <!-- 查询科室排名(根据大队 ID) -->
258
+    <select id="selectDepartmentRankingsByBrigadeId"
259
+            resultType="com.sundot.airport.item.domain.home.SeizureReportDTO$DepartmentRankingItem">
260
+        SELECT
261
+        sd.dept_name AS departmentName,
262
+        COALESCE(SUM(isi.quantity), 0) AS seizureCount
263
+        FROM sys_dept sd
264
+        LEFT JOIN item_seizure_record isr ON sd.dept_id = isr.inspect_team_id
265
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
266
+        AND isr.process_status = 3
267
+        <if test="startDate != null and endDate != null">
268
+            AND isr.create_time BETWEEN #{startDate} AND #{endDate}
269
+        </if>
270
+        WHERE sd.parent_id = #{brigadeId} -- 大队 ID
271
+        AND sd.del_flag = '0'
272
+        AND sd.dept_type = 'MANAGER' -- 确保是科室
273
+        GROUP BY sd.dept_id, sd.dept_name
274
+        ORDER BY seizureCount DESC
275
+    </select>
276
+
277
+    <!-- 查询班组排名(根据科室 ID) -->
278
+    <select id="selectTeamRankingsByDepartmentId"
279
+            resultType="com.sundot.airport.item.domain.home.SeizureReportDTO$TeamRankingItem">
280
+        SELECT
281
+        sd.dept_name AS teamName,
282
+        COALESCE(SUM(isi.quantity), 0) AS seizureCount
283
+        FROM sys_dept sd
284
+        LEFT JOIN item_seizure_record isr ON sd.dept_id = isr.inspect_team_id
285
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
286
+        AND isr.process_status = 3
287
+        <if test="startDate != null and endDate != null">
288
+            AND isr.create_time BETWEEN #{startDate} AND #{endDate}
289
+        </if>
290
+        WHERE sd.parent_id = #{departmentId} -- 科室 ID
291
+        AND sd.del_flag = '0'
292
+        AND sd.dept_type = 'TEAMS' -- 确保是班组
293
+        GROUP BY sd.dept_id, sd.dept_name
294
+        ORDER BY seizureCount DESC
295
+    </select>
296
+
297
+    <!-- 查询用户排名(根据班组 ID) -->
298
+    <select id="selectUserRankingsByTeamId"
299
+            resultType="com.sundot.airport.item.domain.home.SeizureReportDTO$UserRankingItem">
300
+        SELECT
301
+        su.nick_name AS userName,
302
+        COALESCE(SUM(isi.quantity), 0) AS seizureCount
303
+        from sys_user su
304
+        LEFT JOIN item_seizure_record isr ON su.user_id = isr.inspect_user_id
305
+        LEFT JOIN item_seizure_items isi ON isr.id = isi.record_id
306
+        AND isr.process_status = 3
307
+        <if test="startDate != null and endDate != null">
308
+            AND isr.create_time BETWEEN #{startDate} AND #{endDate}
309
+        </if>
310
+        where su.dept_id = #{teamId}
311
+        and su.del_flag = '0'
312
+        GROUP BY su.user_id
313
+        ORDER BY seizureCount DESC
314
+    </select>
315
+
257 316
     <!-- 查询排名前三的班组 -->
258 317
     <select id="selectTopThreeTeams" resultType="com.sundot.airport.item.domain.home.SeizureReportDTO$TopThreeTeamItem">
259 318
         SELECT

+ 8 - 0
airport-system/src/main/java/com/sundot/airport/system/mapper/SysUserMapper.java

@@ -238,4 +238,12 @@ public interface SysUserMapper {
238 238
      * @return 用户信息集合
239 239
      */
240 240
     public List<SysUser> selectUserListByDeptIdAndRoleKeyListAndUserName(@Param("deptId") Long deptId, @Param("list") List<String> list, @Param("nickName") String nickName);
241
+
242
+    /**
243
+     * 首页 - 用户信息(按大队 ID 筛选)
244
+     *
245
+     * @param brigadeId 大队 ID
246
+     * @return 用户信息列表
247
+     */
248
+    public List<LargeScreenHomePageUserInfoSqlDto> homePageUserInfoByBrigadeId(@Param("brigadeId") Long brigadeId);
241 249
 }

+ 8 - 0
airport-system/src/main/java/com/sundot/airport/system/service/ISysUserService.java

@@ -328,4 +328,12 @@ public interface ISysUserService {
328 328
      * @return 用户信息集合
329 329
      */
330 330
     public List<SysUser> selectUserListByDeptIdAndRoleKeyListAndUserName(SysUserConditionDto dto);
331
+
332
+    /**
333
+     * 首页 - 用户信息(按大队 ID 筛选)
334
+     *
335
+     * @param brigadeId 大队 ID
336
+     * @return 用户信息列表
337
+     */
338
+    public List<LargeScreenHomePageUserInfoSqlDto> homePageUserInfoByBrigadeId(Long brigadeId);
331 339
 }

+ 5 - 0
airport-system/src/main/java/com/sundot/airport/system/service/impl/SysUserServiceImpl.java

@@ -1197,4 +1197,9 @@ public class SysUserServiceImpl implements ISysUserService {
1197 1197
     public List<SysUser> selectUserListByDeptIdAndRoleKeyListAndUserName(SysUserConditionDto dto) {
1198 1198
         return userMapper.selectUserListByDeptIdAndRoleKeyListAndUserName(dto.getDeptId(), dto.getRoleKeyList(), dto.getNickName());
1199 1199
     }
1200
+
1201
+    @Override
1202
+    public List<LargeScreenHomePageUserInfoSqlDto> homePageUserInfoByBrigadeId(Long brigadeId) {
1203
+        return userMapper.homePageUserInfoByBrigadeId(brigadeId);
1204
+    }
1200 1205
 }

+ 24 - 0
airport-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -1040,4 +1040,28 @@
1040 1040
         where 1 = 1
1041 1041
           and sr.role_key in ('banzuzhang', 'SecurityCheck')
1042 1042
     </select>
1043
+
1044
+    <select id="homePageUserInfoByBrigadeId" resultType="com.sundot.airport.common.core.domain.LargeScreenHomePageUserInfoSqlDto">
1045
+        select su.user_id      userId,
1046
+               su.user_name    userName,
1047
+               su.nick_name    nickName,
1048
+               sd_bz.dept_id   teamId,
1049
+               sd_bz.dept_name teamName,
1050
+               sd_ks.dept_id   departmentId,
1051
+               sd_ks.dept_name departmentName,
1052
+               sd_dd.dept_id   brigadeId,
1053
+               sd_dd.dept_name brigadeName,
1054
+               sd_zj.dept_id   stationId,
1055
+               sd_zj.dept_name stationName
1056
+        from sys_user su
1057
+                 inner join sys_user_role sur on sur.user_id = su.user_id
1058
+                 inner join sys_role sr on sr.role_id = sur.role_id
1059
+                 inner join sys_dept sd_bz on sd_bz.dept_id = su.dept_id
1060
+                 inner join sys_dept sd_ks on sd_ks.dept_id = sd_bz.parent_id
1061
+                 inner join sys_dept sd_dd on sd_dd.dept_id = sd_ks.parent_id
1062
+                 inner join sys_dept sd_zj on sd_zj.dept_id = sd_dd.parent_id
1063
+        where 1 = 1
1064
+          and sr.role_key in ('banzuzhang', 'SecurityCheck')
1065
+          and sd_dd.dept_id = #{brigadeId}
1066
+    </select>
1043 1067
 </mapper>