src/main/java/com/ruoyi/common/enums/StaffLeaveReason.java
@@ -25,4 +25,18 @@ public String getInfo() { return info; } /** * æ ¹æ®codeè·åæä¸¾å®ä¾ * @param code 离èåå ç¼ç * @return 对åºçæä¸¾å®ä¾ï¼è¥æªæ¾å°åè¿ånull */ public static StaffLeaveReason getByCode(String code) { for (StaffLeaveReason reason : StaffLeaveReason.values()) { if (reason.getCode().equals(code)) { return reason; } } return null; } } src/main/java/com/ruoyi/project/system/domain/SysDept.java
@@ -55,6 +55,9 @@ /** é¨é¨ç¼å· */ private String deptNick; /** åå·¥æ°é */ private Integer staffCount; /** åé¨é¨ */ private List<SysDept> children = new ArrayList<SysDept>(); @@ -192,6 +195,14 @@ this.deptNick = deptNick; } public Integer getStaffCount() { return staffCount; } public void setStaffCount(Integer staffCount) { this.staffCount = staffCount; } @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) @@ -199,6 +210,7 @@ .append("parentId", getParentId()) .append("ancestors", getAncestors()) .append("deptName", getDeptName()) .append("staffCount", getStaffCount()) .append("orderNum", getOrderNum()) .append("leader", getLeader()) .append("phone", getPhone()) src/main/java/com/ruoyi/staff/controller/AnalyticsController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,32 @@ package com.ruoyi.staff.controller; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.staff.service.AnalyticsService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/staff/analytics") public class AnalyticsController { @Resource private AnalyticsService analyticsService; @GetMapping("/reason") public AjaxResult staffLeaveReasonAnalytics() { return AjaxResult.success(analyticsService.staffLeaveReasonAnalytics()); } @GetMapping("/monthly_turnover_rate") public AjaxResult getMonthlyTurnoverRateFor12Months() { return AjaxResult.success(analyticsService.getMonthlyTurnoverRateFor12Months()); } @GetMapping("/total_statistic") public AjaxResult getTotalStatistic() { return AjaxResult.success(analyticsService.getTotalStatistic()); } } src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java
@@ -1,11 +1,8 @@ package com.ruoyi.staff.dto; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import com.ruoyi.staff.pojo.StaffLeave; import lombok.Data; import java.util.Date; @Data public class StaffLeaveDto extends StaffLeave { @@ -95,4 +92,11 @@ */ @Excel(name = "ç´§æ¥è系人çµè¯", sort = 15) private String emergencyContactPhone; private int count; /** * 离èåå ææ¬ */ private String reasonText; } src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java
@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.time.LocalDate; import java.util.List; @@ -18,4 +19,8 @@ IPage<StaffLeaveDto> staffLeaveListPage(Page page, @Param("c") StaffLeaveDto staffLeaveDto); List<StaffLeaveDto> staffLeaveList(@Param("c") StaffLeaveDto staffLeaveDto); List<StaffLeaveDto> staffLeaveReasonAnalytics(); Integer countLeaveByMonth(@Param("monthStart") LocalDate monthStart, @Param("monthEnd") LocalDate monthEnd); } src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
@@ -8,6 +8,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.time.LocalDate; import java.util.List; @Mapper @@ -16,4 +17,19 @@ IPage<StaffOnJobDto> staffOnJobListPage(Page page, @Param("staffOnJob") StaffOnJob staffOnJob); List<StaffOnJobDto> staffOnJobList(@Param("staffOnJob") StaffOnJob staffOnJob); /** * ç»è®¡æå®æ¥æçå¨èåå·¥æ° * @param date æ¥æ * @return å¨èåå·¥æ° */ Integer countOnJobStaffByDate(@Param("date") LocalDate date); /** * ç»è®¡æå®æä»½çæ°å ¥èåå·¥æ° * @param monthStart æä»½å¼å§æ¥æ * @param monthEnd æä»½ç»ææ¥æ * @return æ°å ¥èåå·¥æ° */ Integer countNewHireByMonth(@Param("monthStart") LocalDate monthStart, @Param("monthEnd") LocalDate monthEnd); } src/main/java/com/ruoyi/staff/service/AnalyticsService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.staff.service; import com.ruoyi.staff.dto.StaffLeaveDto; import com.ruoyi.staff.vo.MonthlyTurnoverRateVo; import com.ruoyi.staff.vo.TotalTurnoverRateVo; import java.util.List; public interface AnalyticsService { List<StaffLeaveDto> staffLeaveReasonAnalytics(); List<MonthlyTurnoverRateVo> getMonthlyTurnoverRateFor12Months(); /** * æ¥è¯¢æ»æµå¨çãæµå¤±ç以åå¨èåå·¥æ° * @return æ»ç»è®¡ç»æ */ TotalTurnoverRateVo getTotalStatistic(); } src/main/java/com/ruoyi/staff/service/impl/AnalyticsServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,145 @@ package com.ruoyi.staff.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StaffLeaveReason; import com.ruoyi.staff.dto.StaffLeaveDto; import com.ruoyi.staff.mapper.StaffLeaveMapper; import com.ruoyi.staff.mapper.StaffOnJobMapper; import com.ruoyi.staff.pojo.StaffLeave; import com.ruoyi.staff.service.AnalyticsService; import com.ruoyi.staff.vo.MonthlyTurnoverRateVo; import com.ruoyi.staff.vo.TotalTurnoverRateVo; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; @AllArgsConstructor @Service public class AnalyticsServiceImpl extends ServiceImpl<StaffLeaveMapper, StaffLeave> implements AnalyticsService { @Autowired private StaffLeaveMapper staffLeaveMapper; @Autowired private StaffOnJobMapper staffOnJobMapper; @Override public List<StaffLeaveDto> staffLeaveReasonAnalytics() { List<StaffLeaveDto> result = staffLeaveMapper.staffLeaveReasonAnalytics(); result.forEach(dto -> { String reasonCode = dto.getReason(); StaffLeaveReason reasonEnum = StaffLeaveReason.getByCode(reasonCode); if (reasonEnum != null) { dto.setReasonText(reasonEnum.getInfo()); } else { dto.setReasonText("æªç¥åå "); } }); return result; } @Override public List<MonthlyTurnoverRateVo> getMonthlyTurnoverRateFor12Months() { List<MonthlyTurnoverRateVo> result = new ArrayList<>(); LocalDate now = LocalDate.now(); DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 计ç®è¿12个æçæ°æ® for (int i = 11; i >= 0; i--) { LocalDate currentMonth = now.minusMonths(i); LocalDate monthStart = currentMonth.withDayOfMonth(1); LocalDate monthEnd = currentMonth.withDayOfMonth(currentMonth.lengthOfMonth()); MonthlyTurnoverRateVo vo = new MonthlyTurnoverRateVo(); vo.setMonth(currentMonth.format(monthFormatter)); vo.setMonthStartDate(monthStart); vo.setMonthEndDate(monthEnd); // æååå·¥æ°ï¼ä¸ææ«å¨èåå·¥æ°ï¼ LocalDate lastMonthEnd = monthStart.minusDays(1); Integer beginMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(lastMonthEnd); vo.setBeginMonthStaffCount(beginMonthStaffCount != null ? beginMonthStaffCount : 0); // ææ«åå·¥æ° Integer endMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(monthEnd); vo.setEndMonthStaffCount(endMonthStaffCount != null ? endMonthStaffCount : 0); // æåº¦å ¥èåå·¥æ° Integer newHireCount = staffOnJobMapper.countNewHireByMonth(monthStart, monthEnd); vo.setNewHireCount(newHireCount != null ? newHireCount : 0); // æåº¦ç¦»èåå·¥æ° Integer leaveCount = staffLeaveMapper.countLeaveByMonth(monthStart, monthEnd); vo.setLeaveCount(leaveCount != null ? leaveCount : 0); // è®¡ç®æµå¤±çï¼æµå¤±ç = æåº¦ç¦»èåå·¥æ° / æååå·¥æ° * 100% Double turnoverRate = 0.0; if (vo.getBeginMonthStaffCount() > 0) { turnoverRate = (double) vo.getLeaveCount() / vo.getBeginMonthStaffCount() * 100; // ä¿ç两ä½å°æ° turnoverRate = Math.round(turnoverRate * 100.0) / 100.0; } vo.setTurnoverRate(turnoverRate); // è®¡ç®æµå¨çï¼æµå¨ç = (æåº¦å ¥èåå·¥æ° + æåº¦ç¦»èåå·¥æ°) / æååå·¥æ° * 100% Double flowRate = 0.0; if (vo.getBeginMonthStaffCount() > 0) { flowRate = (double) (vo.getNewHireCount() + vo.getLeaveCount()) / vo.getBeginMonthStaffCount() * 100; // ä¿ç两ä½å°æ° flowRate = Math.round(flowRate * 100.0) / 100.0; } vo.setFlowRate(flowRate); result.add(vo); } return result; } @Override public TotalTurnoverRateVo getTotalStatistic() { TotalTurnoverRateVo result = new TotalTurnoverRateVo(); LocalDate now = LocalDate.now(); // è·åå½åå¨èåå·¥æ° Integer currentOnJobCount = staffOnJobMapper.countOnJobStaffByDate(now); result.setCurrentOnJobCount(currentOnJobCount); // è·åæ¬æçå¼å§åç»ææ¥æ LocalDate monthStartDate = now.withDayOfMonth(1); LocalDate monthEndDate = now.withDayOfMonth(now.lengthOfMonth()); // è·åæååå·¥æ°ï¼å³ä¸ææ«åå·¥æ°ï¼ Integer beginMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(monthStartDate.minusDays(1)); // è·åæ¬ææ°å ¥èåå·¥æ° Integer newHireCount = staffOnJobMapper.countNewHireByMonth(monthStartDate, monthEndDate); // è·åæ¬æç¦»èåå·¥æ° Integer leaveCount = staffLeaveMapper.countLeaveByMonth(monthStartDate, monthEndDate); // è®¡ç®æ»æµå¨ç = (å ¥èäººæ° + 离è人æ°) / æååå·¥æ° * 100% Double totalFlowRate = 0.0; if (beginMonthStaffCount > 0) { totalFlowRate = (double) (newHireCount + leaveCount) / beginMonthStaffCount * 100; // ä¿ç两ä½å°æ° totalFlowRate = Math.round(totalFlowRate * 100.0) / 100.0; } result.setTotalFlowRate(totalFlowRate); // è®¡ç®æ»æµå¤±ç = 离èäººæ° / æååå·¥æ° * 100% Double totalTurnoverRate = 0.0; if (beginMonthStaffCount > 0) { totalTurnoverRate = (double) leaveCount / beginMonthStaffCount * 100; // ä¿ç两ä½å°æ° totalTurnoverRate = Math.round(totalTurnoverRate * 100.0) / 100.0; } result.setTotalTurnoverRate(totalTurnoverRate); return result; } } src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
@@ -11,6 +11,7 @@ import com.ruoyi.staff.pojo.StaffOnJob; import com.ruoyi.staff.service.StaffLeaveService; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.staff.pojo.StaffLeave; import org.springframework.transaction.annotation.Transactional; @@ -23,8 +24,10 @@ @AllArgsConstructor @Service public class StaffLeaveServiceImpl extends ServiceImpl<StaffLeaveMapper, StaffLeave> implements StaffLeaveService { @Autowired private StaffLeaveMapper staffLeaveMapper; @Autowired private StaffOnJobMapper staffOnJobMapper; //æ°å¢ç¦»èå表å页æ¥è¯¢ @@ -97,6 +100,5 @@ ExcelUtil<StaffLeaveDto> util = new ExcelUtil<StaffLeaveDto>(StaffLeaveDto.class); util.exportExcel(response, staffLeaves, "å工离è导åº"); } } src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -23,6 +23,7 @@ import lombok.AllArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -39,12 +40,14 @@ @Service public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob> implements IStaffOnJobService { @Autowired private StaffOnJobMapper staffOnJobMapper; @Autowired private SysPostMapper sysPostMapper; @Autowired private StaffContractMapper staffContractMapper; @Autowired private StaffLeaveMapper staffLeaveMapper; src/main/java/com/ruoyi/staff/vo/MonthlyTurnoverRateVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,39 @@ package com.ruoyi.staff.vo; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDate; /** * æåº¦åå·¥æµå¨ç念失çç»è®¡VO */ @Data public class MonthlyTurnoverRateVo { @ApiModelProperty("æä»½") private String month; @ApiModelProperty("æååå·¥æ°") private Integer beginMonthStaffCount; @ApiModelProperty("ææ«åå·¥æ°") private Integer endMonthStaffCount; @ApiModelProperty("æåº¦å ¥èåå·¥æ°") private Integer newHireCount; @ApiModelProperty("æåº¦ç¦»èåå·¥æ°") private Integer leaveCount; @ApiModelProperty("æµå¤±ç(%)") private Double turnoverRate; @ApiModelProperty("æµå¨ç(%)") private Double flowRate; @ApiModelProperty("æä»½å¼å§æ¥æ") private LocalDate monthStartDate; @ApiModelProperty("æä»½ç»ææ¥æ") private LocalDate monthEndDate; } src/main/java/com/ruoyi/staff/vo/TotalTurnoverRateVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,19 @@ package com.ruoyi.staff.vo; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * åå·¥æ»æµå¨çãæµå¤±çåå¨èåå·¥æ°ç»è®¡VO */ @Data public class TotalTurnoverRateVo { @ApiModelProperty("æ»æµå¨ç(%)") private Double totalFlowRate; @ApiModelProperty("æ»æµå¤±ç(%)") private Double totalTurnoverRate; @ApiModelProperty("å½åå¨èåå·¥æ°") private Integer currentOnJobCount; } src/main/resources/mapper/staff/StaffLeaveMapper.xml
@@ -61,4 +61,24 @@ AND soj.staff_name LIKE CONCAT('%',#{c.staffName},'%') </if> </select> <select id="staffLeaveReasonAnalytics" resultType="com.ruoyi.staff.dto.StaffLeaveDto"> SELECT staff_leave.reason as reason, COUNT(*) as count FROM staff_leave LEFT JOIN staff_on_job soj ON soj.id = staff_leave.staff_on_job_id where 1=1 GROUP BY staff_leave.reason </select> <!-- ç»è®¡æå®æä»½ç离èåå·¥æ° --> <select id="countLeaveByMonth" resultType="java.lang.Integer"> SELECT COUNT(*) FROM staff_leave sl LEFT JOIN staff_on_job soj ON sl.staff_on_job_id = soj.id WHERE DATE_FORMAT(sl.create_time, '%Y-%m-%d') BETWEEN #{monthStart} AND #{monthEnd} AND soj.staff_state = 0 </select> </mapper> src/main/resources/mapper/staff/StaffOnJobMapper.xml
@@ -43,4 +43,19 @@ AND staff_name LIKE CONCAT('%',#{staffOnJob.staffName},'%') </if> </select> <!-- ç»è®¡æå®æ¥æçå¨èåå·¥æ° --> <select id="countOnJobStaffByDate" resultType="java.lang.Integer"> SELECT COUNT(*) FROM staff_on_job WHERE staff_state = 1 AND DATE_FORMAT(create_time, '%Y-%m-%d') <= #{date} </select> <!-- ç»è®¡æå®æä»½çæ°å ¥èåå·¥æ° --> <select id="countNewHireByMonth" resultType="java.lang.Integer"> SELECT COUNT(*) FROM staff_on_job WHERE staff_state = 1 AND DATE_FORMAT(create_time, '%Y-%m-%d') BETWEEN #{monthStart} AND #{monthEnd} </select> </mapper> src/main/resources/mapper/system/SysDeptMapper.xml
@@ -20,6 +20,7 @@ <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> <result property="staffCount" column="staff_count" /> </resultMap> <sql id="selectDeptVo"> @@ -28,22 +29,26 @@ </sql> <select id="selectDeptList" parameterType="com.ruoyi.project.system.domain.SysDept" resultMap="SysDeptResult"> <include refid="selectDeptVo"/> select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time, count(distinct soj.id) as staff_count from sys_dept d left join staff_on_job soj on soj.sys_dept_id = d.dept_id and soj.staff_state = '1' where d.del_flag = '0' <if test="deptId != null and deptId != 0"> AND dept_id = #{deptId} AND d.dept_id = #{deptId} </if> <if test="parentId != null and parentId != 0"> AND parent_id = #{parentId} AND d.parent_id = #{parentId} </if> <if test="deptName != null and deptName != ''"> AND dept_name like concat('%', #{deptName}, '%') AND d.dept_name like concat('%', #{deptName}, '%') </if> <if test="status != null and status != ''"> AND status = #{status} AND d.status = #{status} </if> <!-- æ°æ®èå´è¿æ»¤ --> ${params.dataScope} group by d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time order by d.parent_id, d.order_num </select>