package org.ruoyi.system.service.impl; import cn.dev33.satoken.secure.BCrypt; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.ruoyi.common.core.constant.CacheNames; import org.ruoyi.common.core.constant.Constants; import org.ruoyi.common.core.constant.TenantConstants; import org.ruoyi.common.core.exception.ServiceException; import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.SpringUtils; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.mybatis.core.page.PageQuery; import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.system.domain.*; import org.ruoyi.system.domain.bo.SysTenantBo; import org.ruoyi.system.domain.vo.SysTenantVo; import org.ruoyi.system.mapper.*; import org.ruoyi.system.service.ISysTenantService; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; /** * 租户Service业务层处理 * * @author Michelle.Chung */ @RequiredArgsConstructor @Service public class SysTenantServiceImpl implements ISysTenantService { private final SysTenantMapper baseMapper; private final SysTenantPackageMapper tenantPackageMapper; private final SysUserMapper userMapper; private final SysDeptMapper deptMapper; private final SysRoleMapper roleMapper; private final SysRoleMenuMapper roleMenuMapper; private final SysRoleDeptMapper roleDeptMapper; private final SysUserRoleMapper userRoleMapper; private final SysDictTypeMapper dictTypeMapper; private final SysDictDataMapper dictDataMapper; private final SysConfigMapper configMapper; /** * 查询租户 */ @Override public SysTenantVo queryById(Long id) { return baseMapper.selectVoById(id); } /** * 基于租户ID查询租户 */ @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId") @Override public SysTenantVo queryByTenantId(String tenantId) { return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysTenant::getTenantId, tenantId)); } /** * 查询租户列表 */ @Override public TableDataInfo queryPageList(SysTenantBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); } /** * 查询租户列表 */ @Override public List queryList(SysTenantBo bo) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); return baseMapper.selectVoList(lqw); } private LambdaQueryWrapper buildQueryWrapper(SysTenantBo bo) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()); lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName()); lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone()); lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName()); lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber()); lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress()); lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro()); lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain()); lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId()); lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime()); lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount()); lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus()); return lqw; } /** * 新增租户 */ @Override @Transactional(rollbackFor = Exception.class) public Boolean insertByBo(SysTenantBo bo) { SysTenant add = MapstructUtils.convert(bo, SysTenant.class); // 获取所有租户编号 List tenantIds = baseMapper.selectObjs( new LambdaQueryWrapper().select(SysTenant::getTenantId), Convert::toStr); String tenantId = generateTenantId(tenantIds); add.setTenantId(tenantId); boolean flag = baseMapper.insert(add) > 0; if (!flag) { throw new ServiceException("创建租户失败"); } bo.setId(add.getId()); // 根据套餐创建角色 Long roleId = createTenantRole(tenantId, bo.getPackageId()); // 创建部门: 公司名是部门名称 SysDept dept = new SysDept(); dept.setTenantId(tenantId); dept.setDeptName(bo.getCompanyName()); dept.setLeader(bo.getUsername()); dept.setParentId(Constants.TOP_PARENT_ID); dept.setAncestors(Constants.TOP_PARENT_ID.toString()); deptMapper.insert(dept); Long deptId = dept.getDeptId(); // 角色和部门关联表 SysRoleDept roleDept = new SysRoleDept(); roleDept.setRoleId(roleId); roleDept.setDeptId(deptId); roleDeptMapper.insert(roleDept); // 创建系统用户 SysUser user = new SysUser(); user.setTenantId(tenantId); user.setUserName(bo.getUsername()); user.setNickName(bo.getUsername()); user.setPassword(BCrypt.hashpw(bo.getPassword())); user.setDeptId(deptId); userMapper.insert(user); // 用户和角色关联表 SysUserRole userRole = new SysUserRole(); userRole.setUserId(user.getUserId()); userRole.setRoleId(roleId); userRoleMapper.insert(userRole); String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID; List dictTypeList = dictTypeMapper.selectList( new LambdaQueryWrapper().eq(SysDictType::getTenantId, defaultTenantId)); List dictDataList = dictDataMapper.selectList( new LambdaQueryWrapper().eq(SysDictData::getTenantId, defaultTenantId)); for (SysDictType dictType : dictTypeList) { dictType.setDictId(null); dictType.setTenantId(tenantId); } for (SysDictData dictData : dictDataList) { dictData.setDictCode(null); dictData.setTenantId(tenantId); } dictTypeMapper.insertBatch(dictTypeList); dictDataMapper.insertBatch(dictDataList); List sysConfigList = configMapper.selectList( new LambdaQueryWrapper().eq(SysConfig::getTenantId, defaultTenantId)); for (SysConfig config : sysConfigList) { config.setConfigId(null); config.setTenantId(tenantId); } configMapper.insertBatch(sysConfigList); return true; } /** * 生成租户id * * @param tenantIds 已有租户id列表 * @return 租户id */ private String generateTenantId(List tenantIds) { // 随机生成6位 String numbers = RandomUtil.randomNumbers(6); // 判断是否存在,如果存在则重新生成 if (tenantIds.contains(numbers)) { generateTenantId(tenantIds); } return numbers; } /** * 根据租户菜单创建租户角色 * * @param tenantId 租户编号 * @param packageId 租户套餐id * @return 角色id */ private Long createTenantRole(String tenantId, Long packageId) { // 获取租户套餐 SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); if (ObjectUtil.isNull(tenantPackage)) { throw new ServiceException("套餐不存在"); } // 获取套餐菜单id List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); // 创建角色 SysRole role = new SysRole(); role.setTenantId(tenantId); role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME); role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY); role.setRoleSort(1); role.setStatus(TenantConstants.NORMAL); roleMapper.insert(role); Long roleId = role.getRoleId(); // 创建角色菜单 List roleMenus = new ArrayList<>(menuIds.size()); menuIds.forEach(menuId -> { SysRoleMenu roleMenu = new SysRoleMenu(); roleMenu.setRoleId(roleId); roleMenu.setMenuId(menuId); roleMenus.add(roleMenu); }); roleMenuMapper.insertBatch(roleMenus); return roleId; } /** * 修改租户 */ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") @Override public Boolean updateByBo(SysTenantBo bo) { SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); tenant.setTenantId(null); tenant.setPackageId(null); return baseMapper.updateById(tenant) > 0; } /** * 修改租户状态 * * @param bo 租户信息 * @return 结果 */ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") @Override public int updateTenantStatus(SysTenantBo bo) { SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); return baseMapper.updateById(tenant); } /** * 校验租户是否允许操作 * * @param tenantId 租户ID */ @Override public void checkTenantAllowed(String tenantId) { if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { throw new ServiceException("不允许操作管理租户"); } } /** * 批量删除租户 */ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true) @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { // 做一些业务上的校验,判断是否需要校验 if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) { throw new ServiceException("超管租户不能删除"); } } return baseMapper.deleteBatchIds(ids) > 0; } /** * 校验企业名称是否唯一 */ @Override public boolean checkCompanyNameUnique(SysTenantBo bo) { boolean exist = baseMapper.exists(new LambdaQueryWrapper() .eq(SysTenant::getCompanyName, bo.getCompanyName()) .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId())); return !exist; } /** * 校验账号余额 */ @Override public boolean checkAccountBalance(String tenantId) { SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); // 如果余额为-1代表不限制 if (tenant.getAccountCount() == -1) { return true; } Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>()); // 如果余额大于0代表还有可用名额 return tenant.getAccountCount() - userNumber > 0; } /** * 校验有效期 */ @Override public boolean checkExpireTime(String tenantId) { SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); // 如果未设置过期时间代表不限制 if (ObjectUtil.isNull(tenant.getExpireTime())) { return true; } // 如果当前时间在过期时间之前则通过 return new Date().before(tenant.getExpireTime()); } /** * 同步租户套餐 */ @Override @Transactional(rollbackFor = Exception.class) public Boolean syncTenantPackage(String tenantId, String packageId) { SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); List roles = roleMapper.selectList( new LambdaQueryWrapper().eq(SysRole::getTenantId, tenantId)); List roleIds = new ArrayList<>(roles.size() - 1); List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); roles.forEach(item -> { if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) { List roleMenus = new ArrayList<>(menuIds.size()); menuIds.forEach(menuId -> { SysRoleMenu roleMenu = new SysRoleMenu(); roleMenu.setRoleId(item.getRoleId()); roleMenu.setMenuId(menuId); roleMenus.add(roleMenu); }); roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, item.getRoleId())); roleMenuMapper.insertBatch(roleMenus); } else { roleIds.add(item.getRoleId()); } }); if (!roleIds.isEmpty()) { roleMenuMapper.delete( new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds)); } return true; } }