Commit 12c9524a authored by 刘斌's avatar 刘斌

Initial commit

parents
/mvnw text eol=lf
*.cmd text eol=crlf
target/
log/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
.DS_Store
mvnw
mvnw.cmd
.mvn/
/logs/
/spy.log
/debezium/
# Getting Started
### 文档地址
http://localhost:${项目端口}/api/swagger-ui/index.html
建议配合ApiFox使用
### 使用步骤
1. 创建数据库
2. 执行数据库脚本
```
mvn archetype:generate \
-DgroupId=${groupId} \
-DartifactId=${artifactId} \
-Dversion=${version} \
-DinteractiveMode=false \
-DarchetypeGroupId=com.anplus \
-DarchetypeArtifactId=binfast-archetype-light \
-DarchetypeVersion=0.0.1-SNAPSHOT
```
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.anplus.hr</groupId>
<artifactId>an-plus-hr</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>admin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>admin</name>
<description>admin</description>
<dependencies>
<dependency>
<groupId>top.binfast.app</groupId>
<artifactId>admin</artifactId>
<version>${binfast.version}</version>
</dependency>
<dependency>
<groupId>top.binfast</groupId>
<artifactId>daemon-codegen</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 添加Maven编译插件配置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>21</source>
<target>21</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>
package com.anplus.hr;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j
@EnableAsync
@EnableCaching
@EnableScheduling
@SpringBootApplication(scanBasePackages = {"top.binfast.daemon.codegen", "top.binfast.app", "com.anplus.hr"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
log.info(" =========== 正常启动 ============== ");
}
}
package com.anplus.hr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Profile("dev")
@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackages = {"top.binfast.daemon.codegen"})
public class CodeGenConfig {
}
package com.anplus.hr.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Profile("dev")
@Configuration(proxyBeanMethods = false)
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
\ No newline at end of file
package com.anplus.hr.config;
import com.anplus.hr.constant.HrCacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import top.binfast.app.biz.sysapi.bean.params.sysDept.SysDeptParam;
import top.binfast.common.redis.util.CacheUtils;
/**
* @author 刘斌
* @date 2025/11/12 10:19
*/
@Aspect
@Component
@Slf4j
public class RefreshDeptCacheAspect {
/**
* 定义切入点:Controller包下的方法
*/
@Pointcut("execution(* top.binfast.app.admin.controller.SysDeptCtrl.add(..)) ||" +
" execution(* top.binfast.app.admin.controller.SysDeptCtrl.edit(..)) ||" +
" execution(* top.binfast.app.admin.controller.SysDeptCtrl.deleteOne(..))")
public void deptChangePointcut() {}
/**
* 方法一:基于注解的监听
*/
@AfterReturning(pointcut = "deptChangePointcut()", returning = "result")
public void afterOperation(JoinPoint joinPoint, Object result) {
try {
// 获取方法参数
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Long deptId = null;
if (args[0] instanceof SysDeptParam param) {
deptId = param.getId();
} else if (args[0] instanceof Long) {
deptId = (Long) args[0];
}
// 清除部门缓存
CacheUtils.evict(HrCacheConstants.DEPT_AND_PARENT_NAME, deptId + "");
} catch (Exception e) {
log.error("清楚部门缓存异常", e);
}
}
}
package com.anplus.hr.constant;
/**
* @author 刘斌
* @date 2025/11/12 10:30
*/
public interface HrCacheConstants {
/**
* 部门及以下权限
*/
String DEPT_AND_PARENT_NAME = "dept_and_parent_name#30d";
}
package com.anplus.hr.constant;
/**
* @author 刘斌
* @date 2025/10/29 10:24
*/
public interface HrConstant {
/**
* 员工性别
*/
String HR_USER_SEX = "hr_user_sex";
/**
* 员工年龄组
*/
String HR_AGE_GROUP = "hr_age_group";
/**
* 员工婚姻状况
*/
String HR_MARITAL_STATUS = "hr_marital_status"; // 设备类型
/**
* 员工政治面貌
*/
String HR_POLITICAL_STATUS = "hr_political_status"; // 授权类型
/**
* 员工工龄段
*/
String HR_YEARS_SERVICE_SEGMENT = "hr_years_service_segment";
/**
* 员工学历
*/
String HR_EDUCATION = "hr_education"; // 通知状态
/**
* 员工类型
*/
String HR_EMPLOYEE_TYPE = "hr_employee_type"; // 通知类型
/**
* 员工用工形式
*/
String HR_EMPLOYMENT_FORM = "hr_employment_form";
}
package com.anplus.hr.constant;
/**
* @author 刘斌
* @date 2025/10/30 14:54
*/
public interface HrDeptLevel {
Integer DEPT_LEVEL_ONE = 1;
Integer DEPT_LEVEL_TWO = 2;
}
package com.anplus.hr.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author 刘斌
* @date 2025/10/30 16:57
*/
@Getter
@AllArgsConstructor
public enum HrFlowEnum {
/**
* 草稿
*/
DRAFT(0, "草稿"),
/**
* 待审核
*/
WAITING(1, "待审核"),
/**
* 已完成
*/
FINISH(2, "已完成");
/**
* 状态
*/
private final Integer status;
/**
* 描述
*/
private final String desc;
private static final Map<Integer, HrFlowEnum> STATUS_MAP = Arrays.stream(HrFlowEnum.values())
.collect(Collectors.toConcurrentMap(HrFlowEnum::getStatus, Function.identity()));
}
package com.anplus.hr.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.anplus.hr.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.anplus.hr.domain.params.EmployeeDeptListParam;
import com.anplus.hr.domain.params.EmployeeDeptParam;
import com.anplus.hr.domain.vo.EmployeeDeptVo;
import com.anplus.hr.service.EmployeeDeptServ;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
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.log.annotation.PinSysLog;
import java.util.List;
/**
* 员工部门
*
* @author LiuBin
* @date 2025-10-30
*/
@Validated
@RestController
@RequestMapping("/employee/dept")
public class EmployeeDeptCtrl {
@Resource
private EmployeeDeptServ employeeDeptServ;
/**
* 查询员工部门列表
*/
@SaCheckPermission("employee:dept:list")
@GetMapping("/page")
public PageResponse<EmployeeDeptVo> pageList(EmployeeDeptListParam param) {
return employeeDeptServ.queryPageList(param);
}
/**
* 导出员工部门列表
*/
@ExcelExport
@SaCheckPermission("employee:dept:export")
@PinSysLog(value = "员工部门", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public List<EmployeeDeptVo> export(EmployeeDeptListParam param) {
return employeeDeptServ.queryList(param);
}
/**
* 根据部门级别查询部门名称
*
* @param level 部门级别
*/
@GetMapping("/deptNames/{level}")
public MultiResponse<String> getDeptNamesByLevel(@PathVariable @Min(1) Integer level) {
return MultiResponse.of(employeeDeptServ.selectDeptNamesByLevel(level));
}
/**
* 根据父级部门名称查询部门名称
*
* @param parentName 父级部门名称
*/
@GetMapping("/deptNamesByParentName/{parentName}")
public MultiResponse<String> getDeptNamesByParentName(@PathVariable @NotBlank String parentName) {
return MultiResponse.of(employeeDeptServ.selectDeptNamesByParentName(parentName));
}
/**
* 获取员工部门详细信息
*
* @param id 主键
*/
@SaCheckPermission("employee:dept:query")
@GetMapping("/{id}")
public SingleResponse<EmployeeDeptVo> getDetail(@PathVariable @Min(1)
Long id) {
return SingleResponse.of(employeeDeptServ.queryById(id));
}
/**
* 新增员工部门
*/
@SaCheckPermission("employee:dept:add")
@PinSysLog(value = "员工部门", businessType = BusinessType.INSERT)
@PostMapping()
public Response add(@Validated(AddGroup.class) @RequestBody EmployeeDeptParam param) {
return ResponseUtils.ofResult(employeeDeptServ.insertByParam(param));
}
/**
* 修改员工部门
*/
@SaCheckPermission("employee:dept:edit")
@PinSysLog(value = "员工部门", businessType = BusinessType.UPDATE)
@PutMapping()
public Response edit(@Validated(EditGroup.class) @RequestBody EmployeeDeptParam param) {
return ResponseUtils.ofResult(employeeDeptServ.updateByParam(param));
}
/**
* 删除员工部门
*
* @param ids 主键串
*/
@SaCheckPermission("employee:dept:remove")
@PinSysLog(value = "员工部门", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public Response remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return ResponseUtils.ofResult(employeeDeptServ.delByIds(List.of(ids)));
}
}
\ No newline at end of file
package com.anplus.hr.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.anplus.hr.domain.params.EmployeeFlowListParam;
import com.anplus.hr.domain.params.EmployeeFlowParam;
import com.anplus.hr.domain.vo.EmployeeFlowVo;
import com.anplus.hr.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
package com.anplus.hr.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.anplus.hr.domain.params.*;
import com.anplus.hr.domain.vo.EmployeeInfoImportVo;
import com.anplus.hr.domain.vo.EmployeeInfoVo;
import com.anplus.hr.service.EmployeeInfoServ;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import org.dromara.core.trans.anno.TransMethodResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
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.excel.annotion.ExcelStream;
import top.binfast.common.log.annotation.PinSysLog;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* 员工信息
*
* @author LiuBin
* @date 2025-10-28
*/
@Validated
@RestController
@RequestMapping("/employee/info")
public class EmployeeInfoCtrl {
@Resource
private EmployeeInfoServ employeeInfoServ;
/**
* 查询员工信息列表
*/
@TransMethodResult
@SaCheckPermission("employee:info:list")
@GetMapping("/page")
public PageResponse<EmployeeInfoVo> pageList(EmployeeInfoListParam param) {
return employeeInfoServ.queryPageList(param);
}
/**
* 导出员工信息列表
*/
@ExcelExport(template = "导出简历模板.xlsx", fill = true)
@SaCheckPermission("employee:info:export")
@PinSysLog(value = "员工信息", businessType = BusinessType.EXPORT)
@PostMapping("/export/{id}")
public List<EmployeeInfoVo> export(@PathVariable Long id) {
EmployeeInfoVo vo = employeeInfoServ.infoDetail(id);
vo.setOnDuty("1".equals(vo.getEmployeeType()) ? "在职" : "离职");
return List.of(vo);
}
/**
* 导入员工信息列表
*/
@PinSysLog(value = "系统用户", businessType = BusinessType.IMPORT)
@SaCheckPermission("employee:info:import")
@PostMapping(value = "/excel/import")
public Response importWithOptions(@ExcelStream(headRowNumber = 2) Stream<EmployeeInfoImportVo> stream, @RequestPart("file") MultipartFile file) {
return employeeInfoServ.importEmployeeList(stream, file);
}
/**
* 获取导入模板
*/
@ExcelExport(template = "模板.xlsx", fill = true)
@PostMapping("/importTemplate")
public List<EmployeeInfoImportVo> importTemplate() {
return new ArrayList<>();
}
/**
* 获取员工信息详细信息
*
* @param id 主键
*/
@TransMethodResult
@SaCheckPermission("employee:info:query")
@GetMapping("/{id}")
public SingleResponse<EmployeeInfoVo> getDetail(@PathVariable @Min(1)
Long id) {
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));
}
/**
* 新增员工信息
*/
@SaCheckPermission("employee:info:add")
@PinSysLog(value = "员工信息", businessType = BusinessType.INSERT)
@PostMapping()
public Response add(@Validated(AddGroup.class) @RequestBody EmployeeInfoParam param) {
return ResponseUtils.ofResult(employeeInfoServ.insertByParam(param));
}
/**
* 修改员工信息
*/
@SaCheckPermission("employee:info:edit")
@PinSysLog(value = "员工信息", businessType = BusinessType.UPDATE)
@PutMapping()
public Response edit(@Validated(EditGroup.class) @RequestBody EmployeeInfoParam param) {
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)
@PostMapping("/applyResign")
public Response applyResign(@Validated @RequestBody EmployeeResignApplyParam param) {
return ResponseUtils.ofResult(employeeInfoServ.applyResign(param));
}
/**
* 删除员工信息
*
* @param ids 主键串
*/
@SaCheckPermission("employee:info:remove")
@PinSysLog(value = "员工信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public Response remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return ResponseUtils.ofResult(employeeInfoServ.delByIds(List.of(ids)));
}
}
\ No newline at end of file
package com.anplus.hr.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.mybatis.bean.model.TenantModel;
import java.io.Serial;
/**
* 员工部门对象 employee_dept
*
* @author LiuBin
* @date 2025-10-30
*/
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@TableName("employee_dept")
public class EmployeeDept extends TenantModel {
@Serial
private static final long serialVersionUID = 1L;
/**
* 父级部门
*/
private Long parentId;
/**
* 父级部门名称
*/
private String parentName;
/**
* 部门名称
*/
private String name;
/**
* 部门层级
*/
private Integer level;
/**
* 祖级关系
*/
private String nodePath;
/**
* 显示顺序
*/
private Long orderNum;
/**
* 状态
*/
private Integer status;
}
package com.anplus.hr.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.mybatis.bean.model.TenantModel;
import java.io.Serial;
import java.time.LocalDateTime;
/**
* 人事审批对象对象 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;
}
package com.anplus.hr.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.mybatis.bean.model.BaseModel;
import java.io.Serial;
import java.time.LocalDate;
/**
* 员工信息对象 employee_info
*
* @author LiuBin
* @date 2025-10-28
*/
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@TableName("employee_info")
public class EmployeeInfo extends BaseModel {
@Serial
private static final long serialVersionUID = 1L;
/**
* 板块
*/
private String plate;
/**
* 项目
*/
private String project;
/**
* 一级部门
*/
private String firstLevelDepartment;
/**
* 二级部门
*/
private String secondLevelDepartment;
/**
* 部门id
*/
private Long deptId;
/**
* 工号
*/
private String employeeId;
/**
* 职级
*/
private String jobLevel;
/**
* 岗位
*/
private String position;
/**
* 职务
*/
private String post;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String gender;
/**
* 简历图片
*/
private String resumeImage;
/**
* 身份证号码
*/
private String idCardNumber;
/**
* 出生日期
*/
private LocalDate birthDate;
/**
* 年龄
*/
private Integer age;
/**
* 年龄段
*/
private String ageGroup;
/**
* 籍贯
*/
private String nativePlace;
/**
* 民族
*/
private String ethnicity;
/**
* 婚姻状况
*/
private String maritalStatus;
/**
* 政治面貌
*/
private String politicalStatus;
/**
* 手机号码
*/
private String phoneNumber;
/**
* 紧急联系人
*/
private String emergencyContact;
/**
* 紧急联系人电话
*/
private String emergencyContactPhone;
/**
* 家庭地址
*/
private String homeAddress;
/**
* 户口所在地
*/
private String householdRegistrationAddress;
/**
* 参加工作时间
*/
private LocalDate workStartDate;
/**
* 入职时间
*/
private LocalDate entryDate;
/**
* 工龄
*/
private String yearsOfService;
/**
* 工龄段
*/
private String yearsOfServiceSegment;
/**
* 学历
*/
private String education;
/**
* 学位
*/
private String degree;
/**
* 毕业时间
*/
private LocalDate graduationDate;
/**
* 专业
*/
private String major;
/**
* 毕业院校
*/
private String graduateSchool;
/**
* 员工类型
*/
private String employeeType;
/**
* 职称情况
*/
private String professionalTitle;
/**
* 简历
*/
private String resume;
/**
* 用工形式
*/
private String employmentForm;
/**
* 劳动合同期限
*/
private String contractTerm;
/**
* 劳动合同开始时间
*/
private LocalDate contractStartDate;
/**
* 劳动合同截止时间
*/
private LocalDate contractEndDate;
/**
* 合同到期提醒
*/
private LocalDate contractExpirationReminder;
/**
* 劳动合同签订情况
*/
private String contractSigningStatus;
/**
* 合同主体
*/
private String contractEntity;
/**
* 转正时间
*/
private LocalDate regularizationDate;
/**
* 异动情况
*/
private String transferStatus;
/**
* 奖惩情况
*/
private String rewardPunishmentStatus;
/**
* 备注
*/
private String remarks;
/**
* 离职时间
*/
private LocalDate resignationDate;
/**
* 离职原因
*/
private String resignationReason;
/**
* 离职审批状态
*/
private Integer resignationApplyStatus;
/**
* 入职审批状态
*/
private Integer entryApplyStatus;
/**
* 调配申请审批状态
*/
private Integer transferApplyStatus;
}
package com.anplus.hr.domain.params;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
* @author 刘斌
* @date 2025/10/30 11:59
*/
@Data
@AllArgsConstructor
public class EmployeeDeptCheckAndSaveParam {
private Set<String> deptNames;
private Long userId;
private Long tenantId;
}
package com.anplus.hr.domain.params;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.core.bean.params.PageQueryParam;
import java.util.HashMap;
import java.util.Map;
/**
* 员工部门分页对象 employee_dept
*
* @author LiuBin
* @date 2025-10-30
*/
@Getter
@Setter
public class EmployeeDeptListParam extends PageQueryParam {
/**
* 父级部门
*/
private Long parentId;
/**
* 父级部门名称
*/
private String parentName;
/**
* 部门名称
*/
private String name;
/**
* 祖级关系
*/
private String nodePath;
/**
* 显示顺序
*/
private Long orderNum;
/**
* 状态
*/
private Integer status;
private Map<String, Object> params = new HashMap<>();
}
package com.anplus.hr.domain.params;
import com.anplus.hr.domain.EmployeeDept;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
/**
* 员工部门业务对象 employee_dept
*
* @author LiuBin
* @date 2025-10-30
*/
@Data
@AutoMapper(target = EmployeeDept.class, reverseConvertGenerate = false)
public class EmployeeDeptParam {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 父级部门
*/
@NotNull(message = "父级部门不能为空", groups = { AddGroup.class, EditGroup.class })
private Long parentId;
/**
* 父级部门名称
*/
private String parentName;
/**
* 部门名称
*/
@NotBlank(message = "部门名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String name;
/**
* 部门层级
*/
private Integer level;
/**
* 祖级关系
*/
@NotBlank(message = "祖级关系不能为空", groups = { AddGroup.class, EditGroup.class })
private String nodePath;
/**
* 显示顺序
*/
@NotNull(message = "显示顺序不能为空", groups = { AddGroup.class, EditGroup.class })
private Long orderNum;
/**
* 状态
*/
@NotNull(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer status;
}
package com.anplus.hr.domain.params;
import lombok.Data;
/**
* @author 刘斌
* @date 2025/10/31 15:47
*/
@Data
public class EmployeeEntryApplyParam {
private Long id;
private String remark;
}
package com.anplus.hr.domain.params;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.core.bean.params.PageQueryParam;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
;
/**
* 人事审批对象分页对象 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.anplus.hr.domain.params;
import com.anplus.hr.domain.EmployeeFlow;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
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.anplus.hr.domain.params;
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.core.bean.params.PageQueryParam;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
;
/**
* 员工信息分页对象 employee_info
*
* @author LiuBin
* @date 2025-10-28
*/
@Getter
@Setter
public class EmployeeInfoListParam extends PageQueryParam {
/**
* 板块
*/
private String plate;
/**
* 项目
*/
private String project;
/**
* 一级部门
*/
private String firstLevelDepartment;
/**
* 二级部门
*/
private String secondLevelDepartment;
/**
* 工号
*/
private String employeeId;
/**
* 职级
*/
private String jobLevel;
/**
* 岗位
*/
private String position;
/**
* 职务
*/
private String post;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String gender;
/**
* 身份证号码
*/
private String idCardNumber;
/**
* 出生日期
*/
private LocalDate birthDate;
/**
* 年龄
*/
private Integer age;
/**
* 年龄段
*/
private String ageGroup;
/**
* 籍贯
*/
private String nativePlace;
/**
* 民族
*/
private String ethnicity;
/**
* 婚姻状况
*/
private String maritalStatus;
/**
* 政治面貌
*/
private String politicalStatus;
/**
* 手机号码
*/
private String phoneNumber;
/**
* 紧急联系人
*/
private String emergencyContact;
/**
* 紧急联系人电话
*/
private String emergencyContactPhone;
/**
* 家庭地址
*/
private String homeAddress;
/**
* 户口所在地
*/
private String householdRegistrationAddress;
/**
* 参加工作时间
*/
private LocalDate workStartDate;
/**
* 入职时间
*/
private LocalDate entryDate;
/**
* 工龄
*/
private String yearsOfService;
/**
* 工龄段
*/
private String yearsOfServiceSegment;
/**
* 学历
*/
private String education;
/**
* 学位
*/
private String degree;
/**
* 毕业时间
*/
private LocalDate graduationDate;
/**
* 专业
*/
private String major;
/**
* 毕业院校
*/
private String graduateSchool;
/**
* 员工类型
*/
private String employeeType;
/**
* 职称情况
*/
private String professionalTitle;
/**
* 简历
*/
private String resume;
/**
* 用工形式
*/
private String employmentForm;
/**
* 劳动合同期限
*/
private String contractTerm;
/**
* 劳动合同开始时间
*/
private LocalDate contractStartDate;
/**
* 劳动合同截止时间
*/
private LocalDate contractEndDate;
/**
* 合同到期提醒
*/
private LocalDate contractExpirationReminder;
/**
* 劳动合同签订情况
*/
private String contractSigningStatus;
/**
* 合同主体
*/
private String contractEntity;
/**
* 转正时间
*/
private LocalDate regularizationDate;
/**
* 异动情况
*/
private String transferStatus;
/**
* 奖惩情况
*/
private String rewardPunishmentStatus;
/**
* 备注
*/
private String remarks;
/**
* 离职时间
*/
private LocalDate resignationDate;
/**
* 离职原因
*/
private String resignationReason;
private Map<String, Object> params = new HashMap<>();
}
package com.anplus.hr.domain.params;
import com.anplus.hr.domain.EmployeeInfo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import top.binfast.common.core.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import java.time.LocalDate;
;
/**
* 员工信息业务对象 employee_info
*
* @author LiuBin
* @date 2025-10-28
*/
@Data
@AutoMapper(target = EmployeeInfo.class, reverseConvertGenerate = false)
public class EmployeeInfoParam {
/**
* 序号
*/
@NotNull(message = "序号不能为空", groups = { EditGroup.class })
private Long id;
/**
* 板块
*/
@NotBlank(message = "板块不能为空", groups = { AddGroup.class, EditGroup.class })
private String plate;
/**
* 项目
*/
@NotBlank(message = "项目不能为空", groups = { AddGroup.class, EditGroup.class })
private String project;
/**
* 一级部门
*/
@NotBlank(message = "一级部门不能为空", groups = { AddGroup.class, EditGroup.class })
private String firstLevelDepartment;
/**
* 二级部门
*/
@NotBlank(message = "二级部门不能为空", groups = { AddGroup.class, EditGroup.class })
private String secondLevelDepartment;
/**
* 部门id
*/
@NotNull(message = "部门id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 工号
*/
@NotBlank(message = "工号不能为空", groups = { AddGroup.class, EditGroup.class })
private String employeeId;
/**
* 职级
*/
@NotBlank(message = "职级不能为空", groups = { AddGroup.class, EditGroup.class })
private String jobLevel;
/**
* 岗位
*/
@NotBlank(message = "岗位不能为空", groups = { AddGroup.class, EditGroup.class })
private String position;
/**
* 职务
*/
@NotBlank(message = "职务不能为空", groups = { AddGroup.class, EditGroup.class })
private String post;
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String name;
/**
* 性别
*/
@NotBlank(message = "性别不能为空", groups = { AddGroup.class, EditGroup.class })
private String gender;
/**
* 简历图片
*/
@NotBlank(message = "简历图片不能为空", groups = { AddGroup.class, EditGroup.class })
private String resumeImage;
/**
* 身份证号码
*/
@NotBlank(message = "身份证号码不能为空", groups = { AddGroup.class, EditGroup.class })
private String idCardNumber;
/**
* 出生日期
*/
@NotNull(message = "出生日期不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate birthDate;
/**
* 年龄
*/
@NotNull(message = "年龄不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer age;
/**
* 年龄段
*/
@NotBlank(message = "年龄段不能为空", groups = { AddGroup.class, EditGroup.class })
private String ageGroup;
/**
* 籍贯
*/
@NotBlank(message = "籍贯不能为空", groups = { AddGroup.class, EditGroup.class })
private String nativePlace;
/**
* 民族
*/
@NotBlank(message = "民族不能为空", groups = { AddGroup.class, EditGroup.class })
private String ethnicity;
/**
* 婚姻状况
*/
@NotBlank(message = "婚姻状况不能为空", groups = { AddGroup.class, EditGroup.class })
private String maritalStatus;
/**
* 政治面貌
*/
@NotBlank(message = "政治面貌不能为空", groups = { AddGroup.class, EditGroup.class })
private String politicalStatus;
/**
* 手机号码
*/
@NotBlank(message = "手机号码不能为空", groups = { AddGroup.class, EditGroup.class })
private String phoneNumber;
/**
* 紧急联系人
*/
@NotBlank(message = "紧急联系人不能为空", groups = { AddGroup.class, EditGroup.class })
private String emergencyContact;
/**
* 紧急联系人电话
*/
@NotBlank(message = "紧急联系人电话不能为空", groups = { AddGroup.class, EditGroup.class })
private String emergencyContactPhone;
/**
* 家庭地址
*/
@NotBlank(message = "家庭地址不能为空", groups = { AddGroup.class, EditGroup.class })
private String homeAddress;
/**
* 户口所在地
*/
@NotBlank(message = "户口所在地不能为空", groups = { AddGroup.class, EditGroup.class })
private String householdRegistrationAddress;
/**
* 参加工作时间
*/
@NotNull(message = "参加工作时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate workStartDate;
/**
* 入职时间
*/
@NotNull(message = "入职时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate entryDate;
/**
* 工龄
*/
@NotNull(message = "工龄不能为空", groups = { AddGroup.class, EditGroup.class })
private String yearsOfService;
/**
* 工龄段
*/
@NotBlank(message = "工龄段不能为空", groups = { AddGroup.class, EditGroup.class })
private String yearsOfServiceSegment;
/**
* 学历
*/
@NotBlank(message = "学历不能为空", groups = { AddGroup.class, EditGroup.class })
private String education;
/**
* 学位
*/
@NotBlank(message = "学位不能为空", groups = { AddGroup.class, EditGroup.class })
private String degree;
/**
* 毕业时间
*/
@NotNull(message = "毕业时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate graduationDate;
/**
* 专业
*/
@NotBlank(message = "专业不能为空", groups = { AddGroup.class, EditGroup.class })
private String major;
/**
* 毕业院校
*/
@NotBlank(message = "毕业院校不能为空", groups = { AddGroup.class, EditGroup.class })
private String graduateSchool;
/**
* 员工类型
*/
@NotBlank(message = "员工类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String employeeType;
/**
* 职称情况
*/
// @NotBlank(message = "职称情况不能为空", groups = { AddGroup.class, EditGroup.class })
private String professionalTitle;
/**
* 简历
*/
// @NotBlank(message = "简历不能为空", groups = { AddGroup.class, EditGroup.class })
private String resume;
/**
* 用工形式
*/
@NotBlank(message = "用工形式不能为空", groups = { AddGroup.class, EditGroup.class })
private String employmentForm;
/**
* 劳动合同期限
*/
@NotBlank(message = "劳动合同期限不能为空", groups = { AddGroup.class, EditGroup.class })
private String contractTerm;
/**
* 劳动合同开始时间
*/
@NotNull(message = "劳动合同开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate contractStartDate;
/**
* 劳动合同截止时间
*/
@NotNull(message = "劳动合同截止时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate contractEndDate;
/**
* 合同到期提醒
*/
// @NotNull(message = "合同到期提醒不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate contractExpirationReminder;
/**
* 劳动合同签订情况
*/
@NotBlank(message = "劳动合同签订情况不能为空", groups = { AddGroup.class, EditGroup.class })
private String contractSigningStatus;
/**
* 合同主体
*/
@NotBlank(message = "合同主体不能为空", groups = { AddGroup.class, EditGroup.class })
private String contractEntity;
/**
* 转正时间
*/
// @NotNull(message = "转正时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate regularizationDate;
/**
* 异动情况
*/
// @NotBlank(message = "异动情况不能为空", groups = { AddGroup.class, EditGroup.class })
private String transferStatus;
/**
* 奖惩情况
*/
// @NotBlank(message = "奖惩情况不能为空", groups = { AddGroup.class, EditGroup.class })
private String rewardPunishmentStatus;
/**
* 备注
*/
// @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remarks;
/**
* 离职时间
*/
// @NotNull(message = "离职时间不能为空", groups = { AddGroup.class, EditGroup.class })
private LocalDate resignationDate;
/**
* 离职原因
*/
// @NotBlank(message = "离职原因不能为空", groups = { AddGroup.class, EditGroup.class })
private String resignationReason;
}
package com.anplus.hr.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.anplus.hr.domain.params;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
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;
@NotNull(message = "部门id不能为空")
private Long deptId;
private String remark;
}
package com.anplus.hr.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.anplus.hr.domain.EmployeeDept;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import top.binfast.common.excel.annotion.ExcelDictFormat;
import top.binfast.common.excel.converters.ExcelDictConvert;
import java.io.Serial;
import java.io.Serializable;
/**
* 员工部门视图对象 employee_dept
*
* @author LiuBin
* @date 2025-10-30
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = EmployeeDept.class)
public class EmployeeDeptVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 父级部门
*/
private Long parentId;
/**
* 父级部门名称
*/
@ExcelProperty(value = "父级部门")
private String parentName;
/**
* 部门名称
*/
@ExcelProperty(value = "部门名称")
private String name;
/**
* 部门层级
*/
private Integer level;
/**
* 祖级关系
*/
@ExcelProperty(value = "祖级关系")
private String nodePath;
/**
* 显示顺序
*/
@ExcelProperty(value = "显示顺序")
private Long orderNum;
/**
* 状态
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "SYS_COMMON_STATUS")
private Integer status;
}
package com.anplus.hr.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.anplus.hr.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.anplus.hr.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.anplus.hr.constant.HrConstant;
import com.anplus.hr.domain.EmployeeInfo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.core.trans.anno.Trans;
import org.dromara.core.trans.constant.TransType;
import org.dromara.core.trans.vo.TransPojo;
import top.binfast.common.excel.annotion.ExcelDictFormat;
import top.binfast.common.excel.converters.ExcelDictConvert;
import top.binfast.common.excel.converters.ExcelUrlImageConverter;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
/**
* 员工信息视图对象 employee_info
*
* @author LiuBin
* @date 2025-10-28
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = EmployeeInfo.class)
public class EmployeeInfoVo implements TransPojo, Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 序号
*/
private Long id;
/**
* 板块
*/
@ExcelProperty(value = "板块")
private String plate;
/**
* 项目
*/
@ExcelProperty(value = "项目")
private String project;
/**
* 一级部门
*/
@ExcelProperty(value = "一级部门")
private String firstLevelDepartment;
/**
* 二级部门
*/
@ExcelProperty(value = "二级部门")
private String secondLevelDepartment;
/**
* 工号
*/
@ExcelProperty(value = "工号")
private String employeeId;
/**
* 职级
*/
@ExcelProperty(value = "职级")
private String jobLevel;
/**
* 岗位
*/
@ExcelProperty(value = "岗位")
private String position;
/**
* 职务
*/
@ExcelProperty(value = "职务")
private String post;
/**
* 姓名
*/
@ExcelProperty(value = "姓名")
private String name;
/**
* 性别
*/
@ExcelProperty(value = "性别", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_USER_SEX)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_USER_SEX)
private String gender;
/**
* 简历图片
*/
@ExcelProperty(value = "简历图片", converter = ExcelUrlImageConverter.class)
private String resumeImage;
/**
* 身份证号码
*/
@ExcelProperty(value = "身份证号码")
private String idCardNumber;
/**
* 出生日期
*/
@ExcelProperty(value = "出生日期")
private LocalDate birthDate;
/**
* 年龄
*/
@ExcelProperty(value = "年龄")
private Integer age;
/**
* 年龄段
*/
@ExcelProperty(value = "年龄段", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_AGE_GROUP)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_AGE_GROUP)
private String ageGroup;
/**
* 籍贯
*/
@ExcelProperty(value = "籍贯")
private String nativePlace;
/**
* 民族
*/
@ExcelProperty(value = "民族")
private String ethnicity;
/**
* 婚姻状况
*/
@ExcelProperty(value = "婚姻状况", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_MARITAL_STATUS)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_MARITAL_STATUS)
private String maritalStatus;
/**
* 政治面貌
*/
@ExcelProperty(value = "政治面貌", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_POLITICAL_STATUS)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_POLITICAL_STATUS)
private String politicalStatus;
/**
* 手机号码
*/
@ExcelProperty(value = "手机号码")
private String phoneNumber;
/**
* 紧急联系人
*/
@ExcelProperty(value = "紧急联系人")
private String emergencyContact;
/**
* 紧急联系人电话
*/
@ExcelProperty(value = "紧急联系人电话")
private String emergencyContactPhone;
/**
* 家庭地址
*/
@ExcelProperty(value = "家庭地址")
private String homeAddress;
/**
* 户口所在地
*/
@ExcelProperty(value = "户口所在地")
private String householdRegistrationAddress;
/**
* 参加工作时间
*/
@ExcelProperty(value = "参加工作时间")
private LocalDate workStartDate;
/**
* 入职时间
*/
@ExcelProperty(value = "入职时间")
private LocalDate entryDate;
/**
* 工龄
*/
@ExcelProperty(value = "工龄")
private String yearsOfService;
/**
* 工龄段
*/
@ExcelProperty(value = "工龄段", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_YEARS_SERVICE_SEGMENT)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_YEARS_SERVICE_SEGMENT)
private String yearsOfServiceSegment;
/**
* 学历
*/
@ExcelProperty(value = "学历")
private String education;
/**
* 学位
*/
@ExcelProperty(value = "学位")
private String degree;
/**
* 毕业时间
*/
@ExcelProperty(value = "毕业时间")
private LocalDate graduationDate;
/**
* 专业
*/
@ExcelProperty(value = "专业")
private String major;
/**
* 毕业院校
*/
@ExcelProperty(value = "毕业院校")
private String graduateSchool;
/**
* 员工类型
*/
@ExcelProperty(value = "员工类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_EMPLOYEE_TYPE)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_EMPLOYEE_TYPE)
private String employeeType;
/**
* 职称情况
*/
@ExcelProperty(value = "职称情况")
private String professionalTitle;
/**
* 简历
*/
@ExcelProperty(value = "简历")
private String resume;
/**
* 用工形式
*/
@ExcelProperty(value = "用工形式", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_EMPLOYMENT_FORM)
@Trans(type = TransType.DICTIONARY, key = HrConstant.HR_EMPLOYMENT_FORM)
private String employmentForm;
/**
* 劳动合同期限
*/
@ExcelProperty(value = "劳动合同期限")
private String contractTerm;
/**
* 劳动合同开始时间
*/
@ExcelProperty(value = "劳动合同开始时间")
private LocalDate contractStartDate;
/**
* 劳动合同截止时间
*/
@ExcelProperty(value = "劳动合同截止时间")
private LocalDate contractEndDate;
/**
* 合同到期提醒
*/
@ExcelProperty(value = "合同到期提醒")
private LocalDate contractExpirationReminder;
/**
* 劳动合同签订情况
*/
@ExcelProperty(value = "劳动合同签订情况")
private String contractSigningStatus;
/**
* 合同主体
*/
@ExcelProperty(value = "合同主体")
private String contractEntity;
/**
* 转正时间
*/
@ExcelProperty(value = "转正时间")
private LocalDate regularizationDate;
/**
* 异动情况
*/
@ExcelProperty(value = "异动情况")
private String transferStatus;
/**
* 奖惩情况
*/
@ExcelProperty(value = "奖惩情况")
private String rewardPunishmentStatus;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remarks;
/**
* 离职时间
*/
@ExcelProperty(value = "离职时间")
private LocalDate resignationDate;
/**
* 离职原因
*/
@ExcelProperty(value = "离职原因")
private String resignationReason;
/**
* 是否转正
*/
@ExcelProperty(value = "是否转正")
private String onDuty;
}
package com.anplus.hr.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.anplus.hr.mapper;
import com.anplus.hr.domain.EmployeeDept;
import org.apache.ibatis.annotations.Mapper;
import top.binfast.common.mybatis.mapper.BinBaseMapper;
/**
* 员工部门Mapper接口
*
* @author LiuBin
* @date 2025-10-30
*/
@Mapper
public interface EmployeeDeptMapper extends BinBaseMapper<EmployeeDept> {
}
package com.anplus.hr.mapper;
import com.anplus.hr.domain.EmployeeFlow;
import org.apache.ibatis.annotations.Mapper;
import top.binfast.common.mybatis.mapper.BinBaseMapper;
/**
* 人事审批对象Mapper接口
*
* @author LiuBin
* @date 2025-10-31
*/
@Mapper
public interface EmployeeFlowMapper extends BinBaseMapper<EmployeeFlow> {
}
package com.anplus.hr.mapper;
import com.anplus.hr.domain.EmployeeInfo;
import org.apache.ibatis.annotations.Mapper;
import top.binfast.common.mybatis.mapper.BinBaseMapper;
/**
* 员工信息Mapper接口
*
* @author LiuBin
* @date 2025-10-28
*/
@Mapper
public interface EmployeeInfoMapper extends BinBaseMapper<EmployeeInfo> {
}
package com.anplus.hr.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.anplus.hr.service;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import com.anplus.hr.domain.EmployeeDept;
import com.anplus.hr.domain.params.EmployeeDeptCheckAndSaveParam;
import com.anplus.hr.domain.params.EmployeeDeptListParam;
import com.anplus.hr.domain.params.EmployeeDeptParam;
import com.anplus.hr.domain.vo.EmployeeDeptVo;
import java.util.List;
/**
* 员工部门Service接口
*
* @author LiuBin
* @date 2025-10-30
*/
public interface EmployeeDeptServ extends IService<EmployeeDept> {
/**
* 分页查询员工部门列表
*
* @param param 查询条件
* @return 员工部门分页列表
*/
PageResponse<EmployeeDeptVo> queryPageList(EmployeeDeptListParam param);
/**
* 查询符合条件的员工部门列表
*
* @param param 查询条件
* @return 员工部门列表
*/
List<EmployeeDeptVo> queryList(EmployeeDeptListParam param);
/**
* 批量保存部门信息
*
* @param param 部门名称
*/
void checkAndSaveDept(EmployeeDeptCheckAndSaveParam param);
/**
* 查询部门名称
*
* @param level 部门级别
* @return 部门名称
*/
List<String> selectDeptNamesByLevel(Integer level);
/**
* 查询部门名称
*
* @param parentName 部门名称
* @return 部门名称
*/
List<String> selectDeptNamesByParentName(String parentName);
/**
* 查询员工部门
*
* @param id 主键
* @return 员工部门
*/
EmployeeDeptVo queryById(Long id);
/**
* 新增员工部门
*
* @param param 员工部门
* @return 是否新增成功
*/
Boolean insertByParam(EmployeeDeptParam param);
/**
* 修改员工部门
*
* @param param 员工部门
* @return 是否修改成功
*/
Boolean updateByParam(EmployeeDeptParam param);
/**
* 校验并批量删除员工部门信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean delByIds(List<Long> ids);
}
package com.anplus.hr.service;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import com.anplus.hr.domain.EmployeeFlow;
import com.anplus.hr.domain.params.EmployeeFlowListParam;
import com.anplus.hr.domain.params.EmployeeFlowParam;
import com.anplus.hr.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);
}
package com.anplus.hr.service;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.Response;
import com.baomidou.mybatisplus.extension.service.IService;
import com.anplus.hr.domain.EmployeeInfo;
import com.anplus.hr.domain.params.*;
import com.anplus.hr.domain.vo.EmployeeInfoImportVo;
import com.anplus.hr.domain.vo.EmployeeInfoVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.stream.Stream;
/**
* 员工信息Service接口
*
* @author LiuBin
* @date 2025-10-28
*/
public interface EmployeeInfoServ extends IService<EmployeeInfo> {
/**
* 分页查询员工信息列表
*
* @param param 查询条件
* @return 员工信息分页列表
*/
PageResponse<EmployeeInfoVo> queryPageList(EmployeeInfoListParam param);
/**
* 查询符合条件的员工信息列表
*
* @param param 查询条件
* @return 员工信息列表
*/
List<EmployeeInfoVo> queryList(EmployeeInfoListParam param);
/**
* 导入员工信息列表
*
* @param stream 员工信息列表
* @return 是否导入成功
*/
Response importEmployeeList(Stream<EmployeeInfoImportVo> stream, MultipartFile file);
/**
* 校验员工名称是否唯一
*
* @param param 员工信息
* @return 是否唯一
*/
Boolean checkEmployeeIdCardNumberUnique(EmployeeInfoParam param);
/**
* 查询员工信息
*
* @param id 主键
* @return 员工信息
*/
EmployeeInfoVo queryById(Long id);
/**
* 员工信息详情
*
* @param id 主键
* @return 员工信息
*/
EmployeeInfoVo infoDetail(Long id);
/**
* 新增员工信息
*
* @param param 员工信息
* @return 是否新增成功
*/
Boolean insertByParam(EmployeeInfoParam param);
/**
* 修改员工信息
*
* @param param 员工信息
* @return 是否修改成功
*/
Boolean updateByParam(EmployeeInfoParam param);
/**
* 员工入职申请
*
* @param param 参数
*/
Boolean applyEntry(EmployeeEntryApplyParam param);
/**
* 员工调职申请
*
* @param param 参数
*/
Boolean applyTransfer(EmployeeTransferApplyParam param);
/**
* 员工离职申请
*
* @param param 参数
*/
Boolean applyResign(EmployeeResignApplyParam param);
/**
* 校验并批量删除员工信息信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean delByIds(List<Long> ids);
}
package com.anplus.hr.service;
import java.util.List;
import java.util.Map;
/**
* @author 刘斌
* @date 2025/11/6 11:27
*/
public interface EmployeeSysDeptServ {
/**
* 根据部门id查询部门名称以及父级部门名称
*
* @param deptId 部门id
*/
List<String> selectDeptNameAncestorsById(Long deptId);
Map<String, Long> selectJoinDeptNames();
}
package com.anplus.hr.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.anplus.hr.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.anplus.hr.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.anplus.hr.constant.HrDeptLevel;
import com.anplus.hr.domain.EmployeeDept;
import com.anplus.hr.domain.params.EmployeeDeptCheckAndSaveParam;
import com.anplus.hr.domain.params.EmployeeDeptListParam;
import com.anplus.hr.domain.params.EmployeeDeptParam;
import com.anplus.hr.domain.vo.EmployeeDeptVo;
import com.anplus.hr.mapper.EmployeeDeptMapper;
import com.anplus.hr.service.EmployeeDeptServ;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.binfast.common.core.constant.NormalStatus;
import top.binfast.common.core.util.LambdaUtil;
import top.binfast.common.core.util.MapstructUtils;
import top.binfast.common.mybatis.util.QueryUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* 员工部门Service业务层处理
*
* @author LiuBin
* @date 2025-10-30
*/
@RequiredArgsConstructor
@Service
public class EmployeeDeptServImpl extends ServiceImpl<EmployeeDeptMapper, EmployeeDept> implements EmployeeDeptServ {
private final EmployeeDeptMapper employeeDeptMapper;
/**
* 分页查询员工部门列表
*
* @param param 查询条件
* @return 员工部门分页列表
*/
@Override
public PageResponse<EmployeeDeptVo> queryPageList(EmployeeDeptListParam param) {
Page<EmployeeDept> page = QueryUtil.getPage(param);
LambdaQueryWrapper<EmployeeDept> lambdaQuery = this.buildQueryWrapper(param);
employeeDeptMapper.selectPage(page, lambdaQuery);
return QueryUtil.getPageResponse(page, MapstructUtils.convert(page.getRecords(), EmployeeDeptVo.class));
}
/**
* 查询符合条件的员工部门列表
*
* @param param 查询条件
* @return 员工部门列表
*/
@Override
public List<EmployeeDeptVo> queryList(EmployeeDeptListParam param) {
LambdaQueryWrapper<EmployeeDept> lambdaQuery = this.buildQueryWrapper(param);
return MapstructUtils.convert(employeeDeptMapper.selectList(lambdaQuery), EmployeeDeptVo.class);
}
private LambdaQueryWrapper<EmployeeDept> buildQueryWrapper(EmployeeDeptListParam param) {
LambdaQueryWrapper<EmployeeDept> lambdaQuery = Wrappers.<EmployeeDept>lambdaQuery();
lambdaQuery.orderByDesc(EmployeeDept::getId);
lambdaQuery.eq(param.getParentId() != null, EmployeeDept::getParentId, param.getParentId());
lambdaQuery.like(StrUtil.isNotBlank(param.getName()), EmployeeDept::getName, param.getName());
lambdaQuery.eq(StrUtil.isNotBlank(param.getNodePath()), EmployeeDept::getNodePath, param.getNodePath());
lambdaQuery.eq(param.getOrderNum() != null, EmployeeDept::getOrderNum, param.getOrderNum());
lambdaQuery.eq(param.getStatus() != null, EmployeeDept::getStatus, param.getStatus());
return lambdaQuery;
}
/**
* 批量保存员工部门
*
* @param param 部门名称集合
*/
@Override
@Async
@Transactional(rollbackFor = Exception.class)
public void checkAndSaveDept(EmployeeDeptCheckAndSaveParam param) {
Set<String> deptNames = param.getDeptNames();
if (CollUtil.isEmpty(deptNames)) {
return;
}
List<EmployeeDept> updateList = new ArrayList<>();
for (String deptNameGroup : deptNames) {
String[] split = deptNameGroup.split(StrUtil.DASHED);
if (split.length != 2) {
continue;
}
boolean exists = employeeDeptMapper.exists(new LambdaUpdateWrapper<EmployeeDept>()
.eq(EmployeeDept::getParentName, split[0])
.eq(EmployeeDept::getName, split[1]));
if (!exists) {
EmployeeDept parentDept = employeeDeptMapper.selectOne(new LambdaUpdateWrapper<EmployeeDept>()
.eq(EmployeeDept::getName, split[0]));
if (parentDept == null) {
parentDept = new EmployeeDept();
parentDept.setParentId(0L);
parentDept.setParentName("顶级部门");
parentDept.setName(split[0]);
parentDept.setStatus(NormalStatus.OPEN_STATUS);
parentDept.setLevel(HrDeptLevel.DEPT_LEVEL_ONE);
parentDept.setTenantId(param.getTenantId());
parentDept.setCreateBy(param.getUserId());
employeeDeptMapper.insert(parentDept);
parentDept.setOrderNum(parentDept.getId());
parentDept.setNodePath("/0/" + parentDept.getId());
updateList.add(parentDept);
}
EmployeeDept employeeDept = new EmployeeDept();
employeeDept.setParentId(parentDept.getId());
employeeDept.setParentName(parentDept.getName());
employeeDept.setName(split[1]);
employeeDept.setStatus(NormalStatus.OPEN_STATUS);
parentDept.setLevel(HrDeptLevel.DEPT_LEVEL_TWO);
employeeDept.setTenantId(param.getTenantId());
employeeDept.setCreateBy(param.getUserId());
employeeDeptMapper.insert(employeeDept);
employeeDept.setOrderNum(employeeDept.getId());
employeeDept.setNodePath(parentDept.getNodePath() + "/" + employeeDept.getId() + "/");
updateList.add(employeeDept);
}
}
if (CollUtil.isNotEmpty(updateList)) {
employeeDeptMapper.updateById(updateList);
}
}
/**
* 根据部门等级查询部门名称
*
* @param level 部门等级
* @return 部门名称列表
*/
@Override
public List<String> selectDeptNamesByLevel(Integer level) {
List<EmployeeDept> employeeDeptList = employeeDeptMapper.selectList(new LambdaUpdateWrapper<EmployeeDept>()
.eq(EmployeeDept::getLevel, level));
return LambdaUtil.mapToList(employeeDeptList, EmployeeDept::getName);
}
@Override
public List<String> selectDeptNamesByParentName(String parentName) {
List<EmployeeDept> employeeDeptList = employeeDeptMapper.selectList(new LambdaUpdateWrapper<EmployeeDept>()
.eq(EmployeeDept::getParentName, parentName));
return LambdaUtil.mapToList(employeeDeptList, EmployeeDept::getName);
}
/**
* 查询员工部门
*
* @param id 主键
* @return 员工部门
*/
@Override
public EmployeeDeptVo queryById(Long id) {
EmployeeDept employeeDept = employeeDeptMapper.selectById(id);
return MapstructUtils.convert(employeeDept, EmployeeDeptVo.class);
}
/**
* 新增员工部门
*
* @param param 员工部门
* @return 是否新增成功
*/
@Override
public Boolean insertByParam(EmployeeDeptParam param) {
EmployeeDept employeeDept = MapstructUtils.convert(param, EmployeeDept.class);
return this.save(employeeDept);
}
/**
* 修改员工部门
*
* @param param 员工部门
* @return 是否修改成功
*/
@Override
public Boolean updateByParam(EmployeeDeptParam param) {
EmployeeDept employeeDept = MapstructUtils.convert(param, EmployeeDept.class);
return this.updateById(employeeDept);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(EmployeeDept entity) {
// 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除员工部门信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
@Override
// @Transactional(rollbackFor = {Exception.class})
public Boolean delByIds(List<Long> ids) {
//做一些业务上的校验,判断是否需要校验
return this.removeByIds(ids);
}
}
package com.anplus.hr.service.impl;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.anplus.hr.constant.HrFlowEnum;
import com.anplus.hr.domain.EmployeeInfo;
import com.anplus.hr.mapper.EmployeeInfoMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.List;
/**
* @author 刘斌
* @date 2025/11/5 17:01
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class EmployeeScheduleService {
private final EmployeeInfoMapper employeeInfoMapper;
/**
* 方式1:使用cron表达式
* 每天凌晨1点执行
*/
@Scheduled(cron = "0 0 1 * * ?")
public void midnightTask() {
executeSafely("刷新员工工龄以及年龄", this::processRefreshInfo);
}
/**
* 刷新员工工龄以及工龄组
*/
private void processRefreshInfo() {
List<EmployeeInfo> employeeInfos = employeeInfoMapper.selectList(new LambdaUpdateWrapper<EmployeeInfo>()
.eq(EmployeeInfo::getEntryApplyStatus, HrFlowEnum.FINISH.getStatus())
.ne(EmployeeInfo::getResignationApplyStatus, HrFlowEnum.FINISH.getStatus()));
for (EmployeeInfo employeeInfo : employeeInfos) {
Period period = LocalDateTimeUtil.betweenPeriod(employeeInfo.getEntryDate(), LocalDate.from(LocalDateTime.now()));
int years = period.getYears();
int months = period.getMonths();
employeeInfo.setYearsOfService(years > 0 ? years + "年" + months + "个月" : months + "个月");
// TODO 更新员工工龄组
precessRefreshAge(employeeInfo);
}
}
private void precessRefreshAge(EmployeeInfo employeeInfo) {
Period period = LocalDateTimeUtil.betweenPeriod(employeeInfo.getBirthDate(), LocalDate.from(LocalDateTime.now()));
if (employeeInfo.getAge() != period.getYears()) {
employeeInfo.setAge(period.getYears());
// TODO 更新员工年龄组
}
}
/**
* 安全执行方法,包含异常处理
*/
private void executeSafely(String taskName, Runnable task) {
log.info("开始执行{}", taskName);
long startTime = System.currentTimeMillis();
try {
task.run();
long cost = System.currentTimeMillis() - startTime;
log.info("{}执行完成,耗时:{}ms", taskName, cost);
} catch (Exception e) {
log.error("{}执行失败", taskName, e);
// 这里可以添加告警逻辑,如发送邮件、短信等
}
}
}
package com.anplus.hr.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.anplus.hr.constant.HrCacheConstants;
import com.anplus.hr.service.EmployeeSysDeptServ;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import top.binfast.app.biz.sysapi.bean.model.auth.SysDept;
import top.binfast.app.biz.sysapi.bean.vo.sysDept.SysDeptDTO;
import top.binfast.app.biz.sysapi.dao.auth.SysDeptMapper;
import top.binfast.app.biz.sysbiz.service.SysDeptServ;
import top.binfast.common.core.bean.dto.TreeDTO;
import top.binfast.common.core.util.LambdaUtil;
import top.binfast.common.core.util.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 刘斌
* @date 2025/11/6 11:30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class EmployeeSysDeptServImpl implements EmployeeSysDeptServ {
private final SysDeptMapper sysDeptMapper;
private final SysDeptServ sysDeptServ;
@Cacheable(cacheNames = HrCacheConstants.DEPT_AND_PARENT_NAME, key = "#deptId")
@Override
public List<String> selectDeptNameAncestorsById(Long deptId) {
SysDeptDTO dept = sysDeptServ.selectDeptById(deptId);
List<Long> split = StringUtils.splitTo(dept.getNodePath(), StrUtil.SLASH, Convert::toLong);
if (split.size() <= 2) {
return List.of(dept.getName());
}
List<SysDept> deptNameList = sysDeptMapper.selectByIds(split);
return LambdaUtil.mapToList(deptNameList, SysDept::getName);
}
@Override
public Map<String, Long> selectJoinDeptNames() {
// if (CollUtil.isEmpty(joinNameSet)) {
// return new HashMap<>();
// }
Map<String, Long> result = new HashMap<>();
List<SysDeptDTO> sysDeptDTOS = sysDeptServ.deptTreeForOptions();
traverseDeptTree(sysDeptDTOS, "", result);
// for (String joinName : joinNameSet) {
// List<String> deptNameList = StrUtil.split(joinName, StrUtil.SLASH);
//
// }
return result;
}
// 遍历根节点列表
private <T extends TreeDTO> void traverseDeptTree(List<T> deptList, String parentPath, Map<String, Long> result) {
if (CollUtil.isEmpty(deptList)) {
return;
}
for (TreeDTO dept : deptList) {
String currentPath = StrUtil.isEmpty(parentPath) ? dept.getLabel() : parentPath + StrUtil.SLASH + dept.getLabel();
// 递归处理子节点
if (CollUtil.isNotEmpty(dept.getChildren())) {
traverseDeptTree(dept.getChildren(), currentPath, result);
} else {
result.put(currentPath, dept.getId());
}
}
}
}
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<!--
小技巧: 在根pom里面设置统一存放路径,统一管理方便维护
<properties>
<log-path>/Users/lengleng</log-path>
</properties>
1. 其他模块加日志输出,直接copy本文件放在resources 目录即可
2. 注意修改 <property name="${log-path}/log.path" value=""/> 的value模块
-->
<configuration debug="false" scan="false">
<property name="log.path" value="./logs"/>
<!-- 日志最大的历史 30天 -->
<property name="log.maxHistory" value="30"/>
<property name="log.level" value="debug"/>
<property name="log.maxSize" value="50MB" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="LOG_PATTERN" value="%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n"/>
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" class="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
class="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
class="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- Console log output -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 控制台输出 -->
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/console.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/console.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大 1天 -->
<maxHistory>1</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- Log file info output -->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>${log.maxSize}</maxFileSize>
<maxHistory>${log.maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- Log file error output -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>${log.maxSize}</maxFileSize>
<maxHistory>${log.maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<!-- <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">-->
<!-- &lt;!&ndash; 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 &ndash;&gt;-->
<!-- <discardingThreshold>0</discardingThreshold>-->
<!-- &lt;!&ndash; 更改默认的队列的深度,该值会影响性能.默认值为256 &ndash;&gt;-->
<!-- <queueSize>256</queueSize>-->
<!-- &lt;!&ndash; 开启记录信息 &ndash;&gt;-->
<!-- <includeCallerData>true</includeCallerData>-->
<!-- &lt;!&ndash; 添加附加的appender,最多只能添加一个 &ndash;&gt;-->
<!-- <appender-ref ref="info"/>-->
<!-- </appender>-->
<!-- <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">-->
<!-- &lt;!&ndash; 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 &ndash;&gt;-->
<!-- <discardingThreshold>0</discardingThreshold>-->
<!-- &lt;!&ndash; 更改默认的队列的深度,该值会影响性能.默认值为256 &ndash;&gt;-->
<!-- <queueSize>256</queueSize>-->
<!-- &lt;!&ndash; 开启记录信息 &ndash;&gt;-->
<!-- <includeCallerData>true</includeCallerData>-->
<!-- &lt;!&ndash; 添加附加的appender,最多只能添加一个 &ndash;&gt;-->
<!-- <appender-ref ref="error"/>-->
<!-- </appender>-->
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="file_console"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
</root>
</configuration>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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