diff --git a/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java b/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java index 1a27915..82a0680 100644 --- a/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java +++ b/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java @@ -14,7 +14,7 @@ import java.util.stream.Collectors; /** * 用户简历接口 - *

提供简历列表、主表及5张子表(教育/工作/实习/项目/竞赛)的查询与保存、简历删除功能

+ *

提供简历列表、主表及6张子表(教育/工作/实习/项目/竞赛/社团组织)的查询与保存、简历删除功能

*

所有保存接口支持自动创建:前端不传resumeId时自动创建新简历并返回resumeId

* * @author zk @@ -306,4 +306,49 @@ public class UserResumeController { }).collect(Collectors.toList()); return userResumeService.saveCompetitionList(list, param.getResumeId()); } + + // ==================== 社团组织经历 ==================== + + /** 查询简历的社团组织经历列表 */ + @GetMapping("/organization") + public List listOrganization(@RequestParam Long resumeId) { + return userResumeService.listOrganization(resumeId).stream().map(po -> { + ResumeOrganizationDto dto = new ResumeOrganizationDto(); + BeanUtils.copyProperties(po, dto); + return dto; + }).collect(Collectors.toList()); + } + + /** 添加单条社团组织经历,返回新记录id */ + @PostMapping("/organization/add") + public Long addOrganization(@RequestParam Long resumeId, @Validated @RequestBody ResumeOrganizationParam param) { + UserResumeOrganization po = new UserResumeOrganization(); + BeanUtils.copyProperties(param, po); + return userResumeService.addOrganization(po, resumeId); + } + + /** 根据id编辑单条社团组织经历 */ + @PostMapping("/organization/update") + public void updateOrganization(@Validated @RequestBody ResumeOrganizationUpdateParam param) { + UserResumeOrganization po = new UserResumeOrganization(); + BeanUtils.copyProperties(param, po); + userResumeService.updateOrganization(po); + } + + /** 根据id删除单条社团组织经历 */ + @PostMapping("/organization/delete") + public void deleteOrganization(@RequestParam Long id) { + userResumeService.deleteOrganization(id); + } + + /** 保存简历的社团组织经历列表(先删后插),返回resumeId */ + @PostMapping("/organization") + public Long saveOrganization(@Validated @RequestBody ResumeSubTableParam param) { + List list = param.getItems().stream().map(p -> { + UserResumeOrganization po = new UserResumeOrganization(); + BeanUtils.copyProperties(p, po); + return po; + }).collect(Collectors.toList()); + return userResumeService.saveOrganizationList(list, param.getResumeId()); + } } diff --git a/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeDto.java b/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeDto.java index 24a6eb6..79193f4 100644 --- a/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeDto.java +++ b/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeDto.java @@ -52,4 +52,10 @@ public class ResumeDto { /** 个人概述 */ private String summary; + + /** 兴趣爱好 */ + private String hobbies; + + /** 语言能力 */ + private String languageSkills; } diff --git a/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeOrganizationDto.java b/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeOrganizationDto.java new file mode 100644 index 0000000..8426d3d --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/dto/resume/ResumeOrganizationDto.java @@ -0,0 +1,32 @@ +package org.jiayunet.pojo.dto.resume; + +import lombok.Data; +import org.jiayunet.pojo.vo.DescriptionParagraph; + +import java.util.List; + +/** + * 简历-社团组织经历返回 + * + * @author zk + */ +@Data +public class ResumeOrganizationDto { + + private Long id; + + /** 社团/组织名称 */ + private String organizationName; + + /** 担任角色 */ + private String role; + + /** 开始时间 */ + private String startDate; + + /** 结束时间 */ + private String endDate; + + /** 描述段落 */ + private List description; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationParam.java new file mode 100644 index 0000000..5059da0 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationParam.java @@ -0,0 +1,35 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import org.jiayunet.pojo.vo.DescriptionParagraph; + +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 简历-社团组织经历保存入参 + * + * @author zk + */ +@Data +public class ResumeOrganizationParam { + + /** 社团/组织名称 */ + @Size(max = 200, message = "社团/组织名称长度不能超过200") + private String organizationName; + + /** 担任角色 */ + @Size(max = 100, message = "担任角色长度不能超过100") + private String role; + + /** 开始时间,格式:2023.06 */ + @Size(max = 10, message = "开始时间长度不能超过10") + private String startDate; + + /** 结束时间,格式:2023.09,至今则为空 */ + @Size(max = 10, message = "结束时间长度不能超过10") + private String endDate; + + /** 描述段落 */ + private List description; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationUpdateParam.java new file mode 100644 index 0000000..1b1fcb1 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeOrganizationUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-社团组织经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeOrganizationUpdateParam extends ResumeOrganizationParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeParam.java index 8232cd3..aa36d8a 100644 --- a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeParam.java +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeParam.java @@ -60,4 +60,12 @@ public class ResumeParam { /** 个人概述 */ private String summary; + + /** 兴趣爱好 */ + @Size(max = 2000, message = "兴趣爱好长度不能超过2000") + private String hobbies; + + /** 语言能力 */ + @Size(max = 2000, message = "语言能力长度不能超过2000") + private String languageSkills; } diff --git a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java index 0bf4cec..4f31d6c 100644 --- a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java +++ b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java @@ -23,7 +23,8 @@ import java.util.stream.IntStream; *

依赖:无

*

使用表:bg_user_resume(简历主表CRUD)、bg_user_resume_education(教育经历)、 * bg_user_resume_work(工作经历)、bg_user_resume_internship(实习经历)、 - * bg_user_resume_project(项目经历)、bg_user_resume_competition(竞赛经历)

+ * bg_user_resume_project(项目经历)、bg_user_resume_competition(竞赛经历)、 + * bg_user_resume_organization(社团组织经历)

* * @author zk */ @@ -58,6 +59,9 @@ public class UserResumeService { @Autowired private UserResumeCompetitionMapper competitionMapper; + @Autowired + private UserResumeOrganizationMapper organizationMapper; + // ==================== 简历列表 ==================== /** @@ -135,6 +139,8 @@ public class UserResumeService { .set(UserResume::getSkills, resume.getSkills(), JSON_TYPE_HANDLER) .set(UserResume::getCertificates, resume.getCertificates(), JSON_TYPE_HANDLER) .set(UserResume::getSummary, resume.getSummary()) + .set(UserResume::getHobbies, resume.getHobbies()) + .set(UserResume::getLanguageSkills, resume.getLanguageSkills()) .set(UserResume::getUpdateTime, now)); return resumeId; } @@ -156,7 +162,7 @@ public class UserResumeService { /** * 删除简历(物理删除主表 + 全部子表) - *

1. 校验归属 2. 删除5张子表 3. 删除主表

+ *

1. 校验归属 2. 删除6张子表 3. 删除主表

*/ @Transactional(rollbackFor = Exception.class) public void deleteResume(Long resumeId) { @@ -168,6 +174,7 @@ public class UserResumeService { internshipMapper.delete(new LambdaQueryWrapper().eq(UserResumeInternship::getResumeId, resumeId)); projectMapper.delete(new LambdaQueryWrapper().eq(UserResumeProject::getResumeId, resumeId)); competitionMapper.delete(new LambdaQueryWrapper().eq(UserResumeCompetition::getResumeId, resumeId)); + organizationMapper.delete(new LambdaQueryWrapper().eq(UserResumeOrganization::getResumeId, resumeId)); // 删除主表 userResumeMapper.deleteById(resumeId); } @@ -342,6 +349,40 @@ public class UserResumeService { return resumeId; } + // ==================== 社团组织经历 ==================== + + /** 查询简历的社团组织经历列表 */ + public List listOrganization(Long resumeId) { + checkResumeOwnership(resumeId); + return organizationMapper.selectList(new LambdaQueryWrapper().eq(UserResumeOrganization::getResumeId, resumeId).orderByAsc(UserResumeOrganization::getSortOrder)); + } + + /** + * 保存简历的社团组织经历列表(先删后插) + *

1. resumeId为空则自动创建新简历 2. 按resumeId删除旧数据 3. 批量插入 4. 更新主表修改时间

+ */ + @Transactional(rollbackFor = Exception.class) + public Long saveOrganizationList(List list, Long resumeId) { + Long userId = UserSecurityTool.getUserId(); + resumeId = getOrCreateResumeId(resumeId, userId); + organizationMapper.delete(new LambdaQueryWrapper().eq(UserResumeOrganization::getResumeId, resumeId)); + if (!list.isEmpty()) { + Instant now = Instant.now(); + Long finalResumeId = resumeId; + IntStream.range(0, list.size()).forEach(i -> { + UserResumeOrganization item = list.get(i); + item.setUserId(userId); + item.setResumeId(finalResumeId); + item.setSortOrder(i); + item.setCreateTime(now); + item.setUpdateTime(now); + }); + organizationMapper.batchInsert(list); + } + touchResumeUpdateTime(resumeId); + return resumeId; + } + // ==================== 子表单条添加 ==================== /** @@ -439,6 +480,25 @@ public class UserResumeService { return po.getId(); } + /** + * 添加单条社团组织经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addOrganization(UserResumeOrganization po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + organizationMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + // ==================== 子表单条删除 ==================== /** @@ -506,6 +566,19 @@ public class UserResumeService { touchResumeUpdateTime(existing.getResumeId()); } + /** + * 根据id删除社团组织经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteOrganization(Long id) { + UserResumeOrganization existing = organizationMapper.selectById(id); + Assert.notNull(existing, "社团组织经历不存在"); + checkResumeOwnership(existing.getResumeId()); + organizationMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + // ==================== 子表单条编辑 ==================== /** @@ -615,6 +688,27 @@ public class UserResumeService { touchResumeUpdateTime(existing.getResumeId()); } + /** + * 根据id编辑社团组织经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateOrganization(UserResumeOrganization po) { + UserResumeOrganization existing = organizationMapper.selectById(po.getId()); + Assert.notNull(existing, "社团组织经历不存在"); + checkResumeOwnership(existing.getResumeId()); + // 显式set用户可编辑字段(允许清空为null);resumeId/userId/sortOrder/createTime保留原值 + organizationMapper.update(null, new LambdaUpdateWrapper() + .eq(UserResumeOrganization::getId, po.getId()) + .set(UserResumeOrganization::getOrganizationName, po.getOrganizationName()) + .set(UserResumeOrganization::getRole, po.getRole()) + .set(UserResumeOrganization::getStartDate, po.getStartDate()) + .set(UserResumeOrganization::getEndDate, po.getEndDate()) + .set(UserResumeOrganization::getDescription, po.getDescription(), JSON_TYPE_HANDLER) + .set(UserResumeOrganization::getUpdateTime, Instant.now())); + touchResumeUpdateTime(existing.getResumeId()); + } + // ==================== 内部方法 ==================== /** diff --git a/manager/src/main/java/org/jiayunet/mapper/UserResumeOrganizationMapper.java b/manager/src/main/java/org/jiayunet/mapper/UserResumeOrganizationMapper.java new file mode 100644 index 0000000..7afa44c --- /dev/null +++ b/manager/src/main/java/org/jiayunet/mapper/UserResumeOrganizationMapper.java @@ -0,0 +1,13 @@ +package org.jiayunet.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.jiayunet.pojo.po.UserResumeOrganization; + +/** + * 简历-社团组织经历Mapper + * + * @author zk + */ +@Mapper +public interface UserResumeOrganizationMapper extends CommonMapper { +} diff --git a/manager/src/main/java/org/jiayunet/pojo/po/UserResume.java b/manager/src/main/java/org/jiayunet/pojo/po/UserResume.java index 9eda186..86ddeef 100644 --- a/manager/src/main/java/org/jiayunet/pojo/po/UserResume.java +++ b/manager/src/main/java/org/jiayunet/pojo/po/UserResume.java @@ -74,6 +74,12 @@ public class UserResume { /** 个人概述 */ private String summary; + /** 兴趣爱好 */ + private String hobbies; + + /** 语言能力 */ + private String languageSkills; + /** 简历创建时间 */ private Instant createTime; diff --git a/manager/src/main/java/org/jiayunet/pojo/po/UserResumeOrganization.java b/manager/src/main/java/org/jiayunet/pojo/po/UserResumeOrganization.java new file mode 100644 index 0000000..d2d5266 --- /dev/null +++ b/manager/src/main/java/org/jiayunet/pojo/po/UserResumeOrganization.java @@ -0,0 +1,56 @@ +package org.jiayunet.pojo.po; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import org.jiayunet.pojo.vo.DescriptionParagraph; + +import java.time.Instant; +import java.util.List; + +/** + * 简历-社团组织经历表(bg_user_resume_organization) + * + * @author zk + */ +@Data +@TableName(value = "bg_user_resume_organization", autoResultMap = true) +public class UserResumeOrganization { + + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + /** 关联bg_user_resume.id */ + private Long resumeId; + + /** 用户ID(冗余,便于直接按用户查询) */ + private Long userId; + + /** 社团/组织名称 */ + private String organizationName; + + /** 担任角色 */ + private String role; + + /** 开始时间,格式:2023.06 */ + private String startDate; + + /** 结束时间,格式:2023.09,至今则为空 */ + private String endDate; + + /** 描述段落,id为前端生成的短标识,用于简历优化时精确定位段落 */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List description; + + /** 排序序号,越小越靠前 */ + private Integer sortOrder; + + /** 创建时间 */ + private Instant createTime; + + /** 更新时间 */ + private Instant updateTime; +}