Browse Source

租户部分

zhaopeiqing 9 months ago
parent
commit
4cd438a73f
49 changed files with 2764 additions and 47 deletions
  1. 1 0
      pom.xml
  2. 25 0
      yudao-module-personnel/pom.xml
  3. 34 0
      yudao-module-personnel/yudao-module-employee-api/pom.xml
  4. 32 0
      yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/EmployeeApi.java
  5. 43 0
      yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeCreateReqDTO.java
  6. 43 0
      yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeQueryReqDTO.java
  7. 181 0
      yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeRespDTO.java
  8. 17 0
      yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/enums/ErrorCodeConstants.java
  9. 96 0
      yudao-module-personnel/yudao-module-employee-biz/pom.xml
  10. 41 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/api/employeeinfo/EmployeeApiImpl.java
  11. 97 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/EmployeeContractInfoController.java
  12. 94 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/EmployeeInfoController.java
  13. 52 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoPageReqVO.java
  14. 59 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoRespVO.java
  15. 49 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoSaveReqVO.java
  16. 149 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoPageReqVO.java
  17. 151 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoQueryReqVO.java
  18. 183 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoRespVO.java
  19. 143 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoSaveReqVO.java
  20. 69 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/dataobject/employeeinfo/EmployeeContractInfoDO.java
  21. 191 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/dataobject/employeeinfo/EmployeeInfoDO.java
  22. 33 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/mysql/employeeinfo/EmployeeContractInfoMapper.java
  23. 70 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/mysql/employeeinfo/EmployeeInfoMapper.java
  24. 9 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/package-info.java
  25. 56 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeContractInfoService.java
  26. 71 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeContractInfoServiceImpl.java
  27. 72 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoService.java
  28. 89 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoServiceImpl.java
  29. 12 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/resources/mapper/employeeinfo/EmployeeInfoMapper.xml
  30. 274 0
      yudao-module-personnel/yudao-module-employee-biz/src/test/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoServiceImplTest.java
  31. 2 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
  32. 2 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java
  33. 5 0
      yudao-module-system/yudao-module-system-biz/pom.xml
  34. 24 5
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java
  35. 36 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantJoinReqVO.java
  36. 6 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java
  37. 2 8
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java
  38. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/tenant/UserTenantRelateSaveReqVO.java
  39. 10 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java
  40. 0 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
  41. 4 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
  42. 3 10
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java
  43. 17 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java
  44. 138 15
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
  45. 17 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/UserTenantRelateService.java
  46. 50 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/UserTenantRelateServiceImpl.java
  47. 7 0
      yudao-server/pom.xml
  48. 1 0
      yudao-server/src/main/resources/application-local.yaml
  49. 3 0
      yudao-server/src/main/resources/application.yaml

+ 1 - 0
pom.xml

@@ -23,6 +23,7 @@
         <module>yudao-module-mall</module>
         <module>yudao-module-crm</module>
         <module>yudao-module-erp</module>
+        <module>yudao-module-personnel</module>
     </modules>
 
     <name>${project.artifactId}</name>

+ 25 - 0
yudao-module-personnel/pom.xml

@@ -0,0 +1,25 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>yudao-module-personnel</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+
+    <description>
+        人事大模块
+    </description>
+    <modules>
+        <module>yudao-module-employee-api</module>
+        <module>yudao-module-employee-biz</module>
+    </modules>
+
+</project>

+ 34 - 0
yudao-module-personnel/yudao-module-employee-api/pom.xml

@@ -0,0 +1,34 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>cn.iocoder.boot</groupId>
+        <artifactId>yudao-module-personnel</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>yudao-module-employee-api</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        employee 模块 API,暴露给其它模块调用
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-common</artifactId>
+        </dependency>
+
+        <!-- 参数校验 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>

+ 32 - 0
yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/EmployeeApi.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.employee.api;
+
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeCreateReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeQueryReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+
+import javax.validation.Valid;
+
+/**
+ * 员工 API 接口
+ *
+ * @author 芋道源码
+ */
+public interface EmployeeApi {
+
+    /**
+     * 创建员工
+     *
+     * @param reqDTO
+     * @return
+     */
+    Long createEmployee(@Valid EmployeeCreateReqDTO reqDTO);
+
+    /**
+     * 查询员工
+     *
+     * @param reqDTO
+     * @return
+     */
+    EmployeeRespDTO getEmployee(@Valid EmployeeQueryReqDTO reqDTO);
+
+}

+ 43 - 0
yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeCreateReqDTO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.employee.api.dto;
+
+import lombok.Data;
+
+/**
+ * 员工信息 Request DTO
+ *
+ * @author zhaopq
+ */
+@Data
+public class EmployeeCreateReqDTO {
+
+    /**
+     * 姓名
+     */
+    private String name;
+    /**
+     * 用户头像
+     */
+    private String avatar;
+    /**
+     * 员工状态
+     */
+    private Integer employeeStatus;
+    /**
+     * 状态
+     */
+    private Integer status;
+    /**
+     * 租户编目
+     */
+    private Long tenantId;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+}

+ 43 - 0
yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeQueryReqDTO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.employee.api.dto;
+
+import lombok.Data;
+
+/**
+ * 员工信息 Request DTO
+ *
+ * @author zhaopq
+ */
+@Data
+public class EmployeeQueryReqDTO {
+
+    /**
+     * 姓名
+     */
+    private String name;
+    /**
+     * 用户头像
+     */
+    private String avatar;
+    /**
+     * 员工状态
+     */
+    private Integer employeeStatus;
+    /**
+     * 状态
+     */
+    private Integer status;
+    /**
+     * 租户编目
+     */
+    private Long tenantId;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+}

+ 181 - 0
yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/api/dto/EmployeeRespDTO.java

@@ -0,0 +1,181 @@
+package cn.iocoder.yudao.module.employee.api.dto;
+
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 员工 Response DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class EmployeeRespDTO {
+
+    /**
+     * 员工ID
+     */
+    private Long id;
+    /**
+     * 业务UUID
+     */
+    private String infoId;
+    /**
+     * 员工编号
+     */
+    private String employeeNumber;
+    /**
+     * 姓名
+     */
+    private String name;
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+    /**
+     * 手机号
+     */
+    private String phone;
+    /**
+     * 头像地址
+     */
+    private String avatar;
+    /**
+     * 电子邮箱
+     */
+    private String email;
+    /**
+     * 职位
+     */
+    private String position;
+    /**
+     * 职位编号
+     */
+    private Long postId;
+    /**
+     * 入职时间
+     */
+    private LocalDate entryDate;
+    /**
+     * 试用期到期时间
+     */
+    private LocalDate probationEndDate;
+    /**
+     * 工作地点
+     */
+    private String workLocation;
+    /**
+     * 员工状态
+     */
+    private Integer employeeStatus;
+    /**
+     * 性别
+     */
+    private String gender;
+    /**
+     * 出生日期
+     */
+    private LocalDate birthDate;
+    /**
+     * 婚姻状况
+     */
+    private String marriageStatus;
+    /**
+     * 身份证号
+     */
+    private String idCardNumber;
+    /**
+     * 身份证地址
+     */
+    private String idCardAddress;
+    /**
+     * 户口类型
+     */
+    private String householdType;
+    /**
+     * 户口所在地
+     */
+    private String householdLocation;
+    /**
+     * 学历
+     */
+    private String educationLevel;
+    /**
+     * 专业
+     */
+    private String major;
+    /**
+     * 毕业院校
+     */
+    private String graduationSchool;
+    /**
+     * 毕业时间
+     */
+    private LocalDate graduationDate;
+    /**
+     * 参加工作时间
+     */
+    private LocalDate workStartDate;
+    /**
+     * 年假天数
+     */
+    private Integer annualLeaveDays;
+    /**
+     * 工资卡银行
+     */
+    private String salaryBank;
+    /**
+     * 工资卡号
+     */
+    private String salaryCardNumber;
+    /**
+     * 薪酬
+     */
+    private BigDecimal salary;
+    /**
+     * 岗位薪资
+     */
+    private BigDecimal positionSalary;
+    /**
+     * 项目津贴
+     */
+    private BigDecimal projectAllowance;
+    /**
+     * 特殊岗位津贴
+     */
+    private BigDecimal specialPositionAllowance;
+    /**
+     * 外籍津贴
+     */
+    private BigDecimal foreignAllowance;
+    /**
+     * 午餐补助
+     */
+    private BigDecimal lunchSubsidy;
+    /**
+     * 特别津贴
+     */
+    private BigDecimal specialAllowance;
+    /**
+     * 补贴
+     */
+    private BigDecimal subsidy;
+    /**
+     * 年终奖
+     */
+    private BigDecimal yearEndBonus;
+    /**
+     * 状态
+     */
+    private Integer status;
+    /**
+     * 租户编目
+     */
+    private Long tenantId;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+}

+ 17 - 0
yudao-module-personnel/yudao-module-employee-api/src/main/java/cn/iocoder/yudao/module/employee/enums/ErrorCodeConstants.java

@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.module.employee.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * System 错误码枚举类
+ *
+ * system 系统,使用 1-002-000-000
+ */
+public interface ErrorCodeConstants {
+
+    // ========== 员工模块 1-002-000-000 ==========
+    ErrorCode EMPLOYEE_INFO_NOT_EXISTS = new ErrorCode(1_010_000_000, "员工信息不存在");
+    ErrorCode EMPLOYEE_INFO_EXISTS = new ErrorCode(1_010_000_001, "员工信息已存在");
+    ErrorCode EMPLOYEE_CONTRACT_INFO_NOT_EXISTS = new ErrorCode(1_010_000_002, "员工合同信息不存在");
+
+}

+ 96 - 0
yudao-module-personnel/yudao-module-employee-biz/pom.xml

@@ -0,0 +1,96 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>cn.iocoder.boot</groupId>
+        <artifactId>yudao-module-personnel</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yudao-module-employee-biz</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        employee 模块,主要实现员工相关功能
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-employee-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
+        <!-- 业务组件 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
+        </dependency>
+
+        <!-- Web 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- DB 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-redis</artifactId>
+        </dependency>
+
+        <!-- Job 定时任务相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-job</artifactId>
+        </dependency>
+
+        <!-- 消息队列相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mq</artifactId>
+        </dependency>
+
+        <!-- Test 测试相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- 工具类相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-excel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+
+        <!-- 三方云服务相关 -->
+
+    </dependencies>
+
+</project>

