tuqin
3 天以前 ce96310177bdd6d24ac90bd6f92d8def30b680af
fix(hrm): 修复修改员工时的「部门不存在」与「系统异常」

- DeptServiceImpl.validateDeptList 增加 @DataPermission(enable=false):此前非超管校验部门时受数据权限过滤,误报部门不存在
- HrmEmployeeMapper 新增 selectByPhoneIgnoreDeleted / selectByEmployeeNoIgnoreDeleted(绕过逻辑删除查询)
- 员工新增/修改的手机号唯一性校验改为包含已删除档案:uk_phone 唯一索引不区分 deleted,只查未删除会漏判,写库时抛唯一约束异常(前端表现为系统异常)
- 新增错误码 EMPLOYEE_PHONE_OCCUPIED_BY_DELETED / EMPLOYEE_NO_OCCUPIED_BY_DELETED,提示明确说明被已删除档案占用
已修改4个文件
43 ■■■■■ 文件已修改
yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/employee/HrmEmployeeMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java
@@ -31,6 +31,8 @@
    ErrorCode EMPLOYEE_CONTRACT_IMPORT_EMPLOYEE_NAME_NOT_EXISTS = new ErrorCode(1_030_000_018, "员工姓名【{}】不存在,请先维护员工档案");
    ErrorCode EMPLOYEE_CONTRACT_IMPORT_EMPLOYEE_NAME_MULTIPLE = new ErrorCode(1_030_000_019, "员工姓名【{}】对应多个员工档案,无法自动匹配,请先在页面手工为该员工新增合同");
    ErrorCode EMPLOYEE_CONTRACT_IMPORT_CONTRACT_EXISTS = new ErrorCode(1_030_000_020, "该员工【{}】已存在相同类型、相同开始日期的合同,如需覆盖请勾选“已存在时更新”");
    ErrorCode EMPLOYEE_PHONE_OCCUPIED_BY_DELETED = new ErrorCode(1_030_000_021, "手机号【{}】已被一条【已删除】的员工档案占用,请更换手机号,或联系管理员清理该历史档案");
    ErrorCode EMPLOYEE_NO_OCCUPIED_BY_DELETED = new ErrorCode(1_030_000_022, "员工编号【{}】已被一条【已删除】的员工档案占用,请更换员工编号,或联系管理员清理该历史档案");
    // ========== 请假申请 1-030-001-000 ==========
    ErrorCode LEAVE_APPLICATION_NOT_EXISTS = new ErrorCode(1_030_001_000, "请假申请不存在");
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/employee/HrmEmployeeMapper.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeePageReqVO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Collection;
import java.util.List;
@@ -23,6 +25,20 @@
        return selectOne(HrmEmployeeDO::getPhone, phone);
    }
    /**
     * 按手机号查询(**包含已逻辑删除的记录**)。
     * 唯一性校验必须包含已删除记录:hrm_employee.uk_phone 唯一索引不区分 deleted,
     * 若只查未删除记录会漏判,写库时抛唯一约束异常,前端表现为“系统异常”。
     */
    @Select("SELECT * FROM hrm_employee WHERE phone = #{phone} LIMIT 1")
    HrmEmployeeDO selectByPhoneIgnoreDeleted(@Param("phone") String phone);
    /**
     * 按员工编号查询(**包含已逻辑删除的记录**),用途同上。
     */
    @Select("SELECT * FROM hrm_employee WHERE employee_no = #{employeeNo} LIMIT 1")
    HrmEmployeeDO selectByEmployeeNoIgnoreDeleted(@Param("employeeNo") String employeeNo);
    default HrmEmployeeDO selectByName(String name) {
        return selectOne(HrmEmployeeDO::getName, name);
    }
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
@@ -104,9 +104,15 @@
        deptApi.validateDeptList(Collections.singleton(createReqVO.getDeptId()));
        // 2. 校验岗位
        postApi.validPostList(createReqVO.getPostIds());
        // 3. 校验手机号是否已存在
        if (employeeMapper.selectByPhone(createReqVO.getPhone()) != null) {
            throw exception(EMPLOYEE_PHONE_EXISTS);
        // 3. 校验手机号是否已存在(**包含已删除档案**:uk_phone 唯一索引不区分 deleted,
        //    只查未删除记录会漏判,导致写库时抛唯一约束异常,前端显示“系统异常”)
        if (createReqVO.getPhone() != null) {
            HrmEmployeeDO existPhone = employeeMapper.selectByPhoneIgnoreDeleted(createReqVO.getPhone());
            if (existPhone != null) {
                throw existPhone.getDeleted() != null && existPhone.getDeleted()
                        ? exception(EMPLOYEE_PHONE_OCCUPIED_BY_DELETED, createReqVO.getPhone())
                        : exception(EMPLOYEE_PHONE_EXISTS);
            }
        }
        // 4. 同步创建系统用户
        AdminUserCreateReqDTO userCreateReqDTO = new AdminUserCreateReqDTO();
@@ -186,10 +192,14 @@
        deptApi.validateDeptList(Collections.singleton(updateReqVO.getDeptId()));
        // 校验岗位
        postApi.validPostList(updateReqVO.getPostIds());
        // 校验手机号是否已存在(如果手机号有变更)
        if (!Objects.equals(employee.getPhone(), updateReqVO.getPhone())
                && employeeMapper.selectByPhone(updateReqVO.getPhone()) != null) {
            throw exception(EMPLOYEE_PHONE_EXISTS);
        // 校验手机号是否已存在(如果手机号有变更;**包含已删除档案**,原因见 createEmployee)
        if (!Objects.equals(employee.getPhone(), updateReqVO.getPhone()) && updateReqVO.getPhone() != null) {
            HrmEmployeeDO existPhone = employeeMapper.selectByPhoneIgnoreDeleted(updateReqVO.getPhone());
            if (existPhone != null && !Objects.equals(existPhone.getId(), updateReqVO.getId())) {
                throw existPhone.getDeleted() != null && existPhone.getDeleted()
                        ? exception(EMPLOYEE_PHONE_OCCUPIED_BY_DELETED, updateReqVO.getPhone())
                        : exception(EMPLOYEE_PHONE_EXISTS);
            }
        }
        // 更新员工主表
        HrmEmployeeDO updateObj = BeanUtils.toBean(updateReqVO, HrmEmployeeDO.class);
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -223,6 +223,7 @@
    }
    @Override
    @DataPermission(enable = false) // 仅校验部门是否存在/启用,不受数据权限限制(否则非超管会误报"部门不存在")
    public void validateDeptList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;