Browse Source

预警-员工维度明细

wangxx 1 month ago
parent
commit
22318928bd

+ 12 - 0
airport-admin/src/main/java/com/sundot/airport/web/controller/ledger/LedgerWarningController.java

@@ -3,6 +3,7 @@ package com.sundot.airport.web.controller.ledger;
3 3
 import com.sundot.airport.common.core.controller.BaseController;
4 4
 import com.sundot.airport.common.core.domain.AjaxResult;
5 5
 import com.sundot.airport.common.dto.LedgerCommonQueryReqVO;
6
+import com.sundot.airport.ledger.domain.vo.EmployeeDimensionScoreVO;
6 7
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailItemReduceVO;
7 8
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailVO;
8 9
 import com.sundot.airport.ledger.domain.vo.LedgerWarningVO;
@@ -52,4 +53,15 @@ public class LedgerWarningController extends BaseController {
52 53
         return AjaxResult.success(result);
53 54
     }
54 55
 
56
+    /**
57
+     * 员工维度评分明细
58
+     * 获取指定条件下,相关人员在六个维度下的维度分值和相关信息
59
+     * 数据来源:从event表计算数据
60
+     */
61
+    @PostMapping("/employeeDimensionScores")
62
+    public AjaxResult getEmployeeDimensionScores(@RequestBody LedgerCommonQueryReqVO queryReq) {
63
+        List<EmployeeDimensionScoreVO> result = ledgerWarningService.getEmployeeDimensionScores(queryReq);
64
+        return AjaxResult.success(result);
65
+    }
66
+
55 67
 }

+ 5 - 0
airport-common/src/main/java/com/sundot/airport/common/dto/LedgerCommonQueryReqVO.java