+ 41 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/api/employeeinfo/EmployeeApiImpl.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.employee.api.employeeinfo;
+
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeCreateReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeQueryReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeInfoQueryReqVO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeInfoSaveReqVO;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import cn.iocoder.yudao.module.employee.service.employeeinfo.EmployeeInfoService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 员工 API 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+public class EmployeeApiImpl implements EmployeeApi {
+
+    @Resource
+    private EmployeeInfoService infoService;
+
+    @Override
+    public Long createEmployee(EmployeeCreateReqDTO reqDTO) {
+        EmployeeInfoSaveReqVO reqVO = BeanUtils.toBean(reqDTO, EmployeeInfoSaveReqVO.class);
+        return infoService.createInfo(reqVO);
+    }
+
+    @Override
+    public EmployeeRespDTO getEmployee(EmployeeQueryReqDTO reqDTO) {
+        EmployeeInfoQueryReqVO reqVO = BeanUtils.toBean(reqDTO, EmployeeInfoQueryReqVO.class);
+        EmployeeInfoDO employeeInfoDO = infoService.getInfo(reqVO);
+        EmployeeRespDTO respDTO = BeanUtils.toBean(employeeInfoDO, EmployeeRespDTO.class);
+        return respDTO;
+    }
+
+}

+ 97 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/EmployeeContractInfoController.java

