From cb7118d315191e46746c1e0f3046b990cb1a270c Mon Sep 17 00:00:00 2001 From: dxfeng Date: Tue, 8 Jul 2025 21:02:25 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=86=E5=AF=BC=E9=A9=BE=E9=A9=B6=E8=88=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....gradle => secondev-chapanda-portal.gradle | 0 .../controller/LeaderCockpitController.java | 65 ++++ .../entity/param/SearchConditionParam.java | 21 ++ .../portal/entity/po/PortalData.java | 18 ++ .../seconddev/portal/entity/po/PortalPO.java | 14 + .../seconddev/portal/entity/po/Position.java | 18 ++ .../portal/mapper/LeaderCockpitMapper.java | 102 ++++++ .../portal/service/LeaderCockpitService.java | 74 +++++ .../impl/LeaderCockpitServiceImpl.java | 303 ++++++++++++++++++ .../seconddev/portal/util/DateUtil.java | 252 +++++++++++++++ .../resources/mapper/LeaderCockpitMapper.xml | 101 ++++++ 11 files changed, 968 insertions(+) rename secondev-chabaidao-dxfeng.gradle => secondev-chapanda-portal.gradle (100%) create mode 100644 src/main/java/com/weaver/seconddev/portal/controller/LeaderCockpitController.java create mode 100644 src/main/java/com/weaver/seconddev/portal/entity/param/SearchConditionParam.java create mode 100644 src/main/java/com/weaver/seconddev/portal/entity/po/PortalData.java create mode 100644 src/main/java/com/weaver/seconddev/portal/entity/po/PortalPO.java create mode 100644 src/main/java/com/weaver/seconddev/portal/entity/po/Position.java create mode 100644 src/main/java/com/weaver/seconddev/portal/mapper/LeaderCockpitMapper.java create mode 100644 src/main/java/com/weaver/seconddev/portal/service/LeaderCockpitService.java create mode 100644 src/main/java/com/weaver/seconddev/portal/service/impl/LeaderCockpitServiceImpl.java create mode 100644 src/main/java/com/weaver/seconddev/portal/util/DateUtil.java create mode 100644 src/main/resources/mapper/LeaderCockpitMapper.xml diff --git a/secondev-chabaidao-dxfeng.gradle b/secondev-chapanda-portal.gradle similarity index 100% rename from secondev-chabaidao-dxfeng.gradle rename to secondev-chapanda-portal.gradle diff --git a/src/main/java/com/weaver/seconddev/portal/controller/LeaderCockpitController.java b/src/main/java/com/weaver/seconddev/portal/controller/LeaderCockpitController.java new file mode 100644 index 0000000..34dd006 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/controller/LeaderCockpitController.java @@ -0,0 +1,65 @@ +package com.weaver.seconddev.portal.controller; + +import com.weaver.common.authority.annotation.WeaPermission; +import com.weaver.common.base.entity.result.WeaResult; +import com.weaver.seconddev.portal.entity.po.PortalPO; +import com.weaver.seconddev.portal.service.LeaderCockpitService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Slf4j +@RestController +@RequestMapping("/api/secondev/portal/leader") +@WeaPermission(publicPermission = true) +public class LeaderCockpitController { + + @Autowired + LeaderCockpitService leaderCockpitService; + + @PostMapping("/getOnJobNumber") + private WeaResult> getOnJobNumber(@RequestBody Map params) { + return leaderCockpitService.getOnJobNumber(params); + } + + @PostMapping("/getLaborCost") + private WeaResult> getLaborCost(@RequestBody Map params) { + return leaderCockpitService.getLaborCost(params); + } + + @PostMapping("/getTurnoverRate") + private WeaResult> getTurnoverRate(@RequestBody Map params) { + return leaderCockpitService.getTurnoverRate(params); + } + + @PostMapping("/getAttendanceRate") + private WeaResult> getAttendanceRate(@RequestBody Map params) { + return leaderCockpitService.getAttendanceRate(params); + } + + @PostMapping("/getFullStaffingRate") + private WeaResult> getFullStaffingRate(@RequestBody Map params) { + return leaderCockpitService.getFullStaffingRate(params); + } + + @PostMapping("/getEmploymentStatus") + private WeaResult> getEmploymentStatus(@RequestBody Map params) { + return leaderCockpitService.getEmploymentStatus(params); + } + + @PostMapping("/getResignationSituation") + private WeaResult> getResignationSituation(@RequestBody Map params) { + return leaderCockpitService.getResignationSituation(params); + } +} diff --git a/src/main/java/com/weaver/seconddev/portal/entity/param/SearchConditionParam.java b/src/main/java/com/weaver/seconddev/portal/entity/param/SearchConditionParam.java new file mode 100644 index 0000000..361e7ef --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/entity/param/SearchConditionParam.java @@ -0,0 +1,21 @@ +package com.weaver.seconddev.portal.entity.param; + +import lombok.Data; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Data +public class SearchConditionParam { + private String tenantKey; + private String departmentId; + private String searchDate; + private String startDate; + private String endDate; + /** + * 是否关键人员 + */ + private String isKeyPerson; +} diff --git a/src/main/java/com/weaver/seconddev/portal/entity/po/PortalData.java b/src/main/java/com/weaver/seconddev/portal/entity/po/PortalData.java new file mode 100644 index 0000000..05de3bc --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/entity/po/PortalData.java @@ -0,0 +1,18 @@ +package com.weaver.seconddev.portal.entity.po; + +import lombok.Data; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Data +public class PortalData { + private String index; + private String date; + private String depart; + private String posi; + private String leader; + private String count; +} diff --git a/src/main/java/com/weaver/seconddev/portal/entity/po/PortalPO.java b/src/main/java/com/weaver/seconddev/portal/entity/po/PortalPO.java new file mode 100644 index 0000000..c9b50c2 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/entity/po/PortalPO.java @@ -0,0 +1,14 @@ +package com.weaver.seconddev.portal.entity.po; + +import lombok.Data; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Data +public class PortalPO { + private String value; + private String name; +} diff --git a/src/main/java/com/weaver/seconddev/portal/entity/po/Position.java b/src/main/java/com/weaver/seconddev/portal/entity/po/Position.java new file mode 100644 index 0000000..9358327 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/entity/po/Position.java @@ -0,0 +1,18 @@ +package com.weaver.seconddev.portal.entity.po; + +import lombok.Data; + +/** + * @author:dxfeng + * @createTime: 2025/07/08 + * @version: 1.0 + */ +@Data +public class Position { + private Long positionId; + private String positionName; + private Long departmentId; + private String departmentName; + private Long gradeId; + private String gradeName; +} diff --git a/src/main/java/com/weaver/seconddev/portal/mapper/LeaderCockpitMapper.java b/src/main/java/com/weaver/seconddev/portal/mapper/LeaderCockpitMapper.java new file mode 100644 index 0000000..7d259b8 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/mapper/LeaderCockpitMapper.java @@ -0,0 +1,102 @@ +package com.weaver.seconddev.portal.mapper; + +import com.weaver.seconddev.portal.entity.param.SearchConditionParam; +import com.weaver.seconddev.portal.entity.po.PortalPO; +import com.weaver.seconddev.portal.entity.po.Position; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Mapper +public interface LeaderCockpitMapper { + + /** + * 按类型统计在职人数 + * + * @param conditionParam + * @return + */ + List getOnJobNumber(SearchConditionParam conditionParam); + + /** + * 查询在职人数 + * + * @param conditionParam + * @return + */ + int getOnJobCount(SearchConditionParam conditionParam); + /** + * 查询入职人数 + * + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + int getEmploymentCount(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + /** + * 查询入职人数列表 + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + List getEmploymentListByPosition(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + /** + * 查询关键入职人数 + * + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + int getKeyEmploymentCount(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + + /** + * 查询离职人数 + * + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + int getResignCount(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + /** + * 查询关键离职人数 + * + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + int getKeyResignCount(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + /** + * 查询离职人数列表 + * @param tenantKey + * @param departmentId + * @param startDate + * @param endDate + * @return + */ + List getResignListByPosition(@Param("tenantKey") String tenantKey, @Param("departmentId") String departmentId, @Param("startDate") String startDate, @Param("endDate") String endDate); + + + Position getPositionById(@Param("tenantKey") String tenantKey, @Param("positionId") String positionId); + +} diff --git a/src/main/java/com/weaver/seconddev/portal/service/LeaderCockpitService.java b/src/main/java/com/weaver/seconddev/portal/service/LeaderCockpitService.java new file mode 100644 index 0000000..f53c836 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/service/LeaderCockpitService.java @@ -0,0 +1,74 @@ +package com.weaver.seconddev.portal.service; + +import com.weaver.common.base.entity.result.WeaResult; +import com.weaver.seconddev.portal.entity.po.PortalPO; + +import java.util.List; +import java.util.Map; + +/** + * 领导驾驶舱门户 + * + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +public interface LeaderCockpitService { + + /** + * 获取在职人数 + * + * @param params + * @return + */ + WeaResult> getOnJobNumber(Map params); + + /** + * 获取人工成本 + * + * @param params + * @return + */ + WeaResult> getLaborCost(Map params); + + /** + * 获取离职率 + * + * @param params + * @return + */ + WeaResult> getTurnoverRate(Map params); + + /** + * 获取出勤率 + * + * @param params + * @return + */ + WeaResult> getAttendanceRate(Map params); + + /** + * 获取满编率 + * + * @param params + * @return + */ + WeaResult> getFullStaffingRate(Map params); + + /** + * 获取入职情况 + * + * @param params + * @return + */ + WeaResult> getEmploymentStatus(Map params); + + /** + * 获取离职情况 + * + * @param params + * @return + */ + WeaResult> getResignationSituation(Map params); + +} diff --git a/src/main/java/com/weaver/seconddev/portal/service/impl/LeaderCockpitServiceImpl.java b/src/main/java/com/weaver/seconddev/portal/service/impl/LeaderCockpitServiceImpl.java new file mode 100644 index 0000000..60f0ea1 --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/service/impl/LeaderCockpitServiceImpl.java @@ -0,0 +1,303 @@ +package com.weaver.seconddev.portal.service.impl; + +import com.alibaba.fastjson.JSON; +import com.weaver.common.base.entity.result.WeaResult; +import com.weaver.common.hrm.dao.HrmCommonEmployeeDao; +import com.weaver.seconddev.portal.entity.param.SearchConditionParam; +import com.weaver.seconddev.portal.entity.po.PortalData; +import com.weaver.seconddev.portal.entity.po.PortalPO; +import com.weaver.seconddev.portal.entity.po.Position; +import com.weaver.seconddev.portal.mapper.LeaderCockpitMapper; +import com.weaver.seconddev.portal.service.LeaderCockpitService; +import com.weaver.seconddev.portal.util.DateUtil; +import com.weaver.teams.security.StringUtils; +import com.weaver.teams.security.context.UserContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.*; + +/** + * 领导驾驶舱门户 + * + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ +@Slf4j +@Service +public class LeaderCockpitServiceImpl implements LeaderCockpitService { + @Autowired + LeaderCockpitMapper leaderCockpitMapper; + + @Autowired + HrmCommonEmployeeDao hrmCommonEmployeeDao; + + @Override + public WeaResult> getOnJobNumber(Map params) { + SearchConditionParam searchConditionParam = new SearchConditionParam(); + initSearchConditionParam(searchConditionParam, params, null); + log.error("searchConditionParam===" + JSON.toJSONString(searchConditionParam)); + List onJobNumber = leaderCockpitMapper.getOnJobNumber(searchConditionParam); + return WeaResult.success(onJobNumber); + } + + @Override + public WeaResult> getLaborCost(Map params) { + return null; + } + + @Override + public WeaResult> getTurnoverRate(Map params) { + SearchConditionParam searchConditionParam = new SearchConditionParam(); + initSearchConditionParam(searchConditionParam, params, null); + log.error("searchConditionParam===" + JSON.toJSONString(searchConditionParam)); + // 查询范围内在职人员 + int onJobCount = leaderCockpitMapper.getOnJobCount(searchConditionParam); + // 查询范围内离职人员 + int resignCount = leaderCockpitMapper.getResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate()); + // 查询关键离职率 + int keyResignCount = leaderCockpitMapper.getKeyResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate()); + // 计算离职率 + double turnoverRate = calculateRate(keyResignCount, onJobCount); + //TODO 计算关键离职率 + double keyTurnoverRate = calculateRate(keyResignCount, resignCount); + + Map returnMap = new HashMap<>(2); + returnMap.put("turnoverRate", formatPercentage(turnoverRate)); + returnMap.put("keyTurnoverRate", formatPercentage(keyTurnoverRate)); + return WeaResult.success(returnMap); + } + + @Override + public WeaResult> getAttendanceRate(Map params) { + return null; + } + + @Override + public WeaResult> getFullStaffingRate(Map params) { + return null; + } + + @Override + public WeaResult> getEmploymentStatus(Map params) { + SearchConditionParam searchConditionParam = new SearchConditionParam(); + initSearchConditionParam(searchConditionParam, params, 0); + + log.error("searchConditionParam===" + JSON.toJSONString(searchConditionParam)); + String searchDate = params.get("searchDate"); + if (StringUtils.isBlank(searchDate)) { + searchDate = DateUtil.getCurrentDateStr(); + } + LocalDate localDate = DateUtil.parseDate(searchDate); + + String month = DateUtil.formatToYearMonth_ZH(localDate); + Map allDataMap = new LinkedHashMap<>(3); + Map keyDataMap = new LinkedHashMap<>(3); + allDataMap.put(month, leaderCockpitMapper.getEmploymentCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate())); + keyDataMap.put(month, leaderCockpitMapper.getKeyEmploymentCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate())); + + String firstDayOfMonthStr = DateUtil.getFirstDayOfPreviousMonthStr(searchConditionParam.getStartDate()); + String lastDayOfMonthStr = DateUtil.getLastDayOfPreviousMonthStr(searchConditionParam.getEndDate()); + // 前面5个月 + for (int i = 1; i < 7; i++) { + allDataMap.put(DateUtil.formatToYearMonth_ZH(firstDayOfMonthStr), leaderCockpitMapper.getEmploymentCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), firstDayOfMonthStr, lastDayOfMonthStr)); + keyDataMap.put(DateUtil.formatToYearMonth_ZH(firstDayOfMonthStr), leaderCockpitMapper.getKeyEmploymentCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), firstDayOfMonthStr, lastDayOfMonthStr)); + firstDayOfMonthStr = DateUtil.getFirstDayOfPreviousMonthStr(searchConditionParam.getStartDate(), i); + lastDayOfMonthStr = DateUtil.getLastDayOfPreviousMonthStr(searchConditionParam.getEndDate(), i); + } + + // 查询台账 + String currentMonth = DateUtil.formatToYearMonth(searchConditionParam.getStartDate()); + List employmentListByPosition = leaderCockpitMapper.getEmploymentListByPosition(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate()); + List portalList = new ArrayList<>(); + for (PortalPO portal : employmentListByPosition) { + PortalData portalData = new PortalData(); + portalData.setDate(currentMonth); + portalData.setCount(portal.getName()); + String positionId = portal.getValue(); + // 获取岗位名称 + Position positionById = leaderCockpitMapper.getPositionById(searchConditionParam.getTenantKey(), positionId); + log.error("positionById==" + JSON.toJSONString(positionById)); + + portalData.setPosi(positionById.getPositionName()); + portalData.setDepart(positionById.getDepartmentName()); + portalData.setLeader(positionById.getGradeName()); + portalList.add(portalData); + } + // TODO + if (CollectionUtils.isEmpty(portalList)) { + PortalData portalData = new PortalData(); + portalData.setDate(currentMonth); + portalData.setLeader("M1"); + portalData.setPosi("人事经理"); + portalData.setDepart("薪酬绩效组"); + portalList.add(portalData); + } + + Map returnMap = new HashMap<>(3); + returnMap.put("dataSource", portalList); + returnMap.put("all", allDataMap); + returnMap.put("key", keyDataMap); + return WeaResult.success(returnMap); + } + + @Override + public WeaResult> getResignationSituation(Map params) { + SearchConditionParam searchConditionParam = new SearchConditionParam(); + initSearchConditionParam(searchConditionParam, params, 0); + log.error("searchConditionParam===" + JSON.toJSONString(searchConditionParam)); + + String searchDate = params.get("searchDate"); + if (StringUtils.isBlank(searchDate)) { + searchDate = DateUtil.getCurrentDateStr(); + } + LocalDate localDate = DateUtil.parseDate(searchDate); + + String month = DateUtil.formatToYearMonth_ZH(localDate); + Map allDataMap = new LinkedHashMap<>(3); + Map keyDataMap = new LinkedHashMap<>(3); + allDataMap.put(month, leaderCockpitMapper.getResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate())); + keyDataMap.put(month, leaderCockpitMapper.getKeyResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate())); + + String firstDayOfMonthStr = DateUtil.getFirstDayOfPreviousMonthStr(searchConditionParam.getStartDate()); + String lastDayOfMonthStr = DateUtil.getLastDayOfPreviousMonthStr(searchConditionParam.getEndDate()); + // 前两个月 + for (int i = 1; i < 4; i++) { + allDataMap.put(DateUtil.formatToYearMonth_ZH(firstDayOfMonthStr), leaderCockpitMapper.getResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), firstDayOfMonthStr, lastDayOfMonthStr)); + keyDataMap.put(DateUtil.formatToYearMonth_ZH(firstDayOfMonthStr), leaderCockpitMapper.getKeyResignCount(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), firstDayOfMonthStr, lastDayOfMonthStr)); + + firstDayOfMonthStr = DateUtil.getFirstDayOfPreviousMonthStr(searchConditionParam.getStartDate(), i); + lastDayOfMonthStr = DateUtil.getLastDayOfPreviousMonthStr(searchConditionParam.getEndDate(), i); + } + + + // 查询 + String currentMonth = DateUtil.formatToYearMonth(searchConditionParam.getStartDate()); + List resignListByPosition = leaderCockpitMapper.getResignListByPosition(searchConditionParam.getTenantKey(), searchConditionParam.getDepartmentId(), searchConditionParam.getStartDate(), searchConditionParam.getEndDate()); + List portalList = new ArrayList<>(); + for (PortalPO portal : resignListByPosition) { + PortalData portalData = new PortalData(); + portalData.setDate(currentMonth); + portalData.setCount(portal.getName()); + String positionId = portal.getValue(); + // 获取岗位名称 + Position positionById = leaderCockpitMapper.getPositionById(searchConditionParam.getTenantKey(), positionId); + log.error("positionById==" + JSON.toJSONString(positionById)); + + portalData.setPosi(positionById.getPositionName()); + portalData.setDepart(positionById.getDepartmentName()); + portalData.setLeader(positionById.getGradeName()); + portalList.add(portalData); + } + // TODO + if (CollectionUtils.isEmpty(portalList)) { + PortalData portalData = new PortalData(); + portalData.setDate(currentMonth); + portalData.setLeader("M1"); + portalData.setPosi("人事经理"); + portalData.setDepart("薪酬绩效组"); + portalList.add(portalData); + } + + + Map returnMap = new HashMap<>(3); + returnMap.put("dataSource", portalList); + returnMap.put("all", allDataMap); + returnMap.put("key", keyDataMap); + return WeaResult.success(returnMap); + } + + //public static void main(String[] args) { + // //Map params = new HashMap<>(); + // //params.put("searchDate", "2025-07-18"); + // //SearchConditionParam searchConditionParam = new SearchConditionParam(); + // //initSearchConditionParam(searchConditionParam, params, 0); + // //List list = new ArrayList<>(); + // //list.add(searchConditionParam); + // // + // //params.put("searchDate",searchConditionParam.getEndDate()); + // //System.out.println(JSON.toJSONString(searchConditionParam)); + // String dateStr = "2025-07-05"; + // String lastDayOfPreviousMonthStr = DateUtil.getLastDayOfPreviousMonthStr(dateStr, 2); + // System.out.println(lastDayOfPreviousMonthStr); + // String firstDayOfPreviousMonthStr = DateUtil.getFirstDayOfPreviousMonthStr(dateStr, 2); + // System.out.println(firstDayOfPreviousMonthStr); + //} + + /** + * 构建查询对象 + * + * @param searchConditionParam + * @param params + * @param beforeMonth + */ + private static void initSearchConditionParam(SearchConditionParam searchConditionParam, Map params, Integer beforeMonth) { + String searchDate = params.get("searchDate"); + String departmentId = params.get("departmentId"); + + // 租户 + searchConditionParam.setTenantKey(UserContext.getCurrentUser().getTenantKey()); + // 部门 + searchConditionParam.setDepartmentId(departmentId); + + // 处理截止日期 + String endDateStr; + if (StringUtils.isBlank(searchDate)) { + endDateStr = DateUtil.getCurrentDateStr(); + } else { + try { + // 验证日期格式是否合法 + endDateStr = searchDate; + } catch (Exception e) { + log.error("日期格式错误,使用当前日期: {}", searchDate, e); + endDateStr = DateUtil.getCurrentDateStr(); + } + } + searchConditionParam.setEndDate(endDateStr); + + // 处理开始日期 + if (beforeMonth == null) { + // 查询当前年度数据 + searchConditionParam.setStartDate(DateUtil.getFirstDayOfYearStr()); + } else { + // 查询前N个月数据 + try { + LocalDate endDate = LocalDate.parse(endDateStr); + LocalDate startDate = endDate.minusMonths(beforeMonth); + searchConditionParam.setStartDate(DateUtil.getFirstDayOfMonthStr(DateUtil.formatDate(startDate))); + } catch (Exception e) { + log.error("计算开始日期失败,使用当前年度第一天", e); + searchConditionParam.setStartDate(DateUtil.getFirstDayOfYearStr()); + } + } + } + + /** + * 计算百分比 + * + * @param numerator + * @param denominator + * @return + */ + private double calculateRate(int numerator, int denominator) { + if (denominator == 0) { + log.warn("计算比率时分母为0,返回0"); + return 0.0; + } + return (double) numerator / denominator; + } + + /** + * 格式化百分比 + * + * @param rate + * @return + */ + private String formatPercentage(double rate) { + return String.format("%.2f%%", rate * 100); + } +} diff --git a/src/main/java/com/weaver/seconddev/portal/util/DateUtil.java b/src/main/java/com/weaver/seconddev/portal/util/DateUtil.java new file mode 100644 index 0000000..add15ce --- /dev/null +++ b/src/main/java/com/weaver/seconddev/portal/util/DateUtil.java @@ -0,0 +1,252 @@ +package com.weaver.seconddev.portal.util; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Date; + +/** + * @author:dxfeng + * @createTime: 2025/07/07 + * @version: 1.0 + */ + +public class DateUtil { + + private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + /** + * 获取当前日期字符串 (yyyy-MM-dd) + */ + public static String getCurrentDateStr() { + return LocalDate.now().format(DEFAULT_DATE_FORMATTER); + } + + /** + * 获取当前日期时间字符串 (yyyy-MM-dd HH:mm:ss) + */ + public static String getCurrentDateTimeStr() { + return LocalDateTime.now().format(DEFAULT_DATETIME_FORMATTER); + } + + /** + * 解析日期字符串为LocalDate + */ + public static LocalDate parseDate(String dateStr) { + if (dateStr == null || dateStr.trim().isEmpty()) { + return null; + } + return LocalDate.parse(dateStr, DEFAULT_DATE_FORMATTER); + } + + /** + * 解析日期时间字符串为LocalDateTime + */ + public static LocalDateTime parseDateTime(String dateTimeStr) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) { + return null; + } + return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMATTER); + } + + /** + * 格式化LocalDate为字符串 + */ + public static String formatDate(LocalDate date) { + if (date == null) { + return null; + } + return date.format(DEFAULT_DATE_FORMATTER); + } + + /** + * 格式化LocalDateTime为字符串 + */ + public static String formatDateTime(LocalDateTime dateTime) { + if (dateTime == null) { + return null; + } + return dateTime.format(DEFAULT_DATETIME_FORMATTER); + } + + /** + * 获取当前年度第一天的字符串 + */ + public static String getFirstDayOfYearStr() { + return LocalDate.now().withMonth(1).withDayOfMonth(1).format(DEFAULT_DATE_FORMATTER); + } + + + /** + * 获取当前年度最后一天的字符串 + */ + public static String getLastDayOfYearStr() { + return LocalDate.now().withMonth(12).withDayOfMonth(31).format(DEFAULT_DATE_FORMATTER); + } + + /** + * 获取指定日期所在月份的第一天 + * @param date 输入日期 + * @return 当月第一天的 LocalDate + */ + public static LocalDate getFirstDayOfMonth(LocalDate date) { + if (date == null) { + return null; + } + return date.withDayOfMonth(1); + } + + /** + * 获取指定日期字符串所在月份的第一天(字符串形式) + * @param dateStr 输入日期字符串 (yyyy-MM-dd) + * @return 当月第一天的字符串 + */ + public static String getFirstDayOfMonthStr(String dateStr) { + LocalDate date = parseDate(dateStr); + if (date == null) { + return null; + } + return formatDate(getFirstDayOfMonth(date)); + } + + /** + * 获取指定日期的前N个月日期字符串 + */ + public static String getBeforeMonthDateStr(String dateStr, int months) { + LocalDate date = parseDate(dateStr); + if (date == null) { + return null; + } + return date.minusMonths(months).format(DEFAULT_DATE_FORMATTER); + } + + /** + * 获取指定日期的后N个月日期字符串 + */ + public static String getAfterMonthDateStr(String dateStr, int months) { + LocalDate date = parseDate(dateStr); + if (date == null) { + return null; + } + return date.plusMonths(months).format(DEFAULT_DATE_FORMATTER); + } + + /** + * 计算两个日期之间的天数差 + */ + public static long daysBetween(String startDateStr, String endDateStr) { + LocalDate startDate = parseDate(startDateStr); + LocalDate endDate = parseDate(endDateStr); + if (startDate == null || endDate == null) { + return 0; + } + return ChronoUnit.DAYS.between(startDate, endDate); + } + + /** + * 计算两个日期之间的月数差 + */ + public static long monthsBetween(String startDateStr, String endDateStr) { + LocalDate startDate = parseDate(startDateStr); + LocalDate endDate = parseDate(endDateStr); + if (startDate == null || endDate == null) { + return 0; + } + return ChronoUnit.MONTHS.between(startDate, endDate); + } + + /** + * 将java.util.Date转换为LocalDate + */ + public static LocalDate toLocalDate(Date date) { + if (date == null) { + return null; + } + return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate(); + } + + /** + * 将LocalDate转换为java.util.Date + */ + public static Date toDate(LocalDate localDate) { + if (localDate == null) { + return null; + } + return java.sql.Date.valueOf(localDate); + } + + /** + * 获取指定日期字符串上个月的第一天(字符串形式) + * @param dateStr 输入日期字符串 (yyyy-MM-dd) + * @return 上个月第一天的字符串 + */ + public static String getFirstDayOfPreviousMonthStr(String dateStr) { + return getFirstDayOfPreviousMonthStr(dateStr,1); + } + + public static String getFirstDayOfPreviousMonthStr(String dateStr,int month) { + LocalDate date = parseDate(dateStr); + if (date == null) { + return null; + } + // 获取上个月的第一天 + LocalDate firstDayOfPrevMonth = date.minusMonths(month).withDayOfMonth(1); + return formatDate(firstDayOfPrevMonth); + } + + /** + * 获取指定日期字符串上个月的最后一天(字符串形式) + * @param dateStr 输入日期字符串 (yyyy-MM-dd) + * @return 上个月最后一天的字符串 + */ + public static String getLastDayOfPreviousMonthStr(String dateStr) { + return getLastDayOfPreviousMonthStr(dateStr,1); + } + + public static String getLastDayOfPreviousMonthStr(String dateStr,int month) { + LocalDate date = parseDate(dateStr); + if (date == null) { + return null; + } + // 获取当月第一天,再减一天得到上个月最后一天 + LocalDate firstDayOfCurrentMonth = date.minusMonths(month-1).withDayOfMonth(1); + LocalDate lastDayOfPrevMonth = firstDayOfCurrentMonth.minusDays(1); + return formatDate(lastDayOfPrevMonth); + } + + /** + * 将 LocalDate 格式化为 yyyy-MM 字符串 + * @param date 输入日期 + * @return 年月字符串 (yyyy-MM) + */ + public static String formatToYearMonth(LocalDate date) { + if (date == null) { + return null; + } + return date.format(DateTimeFormatter.ofPattern("yyyy-MM")); + } + + public static String formatToYearMonth_ZH(LocalDate date) { + if (date == null) { + return null; + } + return date.format(DateTimeFormatter.ofPattern("yyyy年MM月")); + } + + /** + * 将日期字符串 (yyyy-MM-dd) 转换为年月字符串 (yyyy-MM) + * @param dateStr 输入日期字符串 + * @return 年月字符串 (yyyy-MM) + */ + public static String formatToYearMonth(String dateStr) { + LocalDate date = parseDate(dateStr); + return formatToYearMonth(date); + } + + public static String formatToYearMonth_ZH(String dateStr) { + LocalDate date = parseDate(dateStr); + return formatToYearMonth_ZH(date); + } +} \ No newline at end of file diff --git a/src/main/resources/mapper/LeaderCockpitMapper.xml b/src/main/resources/mapper/LeaderCockpitMapper.xml new file mode 100644 index 0000000..99000e8 --- /dev/null +++ b/src/main/resources/mapper/LeaderCockpitMapper.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + +