add SysTenantServiceImpl#insertByBo 新增租户 (创建用户, 部门, 角色, 菜单) ;

add Constants, UserConstants 租户新增相关常量值 ;
add SysTenantBo 新增用户名密码字段用于创建系统用户 ;
update 更新租户新增修改表单字段展示, 更新字段校验 ;
update sql 更新超级管理员初始化用户名 ;
This commit is contained in:
zlyx 2023-02-07 19:09:11 +08:00
parent 0ce97a1af9
commit 0c4134978a
10 changed files with 183 additions and 12 deletions

View File

@ -72,5 +72,10 @@ public interface Constants {
*/ */
String TOKEN = "token"; String TOKEN = "token";
/**
* 顶级部门id
*/
Long TOP_PARENT_ID = 0L;
} }

View File

@ -135,4 +135,19 @@ public interface UserConstants {
*/ */
Long SUPER_ADMIN_ID = 1L; Long SUPER_ADMIN_ID = 1L;
/**
* 管理员角色 roleKey
*/
String ADMIN_ROLE_KEY = "admin";
/**
* 管理员角色名称
*/
String ADMIN_ROLE_NAME = "管理员";
/**
* 管理员角色排序
*/
Integer ADMIN_ROLE_SORT = 5;
} }

View File

@ -2,6 +2,7 @@ package com.ruoyi.system.controller.system;
import java.util.List; import java.util.List;
import com.baomidou.lock.annotation.Lock4j;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
@ -72,6 +73,7 @@ public class SysTenantController extends BaseController {
*/ */
@SaCheckPermission("system:tenant:add") @SaCheckPermission("system:tenant:add")
@Log(title = "租户", businessType = BusinessType.INSERT) @Log(title = "租户", businessType = BusinessType.INSERT)
@Lock4j
@RepeatSubmit() @RepeatSubmit()
@PostMapping() @PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) { public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) {

View File

@ -29,7 +29,6 @@ public class SysTenantBo extends BaseEntity {
/** /**
* 租户编号 * 租户编号
*/ */
@NotBlank(message = "租户编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String tenantId; private String tenantId;
/** /**
@ -50,6 +49,18 @@ public class SysTenantBo extends BaseEntity {
@NotBlank(message = "企业名称不能为空", groups = { AddGroup.class, EditGroup.class }) @NotBlank(message = "企业名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String companyName; private String companyName;
/**
* 用户名创建系统用户
*/
@NotBlank(message = "用户名不能为空", groups = { AddGroup.class })
private String username;
/**
* 密码创建系统用户
*/
@NotBlank(message = "密码不能为空", groups = { AddGroup.class })
private String password;
/** /**
* 统一社会信用代码 * 统一社会信用代码
*/ */
@ -73,6 +84,7 @@ public class SysTenantBo extends BaseEntity {
/** /**
* 租户套餐编号 * 租户套餐编号
*/ */
@NotNull(message = "租户套餐不能为空", groups = { AddGroup.class })
private Long packageId; private Long packageId;
/** /**

View File

@ -1,21 +1,31 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.bo.SysUserBo;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.system.domain.bo.SysTenantBo; import com.ruoyi.system.domain.bo.SysTenantBo;
import com.ruoyi.system.domain.vo.SysTenantVo; import com.ruoyi.system.domain.vo.SysTenantVo;
import com.ruoyi.system.domain.SysTenant;
import com.ruoyi.system.mapper.SysTenantMapper;
import com.ruoyi.system.service.ISysTenantService; import com.ruoyi.system.service.ISysTenantService;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Collection; import java.util.Collection;
@ -29,7 +39,15 @@ import java.util.Collection;
@Service @Service
public class SysTenantServiceImpl implements ISysTenantService { public class SysTenantServiceImpl implements ISysTenantService {
private final ISysUserService iSysUserService;
private final SysTenantMapper baseMapper; private final SysTenantMapper baseMapper;
private final SysTenantPackageMapper sysTenantPackageMapper;
private final SysUserMapper sysUserMapper;
private final SysDeptMapper sysDeptMapper;
private final SysRoleMapper sysRoleMapper;
private final SysRoleMenuMapper sysRoleMenuMapper;
private final SysRoleDeptMapper sysRoleDeptMapper;
private final SysUserRoleMapper sysUserRoleMapper;
/** /**
* 查询租户 * 查询租户
@ -82,14 +100,115 @@ public class SysTenantServiceImpl implements ISysTenantService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(SysTenantBo bo) { public Boolean insertByBo(SysTenantBo bo) {
SysTenant add = BeanUtil.toBean(bo, SysTenant.class); SysTenant add = BeanUtil.toBean(bo, SysTenant.class);
validEntityBeforeSave(add);
SysUserBo userBo = new SysUserBo();
userBo.setUserName(bo.getUsername());
// 判断用户名是否重复
if (UserConstants.NOT_UNIQUE.equals(iSysUserService.checkUserNameUnique(userBo))) {
throw new ServiceException("新增用户'" + bo.getUsername() + "'失败,登录账号已存在");
}
// 获取所有租户编号
List<String> tenantIds = baseMapper.selectObjs(
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), Convert::toStr);
String tenantId = generateTenantId(tenantIds);
add.setTenantId(tenantId);
boolean flag = baseMapper.insert(add) > 0; boolean flag = baseMapper.insert(add) > 0;
if (flag) { if (flag) {
bo.setId(add.getId()); bo.setId(add.getId());
} }
// 根据套餐创建角色
Long roleId = createTenantRole(tenantId, bo.getPackageId());
// 创建部门: 公司名是部门名称
SysDept dept = new SysDept();
dept.setTenantId(tenantId);
dept.setDeptName(bo.getCompanyName());
dept.setAncestors(Constants.TOP_PARENT_ID.toString());
sysDeptMapper.insert(dept);
Long deptId = dept.getDeptId();
// 角色和部门关联表
SysRoleDept roleDept = new SysRoleDept();
roleDept.setRoleId(roleId);
roleDept.setDeptId(deptId);
sysRoleDeptMapper.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);
sysUserMapper.insert(user);
// 用户和角色关联表
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getUserId());
userRole.setRoleId(roleId);
sysUserRoleMapper.insert(userRole);
return flag; return flag;
} }
/**
* 生成租户id
*
* @param tenantIds 已有租户id列表
* @return 租户id
*/
private String generateTenantId(List<String> tenantIds) {
// 随机生成6位
String numbers = RandomUtil.randomNumbers(6);
// 判断是否存在如果存在则重新生成
if (tenantIds.contains(numbers)) {
generateTenantId(tenantIds);
}
return numbers;
}
/**
* 根据租户菜单创建租户角色
*
* @param tenantId 租户编号
* @param packageId 租户套餐id
* @return 角色id
*/
@Transactional(rollbackFor = Exception.class)
public Long createTenantRole(String tenantId, Long packageId) {
// 获取租户套餐
SysTenantPackage tenantPackage = sysTenantPackageMapper.selectById(packageId);
if (ObjectUtil.isNull(tenantPackage)) {
throw new ServiceException("套餐不存在");
}
// 获取套餐菜单id
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
// 创建角色
SysRole role = new SysRole();
role.setTenantId(tenantId);
role.setRoleName(UserConstants.ADMIN_ROLE_NAME);
role.setRoleKey(UserConstants.ADMIN_ROLE_KEY);
role.setRoleSort(UserConstants.ADMIN_ROLE_SORT);
role.setStatus(UserConstants.NORMAL);
sysRoleMapper.insert(role);
Long roleId = role.getRoleId();
// 创建角色菜单
List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
menuIds.forEach(menuId -> {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu);
});
sysRoleMenuMapper.insertBatch(roleMenus);
return roleId;
}
/** /**
* 修改租户 * 修改租户
*/ */

View File

@ -139,7 +139,6 @@
<!-- 添加或修改租户对话框 --> <!-- 添加或修改租户对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="企业名称" prop="companyName"> <el-form-item label="企业名称" prop="companyName">
<el-input v-model="form.companyName" placeholder="请输入企业名称" /> <el-input v-model="form.companyName" placeholder="请输入企业名称" />
</el-form-item> </el-form-item>
@ -149,11 +148,14 @@
<el-form-item label="联系电话" prop="contactPhone"> <el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" /> <el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
</el-form-item> </el-form-item>
<el-form-item label="企业代码" prop="licenseNumber"> <el-form-item v-if="form.id == undefined" label="用户名" prop="username">
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" /> <el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30"/>
</el-form-item>
<el-form-item v-if="form.id == undefined" label="用户密码" prop="password">
<el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20"/>
</el-form-item> </el-form-item>
<el-form-item label="租户套餐" prop="packageId"> <el-form-item label="租户套餐" prop="packageId">
<el-select v-model="form.packageId" placeholder="请选择租户套餐" clearable size="small" style="width: 100%"> <el-select v-model="form.packageId" :disabled="form.tenantId" placeholder="请选择租户套餐" clearable size="small" style="width: 100%">
<el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId"/> <el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -171,6 +173,9 @@
<el-form-item label="地址" prop="address"> <el-form-item label="地址" prop="address">
<el-input v-model="form.address" placeholder="请输入地址" /> <el-input v-model="form.address" placeholder="请输入地址" />
</el-form-item> </el-form-item>
<el-form-item label="企业代码" prop="licenseNumber">
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
</el-form-item>
<el-form-item label="企业简介" prop="intro"> <el-form-item label="企业简介" prop="intro">
<el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" /> <el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
</el-form-item> </el-form-item>
@ -252,6 +257,17 @@ export default {
companyName: [ companyName: [
{ required: true, message: "企业名称不能为空", trigger: "blur" } { required: true, message: "企业名称不能为空", trigger: "blur" }
], ],
username: [
{ required: true, message: "用户名不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
],
packageId: [
{ required: true, message: "租户套餐不能为空", trigger: "blur" }
]
} }
}; };
}, },
@ -297,6 +313,8 @@ export default {
tenantId: undefined, tenantId: undefined,
contactUserName: undefined, contactUserName: undefined,
contactPhone: undefined, contactPhone: undefined,
username: undefined,
password: undefined,
companyName: undefined, companyName: undefined,
licenseNumber: undefined, licenseNumber: undefined,
address: undefined, address: undefined,

View File

@ -198,7 +198,7 @@ comment on column sys_user.remark is '备注';
-- ---------------------------- -- ----------------------------
-- 初始化-用户信息表数据 -- 初始化-用户信息表数据
-- ---------------------------- -- ----------------------------
insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); insert into sys_user values(1, '000000', 103, 'superadmin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员');
insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '测试员'); insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '测试员');

