From 431c943019fbaa6372f114745586c40b9f85e162 Mon Sep 17 00:00:00 2001 From: ziin Date: Fri, 21 Nov 2025 19:50:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(system):=20=E5=A2=9E=E5=8A=A0=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E4=BB=A3=E7=90=86=E5=B1=82=E7=BA=A7=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E4=B8=8E=E7=BA=A7=E5=88=AB=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/tenant/TenantController.java | 11 +++ .../tenant/vo/tenant/TenantLevelRespVO.java | 15 ++++ .../admin/tenant/vo/tenant/TenantRespVO.java | 7 +- .../dal/dataobject/tenant/TenantDO.java | 5 ++ .../system/enums/ErrorCodeConstants.java | 1 + .../system/enums/tenant/TenantEnum.java | 23 ++++++ .../service/tenant/TenantServiceImpl.java | 82 ++++++++++++------- 7 files changed, 114 insertions(+), 30 deletions(-) create mode 100755 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java create mode 100644 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index edde75d..9d57581 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -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 getSelfTenantPage() { + Long tenantId = TenantContextHolder.getTenantId(); + TenantDO tenant = tenantService.getTenant(tenantId); + return success(BeanUtils.toBean(tenant, TenantLevelRespVO.class)); + } + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java new file mode 100755 index 0000000..af12227 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java @@ -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; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java index b53cbcc..3564a24 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java @@ -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; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java index 9f1be24..486af7b 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java @@ -106,4 +106,9 @@ public class TenantDO extends BaseDO { * 租户类型 */ private String tenantType; + + /** + * 代理级别 + */ + private Integer tenantLevel; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index be2f4b8..3e33b79 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -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, "租户套餐不存在"); diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java new file mode 100644 index 0000000..5432ea0 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java @@ -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; + +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index e196d7f..48d9720 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -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()); } -} +} \ No newline at end of file