1.修改任务跟踪看板逻辑与显示 。 2.入职管理页面新增入职周知字段的上传和下载

This commit is contained in:
lw 2024-07-08 15:06:11 +08:00
parent daa40c1e96
commit 3ccfd29d01
14 changed files with 288 additions and 36 deletions

View File

@ -5,14 +5,14 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
# master:
# url: jdbc:mysql://192.168.1.165:3306/zeoa?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: zeoa
# password: dHahLWNYB7tD2Mia
master:
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: zero
url: jdbc:mysql://192.168.1.165:3306/zeoa?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: zeoa
password: dHahLWNYB7tD2Mia
# master:
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: zero
# 从库数据源
slave:
# 从数据源开关/默认关闭

View File

@ -7,8 +7,8 @@ ruoyi:
# 版权年份
copyrightYear: 2024
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/zeroerr/uploadPath
#profile: /home/zeroerr_oa/uploadPath
#profile: D:/zeroerr/uploadPath
profile: /home/zeroerr_oa/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
@ -69,15 +69,15 @@ spring:
# redis 配置
redis:
# 地址
#host: 192.168.1.189
host: localhost
host: 192.168.1.189
#host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
#password: 123456
password:
password: 123456
#password:
# 连接超时时间
timeout: 10s
lettuce:

View File

