添加功能

This commit is contained in:
马宝龙
2026-06-28 04:01:00 +08:00
parent 18e90dacbf
commit aadf5654de
11 changed files with 1433 additions and 118 deletions

View File

@@ -10,6 +10,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CommonConstant {
/**
@@ -47,6 +48,15 @@ public class CommonConstant {
Tuples.of("652324524000", "150团"),
Tuples.of("659001500000", "152团")
)));
/**
* 团场Map
*/
public static final Map<String, String> AREA_MAP =
Collections.unmodifiableMap(AREA_LIST.stream()
.collect(Collectors.toMap(
Tuple2::getT1,
Tuple2::getT2
)));
/**
* 行业列表
@@ -104,6 +114,15 @@ public class CommonConstant {
Tuples.of("C27", "医药制造业"),
Tuples.of("M73", "研究和试验发展")
)));
/**
* 重点行业Map
*/
public static final Map<String, String> INDUSTRY_MAP =
Collections.unmodifiableMap(INDUSTRY_LIST.stream()
.collect(Collectors.toMap(
Tuple2::getT1,
Tuple2::getT2
)));
/**
* 高校类型列表

View File

@@ -0,0 +1,43 @@
package com.ruoyi.cms.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 行业就业情况信息分析 - sql
*
* @author 马宝龙
* @date 2026/6/28
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class IndustryEmploymentInfoSqlDto implements Serializable {
private static final long serialVersionUID = 7039748681473387889L;
/**
* 总人数
*/
private Long totalCount;
/**
* 签合同人数
*/
private Long signContractCount;
/**
* 交社保人数
*/
private Long socialInsuranceCount;
/**
* 薪资稳定人数
*/
private Long stableSalaryCount;
/**
* 工作满意人数
*/
private Long satisfiedWorkCount;
}

View File

@@ -1,10 +0,0 @@
package com.ruoyi.cms.mapper;
/**
* <类注释内容>
*
* @author 马宝龙
* @date 2026/6/24
*/
public interface TestMapper {
}

View File

@@ -0,0 +1,132 @@
package com.ruoyi.cms.mapper;
import com.ruoyi.cms.domain.dto.IndustryEmploymentInfoSqlDto;
import com.ruoyi.cms.domain.dto.QueryParamDto;
import com.ruoyi.cms.domain.vo.HeatmapVo;
import com.ruoyi.cms.domain.vo.QueryResultVo;
import com.ruoyi.cms.domain.vo.TreadVo;
import java.math.BigDecimal;
import java.util.List;
/**
* 就业登记主题库
*
* @author 马宝龙
* @date 2026/6/27
*/
public interface ThemeEmploymentRegisterMapper {
/**
* 查询就业登记人数
*
* @param dto 查询参数
* @return 人数
*/
Long queryEmploymentCount(QueryParamDto dto);
/**
* 查询创业企业总数
*
* @param dto 查询参数
* @return 数量
*/
Long queryStartupCompanyCount(QueryParamDto dto);
/**
* 查询创业企业总数
*
* @param dto 查询参数
* @return 数量
*/
Long queryStartupEmploymentCount(QueryParamDto dto);
/**
* 查询灵活就业人数
*
* @param dto 查询参数
* @return 数量
*/
Long queryFlexibleEmploymentCount(QueryParamDto dto);
/**
* 查询平均薪资
*
* @param dto 查询参数
* @return 平均薪资
*/
BigDecimal queryAverageSalary(QueryParamDto dto);
/**
* 行业就业规模与增长趋势 - 年度
*
* @param dto 查询参数
* @return 趋势列表
*/
List<TreadVo> scaleAndTrendYear(QueryParamDto dto);
/**
* 行业就业规模与增长趋势 - 季度
*
* @param dto 查询参数
* @return 趋势列表
*/
List<TreadVo> scaleAndTrendQuarter(QueryParamDto dto);
/**
* 行业就业规模与增长趋势 - 月度
*
* @param dto 查询参数
* @return 趋势列表
*/
List<TreadVo> scaleAndTrendMonth(QueryParamDto dto);
/**
* 行业就业规模对比
*
* @param dto 查询参数
* @return 结果列表
*/
List<QueryResultVo> scaleComparison(QueryParamDto dto);
/**
* 就业结构分析
*
* @param dto 查询参数
* @return 结果列表
*/
List<QueryResultVo> structure(QueryParamDto dto);
/**
* 人员年龄结构
*
* @param dto 查询参数
* @return 结果列表
*/
List<QueryResultVo> ageStructure(QueryParamDto dto);
/**
* 薪酬水平对标
*
* @param dto 查询参数
* @return 结果列表
*/
List<QueryResultVo> salaryLevel(QueryParamDto dto);
/**
* 就业质量指标
*
* @param dto 查询参数
* @return 结果列表
*/
IndustryEmploymentInfoSqlDto qualityIndicator(QueryParamDto dto);
/**
* 热力图
*
* @param dto 查询参数
* @return 热力图列表
*/
List<HeatmapVo> heatmap(QueryParamDto dto);
}

