From 8092f83d71228a8fefef5cd7fcd8f52a0e9c5aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AE=9D=E9=BE=99?= Date: Thu, 25 Jun 2026 18:42:59 +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 | 30 +++ ...lysisIndustryEmploymentInfoController.java | 60 ++++++ .../ruoyi/cms/domain/vo/QueryResultVo.java | 63 +++++++ .../java/com/ruoyi/cms/domain/vo/TreadVo.java | 64 +++++++ ...AnalysisIndustryEmploymentInfoService.java | 47 ++++- .../impl/AnalysisCommonServiceImpl.java | 24 +-- ...ysisIndustryEmploymentInfoServiceImpl.java | 103 +++++++++++ .../java/com/ruoyi/cms/util/MathUtil.java | 171 ++++++++++++++++++ 8 files changed, 539 insertions(+), 23 deletions(-) create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/QueryResultVo.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java create mode 100644 ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/MathUtil.java 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 1f2fc5c..40ce655 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 @@ -1,12 +1,15 @@ package com.ruoyi.cms.constant; +import com.ruoyi.cms.domain.vo.DictVo; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class CommonConstant { /** @@ -45,4 +48,31 @@ public class CommonConstant { Tuples.of("659001500000", "152团") ))); + /** + * 行业列表 + */ + public static final List> INDUSTRY_LIST = + Collections.unmodifiableList(new ArrayList<>(Arrays.asList( + Tuples.of("A", "农、林、牧、渔业"), + Tuples.of("B", "采矿业"), + Tuples.of("C", "制造业"), + Tuples.of("D", "电力、热力、燃气及水生产和供应业"), + Tuples.of("E", "建筑业"), + Tuples.of("F", "批发和零售业"), + Tuples.of("G", "交通运输、仓储和邮政业"), + Tuples.of("H", "住宿和餐饮业"), + Tuples.of("I", "信息传输、软件和信息技术服务业"), + Tuples.of("J", "金融业"), + Tuples.of("K", "房地产业"), + Tuples.of("L", "租赁和商务服务业"), + Tuples.of("M", "科学研究和技术服务业"), + Tuples.of("N", "水利、环境和公共设施管理业"), + Tuples.of("O", "居民服务、修理和其他服务业"), + Tuples.of("P", "教育"), + Tuples.of("Q", "卫生和社会工作"), + Tuples.of("R", "文化、体育和娱乐业"), + Tuples.of("S", "公共管理、社会保障和社会组织"), + Tuples.of("T", "国际组织") + ))); + } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisIndustryEmploymentInfoController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisIndustryEmploymentInfoController.java index 5db0ab7..4cbff35 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisIndustryEmploymentInfoController.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisIndustryEmploymentInfoController.java @@ -33,4 +33,64 @@ public class AnalysisIndustryEmploymentInfoController { public AjaxResult overview(@RequestBody QueryParamDto dto) { return AjaxResult.success(analysisIndustryEmploymentInfoService.overview(dto)); } + + /** + * 行业就业规模与增长趋势 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + @PostMapping("/scaleAndTrend") +// @Log(title = "根据枚举名称查询枚举的所有值", businessType = BusinessType.QUERY) + public AjaxResult scaleAndTrend(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisIndustryEmploymentInfoService.scaleAndTrend(dto)); + } + + /** + * 行业就业规模对比 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/scaleComparison") +// @Log(title = "根据枚举名称查询枚举的所有值", businessType = BusinessType.QUERY) + public AjaxResult scaleComparison(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisIndustryEmploymentInfoService.scaleComparison(dto)); + } + + /** + * 就业结构分析 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/structure") +// @Log(title = "根据枚举名称查询枚举的所有值", businessType = BusinessType.QUERY) + public AjaxResult structure(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisIndustryEmploymentInfoService.structure(dto)); + } + + /** + * 人员年龄结构 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/ageStructure") +// @Log(title = "根据枚举名称查询枚举的所有值", businessType = BusinessType.QUERY) + public AjaxResult ageStructure(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisIndustryEmploymentInfoService.ageStructure(dto)); + } + + /** + * 薪酬水平对标 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/salaryLevel") +// @Log(title = "根据枚举名称查询枚举的所有值", businessType = BusinessType.QUERY) + public AjaxResult salaryLevel(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisIndustryEmploymentInfoService.salaryLevel(dto)); + } } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/QueryResultVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/QueryResultVo.java new file mode 100644 index 0000000..bba767e --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/QueryResultVo.java @@ -0,0 +1,63 @@ +package com.ruoyi.cms.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 查询结果 + * + * @author 马宝龙 + * @date 2026/6/25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class QueryResultVo implements Serializable { + private static final long serialVersionUID = -2300192807003282827L; + /** + * 编码 + */ + private String code; + /** + * 描述 + */ + private String desc; + /** + * 数量 + */ + private Long count; + /** + * 数量占比 + */ + private BigDecimal countPercentage; + /** + * 其他数量 + */ + private Long anotherCount; + /** + * 其他数量占比 + */ + private BigDecimal anotherCountPercentage; + /** + * 金额 + */ + private BigDecimal amount; + /** + * 金额占比 + */ + private BigDecimal amountPercentage; + /** + * 其他金额 + */ + private BigDecimal anotherAmount; + /** + * 其他金额占比 + */ + private BigDecimal anotherAmountPercentage; +} 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 new file mode 100644 index 0000000..cc6ca94 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/TreadVo.java @@ -0,0 +1,64 @@ +package com.ruoyi.cms.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 趋势 + * + * @author 马宝龙 + * @date 2025/11/27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TreadVo implements Serializable { + private static final long serialVersionUID = -3329895390761203373L; + /** + * 编码 + */ + private String code; + /** + * 描述 + */ + private String desc; + /** + * 排序 + */ + private Integer sort; + /** + * 当前人数 + */ + private Long currentCount; + /** + * 上期人数 - 计算同比 + */ + private Long lastYearCount; + /** + * 上期人数 - 计算环比 + */ + private Long lastMonthCount; + /** + * 同比增长差值 + */ + private Long yearOnYearGrowthDiff; + /** + * 同比增长率(百分比,保留两位小数) + */ + private BigDecimal yearOnYearGrowthRate; + /** + * 环比增长差值 + */ + private Long monthOnMonthGrowthDiff; + /** + * 环比增长率(百分比,保留两位小数) + */ + private BigDecimal monthOnMonthGrowthRate; + +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisIndustryEmploymentInfoService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisIndustryEmploymentInfoService.java index e262ae5..d692d3f 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisIndustryEmploymentInfoService.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisIndustryEmploymentInfoService.java @@ -2,8 +2,10 @@ package com.ruoyi.cms.service; import com.ruoyi.cms.domain.dto.QueryParamDto; import com.ruoyi.cms.domain.vo.IndustryEmploymentInfoOverviewVo; -import com.ruoyi.common.core.domain.AjaxResult; -import org.springframework.web.bind.annotation.GetMapping; +import com.ruoyi.cms.domain.vo.QueryResultVo; +import com.ruoyi.cms.domain.vo.TreadVo; + +import java.util.List; /** * 行业就业情况信息分析 @@ -21,4 +23,45 @@ public interface AnalysisIndustryEmploymentInfoService { * @return 数据总览 */ IndustryEmploymentInfoOverviewVo overview(QueryParamDto dto); + + + /** + * 行业就业规模与增长趋势 + * + * @param dto 查询参数 + * @return 趋势列表 + */ + List scaleAndTrend(QueryParamDto dto); + + /** + * 行业就业规模对比 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List scaleComparison(QueryParamDto dto); + + /** + * 就业结构分析 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List structure(QueryParamDto dto); + + /** + * 人员年龄结构 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List ageStructure(QueryParamDto dto); + + /** + * 薪酬水平对标 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List salaryLevel(QueryParamDto dto); } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisCommonServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisCommonServiceImpl.java index 022fdc3..698a002 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisCommonServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisCommonServiceImpl.java @@ -36,27 +36,9 @@ public class AnalysisCommonServiceImpl implements AnalysisCommonService { @Override public List industryList() { List list = new ArrayList<>(); - - list.add(DictVo.builder().code("A").desc("农、林、牧、渔业").build()); - list.add(DictVo.builder().code("B").desc("采矿业").build()); - list.add(DictVo.builder().code("C").desc("制造业").build()); - list.add(DictVo.builder().code("D").desc("电力、热力、燃气及水生产和供应业").build()); - list.add(DictVo.builder().code("E").desc("建筑业").build()); - list.add(DictVo.builder().code("F").desc("批发和零售业").build()); - list.add(DictVo.builder().code("G").desc("交通运输、仓储和邮政业").build()); - list.add(DictVo.builder().code("H").desc("住宿和餐饮业").build()); - list.add(DictVo.builder().code("I").desc("信息传输、软件和信息技术服务业").build()); - list.add(DictVo.builder().code("J").desc("金融业").build()); - list.add(DictVo.builder().code("K").desc("房地产业").build()); - list.add(DictVo.builder().code("L").desc("租赁和商务服务业").build()); - list.add(DictVo.builder().code("M").desc("科学研究和技术服务业").build()); - list.add(DictVo.builder().code("N").desc("水利、环境和公共设施管理业").build()); - list.add(DictVo.builder().code("O").desc("居民服务、修理和其他服务业").build()); - list.add(DictVo.builder().code("P").desc("教育").build()); - list.add(DictVo.builder().code("Q").desc("卫生和社会工作").build()); - list.add(DictVo.builder().code("R").desc("文化、体育和娱乐业").build()); - list.add(DictVo.builder().code("S").desc("公共管理、社会保障和社会组织").build()); - list.add(DictVo.builder().code("T").desc("国际组织").build()); + for (Tuple2 industry : CommonConstant.INDUSTRY_LIST) { + list.add(DictVo.builder().code(industry.getT1()).desc(industry.getT2()).build()); + } return list; } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisIndustryEmploymentInfoServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisIndustryEmploymentInfoServiceImpl.java index 14a056f..ef20226 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisIndustryEmploymentInfoServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisIndustryEmploymentInfoServiceImpl.java @@ -1,13 +1,24 @@ package com.ruoyi.cms.service.impl; +import com.ruoyi.cms.constant.CommonConstant; import com.ruoyi.cms.domain.dto.QueryParamDto; 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.AnalysisIndustryEmploymentInfoService; +import com.ruoyi.cms.util.MathUtil; 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.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * 行业就业情况信息分析 @@ -40,4 +51,96 @@ public class AnalysisIndustryEmploymentInfoServiceImpl implements AnalysisIndust .averageSalaryMom(BigDecimal.valueOf(-3.3)) .build(); } + + @Override + public List scaleAndTrend(QueryParamDto dto) { + + List 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()); + } + + // 计算同环比 + MathUtil.calculatePercentageGrowthRate(dto.getQueryTimeType(), list); + + return list; + } + + @Override + public List scaleComparison(QueryParamDto dto) { + List list = new ArrayList<>(); + for (Tuple2 industry : CommonConstant.INDUSTRY_LIST) { + list.add(QueryResultVo.builder() + .code(industry.getT1()) + .desc(industry.getT2()) + .count((long) Math.floor(Math.random() * 100000) + 1) + .build()); + } + return list; + } + + @Override + public List structure(QueryParamDto dto) { + List list = new ArrayList<>(); + List> structureList = + Collections.unmodifiableList(new ArrayList<>(Arrays.asList( + Tuples.of("1", "管理层"), + Tuples.of("2", "专业技术"), + Tuples.of("3", "技能工人"), + Tuples.of("4", "一般员工") + ))); + for (Tuple2 structure : structureList) { + list.add(QueryResultVo.builder() + .code(structure.getT1()) + .desc(structure.getT2()) + .count((long) Math.floor(Math.random() * 100000) + 1) + .build()); + } + // 计算占比 + MathUtil.calculatePercentage(list); + return list; + } + + @Override + public List ageStructure(QueryParamDto dto) { + List list = new ArrayList<>(); + List> 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 structure : structureList) { + list.add(QueryResultVo.builder() + .code(structure.getT1()) + .desc(structure.getT2()) + .count((long) Math.floor(Math.random() * 100000) + 1) + .build()); + } + // 计算占比 + MathUtil.calculatePercentage(list); + return list; + } + + @Override + public List salaryLevel(QueryParamDto dto) { + List list = new ArrayList<>(); + for (Tuple2 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()); + } + return list; + } } diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/MathUtil.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/MathUtil.java new file mode 100644 index 0000000..ab85223 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/MathUtil.java @@ -0,0 +1,171 @@ +package com.ruoyi.cms.util; + +import com.ruoyi.cms.constant.enums.QueryTimeTypeEnum; +import com.ruoyi.cms.domain.vo.QueryResultVo; +import com.ruoyi.cms.domain.vo.TreadVo; +import org.apache.commons.collections4.CollectionUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * 数学工具 + * + * @author 马宝龙 + * @date 2026/1/21 + */ +public class MathUtil { + private MathUtil() { + } + + + /** + * 除以 10000 + * + * @param n 原数 + * @return 结果 + */ + public static BigDecimal divideTenThousand(Long n) { + if (Objects.isNull(n)) { + return null; + } + BigDecimal bigDecimal = new BigDecimal(n.toString()); + return divideTenThousand(bigDecimal); + } + + + /** + * 除以 10000 + * + * @param bigDecimal 原数 + * @return 结果 + */ + public static BigDecimal divideTenThousand(BigDecimal bigDecimal) { + if (Objects.isNull(bigDecimal)) { + return null; + } + String plainString = bigDecimal.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP) + .stripTrailingZeros().toPlainString(); + return new BigDecimal(plainString); + } + + + /** + * 计算比率 + * + * @param divisor 除数(分母) + * @param dividend 被除数(分子) + * @return 比率 + */ + public static BigDecimal calculatePercentage(Long divisor, Long dividend) { + BigDecimal divisorBigDecimal = Optional.ofNullable(divisor) + .map(item -> new BigDecimal(item.toString())).orElse(null); + BigDecimal dividendBigDecimal = Optional.ofNullable(dividend) + .map(item -> new BigDecimal(item.toString())).orElse(null); + return calculatePercentage(divisorBigDecimal, dividendBigDecimal); + } + + /** + * 计算比率 + * + * @param divisor 除数(分母) + * @param dividend 被除数(分子) + * @return 比率 + */ + public static BigDecimal calculatePercentage(BigDecimal divisor, BigDecimal dividend) { + if (null == dividend || BigDecimal.ZERO.compareTo(dividend) == 0) { + return BigDecimal.ZERO; + } else { + if (null == divisor || BigDecimal.ZERO.compareTo(divisor) == 0) { + return new BigDecimal("100"); + } else { + String plainString = dividend.multiply(new BigDecimal("100")) + .divide(divisor, 2, RoundingMode.HALF_UP) + .stripTrailingZeros().toPlainString(); + return new BigDecimal(plainString); + } + } + } + + /** + * 计算占比 + * + * @param list 热力图数据 + */ + public static void calculatePercentage(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + long totalCount = 0; + for (QueryResultVo dto : list) { + totalCount = totalCount + dto.getCount(); + } + + for (QueryResultVo dto : list) { + dto.setCountPercentage(calculatePercentage(totalCount, dto.getCount())); + } + } + + /** + * 计算同比和环比 + * + * @param queryTimeType 查询时间类型 + * @param list 趋势数据列表 + */ + public static void calculatePercentageGrowthRate(QueryTimeTypeEnum queryTimeType, + List list) { + + if (CollectionUtils.isEmpty(list)) { + return; + } + + // 按月份正序排序 + list.sort(Comparator.comparingInt(TreadVo::getSort)); + + for (int i = 0; i < list.size(); i++) { + + TreadVo item = list.get(i); + + long currentCount = Optional.ofNullable(item.getCurrentCount()) + .orElse(0L); + long lastYearCount = Optional.ofNullable(item.getLastYearCount()) + .orElse(0L); + // 年度不计算同比 + if (queryTimeType != QueryTimeTypeEnum.YEAR) { + // 计算同比 + item.setYearOnYearGrowthDiff(currentCount - lastYearCount); + if (0 == currentCount) { + item.setYearOnYearGrowthRate(BigDecimal.ZERO); + } else if (0 == lastYearCount) { + item.setYearOnYearGrowthRate(new BigDecimal("100.00")); + } else { + item.setYearOnYearGrowthRate(calculatePercentage(lastYearCount, (currentCount - lastYearCount))); + } + } + + // 计算环比 + long lastMonthCount; + if (0 == i) { + // 第一个取上期的最后一个数据 + lastMonthCount = Optional.ofNullable(list.get(list.size() - 1).getLastYearCount()) + .orElse(0L); + } else { + lastMonthCount = Optional.ofNullable(list.get(i - 1).getLastYearCount()) + .orElse(0L); + } + item.setLastMonthCount(lastMonthCount); + item.setMonthOnMonthGrowthDiff(currentCount - lastMonthCount); + if (0 == currentCount) { + item.setMonthOnMonthGrowthRate(BigDecimal.ZERO); + } else if (0 == lastMonthCount) { + item.setMonthOnMonthGrowthRate(new BigDecimal("100.00")); + } else { + item.setMonthOnMonthGrowthRate(calculatePercentage(lastMonthCount, (currentCount - lastMonthCount))); + } + } + } +}