@ -8,6 +8,8 @@ import cn.zeroerr.common.core.domain.entity.SysDept;
import cn.zeroerr.common.core.domain.entity.SysUser;
import cn.zeroerr.common.core.page.TableDataInfo;
import cn.zeroerr.common.enums.BusinessType;
import cn.zeroerr.common.utils.poi.ExcelUtil;
import cn.zeroerr.domain.dto.EntryManagerDTO;
import cn.zeroerr.domain.dto.FollowDTO;
import cn.zeroerr.domain.entity.*;
import cn.zeroerr.domain.vo.FollowVO;
@ -26,9 +28,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@ -57,6 +62,9 @@ public class RecruitFollowController extends BaseController {
@Autowired
private ResumeFollowRecordService resumeFollowRecordService;
@Autowired
private PostGradeService postGradeService;
// @PreAuthorize("@ss.hasPermi('recruit:follow:add')")
// @Log(title = "新增招聘计划与统计", businessType = BusinessType.INSERT)
@ -151,7 +159,16 @@ public class RecruitFollowController extends BaseController {
@ApiOperation(value = "查询招聘计划与统计列表")
public AjaxResult list(FollowDTO req) {
List<FollowVO> followVOList = new ArrayList<>();
String month = req.getMonth();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
// 解析字符串为YearMonth对象
YearMonth yearMonth = YearMonth.parse(month, formatter);
// 获取月份的第一天
LocalDate startDate = yearMonth.atDay(1);
// 获取月份的最后一天
LocalDate endDate =LocalDate.now();
req.setStartDate(startDate);
req.setEndDate(endDate);
// 获取符合条件的简历处理记录并按岗位ID分组
Map<Long, List<ResumeHandleRecord>> mapResumeHandleRecord = resumeHandleRecordService.listBySelect(req)
.stream().collect(Collectors.groupingBy(ResumeHandleRecord::getPostId));
@ -182,10 +199,51 @@ public class RecruitFollowController extends BaseController {
}
// 获取符合条件的面试跟踪记录并按岗位ID分组
handleFollowRecords(req, followVOList);
handleFollowRecords(req, followVOList,startDate,endDate);
// 遍历followVOList将所有字段除了deptName为null的字段设置为0
followVOList.forEach(followVO -> {
//获取该月份筛选岗位等级的岗位信息
List<PostGrade> postGradeList=postGradeService.listByMonth(req.getMonth(),req.getGrade(),req.getHrName(),req.getPostName());
// 获取所有的 postId 列表
List<Long> postGradeIds = postGradeList.stream()
.map(PostGrade::getPostId)
.collect(Collectors.toList());
// 获取 followVOList 中的所有 postId 列表
Set<Long> followVOIds = followVOList.stream()
.map(FollowVO::getPostId)
.collect(Collectors.toSet());
// 找出 postGradeIds 中不包含在 followVOIds 的所有 postId
List<Long> missingPostIds = postGradeIds.stream()
.filter(postId -> !followVOIds.contains(postId))
.collect(Collectors.toList());
// 过滤 followVOList 中的 postId 不在 postGradeIds 里的数据
List<FollowVO> filteredFollowVOList = followVOList.stream()
.filter(followVO -> postGradeIds.contains(followVO.getPostId()))
.collect(Collectors.toList());
missingPostIds.forEach(
missingPostId->{
Optional<PostGrade> optionalPostGrade = postGradeList.stream()
.filter(postGrade -> postGrade.getPostId() == missingPostId)
.findFirst();
PostGrade postGrade = optionalPostGrade.get();
FollowVO followVO = new FollowVO();
followVO.setPostName(postGrade.getPostName());
followVO.setPostId(postGrade.getPostId());
followVO.setHrName(postGrade.getHrName());
followVO.setDeptName(postGrade.getDeptName());
RecruitStructure byNodeId = recruitStructureService.getByNodeId(missingPostId);
if(byNodeId.getTaskId()!=null){
RecruitProcessTask byTaskId = recruitProcessTaskService.getByTaskId(byNodeId.getTaskId());
followVO.setPostCount(byTaskId.getPostCount());
}
filteredFollowVOList.add(followVO);
}
);
// filteredFollowVOList将所有字段除了deptName为null的字段设置为0
filteredFollowVOList.forEach(followVO -> {
if (followVO.getPostId() == null) followVO.setPostId(0L);
if (followVO.getPostName() == null) followVO.setPostName("");
if (followVO.getDeptId() == null) followVO.setDeptId(0L);
@ -203,6 +261,13 @@ public class RecruitFollowController extends BaseController {
if (followVO.getOfferCount() == null) followVO.setOfferCount(0L);
if (followVO.getEntryCount() == null) followVO.setEntryCount(0L);
Optional<PostGrade> optionalPostGrade = postGradeList.stream()
.filter(postGrade -> Objects.equals(postGrade.getPostId(), followVO.getPostId()))
.findFirst();
if(optionalPostGrade.isPresent()){
followVO.setGrade(optionalPostGrade.get().getGrade());
}
//封装到面率(一面人数/接受邀约人数)
if(followVO.getInviteInterviewCount()!=null&&followVO.getInviteInterviewCount()!=0){
BigDecimal arrivePercentage = new BigDecimal(followVO.getFirstInterviewCount()).divide(new BigDecimal(followVO.getInviteInterviewCount()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
@ -219,25 +284,19 @@ public class RecruitFollowController extends BaseController {
}
});
Collections.sort(followVOList, new Comparator<FollowVO>() {
@Override
public int compare(FollowVO o1, FollowVO o2) {
return Long.compare(o1.getHrId(), o2.getHrId());
}
});
filteredFollowVOList.sort(Comparator.comparing(followVO -> Integer.parseInt(followVO.getGrade())));
return AjaxResult.success(followVOList);
return AjaxResult.success(filteredFollowVOList);
}
private String handleDeptName(Long postId) {
return recruitStructureService.findTopLevelDepartmentNameByNodeId(postId);
}
private void handleFollowRecords(FollowDTO req, List<FollowVO> followVOList) {
private void handleFollowRecords(FollowDTO req, List<FollowVO> followVOList,LocalDate startDate,LocalDate endDate) {
String hrName = req.getHrName();
LocalDate startDate = req.getStartDate();
LocalDate endDate = req.getEndDate();
// 定义所有需要处理的状态及其对应的Map
Map<Integer, Map<Long, List<ResumeFollowRecord>>> statusMaps = new HashMap<>();
@ -305,4 +364,143 @@ public class RecruitFollowController extends BaseController {
@PostMapping("/export")
@PreAuthorize("@ss.hasAnyPermi('recruit:follow:export')")
@ApiOperation(value = "下载招聘计划与统计列表")
@Log(title = "下载招聘计划与统计列表", businessType = BusinessType.EXPORT)
public void export(HttpServletResponse response, FollowDTO req) {
List<FollowVO> followVOList = new ArrayList<>();
String month = req.getMonth();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
// 解析字符串为YearMonth对象
YearMonth yearMonth = YearMonth.parse(month, formatter);
// 获取月份的第一天
LocalDate startDate = yearMonth.atDay(1);
// 获取月份的最后一天
LocalDate endDate =LocalDate.now();
req.setStartDate(startDate);
req.setEndDate(endDate);
// 获取符合条件的简历处理记录并按岗位ID分组
Map<Long, List<ResumeHandleRecord>> mapResumeHandleRecord = resumeHandleRecordService.listBySelect(req)
.stream().collect(Collectors.groupingBy(ResumeHandleRecord::getPostId));
if (!mapResumeHandleRecord.isEmpty()) {
mapResumeHandleRecord.forEach((postId, listByPostId) -> {
if (!listByPostId.isEmpty()) {
ResumeHandleRecord firstRecord = listByPostId.get(0);
FollowVO followVO = new FollowVO();
followVO.setPostId(firstRecord.getPostId());
followVO.setPostName(firstRecord.getPostName());
followVO.setDeptId(firstRecord.getDeptId());
followVO.setDeptName(firstRecord.getDeptName());
followVO.setHrId(firstRecord.getOperatorId());
followVO.setHrName(firstRecord.getOperatorName());
RecruitStructure postNodeId = recruitStructureService.getByNodeId(followVO.getPostId());
followVO.setPostCount(postNodeId != null && postNodeId.getTaskId() != null
? recruitProcessTaskService.getByTaskId(postNodeId.getTaskId()).getPostCount()
: 0);
followVO.setLookResumeCount(listByPostId.stream().mapToInt(ResumeHandleRecord::getGreetNum).sum());
followVO.setInviteInterviewCount(listByPostId.stream().mapToInt(ResumeHandleRecord::getReceiveInviteNum).sum());
followVOList.add(followVO);
}
});
}
// 获取符合条件的面试跟踪记录并按岗位ID分组
handleFollowRecords(req, followVOList,startDate,endDate);
//获取该月份筛选岗位等级的岗位信息
List<PostGrade> postGradeList=postGradeService.listByMonth(req.getMonth(),req.getGrade(),req.getHrName(),req.getPostName());
// 获取所有的 postId 列表
List<Long> postGradeIds = postGradeList.stream()
.map(PostGrade::getPostId)
.collect(Collectors.toList());
// 获取 followVOList 中的所有 postId 列表
Set<Long> followVOIds = followVOList.stream()
.map(FollowVO::getPostId)
.collect(Collectors.toSet());
// 找出 postGradeIds 中不包含在 followVOIds 的所有 postId
List<Long> missingPostIds = postGradeIds.stream()
.filter(postId -> !followVOIds.contains(postId))
.collect(Collectors.toList());
// 过滤 followVOList 中的 postId 不在 postGradeIds 里的数据
List<FollowVO> filteredFollowVOList = followVOList.stream()
.filter(followVO -> postGradeIds.contains(followVO.getPostId()))
.collect(Collectors.toList());
missingPostIds.forEach(
missingPostId->{
Optional<PostGrade> optionalPostGrade = postGradeList.stream()
.filter(postGrade -> postGrade.getPostId() == missingPostId)
.findFirst();
PostGrade postGrade = optionalPostGrade.get();
FollowVO followVO = new FollowVO();
followVO.setPostName(postGrade.getPostName());
followVO.setPostId(postGrade.getPostId());
followVO.setHrName(postGrade.getHrName());
followVO.setDeptName(postGrade.getDeptName());
RecruitStructure byNodeId = recruitStructureService.getByNodeId(missingPostId);
if(byNodeId.getTaskId()!=null){
RecruitProcessTask byTaskId = recruitProcessTaskService.getByTaskId(byNodeId.getTaskId());
followVO.setPostCount(byTaskId.getPostCount());
}
filteredFollowVOList.add(followVO);
}
);
// filteredFollowVOList将所有字段除了deptName为null的字段设置为0
filteredFollowVOList.forEach(followVO -> {
if (followVO.getPostId() == null) followVO.setPostId(0L);
if (followVO.getPostName() == null) followVO.setPostName("");
if (followVO.getDeptId() == null) followVO.setDeptId(0L);
if (followVO.getDeptName() == null) followVO.setDeptName(handleDeptName(followVO.getPostId()));
if (followVO.getHrId() == null) followVO.setHrId(0L);
if (followVO.getHrName() == null) followVO.setHrName("");
if (followVO.getPostCount() == null) followVO.setPostCount(0);
if (followVO.getLookResumeCount() == null) followVO.setLookResumeCount(0);
if (followVO.getInviteInterviewCount() == null) followVO.setInviteInterviewCount(0);
if (followVO.getPassResumeCount() == null) followVO.setPassResumeCount(0);
if (followVO.getFirstInterviewCount() == null) followVO.setFirstInterviewCount(0L);
if (followVO.getSecondInterviewCount() == null) followVO.setSecondInterviewCount(0L);
if (followVO.getThirdInterviewCount() == null) followVO.setThirdInterviewCount(0L);
if (followVO.getSalaryCount() == null) followVO.setSalaryCount(0L);
if (followVO.getOfferCount() == null) followVO.setOfferCount(0L);
if (followVO.getEntryCount() == null) followVO.setEntryCount(0L);
Optional<PostGrade> optionalPostGrade = postGradeList.stream()
.filter(postGrade -> Objects.equals(postGrade.getPostId(), followVO.getPostId()))
.findFirst();
if(optionalPostGrade.isPresent()){
followVO.setGrade(optionalPostGrade.get().getGrade());
}
//封装到面率(一面人数/接受邀约人数)
if(followVO.getInviteInterviewCount()!=null&&followVO.getInviteInterviewCount()!=0){
BigDecimal arrivePercentage = new BigDecimal(followVO.getFirstInterviewCount()).divide(new BigDecimal(followVO.getInviteInterviewCount()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
followVO.setArriveRate(arrivePercentage.doubleValue());
}else {
followVO.setArriveRate(0d);
}
//封装招聘达成率入职人数/需求人数
if(followVO.getPostCount()!=null&&followVO.getPostCount()!=0){
BigDecimal entryPercentage = new BigDecimal(followVO.getEntryCount()).divide(new BigDecimal(followVO.getPostCount()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
followVO.setAchievementRate(entryPercentage.doubleValue());
}else {
followVO.setAchievementRate(0d);
}
});
filteredFollowVOList.sort(Comparator.comparing(followVO -> Integer.parseInt(followVO.getGrade())));
ExcelUtil<FollowVO> util = new ExcelUtil<FollowVO>(FollowVO.class);
util.exportExcel(response,filteredFollowVOList, "任务跟踪");
}
}

View File

@ -74,7 +74,7 @@ public class RecruitPostGradeController extends BaseController {
return toAjax(postGradeService.updateById(req));
}
@PreAuthorize("@ss.hasAnyPermi('recruit:grade:list')")
@PreAuthorize("@ss.hasAnyPermi('recruit:grade:query')")
@GetMapping("/list")
@ApiOperation(value = "展示某月份的岗位评级")
public TableDataInfo listPostGrade(PostGrade req) {

View File

@ -115,7 +115,7 @@ public class RecruitProcessController extends BaseController {
return error("上传图片异常,请联系管理员");
}
@PreAuthorize("@ss.hasAnyPermi('recruit:process:list,recruit:postsea:list,recruit:resume:list,recruit:follow:add')")
@GetMapping("/apply/listDept")
@ApiOperation(value = "审批-《我的申请》获取所有二级部门")
public AjaxResult dept() {
@ -372,7 +372,7 @@ public class RecruitProcessController extends BaseController {
}
@PreAuthorize("@ss.hasAnyPermi('recruit:pending:repulse,recruit:postsea:distribution,recruit:follow:list')")
@GetMapping("/pending/getHr")
@ApiOperation(value = "审批-《待我审批》查询所有的hr")
public AjaxResult getHr() {
@ -422,7 +422,7 @@ public class RecruitProcessController extends BaseController {
return success("成功分配");
}
@PreAuthorize("@ss.hasPermi('recruit:mypost:list')")
@PreAuthorize("@ss.hasPermi('recruit:postsea:distribution')")
@GetMapping("/mypost/getOne/{taskId}")
@ApiOperation(value = "岗位公海-获取某个岗位的hr分配数据")
public AjaxResult getPostList(@PathVariable("taskId")String taskId) {
@ -505,12 +505,13 @@ public class RecruitProcessController extends BaseController {
}
@PreAuthorize("@ss.hasAnyPermi('recruit:resume:add,recruit:interview:add,recruit:follow:add')")
@GetMapping("/mypost/resume/postList")
@ApiOperation(value = "在招岗位-《简历处理》获取所有的岗位名字")
public AjaxResult getPostList() {
List<PostListVO> postListVOList = new ArrayList<>();
List<RecruitPost> recruitPostList = recruitPostService.listMyPost(getUserId());
//List<RecruitPost> recruitPostList = recruitPostService.listMyPost(getUserId());
List<RecruitPost> recruitPostList = recruitPostService.list();
if (!CollectionUtils.isEmpty(recruitPostList)) {
recruitPostList.forEach(
recruitPost -> {

View File

@ -30,4 +30,10 @@ public class FollowDTO {
@ApiModelProperty(value = "部门id")
private Long deptId;
@ApiModelProperty(value = "招聘等级")
private Integer grade;
@ApiModelProperty(value = "选择月份")
private String month;
}

View File

@ -130,6 +130,10 @@ public class EntryManage implements Serializable {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@TableField(value = "file")
@Excel(name = "入职周知", cellType = Excel.ColumnType.TEXT)
private String file;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}

View File

@ -1,5 +1,6 @@
package cn.zeroerr.domain.vo;
import cn.zeroerr.common.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -14,14 +15,20 @@ public class FollowVO {
private Long deptId;
@ApiModelProperty(value = "部门名字")
@Excel(name = "部门")
private String deptName;
@ApiModelProperty(value = "岗位id")
private Long postId;
@ApiModelProperty(value = "岗位名字")
@Excel(name = "岗位")
private String postName;
@ApiModelProperty(value = "招聘等级")
@Excel(name = "招聘等级",dictType = "recruit_post_grade")
private String grade;
// /**
// * 招聘时间
// */
@ -31,6 +38,7 @@ public class FollowVO {
// private LocalDate recruitDate;
@ApiModelProperty(value = "需求人数")
@Excel(name = "需求人数")
private Integer postCount;
// /**
@ -51,34 +59,42 @@ public class FollowVO {
// @TableField(value = "pass_count_target")
// private Integer passCountTarget;
@ApiModelProperty(value = "查看过该岗位多少简历数")
@ApiModelProperty(value = "主动打招呼数")
@Excel(name = "主动打招呼数")
private Integer lookResumeCount;
@ApiModelProperty(value = "合格简历数")
@Excel(name = "合格简历数")
private Integer passResumeCount;
@ApiModelProperty(value = "约面人数")
@Excel(name = "约面人数")
private Integer inviteInterviewCount;
@ApiModelProperty(value = "接受邀约人数")
private Integer acceptInviteCount;
@ApiModelProperty(value = "一面人数")
@Excel(name = "初试数")
private Long firstInterviewCount;
@ApiModelProperty(value = "二面人数")
private Long secondInterviewCount;
@ApiModelProperty(value = "三面人数")
@Excel(name = "终试数")
private Long thirdInterviewCount;
@ApiModelProperty(value = "谈薪人数")
@Excel(name = "终试通过人数")
private Long salaryCount;
@ApiModelProperty(value = "offer人数")
@Excel(name = "接受offer人数")
private Long offerCount;
@ApiModelProperty(value = "入职人数")
@Excel(name = "入职人数")
private Long entryCount;
// @ApiModelProperty(value = "离职人数")
@ -112,10 +128,13 @@ public class FollowVO {
private String hrName;
@ApiModelProperty(value = "到面率")
@Excel(name = "到面率(%)")
private Double arriveRate;
@ApiModelProperty(value = "招聘达成率")
@Excel(name = "招聘达成率(%)")
private Double achievementRate;
}

View File

@ -15,6 +15,8 @@ import java.util.List;
public interface PostGradeMapper extends BaseMapper<PostGrade> {
List<PostGrade> listBySelect(@Param("req") PostGrade req);
List<PostGrade> listByMonth(@Param("month") String month, @Param("grade") Integer grade,@Param("hrName") String hrName,@Param("postName") String postName);
}

View File

@ -13,4 +13,6 @@ import java.util.List;
public interface PostGradeService extends IService<PostGrade> {
List<PostGrade> listBySelect(PostGrade req);
List<PostGrade> listByMonth(String month, Integer grade,String hrName,String postName);
}

View File

@ -21,6 +21,11 @@ public class PostGradeServiceImpl extends ServiceImpl<PostGradeMapper, PostGrade
public List<PostGrade> listBySelect(PostGrade req) {
return this.baseMapper.listBySelect(req);
}
@Override
public List<PostGrade> listByMonth(String month, Integer grade,String hrName,String postName) {
return this.baseMapper.listByMonth(month,grade,hrName,postName);
}
}

View File

@ -11,6 +11,7 @@
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="postName" column="post_name" jdbcType="VARCHAR"/>
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
<result property="file" column="file" />
<result property="hrId" column="hr_id" jdbcType="BIGINT"/>
<result property="hrName" column="hr_name" jdbcType="VARCHAR"/>
<result property="finalPassDate" column="final_pass_date" jdbcType="DATE"/>
@ -25,7 +26,7 @@
post_id,post_name,
user_name,hr_id,hr_name,
final_pass_date,join_date,actual_join_date,
entry_fail_reason,is_entry
entry_fail_reason,is_entry,file
</sql>
<select id="listBySelect" resultMap="BaseResultMap">

View File

@ -45,4 +45,18 @@
</if>
</select>
<select id="listByMonth" resultMap="BaseResultMap">
select <include refid="Base_Column_List"/>
from post_grade
where post_name is not null
<if test="month!=null">and month=#{month} </if>
<if test="grade!=null">and grade=#{grade} </if>
<if test="hrName != null and hrName != ''">
and hr_name like concat('%', #{hrName}, '%')
</if>
<if test="postName != null and postName != ''">
and post_name like concat('%', #{postName}, '%')
</if>
</select>
</mapper>

View File

@ -62,7 +62,7 @@
d.type,
d.post_type,
d.task_id,
d.post_complete_date
d.post_complete_date,
(select node_name from recruit_structure where node_id = d.parent_id) parent_name
from recruit_structure d
where d.node_id = #{parentId}