feat(hrm): 添加请假统计功能

- 在控制器中新增 /stats 接口用于获取请假统计数据
- 新增 HrmLeaveStatsVo 数据传输对象定义统计结构
- 在数据访问层添加多个统计查询方法,包括按类型、部门、月份统计
- 实现服务层统计业务逻辑,包括请假汇总、分类统计、员工状态统计
- 配置 MyBatis 映射文件实现各维度统计 SQL 查询
- 添加员工总数和请假中员工数的统计功能
This commit is contained in:
2026-02-24 14:56:51 +08:00
parent 613bf59833
commit 4447fb1cb1
6 changed files with 211 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.bo.HrmLeaveReqBo;
import com.ruoyi.hrm.domain.vo.HrmLeaveReqVo;
import com.ruoyi.hrm.domain.vo.HrmLeaveStatsVo;
import com.ruoyi.hrm.service.IHrmLeaveReqService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
@@ -59,4 +60,9 @@ public class HrmLeaveReqController extends BaseController {
public R<List<HrmLeaveReqVo>> all(HrmLeaveReqBo bo) {
return R.ok(service.queryList(bo));
}
@GetMapping("/stats")
public R<HrmLeaveStatsVo> stats() {
return R.ok(service.getLeaveStats());
}
}

View File

@@ -0,0 +1,69 @@
package com.ruoyi.hrm.domain.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@Data
public class HrmLeaveStatsVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总请假申请数
*/
private Integer totalLeaveRequests;
/**
* 总请假时长(小时)
*/
private BigDecimal totalLeaveHours;
/**
* 按请假类型统计
*/
private List<LeaveTypeStats> leaveByType;
/**
* 按部门统计
*/
private List<DeptStats> leaveByDept;
/**
* 按月份统计(本年)
*/
private List<MonthStats> leaveByMonth;
/**
* 总员工数
*/
private Integer totalEmployees;
/**
* 请假中员工数
*/
private Integer leavingEmployees;
@Data
public static class LeaveTypeStats {
private String leaveType;
private Integer count;
private BigDecimal totalHours;
}
@Data
public static class DeptStats {
private Long deptId;
private String deptName;
private Integer count;
private BigDecimal totalHours;
}
@Data
public static class MonthStats {
private String month; // YYYY-MM
private Integer count;
private BigDecimal totalHours;
}
}

View File

@@ -5,10 +5,13 @@ import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.bo.HrmLeaveReqBo;
import com.ruoyi.hrm.domain.vo.HrmLeaveReqVo;
import com.ruoyi.hrm.domain.vo.HrmLeaveStatsVo;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.RowBounds;
import java.util.List;
import java.util.Map;
public interface HrmLeaveReqMapper extends BaseMapperPlus<HrmLeaveReqMapper, HrmLeaveReq, HrmLeaveReqVo> {
@@ -17,4 +20,17 @@ public interface HrmLeaveReqMapper extends BaseMapperPlus<HrmLeaveReqMapper, Hrm
List<HrmLeaveReqVo> selectVoWithProjectByPage(IPage<HrmLeaveReqVo> page, @Param("bo") HrmLeaveReqBo bo);
List<HrmLeaveReqVo> selectVoWithProjectList(@Param("bo") HrmLeaveReqBo bo);
// 统计相关方法
Map<String, Object> selectLeaveSummary();
List<Map<String, Object>> selectLeaveByType();
List<Map<String, Object>> selectLeaveByDept();
List<Map<String, Object>> selectLeaveByMonth(@Param("year") Integer year);
Integer selectTotalEmployees();
Integer selectLeavingEmployees();
}

View File