@@ -35,6 +35,11 @@ public class LedgerCommonQueryReqVO implements Serializable {
35 35
     private Long userId;
36 36
 
37 37
     /**
38
+     * 维度ID(可选,用于筛选特定维度)
39
+     */
40
+    private Long dimensionId;
41
+
42
+    /**
38 43
      * 开始时间
39 44
      */
40 45
     @JsonFormat(pattern = "yyyy-MM-dd")

+ 66 - 0
airport-ledger/src/main/java/com/sundot/airport/ledger/domain/vo/EmployeeDimensionScoreVO.java

@@ -0,0 +1,66 @@
1
+package com.sundot.airport.ledger.domain.vo;
2
+
3
+import lombok.Data;
4
+
5
+import java.io.Serializable;
6
+import java.math.BigDecimal;
7
+
8
+/**
9
+ * 员工维度评分明细 VO
10
+ */
11
+@Data
12
+public class EmployeeDimensionScoreVO implements Serializable {
13
+
14
+    private static final long serialVersionUID = 1L;
15
+
16
+    /**
17
+     * 员工ID
18
+     */
19
+    private Long userId;
20
+
21
+    /**
22
+     * 姓名
23
+     */
24
+    private String personName;
25
+
26
+    /**
27
+     * 部门
28
+     */
29
+    private String deptName;
30
+
31
+    /**
32
+     * 班组
33
+     */
34
+    private String teamName;
35
+
36
+    /**
37
+     * 小组
38
+     */
39
+    private String groupName;
40
+
41
+    /**
42
+     * 维度名称
43
+     */
44
+    private String dimensionName;
45
+
46
+    /**
47
+     * 维度分值
48
+     */
49
+    private BigDecimal dimensionScore;
50
+
51
+    /**
52
+     * 基础分
53
+     */
54
+    private BigDecimal baseScore;
55
+
56
+    /**
57
+     * 事件加减分合计
58
+     */
59
+    private BigDecimal eventScore;
60
+
61
+    /**
62
+     * 权重(%)
63
+     */
64
+    private BigDecimal weight;
65
+
66
+}

+ 1 - 1
airport-ledger/src/main/java/com/sundot/airport/ledger/mapper/LedgerWarningMapper.java

@@ -60,6 +60,6 @@ public interface LedgerWarningMapper {
60 60
     /**
61 61
      * 配分事项列表
62 62
      */
63
-    List<ScoreEvent> selectScoreEventList(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("scoreIndicatorIdList") List<Long> scoreIndicatorIdList, @Param("userIdList") List<Long> userIdList);
63
+    List<ScoreEvent> selectScoreEventList(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("scoreIndicatorIdList") List<Long> scoreIndicatorIdList, @Param("userIdList") List<Long> userIdList, @Param("dimensionIdList") List<Long> dimensionIdList);
64 64
 
65 65
 }

+ 7 - 0
airport-ledger/src/main/java/com/sundot/airport/ledger/service/ILedgerWarningService.java

@@ -1,6 +1,7 @@
1 1
 package com.sundot.airport.ledger.service;
2 2
 
3 3
 import com.sundot.airport.common.dto.LedgerCommonQueryReqVO;
4
+import com.sundot.airport.ledger.domain.vo.EmployeeDimensionScoreVO;
4 5
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailItemReduceVO;
5 6
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailVO;
6 7
 import com.sundot.airport.ledger.domain.vo.LedgerWarningVO;
@@ -27,4 +28,10 @@ public interface ILedgerWarningService {
27 28
      */
28 29
     List<LedgerWarningDetailItemReduceVO> ledgerReduceDetail(LedgerCommonQueryReqVO queryReq);
29 30
 
31
+    /**
32
+     * 员工维度评分明细
33
+     * 从event表计算指定条件下,相关人员在六个维度下的维度分值和相关信息
34
+     */
35
+    List<EmployeeDimensionScoreVO> getEmployeeDimensionScores(LedgerCommonQueryReqVO queryReq);
36
+
30 37
 }

+ 224 - 2
airport-ledger/src/main/java/com/sundot/airport/ledger/service/impl/LedgerWarningServiceImpl.java

@@ -15,13 +15,16 @@ import com.sundot.airport.common.utils.DateMonthUtils;
15 15
 import com.sundot.airport.common.utils.DeptUtils;
16 16
 import com.sundot.airport.common.utils.SecurityUtils;
17 17
 import com.sundot.airport.common.utils.StreamSortUtils;
18
+import com.sundot.airport.ledger.domain.ScoreDimension;
18 19
 import com.sundot.airport.ledger.domain.ScoreEvent;
19 20
 import com.sundot.airport.ledger.domain.ScoreIndicator;
21
+import com.sundot.airport.ledger.domain.vo.EmployeeDimensionScoreVO;
20 22
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailItemReduceVO;
21 23
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailItemVO;
22 24
 import com.sundot.airport.ledger.domain.vo.LedgerWarningDetailVO;
23 25
 import com.sundot.airport.ledger.domain.vo.LedgerWarningVO;
24 26
 import com.sundot.airport.ledger.mapper.LedgerWarningMapper;
27
+import com.sundot.airport.ledger.mapper.ScoreDimensionMapper;
25 28
 import com.sundot.airport.ledger.service.IEmployeePortraitService;
26 29
 import com.sundot.airport.ledger.service.ILedgerWarningService;
27 30
 import com.sundot.airport.ledger.service.IScoreIndicatorService;
@@ -63,6 +66,9 @@ public class LedgerWarningServiceImpl implements ILedgerWarningService {
63 66
     @Autowired
64 67
     private ISysUserService sysUserService;
65 68
 
69
+    @Autowired
70
+    private ScoreDimensionMapper scoreDimensionMapper;
71
+
66 72
     /**
67 73
      * 台账数据
68 74
      */
@@ -131,7 +137,7 @@ public class LedgerWarningServiceImpl implements ILedgerWarningService {
131 137
             sysUserMap.putAll(sysUserList.stream().collect(Collectors.toMap(SysUser::getUserId, user -> user)));
132 138
         }
133 139
         Map<String, BigDecimal> overallScoreMap = employeePortraitService.getPortraitTotalScore(userNameList, DateUtil.formatDate(queryReq.getStartDate()), DateUtil.formatDate(queryReq.getEndDate()));
134
-        List<ScoreEvent> scoreEventList = ledgerWarningMapper.selectScoreEventList(queryReq.getStartDate(), queryReq.getEndDate(), scoreIndicatorIdList, userIdList);
140
+        List<ScoreEvent> scoreEventList = ledgerWarningMapper.selectScoreEventList(queryReq.getStartDate(), queryReq.getEndDate(), scoreIndicatorIdList, userIdList,null);
135 141
 //        // 由于person_name存在多用户时person_id为空,因此不能根据person_id进行分组处理数据
136 142
 //        Map<Long, List<ScoreEvent>> scoreEventMap = scoreEventList.stream().collect(Collectors.groupingBy(ScoreEvent::getPersonId));
137 143
         List<LedgerWarningDetailItemVO> ledgerWarningDetailItemList = new ArrayList<>();
@@ -311,7 +317,7 @@ public class LedgerWarningServiceImpl implements ILedgerWarningService {
311 317
             userNameList.addAll(sysUserList.stream().map(SysUser::getNickName).collect(Collectors.toList()));
312 318
             sysUserMap.putAll(sysUserList.stream().collect(Collectors.toMap(SysUser::getUserId, user -> user)));
313 319
         }
314
-        List<ScoreEvent> scoreEventList = ledgerWarningMapper.selectScoreEventList(queryReq.getStartDate(), queryReq.getEndDate(), scoreIndicatorIdList, userIdList);
320
+        List<ScoreEvent> scoreEventList = ledgerWarningMapper.selectScoreEventList(queryReq.getStartDate(), queryReq.getEndDate(), scoreIndicatorIdList, userIdList,null);
315 321
 //        // 由于person_name存在多用户时person_id为空,因此不能根据person_id进行分组处理数据
316 322
 //        Map<Long, List<ScoreEvent>> scoreEventMap = scoreEventList.stream().collect(Collectors.groupingBy(ScoreEvent::getPersonId));
317 323
         List<LedgerWarningDetailItemReduceVO> resultList = new ArrayList<>();
@@ -378,4 +384,220 @@ public class LedgerWarningServiceImpl implements ILedgerWarningService {
378 384
         return result;
379 385
     }
380 386
 
387
+    /**
388
+     * 员工维度评分明细(
389
+     * 从event表计算指定条件下,相关人员在六个维度下的维度分值和相关信息
390
+     */
391
+    @Override
392
+    public List<EmployeeDimensionScoreVO> getEmployeeDimensionScores(LedgerCommonQueryReqVO queryReq) {
393
+        // 1. 预加载基础数据
394
+        Long topSiteId = DeptUtils.getTopSiteId(sysDeptService.selectDeptById(SecurityUtils.getDeptId()));
395
+        Map<Long, SysDept> allDeptMap = sysDeptService.selectDeptInfoAll(new SysDept()).stream()
396
+                .collect(Collectors.toMap(SysDept::getDeptId, dept -> dept, (v1, v2) -> v1));
397
+        Map<Long, Set<Long>> brigadeSubDeptsMap = buildBrigadeSubDeptsMap(allDeptMap);
398
+
399
+        // 2. 确定需要查询的用户列表
400
+        List<Long> userIdList = new ArrayList<>();
401
+        Map<Long, SysUser> sysUserMap = new HashMap<>();
402
+        
403
+        if (ObjUtil.isNotNull(queryReq.getUserId())) {
404
+            // 指定单个用户
405
+            SysUser sysUser = sysUserService.selectUserById(queryReq.getUserId());
406
+            if (sysUser != null) {
407
+                userIdList.add(sysUser.getUserId());
408
+                sysUserMap.put(sysUser.getUserId(), sysUser);
409
+            }
410
+        } else {
411
+            // 根据组织架构获取用户列表
412
+            Long targetDeptId = ObjUtil.isNotNull(queryReq.getGroupId()) ? queryReq.getGroupId()
413
+                    : ObjUtil.isNotNull(queryReq.getTeamId()) ? queryReq.getTeamId()
414
+                    : ObjUtil.isNotNull(queryReq.getDeptId()) ? queryReq.getDeptId()
415
+                    : topSiteId;
416
+            List<SysUser> sysUserList = sysUserService.selectUserByDeptId(targetDeptId);
417
+            if (CollUtil.isNotEmpty(sysUserList)) {
418
+                userIdList = sysUserList.stream().map(SysUser::getUserId).collect(Collectors.toList());
419
+                sysUserMap = sysUserList.stream().collect(Collectors.toMap(SysUser::getUserId, user -> user));
420
+            }
421
+        }
422
+
423
+        if (CollUtil.isEmpty(userIdList)) {
424
+            return new ArrayList<>();
425
+        }
426
+
427
+        // 3. 一次性查询员工维度的所有维度配置(org='PERSON')
428
+        ScoreDimension dimensionQuery = new ScoreDimension();
429
+        dimensionQuery.setStatus("0");
430
+        dimensionQuery.setOrg(ScoreLevelEnum.PERSON.getCode());
431
+        if (ObjUtil.isNotNull(queryReq.getDimensionId())) {
432
+            dimensionQuery.setId(queryReq.getDimensionId());
433
+        }
434
+        List<ScoreDimension> dimensions = scoreDimensionMapper.selectList(dimensionQuery);
435
+        
436
+        if (CollUtil.isEmpty(dimensions)) {
437
+            return new ArrayList<>();
438
+        }
439
+
440
+
441
+        List<Long> indicatorIdList = null;
442
+        if (ObjUtil.isNotNull(queryReq.getDimensionId())) {
443
+            indicatorIdList = dimensions.stream().map(ScoreDimension::getId).collect(Collectors.toList());
444
+
445
+        }
446
+
447
+        // 一次性查询event表中该时间段内的事件数据
448
+        List<ScoreEvent> scoreEventList = ledgerWarningMapper.selectScoreEventList(
449
+                queryReq.getStartDate(), 
450
+                queryReq.getEndDate(), 
451
+                null,
452
+                userIdList,
453
+                indicatorIdList);
454
+
455
+        // 5. 用户名到用户对象的映射
456
+        Map<String, SysUser> userNameToUserMap = sysUserMap.values().stream()
457
+                .collect(Collectors.toMap(SysUser::getNickName, user -> user, (u1, u2) -> u1));
458
+
459
+        // 6. 按用户和维度分组统计事件分值
460
+        // Key: userId_dimensionId, Value: eventScore总和
461
+        Map<String, BigDecimal> userDimEventScoreMap = new HashMap<>();
462
+        
463
+        for (ScoreEvent event : scoreEventList) {
464
+            if (ObjUtil.isNull(event.getDimensionId()) || StrUtil.isEmpty(event.getPersonName())) {
465
+                continue;
466
+            }
467
+            
468
+            Long dimId = event.getDimensionId();
469
+            
470
+            // 如果指定了dimensionId,只统计该维度的事件
471
+            if (ObjUtil.isNotNull(queryReq.getDimensionId()) && !dimId.equals(queryReq.getDimensionId())) {
472
+                continue;
473
+            }
474
+            
475
+            BigDecimal eventScore = event.getTotalScore() != null ? event.getTotalScore() : BigDecimal.ZERO;
476
+            
477
+            // 处理person_name可能包含多个用户名的情况
478
+            String[] personNames = event.getPersonName().split("[,,]");
479
+            for (String personName : personNames) {
480
+                String trimmedName = personName.trim();
481
+                SysUser user = userNameToUserMap.get(trimmedName);
482
+                if (user != null) {
483
+                    String key = user.getUserId() + "_" + dimId;
484
+                    userDimEventScoreMap.merge(key, eventScore, BigDecimal::add);
485
+                }
486
+            }
487
+        }
488
+
489
+        // 7. 预计算用户的组织信息
490
+        Map<Long, UserOrgInfo> userOrgInfoMap = new HashMap<>();
491
+        for (SysUser user : sysUserMap.values()) {
492
+            UserOrgInfo orgInfo = buildUserOrgInfo(user, allDeptMap, brigadeSubDeptsMap);
493
+            userOrgInfoMap.put(user.getUserId(), orgInfo);
494
+        }
495
+
496
+        // 8. 构建结果列表
497
+        List<EmployeeDimensionScoreVO> resultList = new ArrayList<>(userIdList.size() * dimensions.size());
498
+        
499
+        for (Long userId : userIdList) {
500
+            SysUser sysUser = sysUserMap.get(userId);
501
+            if (sysUser == null) {
502
+                continue;
503
+            }
504
+
505
+            UserOrgInfo orgInfo = userOrgInfoMap.get(userId);
506
+            
507
+            // 为每个维度生成一条记录
508
+            for (ScoreDimension dimension : dimensions) {
509
+                EmployeeDimensionScoreVO vo = new EmployeeDimensionScoreVO();
510
+                vo.setUserId(userId);
511
+                vo.setPersonName(sysUser.getNickName());
512
+                vo.setDeptName(orgInfo != null ? orgInfo.deptName : "");
513
+                vo.setTeamName(orgInfo != null ? orgInfo.teamName : "");
514
+                vo.setGroupName(orgInfo != null ? orgInfo.groupName : "");
515
+                vo.setDimensionName(dimension.getName());
516
+                
517
+                // 基础分
518
+                BigDecimal baseScore = dimension.getBaseScore() != null ? dimension.getBaseScore() : BigDecimal.valueOf(80);
519
+                vo.setBaseScore(baseScore);
520
+                
521
+                // 事件加减分合计
522
+                String key = userId + "_" + dimension.getId();
523
+                BigDecimal eventScore = userDimEventScoreMap.getOrDefault(key, BigDecimal.ZERO);
524
+                vo.setEventScore(eventScore);
525
+                
526
+                // 维度分值 = 基础分 + 事件加减分
527
+                BigDecimal dimensionScore = baseScore.add(eventScore);
528
+                vo.setDimensionScore(dimensionScore);
529
+                
530
+                // 权重
531
+                vo.setWeight(dimension.getWeight() != null ? dimension.getWeight() : BigDecimal.ZERO);
532
+                
533
+                resultList.add(vo);
534
+            }
535
+        }
536
+
537
+        // 9. 排序
538
+        if (ObjUtil.isNull(queryReq.getSorts())) {
539
+            Map<String, String> sorts = new LinkedHashMap<>();
540
+            sorts.put("userId", "asc");
541
+            sorts.put("dimensionName", "asc");
542
+            queryReq.setSorts(sorts);
543
+        }
544
+        
545
+        List<EmployeeDimensionScoreVO> result = StreamSortUtils.sort(resultList, queryReq.getSorts());
546
+        return result;
547
+    }
548
+
549
+    /**
550
+     * 用户组织信息内部类
551
+     */
552
+    private static class UserOrgInfo {
553
+        String deptName;
554
+        String teamName;
555
+        String groupName;
556
+
557
+        UserOrgInfo(String deptName, String teamName, String groupName) {
558
+            this.deptName = deptName;
559
+            this.teamName = teamName;
560
+            this.groupName = groupName;
561
+        }
562
+    }
563
+
564
+    /**
565
+     * 构建用户组织信息
566
+     */
567
+    private UserOrgInfo buildUserOrgInfo(SysUser user, Map<Long, SysDept> allDeptMap, Map<Long, Set<Long>> brigadeSubDeptsMap) {
568
+        String deptName = "";
569
+        String teamName = "";
570
+        String groupName = "";
571
+        
572
+        if (user.getDeptId() == null) {
573
+            return new UserOrgInfo(deptName, teamName, groupName);
574
+        }
575
+
576
+        // 获取用户所在大队名称
577
+        Long brigadeId = findUserBrigade(user.getDeptId(), brigadeSubDeptsMap);
578
+        if (brigadeId != null && allDeptMap.containsKey(brigadeId)) {
579
+            deptName = allDeptMap.get(brigadeId).getDeptName();
580
+        }
581
+
582
+        // 获取用户的直接部门信息
583
+        SysDept userDept = allDeptMap.get(user.getDeptId());
584
+        if (userDept != null) {
585
+            // 根据部门类型判断是班组还是小组
586
+            if (DeptTypeEnum.TEAMS.getCode().equals(userDept.getDeptType())) {
587
+                groupName = userDept.getDeptName();
588
+                // 查找上级班组
589
+                if (userDept.getParentId() != null && userDept.getParentId() != 0) {
590
+                    SysDept parentDept = allDeptMap.get(userDept.getParentId());
591
+                    if (parentDept != null && DeptTypeEnum.MANAGER.getCode().equals(parentDept.getDeptType())) {
592
+                        teamName = parentDept.getDeptName();
593
+                    }
594
+                }
595
+            } else if (DeptTypeEnum.MANAGER.getCode().equals(userDept.getDeptType())) {
596
+                teamName = userDept.getDeptName();
597
+            }
598
+        }
599
+
600
+        return new UserOrgInfo(deptName, teamName, groupName);
601
+    }
602
+
381 603
 }

+ 6 - 0
airport-ledger/src/main/resources/mapper/ledger/LedgerWarningMapper.xml

@@ -191,6 +191,12 @@
191 191
                 #{item}
192 192
             </foreach>
193 193
         </if>
194
+        <if test="dimensionIdList != null and dimensionIdList.size() > 0">
195
+            and dimension_id in
196
+            <foreach collection="dimensionIdList" item="item" open="(" separator="," close=")">
197
+                #{item}
198
+            </foreach>
199
+        </if>
194 200
         <!--        由于person_name存在多用户时person_id为空,因此不能根据person_id进行查询-->
195 201
         <!--        <if test="userIdList != null and userIdList.size() > 0">-->
196 202
         <!--            and person_id in-->

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

@@ -29,6 +29,7 @@
29 29
     <select id="selectList" parameterType="com.sundot.airport.ledger.domain.ScoreDimension"
30 30
             resultMap="ScoreDimensionResult">
31 31
         <include refid="selectVo"/>
32
+        <if test="id != null">AND id = #{id}</if>
32 33
         <if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if>
33 34
         <if test="status != null and status != ''">AND status = #{status}</if>
34 35
         <if test="org != null and org != ''">AND org = #{org}</if>