diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java index 143f58a..6cd38f7 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/hotake/HotakeRolesApplyInfoController.java @@ -5,6 +5,7 @@ import com.vetti.common.core.controller.BaseController; import com.vetti.common.core.domain.R; import com.vetti.common.core.page.TableWebDataInfo; import com.vetti.common.enums.BusinessType; +import com.vetti.common.utils.SecurityUtils; import com.vetti.hotake.domain.HotakeRolesApplyInfo; import com.vetti.hotake.service.IHotakeRolesApplyInfoService; import io.swagger.annotations.Api; @@ -36,6 +37,8 @@ public class HotakeRolesApplyInfoController extends BaseController public TableWebDataInfo pageList(HotakeRolesApplyInfo hotakeRolesApplyInfo) { startPage(); + //招聘人列表数据 + hotakeRolesApplyInfo.setRecruiterId(SecurityUtils.getUserId()); List list = hotakeRolesApplyInfoService.selectHotakeRolesApplyInfoList(hotakeRolesApplyInfo); return getWebDataTable(list); } diff --git a/vetti-common/src/main/java/com/vetti/common/enums/CandidateStatusEnum.java b/vetti-common/src/main/java/com/vetti/common/enums/CandidateStatusEnum.java new file mode 100644 index 0000000..2984670 --- /dev/null +++ b/vetti-common/src/main/java/com/vetti/common/enums/CandidateStatusEnum.java @@ -0,0 +1,34 @@ +package com.vetti.common.enums; + +/** + * 候选人状态 + */ +public enum CandidateStatusEnum { + + HOT("Hot", "热"), + WARM("Warm", "温暖"), + COLD("Cold", "冷"), + PENDING("Pending", "待定"), + + ; + + private final String code; + private final String info; + + CandidateStatusEnum(String code, String info) + { + this.code = code; + this.info = info; + } + + public String getCode() + { + return code; + } + + public String getInfo() + { + return info; + } + +} diff --git a/vetti-common/src/main/java/com/vetti/common/enums/StageEnum.java b/vetti-common/src/main/java/com/vetti/common/enums/StageEnum.java new file mode 100644 index 0000000..4950523 --- /dev/null +++ b/vetti-common/src/main/java/com/vetti/common/enums/StageEnum.java @@ -0,0 +1,35 @@ +package com.vetti.common.enums; + +/** + * 岗位申请当前阶段 + */ +public enum StageEnum { + + APPLIED("Applied", "已申请"), + SHORTLISTED("Shortlisted", "入围"), + INTERVIEW("Interview", "面试"), + OFFER("Offer", "邀约"), + HIRED("Hired", "受雇"), + + ; + + private final String code; + private final String info; + + StageEnum(String code, String info) + { + this.code = code; + this.info = info; + } + + public String getCode() + { + return code; + } + + public String getInfo() + { + return info; + } + +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java index 3f30ba2..7759dbb 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java @@ -1,6 +1,8 @@ package com.vetti.hotake.domain; import java.math.BigDecimal; + +import com.vetti.hotake.domain.dto.HotakeCvInfoDto; import lombok.Data; import lombok.experimental.Accessors; import io.swagger.annotations.ApiModelProperty; @@ -28,6 +30,11 @@ public class HotakeRolesApplyInfo extends BaseEntity @Excel(name = "候选人ID") private Long candidateId; + /** 招聘人ID */ + @ApiModelProperty("招聘人ID") + @Excel(name = "招聘人ID") + private Long recruiterId; + /** 岗位ID */ @ApiModelProperty("岗位ID") @Excel(name = "岗位ID") @@ -109,4 +116,10 @@ public class HotakeRolesApplyInfo extends BaseEntity @Excel(name = "AI评分百分比") private BigDecimal aiMatchScorePercentage; + @ApiModelProperty("岗位信息") + private HotakeRolesInfo rolesInfo; + + @ApiModelProperty("解析的简历数据信息") + private HotakeCvInfoDto cvInfoDto; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvInfoDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvInfoDto.java index 3a8954d..bfdb445 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvInfoDto.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCvInfoDto.java @@ -29,6 +29,8 @@ public class HotakeCvInfoDto { private String location; @ApiModelProperty("当前工作公司") private String currentWork; + @ApiModelProperty("工作年限") + private String experienceYear; @ApiModelProperty("链接对象集合") private List links; @ApiModelProperty("自我介绍") diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java index 295dfa6..844e5c1 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeRolesInfoDto.java @@ -1,5 +1,6 @@ package com.vetti.hotake.domain.dto; +import com.vetti.common.core.domain.entity.SysUser; import com.vetti.hotake.domain.HotakeAiInterviewQuestionsInfo; import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; import com.vetti.hotake.domain.HotakeRolesInfo; @@ -44,4 +45,7 @@ public class HotakeRolesInfoDto extends HotakeRolesInfo { @ApiModelProperty("AI面试问题数据集合") private List aiInterviewQuestionsInfoList; + @ApiModelProperty("招聘人详细信息") + private SysUser recruiterUser; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java index 84d3601..eb9b8bf 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeCvInfoServiceImpl.java @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.InputStream; +import java.math.BigDecimal; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -265,7 +266,23 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC cvInfo.setProblemBaseInfo(problemBaseInfo); //生成对应的简历评分 String resultMsg = handleHotakeCvInfoScore(cvInfoDto); - cvInfo.setScore(resultMsg); + cvInfo.setCvScore(resultMsg); + cvInfo.setExperience(cvInfoDto.getExperienceYear()); + //分数解析 + String[] strs = resultMsg.split("\n"); + if(strs != null && strs.length > 0){ + String score = strs[0].replaceAll("Score:","").trim(); + String[] scores = score.split("/"); + if(scores != null && scores.length > 0){ + cvInfo.setAiMatchScore(scores[0]); + try{ + cvInfo.setAiMatchScorePercentage(String.valueOf(new BigDecimal(scores[0]). + divide(new BigDecimal(5)).setScale(2,4))); + }catch (Exception e){e.printStackTrace();} + + } + } + cvInfo.setCvTemplateJson(JSONUtil.toJsonStr(cvInfoDto)); fill(FillTypeEnum.UPDATE.getCode(), cvInfo); hotakeCvInfoMapper.updateHotakeCvInfo(cvInfo); @@ -289,7 +306,7 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC List> list = new LinkedList(); Map entity = new HashMap<>(); entity.put("role","user"); - entity.put("content","从下面提供的文本中提取所有能识别到的简历信息,只提取原文中存在的内容,不要补充、不推测、不总结。需要提取的字段包括:name(姓名或人名)、phone(电话号码)、email(电子邮件地址)、position(岗位或者简历中自己期望的职位等)、location(地点或者地址、家庭住址)、links(所有链接地址)、currentWork(当前工作公司)、about(关于我/自我介绍)、skills_tools(关键资格(许可证、注册/会员资格、认证))、languages(语言能力,主要就是Languages下面的语言)、experience(工作经历,除了title、company、location、durationStart、durationEnd,其他的都放到description里面,并且description里面要根据换行符分成不同的content),日期要拆分成开始时间(durationStart)和结束时间(durationEnd))、education(教育经历,日期要拆分成开始时间(durationStart)和结束时间(durationEnd))。请将提取结果以结构化 JSON 格式返回,格式如下:{ \\\"name\\\": \\\"\\\", \\\"phone\\\": \\\"\\\", \\\"currentWork\\\": \\\"\\\", \\\"position\\\": \\\"\\\", \\\"location\\\": \\\"\\\", \\\"email\\\": \\\"\\\", \\\"links\\\": [{\\\"content\\\":\\\"\\\"}], \\\"about\\\": \\\"\\\", \\\"skillsTools\\\": [{\\\"content\\\":\\\"\\\"}], \\\"languages\\\": [{\\\"content\\\":\\\"\\\"}], \\\"experience\\\": [{\\\"title\\\": \\\"\\\", \\\"company\\\": \\\"\\\",\\\"location\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\",\\\"description\\\": [{\\\"content\\\":\\\"\\\"}]}], \\\"education\\\": [{\\\"degree\\\": \\\"\\\",\\\"institution\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\"}] }。字段不存在则返回 null 或空数组。只返回标准可解析的 JSON结构 ,不要多余的```json等信息,不要解释说明,不要改写内容。以下为待处理文本:"+contents); + entity.put("content","从下面提供的文本中提取所有能识别到的简历信息,只提取原文中存在的内容,不要补充、不推测、不总结。需要提取的字段包括:name(姓名或人名)、phone(电话号码)、email(电子邮件地址)、experienceYear(根据工作经验计算出来的工作年限)、position(岗位或者简历中自己期望的职位等)、location(地点或者地址、家庭住址)、links(所有链接地址)、currentWork(当前工作公司)、about(关于我/自我介绍)、skills_tools(关键资格(许可证、注册/会员资格、认证))、languages(语言能力,主要就是Languages下面的语言)、experience(工作经历,除了title、company、location、durationStart、durationEnd,其他的都放到description里面,并且description里面要根据换行符分成不同的content),日期要拆分成开始时间(durationStart)和结束时间(durationEnd))、education(教育经历,日期要拆分成开始时间(durationStart)和结束时间(durationEnd))。请将提取结果以结构化 JSON 格式返回,格式如下:{ \\\"name\\\": \\\"\\\", \\\"phone\\\": \\\"\\\", \\\"currentWork\\\": \\\"\\\", \\\"position\\\": \\\"\\\", \\\"location\\\": \\\"\\\", \\\"email\\\": \\\"\\\", \\\"experienceYear\\\": \\\"\\\", \\\"links\\\": [{\\\"content\\\":\\\"\\\"}], \\\"about\\\": \\\"\\\", \\\"skillsTools\\\": [{\\\"content\\\":\\\"\\\"}], \\\"languages\\\": [{\\\"content\\\":\\\"\\\"}], \\\"experience\\\": [{\\\"title\\\": \\\"\\\", \\\"company\\\": \\\"\\\",\\\"location\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\",\\\"description\\\": [{\\\"content\\\":\\\"\\\"}]}], \\\"education\\\": [{\\\"degree\\\": \\\"\\\",\\\"institution\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\"}] }。字段不存在则返回 null 或空数组。只返回标准可解析的 JSON结构 ,不要多余的```json等信息,不要解释说明,不要改写内容。以下为待处理文本:"+contents); //根据AI做 list.add(entity); String resultCv = chatGPTClient.handleAiChat(JSONUtil.toJsonStr(list), "JX"); @@ -444,5 +461,16 @@ public class HotakeCvInfoServiceImpl extends BaseServiceImpl implements IHotakeC } + public static void main(String[] args){ + String str = "Score: 4.8/5\n" + + "Recommendation: Highly recommended candidate - strong match for the role\n" + + "Strengths: Extensive relevant experience, Professional certifications, Strong skill set alignment\n" + + "Concerns: -"; + + String[] strs = str.split("\n"); + System.out.println(strs[0].replaceAll("Score:","").trim().split("/")[0]); + } + + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java index dc664fe..b3696d7 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java @@ -1,6 +1,7 @@ package com.vetti.hotake.service.impl; import java.io.InputStream; +import java.math.BigDecimal; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -12,19 +13,20 @@ import cn.hutool.crypto.digest.MD5; import cn.hutool.json.JSONUtil; import com.vetti.common.ai.gpt.ChatGPTClient; import com.vetti.common.core.service.BaseServiceImpl; +import com.vetti.common.enums.CandidateStatusEnum; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.enums.MinioBucketNameEnum; +import com.vetti.common.enums.StageEnum; import com.vetti.common.utils.DateUtils; import com.vetti.common.utils.SecurityUtils; import com.vetti.common.utils.readFile.FileContentUtil; -import com.vetti.hotake.domain.HotakeCvInfo; -import com.vetti.hotake.domain.HotakeProblemBaseInfo; -import com.vetti.hotake.domain.HotakeRolesApplyInfo; +import com.vetti.hotake.domain.*; import com.vetti.hotake.domain.dto.HotakeCvInfoDto; import com.vetti.hotake.domain.dto.VcDto.*; import com.vetti.hotake.domain.vo.HotakeInitScreQuestionsReplyRecordInfoVo; import com.vetti.hotake.mapper.HotakeCvInfoMapper; import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper; +import com.vetti.hotake.mapper.HotakeRolesInfoMapper; import io.minio.GetObjectArgs; import io.minio.MinioClient; import lombok.extern.slf4j.Slf4j; @@ -33,7 +35,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.vetti.hotake.mapper.HotakeInitScreQuestionsReplyRecordInfoMapper; -import com.vetti.hotake.domain.HotakeInitScreQuestionsReplyRecordInfo; import com.vetti.hotake.service.IHotakeInitScreQuestionsReplyRecordInfoService; /** @@ -53,6 +54,9 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi @Autowired private HotakeRolesApplyInfoMapper hotakeRolesApplyInfoMapper; + @Autowired + private HotakeRolesInfoMapper hotakeRolesInfoMapper; + @Autowired private HotakeCvInfoMapper hotakeCvInfoMapper; @@ -175,6 +179,7 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi //获取申请的简历数据 HotakeRolesApplyInfo applyInfo = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(initScreQuestionsReplyRecordInfoVo.getRoleApplyId()); if (applyInfo != null) { + HotakeRolesInfo rolesInf = hotakeRolesInfoMapper.selectHotakeRolesInfoById(initScreQuestionsReplyRecordInfoVo.getRoleId()); //查询候选人的当前最新简历信息 HotakeCvInfo queryCv = new HotakeCvInfo(); queryCv.setUserId(SecurityUtils.getUserId()); @@ -196,12 +201,15 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi log.info("简历信息:{}", contents); //验证文件内容是否改变,如果未改变不进行模型解析直接返回原有结果 String md5Hash = MD5.create().digestHex16(contents); + String scoreStr = ""; if (StrUtil.isNotEmpty(md5Hash) && cvInfo != null && md5Hash.equals(cvInfo.getCvMd5())) { //直接获取简历表中的简历解析的详细数据 applyInfo.setCvScore(cvInfo.getCvScore()); applyInfo.setCvTemplateJson(cvInfo.getCvTemplateJson()); fill(FillTypeEnum.UPDATE.getCode(), applyInfo); applyInfo.setCvMd5(md5Hash); + applyInfo.setExperience(cvInfo.getExperience()); + scoreStr = cvInfo.getCvScore(); }else{ //生成简历模版数据信息 HotakeCvInfoDto cvInfoDto = handleAnalysisCvInfo(contents); @@ -211,10 +219,38 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi applyInfo.setCvTemplateJson(JSONUtil.toJsonStr(cvInfoDto)); fill(FillTypeEnum.UPDATE.getCode(), cvInfo); applyInfo.setCvMd5(md5Hash); + applyInfo.setExperience(cvInfoDto.getExperienceYear()); + scoreStr = resultMsg; } - //更新岗位申请数据记录 - applyInfo.setCandidateStatus("Pending"); - applyInfo.setStage(""); + //更新岗位申请数据记录--根据评分进行计算 + //分数解析 + String[] strs = scoreStr.split("\n"); + if(strs != null && strs.length > 0){ + String score = strs[0].replaceAll("Score:","").trim(); + String[] scores = score.split("/"); + if(scores != null && scores.length > 0){ + applyInfo.setAiMatchScore(scores[0]); + try{ + applyInfo.setAiMatchScorePercentage(new BigDecimal(scores[0]). + divide(new BigDecimal(5)).setScale(2,4)); + }catch (Exception e){e.printStackTrace();} + } + } + if(applyInfo.getAiMatchScorePercentage() != null){ + if(applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.85)) >= 0){ + applyInfo.setCandidateStatus(CandidateStatusEnum.HOT.getCode()); + }else if(applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.85)) < 0 + && applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.6)) >= 0){ + applyInfo.setCandidateStatus(CandidateStatusEnum.WARM.getCode()); + }else if(applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.6)) < 0 + && applyInfo.getAiMatchScorePercentage().compareTo(new BigDecimal(0.3)) >= 0){ + applyInfo.setCandidateStatus(CandidateStatusEnum.COLD.getCode()); + }else { + applyInfo.setCandidateStatus(CandidateStatusEnum.PENDING.getCode()); + } + } + applyInfo.setRecruiterId(rolesInf.getRecruiterId()); + applyInfo.setStage(StageEnum.APPLIED.getCode()); hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(applyInfo); } catch (Exception e) { e.printStackTrace(); @@ -238,7 +274,7 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi List> list = new LinkedList(); Map entity = new HashMap<>(); entity.put("role","user"); - entity.put("content","从下面提供的文本中提取所有能识别到的简历信息,只提取原文中存在的内容,不要补充、不推测、不总结。需要提取的字段包括:name(姓名或人名)、phone(电话号码)、email(电子邮件地址)、position(岗位或者简历中自己期望的职位等)、location(地点或者地址、家庭住址)、links(所有链接地址)、currentWork(当前工作公司)、about(关于我/自我介绍)、skills_tools(关键资格(许可证、注册/会员资格、认证))、languages(语言能力,主要就是Languages下面的语言)、experience(工作经历,除了title、company、location、durationStart、durationEnd,其他的都放到description里面,并且description里面要根据换行符分成不同的content),日期要拆分成开始时间(durationStart)和结束时间(durationEnd))、education(教育经历,日期要拆分成开始时间(durationStart)和结束时间(durationEnd))。请将提取结果以结构化 JSON 格式返回,格式如下:{ \\\"name\\\": \\\"\\\", \\\"phone\\\": \\\"\\\", \\\"currentWork\\\": \\\"\\\", \\\"position\\\": \\\"\\\", \\\"location\\\": \\\"\\\", \\\"email\\\": \\\"\\\", \\\"links\\\": [{\\\"content\\\":\\\"\\\"}], \\\"about\\\": \\\"\\\", \\\"skillsTools\\\": [{\\\"content\\\":\\\"\\\"}], \\\"languages\\\": [{\\\"content\\\":\\\"\\\"}], \\\"experience\\\": [{\\\"title\\\": \\\"\\\", \\\"company\\\": \\\"\\\",\\\"location\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\",\\\"description\\\": [{\\\"content\\\":\\\"\\\"}]}], \\\"education\\\": [{\\\"degree\\\": \\\"\\\",\\\"institution\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\"}] }。字段不存在则返回 null 或空数组。只返回标准可解析的 JSON结构 ,不要多余的```json等信息,不要解释说明,不要改写内容。以下为待处理文本:"+contents); + entity.put("content","从下面提供的文本中提取所有能识别到的简历信息,只提取原文中存在的内容,不要补充、不推测、不总结。需要提取的字段包括:name(姓名或人名)、phone(电话号码)、email(电子邮件地址)、experienceYear(根据工作经验计算出来的工作年限)、position(岗位或者简历中自己期望的职位等)、location(地点或者地址、家庭住址)、links(所有链接地址)、currentWork(当前工作公司)、about(关于我/自我介绍)、skills_tools(关键资格(许可证、注册/会员资格、认证))、languages(语言能力,主要就是Languages下面的语言)、experience(工作经历,除了title、company、location、durationStart、durationEnd,其他的都放到description里面,并且description里面要根据换行符分成不同的content),日期要拆分成开始时间(durationStart)和结束时间(durationEnd))、education(教育经历,日期要拆分成开始时间(durationStart)和结束时间(durationEnd))。请将提取结果以结构化 JSON 格式返回,格式如下:{ \\\"name\\\": \\\"\\\", \\\"phone\\\": \\\"\\\", \\\"currentWork\\\": \\\"\\\", \\\"position\\\": \\\"\\\", \\\"location\\\": \\\"\\\", \\\"email\\\": \\\"\\\", \\\"experienceYear\\\": \\\"\\\", \\\"links\\\": [{\\\"content\\\":\\\"\\\"}], \\\"about\\\": \\\"\\\", \\\"skillsTools\\\": [{\\\"content\\\":\\\"\\\"}], \\\"languages\\\": [{\\\"content\\\":\\\"\\\"}], \\\"experience\\\": [{\\\"title\\\": \\\"\\\", \\\"company\\\": \\\"\\\",\\\"location\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\",\\\"description\\\": [{\\\"content\\\":\\\"\\\"}]}], \\\"education\\\": [{\\\"degree\\\": \\\"\\\",\\\"institution\\\": \\\"\\\",\\\"durationStart\\\": \\\"\\\",\\\"durationEnd\\\": \\\"\\\"}] }。字段不存在则返回 null 或空数组。只返回标准可解析的 JSON结构 ,不要多余的```json等信息,不要解释说明,不要改写内容。以下为待处理文本:"+contents); //根据AI做 list.add(entity); String resultCv = chatGPTClient.handleAiChat(JSONUtil.toJsonStr(list), "JX"); @@ -261,6 +297,9 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi if(StrUtil.isEmpty(cvInfoDto.getLocation())){ cvInfoDto.setLocation("-"); } + if (StrUtil.isEmpty(cvInfoDto.getExperienceYear())){ + cvInfoDto.setExperienceYear("-"); + } if(StrUtil.isEmpty(cvInfoDto.getAbout())){ cvInfoDto.setAbout("-"); } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java index 0154a58..df4c316 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java @@ -1,13 +1,22 @@ package com.vetti.hotake.service.impl; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.vetti.common.core.service.BaseServiceImpl; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.utils.DateUtils; import com.vetti.common.utils.SecurityUtils; +import com.vetti.hotake.domain.HotakeRolesInfo; +import com.vetti.hotake.domain.dto.HotakeCvInfoDto; +import com.vetti.hotake.domain.dto.VcDto.*; +import com.vetti.hotake.mapper.HotakeRolesInfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -29,6 +38,9 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements @Autowired private HotakeRolesApplyInfoMapper hotakeRolesApplyInfoMapper; + @Autowired + private HotakeRolesInfoMapper hotakeRolesInfoMapper; + /** * 查询候选人岗位申请信息 * @@ -52,7 +64,22 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements @Override public List selectHotakeRolesApplyInfoList(HotakeRolesApplyInfo hotakeRolesApplyInfo) { - return hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(hotakeRolesApplyInfo); + List applyInfoList = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(hotakeRolesApplyInfo); + if(CollectionUtil.isEmpty(applyInfoList)) { + //查询岗位数据集合 + HotakeRolesInfo query = new HotakeRolesInfo(); + query.setRecruiterId(SecurityUtils.getUserId()); + List rolesInfoList = hotakeRolesInfoMapper.selectHotakeRolesInfoList(query); + + for(HotakeRolesApplyInfo applyInfo : applyInfoList) { + for(HotakeRolesInfo rolesInfo : rolesInfoList) { + if(rolesInfo.getId().longValue() == applyInfo.getRoleId().longValue()) { + applyInfo.setRolesInfo(rolesInfo); + } + } + } + } + return applyInfoList; } /** @@ -133,4 +160,131 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements public int batchInsertHotakeRolesApplyInfo(List hotakeRolesApplyInfoList){ return hotakeRolesApplyInfoMapper.batchInsertHotakeRolesApplyInfo(hotakeRolesApplyInfoList); } + + + /** + * 简历解析数据 + * + * @param contents + * @return + */ + private HotakeCvInfoDto handleAnalysisCvInfo(String contents) { + try { + HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(contents, HotakeCvInfoDto.class); + //数据添加默认值 + if(cvInfoDto != null){ + if(StrUtil.isEmpty(cvInfoDto.getName())){ + cvInfoDto.setName("-"); + } + if(StrUtil.isEmpty(cvInfoDto.getPhone())){ + cvInfoDto.setPhone("-"); + } + if(StrUtil.isEmpty(cvInfoDto.getEmail())){ + cvInfoDto.setEmail("-"); + } + if(StrUtil.isEmpty(cvInfoDto.getPosition())){ + cvInfoDto.setPosition("-"); + } + if(StrUtil.isEmpty(cvInfoDto.getLocation())){ + cvInfoDto.setLocation("-"); + } + if (StrUtil.isEmpty(cvInfoDto.getExperienceYear())){ + cvInfoDto.setExperienceYear("-"); + } + if(StrUtil.isEmpty(cvInfoDto.getAbout())){ + cvInfoDto.setAbout("-"); + } + if (StrUtil.isEmpty(cvInfoDto.getCurrentWork())){ + cvInfoDto.setCurrentWork("-"); + } + if(CollectionUtil.isNotEmpty(cvInfoDto.getSkillsTools())){ + for (VcSkillsToolsDto toolsDto :cvInfoDto.getSkillsTools()) { + if(StrUtil.isEmpty(toolsDto.getContent())){ + toolsDto.setContent("-"); + } + } + } + if(CollectionUtil.isNotEmpty(cvInfoDto.getLinks())){ + for (VcLinksDto linksDto :cvInfoDto.getLinks()) { + if(StrUtil.isEmpty(linksDto.getContent())){ + linksDto.setContent("-"); + } + } + } + + if(CollectionUtil.isNotEmpty(cvInfoDto.getLanguages())){ + for (VcLanguagesDto languagesDto :cvInfoDto.getLanguages()) { + if(StrUtil.isEmpty(languagesDto.getContent())){ + languagesDto.setContent("-"); + } + } + } + + if(CollectionUtil.isNotEmpty(cvInfoDto.getExperience())){ + for (VcExperienceDto experienceDto :cvInfoDto.getExperience()) { + if (StrUtil.isEmpty(experienceDto.getTitle())){ + experienceDto.setTitle("-"); + } + if(StrUtil.isEmpty(experienceDto.getCompany())){ + experienceDto.setCompany("-"); + } + if(StrUtil.isEmpty(experienceDto.getLocation())){ + experienceDto.setLocation("-"); + } + if(StrUtil.isEmpty(experienceDto.getDurationStart())){ + experienceDto.setDurationStart("-"); + } + if(StrUtil.isEmpty(experienceDto.getDurationEnd())){ + experienceDto.setDurationEnd("-"); + } + if (CollectionUtil.isNotEmpty(experienceDto.getDescription())){ + for(VcExperienceDescriptionDto descriptionDto :experienceDto.getDescription()){ + if(StrUtil.isEmpty(descriptionDto.getContent())){ + descriptionDto.setContent("-"); + } + + } + } + } + } + + if(CollectionUtil.isNotEmpty(cvInfoDto.getEducation())){ + for (VcEducationDto educationDto :cvInfoDto.getEducation()) { + if (StrUtil.isEmpty(educationDto.getDegree())){ + educationDto.setDegree("-"); + } + if(StrUtil.isEmpty(educationDto.getInstitution())){ + educationDto.setInstitution("-"); + } + if(StrUtil.isEmpty(educationDto.getDurationStart())){ + educationDto.setDurationStart("-"); + } + if(StrUtil.isEmpty(educationDto.getDurationEnd())){ + educationDto.setDurationEnd("-"); + } + if(educationDto.getCertificate() != null){ + if(StrUtil.isEmpty(educationDto.getCertificate().getFileName())){ + educationDto.getCertificate().setFileName("-"); + } + if (StrUtil.isEmpty(educationDto.getCertificate().getFileSuffix())){ + educationDto.getCertificate().setFileSuffix("-"); + } + if (StrUtil.isEmpty(educationDto.getCertificate().getFileUrl())){ + educationDto.getCertificate().setFileUrl("-"); + } + if (StrUtil.isEmpty(educationDto.getCertificate().getFileSizeShow())){ + educationDto.getCertificate().setFileSizeShow("-"); + } + } + } + } + } + + return cvInfoDto; + } catch (Exception e) { + e.printStackTrace(); + } + return new HotakeCvInfoDto(); + } + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java index af8e225..2b767aa 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; +import com.vetti.common.core.domain.entity.SysUser; import com.vetti.common.core.service.BaseServiceImpl; import com.vetti.common.enums.FillTypeEnum; import com.vetti.common.enums.RoleOperStepsEnum; @@ -23,6 +24,7 @@ import com.vetti.hotake.mapper.HotakeRolesInfoMapper; import com.vetti.hotake.service.IHotakeAiInterviewQuestionsInfoService; import com.vetti.hotake.service.IHotakeInitialScreeningQuestionsInfoService; import com.vetti.hotake.service.IHotakeRolesInfoService; +import com.vetti.system.mapper.SysUserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -43,6 +45,9 @@ public class HotakeRolesInfoServiceImpl extends BaseServiceImpl implements IHota @Autowired private HotakeRolesInfoMapper hotakeRolesInfoMapper; + @Autowired + private SysUserMapper sysUserMapper; + @Autowired private IHotakeInitialScreeningQuestionsInfoService hotakeInitialScreeningQuestionsInfoService; @@ -121,6 +126,9 @@ public class HotakeRolesInfoServiceImpl extends BaseServiceImpl implements IHota queryAiQuestion.setRoleId(id); List aiInterviewQuestionsInfoList = hotakeAiInterviewQuestionsInfoService.selectHotakeAiInterviewQuestionsInfoList(queryAiQuestion); dto.setAiInterviewQuestionsInfoList(aiInterviewQuestionsInfoList); + + SysUser user = sysUserMapper.selectUserById(hotakeRolesInfo.getRecruiterId()); + dto.setRecruiterUser(user); } return dto; diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml index 21a4fc8..5be6b10 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml @@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -33,13 +34,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, candidate_id, role_id, full_name, email, phone_number, cv_file, cv_file_suffix,file_size_show,cover_letter, candidate_status, stage, last_contact, cv_template_json, cv_score, cv_md5, experience, ai_match_score, ai_match_score_percentage, del_flag, create_by, create_time, update_by, update_time, remark from hotake_roles_apply_info + select id, candidate_id,recruiter_id, role_id, full_name, email, phone_number, cv_file, cv_file_suffix,file_size_show,cover_letter, candidate_status, stage, last_contact, cv_template_json, cv_score, cv_md5, experience, ai_match_score, ai_match_score_percentage, del_flag, create_by, create_time, update_by, update_time, remark from hotake_roles_apply_info