View File

@@ -2,17 +2,25 @@ package com.ruoyi.cms.service.impl;
import com.ruoyi.cms.domain.dto.ExcelRow;
import com.ruoyi.cms.domain.dto.QueryParamDto;
import com.ruoyi.cms.domain.vo.HeatmapVo;
import com.ruoyi.cms.domain.vo.IndustryEmploymentInfoOverviewVo;
import com.ruoyi.cms.domain.vo.QueryResultVo;
import com.ruoyi.cms.domain.vo.TreadVo;
import com.ruoyi.cms.service.AnalysisExportService;
import com.ruoyi.cms.service.AnalysisIndustryEmploymentInfoService;
import com.ruoyi.cms.util.document.ExcelUtil;
import com.ruoyi.cms.util.document.MultiSheetExcelUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +35,11 @@ import java.util.Objects;
@Service
@Validated
@Slf4j
@RequiredArgsConstructor
public class AnalysisExportServiceImpl implements AnalysisExportService {
private final AnalysisIndustryEmploymentInfoService analysisIndustryEmploymentInfoService;
@Override
public void exportData(HttpServletResponse response, QueryParamDto dto) {
if (Objects.isNull(dto.getExportModule())) {
@@ -37,7 +49,7 @@ public class AnalysisExportServiceImpl implements AnalysisExportService {
switch (dto.getExportModule()) {
// 就业大数据专题分析平台-行业就业情况信息分析
case EMPLOYMENT_INDUSTRY_EMPLOYMENT_INFO:
test(response, dto);
exportIndustryEmploymentInfo(response, dto);
break;
// 就业大数据专题分析平台-高校毕业生就业信息分析
case EMPLOYMENT_GRADUATE_EMPLOYMENT_INFO:
@@ -65,7 +77,7 @@ public class AnalysisExportServiceImpl implements AnalysisExportService {
break;
// 智慧就业大数据分析展示系统-行业就业情况信息分析
case WISDOM_EMPLOYMENT_INDUSTRY_EMPLOYMENT_INFO:
test(response, dto);
exportWisdomIndustryEmploymentInfo(response, dto);
break;
// 智慧就业大数据分析展示系统-高校毕业生就业信息分析
case WISDOM_EMPLOYMENT_GRADUATE_EMPLOYMENT_INFO:
@@ -131,4 +143,409 @@ public class AnalysisExportServiceImpl implements AnalysisExportService {
return multiSheetExcelUtil;
}
/**
* 导出 行业就业情况信息分析
*
* @param response 响应
* @param dto 查询参数
* @throws IOException 异常
*/
private void exportIndustryEmploymentInfo(HttpServletResponse response, QueryParamDto dto) throws IOException {
MultiSheetExcelUtil multiSheetExcelUtil = new MultiSheetExcelUtil();
String exportTime = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);
// 数据总览
List<ExcelRow> basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("导出时间", exportTime));
basicExportList.add(new ExcelRow("数据总览"));
basicExportList.add(new ExcelRow("指标名称(单位)", "指标值", "较上期变化(%"));
QueryParamDto newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
IndustryEmploymentInfoOverviewVo overview = analysisIndustryEmploymentInfoService.overview(newParam);
basicExportList.add(new ExcelRow(
"总就业人数(人)", transform(overview.getEmploymentCount()), transform(overview.getEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"失业率《%", transform(overview.getUnemploymentRate()), transform(overview.getUnemploymentRateMom())
));
basicExportList.add(new ExcelRow(
"创业企业总数(家)", transform(overview.getStartupCompanyCount()),
transform(overview.getStartupCompanyCountMom())
));
basicExportList.add(new ExcelRow(
"创业带动就业(人)", transform(overview.getStartupEmploymentCount()),
transform(overview.getStartupEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"灵活就业人数(人)", transform(overview.getFlexibleEmploymentCount()),
transform(overview.getFlexibleEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"招聘需求(岗)", transform(overview.getRecruitmentDemand()), transform(overview.getRecruitmentDemandMom())
));
basicExportList.add(new ExcelRow(
"平均薪资(元)", transform(overview.getAverageSalary()), transform(overview.getAverageSalaryMom())
));
// 创建Excel工具类并添加工作表
ExcelUtil<ExcelRow> basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("数据总览");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业就业规模与增长趋势
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业就业规模与增长趋势"));
basicExportList.add(new ExcelRow("时间", "上一时段人数(人)", "本时段人数(人)",
"同比增速(%", "环比增速(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
List<TreadVo> treadList = analysisIndustryEmploymentInfoService.scaleAndTrend(newParam);
for (TreadVo tread : treadList) {
basicExportList.add(new ExcelRow(
tread.getDesc(), transform(tread.getLastYearCount()), transform(tread.getCurrentCount()),
transform(tread.getYearOnYearGrowthRate()), transform(tread.getMonthOnMonthGrowthRate())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业就业规模与增长趋势");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业就业规模对比
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业就业规模对比"));
basicExportList.add(new ExcelRow("行业", "就业人数(人)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
List<QueryResultVo> resultList = analysisIndustryEmploymentInfoService.scaleComparison(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业就业规模对比");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 就业结构分析
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("就业结构分析"));
basicExportList.add(new ExcelRow("结构类型", "人数(人)", "占比(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.structure(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount()), transform(result.getCountPercentage())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("就业结构分析");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 人员年龄结构
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("人员年龄结构"));
basicExportList.add(new ExcelRow("年龄段", "人数(人)", "占比(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.ageStructure(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount()), transform(result.getCountPercentage())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("人员年龄结构");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 薪酬水平对标
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("薪酬水平对标"));
basicExportList.add(new ExcelRow("行业", "平均薪资(元)", "中位数薪资(元)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.salaryLevel(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getAmount()), transform(result.getAnotherAmount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("薪酬水平对标");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业技能需求TOP10
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业技能需求TOP10"));
basicExportList.add(new ExcelRow("技能", "需求人数(人)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.industrySkill(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业技能需求TOP10");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 就业质量指标
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("就业质量指标"));
basicExportList.add(new ExcelRow("指标", "得分(分)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.qualityIndicator(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getAmount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("就业质量指标");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
multiSheetExcelUtil.setFileName(dto.getExportModule().getDesc());
multiSheetExcelUtil.exportExcel(response);
}
/**
* 导出 行业就业情况信息分析
*
* @param response 响应
* @param dto 查询参数
* @throws IOException 异常
*/
private void exportWisdomIndustryEmploymentInfo(HttpServletResponse response, QueryParamDto dto) throws IOException {
MultiSheetExcelUtil multiSheetExcelUtil = new MultiSheetExcelUtil();
String exportTime = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);
// 数据总览
List<ExcelRow> basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("导出时间", exportTime));
basicExportList.add(new ExcelRow("数据总览"));
basicExportList.add(new ExcelRow("指标名称(单位)", "指标值", "较上期变化(%"));
QueryParamDto newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
IndustryEmploymentInfoOverviewVo overview = analysisIndustryEmploymentInfoService.overview(newParam);
basicExportList.add(new ExcelRow(
"总就业人数(人)", transform(overview.getEmploymentCount()), transform(overview.getEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"失业率《%", transform(overview.getUnemploymentRate()), transform(overview.getUnemploymentRateMom())
));
basicExportList.add(new ExcelRow(
"创业企业总数(家)", transform(overview.getStartupCompanyCount()),
transform(overview.getStartupCompanyCountMom())
));
basicExportList.add(new ExcelRow(
"创业带动就业(人)", transform(overview.getStartupEmploymentCount()),
transform(overview.getStartupEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"灵活就业人数(人)", transform(overview.getFlexibleEmploymentCount()),
transform(overview.getFlexibleEmploymentCountMom())
));
basicExportList.add(new ExcelRow(
"招聘需求(岗)", transform(overview.getRecruitmentDemand()), transform(overview.getRecruitmentDemandMom())
));
basicExportList.add(new ExcelRow(
"平均薪资(元)", transform(overview.getAverageSalary()), transform(overview.getAverageSalaryMom())
));
// 创建Excel工具类并添加工作表
ExcelUtil<ExcelRow> basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("数据总览");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 区域就业热力图
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("区域就业热力图"));
basicExportList.add(new ExcelRow("地区", "就业人数(人)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
List<HeatmapVo> heatmapList = analysisIndustryEmploymentInfoService.heatmap(newParam);
for (HeatmapVo heatmap : heatmapList) {
basicExportList.add(new ExcelRow(
heatmap.getAreaName(), transform(heatmap.getCount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("区域就业热力图");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业就业规模与增长趋势
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业就业规模与增长趋势"));
basicExportList.add(new ExcelRow("时间", "上一时段人数(人)", "本时段人数(人)",
"同比增速(%", "环比增速(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
List<TreadVo> treadList = analysisIndustryEmploymentInfoService.scaleAndTrend(newParam);
for (TreadVo tread : treadList) {
basicExportList.add(new ExcelRow(
tread.getDesc(), transform(tread.getLastYearCount()), transform(tread.getCurrentCount()),
transform(tread.getYearOnYearGrowthRate()), transform(tread.getMonthOnMonthGrowthRate())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业就业规模与增长趋势");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业就业规模对比
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业就业规模对比"));
basicExportList.add(new ExcelRow("行业", "就业人数(人)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
List<QueryResultVo> resultList = analysisIndustryEmploymentInfoService.scaleComparison(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业就业规模对比");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 就业结构分析
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("就业结构分析"));
basicExportList.add(new ExcelRow("结构类型", "人数(人)", "占比(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.structure(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount()), transform(result.getCountPercentage())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("就业结构分析");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 人员年龄结构
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("人员年龄结构"));
basicExportList.add(new ExcelRow("年龄段", "人数(人)", "占比(%"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.ageStructure(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount()), transform(result.getCountPercentage())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("人员年龄结构");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 薪酬水平对标
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("薪酬水平对标"));
basicExportList.add(new ExcelRow("行业", "平均薪资(元)", "中位数薪资(元)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.salaryLevel(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getAmount()), transform(result.getAnotherAmount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("薪酬水平对标");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 行业技能需求TOP10
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("行业技能需求TOP10"));
basicExportList.add(new ExcelRow("技能", "需求人数(人)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.industrySkill(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getCount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("行业技能需求TOP10");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
// 就业质量指标
basicExportList = new ArrayList<>();
basicExportList.add(new ExcelRow("就业质量指标"));
basicExportList.add(new ExcelRow("指标", "得分(分)"));
newParam = new QueryParamDto();
BeanUtils.copyProperties(dto, newParam);
resultList = analysisIndustryEmploymentInfoService.qualityIndicator(newParam);
for (QueryResultVo result : resultList) {
basicExportList.add(new ExcelRow(
result.getDesc(), transform(result.getAmount())
));
}
// 创建Excel工具类并添加工作表
basicSituationExcelUtil = new ExcelUtil<>(ExcelRow.class);
basicSituationExcelUtil.setDataList(basicExportList);
basicSituationExcelUtil.setSheetName("就业质量指标");
multiSheetExcelUtil.addSheet(basicSituationExcelUtil);
multiSheetExcelUtil.setFileName(dto.getExportModule().getDesc());
multiSheetExcelUtil.exportExcel(response);
}
private String transform(Long value) {
if (Objects.isNull(value)) {
return "";
}
return value.toString();
}
private String transform(BigDecimal value) {
if (Objects.isNull(value)) {
return "";
}
return value.toPlainString();
}
}

View File

@@ -1,24 +1,25 @@
package com.ruoyi.cms.service.impl;
import com.ruoyi.cms.constant.CommonConstant;
import com.ruoyi.cms.domain.dto.IndustryEmploymentInfoSqlDto;
import com.ruoyi.cms.domain.dto.QueryParamDto;
import com.ruoyi.cms.domain.vo.HeatmapVo;
import com.ruoyi.cms.domain.vo.IndustryEmploymentInfoOverviewVo;
import com.ruoyi.cms.domain.vo.QueryResultVo;
import com.ruoyi.cms.domain.vo.TreadVo;
import com.ruoyi.cms.mapper.ThemeEmploymentRegisterMapper;
import com.ruoyi.cms.service.AnalysisIndustryEmploymentInfoService;
import com.ruoyi.cms.util.MathUtil;
import com.ruoyi.cms.util.ParamUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@@ -30,41 +31,107 @@ import java.util.List;
@Service
@Validated
@Slf4j
@RequiredArgsConstructor
public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndustryEmploymentInfoService {
private final ThemeEmploymentRegisterMapper themeEmploymentRegisterMapper;
@Override
public IndustryEmploymentInfoOverviewVo overview(QueryParamDto dto) {
// 计算当前时间段数据
ParamUtil.dealParam(dto);
Long employmentCount = themeEmploymentRegisterMapper.queryEmploymentCount(dto);
// todo 失业人数
Long unemploymentCount = 13L;
BigDecimal unemploymentRate = MathUtil.calculatePercentage(
(unemploymentCount + employmentCount), unemploymentCount);
Long startupCompanyCount = themeEmploymentRegisterMapper.queryStartupCompanyCount(dto);
Long startupEmploymentCount = themeEmploymentRegisterMapper.queryStartupEmploymentCount(dto);
Long flexibleEmploymentCount = themeEmploymentRegisterMapper.queryFlexibleEmploymentCount(dto);
// todo 岗位表 招聘需求
Long recruitmentDemand = 1234L;
BigDecimal averageSalary = themeEmploymentRegisterMapper.queryAverageSalary(dto);
// 计算上一时间段数据
QueryParamDto lastDto = new QueryParamDto();
BeanUtils.copyProperties(dto, lastDto);
ParamUtil.calculateLastTime(lastDto);
Long lastEmploymentCount = themeEmploymentRegisterMapper.queryEmploymentCount(lastDto);
// todo 失业人数
Long lastUnemploymentCount = 17L;
BigDecimal lastUnemploymentRate = MathUtil.calculatePercentage(
(lastUnemploymentCount + employmentCount), lastUnemploymentCount);
Long lastStartupCompanyCount = themeEmploymentRegisterMapper.queryStartupCompanyCount(lastDto);
Long lastStartupEmploymentCount = themeEmploymentRegisterMapper.queryStartupEmploymentCount(lastDto);
Long lastFlexibleEmploymentCount = themeEmploymentRegisterMapper.queryFlexibleEmploymentCount(lastDto);
// todo 岗位表 招聘需求
Long lastRecruitmentDemand = 634L;
BigDecimal lastAverageSalary = themeEmploymentRegisterMapper.queryAverageSalary(lastDto);
return IndustryEmploymentInfoOverviewVo.builder()
.employmentCount(100L)
.employmentCountMom(BigDecimal.valueOf(10))
.unemploymentRate(BigDecimal.valueOf(3.4))
.unemploymentRateMom(BigDecimal.valueOf(1.2))
.startupCompanyCount(323L)
.startupCompanyCountMom(BigDecimal.valueOf(23))
.startupEmploymentCount(432L)
.startupEmploymentCountMom(BigDecimal.valueOf(-12))
.flexibleEmploymentCount(53L)
.flexibleEmploymentCountMom(BigDecimal.valueOf(2.3))
.recruitmentDemand(2443L)
.recruitmentDemandMom(BigDecimal.valueOf(23.3))
.averageSalary(BigDecimal.valueOf(3424.3))
.averageSalaryMom(BigDecimal.valueOf(-3.3))
.employmentCount(employmentCount)
.employmentCountMom(MathUtil.calculatePercentageGrowthRate(lastEmploymentCount, employmentCount))
.unemploymentRate(unemploymentRate)
.unemploymentRateMom(MathUtil.calculatePercentageGrowthRate(lastUnemploymentRate, unemploymentRate))
.startupCompanyCount(startupCompanyCount)
.startupCompanyCountMom(
MathUtil.calculatePercentageGrowthRate(lastStartupCompanyCount, startupCompanyCount))
.startupEmploymentCount(startupEmploymentCount)
.startupEmploymentCountMom(
MathUtil.calculatePercentageGrowthRate(lastStartupEmploymentCount, startupEmploymentCount))
.flexibleEmploymentCount(flexibleEmploymentCount)
.flexibleEmploymentCountMom(
MathUtil.calculatePercentageGrowthRate(lastFlexibleEmploymentCount, flexibleEmploymentCount))
.recruitmentDemand(recruitmentDemand)
.recruitmentDemandMom(
MathUtil.calculatePercentageGrowthRate(lastRecruitmentDemand, recruitmentDemand))
.averageSalary(averageSalary)
.averageSalaryMom(MathUtil.calculatePercentageGrowthRate(lastAverageSalary, averageSalary))
.build();
}
@Override
public List<TreadVo> scaleAndTrend(QueryParamDto dto) {
List<TreadVo> list = new ArrayList<>();
for (int i = 0; i < 12; i++) {
list.add(TreadVo.builder()
.code(i + 1 + "")
.sort(i)
.desc(i + 1 + "")
.currentCount((long) Math.floor(Math.random() * 10000) + 1)
.lastYearCount((long) Math.floor(Math.random() * 10000) + 1)
.build());
ParamUtil.dealParam(dto);
List<TreadVo> list;
switch (dto.getQueryTimeType()) {
case YEAR: {
dto.setStartTime(LocalDateTime.of(dto.getYear(), 1, 1, 0, 0, 0)
.minusYears(5L));
dto.setEndTime(LocalDateTime.of(dto.getYear(), 12, 31, 23, 59, 59));
list = themeEmploymentRegisterMapper.scaleAndTrendYear(dto);
break;
}
case QUARTER: {
dto.setStartTime(LocalDateTime.of(dto.getYear(), 1, 1, 0, 0, 0));
dto.setEndTime(LocalDateTime.of(dto.getYear(), 12, 31, 23, 59, 59));
list = themeEmploymentRegisterMapper.scaleAndTrendQuarter(dto);
break;
}
case MONTH: {
dto.setStartTime(LocalDateTime.of(dto.getYear(), 1, 1, 0, 0, 0));
dto.setEndTime(LocalDateTime.of(dto.getYear(), 12, 31, 23, 59, 59));
list = themeEmploymentRegisterMapper.scaleAndTrendMonth(dto);
break;
}
default:
throw new ServiceException("时间类型错误");
}
// 计算同环比
@@ -75,34 +142,19 @@ public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndust
@Override
public List<QueryResultVo> scaleComparison(QueryParamDto dto) {
List<QueryResultVo> list = new ArrayList<>();
for (Tuple2<String, String> industry : CommonConstant.INDUSTRY_LIST) {
list.add(QueryResultVo.builder()
.code(industry.getT1())
.desc(industry.getT2())
.count((long) Math.floor(Math.random() * 100000) + 1)
.build());
}
ParamUtil.dealParam(dto);
List<QueryResultVo> list = themeEmploymentRegisterMapper.scaleComparison(dto);
MathUtil.calculatePercentage(list);
ParamUtil.fillDictName(list, "industry");
return list;
}
@Override
public List<QueryResultVo> structure(QueryParamDto dto) {
List<QueryResultVo> list = new ArrayList<>();
List<Tuple2<String, String>> structureList =
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(
Tuples.of("1", "管理层"),
Tuples.of("2", "专业技术"),
Tuples.of("3", "技能工人"),
Tuples.of("4", "一般员工")
)));
for (Tuple2<String, String> structure : structureList) {
list.add(QueryResultVo.builder()
.code(structure.getT1())
.desc(structure.getT2())
.count((long) Math.floor(Math.random() * 100000) + 1)
.build());
}
ParamUtil.dealParam(dto);
List<QueryResultVo> list = themeEmploymentRegisterMapper.structure(dto);
// 计算占比
MathUtil.calculatePercentage(list);
return list;
@@ -110,22 +162,8 @@ public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndust
@Override
public List<QueryResultVo> ageStructure(QueryParamDto dto) {
List<QueryResultVo> list = new ArrayList<>();
List<Tuple2<String, String>> structureList =
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(
Tuples.of("1", "16-25岁"),
Tuples.of("2", "26-35岁"),
Tuples.of("3", "36-45岁"),
Tuples.of("4", "46-55岁"),
Tuples.of("5", "55岁以上")
)));
for (Tuple2<String, String> structure : structureList) {
list.add(QueryResultVo.builder()
.code(structure.getT1())
.desc(structure.getT2())
.count((long) Math.floor(Math.random() * 100000) + 1)
.build());
}
ParamUtil.dealParam(dto);
List<QueryResultVo> list = themeEmploymentRegisterMapper.ageStructure(dto);
// 计算占比
MathUtil.calculatePercentage(list);
return list;
@@ -133,15 +171,10 @@ public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndust
@Override
public List<QueryResultVo> salaryLevel(QueryParamDto dto) {
List<QueryResultVo> list = new ArrayList<>();
for (Tuple2<String, String> industry : CommonConstant.INDUSTRY_LIST) {
list.add(QueryResultVo.builder()
.code(industry.getT1())
.desc(industry.getT2())
.amount(new BigDecimal(Math.random() * 100000 + 1).setScale(2, RoundingMode.HALF_UP))
.anotherAmount(new BigDecimal(Math.random() * 100000 + 1).setScale(2, RoundingMode.HALF_UP))
.build());
}
ParamUtil.dealParam(dto);
List<QueryResultVo> list = themeEmploymentRegisterMapper.salaryLevel(dto);
MathUtil.calculatePercentage(list);
ParamUtil.fillDictName(list, "industry");
return list;
}
@@ -152,34 +185,39 @@ public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndust
@Override
public List<QueryResultVo> qualityIndicator(QueryParamDto dto) {
ParamUtil.dealParam(dto);
IndustryEmploymentInfoSqlDto sqlDto = themeEmploymentRegisterMapper.qualityIndicator(dto);
List<QueryResultVo> list = new ArrayList<>();
List<Tuple2<String, String>> structureList =
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(
Tuples.of("1", "合同完整性"),
Tuples.of("2", "社保覆盖度"),
Tuples.of("3", "薪资稳定性"),
Tuples.of("4", "工作满意度")
)));
for (Tuple2<String, String> structure : structureList) {
list.add(QueryResultVo.builder()
.code(structure.getT1())
.desc(structure.getT2())
.amount(new BigDecimal(Math.random() * 100 + 1).setScale(2, RoundingMode.HALF_UP))
.build());
}
list.add(QueryResultVo.builder()
.code("1")
.desc("合同完整性")
.amount(MathUtil.calculatePercentage(sqlDto.getTotalCount(), sqlDto.getSignContractCount()))
.build());
list.add(QueryResultVo.builder()
.code("2")
.desc("社保覆盖度")
.amount(MathUtil.calculatePercentage(sqlDto.getTotalCount(), sqlDto.getSocialInsuranceCount()))
.build());
list.add(QueryResultVo.builder()
.code("3")
.desc("薪资稳定性")
.amount(MathUtil.calculatePercentage(sqlDto.getTotalCount(), sqlDto.getStableSalaryCount()))
.build());
list.add(QueryResultVo.builder()
.code("4")
.desc("工作满意度")
.amount(MathUtil.calculatePercentage(sqlDto.getTotalCount(), sqlDto.getSatisfiedWorkCount()))
.build());
return list;
}
@Override
public List<HeatmapVo> heatmap(QueryParamDto dto) {
List<HeatmapVo> list = new ArrayList<>();
for (Tuple2<String, String> area : CommonConstant.AREA_LIST) {
list.add(HeatmapVo.builder()
.areaCode(area.getT1())
.areaName(area.getT2())
.count((long) Math.floor(Math.random() * 10000) + 1)
.build());
}
ParamUtil.dealParam(dto);
List<HeatmapVo> list = themeEmploymentRegisterMapper.heatmap(dto);
// 计算占比
MathUtil.calculatePercentageHeatmap(list);
return list;

View File

@@ -1,9 +1,12 @@
package com.ruoyi.cms.util;
import com.ruoyi.cms.constant.CommonConstant;
import com.ruoyi.cms.constant.enums.QueryTimeTypeEnum;
import com.ruoyi.cms.domain.vo.HeatmapVo;
import com.ruoyi.cms.domain.vo.QueryResultVo;
import com.ruoyi.cms.domain.vo.TreadVo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import java.math.BigDecimal;
@@ -92,10 +95,11 @@ public class MathUtil {
}
}
/**
* 计算占比
*
* @param list 热力图数据
* @param list 数据
*/
public static void calculatePercentage(List<QueryResultVo> list) {
if (CollectionUtils.isEmpty(list)) {
@@ -111,6 +115,33 @@ public class MathUtil {
}
}
/**
* 计算环比
*
* @param lastCount 上期数据
* @param currentCount 本期数据
* @return 环比
*/
public static BigDecimal calculatePercentageGrowthRate(Long lastCount, Long currentCount) {
lastCount = Optional.ofNullable(lastCount).orElse(0L);
currentCount = Optional.ofNullable(currentCount).orElse(0L);
return calculatePercentage(lastCount, (currentCount - lastCount));
}
/**
* 计算环比
*
* @param lastBigDecimal 上期数据
* @param currentBigDecimal 本期数据
* @return 环比
*/
public static BigDecimal calculatePercentageGrowthRate(BigDecimal lastBigDecimal, BigDecimal currentBigDecimal) {
lastBigDecimal = Optional.ofNullable(lastBigDecimal).orElse(BigDecimal.ZERO);
currentBigDecimal = Optional.ofNullable(currentBigDecimal).orElse(BigDecimal.ZERO);
return calculatePercentage(lastBigDecimal, (currentBigDecimal.subtract(lastBigDecimal)));
}
/**
* 计算同比和环比
*
@@ -189,6 +220,7 @@ public class MathUtil {
for (HeatmapVo vo : list) {
vo.setPercentage(calculatePercentage(totalCount, vo.getCount()));
vo.setAreaName(Optional.ofNullable(CommonConstant.AREA_MAP.get(vo.getAreaCode())).orElse("未知"));
}
}
}

View File

@@ -0,0 +1,155 @@
package com.ruoyi.cms.util;
import com.ruoyi.cms.constant.CommonConstant;
import com.ruoyi.cms.domain.dto.QueryParamDto;
import com.ruoyi.cms.domain.vo.QueryResultVo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* 参数工具类
*
* @author 马宝龙
* @date 2026/6/27
*/
public class ParamUtil {
private ParamUtil() {
}
/**
* 处理参数
*
* @param dto 参数
*/
public static void dealParam(QueryParamDto dto) {
if (Objects.isNull(dto)) {
throw new ServiceException("参数不能为空");
}
if (Objects.isNull(dto.getQueryTimeType())) {
throw new ServiceException("时间类型不能为空");
}
if (Objects.isNull(dto.getYear())) {
throw new ServiceException("年份不能为空");
}
LocalTime min = LocalTime.of(0, 0, 0);
LocalTime max = LocalTime.of(23, 59, 59);
switch (dto.getQueryTimeType()) {
case YEAR: {
dto.setStartTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 1, 1), min));
dto.setEndTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 12, 31), max));
break;
}
case QUARTER: {
if (Objects.isNull(dto.getQuarter())) {
throw new ServiceException("季度不能为空");
}
switch (dto.getQuarter()) {
case 1:
dto.setStartTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 1, 1), min));
dto.setEndTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 3, 31), max));
break;
case 2:
dto.setStartTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 4, 1), min));
dto.setEndTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 6, 30), max));
break;
case 3:
dto.setStartTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 7, 1), min));
dto.setEndTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 9, 30), max));
break;
case 4:
dto.setStartTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 10, 1), min));
dto.setEndTime(LocalDateTime.of(LocalDate.of(dto.getYear(), 12, 31), max));
break;
default:
throw new ServiceException("季度错误");
}
break;
}
case MONTH: {
if (Objects.isNull(dto.getMonth())) {
throw new ServiceException("月份不能为空");
}
LocalDateTime startTime = LocalDateTime.of(LocalDate.of(dto.getYear(), dto.getMonth(), 1), min);
dto.setStartTime(startTime);
dto.setEndTime(startTime.plusMonths(1L).minusSeconds(1L));
break;
}
default:
throw new ServiceException("时间类型错误");
}
}
/**
* 计算上一时间段时间
*
* @param dto 参数
*/
public static void calculateLastTime(QueryParamDto dto) {
if (Objects.isNull(dto)) {
throw new ServiceException("参数不能为空");
}
if (Objects.isNull(dto.getQueryTimeType())) {
throw new ServiceException("时间类型不能为空");
}
if (Objects.isNull(dto.getStartTime()) || Objects.isNull(dto.getEndTime())) {
throw new ServiceException("时间不能为空");
}
switch (dto.getQueryTimeType()) {
case YEAR: {
dto.setStartTime(dto.getStartTime().minusYears(1L));
dto.setEndTime(dto.getEndTime().minusYears(1L));
break;
}
case QUARTER: {
dto.setStartTime(dto.getStartTime().minusMonths(3L));
dto.setEndTime(dto.getEndTime().minusMonths(3L));
break;
}
case MONTH: {
dto.setStartTime(dto.getStartTime().minusMonths(1L));
dto.setEndTime(dto.getEndTime().minusMonths(1L));
break;
}
default:
throw new ServiceException("时间类型错误");
}
}
/**
* 填充字典名称
*
* @param list 列表
* @param dictName 字典名称
*/
public static void fillDictName(List<QueryResultVo> list, String dictName) {
if (CollectionUtils.isEmpty(list) || StringUtils.isBlank(dictName)) {
return;
}
switch (dictName) {
case "industry": {
for (QueryResultVo vo : list) {
vo.setDesc(Optional.ofNullable(CommonConstant.INDUSTRY_MAP.get(vo.getCode())).orElse("未知"));
}
break;
}
default:
throw new ServiceException("字典名称错误");
}
}
}