@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoPageReqVO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoRespVO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoSaveReqVO;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeContractInfoDO;
+import cn.iocoder.yudao.module.employee.service.employeeinfo.EmployeeContractInfoService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import java.io.IOException;
+import java.util.List;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+@Tag(name = "管理后台 - 员工合同信息")
+@RestController
+@RequestMapping("/presonnel/employee/contract")
+@Validated
+public class EmployeeContractInfoController {
+
+    @Resource
+    private EmployeeContractInfoService contractInfoService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建员工合同信息")
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:create')")
+    public CommonResult<Long> createContractInfo(@Valid @RequestBody EmployeeContractInfoSaveReqVO createReqVO) {
+        return success(contractInfoService.createContractInfo(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新员工合同信息")
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:update')")
+    public CommonResult<Boolean> updateContractInfo(@Valid @RequestBody EmployeeContractInfoSaveReqVO updateReqVO) {
+        contractInfoService.updateContractInfo(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除员工合同信息")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:delete')")
+    public CommonResult<Boolean> deleteContractInfo(@RequestParam("id") Long id) {
+        contractInfoService.deleteContractInfo(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得员工合同信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:query')")
+    public CommonResult<EmployeeContractInfoRespVO> getContractInfo(@RequestParam("id") Long id) {
+        EmployeeContractInfoDO contractInfo = contractInfoService.getContractInfo(id);
+        return success(BeanUtils.toBean(contractInfo, EmployeeContractInfoRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得员工合同信息分页")
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:query')")
+    public CommonResult<PageResult<EmployeeContractInfoRespVO>> getContractInfoPage(@Valid EmployeeContractInfoPageReqVO pageReqVO) {
+        PageResult<EmployeeContractInfoDO> pageResult = contractInfoService.getContractInfoPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, EmployeeContractInfoRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出员工合同信息 Excel")
+    @PreAuthorize("@ss.hasPermission('employee:contract-info:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportContractInfoExcel(@Valid EmployeeContractInfoPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<EmployeeContractInfoDO> list = contractInfoService.getContractInfoPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "员工合同信息.xls", "数据", EmployeeContractInfoRespVO.class,
+                        BeanUtils.toBean(list, EmployeeContractInfoRespVO.class));
+    }
+
+}

+ 94 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/EmployeeInfoController.java

@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo;
+
+
+import java.util.*;
+import java.io.IOException;
+
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.*;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import cn.iocoder.yudao.module.employee.service.employeeinfo.EmployeeInfoService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 员工信息")
+@RestController
+@RequestMapping("/presonnel/employee")
+@Validated
+public class EmployeeInfoController {
+
+    @Resource
+    private EmployeeInfoService infoService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建员工信息")
+//    @PreAuthorize("@ss.hasPermission('employee:info:create')")
+    public CommonResult<Long> createInfo(@Valid @RequestBody EmployeeInfoSaveReqVO createReqVO) {
+        return success(infoService.createInfo(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新员工信息")
+    @PreAuthorize("@ss.hasPermission('employee:info:update')")
+    public CommonResult<Boolean> updateInfo(@Valid @RequestBody EmployeeInfoSaveReqVO updateReqVO) {
+        infoService.updateInfo(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除员工信息")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('employee:info:delete')")
+    public CommonResult<Boolean> deleteInfo(@RequestParam("id") Long id) {
+        infoService.deleteInfo(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得员工信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('employee:info:query')")
+    public CommonResult<EmployeeInfoRespVO> getInfo(@RequestParam("id") Long id) {
+        EmployeeInfoDO info = infoService.getInfo(id);
+        return success(BeanUtils.toBean(info, EmployeeInfoRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得员工信息分页")
+    @PreAuthorize("@ss.hasPermission('employee:info:query')")
+    public CommonResult<PageResult<EmployeeInfoRespVO>> getInfoPage(@Valid EmployeeInfoPageReqVO pageReqVO) {
+        PageResult<EmployeeInfoDO> pageResult = infoService.getInfoPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, EmployeeInfoRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出员工信息 Excel")
+    @PreAuthorize("@ss.hasPermission('employee:info:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportInfoExcel(@Valid EmployeeInfoPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<EmployeeInfoDO> list = infoService.getInfoPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "员工信息.xls", "数据", EmployeeInfoRespVO.class,
+                        BeanUtils.toBean(list, EmployeeInfoRespVO.class));
+    }
+
+}

+ 52 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoPageReqVO.java

@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 员工合同信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class EmployeeContractInfoPageReqVO extends PageParam {
+
+    @Schema(description = "业务UUID", example = "8684")
+    private String infoId;
+
+    @Schema(description = "合同编号,唯一")
+    private String contractNumber;
+
+    @Schema(description = "员工ID", example = "19556")
+    private String employeeId;
+
+    @Schema(description = "合同开始日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] contractStartDate;
+
+    @Schema(description = "合同结束日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] contractEndDate;
+
+    @Schema(description = "工作内容")
+    private String jobContent;
+
+    @Schema(description = "合同状态", example = "1")
+    private String contractStatus;
+
+    @Schema(description = "备注信息")
+    private String remarks;
+
+    @Schema(description = "状态", example = "2")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 59 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoRespVO.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 员工合同信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class EmployeeContractInfoRespVO {
+
+    @Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4905")
+    @ExcelProperty("合同ID")
+    private Long id;
+
+    @Schema(description = "业务UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8684")
+    @ExcelProperty("业务UUID")
+    private String infoId;
+
+    @Schema(description = "合同编号,唯一", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("合同编号,唯一")
+    private String contractNumber;
+
+    @Schema(description = "员工ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19556")
+    @ExcelProperty("员工ID")
+    private String employeeId;
+
+    @Schema(description = "合同开始日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("合同开始日期")
+    private LocalDate contractStartDate;
+
+    @Schema(description = "合同结束日期")
+    @ExcelProperty("合同结束日期")
+    private LocalDate contractEndDate;
+
+    @Schema(description = "工作内容")
+    @ExcelProperty("工作内容")
+    private String jobContent;
+
+    @Schema(description = "合同状态", example = "1")
+    @ExcelProperty("合同状态")
+    private String contractStatus;
+
+    @Schema(description = "备注信息")
+    @ExcelProperty("备注信息")
+    private String remarks;
+
+    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 49 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeContractInfoSaveReqVO.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+
+@Schema(description = "管理后台 - 员工合同信息新增/修改 Request VO")
+@Data
+public class EmployeeContractInfoSaveReqVO {
+
+    @Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4905")
+    private Long id;
+
+    @Schema(description = "业务UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8684")
+    @NotEmpty(message = "业务UUID不能为空")
+    private String infoId;
+
+    @Schema(description = "合同编号,唯一", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "合同编号,唯一不能为空")
+    private String contractNumber;
+
+    @Schema(description = "员工ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19556")
+    @NotEmpty(message = "员工ID不能为空")
+    private String employeeId;
+
+    @Schema(description = "合同开始日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "合同开始日期不能为空")
+    private LocalDate contractStartDate;
+
+    @Schema(description = "合同结束日期")
+    private LocalDate contractEndDate;
+
+    @Schema(description = "工作内容")
+    private String jobContent;
+
+    @Schema(description = "合同状态", example = "1")
+    private String contractStatus;
+
+    @Schema(description = "备注信息")
+    private String remarks;
+
+    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "状态不能为空")
+    private Integer status;
+
+}

+ 149 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoPageReqVO.java

@@ -0,0 +1,149 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import java.math.BigDecimal;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 员工信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class EmployeeInfoPageReqVO extends PageParam {
+
+    @Schema(description = "业务UUID", example = "19517")
+    private String infoId;
+
+    @Schema(description = "员工编号")
+    private String employeeNumber;
+
+    @Schema(description = "姓名", example = "李四")
+    private String name;
+
+    @Schema(description = "部门ID", example = "17351")
+    private Long deptId;
+
+    @Schema(description = "手机号")
+    private String phone;
+
+    @Schema(description = "头像地址")
+    private String avatar;
+
+    @Schema(description = "电子邮箱")
+    private String email;
+
+    @Schema(description = "职位")
+    private String position;
+
+    @Schema(description = "职位编号", example = "7080")
+    private Long postId;
+
+    @Schema(description = "入职时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] entryDate;
+
+    @Schema(description = "试用期到期时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] probationEndDate;
+
+    @Schema(description = "工作地点")
+    private String workLocation;
+
+    @Schema(description = "员工状态", example = "2")
+    private Integer employeeStatus;
+
+    @Schema(description = "性别")
+    private String gender;
+
+    @Schema(description = "出生日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] birthDate;
+
+    @Schema(description = "婚姻状况", example = "1")
+    private String marriageStatus;
+
+    @Schema(description = "身份证号")
+    private String idCardNumber;
+
+    @Schema(description = "身份证地址")
+    private String idCardAddress;
+
+    @Schema(description = "户口类型", example = "1")
+    private String householdType;
+
+    @Schema(description = "户口所在地")
+    private String householdLocation;
+
+    @Schema(description = "学历")
+    private String educationLevel;
+
+    @Schema(description = "专业")
+    private String major;
+
+    @Schema(description = "毕业院校")
+    private String graduationSchool;
+
+    @Schema(description = "毕业时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] graduationDate;
+
+    @Schema(description = "参加工作时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] workStartDate;
+
+    @Schema(description = "年假天数")
+    private Integer annualLeaveDays;
+
+    @Schema(description = "工资卡银行")
+    private String salaryBank;
+
+    @Schema(description = "工资卡号")
+    private String salaryCardNumber;
+
+    @Schema(description = "薪酬")
+    private BigDecimal salary;
+
+    @Schema(description = "岗位薪资")
+    private BigDecimal positionSalary;
+
+    @Schema(description = "项目津贴")
+    private BigDecimal projectAllowance;
+
+    @Schema(description = "特殊岗位津贴")
+    private BigDecimal specialPositionAllowance;
+
+    @Schema(description = "外籍津贴")
+    private BigDecimal foreignAllowance;
+
+    @Schema(description = "午餐补助")
+    private BigDecimal lunchSubsidy;
+
+    @Schema(description = "特别津贴")
+    private BigDecimal specialAllowance;
+
+    @Schema(description = "补贴")
+    private BigDecimal subsidy;
+
+    @Schema(description = "年终奖")
+    private BigDecimal yearEndBonus;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "租户编码", example = "14244")
+    private Long tenantId;
+
+    @Schema(description = "用户ID", example = "14244")
+    private Long userId;
+
+}

+ 151 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoQueryReqVO.java

@@ -0,0 +1,151 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 员工信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class EmployeeInfoQueryReqVO extends PageParam {
+
+    @Schema(description = "业务UUID", example = "19517")
+    private String infoId;
+
+    @Schema(description = "员工编号")
+    private String employeeNumber;
+
+    @Schema(description = "姓名", example = "李四")
+    private String name;
+
+    @Schema(description = "部门ID", example = "17351")
+    private Long deptId;
+
+    @Schema(description = "手机号")
+    private String phone;
+
+    @Schema(description = "头像地址")
+    private String avatar;
+
+    @Schema(description = "电子邮箱")
+    private String email;
+
+    @Schema(description = "职位")
+    private String position;
+
+    @Schema(description = "职位编号", example = "7080")
+    private Long postId;
+
+    @Schema(description = "入职时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] entryDate;
+
+    @Schema(description = "试用期到期时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] probationEndDate;
+
+    @Schema(description = "工作地点")
+    private String workLocation;
+
+    @Schema(description = "员工状态", example = "2")
+    private Integer employeeStatus;
+
+    @Schema(description = "性别")
+    private String gender;
+
+    @Schema(description = "出生日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] birthDate;
+
+    @Schema(description = "婚姻状况", example = "1")
+    private String marriageStatus;
+
+    @Schema(description = "身份证号")
+    private String idCardNumber;
+
+    @Schema(description = "身份证地址")
+    private String idCardAddress;
+
+    @Schema(description = "户口类型", example = "1")
+    private String householdType;
+
+    @Schema(description = "户口所在地")
+    private String householdLocation;
+
+    @Schema(description = "学历")
+    private String educationLevel;
+
+    @Schema(description = "专业")
+    private String major;
+
+    @Schema(description = "毕业院校")
+    private String graduationSchool;
+
+    @Schema(description = "毕业时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] graduationDate;
+
+    @Schema(description = "参加工作时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] workStartDate;
+
+    @Schema(description = "年假天数")
+    private Integer annualLeaveDays;
+
+    @Schema(description = "工资卡银行")
+    private String salaryBank;
+
+    @Schema(description = "工资卡号")
+    private String salaryCardNumber;
+
+    @Schema(description = "薪酬")
+    private BigDecimal salary;
+
+    @Schema(description = "岗位薪资")
+    private BigDecimal positionSalary;
+
+    @Schema(description = "项目津贴")
+    private BigDecimal projectAllowance;
+
+    @Schema(description = "特殊岗位津贴")
+    private BigDecimal specialPositionAllowance;
+
+    @Schema(description = "外籍津贴")
+    private BigDecimal foreignAllowance;
+
+    @Schema(description = "午餐补助")
+    private BigDecimal lunchSubsidy;
+
+    @Schema(description = "特别津贴")
+    private BigDecimal specialAllowance;
+
+    @Schema(description = "补贴")
+    private BigDecimal subsidy;
+
+    @Schema(description = "年终奖")
+    private BigDecimal yearEndBonus;
+
+    @Schema(description = "状态", example = "1")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "租户编码", example = "14244")
+    private Long tenantId;
+
+    @Schema(description = "用户ID", example = "14244")
+    private Long userId;
+
+}

+ 183 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoRespVO.java

@@ -0,0 +1,183 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 员工信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class EmployeeInfoRespVO {
+
+    @Schema(description = "员工ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20870")
+    @ExcelProperty("员工ID")
+    private Long id;
+
+    @Schema(description = "业务UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19517")
+    @ExcelProperty("业务UUID")
+    private String infoId;
+
+    @Schema(description = "员工编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("员工编号")
+    private String employeeNumber;
+
+    @Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @ExcelProperty("姓名")
+    private String name;
+
+    @Schema(description = "部门ID", example = "17351")
+    @ExcelProperty("部门ID")
+    private Long deptId;
+
+    @Schema(description = "手机号")
+    @ExcelProperty("手机号")
+    private String phone;
+
+    @Schema(description = "头像地址")
+    @ExcelProperty("头像地址")
+    private String avatar;
+
+    @Schema(description = "电子邮箱")
+    @ExcelProperty("电子邮箱")
+    private String email;
+
+    @Schema(description = "职位")
+    @ExcelProperty("职位")
+    private String position;
+
+    @Schema(description = "职位编号", example = "7080")
+    @ExcelProperty("职位编号")
+    private Long postId;
+
+    @Schema(description = "入职时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("入职时间")
+    private LocalDate entryDate;
+
+    @Schema(description = "试用期到期时间")
+    @ExcelProperty("试用期到期时间")
+    private LocalDate probationEndDate;
+
+    @Schema(description = "工作地点")
+    @ExcelProperty("工作地点")
+    private String workLocation;
+
+    @Schema(description = "员工状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("员工状态")
+    private Integer employeeStatus;
+
+    @Schema(description = "性别")
+    @ExcelProperty("性别")
+    private String gender;
+
+    @Schema(description = "出生日期")
+    @ExcelProperty("出生日期")
+    private LocalDate birthDate;
+
+    @Schema(description = "婚姻状况", example = "1")
+    @ExcelProperty("婚姻状况")
+    private String marriageStatus;
+
+    @Schema(description = "身份证号")
+    @ExcelProperty("身份证号")
+    private String idCardNumber;
+
+    @Schema(description = "身份证地址")
+    @ExcelProperty("身份证地址")
+    private String idCardAddress;
+
+    @Schema(description = "户口类型", example = "1")
+    @ExcelProperty("户口类型")
+    private String householdType;
+
+    @Schema(description = "户口所在地")
+    @ExcelProperty("户口所在地")
+    private String householdLocation;
+
+    @Schema(description = "学历")
+    @ExcelProperty("学历")
+    private String educationLevel;
+
+    @Schema(description = "专业")
+    @ExcelProperty("专业")
+    private String major;
+
+    @Schema(description = "毕业院校")
+    @ExcelProperty("毕业院校")
+    private String graduationSchool;
+
+    @Schema(description = "毕业时间")
+    @ExcelProperty("毕业时间")
+    private LocalDate graduationDate;
+
+    @Schema(description = "参加工作时间")
+    @ExcelProperty("参加工作时间")
+    private LocalDate workStartDate;
+
+    @Schema(description = "年假天数")
+    @ExcelProperty("年假天数")
+    private Integer annualLeaveDays;
+
+    @Schema(description = "工资卡银行")
+    @ExcelProperty("工资卡银行")
+    private String salaryBank;
+
+    @Schema(description = "工资卡号")
+    @ExcelProperty("工资卡号")
+    private String salaryCardNumber;
+
+    @Schema(description = "薪酬")
+    @ExcelProperty("薪酬")
+    private BigDecimal salary;
+
+    @Schema(description = "岗位薪资")
+    @ExcelProperty("岗位薪资")
+    private BigDecimal positionSalary;
+
+    @Schema(description = "项目津贴")
+    @ExcelProperty("项目津贴")
+    private BigDecimal projectAllowance;
+
+    @Schema(description = "特殊岗位津贴")
+    @ExcelProperty("特殊岗位津贴")
+    private BigDecimal specialPositionAllowance;
+
+    @Schema(description = "外籍津贴")
+    @ExcelProperty("外籍津贴")
+    private BigDecimal foreignAllowance;
+
+    @Schema(description = "午餐补助")
+    @ExcelProperty("午餐补助")
+    private BigDecimal lunchSubsidy;
+
+    @Schema(description = "特别津贴")
+    @ExcelProperty("特别津贴")
+    private BigDecimal specialAllowance;
+
+    @Schema(description = "补贴")
+    @ExcelProperty("补贴")
+    private BigDecimal subsidy;
+
+    @Schema(description = "年终奖")
+    @ExcelProperty("年终奖")
+    private BigDecimal yearEndBonus;
+
+    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14244")
+    @ExcelProperty("租户编码")
+    private Long tenantId;
+
+    @Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14244")
+    @ExcelProperty("用户ID")
+    private Long userId;
+
+}

+ 143 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/controller/admin/employeeinfo/vo/EmployeeInfoSaveReqVO.java

@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@Schema(description = "管理后台 - 员工信息新增/修改 Request VO")
+@Data
+public class EmployeeInfoSaveReqVO {
+
+    @Schema(description = "员工ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20870")
+    private Long id;
+
+    @Schema(description = "业务UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19517")
+    private String infoId;
+
+    @Schema(description = "员工编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    private String employeeNumber;
+
+    @Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @NotEmpty(message = "姓名不能为空")
+    private String name;
+
+    @Schema(description = "部门ID", example = "17351")
+    private Long deptId;
+
+    @Schema(description = "手机号")
+    private String phone;
+
+    @Schema(description = "头像地址")
+    private String avatar;
+
+    @Schema(description = "电子邮箱")
+    private String email;
+
+    @Schema(description = "职位")
+    private String position;
+
+    @Schema(description = "职位编号", example = "7080")
+    private Long postId;
+
+    @Schema(description = "入职时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDate entryDate;
+
+    @Schema(description = "试用期到期时间")
+    private LocalDate probationEndDate;
+
+    @Schema(description = "工作地点")
+    private String workLocation;
+
+    @Schema(description = "员工状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+//    @NotEmpty(message = "员工状态不能为空")
+    private Integer employeeStatus;
+
+    @Schema(description = "性别")
+    private String gender;
+
+    @Schema(description = "出生日期")
+    private LocalDate birthDate;
+
+    @Schema(description = "婚姻状况", example = "1")
+    private String marriageStatus;
+
+    @Schema(description = "身份证号")
+    private String idCardNumber;
+
+    @Schema(description = "身份证地址")
+    private String idCardAddress;
+
+    @Schema(description = "户口类型", example = "1")
+    private String householdType;
+
+    @Schema(description = "户口所在地")
+    private String householdLocation;
+
+    @Schema(description = "学历")
+    private String educationLevel;
+
+    @Schema(description = "专业")
+    private String major;
+
+    @Schema(description = "毕业院校")
+    private String graduationSchool;
+
+    @Schema(description = "毕业时间")
+    private LocalDate graduationDate;
+
+    @Schema(description = "参加工作时间")
+    private LocalDate workStartDate;
+
+    @Schema(description = "年假天数")
+    private Integer annualLeaveDays;
+
+    @Schema(description = "工资卡银行")
+    private String salaryBank;
+
+    @Schema(description = "工资卡号")
+    private String salaryCardNumber;
+
+    @Schema(description = "薪酬")
+    private BigDecimal salary;
+
+    @Schema(description = "岗位薪资")
+    private BigDecimal positionSalary;
+
+    @Schema(description = "项目津贴")
+    private BigDecimal projectAllowance;
+
+    @Schema(description = "特殊岗位津贴")
+    private BigDecimal specialPositionAllowance;
+
+    @Schema(description = "外籍津贴")
+    private BigDecimal foreignAllowance;
+
+    @Schema(description = "午餐补助")
+    private BigDecimal lunchSubsidy;
+
+    @Schema(description = "特别津贴")
+    private BigDecimal specialAllowance;
+
+    @Schema(description = "补贴")
+    private BigDecimal subsidy;
+
+    @Schema(description = "年终奖")
+    private BigDecimal yearEndBonus;
+
+    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+//    @NotNull(message = "状态不能为空")
+    private Integer status;
+
+    @Schema(description = "租户编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "14244")
+    @NotNull(message = "租户编码不能为空")
+    private Long tenantId;
+
+    @Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14244")
+    @NotNull(message = "用户ID不能为空")
+    private Long userId;
+
+}

+ 69 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/dataobject/employeeinfo/EmployeeContractInfoDO.java

@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 员工合同信息 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("employee_contract_info")
+@KeySequence("employee_contract_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class EmployeeContractInfoDO extends BaseDO {
+
+    /**
+     * 合同ID
+     */
+    @TableId
+    private Long id;
+    /**
+     * 业务UUID
+     */
+    private String infoId;
+    /**
+     * 合同编号,唯一
+     */
+    private String contractNumber;
+    /**
+     * 员工ID
+     */
+    private String employeeId;
+    /**
+     * 合同开始日期
+     */
+    private LocalDate contractStartDate;
+    /**
+     * 合同结束日期
+     */
+    private LocalDate contractEndDate;
+    /**
+     * 工作内容
+     */
+    private String jobContent;
+    /**
+     * 合同状态
+     */
+    private String contractStatus;
+    /**
+     * 备注信息
+     */
+    private String remarks;
+    /**
+     * 状态
+     */
+    private Integer status;
+
+}

+ 191 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/dataobject/employeeinfo/EmployeeInfoDO.java

@@ -0,0 +1,191 @@
+package cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 员工信息 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("employee_info")
+@KeySequence("employee_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class EmployeeInfoDO extends BaseDO {
+
+    /**
+     * 员工ID
+     */
+    @TableId
+    private Long id;
+    /**
+     * 业务UUID
+     */
+    private String infoId;
+    /**
+     * 员工编号
+     */
+    private String employeeNumber;
+    /**
+     * 姓名
+     */
+    private String name;
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+    /**
+     * 手机号
+     */
+    private String phone;
+    /**
+     * 头像地址
+     */
+    private String avatar;
+    /**
+     * 电子邮箱
+     */
+    private String email;
+    /**
+     * 职位
+     */
+    private String position;
+    /**
+     * 职位编号
+     */
+    private Long postId;
+    /**
+     * 入职时间
+     */
+    private LocalDate entryDate;
+    /**
+     * 试用期到期时间
+     */
+    private LocalDate probationEndDate;
+    /**
+     * 工作地点
+     */
+    private String workLocation;
+    /**
+     * 员工状态
+     */
+    private Integer employeeStatus;
+    /**
+     * 性别
+     */
+    private String gender;
+    /**
+     * 出生日期
+     */
+    private LocalDate birthDate;
+    /**
+     * 婚姻状况
+     */
+    private String marriageStatus;
+    /**
+     * 身份证号
+     */
+    private String idCardNumber;
+    /**
+     * 身份证地址
+     */
+    private String idCardAddress;
+    /**
+     * 户口类型
+     */
+    private String householdType;
+    /**
+     * 户口所在地
+     */
+    private String householdLocation;
+    /**
+     * 学历
+     */
+    private String educationLevel;
+    /**
+     * 专业
+     */
+    private String major;
+    /**
+     * 毕业院校
+     */
+    private String graduationSchool;
+    /**
+     * 毕业时间
+     */
+    private LocalDate graduationDate;
+    /**
+     * 参加工作时间
+     */
+    private LocalDate workStartDate;
+    /**
+     * 年假天数
+     */
+    private Integer annualLeaveDays;
+    /**
+     * 工资卡银行
+     */
+    private String salaryBank;
+    /**
+     * 工资卡号
+     */
+    private String salaryCardNumber;
+    /**
+     * 薪酬
+     */
+    private BigDecimal salary;
+    /**
+     * 岗位薪资
+     */
+    private BigDecimal positionSalary;
+    /**
+     * 项目津贴
+     */
+    private BigDecimal projectAllowance;
+    /**
+     * 特殊岗位津贴
+     */
+    private BigDecimal specialPositionAllowance;
+    /**
+     * 外籍津贴
+     */
+    private BigDecimal foreignAllowance;
+    /**
+     * 午餐补助
+     */
+    private BigDecimal lunchSubsidy;
+    /**
+     * 特别津贴
+     */
+    private BigDecimal specialAllowance;
+    /**
+     * 补贴
+     */
+    private BigDecimal subsidy;
+    /**
+     * 年终奖
+     */
+    private BigDecimal yearEndBonus;
+    /**
+     * 状态
+     */
+    private Integer status;
+    /**
+     * 租户编目
+     */
+    private Long tenantId;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+}

+ 33 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/mysql/employeeinfo/EmployeeContractInfoMapper.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoPageReqVO;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeContractInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 员工合同信息 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface EmployeeContractInfoMapper extends BaseMapperX<EmployeeContractInfoDO> {
+
+    default PageResult<EmployeeContractInfoDO> selectPage(EmployeeContractInfoPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<EmployeeContractInfoDO>()
+                .eqIfPresent(EmployeeContractInfoDO::getInfoId, reqVO.getInfoId())
+                .eqIfPresent(EmployeeContractInfoDO::getContractNumber, reqVO.getContractNumber())
+                .eqIfPresent(EmployeeContractInfoDO::getEmployeeId, reqVO.getEmployeeId())
+                .betweenIfPresent(EmployeeContractInfoDO::getContractStartDate, reqVO.getContractStartDate())
+                .betweenIfPresent(EmployeeContractInfoDO::getContractEndDate, reqVO.getContractEndDate())
+                .eqIfPresent(EmployeeContractInfoDO::getJobContent, reqVO.getJobContent())
+                .eqIfPresent(EmployeeContractInfoDO::getContractStatus, reqVO.getContractStatus())
+                .eqIfPresent(EmployeeContractInfoDO::getRemarks, reqVO.getRemarks())
+                .eqIfPresent(EmployeeContractInfoDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(EmployeeContractInfoDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(EmployeeContractInfoDO::getId));
+    }
+
+}

+ 70 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/dal/mysql/employeeinfo/EmployeeInfoMapper.java

@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.*;
+
+/**
+ * 员工信息 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface EmployeeInfoMapper extends BaseMapperX<EmployeeInfoDO> {
+
+    default PageResult<EmployeeInfoDO> selectPage(EmployeeInfoPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<EmployeeInfoDO>()
+                .eqIfPresent(EmployeeInfoDO::getInfoId, reqVO.getInfoId())
+                .eqIfPresent(EmployeeInfoDO::getEmployeeNumber, reqVO.getEmployeeNumber())
+                .likeIfPresent(EmployeeInfoDO::getName, reqVO.getName())
+                .eqIfPresent(EmployeeInfoDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(EmployeeInfoDO::getPhone, reqVO.getPhone())
+                .eqIfPresent(EmployeeInfoDO::getAvatar, reqVO.getAvatar())
+                .eqIfPresent(EmployeeInfoDO::getEmail, reqVO.getEmail())
+                .eqIfPresent(EmployeeInfoDO::getPosition, reqVO.getPosition())
+                .eqIfPresent(EmployeeInfoDO::getPostId, reqVO.getPostId())
+                .betweenIfPresent(EmployeeInfoDO::getEntryDate, reqVO.getEntryDate())
+                .betweenIfPresent(EmployeeInfoDO::getProbationEndDate, reqVO.getProbationEndDate())
+                .eqIfPresent(EmployeeInfoDO::getWorkLocation, reqVO.getWorkLocation())
+                .eqIfPresent(EmployeeInfoDO::getEmployeeStatus, reqVO.getEmployeeStatus())
+                .eqIfPresent(EmployeeInfoDO::getGender, reqVO.getGender())
+                .betweenIfPresent(EmployeeInfoDO::getBirthDate, reqVO.getBirthDate())
+                .eqIfPresent(EmployeeInfoDO::getMarriageStatus, reqVO.getMarriageStatus())
+                .eqIfPresent(EmployeeInfoDO::getIdCardNumber, reqVO.getIdCardNumber())
+                .eqIfPresent(EmployeeInfoDO::getIdCardAddress, reqVO.getIdCardAddress())
+                .eqIfPresent(EmployeeInfoDO::getHouseholdType, reqVO.getHouseholdType())
+                .eqIfPresent(EmployeeInfoDO::getHouseholdLocation, reqVO.getHouseholdLocation())
+                .eqIfPresent(EmployeeInfoDO::getEducationLevel, reqVO.getEducationLevel())
+                .eqIfPresent(EmployeeInfoDO::getMajor, reqVO.getMajor())
+                .eqIfPresent(EmployeeInfoDO::getGraduationSchool, reqVO.getGraduationSchool())
+                .betweenIfPresent(EmployeeInfoDO::getGraduationDate, reqVO.getGraduationDate())
+                .betweenIfPresent(EmployeeInfoDO::getWorkStartDate, reqVO.getWorkStartDate())
+                .eqIfPresent(EmployeeInfoDO::getAnnualLeaveDays, reqVO.getAnnualLeaveDays())
+                .eqIfPresent(EmployeeInfoDO::getSalaryBank, reqVO.getSalaryBank())
+                .eqIfPresent(EmployeeInfoDO::getSalaryCardNumber, reqVO.getSalaryCardNumber())
+                .eqIfPresent(EmployeeInfoDO::getSalary, reqVO.getSalary())
+                .eqIfPresent(EmployeeInfoDO::getPositionSalary, reqVO.getPositionSalary())
+                .eqIfPresent(EmployeeInfoDO::getProjectAllowance, reqVO.getProjectAllowance())
+                .eqIfPresent(EmployeeInfoDO::getSpecialPositionAllowance, reqVO.getSpecialPositionAllowance())
+                .eqIfPresent(EmployeeInfoDO::getForeignAllowance, reqVO.getForeignAllowance())
+                .eqIfPresent(EmployeeInfoDO::getLunchSubsidy, reqVO.getLunchSubsidy())
+                .eqIfPresent(EmployeeInfoDO::getSpecialAllowance, reqVO.getSpecialAllowance())
+                .eqIfPresent(EmployeeInfoDO::getSubsidy, reqVO.getSubsidy())
+                .eqIfPresent(EmployeeInfoDO::getYearEndBonus, reqVO.getYearEndBonus())
+                .eqIfPresent(EmployeeInfoDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(EmployeeInfoDO::getCreateTime, reqVO.getCreateTime())
+                .eqIfPresent(EmployeeInfoDO::getUserId, reqVO.getUserId())
+                .orderByDesc(EmployeeInfoDO::getId));
+    }
+
+    default EmployeeInfoDO getInfo(EmployeeInfoQueryReqVO reqVO) {
+        return selectOne(new LambdaQueryWrapperX<EmployeeInfoDO>()
+                .eqIfPresent(EmployeeInfoDO::getUserId, reqVO.getUserId())
+                .eqIfPresent(EmployeeInfoDO::getTenantId, reqVO.getTenantId())
+                .orderByDesc(EmployeeInfoDO::getId));
+    }
+
+}

+ 9 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/package-info.java

@@ -0,0 +1,9 @@
+/**
+ * employee 模块,我们放员工业务,提供员工的相关功能。
+ *
+ * 1. Controller URL:以 /employee/ 开头,避免和其它 Module 冲突
+ * 2. DataObject 表名:以 employee_ 开头,方便在数据库中区分
+ *
+ * 注意,由于 Employee 模块,容易重名,所以类名都加载 Employee 的前缀~
+ */
+package cn.iocoder.yudao.module.employee;

+ 56 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeContractInfoService.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.employee.service.employeeinfo;
+
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoPageReqVO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoSaveReqVO;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeContractInfoDO;
+
+import javax.validation.Valid;
+
+/**
+ * 员工合同信息 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface EmployeeContractInfoService {
+
+    /**
+     * 创建员工合同信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createContractInfo(@Valid EmployeeContractInfoSaveReqVO createReqVO);
+
+    /**
+     * 更新员工合同信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateContractInfo(@Valid EmployeeContractInfoSaveReqVO updateReqVO);
+
+    /**
+     * 删除员工合同信息
+     *
+     * @param id 编号
+     */
+    void deleteContractInfo(Long id);
+
+    /**
+     * 获得员工合同信息
+     *
+     * @param id 编号
+     * @return 员工合同信息
+     */
+    EmployeeContractInfoDO getContractInfo(Long id);
+
+    /**
+     * 获得员工合同信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 员工合同信息分页
+     */
+    PageResult<EmployeeContractInfoDO> getContractInfoPage(EmployeeContractInfoPageReqVO pageReqVO);
+
+}

+ 71 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeContractInfoServiceImpl.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.employee.service.employeeinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoPageReqVO;
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.EmployeeContractInfoSaveReqVO;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeContractInfoDO;
+import cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo.EmployeeContractInfoMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_CONTRACT_INFO_NOT_EXISTS;
+
+/**
+ * 员工合同信息 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class EmployeeContractInfoServiceImpl implements EmployeeContractInfoService {
+
+    @Resource
+    private EmployeeContractInfoMapper contractInfoMapper;
+
+    @Override
+    public Long createContractInfo(EmployeeContractInfoSaveReqVO createReqVO) {
+        // 插入
+        EmployeeContractInfoDO contractInfo = BeanUtils.toBean(createReqVO, EmployeeContractInfoDO.class);
+        contractInfoMapper.insert(contractInfo);
+        // 返回
+        return contractInfo.getId();
+    }
+
+    @Override
+    public void updateContractInfo(EmployeeContractInfoSaveReqVO updateReqVO) {
+        // 校验存在
+        validateContractInfoExists(updateReqVO.getId());
+        // 更新
+        EmployeeContractInfoDO updateObj = BeanUtils.toBean(updateReqVO, EmployeeContractInfoDO.class);
+        contractInfoMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteContractInfo(Long id) {
+        // 校验存在
+        validateContractInfoExists(id);
+        // 删除
+        contractInfoMapper.deleteById(id);
+    }
+
+    private void validateContractInfoExists(Long id) {
+        if (contractInfoMapper.selectById(id) == null) {
+            throw exception(EMPLOYEE_CONTRACT_INFO_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public EmployeeContractInfoDO getContractInfo(Long id) {
+        return contractInfoMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<EmployeeContractInfoDO> getContractInfoPage(EmployeeContractInfoPageReqVO pageReqVO) {
+        return contractInfoMapper.selectPage(pageReqVO);
+    }
+
+}

+ 72 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoService.java

@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.employee.service.employeeinfo;
+
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.*;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.validation.Valid;
+
+/**
+ * 员工信息 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface EmployeeInfoService {
+
+    /**
+     * 创建员工信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createInfo(@Valid EmployeeInfoSaveReqVO createReqVO);
+
+    /**
+     * 更新员工信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateInfo(@Valid EmployeeInfoSaveReqVO updateReqVO);
+
+    /**
+     * 删除员工信息
+     *
+     * @param id 编号
+     */
+    void deleteInfo(Long id);
+
+    /**
+     * 获得员工信息
+     *
+     * @param id 编号
+     * @return 员工信息
+     */
+    EmployeeInfoDO getInfo(Long id);
+
+    /**
+     * 获得员工信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 员工信息分页
+     */
+    PageResult<EmployeeInfoDO> getInfoPage(EmployeeInfoPageReqVO pageReqVO);
+
+    /**
+     *
+     *
+     * @param userId
+     * @param tenantId
+     * @return
+     */
+    EmployeeInfoDO getInfoByUserIdAndTenantId(Long userId, Long tenantId);
+
+    /**
+     * 获得员工信息
+     *
+     * @param queryReqVO
+     * @return
+     */
+    EmployeeInfoDO getInfo(@Valid EmployeeInfoQueryReqVO queryReqVO);
+
+
+}

+ 89 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoServiceImpl.java

@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.module.employee.service.employeeinfo;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.*;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo.EmployeeInfoMapper;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_INFO_NOT_EXISTS;
+
+/**
+ * 员工信息 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class EmployeeInfoServiceImpl implements EmployeeInfoService {
+
+    @Resource
+    private EmployeeInfoMapper infoMapper;
+
+    @Override
+    public Long createInfo(EmployeeInfoSaveReqVO createReqVO) {
+        // 插入
+        // 生成id
+        createReqVO.setInfoId(IdUtil.fastSimpleUUID());
+        EmployeeInfoDO info = BeanUtils.toBean(createReqVO, EmployeeInfoDO.class);
+        infoMapper.insert(info);
+        // 返回
+        return info.getId();
+    }
+
+    @Override
+    public void updateInfo(EmployeeInfoSaveReqVO updateReqVO) {
+        // 校验存在
+        validateInfoExists(updateReqVO.getId());
+        // 更新
+        EmployeeInfoDO updateObj = BeanUtils.toBean(updateReqVO, EmployeeInfoDO.class);
+        infoMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteInfo(Long id) {
+        // 校验存在
+        validateInfoExists(id);
+        // 删除
+        infoMapper.deleteById(id);
+    }
+
+    private void validateInfoExists(Long id) {
+        if (infoMapper.selectById(id) == null) {
+            throw exception(EMPLOYEE_INFO_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public EmployeeInfoDO getInfo(Long id) {
+        return infoMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<EmployeeInfoDO> getInfoPage(EmployeeInfoPageReqVO pageReqVO) {
+        return infoMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public EmployeeInfoDO getInfoByUserIdAndTenantId(Long userId, Long tenantId) {
+        LambdaQueryWrapper<EmployeeInfoDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(EmployeeInfoDO::getUserId, userId)
+                .eq(EmployeeInfoDO::getTenantId, tenantId);
+        return infoMapper.selectOne(lambdaQueryWrapper);
+    }
+
+    @Override
+    public EmployeeInfoDO getInfo(EmployeeInfoQueryReqVO queryReqVO) {
+        return infoMapper.getInfo(queryReqVO);
+    }
+
+}

+ 12 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/resources/mapper/employeeinfo/EmployeeInfoMapper.xml

@@ -0,0 +1,12 @@
+<?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="cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo.EmployeeInfoMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 274 - 0
yudao-module-personnel/yudao-module-employee-biz/src/test/java/cn/iocoder/yudao/module/employee/service/employeeinfo/EmployeeInfoServiceImplTest.java

@@ -0,0 +1,274 @@
+package cn.iocoder.yudao.module.employee.service.employeeinfo;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.employee.controller.admin.employeeinfo.vo.*;
+import cn.iocoder.yudao.module.employee.dal.dataobject.employeeinfo.EmployeeInfoDO;
+import cn.iocoder.yudao.module.employee.dal.mysql.employeeinfo.EmployeeInfoMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_INFO_NOT_EXISTS;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link EmployeeInfoServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(EmployeeInfoServiceImpl.class)
+public class EmployeeInfoServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private EmployeeInfoServiceImpl infoService;
+
+    @Resource
+    private EmployeeInfoMapper infoMapper;
+
+    @Test
+    public void testCreateInfo_success() {
+        // 准备参数
+        EmployeeInfoSaveReqVO createReqVO = randomPojo(EmployeeInfoSaveReqVO.class).setId(null);
+
+        // 调用
+        Long infoId = infoService.createInfo(createReqVO);
+        // 断言
+        assertNotNull(infoId);
+        // 校验记录的属性是否正确
+        EmployeeInfoDO info = infoMapper.selectById(infoId);
+        assertPojoEquals(createReqVO, info, "id");
+    }
+
+    @Test
+    public void testUpdateInfo_success() {
+        // mock 数据
+        EmployeeInfoDO dbInfo = randomPojo(EmployeeInfoDO.class);
+        infoMapper.insert(dbInfo);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        EmployeeInfoSaveReqVO updateReqVO = randomPojo(EmployeeInfoSaveReqVO.class, o -> {
+            o.setId(dbInfo.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        infoService.updateInfo(updateReqVO);
+        // 校验是否更新正确
+        EmployeeInfoDO info = infoMapper.selectById(updateReqVO.getId()); // 获取最新的
+        assertPojoEquals(updateReqVO, info);
+    }
+
+    @Test
+    public void testUpdateInfo_notExists() {
+        // 准备参数
+        EmployeeInfoSaveReqVO updateReqVO = randomPojo(EmployeeInfoSaveReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> infoService.updateInfo(updateReqVO), EMPLOYEE_INFO_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteInfo_success() {
+        // mock 数据
+        EmployeeInfoDO dbInfo = randomPojo(EmployeeInfoDO.class);
+        infoMapper.insert(dbInfo);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbInfo.getId();
+
+        // 调用
+        infoService.deleteInfo(id);
+       // 校验数据不存在了
+       assertNull(infoMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteInfo_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> infoService.deleteInfo(id), EMPLOYEE_INFO_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetInfoPage() {
+       // mock 数据
+       EmployeeInfoDO dbInfo = randomPojo(EmployeeInfoDO.class, o -> { // 等会查询到
+           o.setInfoId(null);
+           o.setEmployeeNumber(null);
+           o.setName(null);
+           o.setDeptId(null);
+           o.setPhone(null);
+           o.setAvatar(null);
+           o.setEmail(null);
+           o.setPosition(null);
+           o.setPostId(null);
+           o.setEntryDate(null);
+           o.setProbationEndDate(null);
+           o.setWorkLocation(null);
+           o.setEmployeeStatus(null);
+           o.setGender(null);
+           o.setBirthDate(null);
+           o.setMarriageStatus(null);
+           o.setIdCardNumber(null);
+           o.setIdCardAddress(null);
+           o.setHouseholdType(null);
+           o.setHouseholdLocation(null);
+           o.setEducationLevel(null);
+           o.setMajor(null);
+           o.setGraduationSchool(null);
+           o.setGraduationDate(null);
+           o.setWorkStartDate(null);
+           o.setAnnualLeaveDays(null);
+           o.setSalaryBank(null);
+           o.setSalaryCardNumber(null);
+           o.setSalary(null);
+           o.setPositionSalary(null);
+           o.setProjectAllowance(null);
+           o.setSpecialPositionAllowance(null);
+           o.setForeignAllowance(null);
+           o.setLunchSubsidy(null);
+           o.setSpecialAllowance(null);
+           o.setSubsidy(null);
+           o.setYearEndBonus(null);
+           o.setStatus(null);
+           o.setCreateTime(null);
+           o.setUserId(null);
+       });
+       infoMapper.insert(dbInfo);
+       // 测试 infoId 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setInfoId(null)));
+       // 测试 employeenumber 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setEmployeeNumber(null)));
+       // 测试 name 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setName(null)));
+       // 测试 deptId 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setDeptId(null)));
+       // 测试 phone 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setPhone(null)));
+       // 测试 avatar 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setAvatar(null)));
+       // 测试 email 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setEmail(null)));
+       // 测试 position 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setPosition(null)));
+       // 测试 postId 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setPostId(null)));
+       // 测试 entryDate 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setEntryDate(null)));
+       // 测试 probationEndDate 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setProbationEndDate(null)));
+       // 测试 workLocation 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setWorkLocation(null)));
+       // 测试 employeeStatus 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setEmployeeStatus(null)));
+       // 测试 gender 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setGender(null)));
+       // 测试 birthDate 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setBirthDate(null)));
+       // 测试 marriageStatus 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setMarriageStatus(null)));
+       // 测试 idCardNumber 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setIdCardNumber(null)));
+       // 测试 idCardAddress 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setIdCardAddress(null)));
+       // 测试 householdType 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setHouseholdType(null)));
+       // 测试 householdLocation 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setHouseholdLocation(null)));
+       // 测试 educationLevel 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setEducationLevel(null)));
+       // 测试 major 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setMajor(null)));
+       // 测试 graduationSchool 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setGraduationSchool(null)));
+       // 测试 graduationDate 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setGraduationDate(null)));
+       // 测试 workStartDate 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setWorkStartDate(null)));
+       // 测试 annualLeaveDays 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setAnnualLeaveDays(null)));
+       // 测试 salaryBank 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSalaryBank(null)));
+       // 测试 salaryCardNumber 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSalaryCardNumber(null)));
+       // 测试 salary 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSalary(null)));
+       // 测试 positionSalary 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setPositionSalary(null)));
+       // 测试 projectAllowance 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setProjectAllowance(null)));
+       // 测试 specialPositionAllowance 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSpecialPositionAllowance(null)));
+       // 测试 foreignAllowance 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setForeignAllowance(null)));
+       // 测试 lunchSubsidy 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setLunchSubsidy(null)));
+       // 测试 specialAllowance 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSpecialAllowance(null)));
+       // 测试 subsidy 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSubsidy(null)));
+       // 测试 yearEndBonus 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setYearEndBonus(null)));
+       // 测试 status 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setStatus(null)));
+       // 测试 createTime 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setCreateTime(null)));
+       // 测试 userId 不匹配
+       infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setUserId(null)));
+       // 准备参数
+       EmployeeInfoPageReqVO reqVO = new EmployeeInfoPageReqVO();
+       reqVO.setInfoId(null);
+       reqVO.setEmployeeNumber(null);
+       reqVO.setName(null);
+       reqVO.setDeptId(null);
+       reqVO.setPhone(null);
+       reqVO.setAvatar(null);
+       reqVO.setEmail(null);
+       reqVO.setPosition(null);
+       reqVO.setPostId(null);
+       reqVO.setWorkLocation(null);
+       reqVO.setEmployeeStatus(null);
+       reqVO.setGender(null);
+       reqVO.setMarriageStatus(null);
+       reqVO.setIdCardNumber(null);
+       reqVO.setIdCardAddress(null);
+       reqVO.setHouseholdType(null);
+       reqVO.setHouseholdLocation(null);
+       reqVO.setEducationLevel(null);
+       reqVO.setMajor(null);
+       reqVO.setGraduationSchool(null);
+       reqVO.setAnnualLeaveDays(null);
+       reqVO.setSalaryBank(null);
+       reqVO.setSalaryCardNumber(null);
+       reqVO.setSalary(null);
+       reqVO.setPositionSalary(null);
+       reqVO.setProjectAllowance(null);
+       reqVO.setSpecialPositionAllowance(null);
+       reqVO.setForeignAllowance(null);
+       reqVO.setLunchSubsidy(null);
+       reqVO.setSpecialAllowance(null);
+       reqVO.setSubsidy(null);
+       reqVO.setYearEndBonus(null);
+       reqVO.setStatus(null);
+       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+       reqVO.setUserId(null);
+
+       // 调用
+       PageResult<EmployeeInfoDO> pageResult = infoService.getInfoPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbInfo, pageResult.getList().get(0));
+    }
+
+}

+ 2 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java

@@ -45,6 +45,8 @@ public interface ErrorCodeConstants {
     ErrorCode USER_PASSWORD_INCONSISTENT_FAILED = new ErrorCode(1_002_003_009, "新密码和确认密码不一致");
     ErrorCode USER_PASSWORD_SIMPLE_FAILED = new ErrorCode(1_002_003_010, "密码必须包含数字、大写字母、小写字母、特殊符号中的3种,且长度为9-30位");
     ErrorCode USER_TENANT_RELATE_NOT_EXISTS = new ErrorCode(1_002_003_011, "用户租户关系不存在");
+    ErrorCode USER_TENANT_EMPLOYEE_DUPLICATE = new ErrorCode(1_002_003_012, "该用户在名字为【{}】的租户下已存在员工");
+    ErrorCode USER_NOT_IN_TENANT = new ErrorCode(1_002_003_013, "该用户不在该租户中");
 
     // ========== 部门模块 1-002-004-000 ==========
     ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门");

+ 2 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java

@@ -14,9 +14,11 @@ public enum LoginLogTypeEnum {
     LOGIN_SOCIAL(101), // 使用社交登录
     LOGIN_MOBILE(103), // 使用手机登陆
     LOGIN_SMS(104), // 使用短信登陆
+    LOGIN_CHANGE_TENANT(105), // 切换租户登录
 
     LOGOUT_SELF(200),  // 自己主动登出
     LOGOUT_DELETE(202), // 强制退出
+    LOGOUT_CHANGE_TENANT(203), // 切换租户退出
     ;
 
     /**

+ 5 - 0
yudao-module-system/yudao-module-system-biz/pom.xml

@@ -28,6 +28,11 @@
             <artifactId>yudao-module-infra-api</artifactId>
             <version>${revision}</version>
         </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-employee-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
 
         <!-- 业务组件 -->
         <dependency>

+ 24 - 5
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java

@@ -6,10 +6,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
-import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO;
-import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
-import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSimpleRespVO;
+import cn.iocoder.yudao.framework.security.config.SecurityProperties;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*;
 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.annotation.security.PermitAll;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
@@ -35,6 +36,8 @@ public class TenantController {
 
     @Resource
     private TenantService tenantService;
+    @Resource
+    private SecurityProperties securityProperties;
 
     @GetMapping("/get-id-by-name")
     @PermitAll
@@ -61,14 +64,30 @@ public class TenantController {
         return success(tenantService.createTenant(createReqVO));
     }
 
+    @PostMapping("/join")
+    @Operation(summary = "加入租户")
+    public CommonResult<Long> joinTenant(@Valid @RequestBody TenantJoinReqVO createReqVO) {
+        return success(tenantService.joinTenant(createReqVO));
+    }
+
     @PutMapping("/update")
     @Operation(summary = "更新租户")
-    @PreAuthorize("@ss.hasPermission('system:tenant:update')")
+//    @PreAuthorize("@ss.hasPermission('system:tenant:update')")
     public CommonResult<Boolean> updateTenant(@Valid @RequestBody TenantSaveReqVO updateReqVO) {
         tenantService.updateTenant(updateReqVO);
         return success(true);
     }
 
+    @PutMapping("/change")
+    @Operation(summary = "切换租户")
+    public CommonResult<AuthLoginRespVO> changeTenant(@Valid @RequestBody TenantJoinReqVO updateReqVO,
+                                                      HttpServletRequest request) {
+        String token = SecurityFrameworkUtils.obtainAuthorization(request,
+                securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
+        updateReqVO.setToken(token);
+        return success(tenantService.changeTenant(updateReqVO));
+    }
+
     @DeleteMapping("/delete")
     @Operation(summary = "删除租户")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")

+ 36 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantJoinReqVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 加入租户 Request VO")
+@Data
+public class TenantJoinReqVO {
+
+//    @Schema(description = "关系ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15794")
+    private Long id;
+
+//    @Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "29632")
+//    @NotNull(message = "用户ID不能为空")
+    private Long userId;
+
+//    @Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3553")
+//    @NotNull(message = "租户ID不能为空")
+    private Long tenantId;
+
+    @Schema(description = "邀请码", requiredMode = Schema.RequiredMode.REQUIRED, example = "3553")
+    @NotNull(message = "邀请码不能为空")
+    private String corpId;
+
+    @Schema(description = "账号模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private String accountMode;
+
+//    @Schema(description = "当前生效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+//    @NotNull(message = "当前生效不能为空")
+    private Boolean actived;
+
+    private String token;
+
+}

+ 6 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java

@@ -52,4 +52,10 @@ public class TenantRespVO {
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    @Schema(description = "邀请码", example = "uuid")
+    private String corpId;
+
+    @Schema(description = "账号模式", example = "1")
+    private Integer accountMode;
+
 }

+ 2 - 8
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java

@@ -1,22 +1,16 @@
 package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant;
 
-import cn.hutool.core.util.ObjectUtil;
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import org.hibernate.validator.constraints.Length;
 
-import javax.validation.constraints.AssertTrue;
 import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-import javax.validation.constraints.Size;
 import java.time.LocalDateTime;
 
 @Schema(description = "管理后台 - 租户创建/修改 Request VO")
 @Data
 public class TenantSaveReqVO {
 
-    @Schema(description = "租户编号", example = "1024")
+//    @Schema(description = "租户编号", example = "1024")
     private Long id;
 
     @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
@@ -30,7 +24,7 @@ public class TenantSaveReqVO {
     @Schema(description = "联系手机", example = "15601691300")
     private String contactMobile;
 
-    @Schema(description = "租户状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "租户状态:默认传0", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
     @NotNull(message = "租户状态")
     private Integer status;
 

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/tenant/UserTenantRelateSaveReqVO.java

@@ -27,7 +27,7 @@ public class UserTenantRelateSaveReqVO {
     private String role;
 
     @Schema(description = "当前生效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "当前生效不能为空")
+//    @NotNull(message = "当前生效不能为空")
     private Boolean actived;
 
     @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")

+ 10 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java

@@ -77,4 +77,14 @@ public class TenantDO extends BaseDO {
      */
     private Integer accountCount;
 
+    /**
+     * 邀请码
+     */
+    private String corpId;
+
+    /**
+     * 账号模式
+     */
+    private Integer accountMode;
+
 }

+ 0 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java

@@ -92,9 +92,5 @@ public class AdminUserDO extends TenantBaseDO {
      * 最后登录时间
      */
     private LocalDateTime loginDate;
-    /**
-     * 当前租户编号
-     */
-    private Long tenantId;
 
 }

+ 4 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java

@@ -43,4 +43,8 @@ public interface TenantMapper extends BaseMapperX<TenantDO> {
         return selectList(TenantDO::getPackageId, packageId);
     }
 
+    default TenantDO selectByCorpId(String corpId){
+        return selectOne(TenantDO::getCorpId, corpId);
+    }
+
 }

+ 3 - 10
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java

@@ -1,14 +1,11 @@
 package cn.iocoder.yudao.module.system.dal.mysql.user;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
-import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
@@ -17,6 +14,7 @@ import java.util.List;
 @Mapper
 public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
 
+    @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到用户
     default AdminUserDO selectByUsername(String username) {
         return selectOne(AdminUserDO::getUsername, username);
     }
@@ -52,12 +50,7 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
     }
 
     default AdminUserDO selectByIdSkipTenant(Long userId) {
-
-        return selectOne(new QueryWrapper<AdminUserDO>()
-                .eq("id", userId)
-                .eq("deleted", false));
-
-
+        return selectOne(AdminUserDO::getId, userId);
     }
 
 }

+ 17 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java

@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.service.tenant;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantJoinReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
@@ -27,6 +29,14 @@ public interface TenantService {
      */
     Long createTenant(@Valid TenantSaveReqVO createReqVO);
 
+    /**
+     * 加入租户
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long joinTenant(@Valid TenantJoinReqVO createReqVO);
+
     /**
      * 更新租户
      *
@@ -34,6 +44,13 @@ public interface TenantService {
      */
     void updateTenant(@Valid TenantSaveReqVO updateReqVO);
 
+    /**
+     * 切换租户
+     *
+     * @param updateReqVO 更新信息
+     */
+    AuthLoginRespVO changeTenant(@Valid TenantJoinReqVO updateReqVO);
+
     /**
      * 更新租户的角色菜单
      *

+ 138 - 15
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java

@@ -2,33 +2,50 @@ package cn.iocoder.yudao.module.system.service.tenant;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
+import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeCreateReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeQueryReqDTO;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
+import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantJoinReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.tenant.UserTenantRelateSaveReqVO;
-import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
+import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
 import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert;
+import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
+import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
+import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
+import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
+import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
+import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
+import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
 import cn.iocoder.yudao.module.system.service.permission.MenuService;
 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
 import cn.iocoder.yudao.module.system.service.permission.RoleService;
@@ -84,7 +101,14 @@ public class TenantServiceImpl implements TenantService {
     private PermissionService permissionService;
     @Resource
     private UserTenantRelateService userTenantRelateService;
-
+    @Resource
+    private EmployeeApi employeeApi;
+    @Resource
+    private LoginLogService loginLogService;
+    @Resource
+    private OAuth2TokenService oauth2TokenService;
+    @Resource
+    private AdminAuthService authService;
 
     @Override
     public List<Long> getTenantIdList() {
@@ -118,27 +142,33 @@ public class TenantServiceImpl implements TenantService {
 
         // 创建租户
         TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);
+        tenant.setCorpId(IdUtil.fastSimpleUUID());
         tenantMapper.insert(tenant);
         // 获得用户信息
         LoginUser user = SecurityFrameworkUtils.getLoginUser();
         // 更新用户信息当前租户
         userService.updateUserTenantId(user.getId(), tenant.getId());
-        // 3创建角色
-
-        // 4给角色授权所有菜单权限
-
-        // 5给角色授权所有数据权限
+        // 将这个用户所有租户关系设为不生效
+        userTenantRelateService.deactivateAllForUser(user.getId());
+        // 插入用户租户关系
+        userTenantRelateService.createUserTenantRelate(new UserTenantRelateSaveReqVO().setUserId(user.getId()).setTenantId(tenant.getId()).setActived(true));
+        // 自动根据账号创建对应人事信息,只保存姓名、头像、手机号
+        AdminUserDO adminUserDO = userService.getUser(user.getId());
+        if (adminUserDO == null) {
+            throw exception(USER_NOT_EXISTS);
+        }
+        // 先判断该租户下员工信息是否存在,如果不存在则创建
+        EmployeeRespDTO employeeRespDTO = employeeApi.getEmployee(new EmployeeQueryReqDTO().setUserId(user.getId()).setTenantId(tenant.getId()));
+        if (employeeRespDTO == null) {
+            // 创建员工信息
+            employeeApi.createEmployee(new EmployeeCreateReqDTO().setUserId(user.getId()).setTenantId(tenant.getId()).setName(adminUserDO.getNickname()).setAvatar(adminUserDO.getAvatar()).setPhone(adminUserDO.getMobile()));
+        } else {
+            throw exception(USER_TENANT_EMPLOYEE_DUPLICATE, tenant.getName());
+        }
         // 创建租户的管理员
         TenantUtils.execute(tenant.getId(), () -> {
             // 创建角色
             Long roleId = createRole(0L);
-
-            // 1.1将这个用户所有租户关系设为不生效
-            userTenantRelateService.deactivateAllForUser(user.getId());
-            // 1.2插入用户租户关系
-            userTenantRelateService.createUserTenantRelate(new UserTenantRelateSaveReqVO().setUserId(user.getId()).setTenantId(tenant.getId()).setActived(true));
-
-
             // 分配角色
             permissionService.assignUserRole(user.getId(), singleton(roleId));
             // 修改租户的管理员
@@ -147,6 +177,38 @@ public class TenantServiceImpl implements TenantService {
         return tenant.getId();
     }
 
+    @Override
+    @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
+    public Long joinTenant(TenantJoinReqVO createReqVO) {
+        // 根据租户邀请码查询租户信息
+        TenantDO tenant = tenantMapper.selectByCorpId(createReqVO.getCorpId());
+        if (tenant == null || tenant.getId() == null) {
+            throw exception(TENANT_NOT_EXISTS);
+        }
+        // 获得用户信息
+        LoginUser user = SecurityFrameworkUtils.getLoginUser();
+        // 更新用户信息当前租户
+        userService.updateUserTenantId(user.getId(), tenant.getId());
+        // 将这个用户所有租户关系设为不生效
+        userTenantRelateService.deactivateAllForUser(user.getId());
+        // 插入用户租户关系
+        userTenantRelateService.createUserTenantRelate(new UserTenantRelateSaveReqVO().setUserId(user.getId()).setTenantId(tenant.getId()).setActived(true));
+        // 自动根据账号创建对应人事信息,只保存姓名、头像、手机号
+        AdminUserDO adminUserDO = userService.getUser(user.getId());
+        if (adminUserDO == null) {
+            throw exception(USER_NOT_EXISTS);
+        }
+        // 先判断该租户下员工信息是否存在,如果不存在则创建
+        EmployeeRespDTO employeeRespDTO = employeeApi.getEmployee(new EmployeeQueryReqDTO().setUserId(user.getId()).setTenantId(tenant.getId()));
+        if (employeeRespDTO == null) {
+            // 创建员工信息
+            employeeApi.createEmployee(new EmployeeCreateReqDTO().setUserId(user.getId()).setTenantId(tenant.getId()).setName(adminUserDO.getNickname()).setAvatar(adminUserDO.getAvatar()).setPhone(adminUserDO.getMobile()));
+        } else {
+            throw exception(USER_TENANT_EMPLOYEE_DUPLICATE, tenant.getName());
+        }
+        return tenant.getId();
+    }
+
     private Long createUser(Long roleId, TenantSaveReqVO createReqVO) {
         // 创建用户
         Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO));
@@ -205,6 +267,34 @@ public class TenantServiceImpl implements TenantService {
 //        }
     }
 
+    @Override
+    @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
+    public AuthLoginRespVO changeTenant(TenantJoinReqVO createReqVO) {
+        // 根据租户邀请码查询租户信息
+        TenantDO tenant = tenantMapper.selectByCorpId(createReqVO.getCorpId());
+        if (tenant == null || tenant.getId() == null) {
+            throw exception(TENANT_NOT_EXISTS);
+        }
+        // 获得用户信息
+        LoginUser user = SecurityFrameworkUtils.getLoginUser();
+        if (user == null) {
+            throw exception(USER_NOT_EXISTS);
+        }
+        AdminUserDO adminUserDO = userService.getUser(user.getId());
+        // 校验该用户是否在该租户中
+        if (!userTenantRelateService.checkUserHasTenant(user.getId(), tenant.getId())) {
+            throw exception(USER_NOT_IN_TENANT);
+        }
+        // 更新用户信息当前租户
+        userService.updateUserTenantId(user.getId(), tenant.getId());
+        // 将这个用户所有租户关系设为不生效
+        userTenantRelateService.deactivateAllForUser(user.getId());
+        // 将这个用户的这个租户关系设为生效
+        userTenantRelateService.activateForUser(new UserTenantRelateSaveReqVO().setUserId(user.getId()).setTenantId(tenant.getId()));
+        authService.logout(createReqVO.getToken(), LoginLogTypeEnum.LOGOUT_CHANGE_TENANT.getType());
+        return createTokenAfterLoginSuccess(adminUserDO.getId(), adminUserDO.getUsername(), LoginLogTypeEnum.LOGIN_CHANGE_TENANT);
+    }
+
     private void validTenantNameDuplicate(String name, Long id) {
         TenantDO tenant = tenantMapper.selectByName(name);
         if (tenant == null) {
@@ -354,4 +444,37 @@ public class TenantServiceImpl implements TenantService {
         return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
     }
 
+    private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
+        // 插入登陆日志
+        createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
+        // 创建访问令牌
+        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
+                OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);
+        // 构建返回结果
+        return AuthConvert.INSTANCE.convert(accessTokenDO);
+    }
+
+    private void createLoginLog(Long userId, String username,
+                                LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
+        // 插入登录日志
+        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
+        reqDTO.setLogType(logTypeEnum.getType());
+        reqDTO.setTraceId(TracerUtils.getTraceId());
+        reqDTO.setUserId(userId);
+        reqDTO.setUserType(getUserType().getValue());
+        reqDTO.setUsername(username);
+        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+        reqDTO.setUserIp(ServletUtils.getClientIP());
+        reqDTO.setResult(loginResult.getResult());
+        loginLogService.createLoginLog(reqDTO);
+        // 更新最后登录时间
+        if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
+            userService.updateUserLogin(userId, ServletUtils.getClientIP());
+        }
+    }
+
+    private UserTypeEnum getUserType() {
+        return UserTypeEnum.ADMIN;
+    }
+
 }

+ 17 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/UserTenantRelateService.java

@@ -61,4 +61,21 @@ public interface UserTenantRelateService {
      */
     int deactivateAllForUser(Long userId);
 
+    /**
+     * 校验该用户是否在该租户中
+     *
+     * @param userId
+     * @param tenantId
+     * @return
+     */
+    boolean checkUserHasTenant(Long userId, Long tenantId);
+
+    /**
+     * 将这个用户这个租户关系设为生效
+     *
+     * @param queryReqVO
+     * @return
+     */
+    int activateForUser(@Valid UserTenantRelateSaveReqVO queryReqVO);
+
 }

+ 50 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/UserTenantRelateServiceImpl.java

@@ -5,7 +5,8 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.tenant.UserTenant
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.tenant.UserTenantRelateSaveReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.UserTenantRelateDO;
 import cn.iocoder.yudao.module.system.dal.mysql.user.UserTenantRelateMapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -79,9 +80,54 @@ public class UserTenantRelateServiceImpl implements UserTenantRelateService {
      */
     @Override
     public int deactivateAllForUser(Long userId) {
-        UpdateWrapper<UserTenantRelateDO> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.eq("user_id", userId).set("actived", false); // 注意:这里使用false而不是b'0',因为MyBatis-Plus会处理类型转换
-        return userTenantRelateMapper.update(null, updateWrapper); // 第一个参数是null,因为我们不需要传递实体对象,只使用Wrapper来指定更新条件
+        // 创建一个LambdaUpdateWrapper实例
+        LambdaUpdateWrapper<UserTenantRelateDO> updateWrapper = new LambdaUpdateWrapper<>();
+        // 使用Lambda表达式来指定更新条件和要更新的字段
+        updateWrapper.eq(UserTenantRelateDO::getUserId, userId)
+                .set(UserTenantRelateDO::getActived, false); // 注意:这里使用false,MyBatis-Plus会处理类型转换
+        // 调用Mapper的update方法,传入null作为实体对象(因为我们只使用Wrapper来指定更新条件)
+        // 和LambdaUpdateWrapper作为更新条件
+        return userTenantRelateMapper.update(null, updateWrapper);
+    }
+
+    /**
+     * 校验该用户是否在该租户中
+     *
+     * @param userId
+     * @param tenantId
+     * @return
+     */
+    @Override
+    public boolean checkUserHasTenant(Long userId, Long tenantId) {
+        // 使用LambdaQueryWrapper来构建查询条件
+        LambdaQueryWrapper<UserTenantRelateDO> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(UserTenantRelateDO::getUserId, userId)
+                .eq(UserTenantRelateDO::getTenantId, tenantId);
+        // 使用Mapper的selectCount方法查询满足条件的记录数
+        Long count = userTenantRelateMapper.selectCount(queryWrapper);
+        // 如果记录数大于0,则返回true,表示用户拥有该租户
+        return count > 0;
+    }
+
+
+    /**
+     * 将这个用户这个租户关系设为生效
+     *
+     * @param updateReqVO 包含用户ID和可能的其他信息
+     * @return 受影响的行数
+     */
+    @Override
+    public int activateForUser(UserTenantRelateSaveReqVO updateReqVO) {
+        // 创建一个LambdaUpdateWrapper实例
+        LambdaUpdateWrapper<UserTenantRelateDO> updateWrapper = new LambdaUpdateWrapper<>();
+        // 使用Lambda表达式来指定更新条件和要更新的字段
+        updateWrapper
+                .eq(UserTenantRelateDO::getUserId, updateReqVO.getUserId())
+                .eq(UserTenantRelateDO::getTenantId, updateReqVO.getTenantId())
+                .set(UserTenantRelateDO::getActived, true);
+        // 调用Mapper的update方法,传入null作为实体对象(因为我们只使用Wrapper来指定更新条件)
+        // 和LambdaUpdateWrapper作为更新条件
+        return userTenantRelateMapper.update(null, updateWrapper);
     }
 
 }

+ 7 - 0
yudao-server/pom.xml

@@ -101,6 +101,13 @@
             <version>${revision}</version>
         </dependency>
 
+        <!-- 人事 相关模块。默认注释,保证编译速度 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-employee-biz</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
         <!-- spring boot 配置所需依赖 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 1 - 0
yudao-server/src/main/resources/application-local.yaml

@@ -172,6 +172,7 @@ logging:
     cn.iocoder.yudao.module.statistics.dal.mysql: debug
     cn.iocoder.yudao.module.crm.dal.mysql: debug
     cn.iocoder.yudao.module.erp.dal.mysql: debug
+    cn.iocoder.yudao.module.personnel.dal.mysql: debug
     org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示
 
 debug: false

+ 3 - 0
yudao-server/src/main/resources/application.yaml

@@ -199,6 +199,9 @@ yudao:
       - /admin-api/system/user/profile/reset-password # 使用验证码重置密码,和租户无关
       - /admin-api/system/auth/login # 使用账号登录,和租户无关
       - /admin-api/system/tenant/create # 创建租户,不携带租户编号
+      - /admin-api/system/tenant/join # 加入租户,不携带租户编号
+      - /admin-api/system/tenant/change # 切换租户,不携带租户编号
+      - /admin-api/presonnel/employee/create  # 创建员工,不携带租户编号
     ignore-tables:
       - system_tenant
       - system_tenant_package