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.ExcelProperty;
import com.anplus.hr.constant.HrConstant;
import com.anplus.hr.domain.EmployeeInfo;
import com.anplus.hr.domain.params.EmployeeInfoParam;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import top.binfast.common.excel.annotion.ExcelDictFormat;
import top.binfast.common.excel.bean.ExcelBaseEntity;
import top.binfast.common.excel.converters.ExcelDictConvert;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
/**
* @author 刘斌
* @date 2025/10/29 09:42
*/
@Getter
@AutoMappers({
@AutoMapper(target = EmployeeInfo.class, reverseConvertGenerate = false),
@AutoMapper(target = EmployeeInfoParam.class, reverseConvertGenerate = false)
})
public class EmployeeInfoImportVo extends ExcelBaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 板块
*/
@NotBlank(message = "板块不能为空")
@ExcelProperty(value = "板块")
private String plate;
/**
* 项目
*/
@NotBlank(message = "项目不能为空")
@ExcelProperty(value = "项目")
private String project;
/**
* 一级部门
*/
@NotBlank(message = "一级部门不能为空")
@ExcelProperty(value = "一级部门")
private String firstLevelDepartment;
/**
* 二级部门
*/
@ExcelProperty(value = "二级部门")
private String secondLevelDepartment;
/**
* 工号
*/
@NotBlank(message = "工号不能为空")
@ExcelProperty(value = "工号")
private String employeeId;
/**
* 职级
*/
@ExcelProperty(value = "职级")
private String jobLevel;
/**
* 岗位
*/
@NotBlank(message = "岗位不能为空")
@ExcelProperty(value = "岗位")
private String position;
/**
* 职务
*/
@ExcelProperty(value = "职务")
private String post;
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空")
@ExcelProperty(value = "姓名")
private String name;
/**
* 性别
*/
@NotBlank(message = "性别不能为空")
@ExcelProperty(value = "性别", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_USER_SEX)
private String gender;
/**
* 简历图片
*/
@ExcelProperty(value = "简历图片")
private String resumeImage;
// /**
// * 性别
// */
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_USER_SEX,refs = {"genderName"})
// private String gender;
/**
* 身份证号码
*/
@NotBlank(message = "身份证号码不能为空")
@ExcelProperty(value = "身份证号码")
private String idCardNumber;
/**
* 出生日期
*/
@ExcelProperty(value = "出生日期")
private LocalDate birthDate;
/**
* 年龄
*/
@NotNull(message = "年龄不能为空")
@ExcelProperty(value = "年龄")
private Integer age;
/**
* 年龄段
*/
@ExcelProperty(value = "年龄段", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_AGE_GROUP)
private String ageGroup;
// /**
// * 年龄段
// */
//// @ExcelProperty(value = "年龄段")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_AGE_GROUP,refs = {"ageGroupName"})
// private String ageGroup;
/**
* 籍贯
*/
@ExcelProperty(value = "籍贯")
private String nativePlace;
/**
* 民族
*/
@ExcelProperty(value = "民族")
private String ethnicity;
/**
* 婚姻状况
*/
@ExcelProperty(value = "婚姻状况", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_MARITAL_STATUS)
private String maritalStatus;
// /**
// * 婚姻状况
// */
//// @ExcelProperty(value = "婚姻状况")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_MARITAL_STATUS,refs = {"maritalStatusName"})
// private String maritalStatus;
/**
* 政治面貌
*/
@ExcelProperty(value = "政治面貌", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_POLITICAL_STATUS)
private String politicalStatus;
//
// /**
// * 政治面貌
// */
// @ExcelProperty(value = "政治面貌")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_POLITICAL_STATUS,refs = {"politicalStatusName"})
// private String politicalStatus;
/**
* 手机号码
*/
@NotBlank(message = "手机号码不能为空")
@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)
private String yearsOfServiceSegment;
// /**
// * 工龄段
// */
// @ExcelProperty(value = "工龄段")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_YEARS_SERVICE_SEGMENT,refs = {"yearsOfServiceSegmentName"})
// 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)
private String employeeType;
// /**
// * 员工类型
// */
//// @ExcelProperty(value = "员工类型")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_EMPLOYEE_TYPE,refs = {"employeeTypeName"})
// private String employeeType;
/**
* 职称情况
*/
@ExcelProperty(value = "职称情况")
private String professionalTitle;
/**
* 简历
*/
@ExcelProperty(value = "简历")
private String resume;
/**
* 用工形式
*/
// @ExcelProperty(value = "用工形式")
@ExcelProperty(value = "用工形式", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = HrConstant.HR_EMPLOYMENT_FORM)
private String employmentForm;
// /**
// * 用工形式
// */
//// @ExcelProperty(value = "用工形式")
// @UnTrans(type= UnTransType.DICTIONARY, dict= HrConstant.HR_EMPLOYMENT_FORM,refs = {"employmentFormName"})
// 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;
public void setPlate(String plate) {
this.plate = plate == null ? null : plate.trim();
}
public void setProject(String project) {
this.project = project == null ? null : project.trim();
}
public void setFirstLevelDepartment(String firstLevelDepartment) {
this.firstLevelDepartment = firstLevelDepartment == null ? null : firstLevelDepartment.trim();
}
public void setSecondLevelDepartment(String secondLevelDepartment) {
this.secondLevelDepartment = secondLevelDepartment == null ? null : secondLevelDepartment.trim();
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId == null ? null : employeeId.trim();
}
public void setJobLevel(String jobLevel) {
this.jobLevel = jobLevel == null ? null : jobLevel.trim();
}
public void setPosition(String position) {
this.position = position == null ? null : position.trim();
}
public void setPost(String post) {
this.post = post == null ? null : post.trim();
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public void setGender(String gender) {
this.gender = gender == null ? null : gender.trim();
}
public void setResumeImage(String resumeImage) {
this.resumeImage = resumeImage == null ? null : resumeImage.trim();
}
public void setIdCardNumber(String idCardNumber) {
this.idCardNumber = idCardNumber == null ? null : idCardNumber.trim();
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public void setAge(Integer age) {
this.age = age;
}
public void setAgeGroup(String ageGroup) {
this.ageGroup = ageGroup == null ? null : ageGroup.trim();
}
public void setNativePlace(String nativePlace) {
this.nativePlace = nativePlace == null ? null : nativePlace.trim();
}
public void setEthnicity(String ethnicity) {
this.ethnicity = ethnicity == null ? null : ethnicity.trim();
}
public void setMaritalStatus(String maritalStatus) {
this.maritalStatus = maritalStatus == null ? null : maritalStatus.trim();
}
public void setPoliticalStatus(String politicalStatus) {
this.politicalStatus = politicalStatus == null ? null : politicalStatus.trim();
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber == null ? null : phoneNumber.trim();
}
public void setEmergencyContact(String emergencyContact) {
this.emergencyContact = emergencyContact == null ? null : emergencyContact.trim();
}
public void setEmergencyContactPhone(String emergencyContactPhone) {
this.emergencyContactPhone = emergencyContactPhone == null ? null : emergencyContactPhone.trim();
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress == null ? null : homeAddress.trim();
}
public void setHouseholdRegistrationAddress(String householdRegistrationAddress) {
this.householdRegistrationAddress = householdRegistrationAddress == null ? null : householdRegistrationAddress.trim();
}
public void setWorkStartDate(LocalDate workStartDate) {
this.workStartDate = workStartDate;
}
public void setEntryDate(LocalDate entryDate) {
this.entryDate = entryDate;
}
public void setYearsOfService(String yearsOfService) {
this.yearsOfService = yearsOfService == null ? null : yearsOfService.trim();
}
public void setYearsOfServiceSegment(String yearsOfServiceSegment) {
this.yearsOfServiceSegment = yearsOfServiceSegment == null ? null : yearsOfServiceSegment.trim();
}
public void setEducation(String education) {
this.education = education == null ? null : education.trim();
}
public void setDegree(String degree) {
this.degree = degree == null ? null : degree.trim();
}
public void setGraduationDate(LocalDate graduationDate) {
this.graduationDate = graduationDate;
}
public void setMajor(String major) {
this.major = major == null ? null : major.trim();
}
public void setGraduateSchool(String graduateSchool) {
this.graduateSchool = graduateSchool == null ? null : graduateSchool.trim();
}
public void setEmployeeType(String employeeType) {
this.employeeType = employeeType == null ? null : employeeType.trim();
}
public void setProfessionalTitle(String professionalTitle) {
this.professionalTitle = professionalTitle == null ? null : professionalTitle.trim();
}
public void setResume(String resume) {
this.resume = resume == null ? null : resume.trim();
}
public void setEmploymentForm(String employmentForm) {
this.employmentForm = employmentForm == null ? null : employmentForm.trim();
}
public void setContractTerm(String contractTerm) {
this.contractTerm = contractTerm == null ? null : contractTerm.trim();
}
public void setContractStartDate(LocalDate contractStartDate) {
this.contractStartDate = contractStartDate;
}
public void setContractEndDate(LocalDate contractEndDate) {
this.contractEndDate = contractEndDate;
}
public void setContractExpirationReminder(LocalDate contractExpirationReminder) {
this.contractExpirationReminder = contractExpirationReminder;
}
public void setContractSigningStatus(String contractSigningStatus) {
this.contractSigningStatus = contractSigningStatus == null ? null : contractSigningStatus.trim();
}
public void setContractEntity(String contractEntity) {
this.contractEntity = contractEntity == null ? null : contractEntity.trim();
}
public void setRegularizationDate(LocalDate regularizationDate) {
this.regularizationDate = regularizationDate;
}
public void setTransferStatus(String transferStatus) {
this.transferStatus = transferStatus == null ? null : transferStatus.trim();
}
public void setRewardPunishmentStatus(String rewardPunishmentStatus) {
this.rewardPunishmentStatus = rewardPunishmentStatus == null ? null : rewardPunishmentStatus.trim();
}
public void setRemarks(String remarks) {
this.remarks = remarks == null ? null : remarks.trim();
}
public void setResignationDate(LocalDate resignationDate) {
this.resignationDate = resignationDate;
}
public void setResignationReason(String resignationReason) {
this.resignationReason = resignationReason == null ? null : resignationReason.trim();
}
}
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.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.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.anplus.hr.constant.HrFlowEnum;
import com.anplus.hr.constant.HrFlowTypeConstant;
import com.anplus.hr.domain.EmployeeFlow;
import com.anplus.hr.domain.EmployeeInfo;
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.domain.vo.SysAuditLogVo;
import com.anplus.hr.mapper.EmployeeFlowMapper;
import com.anplus.hr.mapper.EmployeeInfoMapper;
import com.anplus.hr.service.EmployeeAuditLogServ;
import com.anplus.hr.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.anplus.hr.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.anplus.hr.constant.HrFlowEnum;
import com.anplus.hr.constant.HrFlowTypeConstant;
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 com.anplus.hr.mapper.EmployeeInfoMapper;
import com.anplus.hr.service.*;
import lombok.RequiredArgsConstructor;
import org.dromara.trans.service.impl.TransService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
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.excel.image.CellImageData;
import top.binfast.common.excel.image.ExcelProcessingResult;
import top.binfast.common.excel.image.TempFileExcelImageImporter;
import top.binfast.common.log.model.SysAuditLog;
import top.binfast.common.mybatis.util.QueryUtil;
import top.binfast.common.oss.core.OssService;
import top.binfast.common.oss.entity.UploadResult;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
/**
* 员工信息Service业务层处理
*
* @author LiuBin
* @date 2025-10-28
*/
@RequiredArgsConstructor
@Service
public class EmployeeInfoServImpl extends ServiceImpl<EmployeeInfoMapper, EmployeeInfo> implements EmployeeInfoServ {
private final EmployeeInfoMapper employeeInfoMapper;
private final EmployeeSysDeptServ employeeSysDeptServ;
private final EmployeeFlowServ employeeFlowServ;
private final EmployeeAuditLogServ employeeAuditLogServ;
private final TransService transService;
private final OssService ossService;
/**
* 分页查询员工信息列表
*
* @param param 查询条件
* @return 员工信息分页列表
*/
@Override
public PageResponse<EmployeeInfoVo> queryPageList(EmployeeInfoListParam param) {
Page<EmployeeInfo> page = QueryUtil.getPage(param);
LambdaQueryWrapper<EmployeeInfo> lambdaQuery = this.buildQueryWrapper(param);
employeeInfoMapper.selectPage(page, lambdaQuery);
return QueryUtil.getPageResponse(page, MapstructUtils.convert(page.getRecords(), EmployeeInfoVo.class));
}
/**
* 查询符合条件的员工信息列表
*
* @param param 查询条件
* @return 员工信息列表
*/
@Override
public List<EmployeeInfoVo> queryList(EmployeeInfoListParam param) {
LambdaQueryWrapper<EmployeeInfo> lambdaQuery = this.buildQueryWrapper(param);
return MapstructUtils.convert(employeeInfoMapper.selectList(lambdaQuery), EmployeeInfoVo.class);
}
private LambdaQueryWrapper<EmployeeInfo> buildQueryWrapper(EmployeeInfoListParam param) {
Map<String, Object> params = param.getParams();
LambdaQueryWrapper<EmployeeInfo> lambdaQuery = Wrappers.<EmployeeInfo>lambdaQuery();
lambdaQuery.orderByDesc(EmployeeInfo::getId);
lambdaQuery.eq(StrUtil.isNotBlank(param.getPlate()), EmployeeInfo::getPlate, param.getPlate());
lambdaQuery.eq(StrUtil.isNotBlank(param.getProject()), EmployeeInfo::getProject, param.getProject());
lambdaQuery.eq(StrUtil.isNotBlank(param.getFirstLevelDepartment()), EmployeeInfo::getFirstLevelDepartment, param.getFirstLevelDepartment());
lambdaQuery.eq(StrUtil.isNotBlank(param.getSecondLevelDepartment()), EmployeeInfo::getSecondLevelDepartment, param.getSecondLevelDepartment());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEmployeeId()), EmployeeInfo::getEmployeeId, param.getEmployeeId());
lambdaQuery.eq(StrUtil.isNotBlank(param.getJobLevel()), EmployeeInfo::getJobLevel, param.getJobLevel());
lambdaQuery.eq(StrUtil.isNotBlank(param.getPosition()), EmployeeInfo::getPosition, param.getPosition());
lambdaQuery.eq(StrUtil.isNotBlank(param.getPost()), EmployeeInfo::getPost, param.getPost());
lambdaQuery.like(StrUtil.isNotBlank(param.getName()), EmployeeInfo::getName, param.getName());
lambdaQuery.eq(StrUtil.isNotBlank(param.getGender()), EmployeeInfo::getGender, param.getGender());
lambdaQuery.eq(StrUtil.isNotBlank(param.getIdCardNumber()), EmployeeInfo::getIdCardNumber, param.getIdCardNumber());
lambdaQuery.eq(param.getBirthDate() != null, EmployeeInfo::getBirthDate, param.getBirthDate());
lambdaQuery.eq(param.getAge() != null, EmployeeInfo::getAge, param.getAge());
lambdaQuery.eq(StrUtil.isNotBlank(param.getAgeGroup()), EmployeeInfo::getAgeGroup, param.getAgeGroup());
lambdaQuery.eq(StrUtil.isNotBlank(param.getNativePlace()), EmployeeInfo::getNativePlace, param.getNativePlace());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEthnicity()), EmployeeInfo::getEthnicity, param.getEthnicity());
lambdaQuery.eq(StrUtil.isNotBlank(param.getMaritalStatus()), EmployeeInfo::getMaritalStatus, param.getMaritalStatus());
lambdaQuery.eq(StrUtil.isNotBlank(param.getPoliticalStatus()), EmployeeInfo::getPoliticalStatus, param.getPoliticalStatus());
lambdaQuery.eq(StrUtil.isNotBlank(param.getPhoneNumber()), EmployeeInfo::getPhoneNumber, param.getPhoneNumber());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEmergencyContact()), EmployeeInfo::getEmergencyContact, param.getEmergencyContact());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEmergencyContactPhone()), EmployeeInfo::getEmergencyContactPhone, param.getEmergencyContactPhone());
lambdaQuery.eq(StrUtil.isNotBlank(param.getHomeAddress()), EmployeeInfo::getHomeAddress, param.getHomeAddress());
lambdaQuery.eq(StrUtil.isNotBlank(param.getHouseholdRegistrationAddress()), EmployeeInfo::getHouseholdRegistrationAddress, param.getHouseholdRegistrationAddress());
lambdaQuery.eq(param.getWorkStartDate() != null, EmployeeInfo::getWorkStartDate, param.getWorkStartDate());
// lambdaQuery.eq(param.getEntryDate() != null, EmployeeInfo::getEntryDate, param.getEntryDate());
lambdaQuery.between(params.get("entryBeginTime") != null && params.get("entryEndTime") != null,
EmployeeInfo::getEntryDate, params.get("entryBeginTime"), params.get("entryEndTime"));
lambdaQuery.eq(param.getYearsOfService() != null, EmployeeInfo::getYearsOfService, param.getYearsOfService());
lambdaQuery.eq(StrUtil.isNotBlank(param.getYearsOfServiceSegment()), EmployeeInfo::getYearsOfServiceSegment, param.getYearsOfServiceSegment());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEducation()), EmployeeInfo::getEducation, param.getEducation());
lambdaQuery.eq(StrUtil.isNotBlank(param.getDegree()), EmployeeInfo::getDegree, param.getDegree());
lambdaQuery.eq(param.getGraduationDate() != null, EmployeeInfo::getGraduationDate, param.getGraduationDate());
lambdaQuery.eq(StrUtil.isNotBlank(param.getMajor()), EmployeeInfo::getMajor, param.getMajor());
lambdaQuery.eq(StrUtil.isNotBlank(param.getGraduateSchool()), EmployeeInfo::getGraduateSchool, param.getGraduateSchool());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEmployeeType()), EmployeeInfo::getEmployeeType, param.getEmployeeType());
lambdaQuery.eq(StrUtil.isNotBlank(param.getProfessionalTitle()), EmployeeInfo::getProfessionalTitle, param.getProfessionalTitle());
lambdaQuery.eq(StrUtil.isNotBlank(param.getResume()), EmployeeInfo::getResume, param.getResume());
lambdaQuery.eq(StrUtil.isNotBlank(param.getEmploymentForm()), EmployeeInfo::getEmploymentForm, param.getEmploymentForm());
lambdaQuery.eq(StrUtil.isNotBlank(param.getContractTerm()), EmployeeInfo::getContractTerm, param.getContractTerm());
lambdaQuery.eq(param.getContractStartDate() != null, EmployeeInfo::getContractStartDate, param.getContractStartDate());
lambdaQuery.eq(param.getContractEndDate() != null, EmployeeInfo::getContractEndDate, param.getContractEndDate());
lambdaQuery.eq(param.getContractExpirationReminder() != null, EmployeeInfo::getContractExpirationReminder, param.getContractExpirationReminder());
lambdaQuery.eq(StrUtil.isNotBlank(param.getContractSigningStatus()), EmployeeInfo::getContractSigningStatus, param.getContractSigningStatus());
lambdaQuery.eq(StrUtil.isNotBlank(param.getContractEntity()), EmployeeInfo::getContractEntity, param.getContractEntity());
lambdaQuery.eq(param.getRegularizationDate() != null, EmployeeInfo::getRegularizationDate, param.getRegularizationDate());
lambdaQuery.eq(StrUtil.isNotBlank(param.getTransferStatus()), EmployeeInfo::getTransferStatus, param.getTransferStatus());
lambdaQuery.eq(StrUtil.isNotBlank(param.getRewardPunishmentStatus()), EmployeeInfo::getRewardPunishmentStatus, param.getRewardPunishmentStatus());
lambdaQuery.eq(StrUtil.isNotBlank(param.getRemarks()), EmployeeInfo::getRemarks, param.getRemarks());
lambdaQuery.eq(param.getResignationDate() != null, EmployeeInfo::getResignationDate, param.getResignationDate());
lambdaQuery.eq(StrUtil.isNotBlank(param.getResignationReason()), EmployeeInfo::getResignationReason, param.getResignationReason());
return lambdaQuery;
}
/**
* 导入员工信息列表
*
* @param list 员工信息列表
* @return 是否导入成功
*/
@Override
public Response importEmployeeList(Stream<EmployeeInfoImportVo> list, MultipartFile file) {
List<EmployeeInfoImportVo> errorList = new ArrayList<>();
List<EmployeeInfoImportVo> successList = new ArrayList<>();
CompletableFuture<ExcelProcessingResult> future = CompletableFuture.supplyAsync(() -> {
try {
return TempFileExcelImageImporter.importExcelWithAllImages(file);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
list.forEach(item -> {
// System.out.println(item.getNickName());
// item.validGroup(AddGroup.class);
// Set<ConstraintViolation<ExportDemoVo>> validate = ValidatorUtils.validate(item, AddGroup.class);
if (item.hasError()) {
// item.addError("业务错误");
errorList.add(item);
return;
}
EmployeeInfoParam employeeInfoParam = MapstructUtils.convert(item, EmployeeInfoParam.class);
if (!checkEmployeeIdCardNumberUnique(employeeInfoParam)) {
item.addError("姓名已存在");
errorList.add(item);
return;
}
successList.add(item);
});
if (CollUtil.isNotEmpty(successList)) {
Map<String, Long> deptNamesIdMap = employeeSysDeptServ.selectJoinDeptNames();
ExcelProcessingResult excelProcessingResult = future.join();
List<EmployeeInfo> insertList = new ArrayList<>(successList.size());
for (EmployeeInfoImportVo importVo : successList) {
this.handleImageToUrl(excelProcessingResult, importVo);
Long leafDeptId = deptNamesIdMap.get(buildDeptNameStr(importVo));
if (leafDeptId == null) {
importVo.addError("部门不存在");
errorList.add(importVo);
continue;
}
EmployeeInfo employeeInfo = MapstructUtils.convert(importVo, EmployeeInfo.class);
employeeInfo.setDeptId(leafDeptId);
insertList.add(employeeInfo);
}
employeeInfoMapper.insert(insertList);
// EmployeeDeptCheckAndSaveParam checkAndSaveParam =
// new EmployeeDeptCheckAndSaveParam(deptNameGroups, SecurityUtils.getCurrentUserId(), SecurityUtils.getTenantId());
// employeeDeptServ.checkAndSaveDept(checkAndSaveParam);
}
StringBuilder message;
if (CollUtil.isNotEmpty(errorList)) {
ExcelContextHolder.setErrorExist();
message = new StringBuilder("共" + errorList.size() + "条数据导入失败,错误如下:<br/>");
errorList.forEach(item -> message.append(item.defaultFailMsg()));
return Response.buildFailure(ResultCode.FAIL.getCode(), message.toString());
} else {
message = new StringBuilder("共" + successList.size() + "条数据导入成功");
Response response = Response.buildSuccess();
response.setErrMessage(message.toString());
return response;
}
}
private void handleImageToUrl(ExcelProcessingResult excelProcessingResult, EmployeeInfoImportVo importVo) {
// 处理图片,保存到OSS,替换成url
List<CellImageData> imageData = null;
if (excelProcessingResult.checkWpsOrOffice(importVo.getResumeImage())) {
imageData = excelProcessingResult.getWpsImageData(importVo.getResumeImage());
} else {
imageData = excelProcessingResult.getOfficeImageData(importVo.getLineNum());
}
if (CollUtil.isNotEmpty(imageData)) {
CellImageData cellImageData = imageData.getFirst();
UploadResult uploadResult = ossService.upload(cellImageData.getImageName(), cellImageData.getImageData());
importVo.setResumeImage(uploadResult.getUrl());
}
}
private String buildDeptNameStr(EmployeeInfoImportVo importVo) {
StringBuilder builder = new StringBuilder(importVo.getPlate() + StrUtil.SLASH + importVo.getProject());
if (StrUtil.isNotBlank(importVo.getFirstLevelDepartment())) {
builder.append(StrUtil.SLASH).append(importVo.getFirstLevelDepartment());
}
if (StrUtil.isNotBlank(importVo.getSecondLevelDepartment())) {
builder.append(StrUtil.SLASH).append(importVo.getSecondLevelDepartment());
}
return builder.toString();
}
@Override
public Boolean checkEmployeeIdCardNumberUnique(EmployeeInfoParam employee) {
boolean exist = employeeInfoMapper.exists(new LambdaQueryWrapper<EmployeeInfo>()
.eq(EmployeeInfo::getIdCardNumber, employee.getIdCardNumber())
.ne(ObjectUtil.isNotNull(employee.getId()), EmployeeInfo::getId, employee.getId()));
return !exist;
}
/**
* 查询员工信息
*
* @param id 主键
* @return 员工信息
*/
@Override
public EmployeeInfoVo queryById(Long id) {
EmployeeInfo employeeInfo = employeeInfoMapper.selectById(id);
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;
}
/**
* 新增员工信息
*
* @param param 员工信息
* @return 是否新增成功
*/
@Override
public Boolean insertByParam(EmployeeInfoParam param) {
EmployeeInfo employeeInfo = MapstructUtils.convert(param, EmployeeInfo.class);
// 检查或增加部门
Set<String> deptNameGroups = new HashSet<>();
deptNameGroups.add(employeeInfo.getFirstLevelDepartment() + StrUtil.DASHED + employeeInfo.getSecondLevelDepartment());
// EmployeeDeptCheckAndSaveParam checkAndSaveParam =
// new EmployeeDeptCheckAndSaveParam(deptNameGroups, SecurityUtils.getCurrentUserId(), SecurityUtils.getTenantId());
// employeeDeptServ.checkAndSaveDept(checkAndSaveParam);
employeeInfo.setEntryApplyStatus(HrFlowEnum.WAITING.getStatus());
return this.save(employeeInfo);
}
/**
* 修改员工信息
*
* @param param 员工信息
* @return 是否修改成功
*/
@Override
public Boolean updateByParam(EmployeeInfoParam param) {
EmployeeInfo employeeInfo = MapstructUtils.convert(param, EmployeeInfo.class);
return this.updateById(employeeInfo);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(EmployeeInfo entity) {
// 做一些数据校验,如唯一约束
}
/**
* 员工入职申请
*
* @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 param 入职申请参数
* @return 是否申请成功
*/
@Override
@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;
}
/**
* 校验并批量删除员工信息信息
*
* @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());
}
}
}
}
spring:
datasource:
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://119.184.127.215:13306/binfast?allowMultiQueries=true&characterEncoding=utf8&useSSL=true&useUnicode=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: antaikeji2019
type: com.zaxxer.hikari.HikariDataSource
logSource:
url: jdbc:mysql://119.184.127.215:13306/binfast_log?allowMultiQueries=true&characterEncoding=utf8&useSSL=true&useUnicode=true&serverTimezone=GMT%2B8
username: root
password: antaikeji2019
type: com.zaxxer.hikari.HikariDataSource
redis:
redisson:
keyPrefix:
file: classpath:redisson-dev.yml
logging:
level:
top.binfast: info
org.springframework: warn
org.mybatis.spring.mapper: error
org.apache.fury: warn
config: classpath:logback-spring-dev.xml
springdoc:
api-docs:
# 是否开启接口文档
enabled: true
# swagger-ui:
# # 持久化认证数据
# persistAuthorization: true
info:
# 标题
title: '标题:binfast管理系统_接口文档'
# 描述
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本
version: '版本号: 1.0'
# 作者信息
contact:
name: binfast
components:
# 鉴权方式配置
security-schemes:
apiKey:
type: APIKEY
in: HEADER
name: Authorization
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.管理端
packages-to-scan: top.binfast.app.admin,top.binfast.app.biz.sysbiz
- group: 2.微信端
packages-to-scan: top.binfast.app.weixin
oss:
enable: true
endpoint: https://oss-cn-hangzhou.aliyuncs.com
# 也可以采用自定义域名
# endpoint: https://rjyefa9l9.hn-bkt.clouddn.com
access-key: AASFFFKKK
access-secret: PPSFSFAFJH8783JJK
bucket: binfast
region: cn-hangzhou
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
isPrint: false
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
enable: true
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
current:
domain: http://www.test.cn:8001
\ No newline at end of file
server:
port: 9000
servlet:
context-path: /api
# 开启优雅停机,默认值:immediate 为立即关闭
shutdown: graceful
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512
# 是否分配的直接内存
direct-buffers: true
threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256
spring:
profiles:
active: dev
application:
name: binfast-admin
threads:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: true
task:
execution:
# 从 springboot 3.5 开始 spring自带线程池
# 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用
thread-name-prefix: async-
# 由spring自己初始化线程池
mode: force
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
#缓存配置
cache:
type: redis
redis:
cache-null-values: true
# redis:
# redisson:
# config: classpath:redisson.yml
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
exposure:
include: health,info,logfile
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/console.log
# mybaits-plus配置
mybatis-plus:
# 多包名使用 例如
mapper-package: com.anplus.hr.**.mapper,top.binfast.**.dao,top.binfast.**.mapper
# MyBatis Mapper所对应的XML文件位置
mapper-locations: classpath*:/mapper/**/*Mapper.xml
global-config:
# 关闭MP3.0自带的banner
banner: false
db-config:
# 主键类型 0:数据库ID自增 1.未定义 2.用户输入 3 id_worker 4.uuid 5.id_worker字符串表示
id-type: AUTO
# 默认数据库表下划线命名
table-underline: true
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# token有效期 设为一天 (必定过期) 单位: 秒
timeout: 86400
# 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
# token最低活跃时间 (指定时间无操作就过期) 单位: 秒
active-timeout: 1800
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
# 是否尝试从header里读取token
is-read-header: true
# 是否尝试从cookie里读取token
is-read-cookie: false
# token前缀
token-prefix: Bearer
# Token 风格 随机64位字符串
token-style: random-64
# 是否在初始化配置时打印版本字符画
is-print: false
# jwt秘钥
# jwt-secret-key: abcdefghijklmnopqrstuvwxyz1
tenant:
enable: true
# 多租户字段
column: tenant_id
excludes:
- sys_menu
- sys_tenant
- sys_tenant_package
- sys_role_menu
- sys_role_dept
- sys_user_post
- sys_user_role
- sys_client
- flow_spel
log:
enable: true
security:
# 排除路径
excludes:
# 静态资源
- /*.html
- /**/*.html
- /**/*.css
- /**/*.js
# 公共路径
- /favicon.ico
- /error
# swagger 文档配置
- /*/api-docs
- /*/api-docs/**
# actuator 监控配置
- /actuator
- /actuator/**
# warm-flow
- /warm-flow-ui/config
encrypt:
enable: true
appId: 123456
appSecret: 654321
rsaPrivateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsR0WQEd5DDsXC33chtNQUIW3mcA/5Ot9SuNVDrWObebK2i4OUWoeU1jopL0srtdZEmNrymCFbfBCn7p4LQTrFQhPT4lBADB6g+m6uwBa99qWTNW3Zcups/X6V0QxqkSjVCCeaR/YRoqgkUFIHTkFxyFs3nbZFGAXUnyrQb6U5BqkzcJhB54zAL6O4R6jxACpQmVBT06gjOWD/asXc0gZvv52YkIo1bwMMAjwdFfHkARn404WaPIPn6ebX07EzytKyoeIZXaG9/S1/fmihKRAOy/F+ZqElnJjBVR3iF4KkiFjSMVM8Y7mq6hcaLCGWGTB+0qZOaPcOnWxW4w6dkfXbAgMBAAECggEAF+LH18pKbTS6oaK3E0LNlr7tzGHkLROHDCKZWwlKwq80Yo/kXejRXIb5SGWIwBY1j4w76x/BnDwO2SHB4uCX4+qd8iYyJzcm9f3S48K5RHxSh58ETH5c12CsMNxrosjehu7bAs6QZPCO7H4AaYfllf+H+iWRNHI4uLqaxox8NXQm/Lb+2XWDVpfbYo1RD6vKRUFFuHK/jzzwaVrEcPQFm/xt2yEUoVfxINv5au/Pl9C38fkoLXcXZSRo+cjmcgFmz2ItUaBw299s6Y67IprO/a4ByoN9ga00IJYpksrfNpI1nICIREPu1NqnFErcKQQ7FhbK37bn42SFfhoYP3hMXQKBgQDmVjFoX6YAGY64sRE3lIwoIPmUoAloRp193rLYBEQlO6YQ/E2UDI/gS6Iy0kLqQiHVmQHoYYKxNIFx+u3OvMwLdQgozu4EXER5ayzh+IsIYHuHzsLOyATyWL9fFkNwrpBIGaEzpEQnmmMtGmGeRyxRP4LlzUVbuIL5BDWun/6d7wKBgQC/eRqhQYPcogfhHRV2XMDPxJrm8VJ7pYsl2U6p+Cbq0xjHaD2dhwambTtVEV8tyjx46atvQLg4mS8QPDLrRZGf5vPm6NIuRSGdN4gQlmP5uKAv+MVVcFmhmMSQv2QqCWzTb/D6FjHhdsUJ8x1YRslB9XUq6osAUQGllM/9k/5S1QKBgA3NRmKhsJm67lFk0spIzWkuKKZePJISASfkq0TEZKzyeQ31gFSJuClRfuOas8XDtrFM3M9m4GTr54HD7nH/4B4johyH4b1DJhs8b9EOio4y8dP+cK/hTmKTLMxu0hWzcBPR7VXh1u+kkaLHPOg2DZLEwnwwo6JOWRLAzNKs5Z3jAoGAFfVxlGTLFpaOiMapG3XvtuQ5T5sFdqC5oJGXb+7Bp9Sl1tihmFtP6+5DC7J+U+YJoWRLAOtPNU58E0SUIl9MICaAek7hK+VJwZoIxL46oP0HgfjpyK6l2N6ITIFmn1uNW4JPBJ9fARh56HY1O1aC5kmcMlvLrTGdGrxCTjaWyDECgYEAhjtj0xIT3Cel4ZSYQy16QCuRDOB1W5jJIFv2H/v+8PjdRCunl1qz6CUQE4Tjtm8knlnUUrdROHJmHLB8wVJF/XZfYC1U3t+stnBsq2clQFci/tWE0D9jSgy7UkQjKwe2nlwq1qiUMzza06w27SM+eIcYVV2ryhllyJNHbYlAya0=
rsaPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArEdFkBHeQw7Fwt93IbTUFCFt5nAP+TrfUrjVQ61jm3mytouDlFqHlNY6KS9LK7XWRJja8pghW3wQp+6eC0E6xUIT0+JQQAweoPpursAWvfalkzVt2XLqbP1+ldEMapEo1Qgnmkf2EaKoJFBSB05BcchbN522RRgF1J8q0G+lOQapM3CYQeeMwC+juEeo8QAqUJlQU9OoIzlg/2rF3NIGb7+dmJCKNW8DDAI8HRXx5AEZ+NOFmjyD5+nm19OxM8rSsqHiGV2hvf0tf35ooSkQDsvxfmahJZyYwVUd4heCpIhY0jFTPGO5quoXGiwhlhkwftKmTmj3Dp1sVuMOnZH12wIDAQAB
aesKey: 1NGHsHvI8LHtF60HI5Bqcg==
easy-trans:
#启用redis缓存 如果不用redis请设置为false
is-enable-redis: true
#启用全局翻译(拦截所有responseBody进行自动翻译),如果对于性能要求很高可关闭此配置在方法上使用注解翻译
is-enable-global: false
#启用平铺模式 手动翻译无效
is-enable-tile: true
#字典缓存放到redis 微服务模式请开启
dict-use-redis: true
#使用@RpcTrans来标记哪些类可以进行RPC翻译,默认为关闭,多团队协作推荐开启
is-enable-custom-rpc: false
# ruoyi相关的框架请开启
is-enable-map-result: false
# 反向翻译数据库类型 mysql
db-type: mysql
# Mybatis-plus 为 3.5.3.2版本以上的3.x 版本请设置为true
mp-new: true
dict:
basePackages:
- top.binfast.app.admin.services
thread-pool:
enabled: true
trace: true
captcha:
# 是否启用验证码校验
enable: false
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
--- # 默认/推荐使用sse推送
sse:
enabled: true
path: /resource/sse
--- # warm-flow工作流配置
warm-flow:
# 是否开启工作流,默认true
enabled: true
# 是否显示banner图,默认是
banner: false
# 是否开启设计器ui
ui: true
# 是否显示流程图顶部文字
top-text-show: true
# 是否渲染节点悬浮提示,默认true
node-tooltip: true
# id生成器类型, 不填默认为orm扩展自带生成器或者warm-flow内置的19位雪花算法, SnowId14:14位,SnowId15:15位, SnowFlake19:19位
key_type: SnowId14
# 是否开启逻辑删除(orm框架本身不支持逻辑删除,可通过这种方式开启)
logic_delete: true
# 默认Authorization,如果有多个token,用逗号分隔
token-name: ${sa-token.token-name},clientid
# 代码生成
codegen:
# 作者
author: LiuBin
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: top.binfast.app
# 自动去除表前缀,默认是false
autoRemovePre: false
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_
\ No newline at end of file
<?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>
<?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">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>256</queueSize>
<!-- 开启记录信息 -->
<includeCallerData>true</includeCallerData>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="info"/>
</appender>
<appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>256</queueSize>
<!-- 开启记录信息 -->
<includeCallerData>true</includeCallerData>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="error"/>
</appender>
<!-- &lt;!&ndash;nacos 心跳 INFO 屏蔽&ndash;&gt;-->
<!-- <logger name="com.alibaba.nacos" level="OFF">-->
<!-- <appender-ref ref="error"/>-->
<!-- </logger>-->
<!--name包下的类的日志输出-->
<!-- <logger name="top.binfast" additivity="true" level="DEBUG" >-->
<!-- <appender-ref ref="error" />-->
<!-- <appender-ref ref="debug" />-->
<!-- </logger>-->
<!-- 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="ASYNC-INFO"/>
<appender-ref ref="ASYNC-ERROR"/>
</root>
</configuration>
<?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.anplus.hr.mapper.EmployeeDeptMapper">
</mapper>
<?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.anplus.hr.mapper.EmployeeFlowMapper">
</mapper>
<?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.anplus.hr.mapper.EmployeeInfoMapper">
</mapper>
singleServerConfig:
address: "redis://119.184.127.215:16379"
database: 12
password: antaikeji2020
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
clientName: null
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 5
subscriptionsPerConnection: 5
connectionMinimumIdleSize: 4
connectionPoolSize: 5
threads: 0
nettyThreads: 0
transportMode: NIO
\ No newline at end of file
# p6spy 性能分析插件配置文件
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
#deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# SQL语句打印时间格式
databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 是否过滤 Log
filter=true
# 过滤 Log 时所排除的 sql 关键字,以逗号分隔
exclude=SELECT 1
package ${packageName}.controller;
import java.util.List;
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 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.validate.AddGroup;
import top.binfast.common.core.validate.EditGroup;
import top.binfast.common.core.util.ResponseUtils;
import top.binfast.common.excel.annotion.ExcelExport;
import top.binfast.common.log.annotation.PinSysLog;
import ${packageName}.domain.params.${className}.${ClassName}ListParam;
import ${packageName}.domain.params.${className}.${ClassName}Param;
import ${packageName}.domain.vo.${className}.${ClassName}Vo;
import ${packageName}.service.${className}.${ClassName}Serv;
/**
* ${functionName}
*
* @author ${author}
* @date ${datetime}
*/
@Validated
@RestController
@RequestMapping("/${moduleName}/${businessName}")
public class ${ClassName}Ctrl {
@Resource
private ${ClassName}Serv ${className}Serv;
/**
* 查询${functionName}列表
*/
@SaCheckPermission("${permissionPrefix}:list")
@GetMapping("/page")
public PageResponse<${ClassName}Vo> pageList(${ClassName}ListParam param) {
return ${className}Serv.queryPageList(param);
}
/**
* 导出${functionName}列表
*/
@ExcelExport
@SaCheckPermission("${permissionPrefix}:export")
@PinSysLog(value = "${functionName}", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public List<${ClassName}Vo> export(${ClassName}ListParam param) {
return ${className}Serv.queryList(param);
}
/**
* 获取${functionName}详细信息
*
* @param ${pkColumn.javaField} 主键
*/
@SaCheckPermission("${permissionPrefix}:query")
@GetMapping("/{${pkColumn.javaField}}")
public SingleResponse<${ClassName}Vo> getDetail(@PathVariable @Min(1)
${pkColumn.javaType} ${pkColumn.javaField}) {
return SingleResponse.of(${className}Serv.queryById(${pkColumn.javaField}));
}
/**
* 新增${functionName}
*/
@SaCheckPermission("${permissionPrefix}:add")
@PinSysLog(value = "${functionName}", businessType = BusinessType.INSERT)
@PostMapping()
public Response add(@Validated(AddGroup.class) @RequestBody ${ClassName}Param param) {
return ResponseUtils.ofResult(${className}Serv.insertByParam(param));
}
/**
* 修改${functionName}
*/
@SaCheckPermission("${permissionPrefix}:edit")
@PinSysLog(value = "${functionName}", businessType = BusinessType.UPDATE)
@PutMapping()
public Response edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Param param) {
return ResponseUtils.ofResult(${className}Serv.updateByParam(param));
}
/**
* 删除${functionName}
*
* @param ${pkColumn.javaField}s 主键串
*/
@SaCheckPermission("${permissionPrefix}:remove")
@PinSysLog(value = "${functionName}", businessType = BusinessType.DELETE)
@DeleteMapping("/{${pkColumn.javaField}s}")
public Response remove(@NotEmpty(message = "主键不能为空")
@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
return ResponseUtils.ofResult(${className}Serv.delByIds(List.of(${pkColumn.javaField}s)));
}
}
\ No newline at end of file
package ${packageName}.domain.model.${className};
#foreach ($column in $columns)
#if($column.javaField=='tenantId')
#set($IsTenant=1)
#end
#end
#if($IsTenant==1)
import top.binfast.common.mybatis.bean.model.TenantModel;
#else
import top.binfast.common.mybatis.bean.model.BaseModel;
#end
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.EqualsAndHashCode;
#foreach ($import in $importList)
import ${import};
#end
import java.io.Serial;
/**
* ${functionName}对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
#if($IsTenant==1)
#set($Entity="TenantModel")
#else
#set($Entity="BaseModel")
#end
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@TableName("${tableName}")
public class ${ClassName} extends ${Entity} {
@Serial
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField))
/**
* $column.columnComment
*/
#if($column.javaField=='deleted')
@TableLogic
#end
#if($column.javaField=='version')
@Version
#end
#if($column.isPk==1)
@TableId(value = "$column.columnName")
#end
private $column.javaType $column.javaField;
#end
#end
}
package ${packageName}.mapper.${className};
import ${packageName}.domain.model.${className}.${ClassName};
import top.binfast.common.mybatis.mapper.BinBaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* ${functionName}Mapper接口
*
* @author ${author}
* @date ${datetime}
*/
@Mapper
public interface ${ClassName}Mapper extends BinBaseMapper<${ClassName}> {
}
package ${packageName}.domain.params.${className};
import lombok.Getter;
import lombok.Setter;
import top.binfast.common.core.bean.params.PageQueryParam;
import java.util.HashMap;
import java.util.Map;
#foreach ($import in $importList)
import ${import};
#end
/**
* ${functionName}分页对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
@Getter
@Setter
public class ${ClassName}ListParam extends PageQueryParam {
#foreach ($column in $columns)
#if(($column.query))
/**
* $column.columnComment
*/
private $column.javaType $column.javaField;
#end
#end
private Map<String, Object> params = new HashMap<>();
}
package ${packageName}.domain.params.${className};
import ${packageName}.domain.model.${ClassName};
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.*;
#foreach ($import in $importList)
import ${import};
#end
/**
* ${functionName}业务对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
@Data
@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
public class ${ClassName}Param {
#foreach ($column in $columns)
#if(($column.isPk == 1 || !$table.isSuperColumn($column.javaField)) && ($column.query || $column.insert || $column.edit))
/**
* $column.columnComment
*/
#if($column.insert && $column.edit)
#set($Group="AddGroup.class, EditGroup.class")
#elseif($column.insert)
#set($Group="AddGroup.class")
#elseif($column.edit)
#set($Group="EditGroup.class")
#end
#if($column.required)
#if($column.javaType == 'String')
@NotBlank(message = "$column.columnComment不能为空", groups = { $Group })
#else
@NotNull(message = "$column.columnComment不能为空", groups = { $Group })
#end
#end
private $column.javaType $column.javaField;
#end
#end
}
package ${packageName}.${className}.service;
import ${packageName}.domain.model.${className}.${ClassName};
import ${packageName}.domain.vo.${className}.${ClassName}Vo;
import ${packageName}.domain.params.${className}.${ClassName}ListParam;
import ${packageName}.domain.params.${className}.${ClassName}Param;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* ${functionName}Service接口
*
* @author ${author}
* @date ${datetime}
*/
public interface ${ClassName}Serv extends IService<${ClassName}> {
/**
* 分页查询${functionName}列表
*
* @param param 查询条件
* @return ${functionName}分页列表
*/
PageResponse<${ClassName}Vo> queryPageList(${ClassName}ListParam param);
/**
* 查询符合条件的${functionName}列表
*
* @param param 查询条件
* @return ${functionName}列表
*/
List<${ClassName}Vo> queryList(${ClassName}ListParam param);
/**
* 查询${functionName}
*
* @param ${pkColumn.javaField} 主键
* @return ${functionName}
*/
${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
/**
* 新增${functionName}
*
* @param param ${functionName}
* @return 是否新增成功
*/
Boolean insertByParam(${ClassName}Param param);
/**
* 修改${functionName}
*
* @param param ${functionName}
* @return 是否修改成功
*/
Boolean updateByParam(${ClassName}Param param);
/**
* 校验并批量删除${functionName}信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean delByIds(List<${pkColumn.javaType}> ids);
}
package ${packageName}.service.${className}.impl;
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.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.binfast.common.core.util.MapstructUtils;
import top.binfast.common.mybatis.util.QueryUtil;
import ${packageName}.domain.model.${className}.${ClassName};
import ${packageName}.domain.vo.${className}.${ClassName}Vo;
import ${packageName}.domain.params.${className}.${ClassName}ListParam;
import ${packageName}.domain.params.${className}.${ClassName}Param;
import ${packageName}.mapper.${className}.${ClassName}Mapper;
import ${packageName}.service.${className}.${ClassName}Serv;
#if($table.tree)
import top.binfast.common.seed.base.DataObjectUtil;
#end
import java.util.List;
/**
* ${functionName}Service业务层处理
*
* @author ${author}
* @date ${datetime}
*/
@RequiredArgsConstructor
@Service
public class ${ClassName}ServImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}> implements ${ClassName}Serv {
private final ${ClassName}Mapper ${className}Mapper;
/**
* 分页查询${functionName}列表
*
* @param param 查询条件
* @return ${functionName}分页列表
*/
@Override
public PageResponse<${ClassName}Vo> queryPageList(${ClassName}ListParam param) {
Page<${ClassName}> page = QueryUtil.getPage(param);
LambdaQueryWrapper<${ClassName}> lambdaQuery = this.buildQueryWrapper(param);
${className}Mapper.selectPage(page, lambdaQuery);
#if($table.crud)
return QueryUtil.getPageResponse(page, MapstructUtils.convert(page.getRecords(), ${ClassName}Vo.class));
#elseif($table.tree)
List<${ClassName}Vo> ${className}VoList = DataObjectUtil.generateTree(MapstructUtils.convert(page.getRecords(), ${ClassName}Vo.class));
return QueryUtil.getPageResponse(${className}VoList, page);
#end
}
/**
* 查询符合条件的${functionName}列表
*
* @param param 查询条件
* @return ${functionName}列表
*/
@Override
public List<${ClassName}Vo> queryList(${ClassName}ListParam param) {
LambdaQueryWrapper<${ClassName}> lambdaQuery = this.buildQueryWrapper(param);
return MapstructUtils.convert(${className}Mapper.selectList(lambdaQuery), ${ClassName}Vo.class);
}
private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}ListParam param) {
LambdaQueryWrapper<${ClassName}> lambdaQuery = Wrappers.<${ClassName}>lambdaQuery();
#foreach($column in $columns)
#if($column.query)
#set($queryType=$column.queryType)
#set($javaField=$column.javaField)
#set($javaType=$column.javaType)
#set($columnName=$column.columnName)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($mpMethod=$column.queryType.toLowerCase())
#if($queryType != 'BETWEEN')
#if($javaType == 'String')
#set($condition='StrUtil.isNotBlank(param.get'+$AttrName+'())')
#else
#set($condition='param.get'+$AttrName+'() != null')
#end
lambdaQuery.$mpMethod($condition, ${ClassName}::get$AttrName, param.get$AttrName());
#else
lambdaQuery.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null,
${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName"));
#end
#end
###if($column.javaField == 'deleted')
## lambdaQuery.eq(${ClassName}::getDeleted, DeletedStatus.UN_DELETED);
###end
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#if($column.isPk==1)
lambdaQuery.orderByDesc(${ClassName}::get$AttrName);
#end
#end
return lambdaQuery;
}
/**
* 查询${functionName}
*
* @param ${pkColumn.javaField} 主键
* @return ${functionName}
*/
@Override
public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){
${ClassName} ${className} = ${className}Mapper.selectById(${pkColumn.javaField});
return MapstructUtils.convert(${className}, ${ClassName}Vo.class);
}
/**
* 新增${functionName}
*
* @param param ${functionName}
* @return 是否新增成功
*/
@Override
public Boolean insertByParam(${ClassName}Param param) {
${ClassName} ${className} = MapstructUtils.convert(param, ${ClassName}.class);
return this.save(${className});
}
/**
* 修改${functionName}
*
* @param param ${functionName}
* @return 是否修改成功
*/
@Override
public Boolean updateByParam(${ClassName}Param param) {
${ClassName} ${className} = MapstructUtils.convert(param, ${ClassName}.class);
return this.updateById(${className});
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(${ClassName} entity){
// 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除${functionName}信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = {Exception.class})
public Boolean delByIds(List<${pkColumn.javaType}> ids) {
//做一些业务上的校验,判断是否需要校验
return this.removeByIds(ids);
}
}
package ${packageName}.domain.vo.${className};
#foreach ($import in $importList)
import ${import};
#end
import ${packageName}.domain.model.${ClassName};
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.ExcelIgnore;
import top.binfast.common.excel.annotion.ExcelDictFormat;
import top.binfast.common.excel.converters.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* ${functionName}视图对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ${ClassName}.class)
public class ${ClassName}Vo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if($column.list)
/**
* $column.columnComment
*/
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if(${column.dictType} && ${column.dictType} != '')
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "${column.dictType}")
#elseif($parentheseIndex != -1)
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
#elseif($column.isPk==1)
#else
@ExcelProperty(value = "${comment}")
#end
private $column.javaType $column.javaField;
#if($column.htmlType == "imageUpload")
/**
* ${column.columnComment}Url
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
private String ${column.javaField}Url;
#end
#end
#end
}
-- 菜单 SQL
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[0]}, '${functionName}', ${parentMenuId}, '${ClassName}List', ${table.menuIds[0]}, '/0/${parentMenuId}/${table.menuIds[0]}/', 1, 0, '${permissionPrefix}:list', 2, 1, 1, 0, 1, sysdate(), null, null);
-- 按钮 SQL
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '', 1, '/0/${parentMenuId}/${table.menuIds[0]}/${table.menuIds[1]}/', 2, 1, '${permissionPrefix}:query', 3, 0, 0, 0, 1, sysdate(), null, null);
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '', 2, '/0/${parentMenuId}/${table.menuIds[0]}/${table.menuIds[2]}/', 2, 1, '${permissionPrefix}:add', 3, 0, 0, 0, 1, sysdate(), null, null);
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '', 3, '/0/${parentMenuId}/${table.menuIds[0]}/${table.menuIds[3]}/', 2, 1, '${permissionPrefix}:edit', 3, 0, 0, 0, 1, sysdate(), null, null);
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '', 4, '/0/${parentMenuId}/${table.menuIds[0]}/${table.menuIds[4]}/', 2, 1, '${permissionPrefix}:remove', 3, 0, 0, 0, 1, sysdate(), null, null);
insert into sys_menu (id, name, parent_id, page_name, order_num, node_path, type, is_leaf, perms, level, visible, is_cache, deleted, create_by, create_time, update_by, update_time)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '', 5, '/0/${parentMenuId}/${table.menuIds[0]}/${table.menuIds[5]}/', 2, 1, '${permissionPrefix}:export', 3, 0, 0, 0, 1, sysdate(), null, null);
-- 管理员菜单关联 SQL
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[0]}, ${table.menuIds[0]}, 1);
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[1]}, ${table.menuIds[1]}, 1);
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[2]}, ${table.menuIds[2]}, 1);
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[3]}, ${table.menuIds[3]}, 1);
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[4]}, ${table.menuIds[4]}, 1);
INSERT INTO sys_role_menu (id, menu_id, role_id)
VALUES (${table.menuRoleIds[5]}, ${table.menuIds[5]}, 1);
\ No newline at end of file
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace ${BusinessName}Api {
export interface ${BusinessName} extends BaseModel {
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField) && ($column.insert || $column.edit))
/**
* $column.columnComment
*/
$column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) number;
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
#elseif($column.javaType == 'Boolean') boolean;
#else string;#end
#end
#end
}
}
/**
* 查询${functionName}列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/${moduleName}/${businessName}/page', { params });
}
/**
* 查询${functionName}详细
* @param ${pkColumn.javaField}
*/
export function apiDetail(${pkColumn.javaField}: number) {
return requestClient.get(`/${moduleName}/${businessName}/${${pkColumn.javaField}}`);
}
/**
* 新增${functionName}
* @param data
*/
export function apiAdd(data: ${BusinessName}Api.${BusinessName}) {
return requestClient.post('/${moduleName}/${businessName}', data);
}
/**
* 修改${functionName}
* @param data
*/
export function apiUpdate(data: ${BusinessName}Api.${BusinessName}) {
return requestClient.put('/${moduleName}/${businessName}', data);
}
/**
* 删除${functionName}
* @param ${pkColumn.javaField}
*/
export function apiDelete(${pkColumn.javaField}: Array<number> | number) {
return requestClient.delete(`/${moduleName}/${businessName}/${${pkColumn.javaField}}`);
}
/**
* 导出${functionName}
* @param params
*/
export function apiExport(params: PageQuery) {
return commonExport('/${moduleName}/${businessName}/export', params);
}
import { BaseModel, QueryParam } from '@/api/model/baseModel';
export interface ${BusinessName}VO extends BaseModel {
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField) && $column.list)
/**
* $column.columnComment
*/
$column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
#elseif($column.javaType == 'Boolean') boolean;
#else string;
#end
#if($column.htmlType == "imageUpload")
/**
* ${column.columnComment}Url
*/
${column.javaField}Url: string;
#end
#end
#end
#if ($table.tree)
/**
* 子对象
*/
children: ${BusinessName}VO[];
#end
}
export interface ${BusinessName}Param extends BaseModel {
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField) && ($column.insert || $column.edit))
/**
* $column.columnComment
*/
$column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
#elseif($column.javaType == 'Boolean') boolean;
#else string;
#end
#end
#end
}
export interface ${BusinessName}Query extends QueryParam{
#foreach ($column in $columns)
#if($column.query)
/**
* $column.columnComment
*/
$column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
#elseif($column.javaType == 'Boolean') boolean;
#else string;
#end
#end
#end
/**
* 日期范围参数等
*/
params?: any;
}
import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ${BusinessName}Api } from '#/api/${moduleName}/${businessName}';
import { DictEnum } from '@vben/constants';
import { getDictOptions, getTagDicts } from '#/utils/dict';
export const querySchema: VbenFormSchema[] = [
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
{
component: 'Input',
fieldName: '${column.javaField}',
label: '${comment}',
},
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType && $dictType)
{
component: 'Select',
componentProps: {
#if($dictType == "SYS_COMMON_STATUS")
options: getDictOptions(DictEnum.${dictType}, true),
#else
options: getDictOptions(DictEnum.${dictType}),
#end
},
fieldName: '${column.javaField}',
label: '${comment}',
},
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
{
component: 'Select',
componentProps: {
},
fieldName: '${column.javaField}',
label: '${comment}',
},
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
{
component: 'DatePicker',
fieldName: '${column.javaField}',
label: '${comment}',
},
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
{
component: 'RangePicker',
fieldName: '${column.javaField}',
label: '${comment}',
},
#end
#end
#end
];
export function useColumns(
onActionClick: OnActionClickFn<${BusinessName}Api.${BusinessName}>,
): VxeTableGridOptions<${BusinessName}Api.${BusinessName}>['columns'] {
return [
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if(!$column.pk)
#if($column.list && $column.htmlType == "datetime")
{
title: '${comment}',
field: '${javaField}',
formatter: 'formatDateTime',
},
#elseif($column.list && $column.htmlType == "imageUpload")
{
title: '${comment}',
field: '${javaField}',
slots: { default: '${javaField}' },
},
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio") && $column.dictType && "" != $column.dictType)
{
title: '${comment}',
field: '${javaField}',
#if($column.dictType == "SYS_COMMON_STATUS")
cellRender: { name: 'CellTag', options: [getTagDicts(DictEnum.${column.dictType}, true)] },
#else
cellRender: { name: 'CellTag', options: [getTagDicts(DictEnum.${column.dictType})] },
#end
},
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio") && !$column.dictType)
{
title: '${comment}',
field: '${javaField}',
cellRender: { name: 'CellTag', options: [getTagDicts()] },
},
#elseif($column.list && "" != $javaField)
{
title: '${comment}',
field: '${javaField}',
},
#end
#end
#end
{
align: 'right',
cellRender: {
attrs: {
nameField: 'name',
nameTitle: '${functionName}',
onClick: onActionClick,
},
name: 'CellOperation',
options: [
{
code: 'edit',
accessCode: ['${permissionPrefix}:edit'],
}, // 默认的编辑按钮
{
code: 'delete',
accessCode: ['${permissionPrefix}:remove'],
}, // 默认的删除按钮
],
},
field: 'action',
fixed: 'right',
headerAlign: 'center',
resizable: false,
showOverflow: false,
title: '操作',
width: 'auto',
},
];
}
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { ${BusinessName}Api } from '#/api/${moduleName}/${businessName}';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { DictEnum } from '@vben/constants';
import { getVxePopupContainer } from '@vben/utils';
import { useVbenForm, z } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/${moduleName}/${businessName}';
import { getDictOptions } from '#/utils/dict';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const formData = ref<${BusinessName}Api.${BusinessName}>();
const formSchema: VbenFormSchema[] = [
#foreach($column in $columns)
#set($field=$column.javaField)
#if(($column.insert || $column.edit) && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
{
#if($column.htmlType == "input")
component: 'Input',
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "imageUpload")
component: 'ImageUpload',
componentProps: {
maxCount: 1,
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "fileUpload")
component: 'FileUpload',
componentProps: {
maxCount: 1,
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "editor")
component: 'RichTextarea',
componentProps: {
width: '100%',
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "select" && "" != $dictType && $dictType)
component: 'Select',
componentProps: {
getVxePopupContainer,
#if($dictType == "SYS_COMMON_STATUS")
options: getDictOptions(DictEnum.${dictType}, true),
#else
options: getDictOptions(DictEnum.${dictType}),
#end
},
fieldName: '${field}',
label: '${comment}',
rules: 'selectRequired',
#elseif($column.htmlType == "select" && !$dictType)
component: 'Select',
componentProps: {
},
fieldName: '${field}',
label: '${comment}',
rules: 'selectRequired',
#elseif($column.htmlType == "checkbox" && "" != $dictType && $dictType)
component: 'CheckboxGroup',
componentProps: {
getVxePopupContainer,
#if($dictType == "SYS_COMMON_STATUS")
options: getDictOptions(DictEnum.${dictType}, true),
#else
options: getDictOptions(DictEnum.${dictType}),
#end
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "checkbox" && !$dictType)
component: 'CheckboxGroup',
componentProps: {
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "radio" && "" != $dictType && $dictType)
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
#if($dictType == "SYS_COMMON_STATUS")
options: getDictOptions(DictEnum.${dictType}, true),
#else
options: getDictOptions(DictEnum.${dictType}),
#end
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "radio" && !$dictType)
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
},
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "datetime")
component: 'DatePicker',
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#elseif($column.htmlType == "textarea")
component: 'Textarea',
fieldName: '${field}',
label: '${comment}',
rules: 'required',
#end
},
#end
#end
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [Drawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
const data = drawerApi.getData<${BusinessName}Api.${BusinessName}>();
if (data) {
formData.value = data;
await formApi.setValues(formData.value);
} else {
formApi.resetForm();
}
await markInitialized();
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
drawerApi.lock();
const data = await formApi.getValues<${BusinessName}Api.${BusinessName}>();
try {
await (formData.value?.id
? apiUpdate({ id: formData.value.id, ...data })
: apiAdd(data));
resetInitialized();
emit('success');
drawerApi.close();
} finally {
drawerApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getDrawerTitle = computed(() =>
formData.value?.id ? '修改${functionName}' : '新增${functionName}',
);
</script>
<template>
<Drawer class="w-full max-w-[800px]" :title="getDrawerTitle">
<BasicForm class="mx-4" />
</Drawer>
</template>
<script lang="ts" setup>
import type { VbenFormProps } from '@vben/common-ui';
import type {
OnActionClickParams,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { ${BusinessName}Api } from '#/api/${moduleName}/${businessName}';
import { Page, useVbenDrawer } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiDelete, apiExport, apiPage } from '#/api/${moduleName}/${businessName}';
import { commonDownloadExcel } from '#/utils/file/download';
import { querySchema, useColumns } from './data';
import Form from './form.vue';
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const [FormDrawer, formDrawerApi] = useVbenDrawer({
connectedComponent: Form,
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
columns: useColumns(onActionClick),
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: true,
},
} as VxeTableGridOptions,
});
function onActionClick({ code, row }: OnActionClickParams<${BusinessName}Api.${BusinessName}>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
case 'edit': {
onEdit(row);
break;
}
default: {
break;
}
}
}
function onRefresh() {
gridApi.query();
}
function onEdit(row: ${BusinessName}Api.${BusinessName}) {
formDrawerApi.setData(row).open();
}
function onCreate() {
formDrawerApi.setData({}).open();
}
function onDelete(row: ${BusinessName}Api.${BusinessName}) {
const hideLoading = message.loading({
content: `正在删除${row.name}...`,
duration: 0,
key: 'action_process_msg',
});
apiDelete(row.id || 0)
.then(() => {
message.success({
content: `${row.name}删除成功`,
key: 'action_process_msg',
});
onRefresh();
})
.catch(() => {
hideLoading();
});
}
function handleDownloadExcel() {
commonDownloadExcel(apiExport, '${functionName}', gridApi.formApi.form.values);
}
</script>
<template>
<Page auto-content-height>
<FormDrawer @success="onRefresh" />
<Grid table-title="${functionName}列表">
<template #toolbar-tools>
<Space>
<Button
v-access:code="['${permissionPrefix}:export']"
@click="handleDownloadExcel"
>
导出
</Button>
<Button
v-access:code="['${permissionPrefix}:add']"
type="primary"
@click="onCreate"
>
<Plus class="size-5" />
新增
</Button>
</Space>
</template>
#foreach($column in $columns)
#set($javaField=$column.javaField)
#if($column.list && $column.htmlType == "imageUpload")
<template #${javaField}="{ row }">
<img style="width: 21px;" :src="row.${javaField}" />
</template>
#end
#end
</Grid>
</Page>
</template>
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { ${BusinessName}Api } from '#/api/${moduleName}/${businessName}';
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/${moduleName}/${businessName}';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const formData = ref<${BusinessName}Api.${BusinessName}>();
const formSchema: VbenFormSchema[] = [
#foreach($column in $columns)
#set($field=$column.javaField)
#if(($column.insert || $column.edit) && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
{
#if($column.htmlType == "input")
component: 'Input',
#elseif($column.htmlType == "imageUpload")
component: 'ImageUpload',
componentProps: {
maxCount: 1,
},
#elseif($column.htmlType == "fileUpload")
component: 'FileUpload',
componentProps: {
maxCount: 1,
},
#elseif($column.htmlType == "editor")
component: 'RichTextarea',
componentProps: {
width: '100%',
},
#elseif($column.htmlType == "select" && "" != $dictType && $dictType)
component: 'Select',
componentProps: {
getVxePopupContainer,
options: getDictOptions('${dictType}'),
},
#elseif($column.htmlType == "select" && !$dictType)
component: 'Select',
componentProps: {
},
#elseif($column.htmlType == "checkbox" && "" != $dictType && $dictType)
component: 'CheckboxGroup',
componentProps: {
getVxePopupContainer,
options: getDictOptions('${dictType}'),
},
#elseif($column.htmlType == "checkbox" && !$dictType)
component: 'CheckboxGroup',
componentProps: {
},
#elseif($column.htmlType == "radio" && "" != $dictType && $dictType)
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
options: getDictOptions('${dictType}'),
},
#elseif($column.htmlType == "radio" && !$dictType)
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
},
#elseif($column.htmlType == "datetime")
component: 'DatePicker',
#elseif($column.htmlType == "textarea")
component: 'Textarea',
#end
fieldName: '${field}',
label: '${comment}',
rules: 'required',
},
#end
#end
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [BasicModal, modalApi] = useVbenModal({
fullscreenButton: false,
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
modalApi.modalLoading(true);
const data = modalApi.getData<${BusinessName}Api.${BusinessName}>();
if (data) {
formData.value = data;
await formApi.setValues(formData.value);
}
await markInitialized();
modalApi.modalLoading(false);
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
modalApi.lock();
const data = await formApi.getValues<${BusinessName}Api.${BusinessName}>();
try {
await (formData.value?.id
? apiUpdate({ id: formData.value.id, ...data })
: apiAdd(data));
resetInitialized();
emit('success');
modalApi.close();
} finally {
modalApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getModalTitle = computed(() =>
formData.value?.id ? '修改${functionName}' : '新增${functionName}',
);
</script>
<template>
<BasicModal :title="getModalTitle">
<BasicForm class="mx-4" />
</BasicModal>
</template>
<?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="${packageName}.mapper.${className}.${ClassName}Mapper">
</mapper>
package com.anplus.hr;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
}
<?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>
<groupId>com.anplus.hr</groupId>
<artifactId>an-plus-hr</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>an-plus-hr</name>
<description>an-plus-hr</description>
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
<spring-boot.version>3.5.7</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<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.5</binfast.version>
<lombok.version>1.18.38</lombok.version>
</properties>
<modules>
<module>admin</module>
</modules>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>top.binfast</groupId>
<artifactId>common-bom</artifactId>
<version>${binfast.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering>
<!-- <excludes>-->
<!-- <exclude>**/*.xlsx</exclude>-->
<!-- <exclude>**/*.xls</exclude>-->
<!-- </excludes>-->
</resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
</resources>
<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>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<target>${java.version}</target>
<source>${java.version}</source>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<!-- <path>-->
<!-- <groupId>org.mapstruct</groupId>-->
<!-- <artifactId>mapstruct-processor</artifactId>-->
<!-- <version>${org.mapstruct.version}</version>-->
<!-- </path>-->
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>${therapi-javadoc.version}</version>
</path>
</annotationProcessorPaths>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
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