From 4baeb8262fec58becf0713c7fbee6a6c069b9183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AE=9D=E9=BE=99?= Date: Tue, 30 Jun 2026 18:57:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/cms/constant/CommonConstant.java | 41 ++ .../java/com/ruoyi/cms/domain/vo/TreadVo.java | 8 + .../cms/mapper/ThemeRecruitmentJobMapper.java | 98 ++++ ...aborForceRecruitmentDemandServiceImpl.java | 276 +++++----- .../java/com/ruoyi/cms/util/ParamUtil.java | 35 +- .../mapper/ThemeRecruitmentJobMapper.xml | 475 ++++++++++++++++++ 6 files changed, 810 insertions(+), 123 deletions(-) diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/constant/CommonConstant.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/constant/CommonConstant.java index 09599a0..11ab209 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/constant/CommonConstant.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/constant/CommonConstant.java @@ -302,4 +302,45 @@ public class CommonConstant { Tuple2::getT1, Tuple2::getT2 ))); + + /** + * 企业类型列表 + */ + public static final List> COMPANY_TYPE_LIST = + Collections.unmodifiableList(new ArrayList<>(Arrays.asList( + Tuples.of("1", "国有企业"), + Tuples.of("2", "民营企业"), + Tuples.of("3", "外资企业"), + Tuples.of("4", "合资企业"), + Tuples.of("5", "事业单位") + ))); + /** + * 企业类型Map + */ + public static final Map COMPANY_TYPE_MAP = + Collections.unmodifiableMap(COMPANY_TYPE_LIST.stream() + .collect(Collectors.toMap( + Tuple2::getT1, + Tuple2::getT2 + ))); + + /** + * 招聘方式列表 + */ + public static final List> RECRUITMENT_WAY_LIST = + Collections.unmodifiableList(new ArrayList<>(Arrays.asList( + Tuples.of("1", "线上招聘"), + Tuples.of("2", "线下招聘"), + Tuples.of("3", "校园招聘"), + Tuples.of("4", "内部推荐") + ))); + /** + * 企业类型Map + */ + public static final Map RECRUITMENT_WAY_MAP = + Collections.unmodifiableMap(RECRUITMENT_WAY_LIST.stream() + .collect(Collectors.toMap( + Tuple2::getT1, + Tuple2::getT2 + ))); } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java index cc6ca94..4dd7a2b 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java @@ -24,10 +24,18 @@ public class TreadVo implements Serializable { * 编码 */ private String code; + /** + * 另一个编码 + */ + private String anotherCode; /** * 描述 */ private String desc; + /** + * 另一个描述 + */ + private String anotherDesc; /** * 排序 */ diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/ThemeRecruitmentJobMapper.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/ThemeRecruitmentJobMapper.java index 2104de4..256b055 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/ThemeRecruitmentJobMapper.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/mapper/ThemeRecruitmentJobMapper.java @@ -4,6 +4,7 @@ import com.ruoyi.cms.domain.dto.QueryParamDto; import com.ruoyi.cms.domain.vo.HeatmapVo; import com.ruoyi.cms.domain.vo.MajorIndustryEmploymentMonitorTreadVo; import com.ruoyi.cms.domain.vo.QueryResultVo; +import com.ruoyi.cms.domain.vo.TreadVo; import java.math.BigDecimal; import java.util.List; @@ -123,4 +124,101 @@ public interface ThemeRecruitmentJobMapper { * @return 热力图列表 */ List heatmap(QueryParamDto dto); + + /** + * 招聘需求规模趋势 - 年度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List recruitmentTrendYear(QueryParamDto dto); + + /** + * 招聘需求规模趋势 - 季度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List recruitmentTrendQuarter(QueryParamDto dto); + + /** + * 招聘需求规模趋势 - 月度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List recruitmentTrendMonth(QueryParamDto dto); + + /** + * 重点产业招聘需求对比 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List majorIndustryRecruitment(QueryParamDto dto); + + + /** + * 重点监测行业劳动力动态走势 - 年度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List majorIndustryLaborForceTreadYear(QueryParamDto dto); + + /** + * 重点监测行业劳动力动态走势 - 季度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List majorIndustryLaborForceTreadQuarter(QueryParamDto dto); + + /** + * 重点监测行业劳动力动态走势 - 月度 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List majorIndustryLaborForceTreadMonth(QueryParamDto dto); + + /** + * 不同类型企业用工规模 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List companyRecruitmentCount(QueryParamDto dto); + + /** + * 不同企业类型招聘活跃度 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List companyRecruitmentWay(QueryParamDto dto); + + /** + * 不同类型企业的人才结构需求 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List companyRecruitmentEducationLevel(QueryParamDto dto); + + /** + * 招聘需求区域分布 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List recruitmentArea(QueryParamDto dto); + + /** + * 承诺薪酬分布分布 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List commitmentSalary(QueryParamDto dto); } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisLaborForceRecruitmentDemandServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisLaborForceRecruitmentDemandServiceImpl.java index af83233..3af6641 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisLaborForceRecruitmentDemandServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisLaborForceRecruitmentDemandServiceImpl.java @@ -12,21 +12,24 @@ import com.ruoyi.cms.mapper.ThemeRecruitmentJobMapper; import com.ruoyi.cms.service.AnalysisLaborForceRecruitmentDemandService; import com.ruoyi.cms.util.MathUtil; import com.ruoyi.cms.util.ParamUtil; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; 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.time.LocalDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -import java.util.stream.IntStream; /** * 劳动力招聘需求分析 @@ -140,178 +143,207 @@ public class AnalysisLaborForceRecruitmentDemandServiceImpl implements AnalysisL @Override public List recruitmentTrend(QueryParamDto dto) { - List list = new ArrayList<>(); - for (int i = 1; i <= 12; i++) { - long currentCount = (long) Math.floor(Math.random() * 15000) + 5000; - long lastYearCount = (long) Math.floor(Math.random() * 14000) + 4000; - list.add(TreadVo.builder() - .code(String.valueOf(i)) - .desc(i + "月") - .sort(i) - .currentCount(currentCount) - .lastYearCount(lastYearCount) - .build()); + + ParamUtil.dealParam(dto); + + List 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 = themeRecruitmentJobMapper.recruitmentTrendYear(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 = themeRecruitmentJobMapper.recruitmentTrendQuarter(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 = themeRecruitmentJobMapper.recruitmentTrendMonth(dto); + break; + } + default: + throw new ServiceException("时间类型错误"); } + + // 计算同环比 MathUtil.calculatePercentageGrowthRate(dto.getQueryTimeType(), list); + return list; } @Override public List majorIndustryRecruitment(QueryParamDto dto) { - List list = new ArrayList<>(); - List> industryList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "制造业"), - Tuples.of("2", "信息技术"), - Tuples.of("3", "建筑业"), - Tuples.of("4", "批发零售业"), - Tuples.of("5", "住宿餐饮业"), - Tuples.of("6", "交通运输业") - ))); - for (Tuple2 industry : industryList) { - list.add(QueryResultVo.builder() - .code(industry.getT1()) - .desc(industry.getT2()) - .count((long) Math.floor(Math.random() * 5000) + 500) - .build()); - } + + dealParam(dto); + List list = themeRecruitmentJobMapper.majorIndustryRecruitment(dto); MathUtil.calculatePercentage(list); + ParamUtil.fillDictName(list, "majorIndustry"); + return list; } @Override public EchartsVo majorIndustryLaborForceTread(QueryParamDto dto) { - List xAxis = IntStream.rangeClosed(1, 12) - .mapToObj(i -> i + "月") - .collect(Collectors.toList()); - List> industryList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "制造业"), - Tuples.of("2", "信息技术"), - Tuples.of("3", "建筑业") - ))); - List series = new ArrayList<>(); - for (Tuple2 industry : industryList) { - List dataList = new ArrayList<>(); - for (int i = 0; i < 12; i++) { - dataList.add((long) Math.floor(Math.random() * 4000) + 1000); + ParamUtil.dealParam(dto); + + EchartsVo vo; + List 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 = themeRecruitmentJobMapper.majorIndustryLaborForceTreadYear(dto); + vo = transform(list); + ParamUtil.fillDictName(vo, "majorIndustry"); + break; } - series.add(EchartsSeriesVo.builder().name(industry.getT2()).data(dataList).build()); + 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 = themeRecruitmentJobMapper.majorIndustryLaborForceTreadQuarter(dto); + vo = transform(list); + ParamUtil.fillDictName(vo, "majorIndustry"); + 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 = themeRecruitmentJobMapper.majorIndustryLaborForceTreadMonth(dto); + vo = transform(list); + ParamUtil.fillDictName(vo, "majorIndustry"); + break; + } + default: + throw new ServiceException("时间类型错误"); + } + return vo; + } + + private EchartsVo transform(List list) { + + EchartsVo vo = EchartsVo.builder() + .xAxis(new ArrayList<>()) + .series(new ArrayList<>()) + .build(); + if (CollectionUtils.isEmpty(list)) { + return vo; } - return EchartsVo.builder().xAxis(xAxis).series(series).build(); + Map> anotherCodeMap = new HashMap<>(); + for (TreadVo tread : list) { + if (StringUtils.isBlank(tread.getAnotherCode())) { + continue; + } + if (!anotherCodeMap.containsKey(tread.getAnotherCode())) { + anotherCodeMap.put(tread.getAnotherCode(), new ArrayList<>()); + } + anotherCodeMap.get(tread.getAnotherCode()).add(tread); + } + + List xAxis = anotherCodeMap.values().stream() + .findFirst() + .map(firstGroup -> firstGroup.stream() + .map(TreadVo::getDesc) + .collect(Collectors.toList())) + .orElse(new ArrayList<>()); + + List series = new ArrayList<>(); + for (Map.Entry> entry : anotherCodeMap.entrySet()) { + List dataList = new ArrayList<>(); + for (TreadVo tread : entry.getValue()) { + dataList.add(tread.getCurrentCount()); + } + series.add(EchartsSeriesVo.builder() + .name(entry.getKey()) + .data(dataList) + .build()); + } + + vo.setXAxis(xAxis); + vo.setSeries(series); + return vo; } @Override public List companyRecruitmentCount(QueryParamDto dto) { - List list = new ArrayList<>(); - List> companyTypeList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "国有企业"), - Tuples.of("2", "民营企业"), - Tuples.of("3", "外资企业"), - Tuples.of("4", "合资企业"), - Tuples.of("5", "事业单位") - ))); - for (Tuple2 type : companyTypeList) { - list.add(QueryResultVo.builder() - .code(type.getT1()) - .desc(type.getT2()) - .count((long) Math.floor(Math.random() * 3000) + 200) - .build()); - } + + ParamUtil.dealParam(dto); + List list = themeRecruitmentJobMapper.companyRecruitmentCount(dto); MathUtil.calculatePercentage(list); + ParamUtil.fillDictName(list, "companyType"); + return list; } @Override public EchartsVo companyRecruitmentWay(QueryParamDto dto) { - List xAxis = IntStream.rangeClosed(1, 12) - .mapToObj(i -> i + "月") - .collect(Collectors.toList()); - List> wayList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "线上招聘"), - Tuples.of("2", "线下招聘"), - Tuples.of("3", "校园招聘"), - Tuples.of("4", "内部推荐") - ))); + ParamUtil.dealParam(dto); + List list = themeRecruitmentJobMapper.companyRecruitmentWay(dto); + EchartsVo vo = transform(list); + ParamUtil.fillDictName(vo, "recruitmentWay"); - List series = new ArrayList<>(); - for (Tuple2 way : wayList) { - List dataList = new ArrayList<>(); - for (int i = 0; i < 12; i++) { - dataList.add((long) Math.floor(Math.random() * 300) + 50); + // 填充重点行业 + List xAxis = vo.getXAxis(); + if (CollectionUtils.isNotEmpty(xAxis)) { + List xAxisDesc = new ArrayList<>(); + for (String x : xAxis) { + xAxisDesc.add(ParamUtil.fillDictName(x, "majorIndustry")); } - series.add(EchartsSeriesVo.builder().name(way.getT2()).data(dataList).build()); + vo.setXAxis(xAxisDesc); } - return EchartsVo.builder().xAxis(xAxis).series(series).build(); + return vo; } @Override public EchartsVo companyRecruitmentEducationLevel(QueryParamDto dto) { - List xAxis = IntStream.rangeClosed(1, 12) - .mapToObj(i -> i + "月") - .collect(Collectors.toList()); - List> levelList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "高中及以下"), - Tuples.of("2", "大专"), - Tuples.of("3", "本科"), - Tuples.of("4", "硕士及以上") - ))); + ParamUtil.dealParam(dto); + List list = themeRecruitmentJobMapper.companyRecruitmentEducationLevel(dto); + EchartsVo vo = transform(list); + ParamUtil.fillDictName(vo, "educationLevel"); - List series = new ArrayList<>(); - for (Tuple2 level : levelList) { - List dataList = new ArrayList<>(); - for (int i = 0; i < 12; i++) { - dataList.add((long) Math.floor(Math.random() * 500) + 100); + // 填充重点行业 + List xAxis = vo.getXAxis(); + if (CollectionUtils.isNotEmpty(xAxis)) { + List xAxisDesc = new ArrayList<>(); + for (String x : xAxis) { + xAxisDesc.add(ParamUtil.fillDictName(x, "majorIndustry")); } - series.add(EchartsSeriesVo.builder().name(level.getT2()).data(dataList).build()); + vo.setXAxis(xAxisDesc); } - return EchartsVo.builder().xAxis(xAxis).series(series).build(); + return vo; } @Override public List recruitmentArea(QueryParamDto dto) { - List list = new ArrayList<>(); - for (Tuple2 area : CommonConstant.AREA_LIST) { - list.add(QueryResultVo.builder() - .code(area.getT1()) - .desc(area.getT2()) - .count((long) Math.floor(Math.random() * 2000) + 100) - .build()); - } + + ParamUtil.dealParam(dto); + List list = themeRecruitmentJobMapper.recruitmentArea(dto); MathUtil.calculatePercentage(list); + ParamUtil.fillDictName(list, "area"); + return list; } @Override public List commitmentSalary(QueryParamDto dto) { - List list = new ArrayList<>(); - List> salaryList = - Collections.unmodifiableList(new ArrayList<>(Arrays.asList( - Tuples.of("1", "2000元以下"), - Tuples.of("2", "2000-4000元"), - Tuples.of("3", "4000-6000元"), - Tuples.of("4", "6000-8000元"), - Tuples.of("5", "8000-10000元"), - Tuples.of("6", "10000元以上") - ))); - for (Tuple2 salary : salaryList) { - list.add(QueryResultVo.builder() - .code(salary.getT1()) - .desc(salary.getT2()) - .count((long) Math.floor(Math.random() * 3000) + 200) - .build()); - } + + ParamUtil.dealParam(dto); + List list = themeRecruitmentJobMapper.commitmentSalary(dto); MathUtil.calculatePercentage(list); + return list; } } \ No newline at end of file diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/ParamUtil.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/ParamUtil.java index ea6c345..9320d19 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/ParamUtil.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/ParamUtil.java @@ -2,8 +2,11 @@ package com.ruoyi.cms.util; import com.ruoyi.cms.constant.CommonConstant; import com.ruoyi.cms.domain.dto.QueryParamDto; +import com.ruoyi.cms.domain.vo.EchartsSeriesVo; +import com.ruoyi.cms.domain.vo.EchartsVo; import com.ruoyi.cms.domain.vo.GraduateEmploymentInfoTreadVo; 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; @@ -146,6 +149,21 @@ public class ParamUtil { } } + /** + * 填充字典名称 + * + * @param echarts 数据 + * @param dictName 字典名称 + */ + public static void fillDictName(EchartsVo echarts, String dictName) { + if (Objects.isNull(echarts) || CollectionUtils.isEmpty(echarts.getSeries()) || StringUtils.isBlank(dictName)) { + return; + } + + for (EchartsSeriesVo vo : echarts.getSeries()) { + vo.setName(fillDictName(vo.getName(), dictName)); + } + } /** * 填充字典名称 @@ -164,7 +182,13 @@ public class ParamUtil { } } - private static String fillDictName(String code, String dictName){ + /** + * 填充字典名称 + * @param code 码值 + * @param dictName 字典名称 + * @return 字典值 + */ + public static String fillDictName(String code, String dictName) { switch (dictName) { case "industry": { return Optional.ofNullable(CommonConstant.INDUSTRY_MAP.get(code)).orElse("未知"); @@ -190,6 +214,15 @@ public class ParamUtil { case "jobType": { return Optional.ofNullable(CommonConstant.JOB_TYPE_MAP.get(code)).orElse("未知"); } + case "companyType": { + return Optional.ofNullable(CommonConstant.COMPANY_TYPE_MAP.get(code)).orElse("未知"); + } + case "recruitmentWay": { + return Optional.ofNullable(CommonConstant.RECRUITMENT_WAY_MAP.get(code)).orElse("未知"); + } + case "area": { + return Optional.ofNullable(CommonConstant.AREA_MAP.get(code)).orElse("未知"); + } default: throw new ServiceException("字典名称错误"); } diff --git a/ruoyi-bussiness/src/main/resources/mapper/ThemeRecruitmentJobMapper.xml b/ruoyi-bussiness/src/main/resources/mapper/ThemeRecruitmentJobMapper.xml index 1d568a9..2f2b0e2 100644 --- a/ruoyi-bussiness/src/main/resources/mapper/ThemeRecruitmentJobMapper.xml +++ b/ruoyi-bussiness/src/main/resources/mapper/ThemeRecruitmentJobMapper.xml @@ -332,4 +332,479 @@ GROUP BY areaCode ORDER BY areaCode + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file