@@ -5,6 +5,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.bo.HrmLeaveReqBo;
import com.ruoyi.hrm.domain.vo.HrmLeaveReqVo;
import com.ruoyi.hrm.domain.vo.HrmLeaveStatsVo;
import java.util.Collection;
import java.util.List;
@@ -24,4 +25,7 @@ public interface IHrmLeaveReqService {
Boolean updateByBo(HrmLeaveReqBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
// 统计方法
HrmLeaveStatsVo getLeaveStats();
}

View File

@@ -13,6 +13,13 @@ import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.bo.HrmFlowStartBo;
import com.ruoyi.hrm.domain.bo.HrmLeaveReqBo;
import com.ruoyi.hrm.domain.vo.HrmLeaveReqVo;
import com.ruoyi.hrm.domain.vo.HrmLeaveStatsVo;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.ruoyi.hrm.mapper.HrmFlowTemplateMapper;
import com.ruoyi.hrm.mapper.HrmLeaveReqMapper;
import com.ruoyi.hrm.service.IHrmFlowInstanceService;
@@ -117,6 +124,55 @@ public class HrmLeaveReqServiceImpl implements IHrmLeaveReqService {
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public HrmLeaveStatsVo getLeaveStats() {
HrmLeaveStatsVo stats = new HrmLeaveStatsVo();
// 获取汇总数据
Map<String, Object> summary = baseMapper.selectLeaveSummary();
stats.setTotalLeaveRequests(((Long) summary.get("totalRequests")).intValue());
stats.setTotalLeaveHours((BigDecimal) summary.get("totalHours"));
// 按类型统计
List<Map<String, Object>> leaveByType = baseMapper.selectLeaveByType();
stats.setLeaveByType(leaveByType.stream().map(map -> {
HrmLeaveStatsVo.LeaveTypeStats s = new HrmLeaveStatsVo.LeaveTypeStats();
s.setLeaveType((String) map.get("leaveType"));
s.setCount(((Long) map.get("count")).intValue());
s.setTotalHours((BigDecimal) map.get("totalHours"));
return s;
}).collect(Collectors.toList()));
// 按部门统计
List<Map<String, Object>> leaveByDept = baseMapper.selectLeaveByDept();
stats.setLeaveByDept(leaveByDept.stream().map(map -> {
HrmLeaveStatsVo.DeptStats s = new HrmLeaveStatsVo.DeptStats();
s.setDeptName((String) map.get("deptName"));
s.setCount(((Long) map.get("count")).intValue());
s.setTotalHours((BigDecimal) map.get("totalHours"));
return s;
}).collect(Collectors.toList()));
// 按月份统计(当前年)
int currentYear = LocalDate.now().getYear();
List<Map<String, Object>> leaveByMonth = baseMapper.selectLeaveByMonth(currentYear);
stats.setLeaveByMonth(leaveByMonth.stream().map(map -> {
HrmLeaveStatsVo.MonthStats s = new HrmLeaveStatsVo.MonthStats();
s.setMonth((String) map.get("month"));
s.setCount(((Long) map.get("count")).intValue());
s.setTotalHours((BigDecimal) map.get("totalHours"));
return s;
}).collect(Collectors.toList()));
// 总员工数
stats.setTotalEmployees(baseMapper.selectTotalEmployees());
// 请假中员工数
stats.setLeavingEmployees(baseMapper.selectLeavingEmployees());
return stats;
}
private LambdaQueryWrapper<HrmLeaveReq> buildQueryWrapper(HrmLeaveReqBo bo) {
LambdaQueryWrapper<HrmLeaveReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmLeaveReq::getBizId, bo.getBizId());

View File

@@ -149,4 +149,64 @@
</if>
ORDER BY l.create_time DESC
</select>
<!-- 统计查询 -->
<select id="selectLeaveSummary" resultType="java.util.Map">
SELECT
COUNT(*) as totalRequests,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
</select>
<select id="selectLeaveByType" resultType="java.util.Map">
SELECT
leave_type as leaveType,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
GROUP BY leave_type
ORDER BY totalHours DESC
</select>
<select id="selectLeaveByDept" resultType="java.util.Map">
SELECT
d.dept_name as deptName,
COUNT(l.biz_id) as count,
SUM(l.hours) as totalHours
FROM hrm_leave_req l
JOIN hrm_employee e ON l.emp_id = e.emp_id AND e.del_flag = 0
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id AND d.del_flag = '0'
WHERE l.del_flag = 0
AND l.status = 'approved'
GROUP BY d.dept_id, d.dept_name
ORDER BY totalHours DESC
</select>
<select id="selectLeaveByMonth" resultType="java.util.Map">
SELECT
DATE_FORMAT(start_time, '%Y-%m') as month,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
AND YEAR(start_time) = #{year}
GROUP BY DATE_FORMAT(start_time, '%Y-%m')
ORDER BY month
</select>
<select id="selectTotalEmployees" resultType="java.lang.Integer">
SELECT COUNT(*) FROM hrm_employee WHERE del_flag = 0 AND status = 'onboard'
</select>
<select id="selectLeavingEmployees" resultType="java.lang.Integer">
SELECT COUNT(DISTINCT l.emp_id)
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND l.status = 'approved'
AND NOW() BETWEEN l.start_time AND l.end_time
</select>
</mapper>