feat(system): 增加租户代理层级控制与级别校验
This commit is contained in:
@@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantLevelRespVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
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.TenantRespVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO;
|
||||||
@@ -136,4 +138,13 @@ public class TenantController {
|
|||||||
return success(BeanUtils.toBean(pageResult, TenantRespVO.class));
|
return success(BeanUtils.toBean(pageResult, TenantRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getSelfTenantLevel")
|
||||||
|
@Operation(summary = "获取自身代理级别")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:tenant:query-self-Level')")
|
||||||
|
public CommonResult<TenantLevelRespVO> getSelfTenantPage() {
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
TenantDO tenant = tenantService.getTenant(tenantId);
|
||||||
|
return success(BeanUtils.toBean(tenant, TenantLevelRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 租户 Response VO")
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class TenantLevelRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "租户等级",example = "1")
|
||||||
|
private String tenantLevel;
|
||||||
|
}
|
||||||
@@ -67,6 +67,9 @@ public class TenantRespVO {
|
|||||||
@Schema(description = "上级租户 Id", example = "1024")
|
@Schema(description = "上级租户 Id", example = "1024")
|
||||||
private Long parentId;
|
private Long parentId;
|
||||||
|
|
||||||
@Schema(description = "租户类型", example = "代理/客户")
|
@Schema(description = "租户类型", example = "代理/客户")
|
||||||
private String tenantType;
|
private String tenantType;
|
||||||
|
|
||||||
|
@Schema(description = "租户等级",example = "1")
|
||||||
|
private String tenantLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,4 +106,9 @@ public class TenantDO extends BaseDO {
|
|||||||
* 租户类型
|
* 租户类型
|
||||||
*/
|
*/
|
||||||
private String tenantType;
|
private String tenantType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理级别
|
||||||
|
*/
|
||||||
|
private Integer tenantLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!");
|
ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!");
|
||||||
ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在");
|
ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在");
|
||||||
ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在");
|
ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在");
|
||||||
|
ErrorCode TENANT_LEVEL_CANT_CREATE_AGENCY = new ErrorCode(1_002_015_006, "租户级别不能创建代理租户");
|
||||||
|
|
||||||
// ========== 租户套餐 1-002-016-000 ==========
|
// ========== 租户套餐 1-002-016-000 ==========
|
||||||
ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在");
|
ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在");
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.enums.tenant;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2025/11/21 18:55
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public enum TenantEnum {
|
||||||
|
|
||||||
|
|
||||||
|
AGENCY("代理"),
|
||||||
|
USER("用户");
|
||||||
|
|
||||||
|
|
||||||
|
private String tenantType;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
|
|||||||
import cn.iocoder.yudao.module.system.dal.mysql.tenantbalance.TenantBalanceMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.tenantbalance.TenantBalanceMapper;
|
||||||
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
|
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
|
||||||
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
|
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.enums.tenant.TenantEnum;
|
||||||
import cn.iocoder.yudao.module.system.service.permission.MenuService;
|
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.PermissionService;
|
||||||
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
||||||
@@ -110,37 +111,62 @@ public class TenantServiceImpl implements TenantService {
|
|||||||
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
||||||
@DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明
|
@DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明
|
||||||
public Long createTenant(TenantSaveReqVO createReqVO) {
|
public Long createTenant(TenantSaveReqVO createReqVO) {
|
||||||
// 校验租户名称是否重复
|
// 校验租户名称是否重复(null表示新增场景,无需排除当前ID)
|
||||||
validTenantNameDuplicate(createReqVO.getName(), null);
|
validTenantNameDuplicate(createReqVO.getName(), null);
|
||||||
// 校验租户域名是否重复
|
|
||||||
|
// 校验租户域名是否重复(null表示新增场景,无需排除当前ID)
|
||||||
validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
|
validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
|
||||||
// 校验套餐被禁用
|
|
||||||
|
// 校验并获取租户套餐信息(确保套餐存在且未被禁用)
|
||||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
||||||
|
|
||||||
// 创建租户
|
// 获取当前操作租户的ID(即创建者的租户ID)
|
||||||
TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);
|
Long currentTenantId = TenantContextHolder.getTenantId();
|
||||||
Long tenantId = TenantContextHolder.getTenantId();
|
|
||||||
tenant.setParentId(tenantId);
|
// 查询当前租户的详细信息
|
||||||
tenantMapper.insert(tenant);
|
TenantDO currentTenant = tenantMapper.selectById(currentTenantId);
|
||||||
// 创建租户的管理员
|
|
||||||
TenantUtils.execute(tenant.getId(), () -> {
|
// 校验租户类型和层级权限:不允许创建代理类型租户,或当前租户级别为2的租户不允许创建
|
||||||
// 创建角色
|
if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) {
|
||||||
Long roleId = createRole(tenantPackage);
|
throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY);
|
||||||
// 创建用户,并分配角色
|
|
||||||
Long userId = createUser(roleId, createReqVO);
|
|
||||||
// 修改租户的管理员
|
|
||||||
tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId));
|
|
||||||
});
|
|
||||||
// 初始化代理钱包
|
|
||||||
if (tenant.getTenantType().equals("代理")) {
|
|
||||||
// 创建租户的钱包
|
|
||||||
TenantBalanceDO tenantBalance = new TenantBalanceDO();
|
|
||||||
tenantBalance.setId(tenant.getId());
|
|
||||||
tenantBalance.setBalance(0);
|
|
||||||
tenantBalance.setVersion(0);
|
|
||||||
tenantBalanceMapper.insert(tenantBalance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将请求参数转换为租户数据对象
|
||||||
|
TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);
|
||||||
|
|
||||||
|
// 设置新租户的级别为当前租户级别+1(层级关系)
|
||||||
|
if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType())){
|
||||||
|
tenant.setTenantLevel(currentTenant.getTenantLevel() + 1);
|
||||||
|
}
|
||||||
|
// 设置新租户的父租户ID为当前租户ID(建立层级关系)
|
||||||
|
tenant.setParentId(currentTenantId);
|
||||||
|
|
||||||
|
// 将新租户信息插入数据库
|
||||||
|
tenantMapper.insert(tenant);
|
||||||
|
|
||||||
|
// 在新创建的租户上下文中执行管理员初始化操作
|
||||||
|
TenantUtils.execute(tenant.getId(), () -> {
|
||||||
|
// 创建租户的默认角色
|
||||||
|
Long roleId = createRole(tenantPackage);
|
||||||
|
|
||||||
|
// 创建租户的管理员用户,并分配角色
|
||||||
|
Long userId = createUser(roleId, createReqVO);
|
||||||
|
|
||||||
|
// 将创建的用户设置为租户的联系人(管理员)
|
||||||
|
tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果创建的是代理类型租户,则初始化其钱包
|
||||||
|
if (tenant.getTenantType().equals("代理")) {
|
||||||
|
// 创建租户钱包对象
|
||||||
|
TenantBalanceDO tenantBalance = new TenantBalanceDO();
|
||||||
|
tenantBalance.setId(tenant.getId()); // 钱包ID与租户ID一致
|
||||||
|
tenantBalance.setBalance(0); // 初始余额设为0
|
||||||
|
tenantBalance.setVersion(0); // 初始版本号设为0
|
||||||
|
tenantBalanceMapper.insert(tenantBalance); // 插入钱包记录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回新创建的租户ID
|
||||||
return tenant.getId();
|
return tenant.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,4 +359,4 @@ public class TenantServiceImpl implements TenantService {
|
|||||||
return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
|
return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user