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.excel.core.util.ExcelUtils;
|
||||
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.TenantRespVO;
|
||||
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));
|
||||
}
|
||||
|
||||
@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")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "租户类型", example = "代理/客户")
|
||||
private String tenantType;
|
||||
@Schema(description = "租户类型", example = "代理/客户")
|
||||
private String tenantType;
|
||||
|
||||
@Schema(description = "租户等级",example = "1")
|
||||
private String tenantLevel;
|
||||
}
|
||||
|
||||
@@ -106,4 +106,9 @@ public class TenantDO extends BaseDO {
|
||||
* 租户类型
|
||||
*/
|
||||
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_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在");
|
||||
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 ==========
|
||||
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.enums.permission.RoleCodeEnum;
|
||||
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.PermissionService;
|
||||
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
||||
@@ -110,37 +111,62 @@ public class TenantServiceImpl implements TenantService {
|
||||
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
||||
@DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明
|
||||
public Long createTenant(TenantSaveReqVO createReqVO) {
|
||||
// 校验租户名称是否重复
|
||||
// 校验租户名称是否重复(null表示新增场景,无需排除当前ID)
|
||||
validTenantNameDuplicate(createReqVO.getName(), null);
|
||||
// 校验租户域名是否重复
|
||||
|
||||
// 校验租户域名是否重复(null表示新增场景,无需排除当前ID)
|
||||
validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
|
||||
// 校验套餐被禁用
|
||||
|
||||
// 校验并获取租户套餐信息(确保套餐存在且未被禁用)
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
||||
|
||||
// 创建租户
|
||||
TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
tenant.setParentId(tenantId);
|
||||
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());
|
||||
tenantBalance.setBalance(0);
|
||||
tenantBalance.setVersion(0);
|
||||
tenantBalanceMapper.insert(tenantBalance);
|
||||
|
||||
// 获取当前操作租户的ID(即创建者的租户ID)
|
||||
Long currentTenantId = TenantContextHolder.getTenantId();
|
||||
|
||||
// 查询当前租户的详细信息
|
||||
TenantDO currentTenant = tenantMapper.selectById(currentTenantId);
|
||||
|
||||
// 校验租户类型和层级权限:不允许创建代理类型租户,或当前租户级别为2的租户不允许创建
|
||||
if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) {
|
||||
throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY);
|
||||
}
|
||||
|
||||
|
||||
// 将请求参数转换为租户数据对象
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -333,4 +359,4 @@ public class TenantServiceImpl implements TenantService {
|
||||
return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user