Commit b5daf20e authored by 刘斌's avatar 刘斌

feat: 新增入职,调配,离职流程

parent f4f0c70b
package com.example.constant;
/**
* @author 刘斌
* @date 2025/10/31 16:54
*/
public interface HrFlowTypeConstant {
String Entry = "1";
String RESIGN = "2";
String TRANSFER = "3";
String ENTRY_CODE = "hrEntryFlow";
String RESIGN_CODE = "hrResignFlow";
String TRANSFER_CODE = "hrTransferFlow";
}
package com.example.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.example.domain.params.EmployeeFlowListParam;
import com.example.domain.params.EmployeeFlowParam;
import com.example.domain.vo.EmployeeFlowVo;
import com.example.service.EmployeeFlowServ;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.binfast.common.core.constant.BusinessType;
import top.binfast.common.core.util.ResponseUtils;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import top.binfast.common.excel.annotion.ExcelExport;
import top.binfast.common.idempotent.annotation.NoRepeatSubmit;
import top.binfast.common.log.annotation.PinSysLog;
import java.util.List;
/**
* 人事审批对象
*
* @author LiuBin
* @date 2025-10-31
*/
@Validated
@RestController
@RequestMapping("/employee/flow")
public class EmployeeFlowCtrl {
@Resource
private EmployeeFlowServ employeeFlowServ;
/**
* 查询人事审批对象列表
*/
@SaCheckPermission("employee:flow:list")
@GetMapping("/page")
public PageResponse<EmployeeFlowVo> pageList(EmployeeFlowListParam param) {
return employeeFlowServ.queryPageList(param);
}
/**
* 导出人事审批对象列表
*/
@ExcelExport
@SaCheckPermission("employee:flow:export")
@PinSysLog(value = "人事审批对象", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public List<EmployeeFlowVo> export(EmployeeFlowListParam param) {
return employeeFlowServ.queryList(param);
}
/**
* 获取人事审批对象详细信息
*
* @param id 主键
*/
@SaCheckPermission("employee:flow:query")
@GetMapping("/{id}")
public SingleResponse<EmployeeFlowVo> getDetail(@PathVariable @Min(1)
Long id) {
return SingleResponse.of(employeeFlowServ.queryById(id));
}
/**
* 新增人事审批对象
*/
@SaCheckPermission("employee:flow:add")
@PinSysLog(value = "人事审批对象", businessType = BusinessType.INSERT)
@PostMapping()
public Response add(@Validated(AddGroup.class) @RequestBody EmployeeFlowParam param) {
return ResponseUtils.ofResult(employeeFlowServ.insertByParam(param));
}
/**
* 修改人事审批对象
*/
@SaCheckPermission("employee:flow:edit")
@PinSysLog(value = "人事审批对象", businessType = BusinessType.UPDATE)
@PutMapping()
public Response edit(@Validated(EditGroup.class) @RequestBody EmployeeFlowParam param) {
return ResponseUtils.ofResult(employeeFlowServ.updateByParam(param));
}
/**
* 提交请假并提交流程
*/
@SaCheckPermission("employee:leave:add")
@PinSysLog(value = "发起人事审批", businessType = BusinessType.INSERT)
@NoRepeatSubmit()
@PostMapping("/submitAndFlowStart")
public SingleResponse<EmployeeFlowVo> submitAndFlowStart(@Validated(AddGroup.class) @RequestBody EmployeeFlowParam param) {
return SingleResponse.of(employeeFlowServ.submitAndFlowStart(param));
}
/**
* 删除人事审批对象
*
* @param ids 主键串
*/
@SaCheckPermission("employee:flow:remove")
@PinSysLog(value = "人事审批对象", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public Response remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return ResponseUtils.ofResult(employeeFlowServ.delByIds(List.of(ids)));
}
}
\ No newline at end of file
......@@ -5,8 +5,7 @@ import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.example.domain.EmployeeInfo;
import com.example.domain.params.EmployeeInfoListParam;
import com.example.domain.params.EmployeeInfoParam;
import com.example.domain.params.*;
import com.example.domain.vo.EmployeeInfoImportVo;
import com.example.domain.vo.EmployeeInfoVo;
import com.example.service.EmployeeInfoServ;
......@@ -64,7 +63,7 @@ public class EmployeeInfoCtrl {
@PinSysLog(value = "员工信息", businessType = BusinessType.EXPORT)
@PostMapping("/export/{id}")
public List<EmployeeInfoVo> export(@PathVariable Long id) {
EmployeeInfoVo vo = employeeInfoServ.queryById(id);
EmployeeInfoVo vo = employeeInfoServ.infoDetail(id);
vo.setOnDuty("1".equals(vo.getEmployeeType()) ? "在职" : "离职");
return List.of(vo);
}
......@@ -101,6 +100,19 @@ public class EmployeeInfoCtrl {
return SingleResponse.of(employeeInfoServ.queryById(id));
}
/**
* 展示员工信息详细信息
*
* @param id 主键
*/
@TransMethodResult
@SaCheckPermission("employee:info:query")
@GetMapping("/detail/{id}")
public SingleResponse<EmployeeInfoVo> infoDetail(@PathVariable @Min(1)
Long id) {
return SingleResponse.of(employeeInfoServ.infoDetail(id));
}
/**
* 新增员工信息
*/
......@@ -121,14 +133,34 @@ public class EmployeeInfoCtrl {
return ResponseUtils.ofResult(employeeInfoServ.updateByParam(param));
}
/**
* 申请入职
*/
@SaCheckPermission("employee:info:add")
@PinSysLog(value = "员工信息-入职申请", businessType = BusinessType.UPDATE)
@PostMapping("/applyEntry")
public Response applyEntry(@RequestBody EmployeeEntryApplyParam param) {
return ResponseUtils.ofResult(employeeInfoServ.applyEntry(param));
}
/**
* 申请调职
*/
@SaCheckPermission("employee:info:edit")
@PinSysLog(value = "员工信息-调职申请", businessType = BusinessType.UPDATE)
@PostMapping("/applyTransfer")
public Response applyTransfer(@Validated @RequestBody EmployeeTransferApplyParam param) {
return ResponseUtils.ofResult(employeeInfoServ.applyTransfer(param));
}
/**
* 申请离职
*/
@SaCheckPermission("employee:info:resign")
@PinSysLog(value = "员工信息-申请离职", businessType = BusinessType.UPDATE)
@PutMapping("/applyResign/{id}")
public Response applyResign(@PathVariable @Min(1) Long id) {
return ResponseUtils.ofResult(employeeInfoServ.applyResign(id));
@PinSysLog(value = "员工信息-离职申请", businessType = BusinessType.UPDATE)
@PostMapping("/applyResign")
public Response applyResign(@Validated @RequestBody EmployeeResignApplyParam param) {
return ResponseUtils.ofResult(employeeInfoServ.applyResign(param));
}
/**
......
package com.example.domain;
import top.binfast.common.mybatis.bean.model.TenantModel;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;;
import java.io.Serial;
/**
* 人事审批对象对象 employee_flow
*
* @author LiuBin
* @date 2025-10-31
*/
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@TableName("employee_flow")
public class EmployeeFlow extends TenantModel {
@Serial
private static final long serialVersionUID = 1L;
/**
* 申请编号
*/
private String applyCode;
/**
* 审批类型
*/
private String flowType;
/**
* 员工信息ID
*/
private Long employeeId;
/**
* 开始时间
*/
private LocalDateTime startDate;
/**
* 结束时间
*/
private LocalDateTime endDate;
/**
* 状态
*/
private String status;
/**
* 审批日志ID,如(1,2)
*/
private String logIds;
/**
* 处理人信息
*/
private String handlerMessage;
/**
* 备注
*/
private String remark;
}
......@@ -268,12 +268,17 @@ public class EmployeeInfo extends BaseModel {
/**
* 离职审批状态
*/
private Integer resignationStatus;
private Integer resignationApplyStatus;
/**
* 入职审批状态
*/
private Integer entryStatus;
private Integer entryApplyStatus;
/**
* 调配申请审批状态
*/
private Integer transferApplyStatus;
}
package com.example.domain.params;
import lombok.Data;
/**
* @author 刘斌
* @date 2025/10/31 15:47
*/
@Data
public class EmployeeEntryApplyParam {
private Long id;
private String remark;
}
package com.example.domain.params;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.core.bean.params.PageQueryParam;
import java.util.HashMap;
import java.util.Map;
import java.time.LocalDateTime;;
/**
* 人事审批对象分页对象 employee_flow
*
* @author LiuBin
* @date 2025-10-31
*/
@Getter
@Setter
public class EmployeeFlowListParam extends PageQueryParam {
/**
* 申请编号
*/
private String applyCode;
/**
* 审批类型
*/
private String flowType;
/**
* 员工信息ID
*/
private Long employeeId;
/**
* 开始时间
*/
private LocalDateTime startDate;
/**
* 结束时间
*/
private LocalDateTime endDate;
/**
* 状态
*/
private String status;
private Map<String, Object> params = new HashMap<>();
}
package com.example.domain.params;
import com.example.domain.EmployeeFlow;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import jakarta.validation.constraints.*;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;;
/**
* 人事审批对象业务对象 employee_flow
*
* @author LiuBin
* @date 2025-10-31
*/
@Data
@AutoMapper(target = EmployeeFlow.class, reverseConvertGenerate = false)
public class EmployeeFlowParam {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 流程code
*/
private String flowCode;
/**
* 申请编号
*/
// @NotBlank(message = "申请编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String applyCode;
/**
* 审批类型
*/
@NotBlank(message = "审批类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String flowType;
/**
* 员工信息ID
*/
// @NotNull(message = "员工信息ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long employeeId;
/**
* 审批日志ID,如(1,2)
*/
private String logIds;
/**
* 开始时间
*/
// @NotNull(message = "开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDateTime startDate;
/**
* 结束时间
*/
// @NotNull(message = "结束时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDateTime endDate;
/**
* 状态
*/
// @NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 备注
*/
// @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark;
private Map<String, Object> params = new HashMap<>();
}
package com.example.domain.params;
import com.example.domain.EmployeeInfo;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import java.time.LocalDate;
;
/**
* 员工信息业务对象 employee_info
......@@ -226,13 +229,13 @@ public class EmployeeInfoParam {
/**
* 职称情况
*/
@NotBlank(message = "职称情况不能为空", groups = { AddGroup.class, EditGroup.class })
// @NotBlank(message = "职称情况不能为空", groups = { AddGroup.class, EditGroup.class })
private String professionalTitle;
/**
* 简历
*/
@NotBlank(message = "简历不能为空", groups = { AddGroup.class, EditGroup.class })
// @NotBlank(message = "简历不能为空", groups = { AddGroup.class, EditGroup.class })
private String resume;
/**
......@@ -262,7 +265,7 @@ public class EmployeeInfoParam {
/**
* 合同到期提醒
*/
@NotNull(message = "合同到期提醒不能为空", groups = { AddGroup.class, EditGroup.class })
// @NotNull(message = "合同到期提醒不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate contractExpirationReminder;
/**
......@@ -280,7 +283,7 @@ public class EmployeeInfoParam {
/**
* 转正时间
*/
@NotNull(message = "转正时间不能为空", groups = { AddGroup.class, EditGroup.class })
// @NotNull(message = "转正时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate regularizationDate;
/**
......
package com.example.domain.params;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
/**
* @author 刘斌
* @date 2025/10/31 15:48
*/
@Data
public class EmployeeResignApplyParam {
private Long id;
/**
* 离职时间
*/
@NotNull(message = "离职时间不能为空")
private LocalDate resignDate;
/**
* 离职原因
*/
private String resignReason;
private String remark;
}
package com.example.domain.params;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @author 刘斌
* @date 2025/10/31 17:07
*/
@Data
public class EmployeeTransferApplyParam {
private Long id;
@NotBlank(message = "一级部门不能为空")
private String firstLevelDepartment;
@NotBlank(message = "二级部门不能为空")
private String secondLevelDepartment;
private String remark;
}
package com.example.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.example.domain.EmployeeFlow;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 人事审批对象视图对象 employee_flow
*
* @author LiuBin
* @date 2025-10-31
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = EmployeeFlow.class)
public class EmployeeFlowVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 申请编号
*/
@ExcelProperty(value = "申请编号")
private String applyCode;
/**
* 审批类型
*/
@ExcelProperty(value = "审批类型")
private String flowType;
/**
* 员工信息ID
*/
@ExcelProperty(value = "员工信息ID")
private Long employeeId;
// /**
// * 开始时间
// */
// @ExcelProperty(value = "开始时间")
// private LocalDateTime startDate;
//
// /**
// * 结束时间
// */
// @ExcelProperty(value = "结束时间")
// private LocalDateTime endDate;
/**
* 审计内容
*/
private List<SysAuditLogVo> auditLogList;
/**
* 状态
*/
@ExcelProperty(value = "状态")
private String status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}
package com.example.domain.vo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import top.binfast.common.log.model.SysAuditLog;
/**
* @author 刘斌
* @date 2025/10/31 15:11
*/
@Data
@AutoMapper(target = SysAuditLog.class)
public class SysAuditLogVo {
/**
* 审计名称(入职、调职、离职)
*/
private String auditName;
/**
* 字段名称
*/
private String auditField;
/**
* 字段注释名称
*/
private String auditFieldName;
/**
* 变更前值
*/
private String beforeVal;
/**
* 变更后值
*/
private String afterVal;
}
package com.example.mapper;
import com.example.domain.EmployeeFlow;
import top.binfast.common.mybatis.mapper.BinBaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 人事审批对象Mapper接口
*
* @author LiuBin
* @date 2025-10-31
*/
@Mapper
public interface EmployeeFlowMapper extends BinBaseMapper<EmployeeFlow> {
}
package com.example.service;
import top.binfast.common.log.model.SysAuditLog;
import java.util.List;
/**
* @author 刘斌
* @date 2025/11/2 20:55
*/
public interface EmployeeAuditLogServ {
List<SysAuditLog> queryAuditLogs(String flowLogIds);
Boolean saveAuditLogs(List<SysAuditLog> auditLog);
}
package com.example.service;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.domain.EmployeeFlow;
import com.example.domain.params.EmployeeFlowListParam;
import com.example.domain.params.EmployeeFlowParam;
import com.example.domain.vo.EmployeeFlowVo;
import java.util.List;
/**
* 人事审批对象Service接口
*
* @author LiuBin
* @date 2025-10-31
*/
public interface EmployeeFlowServ extends IService<EmployeeFlow> {
/**
* 分页查询人事审批对象列表
*
* @param param 查询条件
* @return 人事审批对象分页列表
*/
PageResponse<EmployeeFlowVo> queryPageList(EmployeeFlowListParam param);
/**
* 查询符合条件的人事审批对象列表
*
* @param param 查询条件
* @return 人事审批对象列表
*/
List<EmployeeFlowVo> queryList(EmployeeFlowListParam param);
/**
* 查询人事审批对象
*
* @param id 主键
* @return 人事审批对象
*/
EmployeeFlowVo queryById(Long id);
/**
* 新增人事审批对象
*
* @param param 人事审批对象
* @return 是否新增成功
*/
Boolean insertByParam(EmployeeFlowParam param);
/**
* 修改人事审批对象
*
* @param param 人事审批对象
* @return 是否修改成功
*/
Boolean updateByParam(EmployeeFlowParam param);
/**
* 提交请假并发起流程
*/
EmployeeFlowVo submitAndFlowStart(EmployeeFlowParam param);
/**
* 校验并批量删除人事审批对象信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean delByIds(List<Long> ids);
}
......@@ -4,8 +4,7 @@ import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.domain.EmployeeInfo;
import com.example.domain.params.EmployeeInfoListParam;
import com.example.domain.params.EmployeeInfoParam;
import com.example.domain.params.*;
import com.example.domain.vo.EmployeeInfoImportVo;
import com.example.domain.vo.EmployeeInfoVo;
......@@ -60,6 +59,14 @@ public interface EmployeeInfoServ extends IService<EmployeeInfo> {
*/
EmployeeInfoVo queryById(Long id);
/**
* 员工信息详情
*
* @param id 主键
* @return 员工信息
*/
EmployeeInfoVo infoDetail(Long id);
/**
* 新增员工信息
*
......@@ -76,12 +83,26 @@ public interface EmployeeInfoServ extends IService<EmployeeInfo> {
*/
Boolean updateByParam(EmployeeInfoParam param);
/**
* 员工入职申请
*
* @param param 参数
*/
Boolean applyEntry(EmployeeEntryApplyParam param);
/**
* 员工调职申请
*
* @param param 参数
*/
Boolean applyTransfer(EmployeeTransferApplyParam param);
/**
* 员工离职申请
*
* @param id 主键
* @param param 参数
*/
Boolean applyResign(Long id);
Boolean applyResign(EmployeeResignApplyParam param);
/**
* 校验并批量删除员工信息信息
......
package com.example.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.example.service.EmployeeAuditLogServ;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import top.binfast.common.log.dao.SysAuditLogMapper;
import top.binfast.common.log.model.SysAuditLog;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author 刘斌
* @date 2025/11/2 20:56
*/
@DS("logSource")
@Service
@RequiredArgsConstructor
public class EmployeeAuditLogServImpl implements EmployeeAuditLogServ {
private final SysAuditLogMapper auditLogMapper;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public List<SysAuditLog> queryAuditLogs(String flowLogIds) {
List<Long> logIds = StrUtil.split(flowLogIds, StrUtil.COMMA)
.stream()
.filter(Objects::nonNull)
.map(Convert::toLong)
.collect(Collectors.toList());
return auditLogMapper.selectList(new LambdaUpdateWrapper<SysAuditLog>().in(SysAuditLog::getId, logIds));
}
@Override
public Boolean saveAuditLogs(List<SysAuditLog> auditLog) {
return SqlHelper.retBool(auditLogMapper.insert(auditLog));
}
}
\ No newline at end of file
package com.example.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.constant.HrFlowEnum;
import com.example.constant.HrFlowTypeConstant;
import com.example.domain.EmployeeFlow;
import com.example.domain.EmployeeInfo;
import com.example.domain.params.EmployeeFlowListParam;
import com.example.domain.params.EmployeeFlowParam;
import com.example.domain.vo.EmployeeFlowVo;
import com.example.domain.vo.SysAuditLogVo;
import com.example.mapper.EmployeeFlowMapper;
import com.example.mapper.EmployeeInfoMapper;
import com.example.service.EmployeeAuditLogServ;
import com.example.service.EmployeeFlowServ;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.binfast.app.biz.sysapi.bean.model.auth.SysUser;
import top.binfast.app.biz.sysapi.dao.auth.SysUserMapper;
import top.binfast.common.core.exception.PlatformException;
import top.binfast.common.core.util.MapstructUtils;
import top.binfast.common.core.util.SnGen;
import top.binfast.common.log.model.SysAuditLog;
import top.binfast.common.mybatis.util.QueryUtil;
import top.binfast.daemon.workflow.common.enums.BusinessStatusEnum;
import top.binfast.daemon.workflow.domain.dto.StartProcessDTO;
import top.binfast.daemon.workflow.domain.event.ProcessDeleteEvent;
import top.binfast.daemon.workflow.domain.event.ProcessEvent;
import top.binfast.daemon.workflow.domain.event.ProcessTaskEvent;
import top.binfast.daemon.workflow.service.WorkflowService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 人事审批对象Service业务层处理
*
* @author LiuBin
* @date 2025-10-31
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class EmployeeFlowServImpl extends ServiceImpl<EmployeeFlowMapper, EmployeeFlow> implements EmployeeFlowServ {
private final static SnGen snGen = new SnGen();
private final EmployeeFlowMapper employeeFlowMapper;
private final WorkflowService workflowService;
private final EmployeeAuditLogServ employeeAuditLogServ;
private final EmployeeInfoMapper employeeInfoMapper;
private final SysUserMapper sysUserMapper;
/**
* 分页查询人事审批对象列表
*
* @param param 查询条件
* @return 人事审批对象分页列表
*/
@Override
public PageResponse<EmployeeFlowVo> queryPageList(EmployeeFlowListParam param) {
Page<EmployeeFlow> page = QueryUtil.getPage(param);
LambdaQueryWrapper<EmployeeFlow> lambdaQuery = this.buildQueryWrapper(param);
employeeFlowMapper.selectPage(page, lambdaQuery);
return QueryUtil.getPageResponse(page, MapstructUtils.convert(page.getRecords(), EmployeeFlowVo.class));
}
/**
* 查询符合条件的人事审批对象列表
*
* @param param 查询条件
* @return 人事审批对象列表
*/
@Override
public List<EmployeeFlowVo> queryList(EmployeeFlowListParam param) {
LambdaQueryWrapper<EmployeeFlow> lambdaQuery = this.buildQueryWrapper(param);
return MapstructUtils.convert(employeeFlowMapper.selectList(lambdaQuery), EmployeeFlowVo.class);
}
private LambdaQueryWrapper<EmployeeFlow> buildQueryWrapper(EmployeeFlowListParam param) {
LambdaQueryWrapper<EmployeeFlow> lambdaQuery = Wrappers.<EmployeeFlow>lambdaQuery();
lambdaQuery.orderByDesc(EmployeeFlow::getId);
lambdaQuery.eq(StrUtil.isNotBlank(param.getApplyCode()), EmployeeFlow::getApplyCode, param.getApplyCode());
lambdaQuery.eq(StrUtil.isNotBlank(param.getFlowType()), EmployeeFlow::getFlowType, param.getFlowType());
lambdaQuery.eq(param.getEmployeeId() != null, EmployeeFlow::getEmployeeId, param.getEmployeeId());
lambdaQuery.eq(param.getStartDate() != null, EmployeeFlow::getStartDate, param.getStartDate());
lambdaQuery.eq(param.getEndDate() != null, EmployeeFlow::getEndDate, param.getEndDate());
lambdaQuery.eq(StrUtil.isNotBlank(param.getStatus()), EmployeeFlow::getStatus, param.getStatus());
return lambdaQuery;
}
/**
* 查询人事审批对象
*
* @param id 主键
* @return 人事审批对象
*/
@Override
public EmployeeFlowVo queryById(Long id){
EmployeeFlow employeeFlow = employeeFlowMapper.selectById(id);
List<SysAuditLogVo> sysAuditLogVoList = null;
if (StrUtil.isNotBlank(employeeFlow.getLogIds())) {
List<SysAuditLog> auditLogs = employeeAuditLogServ.queryAuditLogs(employeeFlow.getLogIds());
sysAuditLogVoList = MapstructUtils.convert(auditLogs, SysAuditLogVo.class);
}
EmployeeFlowVo employeeFlowVo = MapstructUtils.convert(employeeFlow, EmployeeFlowVo.class);
employeeFlowVo.setAuditLogList(sysAuditLogVoList);
return employeeFlowVo;
}
/**
* 新增人事审批对象
*
* @param param 人事审批对象
* @return 是否新增成功
*/
@Override
public Boolean insertByParam(EmployeeFlowParam param) {
EmployeeFlow employeeFlow = MapstructUtils.convert(param, EmployeeFlow.class);
employeeFlow.setId(snGen.nextId());
return this.save(employeeFlow);
}
/**
* 修改人事审批对象
*
* @param param 人事审批对象
* @return 是否修改成功
*/
@Override
public Boolean updateByParam(EmployeeFlowParam param) {
EmployeeFlow employeeFlow = MapstructUtils.convert(param, EmployeeFlow.class);
return this.updateById(employeeFlow);
}
@Transactional(rollbackFor = {Exception.class})
@Override
public EmployeeFlowVo submitAndFlowStart(EmployeeFlowParam param) {
// long day = DateUtil.betweenDay(param.getStartDate(), param.getEndDate(), true);
if (ObjectUtil.isNull(param.getId())) {
param.setStatus(BusinessStatusEnum.DRAFT.getStatus());
param.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY);
}
EmployeeFlow employeeFlow = MapstructUtils.convert(param, EmployeeFlow.class);
employeeFlow.setId(snGen.nextId());
boolean flag = baseMapper.insertOrUpdate(employeeFlow);
if (flag) {
param.setId(employeeFlow.getId());
// 后端发起需要忽略权限
param.getParams().put("ignore", true);
StartProcessDTO startProcess = new StartProcessDTO();
startProcess.setBusinessId(employeeFlow.getId().toString());
startProcess.setFlowCode(StrUtil.isEmpty(param.getFlowCode()) ? "hrEntryFlow" : param.getFlowCode());
startProcess.setVariables(param.getParams());
// 后端发起 如果没有登录用户 比如定时任务 可以手动设置一个处理人id
// startProcess.setHandler("0");
boolean flag1 = workflowService.startCompleteTask(startProcess);
if (!flag1) {
throw new PlatformException("流程发起异常");
}
}
return MapstructUtils.convert(employeeFlow, EmployeeFlowVo.class);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(EmployeeFlow entity){
// 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除人事审批对象信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = {Exception.class})
public Boolean delByIds(List<Long> ids) {
//做一些业务上的校验,判断是否需要校验
workflowService.deleteInstance(ids);
return this.removeByIds(ids);
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等)
* 正常使用只需#processEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processEvent 参数
*/
// @Transactional(rollbackFor = Exception.class)
@EventListener(condition = "#processEvent.flowCode.startsWith('hr')")
public void processHandler(ProcessEvent processEvent) {
log.info("当前任务执行了{}", processEvent.toString());
EmployeeFlow employeeFlow = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId()));
employeeFlow.setStatus(processEvent.getStatus());
// 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程
Map<String, Object> params = processEvent.getParams();
if (MapUtil.isNotEmpty(params)) {
// 历史任务扩展(通常为附件)
String hisTaskExt = Convert.toStr(params.get("hisTaskExt"));
// 办理人
String handler = Convert.toStr(params.get("handler"));
// 办理意见
String message = Convert.toStr(params.get("message"));
if (StrUtil.isNotBlank(handler) && StrUtil.isNotBlank(message)) {
SysUser sysUser = sysUserMapper.selectById(Convert.toLong(handler));
if (sysUser != null) {
employeeFlow.setHandlerMessage(sysUser.getName() + ":" + message);
}
}
}
if (processEvent.getSubmit()) {
employeeFlow.setStatus(BusinessStatusEnum.WAITING.getStatus());
if(StrUtil.isBlank(employeeFlow.getApplyCode())){
String businessCode = MapUtil.getStr(params, "businessCode",StrUtil.EMPTY);
employeeFlow.setApplyCode(businessCode);
}
} else if (processEvent.getStatus().equals(BusinessStatusEnum.FINISH.getStatus())) {
List<SysAuditLog> auditLogs = new ArrayList<>(6);
if (StrUtil.isNotBlank(employeeFlow.getLogIds())) {
auditLogs = employeeAuditLogServ.queryAuditLogs(employeeFlow.getLogIds());
}
this.handleProcessFinished(processEvent.getFlowCode(), employeeFlow, auditLogs);
}
baseMapper.updateById(employeeFlow);
}
/**
* 执行任务创建监听(也代表上一条任务完成事件)
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
* 在方法中判断流程节点key
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
* //执行业务逻辑
* }
*
* @param processTaskEvent 参数
*/
@EventListener(condition = "#processTaskEvent.flowCode.startsWith('hr')")
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
log.info("当前任务创建了{}", processTaskEvent.toString());
}
/**
* 监听删除流程事件
* 正常使用只需#processDeleteEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processDeleteEvent 参数
*/
@EventListener(condition = "#processDeleteEvent.flowCode.startsWith('hr')")
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString());
EmployeeFlow employeeFlow = baseMapper.selectById(Convert.toLong(processDeleteEvent.getBusinessId()));
if (ObjectUtil.isNull(employeeFlow)) {
return;
}
baseMapper.deleteById(employeeFlow.getId());
}
/**
* 流程结束处理
*
* @param flowCode 流程编码
* @param employeeFlow 员工审批对象
*/
public void handleProcessFinished(String flowCode, EmployeeFlow employeeFlow, List<SysAuditLog> auditLogs) {
EmployeeInfo employeeInfo = employeeInfoMapper.selectById(employeeFlow.getEmployeeId());
switch (flowCode) {
case HrFlowTypeConstant.ENTRY_CODE:
// 入职流程结束
employeeInfo.setEntryApplyStatus(HrFlowEnum.FINISH.getStatus());
break;
case HrFlowTypeConstant.RESIGN_CODE:
// 离职流程结束
employeeInfo.setResignationApplyStatus(HrFlowEnum.FINISH.getStatus());
for (SysAuditLog auditLog : auditLogs) {
if ("resignationReason".equals(auditLog.getAuditField())) {
employeeInfo.setResignationReason(auditLog.getAfterVal());
}
if ("resignationDate".equals(auditLog.getAuditField())) {
employeeInfo.setResignationDate(LocalDateTimeUtil.parseDate(auditLog.getAfterVal()));
}
}
break;
case HrFlowTypeConstant.TRANSFER_CODE:
// 调配流程结束
employeeInfo.setTransferApplyStatus(HrFlowEnum.FINISH.getStatus());
for (SysAuditLog auditLog : auditLogs) {
if ("firstLevelDepartment".equals(auditLog.getAuditField())) {
employeeInfo.setFirstLevelDepartment(auditLog.getAfterVal());
}
if ("secondLevelDepartment".equals(auditLog.getAuditField())) {
employeeInfo.setSecondLevelDepartment(auditLog.getAfterVal());
}
}
break;
default: {
// 其他流程结束
}
}
employeeInfoMapper.updateById(employeeInfo);
}
}
package com.example.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.constant.HrFlowEnum;
import com.example.constant.HrFlowTypeConstant;
import com.example.domain.EmployeeInfo;
import com.example.domain.params.EmployeeDeptCheckAndSaveParam;
import com.example.domain.params.EmployeeInfoListParam;
import com.example.domain.params.EmployeeInfoParam;
import com.example.domain.params.*;
import com.example.domain.vo.EmployeeInfoImportVo;
import com.example.domain.vo.EmployeeInfoVo;
import com.example.mapper.EmployeeInfoMapper;
import com.example.service.EmployeeAuditLogServ;
import com.example.service.EmployeeDeptServ;
import com.example.service.EmployeeFlowServ;
import com.example.service.EmployeeInfoServ;
import lombok.RequiredArgsConstructor;
import org.dromara.trans.service.impl.TransService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.binfast.common.core.enums.ResultCode;
import top.binfast.common.core.util.LambdaUtil;
import top.binfast.common.core.util.MapstructUtils;
import top.binfast.common.excel.core.ExcelContextHolder;
import top.binfast.common.log.model.SysAuditLog;
import top.binfast.common.mybatis.util.QueryUtil;
import top.binfast.common.satoken.util.SecurityUtils;
......@@ -42,6 +50,9 @@ public class EmployeeInfoServImpl extends ServiceImpl<EmployeeInfoMapper, Employ
private final EmployeeInfoMapper employeeInfoMapper;
private final EmployeeDeptServ employeeDeptServ;
private final EmployeeFlowServ employeeFlowServ;
private final EmployeeAuditLogServ employeeAuditLogServ;
private final TransService transService;
/**
* 分页查询员工信息列表
......@@ -198,6 +209,20 @@ public class EmployeeInfoServImpl extends ServiceImpl<EmployeeInfoMapper, Employ
return MapstructUtils.convert(employeeInfo, EmployeeInfoVo.class);
}
/**
* 获取员工信息详细信息
*
* @param id 主键
* @return 员工信息
*/
@Override
public EmployeeInfoVo infoDetail(Long id) {
EmployeeInfo employeeInfo = employeeInfoMapper.selectById(id);
EmployeeInfoVo employeeInfoVo = MapstructUtils.convert(employeeInfo, EmployeeInfoVo.class);
transService.transOne(employeeInfoVo);
return employeeInfoVo;
}
/**
* 新增员工信息
*
......@@ -213,7 +238,7 @@ public class EmployeeInfoServImpl extends ServiceImpl<EmployeeInfoMapper, Employ
EmployeeDeptCheckAndSaveParam checkAndSaveParam =
new EmployeeDeptCheckAndSaveParam(deptNameGroups, SecurityUtils.getCurrentUserId(), SecurityUtils.getTenantId());
employeeDeptServ.checkAndSaveDept(checkAndSaveParam);
employeeInfo.setEntryStatus(HrFlowEnum.WAITING.getStatus());
employeeInfo.setEntryApplyStatus(HrFlowEnum.WAITING.getStatus());
return this.save(employeeInfo);
}
......@@ -236,16 +261,93 @@ public class EmployeeInfoServImpl extends ServiceImpl<EmployeeInfoMapper, Employ
// 做一些数据校验,如唯一约束
}
/**
* 员工入职申请
*
* @param param 入职申请参数
* @return 是否申请成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean applyEntry(EmployeeEntryApplyParam param) {
EmployeeFlowParam flowParam = new EmployeeFlowParam();
flowParam.setFlowCode(HrFlowTypeConstant.ENTRY_CODE);
flowParam.setFlowType(HrFlowTypeConstant.Entry);
flowParam.setEmployeeId(param.getId());
flowParam.setRemark(param.getRemark());
employeeFlowServ.submitAndFlowStart(flowParam);
return true;
}
/**
* 员工调岗申请
*
* @param param 调岗申请参数
* @return 是否申请成功
*/
@Override
public Boolean applyTransfer(EmployeeTransferApplyParam param) {
List<SysAuditLog> list = new ArrayList<>(6);
SysAuditLog firstAuditLog = new SysAuditLog();
firstAuditLog.setAuditName("调职申请");
firstAuditLog.setAuditField("firstLevelDepartment");
firstAuditLog.setAuditFieldName("一级部门");
firstAuditLog.setAfterVal(param.getFirstLevelDepartment());
SysAuditLog secondAuditLog = new SysAuditLog();
secondAuditLog.setAuditName("调职申请");
secondAuditLog.setAuditField("secondLevelDepartment");
secondAuditLog.setAuditFieldName("二级部门");
secondAuditLog.setAfterVal(param.getSecondLevelDepartment());
list.add(firstAuditLog);
list.add(secondAuditLog);
employeeAuditLogServ.saveAuditLogs(list);
String logIds = LambdaUtil.join(list, (item) -> item.getId() + StrUtil.EMPTY, StrUtil.COMMA);
EmployeeFlowParam flowParam = new EmployeeFlowParam();
flowParam.setFlowCode(HrFlowTypeConstant.TRANSFER_CODE);
flowParam.setFlowType(HrFlowTypeConstant.TRANSFER);
flowParam.setEmployeeId(param.getId());
flowParam.setRemark(param.getRemark());
flowParam.setLogIds(logIds);
employeeFlowServ.submitAndFlowStart(flowParam);
return true;
}
/**
* 员工离职申请
*
* @param id 主键
* @param param 入职申请参数
* @return 是否申请成功
*/
@Override
public Boolean applyResign(Long id) {
EmployeeInfo employeeInfo = employeeInfoMapper.selectById(id);
employeeInfo.setResignationStatus(HrFlowEnum.WAITING.getStatus());
return this.updateById(employeeInfo);
@DSTransactional(rollbackFor = Exception.class)
public Boolean applyResign(EmployeeResignApplyParam param) {
List<SysAuditLog> list = new ArrayList<>(6);
if (StrUtil.isNotBlank(param.getResignReason())) {
SysAuditLog reasonAuditLog = new SysAuditLog();
reasonAuditLog.setAuditName("离职申请");
reasonAuditLog.setAuditField("resignationReason");
reasonAuditLog.setAuditFieldName("离职原因");
reasonAuditLog.setAfterVal(param.getResignReason());
list.add(reasonAuditLog);
}
SysAuditLog dateAuditLog = new SysAuditLog();
dateAuditLog.setAuditName("离职申请");
dateAuditLog.setAuditField("resignationDate");
dateAuditLog.setAuditFieldName("离职时间");
dateAuditLog.setAfterVal(LocalDateTimeUtil.format(param.getResignDate(), DatePattern.NORM_DATE_PATTERN));
list.add(dateAuditLog);
employeeAuditLogServ.saveAuditLogs(list);
String logIds = LambdaUtil.join(list, (item) -> item.getId() + StrUtil.EMPTY, StrUtil.COMMA);
EmployeeFlowParam flowParam = new EmployeeFlowParam();
flowParam.setFlowCode(HrFlowTypeConstant.RESIGN_CODE);
flowParam.setFlowType(HrFlowTypeConstant.RESIGN);
flowParam.setEmployeeId(param.getId());
flowParam.setRemark(param.getRemark());
flowParam.setLogIds(logIds);
employeeFlowServ.submitAndFlowStart(flowParam);
return true;
}
/**
......
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.EmployeeFlowMapper">
</mapper>
......@@ -18,7 +18,7 @@
<mapstruct-plus.version>1.4.8</mapstruct-plus.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<binfast.version>1.2.2</binfast.version>
<binfast.version>1.2.3</binfast.version>
<lombok.version>1.18.38</lombok.version>
</properties>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment