From 40b87882273c8141207526e2ea9fad78f7f22d33 Mon Sep 17 00:00:00 2001 From: sh Date: Mon, 23 Mar 2026 16:27:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=AB=9E=E4=BA=89=E5=8A=9B?= =?UTF-8?q?=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/JobCollectionServiceImpl.java | 232 +++++++++++------- .../java/com/ruoyi/cms/util/RoleUtils.java | 22 ++ 2 files changed, 172 insertions(+), 82 deletions(-) diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/JobCollectionServiceImpl.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/JobCollectionServiceImpl.java index 34b7158..1f6fbe5 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/JobCollectionServiceImpl.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/service/impl/JobCollectionServiceImpl.java @@ -14,9 +14,12 @@ import com.ruoyi.cms.mapper.AppUserMapper; import com.ruoyi.cms.mapper.JobApplyMapper; import com.ruoyi.cms.mapper.JobMapper; import com.ruoyi.cms.service.IBussinessDictTypeService; +import com.ruoyi.cms.util.RoleUtils; +import com.ruoyi.cms.util.StringUtil; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SiteSecurityUtils; +import com.ruoyi.common.utils.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; @@ -186,22 +189,6 @@ public class JobCollectionServiceImpl extends ServiceImpl appUsers = appUserMapper.selectByJobId(jobId); - Long applyCount = (long) appUsers.size(); - - if (appUsers.isEmpty()) { - // 没有人申请,返回默认值或0 - CompetitivenessResponse emptyResponse = new CompetitivenessResponse(); - emptyResponse.setTotalApplicants(0); - emptyResponse.setMatchScore(0); - emptyResponse.setRank(0); - emptyResponse.setPercentile(0); - RadarChart radarChart = new RadarChart(); - emptyResponse.setRadarChart(radarChart); - return emptyResponse; - } - // ================== 数据字典映射(用于排序比较)================== // 假设你有字典工具类,如 DictUtils.getSort("education", value) 返回排序值 // 这里我们用 Map 模拟字典排序(越小要求越低) @@ -212,81 +199,53 @@ public class JobCollectionServiceImpl extends ServiceImpl dictSort(越小要求越低) Map educationRank = educationDict.stream() .collect(Collectors.toMap( - BussinessDictData::getDictLabel, + BussinessDictData::getDictValue, data -> Math.toIntExact(data.getDictSort()), (a, b) -> a // 若有重复 key,保留第一个 )); Map experienceRank = experienceDict.stream() .collect(Collectors.toMap( - BussinessDictData::getDictLabel, + BussinessDictData::getDictValue, data -> Math.toIntExact(data.getDictSort()), (a, b) -> a )); - // ================== 提取岗位要求 ================== - Integer jobEducationRank = educationRank.getOrDefault(job.getEducation(), 999); - Integer jobExperienceRank = experienceRank.getOrDefault(job.getExperience(), 999); - Integer jobMinSalary = job.getMinSalary() != null ? job.getMinSalary().intValue() : 0; - String jobLocation = job.getJobLocation(); + // 获取所有申请该岗位的用户 + List appUsers = appUserMapper.selectByJobId(jobId); + appUsers = appUsers == null ? new ArrayList<>() : appUsers; + Long applyCount = (long) appUsers.size(); + + //获取求职者状态 + Long loginUserId = RoleUtils.getAppUserId(); + boolean isLogin = loginUserId != null; + AppUser currentAppUser = new AppUser(); + if (isLogin) { + AppUser tempUser = appUserMapper.selectById(loginUserId); + if (tempUser != null && !StringUtil.IS_COMPANY_USER.equals(tempUser.getIsCompanyUser())) { + currentAppUser = tempUser; + } + } + + if (appUsers.isEmpty()) { + // 没有人申请,返回默认值或0 + CompetitivenessResponse emptyResponse = new CompetitivenessResponse(); + emptyResponse.setTotalApplicants(0); + //计算匹配度 + int realMatchScore = isLogin && !StringUtil.IS_COMPANY_USER.equals(currentAppUser.getIsCompanyUser())? calculateUserMatchScore(currentAppUser, job, educationRank, experienceRank): 0; + emptyResponse.setMatchScore(realMatchScore); + emptyResponse.setRank(0); + emptyResponse.setPercentile(0); + emptyResponse.setRadarChart(buildUserRadarChart(currentAppUser,job,educationRank,experienceRank)); + return emptyResponse; + } // ================== 聚合用户数据用于分析 ================== List userScores = new ArrayList<>(); for (AppUser user : appUsers) { - int matchScore = 0; - int totalFactors = 6; // 年龄、经验、学历、技能(暂用期望岗位匹配)、薪资、地点 - - // 1. 学历匹配(越接近越好) - Integer userEduRank = educationRank.getOrDefault(user.getEducation(), 999); - if (userEduRank <= jobEducationRank) { - matchScore += 1; // 达标 - } else if (userEduRank == jobEducationRank + 1) { - matchScore += 0.5; // 略高也算匹配 - } - - // 2. 经验匹配 - Integer userExpRank = experienceRank.getOrDefault(user.getExperience(), 999); - if (userExpRank >= jobExperienceRank) { - matchScore += 1; // 满足经验要求 - } - - // 3. 薪资匹配(用户期望 <= 岗位最大薪资,且不低于最小太多) - Integer userMinSalary = parseSalary(user.getSalaryMin()); - if (userMinSalary != null && userMinSalary <= job.getMaxSalary()) { - if (userMinSalary >= job.getMinSalary()) { - matchScore += 1; - } else if (userMinSalary >= job.getMinSalary() * 0.8) { - matchScore += 0.5; - } - } - - // 4. 地点匹配 - if (user.getArea() != null) { - if(user.getArea().contains(jobLocation) || jobLocation.contains(user.getArea())){ - matchScore += 1; - } - } - - // 5. 年龄估算(从生日计算) - int userAge = getUserAge(DateUtils.stringToDateWithYmd(user.getBirthDate(),DateUtils.YYYY_MM_DD)); - // 假设最佳年龄区间为 22-35,越接近越匹配 - if (userAge >= 22 && userAge <= 35) { - matchScore += 1; - } else if (userAge >= 18 && userAge <= 45) { - matchScore += 0.5; - } - - // 6. 技能/岗位匹配(简化:期望岗位是否包含该岗位关键词) - boolean jobMatch = user.getJobTitle() != null && - user.getJobTitle().stream().anyMatch(title -> title.contains(job.getJobTitle()) || job.getJobTitle().contains(title)); - if (jobMatch) { - matchScore += 1; - } - - // 匹配度:0-6 → 映射为 0-100 分 - int finalScore = (int) Math.round((matchScore / (double) totalFactors) * 100); - userScores.add(new UserCompetitiveness(user, finalScore)); + int matchScore = calculateUserMatchScore(user, job, educationRank, experienceRank); + userScores.add(new UserCompetitiveness(user, matchScore)); } // 按匹配度降序 @@ -314,19 +273,128 @@ public class JobCollectionServiceImpl extends ServiceImpl userMatchScore) { + userRank++; + } + } + response.setRank(userRank); + int percentile = (int) Math.round(((applyCount - userRank) * 1.0 / applyCount) * 100); + response.setPercentile(percentile); + } else { + response.setMatchScore(0); + response.setRank(0); + response.setPercentile(0); + } response.setRadarChart(radarChart); return response; } + + /** + * 构建雷达图 + * @param user + * @param job + * @param educationRank + * @param experienceRank + * @return + */ + private RadarChart buildUserRadarChart(AppUser user, Job job, Map educationRank, Map experienceRank) { + RadarChart radarChart = new RadarChart(); + int ageScore = getAgeScore(DateUtils.stringToDateWithYmd(user.getBirthDate(),DateUtils.YYYY_MM_DD)); + int expScore = getExperienceScore(user.getExperience(), job.getExperience(), experienceRank); + int eduScore = getEducationScore(user.getEducation(), job.getEducation(), educationRank); + int skillScore = getSkillScore(user, job); + int salaryScore = getSalaryScore(user, job); + int locScore = getLocationScore(user, job); + // 赋值雷达图 + radarChart.setAge(ageScore); + radarChart.setExperience(expScore); + radarChart.setEducation(eduScore); + radarChart.setSkill(skillScore); + radarChart.setSalary(salaryScore); + radarChart.setLocation(locScore); + return radarChart; + } + + /** + * 构建匹配度 + * @param user + * @param job + * @param educationRank + * @param experienceRank + * @return + */ + private int calculateUserMatchScore(AppUser user, Job job, Map educationRank, Map experienceRank) { + int matchScore = 0; + int totalFactors = 6; + Integer userEduRank = educationRank.getOrDefault(user.getEducation(), 999); + Integer jobEduRank = educationRank.getOrDefault(job.getEducation(), 999); + //判断学历 + if (userEduRank <= jobEduRank) { + matchScore += 1; + } else if (userEduRank == jobEduRank + 1) { + matchScore += 0.5; + } + //判断工作经验 + Integer userExpRank = experienceRank.getOrDefault(user.getExperience(), 999); + Integer jobExpRank = experienceRank.getOrDefault(job.getExperience(), 999); + if (userExpRank >= jobExpRank) { + matchScore += 1; + } + //判断薪资 + Integer userMinSalary = parseSalary(user.getSalaryMin()); + if (userMinSalary != null && userMinSalary <= job.getMaxSalary()) { + if (userMinSalary >= job.getMinSalary()) { + matchScore += 1; + } else if (userMinSalary >= job.getMinSalary() * 0.8) { + matchScore += 0.5; + } + } + //判断区域 + if (user.getArea() != null && job.getJobLocationAreaCode() != null) { + //if(user.getArea().contains(job.getJobLocation()) || job.getJobLocation().contains(user.getArea())){ + String userArea = user.getArea().trim(); + String jobArea = job.getJobLocationAreaCode().trim(); + if(userArea.equals(jobArea)){ + matchScore += 1; + } + } + //判断年龄 + if (!StringUtil.IS_COMPANY_USER.equals(user.getIsCompanyUser())) { + int userAge = 0; + String birthDate = user.getBirthDate(); + if (StringUtils.isNotBlank(birthDate)) { + userAge = getUserAge(DateUtils.stringToDateWithYmd(birthDate, DateUtils.YYYY_MM_DD)); + }else if (StringUtils.isNotBlank(user.getIdCard())) { + birthDate = StringUtil.getBirthDateFromIdCard(user.getIdCard()); + userAge = getUserAge(DateUtils.stringToDateWithYmd(birthDate, DateUtils.YYYY_MM_DD)); + } + if (userAge >= 22 && userAge <= 35) { + matchScore += 1; + } else if (userAge >= 18 && userAge <= 45) { + matchScore += 0.5; + } + } + //判断岗位 + boolean jobMatch = user.getJobTitle() != null && + user.getJobTitle().stream().anyMatch(title -> title.contains(job.getJobTitle()) || job.getJobTitle().contains(title)); + if (jobMatch) { + matchScore += 1; + } + return (int) Math.round((matchScore / (double) totalFactors) * 100); + } + private int getUserAge(Date birthDate) { if (birthDate == null) return 0; try { diff --git a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/RoleUtils.java b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/RoleUtils.java index d101fa4..2652240 100644 --- a/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/RoleUtils.java +++ b/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/RoleUtils.java @@ -74,4 +74,26 @@ public class RoleUtils { } return appUser.getIsCompanyUser(); } + + /** + * 获取userId + * @return + */ + public static Long getAppUserId(){ + try { + Long userId=null; + LoginSiteUser loginSiteUser = SiteSecurityUtils.getLoginUser(); + AppUser appUser = loginSiteUser.getUser(); + if (appUser != null) { + userId=appUser.getUserId(); + }else{ + LoginUser loginUser = SecurityUtils.getLoginUser(); + SysUser sysUser = loginUser.getUser(); + userId=sysUser.getAppUserId(); + } + return userId; + } catch (Exception e) { + return null; + } + } } \ No newline at end of file