Przeglądaj źródła

部门画像--能里画像--雷达图代码修改

wangxx 3 tygodni temu
rodzic
commit
1d2288c0cb

+ 19 - 2
airport-ledger/src/main/java/com/sundot/airport/ledger/service/impl/DeptPortraitServiceImpl.java

@@ -376,14 +376,14 @@ public class DeptPortraitServiceImpl implements IDeptPortraitService {
376
     public List<StationTeamStatsDTO> getStationTeamStats(DeptPortraitQueryDTO query) {
376
     public List<StationTeamStatsDTO> getStationTeamStats(DeptPortraitQueryDTO query) {
377
         // 1. 验证是站级别
377
         // 1. 验证是站级别
378
         SysDept station = sysDeptMapper.selectDeptById(query.getDeptId());
378
         SysDept station = sysDeptMapper.selectDeptById(query.getDeptId());
379
-        if (station == null || !"STATION".equals(station.getDeptType())) {
379
+        if (station == null) {
380
             throw new RuntimeException("请选择站级别部门");
380
             throw new RuntimeException("请选择站级别部门");
381
         }
381
         }
382
 
382
 
383
         // 2. 查询站下所有部门(BRIGADE)
383
         // 2. 查询站下所有部门(BRIGADE)
384
         SysDept deptQuery = new SysDept();
384
         SysDept deptQuery = new SysDept();
385
         deptQuery.setParentId(query.getDeptId());
385
         deptQuery.setParentId(query.getDeptId());
386
-        deptQuery.setDeptType(DeptTypeEnum.BRIGADE.getCode());
386
+        deptQuery.setDeptType(getChildDeptType(station.getDeptType()));
387
         deptQuery.setStatus("0");
387
         deptQuery.setStatus("0");
388
         List<SysDept> brigades = sysDeptMapper.selectDeptList(deptQuery);
388
         List<SysDept> brigades = sysDeptMapper.selectDeptList(deptQuery);
389
 
389
 
@@ -403,6 +403,23 @@ public class DeptPortraitServiceImpl implements IDeptPortraitService {
403
         return result;
403
         return result;
404
     }
404
     }
405
 
405
 
406
+    private String getChildDeptType(String deptType) {
407
+        if (deptType == null || deptType.isEmpty()) {
408
+            return null;
409
+        }
410
+
411
+        switch (deptType) {
412
+            case "STATION":
413
+                return DeptTypeEnum.BRIGADE.getCode();
414
+            case "BRIGADE":
415
+                return DeptTypeEnum.MANAGER.getCode();
416
+            case "MANAGER":
417
+                return DeptTypeEnum.TEAMS.getCode();
418
+            default:
419
+                return null;
420
+        }
421
+    }
422
+
406
     @Override
423
     @Override
407
     public StationTeamStatsDTO getTeamStats(DeptPortraitQueryDTO query) {
424
     public StationTeamStatsDTO getTeamStats(DeptPortraitQueryDTO query) {
408
         SysDept sysDept = sysDeptMapper.selectDeptById(query.getDeptId());
425
         SysDept sysDept = sysDeptMapper.selectDeptById(query.getDeptId());

+ 88 - 23
airport-ledger/src/main/java/com/sundot/airport/ledger/service/impl/GroupPortraitServiceImpl.java

@@ -109,10 +109,11 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
109
         dims.sort(Comparator.comparing(d -> d.getSortOrder() == null ? 999 : d.getSortOrder()));
109
         dims.sort(Comparator.comparing(d -> d.getSortOrder() == null ? 999 : d.getSortOrder()));
110
 
110
 
111
         List<GroupPortraitDTO.DimensionScore> result = new ArrayList<>();
111
         List<GroupPortraitDTO.DimensionScore> result = new ArrayList<>();
112
-
112
+        String beginTime = query.getStartDate()+" 00:00:00";
113
+        String endTime = query.getEndDate()+" 23:59:59";
113
         for (ScoreDimension dim : dims) {
114
         for (ScoreDimension dim : dims) {
114
             // 3. 通过dimRelationship找到下级维度,计算下级平均值
115
             // 3. 通过dimRelationship找到下级维度,计算下级平均值
115
-            BigDecimal lowerLevelAverage = calculateLowerLevelAverage(dim, query.getStartDate(), query.getEndDate());
116
+            BigDecimal lowerLevelAverage = calculateLowerLevelAverage(dim,beginTime , endTime,dept.getDeptId());
116
             
117
             
117
             // 4. 获取基础分(如果下级有值就不用基础分)
118
             // 4. 获取基础分(如果下级有值就不用基础分)
118
             BigDecimal baseScore = dim.getBaseScore() != null ? dim.getBaseScore() : BigDecimal.ZERO;
119
             BigDecimal baseScore = dim.getBaseScore() != null ? dim.getBaseScore() : BigDecimal.ZERO;
@@ -123,8 +124,8 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
123
                     : baseScore;
124
                     : baseScore;
124
 
125
 
125
             // 6. 计算当前层级特有加减分
126
             // 6. 计算当前层级特有加减分
126
-            Map<String, Object> specialScores = calculateSpecialScores(dim.getId(), query.getDeptId(), 
127
-                    query.getStartDate(), query.getEndDate(),org);
127
+            Map<String, Object> specialScores = calculateSpecialScores(dim.getId(), query.getDeptId(),
128
+                    beginTime, endTime,org);
128
             BigDecimal addScore = (BigDecimal) specialScores.getOrDefault("add", BigDecimal.ZERO);
129
             BigDecimal addScore = (BigDecimal) specialScores.getOrDefault("add", BigDecimal.ZERO);
129
             BigDecimal subtractScore = (BigDecimal) specialScores.getOrDefault("subtract", BigDecimal.ZERO);
130
             BigDecimal subtractScore = (BigDecimal) specialScores.getOrDefault("subtract", BigDecimal.ZERO);
130
             BigDecimal specialTotal = addScore.subtract(subtractScore);
131
             BigDecimal specialTotal = addScore.subtract(subtractScore);
@@ -194,15 +195,15 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
194
     }
195
     }
195
 
196
 
196
     /**
197
     /**
197
-     * 计算下级维度平均值(递归查找)
198
+     * 计算下级维度平均值
198
      * 层级关系:部门(DEPT) → 队/班组(TEAM) → 小组(GROUP) → 人员(PERSON)
199
      * 层级关系:部门(DEPT) → 队/班组(TEAM) → 小组(GROUP) → 人员(PERSON)
199
      * 递进逻辑:
200
      * 递进逻辑:
200
-     * - org=DEPT → 查询org=TEAM的维度 → 继续递归找org=GROUP → 继续递归找org=PERSON
201
-     * - org=TEAM → 查询org=GROUP的维度 → 继续递归找org=PERSON
201
+     * - org=DEPT → 获取子班组列表 → 计算每个班组的最终分数 → 求平均值
202
+     * - org=TEAM → 获取子小组列表 → 计算每个小组的最终分数 → 求平均值
202
      * - org=GROUP → 查询org=PERSON的维度 → 计算人员事件平均
203
      * - org=GROUP → 查询org=PERSON的维度 → 计算人员事件平均
203
      * - org=PERSON → 最底层,直接返回0
204
      * - org=PERSON → 最底层,直接返回0
204
      */
205
      */
205
-    private BigDecimal calculateLowerLevelAverage(ScoreDimension currentDim, String beginTime, String endTime) {
206
+    private BigDecimal calculateLowerLevelAverage(ScoreDimension currentDim, String beginTime, String endTime, Long deptId) {
206
         String dimRelationship = currentDim.getDimRelationship();
207
         String dimRelationship = currentDim.getDimRelationship();
207
         String currentOrg = currentDim.getOrg();
208
         String currentOrg = currentDim.getOrg();
208
         
209
         
@@ -217,7 +218,6 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
217
             return BigDecimal.ZERO;
218
             return BigDecimal.ZERO;
218
         }
219
         }
219
 
220
 
220
-        
221
         // 3. 查询下一级维度(通过dimRelationship匹配)
221
         // 3. 查询下一级维度(通过dimRelationship匹配)
222
         ScoreDimension query = new ScoreDimension();
222
         ScoreDimension query = new ScoreDimension();
223
         query.setDimRelationship(dimRelationship);
223
         query.setDimRelationship(dimRelationship);
@@ -236,19 +236,78 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
236
         // 4. 根据下一级的org决定如何处理
236
         // 4. 根据下一级的org决定如何处理
237
         if (ScoreLevelEnum.PERSON.getCode().equals(lowerOrg)) {
237
         if (ScoreLevelEnum.PERSON.getCode().equals(lowerOrg)) {
238
             // 下一级是人员维度,计算人员事件平均值
238
             // 下一级是人员维度,计算人员事件平均值
239
-            return calculatePersonDimensionAverage(lowerDim, beginTime, endTime);
239
+            return calculatePersonDimensionAverage(lowerDim, beginTime, endTime, deptId);
240
         } else {
240
         } else {
241
-            // 下一级是组织维度(TEAM或GROUP),需要继续递归查找更下一级
242
-            // 例如:部门(DEPT)找队(TEAM),队(TEAM)还要继续找小组(GROUP)
243
-            return calculateLowerLevelAverage(lowerDim, beginTime, endTime);
241
+            // 下一级是 TEAM 或 GROUP 层级,需要获取子部门并计算每个子部门的最终分数
242
+            return calculateChildDeptAverage(lowerDim, beginTime, endTime, deptId);
244
         }
243
         }
245
     }
244
     }
246
 
245
 
247
     /**
246
     /**
247
+     * 计算子部门的平均分数
248
+     * 对于 TEAM 和 GROUP 层级,需要获取子部门列表,计算每个子部门的最终分数,然后求平均
249
+     */
250
+    private BigDecimal calculateChildDeptAverage(ScoreDimension lowerDim, String beginTime, String endTime, Long deptId) {
251
+        // 获取子部门列表
252
+        List<SysDept> childDepts = sysDeptMapper.selectChildrenDeptById(deptId);
253
+        
254
+        if (childDepts == null || childDepts.isEmpty()) {
255
+            log.info("部门 {} 没有子部门", deptId);
256
+            return BigDecimal.ZERO;
257
+        }
258
+
259
+        BigDecimal totalScore = BigDecimal.ZERO;
260
+        int count = 0;
261
+
262
+        for (SysDept childDept : childDepts) {
263
+            // 计算该子部门在当前维度下的最终分数
264
+            BigDecimal childScore = calculateChildDeptDimensionScore(lowerDim, beginTime, endTime, childDept.getDeptId());
265
+            if (childScore.compareTo(BigDecimal.ZERO) > 0) {
266
+                totalScore = totalScore.add(childScore);
267
+                count++;
268
+            }
269
+        }
270
+
271
+        if (count == 0) {
272
+            return BigDecimal.ZERO;
273
+        }
274
+
275
+        return totalScore.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP);
276
+    }
277
+
278
+    /**
279
+     * 计算单个子部门在指定维度下的最终分数
280
+     * 最终分数 = 下级平均值(或基础分) + 特有加减分
281
+     */
282
+    private BigDecimal calculateChildDeptDimensionScore(ScoreDimension dim, String beginTime, String endTime, Long deptId) {
283
+        String currentOrg = dim.getOrg();
284
+        
285
+        // 1. 递归计算下级平均值
286
+        BigDecimal lowerLevelAverage = calculateLowerLevelAverage(dim, beginTime, endTime, deptId);
287
+        
288
+        // 2. 获取基础分(如果下级有值就不用基础分)
289
+        BigDecimal baseScore = dim.getBaseScore() != null ? dim.getBaseScore() : BigDecimal.ZERO;
290
+        
291
+        // 3. 决定使用下级平均值还是基础分
292
+        BigDecimal averageScore = lowerLevelAverage.compareTo(BigDecimal.ZERO) > 0 
293
+                ? lowerLevelAverage 
294
+                : baseScore;
295
+
296
+        // 4. 计算当前层级特有加减分
297
+        Map<String, Object> specialScores = calculateSpecialScores(dim.getId(), deptId, beginTime, endTime, currentOrg);
298
+        BigDecimal addScore = (BigDecimal) specialScores.getOrDefault("add", BigDecimal.ZERO);
299
+        BigDecimal subtractScore = (BigDecimal) specialScores.getOrDefault("subtract", BigDecimal.ZERO);
300
+        BigDecimal specialTotal = addScore.subtract(subtractScore);
301
+
302
+        // 5. 最终分值 = 下级平均值(或基础分) + 特有合计
303
+        return averageScore.add(specialTotal);
304
+    }
305
+
306
+    /**
248
      * 计算人员维度平均值
307
      * 计算人员维度平均值
249
      * 最底层(org=4),查询该维度下的所有人员事件,计算平均分数
308
      * 最底层(org=4),查询该维度下的所有人员事件,计算平均分数
250
      */
309
      */
251
-    private BigDecimal calculatePersonDimensionAverage(ScoreDimension dimension, String beginTime, String endTime) {
310
+    private BigDecimal calculatePersonDimensionAverage(ScoreDimension dimension, String beginTime, String endTime,Long deptId) {
252
 
311
 
253
         // 查询该维度下的所有事件
312
         // 查询该维度下的所有事件
254
         ScoreEvent eventQuery = new ScoreEvent();
313
         ScoreEvent eventQuery = new ScoreEvent();
@@ -259,11 +318,13 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
259
         if (endTime != null && !endTime.isEmpty()) {
318
         if (endTime != null && !endTime.isEmpty()) {
260
             eventQuery.getParams().put("endTime", endTime);
319
             eventQuery.getParams().put("endTime", endTime);
261
         }
320
         }
321
+        eventQuery.setGroupId(deptId);
262
         List<ScoreEvent> events = scoreEventMapper.selectList(eventQuery);
322
         List<ScoreEvent> events = scoreEventMapper.selectList(eventQuery);
263
 
323
 
324
+        BigDecimal base = dimension.getBaseScore() != null ? dimension.getBaseScore() : BigDecimal.valueOf(80);
264
         if (events == null || events.isEmpty()) {
325
         if (events == null || events.isEmpty()) {
265
             log.info("人员维度无事件数据");
326
             log.info("人员维度无事件数据");
266
-            return BigDecimal.ZERO;
327
+            return base;
267
         }
328
         }
268
 
329
 
269
         // 按人员分组统计总分
330
         // 按人员分组统计总分
@@ -286,14 +347,12 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
286
         if (personScores.isEmpty()) {
347
         if (personScores.isEmpty()) {
287
             return BigDecimal.ZERO;
348
             return BigDecimal.ZERO;
288
         }
349
         }
350
+        BigDecimal bigDecimal = BigDecimal.valueOf(personScores.size());
289
         BigDecimal sum = personScores.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
351
         BigDecimal sum = personScores.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
290
 
352
 
291
-        BigDecimal base = dimension.getBaseScore() != null ? dimension.getBaseScore() : BigDecimal.valueOf(80);
292
-        BigDecimal dimScore = base.add(sum);
293
-        BigDecimal weight = dimension.getWeight() != null ? dimension.getWeight() : BigDecimal.ZERO;
294
-        BigDecimal contribution = dimScore.multiply(weight)
295
-                .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
296
-        return contribution;
353
+
354
+        BigDecimal dimScore = base.multiply(bigDecimal).add(sum);
355
+        return dimScore.divide(bigDecimal, 2, RoundingMode.HALF_UP);
297
     }
356
     }
298
 
357
 
299
     /**
358
     /**
@@ -328,7 +387,13 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
328
         // 查询该部门在该维度的特有事件(根据org参数筛选)
387
         // 查询该部门在该维度的特有事件(根据org参数筛选)
329
         ScoreEvent eventQuery = new ScoreEvent();
388
         ScoreEvent eventQuery = new ScoreEvent();
330
         eventQuery.setDimensionId(dimensionId);
389
         eventQuery.setDimensionId(dimensionId);
331
-        eventQuery.setDeptId(deptId);
390
+        if(ScoreLevelEnum.GROUP.getCode().equals(org)){
391
+            eventQuery.setGroupId(deptId);
392
+        }else if(ScoreLevelEnum.TEAM.getCode().equals(org)){
393
+            eventQuery.setTeamId(deptId);
394
+        }else if(ScoreLevelEnum.DEPT.getCode().equals(org)){
395
+            eventQuery.setDeptId(deptId);
396
+        }
332
         eventQuery.setOrg(org); // 使用传入的org参数
397
         eventQuery.setOrg(org); // 使用传入的org参数
333
         if (beginTime != null && !beginTime.isEmpty()) {
398
         if (beginTime != null && !beginTime.isEmpty()) {
334
             eventQuery.getParams().put("beginTime", beginTime);
399
             eventQuery.getParams().put("beginTime", beginTime);
@@ -411,4 +476,4 @@ public class GroupPortraitServiceImpl implements IGroupPortraitService {
411
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
476
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
412
         return total.setScale(2, RoundingMode.HALF_UP);
477
         return total.setScale(2, RoundingMode.HALF_UP);
413
     }
478
     }
414
-}
479
+}

+ 1 - 0
airport-ledger/src/main/resources/mapper/ledger/ScoreDimensionMapper.xml

@@ -32,6 +32,7 @@
32
         <if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if>
32
         <if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if>
33
         <if test="status != null and status != ''">AND status = #{status}</if>
33
         <if test="status != null and status != ''">AND status = #{status}</if>
34
         <if test="org != null and org != ''">AND org = #{org}</if>
34
         <if test="org != null and org != ''">AND org = #{org}</if>
35
+        <if test="dimRelationship != null and dimRelationship != ''">AND dim_relationship = #{dimRelationship}</if>
35
         ORDER BY sort_order ASC, id ASC
36
         ORDER BY sort_order ASC, id ASC
36
     </select>
37
     </select>
37
 
38