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;
+}