|
|
|
@@ -23,7 +23,8 @@ import java.util.stream.IntStream;
|
|
|
|
|
* <p>依赖:无</p>
|
|
|
|
|
* <p>使用表:bg_user_profile(主表CRUD)、bg_user_profile_education(教育经历)、
|
|
|
|
|
* bg_user_profile_work(工作经历)、bg_user_profile_internship(实习经历)、
|
|
|
|
|
* bg_user_profile_project(项目经历)、bg_user_profile_competition(竞赛经历)</p>
|
|
|
|
|
* bg_user_profile_project(项目经历)、bg_user_profile_competition(竞赛经历)、
|
|
|
|
|
* bg_user_profile_organization(社团组织经历)</p>
|
|
|
|
|
*
|
|
|
|
|
* @author zk
|
|
|
|
|
*/
|
|
|
|
@@ -49,6 +50,9 @@ public class UserProfileService {
|
|
|
|
|
@Autowired
|
|
|
|
|
private UserProfileCompetitionMapper competitionMapper;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private UserProfileOrganizationMapper organizationMapper;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private org.jiayunet.service.UserProfileAnalyzeService userProfileAnalyzeService;
|
|
|
|
|
|
|
|
|
@@ -70,6 +74,9 @@ public class UserProfileService {
|
|
|
|
|
@Autowired
|
|
|
|
|
private UserResumeCompetitionMapper resumeCompetitionMapper;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private UserResumeOrganizationMapper resumeOrganizationMapper;
|
|
|
|
|
|
|
|
|
|
/** 学历文本→枚举映射 */
|
|
|
|
|
private static final Map<String, Integer> DEGREE_MAP = Map.of(
|
|
|
|
|
"大专", 1, "本科", 2, "硕士", 3, "博士", 4
|
|
|
|
@@ -126,6 +133,8 @@ public class UserProfileService {
|
|
|
|
|
.set(UserProfile::getPortfolioUrl, profile.getPortfolioUrl())
|
|
|
|
|
.set(UserProfile::getSkills, profile.getSkills(), JSON_TYPE_HANDLER)
|
|
|
|
|
.set(UserProfile::getCertificates, profile.getCertificates(), JSON_TYPE_HANDLER)
|
|
|
|
|
.set(UserProfile::getHobbies, profile.getHobbies())
|
|
|
|
|
.set(UserProfile::getLanguageSkills, profile.getLanguageSkills())
|
|
|
|
|
.set(UserProfile::getUpdateTime, now));
|
|
|
|
|
} else {
|
|
|
|
|
profile.setUserId(userId);
|
|
|
|
@@ -320,11 +329,48 @@ public class UserProfileService {
|
|
|
|
|
userProfileAnalyzeService.analyzeUserProfile(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==================== 社团组织经历 ====================
|
|
|
|
|
|
|
|
|
|
/** 查询社团组织经历列表 */
|
|
|
|
|
public List<UserProfileOrganization> listOrganization() {
|
|
|
|
|
Long userId = UserSecurityTool.getUserId();
|
|
|
|
|
return organizationMapper.selectList(
|
|
|
|
|
new LambdaQueryWrapper<UserProfileOrganization>()
|
|
|
|
|
.eq(UserProfileOrganization::getUserId, userId)
|
|
|
|
|
.orderByAsc(UserProfileOrganization::getSortOrder));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 保存社团组织经历列表(先删后插)
|
|
|
|
|
* <p>1. 删除该用户所有社团组织经历 2. 批量插入新数据</p>
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public void saveOrganizationList(List<UserProfileOrganization> list) {
|
|
|
|
|
Long userId = UserSecurityTool.getUserId();
|
|
|
|
|
Long profileId = getOrCreateProfileId(userId);
|
|
|
|
|
organizationMapper.delete(
|
|
|
|
|
new LambdaQueryWrapper<UserProfileOrganization>().eq(UserProfileOrganization::getUserId, userId));
|
|
|
|
|
if (list.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Instant now = Instant.now();
|
|
|
|
|
IntStream.range(0, list.size()).forEach(i -> {
|
|
|
|
|
UserProfileOrganization item = list.get(i);
|
|
|
|
|
item.setUserId(userId);
|
|
|
|
|
item.setProfileId(profileId);
|
|
|
|
|
item.setSortOrder(i);
|
|
|
|
|
item.setCreateTime(now);
|
|
|
|
|
item.setUpdateTime(now);
|
|
|
|
|
});
|
|
|
|
|
organizationMapper.batchInsert(list);
|
|
|
|
|
userProfileAnalyzeService.analyzeUserProfile(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==================== 从简历同步到个人资料 ====================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据简历ID同步更新个人资料
|
|
|
|
|
* <p>1. 校验简历归属 2. 读取简历主表+5子表 3. 事务内覆盖写入Profile主表+5子表 4. 同步执行一次AI分析</p>
|
|
|
|
|
* <p>1. 校验简历归属 2. 读取简历主表+6子表 3. 事务内覆盖写入Profile主表+6子表 4. 同步执行一次AI分析</p>
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public void syncProfileFromResume(Long resumeId) {
|
|
|
|
@@ -336,12 +382,13 @@ public class UserProfileService {
|
|
|
|
|
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "简历不存在或无权操作");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 读取简历5张子表
|
|
|
|
|
// 2. 读取简历6张子表
|
|
|
|
|
List<UserResumeEducation> resumeEducationList = resumeEducationMapper.selectList(new LambdaQueryWrapper<UserResumeEducation>().eq(UserResumeEducation::getResumeId, resumeId).orderByAsc(UserResumeEducation::getSortOrder));
|
|
|
|
|
List<UserResumeWork> resumeWorkList = resumeWorkMapper.selectList(new LambdaQueryWrapper<UserResumeWork>().eq(UserResumeWork::getResumeId, resumeId).orderByAsc(UserResumeWork::getSortOrder));
|
|
|
|
|
List<UserResumeInternship> resumeInternshipList = resumeInternshipMapper.selectList(new LambdaQueryWrapper<UserResumeInternship>().eq(UserResumeInternship::getResumeId, resumeId).orderByAsc(UserResumeInternship::getSortOrder));
|
|
|
|
|
List<UserResumeProject> resumeProjectList = resumeProjectMapper.selectList(new LambdaQueryWrapper<UserResumeProject>().eq(UserResumeProject::getResumeId, resumeId).orderByAsc(UserResumeProject::getSortOrder));
|
|
|
|
|
List<UserResumeCompetition> resumeCompetitionList = resumeCompetitionMapper.selectList(new LambdaQueryWrapper<UserResumeCompetition>().eq(UserResumeCompetition::getResumeId, resumeId).orderByAsc(UserResumeCompetition::getSortOrder));
|
|
|
|
|
List<UserResumeOrganization> resumeOrganizationList = resumeOrganizationMapper.selectList(new LambdaQueryWrapper<UserResumeOrganization>().eq(UserResumeOrganization::getResumeId, resumeId).orderByAsc(UserResumeOrganization::getSortOrder));
|
|
|
|
|
|
|
|
|
|
Instant now = Instant.now();
|
|
|
|
|
|
|
|
|
@@ -362,6 +409,8 @@ public class UserProfileService {
|
|
|
|
|
.set(UserProfile::getPortfolioUrl, resume.getPortfolioUrl())
|
|
|
|
|
.set(UserProfile::getSkills, resume.getSkills(), JSON_TYPE_HANDLER)
|
|
|
|
|
.set(UserProfile::getCertificates, resume.getCertificates(), JSON_TYPE_HANDLER)
|
|
|
|
|
.set(UserProfile::getHobbies, resume.getHobbies())
|
|
|
|
|
.set(UserProfile::getLanguageSkills, resume.getLanguageSkills())
|
|
|
|
|
.set(UserProfile::getUpdateTime, now));
|
|
|
|
|
} else {
|
|
|
|
|
UserProfile profile = new UserProfile();
|
|
|
|
@@ -373,6 +422,8 @@ public class UserProfileService {
|
|
|
|
|
profile.setPortfolioUrl(resume.getPortfolioUrl());
|
|
|
|
|
profile.setSkills(resume.getSkills());
|
|
|
|
|
profile.setCertificates(resume.getCertificates());
|
|
|
|
|
profile.setHobbies(resume.getHobbies());
|
|
|
|
|
profile.setLanguageSkills(resume.getLanguageSkills());
|
|
|
|
|
profile.setCreateTime(now);
|
|
|
|
|
profile.setUpdateTime(now);
|
|
|
|
|
userProfileMapper.insert(profile);
|
|
|
|
@@ -486,7 +537,28 @@ public class UserProfileService {
|
|
|
|
|
competitionMapper.batchInsert(profileCompetitionList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 9. 事务内所有数据写入完成,同步执行AI分析并等待完成
|
|
|
|
|
// 9. 同步社团组织经历
|
|
|
|
|
organizationMapper.delete(new LambdaQueryWrapper<UserProfileOrganization>().eq(UserProfileOrganization::getUserId, userId));
|
|
|
|
|
if (!resumeOrganizationList.isEmpty()) {
|
|
|
|
|
List<UserProfileOrganization> profileOrganizationList = IntStream.range(0, resumeOrganizationList.size()).mapToObj(i -> {
|
|
|
|
|
UserResumeOrganization src = resumeOrganizationList.get(i);
|
|
|
|
|
UserProfileOrganization dest = new UserProfileOrganization();
|
|
|
|
|
dest.setProfileId(profileId);
|
|
|
|
|
dest.setUserId(userId);
|
|
|
|
|
dest.setOrganizationName(src.getOrganizationName());
|
|
|
|
|
dest.setRole(src.getRole());
|
|
|
|
|
dest.setStartDate(src.getStartDate());
|
|
|
|
|
dest.setEndDate(src.getEndDate());
|
|
|
|
|
dest.setDescription(src.getDescription());
|
|
|
|
|
dest.setSortOrder(i);
|
|
|
|
|
dest.setCreateTime(now);
|
|
|
|
|
dest.setUpdateTime(now);
|
|
|
|
|
return dest;
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
organizationMapper.batchInsert(profileOrganizationList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 10. 事务内所有数据写入完成,同步执行AI分析并等待完成
|
|
|
|
|
userProfileAnalyzeService.analyzeUserProfileSync(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -494,9 +566,9 @@ public class UserProfileService {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据当前用户的个人资料创建一份新简历
|
|
|
|
|
* <p>syncProfileFromResume 的反向操作:读取个人资料主表+5子表,新建一份简历(名"个人资料简历")及对应子表,返回新简历ID</p>
|
|
|
|
|
* <p>1. 校验个人资料存在 2. 读取个人资料5子表 3. 新建简历主表(复制共有字段,简历独有字段targetPosition/avatarUrl/city/summary留空)
|
|
|
|
|
* 4. 转换并批量插入5张简历子表(含degree/studyType反向映射) 5. 返回新简历ID</p>
|
|
|
|
|
* <p>syncProfileFromResume 的反向操作:读取个人资料主表+6子表,新建一份简历(名"个人资料简历")及对应子表,返回新简历ID</p>
|
|
|
|
|
* <p>1. 校验个人资料存在 2. 读取个人资料6子表 3. 新建简历主表(复制共有字段,简历独有字段targetPosition/avatarUrl/city/summary留空)
|
|
|
|
|
* 4. 转换并批量插入6张简历子表(含degree/studyType反向映射) 5. 返回新简历ID</p>
|
|
|
|
|
* <p>注意:这是创建新简历(非覆盖),不删除已有简历;简历侧无AI分析,故不触发分析</p>
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
@@ -511,12 +583,13 @@ public class UserProfileService {
|
|
|
|
|
}
|
|
|
|
|
Long profileId = profile.getId();
|
|
|
|
|
|
|
|
|
|
// 2. 读取个人资料5张子表
|
|
|
|
|
// 2. 读取个人资料6张子表
|
|
|
|
|
List<UserProfileEducation> profileEducationList = educationMapper.selectList(new LambdaQueryWrapper<UserProfileEducation>().eq(UserProfileEducation::getProfileId, profileId).orderByAsc(UserProfileEducation::getSortOrder));
|
|
|
|
|
List<UserProfileWork> profileWorkList = workMapper.selectList(new LambdaQueryWrapper<UserProfileWork>().eq(UserProfileWork::getProfileId, profileId).orderByAsc(UserProfileWork::getSortOrder));
|
|
|
|
|
List<UserProfileInternship> profileInternshipList = internshipMapper.selectList(new LambdaQueryWrapper<UserProfileInternship>().eq(UserProfileInternship::getProfileId, profileId).orderByAsc(UserProfileInternship::getSortOrder));
|
|
|
|
|
List<UserProfileProject> profileProjectList = projectMapper.selectList(new LambdaQueryWrapper<UserProfileProject>().eq(UserProfileProject::getProfileId, profileId).orderByAsc(UserProfileProject::getSortOrder));
|
|
|
|
|
List<UserProfileCompetition> profileCompetitionList = competitionMapper.selectList(new LambdaQueryWrapper<UserProfileCompetition>().eq(UserProfileCompetition::getProfileId, profileId).orderByAsc(UserProfileCompetition::getSortOrder));
|
|
|
|
|
List<UserProfileOrganization> profileOrganizationList = organizationMapper.selectList(new LambdaQueryWrapper<UserProfileOrganization>().eq(UserProfileOrganization::getProfileId, profileId).orderByAsc(UserProfileOrganization::getSortOrder));
|
|
|
|
|
|
|
|
|
|
Instant now = Instant.now();
|
|
|
|
|
|
|
|
|
@@ -531,6 +604,8 @@ public class UserProfileService {
|
|
|
|
|
resume.setPortfolioUrl(profile.getPortfolioUrl());
|
|
|
|
|
resume.setSkills(profile.getSkills());
|
|
|
|
|
resume.setCertificates(profile.getCertificates());
|
|
|
|
|
resume.setHobbies(profile.getHobbies());
|
|
|
|
|
resume.setLanguageSkills(profile.getLanguageSkills());
|
|
|
|
|
// 无简历时新建的这份自动设为默认,与 UserResumeService.saveResume 逻辑一致
|
|
|
|
|
boolean hasResume = userResumeMapper.selectCount(new LambdaQueryWrapper<UserResume>().eq(UserResume::getUserId, userId)) > 0;
|
|
|
|
|
resume.setIsDefault(hasResume ? 0 : 1);
|
|
|
|
@@ -642,7 +717,27 @@ public class UserProfileService {
|
|
|
|
|
resumeCompetitionMapper.batchInsert(resumeCompetitionList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 9. 返回新简历ID
|
|
|
|
|
// 9. 转换并插入简历社团组织经历
|
|
|
|
|
if (!profileOrganizationList.isEmpty()) {
|
|
|
|
|
List<UserResumeOrganization> resumeOrganizationList = IntStream.range(0, profileOrganizationList.size()).mapToObj(i -> {
|
|
|
|
|
UserProfileOrganization src = profileOrganizationList.get(i);
|
|
|
|
|
UserResumeOrganization dest = new UserResumeOrganization();
|
|
|
|
|
dest.setResumeId(resumeId);
|
|
|
|
|
dest.setUserId(userId);
|
|
|
|
|
dest.setOrganizationName(src.getOrganizationName());
|
|
|
|
|
dest.setRole(src.getRole());
|
|
|
|
|
dest.setStartDate(src.getStartDate());
|
|
|
|
|
dest.setEndDate(src.getEndDate());
|
|
|
|
|
dest.setDescription(src.getDescription());
|
|
|
|
|
dest.setSortOrder(i);
|
|
|
|
|
dest.setCreateTime(now);
|
|
|
|
|
dest.setUpdateTime(now);
|
|
|
|
|
return dest;
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
resumeOrganizationMapper.batchInsert(resumeOrganizationList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 10. 返回新简历ID
|
|
|
|
|
return resumeId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|