From d39e4f7d839167c16425086dfa2f8747bccfdff9 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 05 十一月 2026 17:39:01 +0800
Subject: [PATCH] feat: 打通销售采购财务闭环并完成累计业务优化
---
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 351 insertions(+), 0 deletions(-)
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
index f03a1c0..2d1d674 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
@@ -16,11 +16,14 @@
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSimpleRespVO;
+import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeStatisticsRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeWorkHistorySaveReqVO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeContractDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEducationDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEmergencyContactDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeWorkHistoryDO;
+import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeContractMapper;
import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEducationMapper;
import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEmergencyContactMapper;
import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper;
@@ -42,9 +45,14 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.time.LocalDate;
+import java.time.YearMonth;
+import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -67,10 +75,15 @@
@Validated
public class HrmEmployeeServiceImpl implements HrmEmployeeService {
+ /** 鍛樺伐鐘舵�侊細绂昏亴 */
+ private static final Integer EMPLOYEE_STATUS_RESIGNED = 3;
+
@Resource
private HrmEmployeeMapper employeeMapper;
@Resource
private HrmEmployeeEducationMapper educationMapper;
+ @Resource
+ private HrmEmployeeContractMapper contractMapper;
@Resource
private HrmEmployeeWorkHistoryMapper workHistoryMapper;
@Resource
@@ -374,6 +387,14 @@
}
@Override
+ public boolean updateEmployeeStatusToResignedByUserId(Long userId, LocalDate leaveDate) {
+ if (userId == null) {
+ return false;
+ }
+ return employeeMapper.updateEmployeeStatusByUserId(userId, EMPLOYEE_STATUS_RESIGNED, leaveDate) > 0;
+ }
+
+ @Override
public HrmEmployeeDO getEmployeeByName(String name) {
return employeeMapper.selectByName(name);
}
@@ -526,4 +547,334 @@
return roleIds;
}
+ // ==================== 浜哄姏缁熻 ====================
+
+ /** 鍛樺伐鐘舵�侊細鍦ㄨ亴 */
+ private static final Integer EMPLOYEE_STATUS_ACTIVE = 1;
+ /** 鍛樺伐鐘舵�侊細璇曠敤 */
+ private static final Integer EMPLOYEE_STATUS_PROBATION = 2;
+
+ /** 宸ラ緞鍖洪棿鍚嶇О锛屼笌涓嬮檺锛堝惈锛変竴涓�瀵瑰簲锛屾渶鍚庝竴妗f棤涓婇檺 */
+ private static final String[] TENURE_BUCKET_NAMES = {"1骞翠互鍐�", "1-3骞�", "3-5骞�", "5-10骞�", "10骞翠互涓�"};
+ private static final double[] TENURE_BUCKET_MIN = {0, 1, 3, 5, 10};
+
+ /** 骞撮緞鍖洪棿鍚嶇О锛屼笌涓嬮檺锛堝惈锛変竴涓�瀵瑰簲锛屾渶鍚庝竴妗f棤涓婇檺 */
+ private static final String[] AGE_BUCKET_NAMES = {"25宀佷互涓�", "25-30宀�", "30-35宀�", "35-40宀�", "40-50宀�", "50宀佷互涓�"};
+ private static final int[] AGE_BUCKET_MIN = {0, 25, 30, 35, 40, 50};
+
+ @Override
+ public HrmEmployeeStatisticsRespVO getTenureStatistics() {
+ List<HrmEmployeeDO> allEmployees = employeeMapper.selectList();
+ LocalDate today = LocalDate.now();
+ int currentYear = today.getYear();
+
+ List<HrmEmployeeDO> activeEmployees = allEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE)
+ || Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION))
+ .collect(Collectors.toList());
+
+ HrmEmployeeStatisticsRespVO respVO = new HrmEmployeeStatisticsRespVO();
+ respVO.setTotalCount(activeEmployees.size());
+ respVO.setActiveCount((int) activeEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE)).count());
+ respVO.setProbationCount((int) activeEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION)).count());
+ respVO.setResignedCount((int) allEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)).count());
+ // 鏈勾鍏ヨ亴锛氬湪宀楀憳宸ヤ腑鍏ヨ亴鏃ユ湡钀藉湪浠婂勾
+ respVO.setThisYearHireCount((int) activeEmployees.stream()
+ .filter(e -> e.getHireDate() != null && e.getHireDate().getYear() == currentYear).count());
+ // 鏈勾绂昏亴锛氱鑱屽憳宸ヤ腑绂昏亴鏃ユ湡钀藉湪浠婂勾
+ respVO.setThisYearResignCount((int) allEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED))
+ .filter(e -> e.getLeaveDate() != null && e.getLeaveDate().getYear() == currentYear).count());
+
+ // 1. 骞冲潎宸ラ緞銆佸钩鍧囧勾榫�
+ List<Double> tenureList = activeEmployees.stream()
+ .map(e -> calculateTenureYears(e, today))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ respVO.setAverageTenureYears(averageOf(tenureList));
+ List<Integer> ageList = activeEmployees.stream()
+ .map(e -> resolveAge(e, today))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ respVO.setAverageAge(averageOfInt(ageList));
+
+ // 2. 宸ラ緞鍒嗗竷
+ int[] tenureCounts = new int[TENURE_BUCKET_NAMES.length];
+ for (Double tenure : tenureList) {
+ tenureCounts[resolveTenureBucket(tenure)]++;
+ }
+ List<HrmEmployeeStatisticsRespVO.ItemVO> tenureDistribution = new ArrayList<>();
+ for (int i = 0; i < TENURE_BUCKET_NAMES.length; i++) {
+ tenureDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO(TENURE_BUCKET_NAMES[i], tenureCounts[i]));
+ }
+ respVO.setTenureDistribution(tenureDistribution);
+
+ // 3. 骞撮緞鍒嗗竷
+ int[] ageCounts = new int[AGE_BUCKET_NAMES.length];
+ for (Integer age : ageList) {
+ ageCounts[resolveAgeBucket(age)]++;
+ }
+ List<HrmEmployeeStatisticsRespVO.ItemVO> ageDistribution = new ArrayList<>();
+ for (int i = 0; i < AGE_BUCKET_NAMES.length; i++) {
+ ageDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO(AGE_BUCKET_NAMES[i], ageCounts[i]));
+ }
+ respVO.setAgeDistribution(ageDistribution);
+
+ // 4. 瀛﹀巻鍒嗗竷锛堟湭濉啓鐨勫綊鍏モ�滄湭濉啓鈥濓級
+ Map<String, Integer> educationMap = new LinkedHashMap<>();
+ activeEmployees.stream()
+ .map(e -> StrUtil.blankToDefault(StrUtil.trim(e.getEducation()), "鏈~鍐�"))
+ .forEach(name -> educationMap.merge(name, 1, Integer::sum));
+ respVO.setEducationDistribution(toItemListSorted(educationMap));
+
+ // 5. 鎬у埆鍒嗗竷锛�1 鐢� / 2 濂� / 鍏跺畠 鏈煡锛�
+ Map<String, Integer> genderMap = new LinkedHashMap<>();
+ activeEmployees.forEach(e -> {
+ String name = Objects.equals(e.getGender(), 1) ? "鐢�" : Objects.equals(e.getGender(), 2) ? "濂�" : "鏈煡";
+ genderMap.merge(name, 1, Integer::sum);
+ });
+ respVO.setGenderDistribution(toItemListSorted(genderMap));
+
+ // 6. 閮ㄩ棬宸ラ緞缁熻
+ Set<Long> deptIds = activeEmployees.stream()
+ .map(HrmEmployeeDO::getDeptId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ Map<Long, DeptRespDTO> deptMap = CollUtil.isEmpty(deptIds) ? Collections.emptyMap() : deptApi.getDeptMap(deptIds);
+ Map<Long, List<Double>> deptTenureMap = new LinkedHashMap<>();
+ Map<Long, String> deptNameMap = new LinkedHashMap<>();
+ for (HrmEmployeeDO employee : activeEmployees) {
+ Double tenure = calculateTenureYears(employee, today);
+ if (employee.getDeptId() == null) {
+ deptTenureMap.computeIfAbsent(0L, k -> new ArrayList<>()).add(tenure == null ? 0D : tenure);
+ deptNameMap.putIfAbsent(0L, "鏈垎閰嶉儴闂�");
+ continue;
+ }
+ deptTenureMap.computeIfAbsent(employee.getDeptId(), k -> new ArrayList<>())
+ .add(tenure == null ? 0D : tenure);
+ DeptRespDTO dept = deptMap.get(employee.getDeptId());
+ deptNameMap.put(employee.getDeptId(), dept != null ? dept.getName() : "閮ㄩ棬ID=" + employee.getDeptId());
+ }
+ List<HrmEmployeeStatisticsRespVO.DeptTenureVO> deptTenureList = new ArrayList<>();
+ deptTenureMap.forEach((deptId, tenures) -> {
+ HrmEmployeeStatisticsRespVO.DeptTenureVO deptVO = new HrmEmployeeStatisticsRespVO.DeptTenureVO();
+ deptVO.setDeptId(deptId == 0L ? null : deptId);
+ deptVO.setDeptName(deptNameMap.get(deptId));
+ deptVO.setCount(tenures.size());
+ deptVO.setAverageTenureYears(averageOf(tenures));
+ deptTenureList.add(deptVO);
+ });
+ deptTenureList.sort(Comparator.comparing(HrmEmployeeStatisticsRespVO.DeptTenureVO::getAverageTenureYears,
+ Comparator.nullsLast(Comparator.reverseOrder())));
+ respVO.setDeptTenureList(deptTenureList);
+
+ // 6.1 閮ㄩ棬浜烘暟鍒嗗竷锛堜笌閮ㄩ棬宸ラ緞鍚屼竴浠藉垎缁勶紝鐩存帴澶嶇敤锛�
+ Map<String, Integer> deptCountMap = new LinkedHashMap<>();
+ deptTenureMap.forEach((deptId, tenures) -> deptCountMap.put(deptNameMap.get(deptId), tenures.size()));
+ respVO.setDeptDistribution(toItemListSorted(deptCountMap));
+
+ // 7. 宸ラ緞鎺掕锛堝墠 10 鍚嶏級
+ respVO.setTopTenureEmployees(activeEmployees.stream()
+ .filter(e -> e.getHireDate() != null)
+ .sorted(Comparator.comparing(HrmEmployeeDO::getHireDate))
+ .limit(10)
+ .map(e -> {
+ HrmEmployeeStatisticsRespVO.TenureEmployeeVO employeeVO = new HrmEmployeeStatisticsRespVO.TenureEmployeeVO();
+ employeeVO.setId(e.getId());
+ employeeVO.setName(e.getName());
+ DeptRespDTO dept = e.getDeptId() == null ? null : deptMap.get(e.getDeptId());
+ employeeVO.setDeptName(dept != null ? dept.getName() : (e.getDeptId() == null ? "鏈垎閰嶉儴闂�" : "閮ㄩ棬ID=" + e.getDeptId()));
+ employeeVO.setHireDate(e.getHireDate());
+ employeeVO.setTenureYears(calculateTenureYears(e, today));
+ return employeeVO;
+ })
+ .collect(Collectors.toList()));
+
+ // 8. 浜哄憳鐘舵�佹瀯鎴愶紙鍦ㄨ亴 / 璇曠敤 / 绂昏亴锛屽叾浣欑姸鎬佸綊鍏モ�滃叾瀹冣�濓級
+ int activeStatusCount = (int) activeEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_ACTIVE)).count();
+ int probationStatusCount = (int) activeEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_PROBATION)).count();
+ int resignedStatusCount = (int) allEmployees.stream()
+ .filter(e -> Objects.equals(e.getEmployeeStatus(), EMPLOYEE_STATUS_RESIGNED)).count();
+ List<HrmEmployeeStatisticsRespVO.ItemVO> statusDistribution = new ArrayList<>();
+ statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("鍦ㄨ亴", activeStatusCount));
+ statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("璇曠敤", probationStatusCount));
+ statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("绂昏亴", resignedStatusCount));
+ int otherStatusCount = allEmployees.size() - activeStatusCount - probationStatusCount - resignedStatusCount;
+ if (otherStatusCount > 0) {
+ statusDistribution.add(new HrmEmployeeStatisticsRespVO.ItemVO("鍏跺畠", otherStatusCount));
+ }
+ respVO.setStatusDistribution(statusDistribution);
+
+ // 9. 宀椾綅鍒嗗竷锛坧ostIds 涓� JSON 鏁扮粍锛屽彲涓�浜哄宀楋紱鏃犲矖浣嶅綊鍏モ�滄湭鍒嗛厤宀椾綅鈥濓級
+ Set<Long> postIds = new HashSet<>();
+ for (HrmEmployeeDO employee : activeEmployees) {
+ if (StrUtil.isNotBlank(employee.getPostIds())) {
+ postIds.addAll(JSONUtil.toList(employee.getPostIds(), Long.class));
+ }
+ }
+ Map<Long, PostRespDTO> postMap = CollUtil.isEmpty(postIds) ? Collections.emptyMap() : postApi.getPostMap(postIds);
+ Map<String, Integer> postCountMap = new LinkedHashMap<>();
+ for (HrmEmployeeDO employee : activeEmployees) {
+ List<Long> employeePostIds = StrUtil.isNotBlank(employee.getPostIds())
+ ? JSONUtil.toList(employee.getPostIds(), Long.class) : Collections.emptyList();
+ if (CollUtil.isEmpty(employeePostIds)) {
+ postCountMap.merge("鏈垎閰嶅矖浣�", 1, Integer::sum);
+ continue;
+ }
+ for (Long postId : employeePostIds) {
+ PostRespDTO post = postMap.get(postId);
+ postCountMap.merge(post != null ? post.getName() : "宀椾綅ID=" + postId, 1, Integer::sum);
+ }
+ }
+ respVO.setPostDistribution(toItemListSorted(postCountMap));
+
+ // 10. 濠氬Щ鐘跺喌銆佹斂娌婚潰璨屽垎甯冿紙妗f鑷敱鏂囨湰锛岀┖鍊煎綊鍏モ�滄湭濉啓鈥濓級
+ Map<String, Integer> marriageMap = new LinkedHashMap<>();
+ Map<String, Integer> politicalMap = new LinkedHashMap<>();
+ for (HrmEmployeeDO employee : activeEmployees) {
+ marriageMap.merge(StrUtil.blankToDefault(StrUtil.trim(employee.getMarriageStatus()), "鏈~鍐�"), 1, Integer::sum);
+ politicalMap.merge(StrUtil.blankToDefault(StrUtil.trim(employee.getPoliticalStatus()), "鏈~鍐�"), 1, Integer::sum);
+ }
+ respVO.setMarriageDistribution(toItemListSorted(marriageMap));
+ respVO.setPoliticalDistribution(toItemListSorted(politicalMap));
+
+ // 11. 杩� 12 涓湀鍏ヨ亴 / 绂昏亴瓒嬪娍锛堝惈鏈湀锛�
+ Map<YearMonth, Integer> hireMonthMap = new LinkedHashMap<>();
+ Map<YearMonth, Integer> resignMonthMap = new LinkedHashMap<>();
+ allEmployees.forEach(e -> {
+ if (e.getHireDate() != null) {
+ hireMonthMap.merge(YearMonth.from(e.getHireDate()), 1, Integer::sum);
+ }
+ if (e.getLeaveDate() != null) {
+ resignMonthMap.merge(YearMonth.from(e.getLeaveDate()), 1, Integer::sum);
+ }
+ });
+ List<HrmEmployeeStatisticsRespVO.TrendVO> trendList = new ArrayList<>();
+ YearMonth startMonth = YearMonth.from(today).minusMonths(11);
+ for (int i = 0; i < 12; i++) {
+ YearMonth month = startMonth.plusMonths(i);
+ HrmEmployeeStatisticsRespVO.TrendVO trendVO = new HrmEmployeeStatisticsRespVO.TrendVO();
+ trendVO.setMonth(month.toString());
+ trendVO.setHireCount(hireMonthMap.getOrDefault(month, 0));
+ trendVO.setResignCount(resignMonthMap.getOrDefault(month, 0));
+ trendList.add(trendVO);
+ }
+ respVO.setHireResignTrend(trendList);
+
+ // 12. 鍚堝悓鍒版湡棰勮锛堝彧鐪嬪湪宀楀憳宸ョ殑褰撳墠鐢熸晥鍚堝悓锛�
+ Set<Long> activeEmployeeIds = activeEmployees.stream()
+ .map(HrmEmployeeDO::getId)
+ .collect(Collectors.toSet());
+ Map<Long, HrmEmployeeContractDO> currentContractMap = contractMapper.selectList().stream()
+ .filter(c -> Boolean.TRUE.equals(c.getIsCurrent()))
+ .filter(c -> c.getTerminateStatus() == null || c.getTerminateStatus() == 0)
+ .filter(c -> activeEmployeeIds.contains(c.getEmployeeId()))
+ .collect(Collectors.toMap(HrmEmployeeContractDO::getEmployeeId, c -> c, (a, b) -> a));
+ int expiredCount = 0;
+ int expireIn30Count = 0;
+ int expireIn90Count = 0;
+ int expireOver90Count = 0;
+ int unlimitedCount = 0;
+ for (HrmEmployeeContractDO contract : currentContractMap.values()) {
+ if (contract.getEndDate() == null) {
+ unlimitedCount++;
+ continue;
+ }
+ long days = ChronoUnit.DAYS.between(today, contract.getEndDate());
+ if (days < 0) {
+ expiredCount++;
+ } else if (days <= 30) {
+ expireIn30Count++;
+ } else if (days <= 90) {
+ expireIn90Count++;
+ } else {
+ expireOver90Count++;
+ }
+ }
+ List<HrmEmployeeStatisticsRespVO.ItemVO> contractWarning = new ArrayList<>();
+ contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("宸插埌鏈�", expiredCount));
+ contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("30澶╁唴鍒版湡", expireIn30Count));
+ contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("31-90澶╁埌鏈�", expireIn90Count));
+ contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("90澶╀互涓�", expireOver90Count));
+ contractWarning.add(new HrmEmployeeStatisticsRespVO.ItemVO("鏃犲浐瀹氭湡闄�", unlimitedCount));
+ respVO.setContractWarning(contractWarning);
+ respVO.setNoContractCount(Math.max(0, activeEmployeeIds.size() - currentContractMap.size()));
+
+ return respVO;
+ }
+
+ /**
+ * 璁$畻宸ラ緞锛堝勾锛屼繚鐣� 1 浣嶅皬鏁帮級锛涚鑱屽憳宸ユ寜绂昏亴鏃ユ湡璁$畻锛屾棤鍏ヨ亴鏃ユ湡杩斿洖 null
+ */
+ private Double calculateTenureYears(HrmEmployeeDO employee, LocalDate today) {
+ if (employee.getHireDate() == null) {
+ return null;
+ }
+ LocalDate endDate = employee.getLeaveDate() != null ? employee.getLeaveDate() : today;
+ if (endDate.isBefore(employee.getHireDate())) {
+ return 0D;
+ }
+ double years = ChronoUnit.DAYS.between(employee.getHireDate(), endDate) / 365.25D;
+ return Math.round(years * 10D) / 10D;
+ }
+
+ /**
+ * 瑙f瀽骞撮緞锛氫紭鍏堝彇妗f骞撮緞锛岀己澶辨椂鐢ㄥ嚭鐢熸棩鏈熸帹绠�
+ */
+ private Integer resolveAge(HrmEmployeeDO employee, LocalDate today) {
+ if (employee.getAge() != null && employee.getAge() > 0) {
+ return employee.getAge();
+ }
+ if (employee.getBirthday() == null) {
+ return null;
+ }
+ return (int) ChronoUnit.YEARS.between(employee.getBirthday(), today);
+ }
+
+ private int resolveTenureBucket(double tenure) {
+ for (int i = TENURE_BUCKET_MIN.length - 1; i >= 0; i--) {
+ if (tenure >= TENURE_BUCKET_MIN[i]) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ private int resolveAgeBucket(int age) {
+ for (int i = AGE_BUCKET_MIN.length - 1; i >= 0; i--) {
+ if (age >= AGE_BUCKET_MIN[i]) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ private List<HrmEmployeeStatisticsRespVO.ItemVO> toItemListSorted(Map<String, Integer> countMap) {
+ return countMap.entrySet().stream()
+ .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
+ .map(entry -> new HrmEmployeeStatisticsRespVO.ItemVO(entry.getKey(), entry.getValue()))
+ .collect(Collectors.toList());
+ }
+
+ private Double averageOf(List<Double> values) {
+ if (CollUtil.isEmpty(values)) {
+ return 0D;
+ }
+ double sum = values.stream().mapToDouble(Double::doubleValue).sum();
+ return Math.round(sum / values.size() * 10D) / 10D;
+ }
+
+ private Double averageOfInt(List<Integer> values) {
+ if (CollUtil.isEmpty(values)) {
+ return 0D;
+ }
+ double sum = values.stream().mapToInt(Integer::intValue).sum();
+ return Math.round(sum / values.size() * 10D) / 10D;
+ }
+
}
\ No newline at end of file
--
Gitblit v1.9.3