View File

@ -205,7 +205,7 @@ comment on column sys_user.remark is '备注';
-- 初始化-用户信息表数据 -- 初始化-用户信息表数据
-- ---------------------------- -- ----------------------------
insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); insert into sys_user values(1, '000000', 103, 'superadmin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员');
insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '测试员'); insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '测试员');

View File

@ -128,7 +128,7 @@ create table sys_user (
-- ---------------------------- -- ----------------------------
-- 初始化-用户信息表数据 -- 初始化-用户信息表数据
-- ---------------------------- -- ----------------------------
insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); insert into sys_user values(1, '000000', 103, 'superadmin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员');
insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '测试员'); insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '测试员');

View File

@ -2427,7 +2427,7 @@ EXEC sys.sp_addextendedproperty
'TABLE', N'sys_user' 'TABLE', N'sys_user'
GO GO
INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (1, 103, N'000000', N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (1, 103, N'000000', N'superadmin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员')
GO GO
INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (2, 105, N'000000', N'lionli', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@qq.com', N'15666666666', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'测试员') INSERT [sys_user] ([user_id], [tenant_id], [dept_id], [user_name], [nick_name], [user_type], [email], [phonenumber], [sex], [avatar], [password], [status], [del_flag], [login_ip], [login_date], [create_dept], [create_by], [create_time], [update_by], [update_time], [remark]) VALUES (2, 105, N'000000', N'lionli', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@qq.com', N'15666666666', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'测试员')
GO GO