From 0530605839d859d82b3bcdce095bf8b0e3a89d6b Mon Sep 17 00:00:00 2001 From: chenhao Date: Thu, 26 Feb 2026 16:50:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(tenant):=20=E5=AE=9E=E7=8E=B0=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E5=88=9B=E5=BB=BA=E6=97=B6=E8=87=AA=E5=8A=A8=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=92=8C=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改create方法返回类型为Long并接收CreateTenantDTO参数 - 新增createTenantWithAdmin方法实现完整的租户初始化流程 - 添加租户编码唯一性校验逻辑 - 实现根组织、管理员角色、默认菜单权限的自动创建 - 集成管理员用户的自动生成和绑定机制 - 添加密码重置标识字段到SysUser实体 - 实现事务回滚确保数据一致性 --- .../controller/SysTenantController.java | 4 +- .../java/com/imeeting/entity/SysUser.java | 1 + .../imeeting/service/SysTenantService.java | 7 + .../service/impl/SysTenantServiceImpl.java | 132 +++++++++++++++++- 4 files changed, 140 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/imeeting/controller/SysTenantController.java b/backend/src/main/java/com/imeeting/controller/SysTenantController.java index 9977b3a..79e4562 100644 --- a/backend/src/main/java/com/imeeting/controller/SysTenantController.java +++ b/backend/src/main/java/com/imeeting/controller/SysTenantController.java @@ -48,8 +48,8 @@ public class SysTenantController { @PostMapping @PreAuthorize("@ss.hasPermi('sys_tenant:create')") @Log(value = "新增租户", type = "租户管理") - public ApiResponse create(@RequestBody SysTenant tenant) { - return ApiResponse.ok(sysTenantService.save(tenant)); + public ApiResponse create(@RequestBody com.imeeting.dto.CreateTenantDTO tenantDto) { + return ApiResponse.ok(sysTenantService.createTenantWithAdmin(tenantDto)); } @PutMapping("/{id}") diff --git a/backend/src/main/java/com/imeeting/entity/SysUser.java b/backend/src/main/java/com/imeeting/entity/SysUser.java index 13ae135..8ee5cd8 100644 --- a/backend/src/main/java/com/imeeting/entity/SysUser.java +++ b/backend/src/main/java/com/imeeting/entity/SysUser.java @@ -15,6 +15,7 @@ public class SysUser extends BaseEntity { private String email; private String phone; private String passwordHash; + private Integer pwdResetRequired; private Boolean isPlatformAdmin; diff --git a/backend/src/main/java/com/imeeting/service/SysTenantService.java b/backend/src/main/java/com/imeeting/service/SysTenantService.java index ceae7a0..01b851f 100644 --- a/backend/src/main/java/com/imeeting/service/SysTenantService.java +++ b/backend/src/main/java/com/imeeting/service/SysTenantService.java @@ -1,7 +1,14 @@ package com.imeeting.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.imeeting.dto.CreateTenantDTO; import com.imeeting.entity.SysTenant; public interface SysTenantService extends IService { + /** + * 创建租户并自动初始化管理员、角色、组织及权限 + * @param dto 租户创建信息 + * @return 租户ID + */ + Long createTenantWithAdmin(CreateTenantDTO dto); } diff --git a/backend/src/main/java/com/imeeting/service/impl/SysTenantServiceImpl.java b/backend/src/main/java/com/imeeting/service/impl/SysTenantServiceImpl.java index 46686fe..8c6bd8d 100644 --- a/backend/src/main/java/com/imeeting/service/impl/SysTenantServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/impl/SysTenantServiceImpl.java @@ -1,11 +1,139 @@ package com.imeeting.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.imeeting.entity.SysTenant; +import com.imeeting.dto.CreateTenantDTO; +import com.imeeting.entity.*; +import com.imeeting.mapper.SysRolePermissionMapper; import com.imeeting.mapper.SysTenantMapper; -import com.imeeting.service.SysTenantService; +import com.imeeting.mapper.SysUserRoleMapper; +import com.imeeting.service.*; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; @Service public class SysTenantServiceImpl extends ServiceImpl implements SysTenantService { + + private final SysUserService sysUserService; + private final SysRoleService sysRoleService; + private final SysOrgService sysOrgService; + private final SysPermissionService sysPermissionService; + private final SysParamService sysParamService; + private final SysUserRoleMapper sysUserRoleMapper; + private final SysRolePermissionMapper sysRolePermissionMapper; + private final SysTenantUserService sysTenantUserService; + private final PasswordEncoder passwordEncoder; + + public SysTenantServiceImpl(SysUserService sysUserService, SysRoleService sysRoleService, + SysOrgService sysOrgService, SysPermissionService sysPermissionService, + SysParamService sysParamService, SysUserRoleMapper sysUserRoleMapper, + SysRolePermissionMapper sysRolePermissionMapper, + SysTenantUserService sysTenantUserService, PasswordEncoder passwordEncoder) { + this.sysUserService = sysUserService; + this.sysRoleService = sysRoleService; + this.sysOrgService = sysOrgService; + this.sysPermissionService = sysPermissionService; + this.sysParamService = sysParamService; + this.sysUserRoleMapper = sysUserRoleMapper; + this.sysRolePermissionMapper = sysRolePermissionMapper; + this.sysTenantUserService = sysTenantUserService; + this.passwordEncoder = passwordEncoder; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createTenantWithAdmin(CreateTenantDTO dto) { + // 1. 校验租户编码唯一性 + if (count(new LambdaQueryWrapper().eq(SysTenant::getTenantCode, dto.getTenantCode())) > 0) { + throw new RuntimeException("租户编码已存在:" + dto.getTenantCode()); + } + + // 2. 创建租户 + SysTenant tenant = new SysTenant(); + tenant.setTenantCode(dto.getTenantCode()); + tenant.setTenantName(dto.getTenantName()); + tenant.setContactName(dto.getContactName()); + tenant.setContactPhone(dto.getContactPhone()); + tenant.setRemark(dto.getRemark()); + tenant.setExpireTime(dto.getExpireTime()); + tenant.setStatus(1); + save(tenant); + Long tenantId = tenant.getId(); + + // 3. 初始化根组织 + SysOrg rootOrg = new SysOrg(); + rootOrg.setTenantId(tenantId); + rootOrg.setOrgName(dto.getTenantName()); + rootOrg.setOrgCode(dto.getTenantCode() + "_ROOT"); + rootOrg.setParentId(null); + rootOrg.setStatus(1); + sysOrgService.save(rootOrg); + Long orgId = rootOrg.getId(); + + // 4. 创建租户管理员角色 + SysRole adminRole = new SysRole(); + adminRole.setTenantId(tenantId); + adminRole.setRoleCode("TENANT_ADMIN"); + adminRole.setRoleName("租户管理员"); + adminRole.setStatus(1); + adminRole.setRemark("系统自动初始化的租户管理员角色"); + sysRoleService.save(adminRole); + Long roleId = adminRole.getRoleId(); + + // 5. 分配默认菜单权限 + String menuCodes = sysParamService.getParamValue("tenant.init.default.menu.codes", ""); + if (menuCodes != null && !menuCodes.trim().isEmpty()) { + List codes = Arrays.asList(menuCodes.split(",")); + List perms = sysPermissionService.list( + new LambdaQueryWrapper().in(SysPermission::getCode, codes) + ); + if (!perms.isEmpty()) { + for (SysPermission p : perms) { + SysRolePermission rp = new SysRolePermission(); + rp.setRoleId(roleId); + rp.setPermId(p.getPermId()); + sysRolePermissionMapper.insert(rp); + } + } + } + + // 6. 创建管理员用户 + String username = "admin_" + dto.getTenantCode(); + if (sysUserService.count(new LambdaQueryWrapper().eq(SysUser::getUsername, username)) > 0) { + throw new RuntimeException("管理员用户名已存在:" + username); + } + + String defaultPwd = sysParamService.getParamValue("tenant.init.default.password", "123456"); + SysUser user = new SysUser(); + user.setUsername(username); + user.setDisplayName(dto.getTenantName() + "管理员"); + user.setPasswordHash(passwordEncoder.encode(defaultPwd)); + user.setPwdResetRequired(1); + user.setStatus(1); + user.setIsPlatformAdmin(false); + sysUserService.save(user); + Long userId = user.getUserId(); + + // 7. 绑定用户与角色 (sys_user_role) + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + sysUserRoleMapper.insert(ur); + + // 8. 绑定用户与租户/组织 (sys_tenant_user) + SysTenantUser tu = new SysTenantUser(); + tu.setUserId(userId); + tu.setTenantId(tenantId); + tu.setOrgId(orgId); + tu.setStatus(1); + sysTenantUserService.save(tu); + + return tenantId; + } }