diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisSectorOccupationSkillController.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisSectorOccupationSkillController.java new file mode 100644 index 0000000..f517e33 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/controller/AnalysisSectorOccupationSkillController.java @@ -0,0 +1,90 @@ +package com.ruoyi.cms.controller; + +import com.ruoyi.cms.domain.dto.QueryParamDto; +import com.ruoyi.cms.service.AnalysisSectorOccupationSkillService; +import com.ruoyi.common.core.domain.AjaxResult; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 产业发展与职业技能提升分析 + * + * @author 马宝龙 + * @date 2026/6/26 + */ +@RestController +@RequestMapping("/analysis/sectorOccupationSkill") +@RequiredArgsConstructor +public class AnalysisSectorOccupationSkillController { + + private final AnalysisSectorOccupationSkillService analysisSectorOccupationSkillService; + + /** + * 数据总览 + * + * @param dto 查询参数 + * @return 数据总览 + */ + @PostMapping("/overview") + public AjaxResult overview(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.overview(dto)); + } + + /** + * 产业发展与人才需求趋势 + * + * @param dto 查询参数 + * @return 趋势数据 + */ + @PostMapping("/sectorAndTalentDemandTread") + public AjaxResult sectorAndTalentDemandTread(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.sectorAndTalentDemandTread(dto)); + } + + /** + * 重点产业的核心职业技能需求 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/coreSkillDemand") + public AjaxResult coreSkillDemand(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.coreSkillDemand(dto)); + } + + /** + * 职业技能供给与缺口分析 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/skillSupplyAndGap") + public AjaxResult skillSupplyAndGap(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.skillSupplyAndGap(dto)); + } + + /** + * 重点群体技能培训覆盖率 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/keyGroupSkillCoverageRate") + public AjaxResult keyGroupSkillCoverageRate(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.keyGroupSkillCoverageRate(dto)); + } + + /** + * 职业培训技能人才等级分布 + * + * @param dto 查询参数 + * @return 结果列表 + */ + @PostMapping("/talentSkillLevelDistribution") + public AjaxResult talentSkillLevelDistribution(@RequestBody QueryParamDto dto) { + return AjaxResult.success(analysisSectorOccupationSkillService.talentSkillLevelDistribution(dto)); + } +} \ No newline at end of file diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/dto/QueryParamDto.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/dto/QueryParamDto.java index a16535f..032e734 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/dto/QueryParamDto.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/dto/QueryParamDto.java @@ -46,6 +46,10 @@ public class QueryParamDto implements Serializable { * 行业 */ private String industry; + /** + * 产业 + */ + private String sector; /** * 高校类型 */ diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsSeriesVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsSeriesVo.java new file mode 100644 index 0000000..1266434 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsSeriesVo.java @@ -0,0 +1,31 @@ +package com.ruoyi.cms.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * ECharts 数据详情 + * + * @author 马宝龙 + * @date 2026/6/26 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class EchartsSeriesVo implements Serializable { + private static final long serialVersionUID = -6091482594897390325L; + /** + * 名称 + */ + private String name; + /** + * 数据 + */ + private List data; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsVo.java new file mode 100644 index 0000000..2d64be7 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/EchartsVo.java @@ -0,0 +1,31 @@ +package com.ruoyi.cms.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * ECharts 数据 + * + * @author 马宝龙 + * @date 2026/6/26 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class EchartsVo implements Serializable { + private static final long serialVersionUID = 5247605806734583465L; + /** + * 横坐标 + */ + private List xAxis; + /** + * 数据 + */ + private List series; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillGapVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillGapVo.java new file mode 100644 index 0000000..802a9d6 --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillGapVo.java @@ -0,0 +1,42 @@ +package com.ruoyi.cms.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 产业发展与职业技能提升分析 - 职业技能供给与缺口分析 + * + * @author 马宝龙 + * @date 2026/6/25 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SectorOccupationSkillGapVo implements Serializable { + private static final long serialVersionUID = -4931394603750785849L; + /** + * 编码 + */ + private String code; + /** + * 描述 + */ + private String desc; + /** + * 招聘需求 + */ + private Long recruitmentDemandCount; + /** + * 培训供给 + */ + private Long trainSupplyCount; + /** + * 缺口数量 + */ + private Long gapCount; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillOverviewVo.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillOverviewVo.java new file mode 100644 index 0000000..963af4f --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/domain/vo/SectorOccupationSkillOverviewVo.java @@ -0,0 +1,72 @@ +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 +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SectorOccupationSkillOverviewVo implements Serializable { + private static final long serialVersionUID = -1318931122984257073L; + + /** + * 技能培训总人数 + */ + private Long skillTrainCount; + /** + * 技能培训总人数环比 + */ + private BigDecimal skillTrainCountMom; + /** + * 培训覆盖率 + */ + private BigDecimal trainCoverageRate; + /** + * 培训覆盖率环比 + */ + private BigDecimal trainCoverageRateMom; + /** + * 平均薪资 + */ + private BigDecimal averageSalary; + /** + * 平均薪资环比 + */ + private BigDecimal averageSalaryMom; + /** + * 培训后就业率 + */ + private BigDecimal afterTrainEmploymentRate; + /** + * 培训后就业率环比 + */ + private BigDecimal afterTrainEmploymentRateMom; + /** + * 高级技能人才人数 + */ + private Long advanceSkillTalentCount; + /** + * 高级技能人才人数环比 + */ + private BigDecimal advanceSkillTalentCountMom; + /** + * 新兴技能缺口 + */ + private Long newSkillGapCount; + /** + * 新兴技能缺口环比 + */ + private BigDecimal newSkillGapCountMom; +} diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisSectorOccupationSkillService.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisSectorOccupationSkillService.java new file mode 100644 index 0000000..6e4422d --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/AnalysisSectorOccupationSkillService.java @@ -0,0 +1,68 @@ +package com.ruoyi.cms.service; + +import com.ruoyi.cms.domain.dto.QueryParamDto; +import com.ruoyi.cms.domain.vo.EchartsVo; +import com.ruoyi.cms.domain.vo.QueryResultVo; +import com.ruoyi.cms.domain.vo.SectorOccupationSkillGapVo; +import com.ruoyi.cms.domain.vo.SectorOccupationSkillOverviewVo; + +import java.util.List; + +/** + * 产业发展与职业技能提升分析 + * + * @author 马宝龙 + * @date 2026/6/26 + */ +public interface AnalysisSectorOccupationSkillService { + + + /** + * 数据总览 + * + * @param dto 查询参数 + * @return 数据总览 + */ + SectorOccupationSkillOverviewVo overview(QueryParamDto dto); + + /** + * 产业发展与人才需求趋势 + * + * @param dto 查询参数 + * @return 趋势数据 + */ + EchartsVo sectorAndTalentDemandTread(QueryParamDto dto); + + /** + * 重点产业的核心职业技能需求 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List coreSkillDemand(QueryParamDto dto); + + /** + * 职业技能供给与缺口分析 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List skillSupplyAndGap(QueryParamDto dto); + + /** + * 重点群体技能培训覆盖率 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List keyGroupSkillCoverageRate(QueryParamDto dto); + + /** + * 职业培训技能人才等级分布 + * + * @param dto 查询参数 + * @return 结果列表 + */ + List talentSkillLevelDistribution(QueryParamDto dto); + +} \ No newline at end of file diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisSectorOccupationSkillServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisSectorOccupationSkillServiceImpl.java new file mode 100644 index 0000000..1e1405f --- /dev/null +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/AnalysisSectorOccupationSkillServiceImpl.java @@ -0,0 +1,157 @@ +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.EchartsSeriesVo; +import com.ruoyi.cms.domain.vo.EchartsVo; +import com.ruoyi.cms.domain.vo.QueryResultVo; +import com.ruoyi.cms.domain.vo.SectorOccupationSkillGapVo; +import com.ruoyi.cms.domain.vo.SectorOccupationSkillOverviewVo; +import com.ruoyi.cms.service.AnalysisSectorOccupationSkillService; +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; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 产业发展与职业技能提升分析 + * + * @author 马宝龙 + * @date 2026/6/26 + */ +@Service +@Validated +@Slf4j +public class AnalysisSectorOccupationSkillServiceImpl implements AnalysisSectorOccupationSkillService { + + @Override + public SectorOccupationSkillOverviewVo overview(QueryParamDto dto) { + return SectorOccupationSkillOverviewVo.builder() + .skillTrainCount(25000L) + .skillTrainCountMom(BigDecimal.valueOf(8.5)) + .trainCoverageRate(BigDecimal.valueOf(68.3)) + .trainCoverageRateMom(BigDecimal.valueOf(3.2)) + .averageSalary(BigDecimal.valueOf(6850.50)) + .averageSalaryMom(BigDecimal.valueOf(4.2)) + .afterTrainEmploymentRate(BigDecimal.valueOf(82.5)) + .afterTrainEmploymentRateMom(BigDecimal.valueOf(2.1)) + .advanceSkillTalentCount(5800L) + .advanceSkillTalentCountMom(BigDecimal.valueOf(6.8)) + .newSkillGapCount(3200L) + .newSkillGapCountMom(BigDecimal.valueOf(-2.5)) + .build(); + } + + @Override + public EchartsVo sectorAndTalentDemandTread(QueryParamDto dto) { + + List xAxis = IntStream.rangeClosed(1, 12) + .mapToObj(i -> i + "月") + .collect(Collectors.toList()); + List series = new ArrayList<>(); + for (Tuple2 sector : CommonConstant.SECTOR_LIST) { + List dataList = new ArrayList<>(); + for (int i = 0; i < 12; i++) { + dataList.add((long) Math.floor(Math.random() * 20000) + 5000); + } + series.add(EchartsSeriesVo.builder().name(sector.getT2()).data(dataList).build()); + } + + return EchartsVo.builder().xAxis(xAxis).series(series).build(); + } + + @Override + public List coreSkillDemand(QueryParamDto dto) { + List list = new ArrayList<>(); + List> skillList = + 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 skill : skillList) { + list.add(QueryResultVo.builder() + .code(skill.getT1()) + .desc(skill.getT2()) + .count((long) Math.floor(Math.random() * 100000) + 1) + .build()); + } + return list; + } + + @Override + public List skillSupplyAndGap(QueryParamDto dto) { + List list = new ArrayList<>(); + for (Tuple2 sector : CommonConstant.SECTOR_LIST) { + long demand = (long) Math.floor(Math.random() * 10000) + 500; + long supply = (long) Math.floor(Math.random() * 5000) + 100; + list.add(SectorOccupationSkillGapVo.builder() + .code(sector.getT1()) + .desc(sector.getT2()) + .recruitmentDemandCount(demand) + .trainSupplyCount(supply) + .gapCount((demand - supply) > 0 ? demand - supply : 0) + .build()); + } + return list; + } + + @Override + public List keyGroupSkillCoverageRate(QueryParamDto dto) { + List list = new ArrayList<>(); + List> groupList = + 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 group : groupList) { + list.add(QueryResultVo.builder() + .code(group.getT1()) + .desc(group.getT2()) + .count((long) Math.floor(Math.random() * 20000) + 5000) + .anotherCount((long) Math.floor(Math.random() * 20000) + 5000) + .rate(BigDecimal.valueOf(Math.random() * 100 + 1).setScale(1, RoundingMode.HALF_UP)) + .build()); + } + return list; + } + + @Override + public List talentSkillLevelDistribution(QueryParamDto dto) { + List list = new ArrayList<>(); + List> skillLevelList = + Collections.unmodifiableList(new ArrayList<>(Arrays.asList( + Tuples.of("1", "初级工及其他"), + Tuples.of("2", "中级工"), + Tuples.of("3", "高级工"), + Tuples.of("4", "技师/高级技师") + ))); + for (Tuple2 level : skillLevelList) { + list.add(QueryResultVo.builder() + .code(level.getT1()) + .desc(level.getT2()) + .count((long) Math.floor(Math.random() * 100000) + 1) + .build()); + } + MathUtil.calculatePercentage(list); + return list; + } +} \ No newline at end of file