薪资分析
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package com.ruoyi.oa.controller;
|
||||
|
||||
|
||||
import com.ruoyi.common.core.AjaxResult;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.oa.domain.vo.SalaryDashboardVo;
|
||||
import com.ruoyi.oa.service.ISalaryDashboardService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/oa/salary/dashboard")
|
||||
public class SalaryDashboardController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ISalaryDashboardService salaryDashboardService;
|
||||
|
||||
@GetMapping
|
||||
public R<SalaryDashboardVo>getDashboardData(
|
||||
@RequestParam(required = true) Long payYear,
|
||||
@RequestParam(required = true) Long payMonth
|
||||
) {
|
||||
return R.ok(
|
||||
salaryDashboardService.getDashboardData(payYear, payMonth)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,10 @@ public class OaEmployee extends BaseEntity {
|
||||
* 姓名
|
||||
*/
|
||||
private String employeeName;
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
/**
|
||||
* 公司
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class CardDataVo {
|
||||
private BigDecimal totalSalaryExpenditure;
|
||||
private BigDecimal lastMonthTotalSalaryExpenditureRate;
|
||||
private BigDecimal avgDepartmentExpenditure;
|
||||
private BigDecimal lastMonthAvgDepartmentExpenditureRate;
|
||||
private BigDecimal avgPersonSalary;
|
||||
private BigDecimal lastMonthAvgPersonSalaryRate;
|
||||
private BigDecimal yearOnYearGrowthRate;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class CardMetricsVo {
|
||||
private BigDecimal totalSalaryExpenditure;
|
||||
private BigDecimal totalCompanyExpenditure;
|
||||
private Integer employeeCount;
|
||||
private Integer departmentCount;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ChartDataVo {
|
||||
private List<MonthlyExpenditureVo> monthlyExpenditures;
|
||||
private List<SalaryComponentVo> salaryComponents;
|
||||
private LineChartVo lineChartData;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class DepartmentStatVo {
|
||||
private Long deptId;
|
||||
private String deptName;
|
||||
private BigDecimal totalExpenditure;
|
||||
private BigDecimal avgSalary;
|
||||
private Integer employeeCount;
|
||||
private BigDecimal yearOnYearGrowthRate;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class LineChartPointVo {
|
||||
private Integer month;
|
||||
private BigDecimal totalExpenditure;
|
||||
private BigDecimal avgSalary;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class LineChartVo {
|
||||
private List<Integer> months;
|
||||
private List<BigDecimal> totalExpenditures;
|
||||
private List<BigDecimal> avgSalaries;
|
||||
|
||||
public LineChartVo(List<LineChartPointVo> points) {
|
||||
this.months = new ArrayList<>();
|
||||
this.totalExpenditures = new ArrayList<>();
|
||||
this.avgSalaries = new ArrayList<>();
|
||||
|
||||
for (LineChartPointVo point : points) {
|
||||
this.months.add(point.getMonth());
|
||||
this.totalExpenditures.add(point.getTotalExpenditure());
|
||||
this.avgSalaries.add(point.getAvgSalary());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class MonthlyExpenditureVo {
|
||||
private Integer month;
|
||||
private BigDecimal totalExpenditure;
|
||||
}
|
||||
@@ -44,6 +44,16 @@ public class OaEmployeeVo {
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@ExcelProperty(value = "部门ID")
|
||||
private Long deptId;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class SalaryComponentVo {
|
||||
private String itemName;
|
||||
private BigDecimal totalAmount;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SalaryDashboardVo {
|
||||
private CardDataVo cardData;
|
||||
private ChartDataVo chartData;
|
||||
private TableDataInfo<DepartmentStatVo> departmentStats;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruoyi.oa.mapper;
|
||||
|
||||
import com.ruoyi.oa.domain.vo.*;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SalaryDashboardMapper {
|
||||
|
||||
CardMetricsVo queryCardMetrics(@Param("year") Long year, @Param("month") Long month);
|
||||
|
||||
List<MonthlyExpenditureVo> queryMonthlyExpenditures(@Param("year") Long year);
|
||||
|
||||
List<SalaryComponentVo> querySalaryComponents(@Param("year") Long year, @Param("month") Long month);
|
||||
|
||||
List<LineChartPointVo> queryLineChartData(@Param("year") Long year);
|
||||
|
||||
List<DepartmentStatVo> queryDepartmentStats(@Param("year") Long year, @Param("month") Long month);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ruoyi.oa.service;
|
||||
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.oa.domain.vo.SalaryDashboardVo;
|
||||
|
||||
public interface ISalaryDashboardService {
|
||||
SalaryDashboardVo getDashboardData(Long payYear, Long payMonth);
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.ruoyi.oa.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.oa.domain.bo.OaEmployeeBo;
|
||||
@@ -18,6 +21,8 @@ import com.ruoyi.oa.service.IOaEmployeeService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 员工基础信息Service业务层处理
|
||||
@@ -30,6 +35,7 @@ import java.util.Collection;
|
||||
public class OaEmployeeServiceImpl implements IOaEmployeeService {
|
||||
|
||||
private final OaEmployeeMapper baseMapper;
|
||||
private final SysDeptMapper deptMapper;
|
||||
|
||||
/**
|
||||
* 查询员工基础信息
|
||||
@@ -46,6 +52,35 @@ public class OaEmployeeServiceImpl implements IOaEmployeeService {
|
||||
public TableDataInfo<OaEmployeeVo> queryPageList(OaEmployeeBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<OaEmployee> lqw = buildQueryWrapper(bo);
|
||||
Page<OaEmployeeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
// 根据部门id查询部门名称
|
||||
if (CollectionUtils.isNotEmpty(result.getRecords())) {
|
||||
// 提取所有部门ID
|
||||
List<Long> deptIds = result.getRecords().stream()
|
||||
.map(OaEmployeeVo::getDeptId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量查询部门信息
|
||||
if (!deptIds.isEmpty()) {
|
||||
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.in(SysDept::getDeptId, deptIds)
|
||||
.eq(SysDept::getDelFlag, '0'); // 只查询未删除的部门
|
||||
|
||||
List<SysDept> deptList = deptMapper.selectList(queryWrapper);
|
||||
Map<Long, String> deptNameMap = deptList.stream()
|
||||
.collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName, (k1, k2) -> k1));
|
||||
|
||||
// 将部门名称设置到对应的VO对象中
|
||||
for (OaEmployeeVo vo : result.getRecords()) {
|
||||
if (vo.getDeptId() != null) {
|
||||
vo.setDeptName(deptNameMap.getOrDefault(vo.getDeptId(), "未知部门"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.ruoyi.oa.service.impl;
|
||||
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.oa.domain.vo.*;
|
||||
import com.ruoyi.oa.mapper.SalaryDashboardMapper;
|
||||
import com.ruoyi.oa.service.ISalaryDashboardService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SalaryDashboardServiceImpl implements ISalaryDashboardService {
|
||||
|
||||
@Autowired
|
||||
private SalaryDashboardMapper dashboardMapper;
|
||||
|
||||
@Override
|
||||
public SalaryDashboardVo getDashboardData(Long payYear, Long payMonth) {
|
||||
SalaryDashboardVo dashboardVo = new SalaryDashboardVo();
|
||||
|
||||
// 1. 获取卡片数据
|
||||
dashboardVo.setCardData(getCardData(payYear, payMonth));
|
||||
|
||||
// 2. 获取图表数据
|
||||
dashboardVo.setChartData(getChartData(payYear, payMonth));
|
||||
|
||||
// 3. 获取部门统计表格数据 (带分页)
|
||||
// PageHelper.startPage(pageNum, pageSize);
|
||||
List<DepartmentStatVo> deptStats = dashboardMapper.queryDepartmentStats(payYear, payMonth);
|
||||
TableDataInfo<DepartmentStatVo> tableData = new TableDataInfo<>(deptStats, deptStats.size());
|
||||
dashboardVo.setDepartmentStats(tableData);
|
||||
return dashboardVo;
|
||||
}
|
||||
|
||||
private CardDataVo getCardData(Long payYear, Long payMonth) {
|
||||
CardDataVo cardData = new CardDataVo();
|
||||
|
||||
// 获取当月数据
|
||||
CardMetricsVo currentMonthMetrics = dashboardMapper.queryCardMetrics(payYear, payMonth);
|
||||
|
||||
// 获取上月数据 (处理1月的情况)
|
||||
Long lastMonth = payMonth == 1 ? 12 : payMonth - 1;
|
||||
Long lastYear = payMonth == 1 ? payYear - 1 : payYear;
|
||||
CardMetricsVo lastMonthMetrics = dashboardMapper.queryCardMetrics(lastYear, lastMonth);
|
||||
|
||||
// 获取去年同期数据
|
||||
CardMetricsVo lastYearMetrics = dashboardMapper.queryCardMetrics(payYear - 1, payMonth);
|
||||
|
||||
// 计算各项指标
|
||||
cardData.setTotalSalaryExpenditure(currentMonthMetrics.getTotalSalaryExpenditure());
|
||||
|
||||
// 计算较上月增长率
|
||||
if (lastMonthMetrics.getTotalSalaryExpenditure().compareTo(BigDecimal.ZERO) != 0) {
|
||||
BigDecimal monthGrowth = currentMonthMetrics.getTotalSalaryExpenditure()
|
||||
.subtract(lastMonthMetrics.getTotalSalaryExpenditure())
|
||||
.divide(lastMonthMetrics.getTotalSalaryExpenditure(), 4, RoundingMode.HALF_UP)
|
||||
.multiply(new BigDecimal("100"));
|
||||
cardData.setLastMonthTotalSalaryExpenditureRate(monthGrowth);
|
||||
}
|
||||
|
||||
// 计算部门平均支出
|
||||
if (currentMonthMetrics.getDepartmentCount() > 0) {
|
||||
cardData.setAvgDepartmentExpenditure(
|
||||
currentMonthMetrics.getTotalCompanyExpenditure()
|
||||
.divide(new BigDecimal(currentMonthMetrics.getDepartmentCount()), 2, RoundingMode.HALF_UP)
|
||||
);
|
||||
}
|
||||
|
||||
// 计算人均实发工资
|
||||
if (currentMonthMetrics.getEmployeeCount() > 0) {
|
||||
cardData.setAvgPersonSalary(
|
||||
currentMonthMetrics.getTotalSalaryExpenditure()
|
||||
.divide(new BigDecimal(currentMonthMetrics.getEmployeeCount()), 2, RoundingMode.HALF_UP)
|
||||
);
|
||||
}
|
||||
|
||||
// 计算同比增长率
|
||||
if (lastYearMetrics.getEmployeeCount() > 0) {
|
||||
BigDecimal lastYearAvgSalary = lastYearMetrics.getTotalSalaryExpenditure()
|
||||
.divide(new BigDecimal(lastYearMetrics.getEmployeeCount()), 2, RoundingMode.HALF_UP);
|
||||
if (lastYearAvgSalary.compareTo(BigDecimal.ZERO) != 0) {
|
||||
BigDecimal yearGrowth = cardData.getAvgPersonSalary()
|
||||
.subtract(lastYearAvgSalary)
|
||||
.divide(lastYearAvgSalary, 4, RoundingMode.HALF_UP)
|
||||
.multiply(new BigDecimal("100"));
|
||||
cardData.setYearOnYearGrowthRate(yearGrowth);
|
||||
}
|
||||
}
|
||||
|
||||
return cardData;
|
||||
}
|
||||
|
||||
private ChartDataVo getChartData(Long payYear, Long payMonth) {
|
||||
ChartDataVo chartData = new ChartDataVo();
|
||||
|
||||
// 1. 获取柱状图数据 (年度每月总支出)
|
||||
List<MonthlyExpenditureVo> monthlyExpenditures =
|
||||
dashboardMapper.queryMonthlyExpenditures(payYear);
|
||||
chartData.setMonthlyExpenditures(monthlyExpenditures);
|
||||
|
||||
// 2. 获取饼图数据 (薪资构成)
|
||||
List<SalaryComponentVo> salaryComponents =
|
||||
dashboardMapper.querySalaryComponents(payYear, payMonth);
|
||||
chartData.setSalaryComponents(salaryComponents);
|
||||
|
||||
// 3. 获取折线图数据 (总支出 vs 平均工资)
|
||||
List<LineChartPointVo> lineChartData =
|
||||
dashboardMapper.queryLineChartData(payYear);
|
||||
chartData.setLineChartData(new LineChartVo(lineChartData));
|
||||
|
||||
return chartData;
|
||||
}
|
||||
}
|
||||
143
ruoyi-oa/src/main/resources/mapper/oa/SalaryDashboardMapper.xml
Normal file
143
ruoyi-oa/src/main/resources/mapper/oa/SalaryDashboardMapper.xml
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.oa.mapper.SalaryDashboardMapper">
|
||||
|
||||
<!-- 查询卡片指标数据 -->
|
||||
<select id="queryCardMetrics" resultType="com.ruoyi.oa.domain.vo.CardMetricsVo">
|
||||
SELECT
|
||||
-- 薪资支出总额:只计算salary类型的实际支出
|
||||
SUM(CASE WHEN d.template_type = 'salary' THEN d.paid_amount ELSE 0 END) AS totalSalaryExpenditure,
|
||||
-- 公司总支出:包括薪资和社保的所有实际支出
|
||||
SUM(d.paid_amount) AS totalCompanyExpenditure,
|
||||
COUNT(DISTINCT b.employee_id) AS employeeCount,
|
||||
COUNT(DISTINCT e.dept_id) AS departmentCount
|
||||
FROM
|
||||
oa_employee_template_binding b
|
||||
JOIN oa_binding_item_detail d ON b.binding_id = d.binding_id
|
||||
JOIN oa_employee e ON b.employee_id = e.employee_id
|
||||
WHERE
|
||||
b.pay_year = #{year}
|
||||
AND b.pay_month = #{month}
|
||||
AND b.del_flag = 0
|
||||
AND e.del_flag = 0
|
||||
AND d.del_flag = 0
|
||||
</select>
|
||||
|
||||
<!-- 查询年度每月总支出 -->
|
||||
<select id="queryMonthlyExpenditures" resultType="com.ruoyi.oa.domain.vo.MonthlyExpenditureVo">
|
||||
SELECT
|
||||
b.pay_month AS month,
|
||||
SUM(d.paid_amount) AS totalExpenditure
|
||||
FROM
|
||||
oa_employee_template_binding b
|
||||
JOIN oa_binding_item_detail d ON b.binding_id = d.binding_id
|
||||
WHERE
|
||||
b.pay_year = #{year}
|
||||
AND b.del_flag = 0
|
||||
AND d.del_flag = 0
|
||||
GROUP BY
|
||||
b.pay_month
|
||||
ORDER BY
|
||||
b.pay_month
|
||||
</select>
|
||||
|
||||
<!-- 查询薪资构成 -->
|
||||
<select id="querySalaryComponents" resultType="com.ruoyi.oa.domain.vo.SalaryComponentVo">
|
||||
SELECT
|
||||
sdt.salary_item AS itemName,
|
||||
SUM(bid.paid_amount) AS totalAmount
|
||||
FROM
|
||||
oa_binding_item_detail bid
|
||||
JOIN oa_employee_template_binding betb ON bid.binding_id = betb.binding_id
|
||||
JOIN oa_salary_template_detail sdt ON bid.item_detail_id = sdt.salary_detail_id
|
||||
WHERE
|
||||
betb.pay_year = #{year}
|
||||
AND betb.pay_month = #{month}
|
||||
AND bid.template_type = 'salary'
|
||||
AND betb.del_flag = 0
|
||||
AND bid.del_flag = 0
|
||||
GROUP BY
|
||||
sdt.salary_item
|
||||
</select>
|
||||
|
||||
<!-- 查询折线图数据 -->
|
||||
<select id="queryLineChartData" resultType="com.ruoyi.oa.domain.vo.LineChartPointVo">
|
||||
SELECT
|
||||
b.pay_month AS month,
|
||||
-- 总支出:所有实际支出(包括薪资和社保)
|
||||
SUM(d.paid_amount) AS totalExpenditure,
|
||||
-- 平均工资:只计算salary类型的实际支出的平均值
|
||||
AVG(CASE WHEN d.template_type = 'salary' THEN d.paid_amount ELSE 0 END) AS avgSalary
|
||||
FROM
|
||||
oa_employee_template_binding b
|
||||
JOIN oa_binding_item_detail d ON b.binding_id = d.binding_id
|
||||
WHERE
|
||||
b.pay_year = #{year}
|
||||
AND b.del_flag = 0
|
||||
AND d.del_flag = 0
|
||||
GROUP BY
|
||||
b.pay_month
|
||||
ORDER BY
|
||||
b.pay_month
|
||||
</select>
|
||||
|
||||
<!-- 查询部门统计数据 -->
|
||||
<select id="queryDepartmentStats" resultType="com.ruoyi.oa.domain.vo.DepartmentStatVo">
|
||||
WITH CurrentYearStats AS (
|
||||
SELECT
|
||||
e.dept_id,
|
||||
-- 部门总支出:该部门所有员工的所有实际支出
|
||||
SUM(d.paid_amount) AS totalExpenditure,
|
||||
-- 部门平均工资:该部门所有员工的salary类型实际支出的平均值
|
||||
AVG(CASE WHEN d.template_type = 'salary' THEN d.paid_amount ELSE 0 END) AS avgSalary,
|
||||
COUNT(DISTINCT e.employee_id) AS employeeCount
|
||||
FROM
|
||||
oa_employee_template_binding b
|
||||
JOIN oa_employee e ON b.employee_id = e.employee_id
|
||||
JOIN oa_binding_item_detail d ON b.binding_id = d.binding_id
|
||||
WHERE
|
||||
b.pay_year = #{year}
|
||||
AND b.pay_month = #{month}
|
||||
AND b.del_flag = 0
|
||||
AND d.del_flag = 0
|
||||
GROUP BY
|
||||
e.dept_id
|
||||
),
|
||||
LastYearStats AS (
|
||||
SELECT
|
||||
e.dept_id,
|
||||
-- 去年同期部门平均工资:只计算salary类型的实际支出
|
||||
AVG(CASE WHEN d.template_type = 'salary' THEN d.paid_amount ELSE 0 END) AS lastYearAvgSalary
|
||||
FROM
|
||||
oa_employee_template_binding b
|
||||
JOIN oa_employee e ON b.employee_id = e.employee_id
|
||||
JOIN oa_binding_item_detail d ON b.binding_id = d.binding_id
|
||||
WHERE
|
||||
b.pay_year = #{year} - 1
|
||||
AND b.pay_month = #{month}
|
||||
AND b.del_flag = 0
|
||||
AND d.del_flag = 0
|
||||
GROUP BY
|
||||
e.dept_id
|
||||
)
|
||||
SELECT
|
||||
d.dept_id,
|
||||
d.dept_name,
|
||||
COALESCE(cys.totalExpenditure, 0) AS totalExpenditure,
|
||||
COALESCE(cys.avgSalary, 0) AS avgSalary,
|
||||
COALESCE(cys.employeeCount, 0) AS employeeCount,
|
||||
CASE
|
||||
WHEN lys.lastYearAvgSalary IS NULL OR lys.lastYearAvgSalary = 0 THEN 0
|
||||
ELSE ((COALESCE(cys.avgSalary, 0) - lys.lastYearAvgSalary) / lys.lastYearAvgSalary) * 100
|
||||
END AS yearOnYearGrowthRate
|
||||
FROM
|
||||
sys_dept d
|
||||
LEFT JOIN CurrentYearStats cys ON d.dept_id = cys.dept_id
|
||||
LEFT JOIN LastYearStats lys ON d.dept_id = lys.dept_id
|
||||
WHERE
|
||||
d.del_flag = '0'
|
||||
AND cys.employeeCount > 0
|
||||
ORDER BY
|
||||
totalExpenditure DESC
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user