jeecgboot/JeecgBoot · error · JeecgBootException

用户尚有未退出的组织,无法删除!

Error message

用户尚有未退出的组织,无法删除!

What it means

deleteUserByPassword throws (step2 continued) when getTenantIdsByUserId returns a non-empty list — the user still belongs to other tenants/orgs. Full deletion would orphan their membership elsewhere, so it is blocked until all orgs are exited.

Source

Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java:912

        //被删除人的用户id
        String userId = sysUser.getId();
        //被删除人的密码
        String password = sysUser.getPassword();
        //当前登录用户
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //step1 判断当前用户是否为当前租户的管理员(只有超级管理员和账号管理员可以删除)
        Long isHaveAdmin = sysTenantPackUserMapper.izHaveBuyAuth(user.getId(), tenantId);
        if(null == isHaveAdmin || 0 == isHaveAdmin){
            throw new JeecgBootException("您不是当前组织的管理员,无法删除用户!");
        }
        //step2 离职状态下,并且无其他组织情况下,可以删除
        SysUserTenant sysUserTenant = userTenantMapper.getUserTenantByTenantId(userId, tenantId);
        if(null == sysUserTenant || !CommonConstant.USER_TENANT_QUIT.equals(sysUserTenant.getStatus())){
            throw new JeecgBootException("用户没有离职,不允许删除!"); 
        }
        List<Integer> tenantIdsByUserId = userTenantMapper.getTenantIdsByUserId(userId);
        if(CollectionUtils.isNotEmpty(tenantIdsByUserId) && tenantIdsByUserId.size()>0){
            throw new JeecgBootException("用户尚有未退出的组织,无法删除!");
        }
        //step3 当天创建的用户和创建人可以删除
        SysUser sysUserData = userService.getById(userId);
        if(!sysUserData.getCreateBy().equals(user.getUsername())){
            throw new JeecgBootException("您不是该用户的创建人,无法删除!");
        }
        
        // 代码逻辑说明: 【QQYUN-11839】删除用户,需要输入被删除用户的密码,这逻辑对吗?不应该是管理员的密码吗---
        this.verifyCreateTimeAndPassword(sysUserData,password);

        //step5 逻辑删除用户
        userService.deleteUser(userId);
        //step6 真实删除用户
        userService.removeLogicDeleted(Collections.singletonList(userId));
    }

    /**
     * 验证创建时间和密码

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Process the user's resignation from all other tenants first until getTenantIdsByUserId returns empty.
  2. Review the list of remaining tenants returned and exit each.
  3. If relations are stale, remove them administratively, then retry deletion.
  4. Frontend should show the remaining orgs so the operator knows what to clear.

Example fix

// before
tenantService.deleteUserByPassword(targetUser, tenantId);

// after
List<Integer> remaining = userTenantMapper.getTenantIdsByUserId(targetUser.getId());
if (CollectionUtils.isNotEmpty(remaining)) {
    return Result.error("用户仍属于其它组织:" + remaining + ",请先全部退出");
}
tenantService.deleteUserByPassword(targetUser, tenantId);
Defensive patterns

Strategy: validation

Validate before calling

List<Integer> remaining = userTenantMapper.getTenantIdsByUserId(userId);
if (CollectionUtils.isNotEmpty(remaining)) {
    return Result.error("用户仍属于其它组织:" + remaining);
}

Prevention

When it happens

Trigger: The user has resigned from the current tenant but still has active relations in one or more other tenants. The deletion is refused to preserve referential integrity across organizations.

Common situations: Multi-tenant user who resigned from one org but remains in others; stale relations not cleaned up after prior exits; the operator overlooked other memberships.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/8cdb6ec85149eb3c. Report an issue: GitHub.