重构:重构系统管理/角色管理功能

1. 使用抽屉代替对话框
2. 优化数据权限权限范围存储,新增角色和部门关联表
3. 新增角色和菜单关联表
4. 部分细节优化
This commit is contained in:
Charles7c 2023-02-20 00:14:14 +08:00
parent 510f86031f
commit 297fbd3675
28 changed files with 889 additions and 299 deletions

View File

@ -37,7 +37,7 @@ public @interface CrudRequestMapping {
/**
* API 列表
*/
Api[] api() default {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT};
Api[] api() default {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT};
/**
* API 枚举
@ -62,7 +62,7 @@ public @interface CrudRequestMapping {
/**
* 新增
*/
CREATE,
ADD,
/**
* 修改
*/

View File

@ -117,8 +117,8 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
@Operation(summary = "新增数据")
@ResponseBody
@PostMapping
protected R<Long> create(@Validated(BaseRequest.Create.class) @RequestBody C request) {
Long id = baseService.create(request);
protected R<Long> add(@Validated(BaseRequest.Create.class) @RequestBody C request) {
Long id = baseService.add(request);
return R.ok("新增成功", id);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.common.base;
import java.util.Collection;
import com.baomidou.mybatisplus.extension.toolkit.Db;
/**
* Mapper 基类
*
* @param <T>
* 实体类
* @author Charles7c
* @since 2023/2/19 20:47
*/
public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {
/**
* 批量插入记录
*
* @param entityList
* 实体列表
* @return 是否成功
*/
default boolean insertBatch(Collection<T> entityList) {
return Db.saveBatch(entityList);
}
}

View File

@ -78,7 +78,7 @@ public interface BaseService<V, D, Q, C extends BaseRequest> {
* 创建信息
* @return 自增 ID
*/
Long create(C request);
Long add(C request);
/**
* 修改

View File

@ -41,6 +41,7 @@ import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
@ -107,7 +108,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T, V, D, Q, C ext
@Override
@Transactional(rollbackFor = Exception.class)
public Long create(C request) {
public Long add(C request) {
if (request == null) {
return 0L;
}
@ -153,7 +154,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T, V, D, Q, C ext
protected <E> List<E> list(Q query, SortQuery sortQuery, Class<E> targetClass) {
QueryWrapper<T> queryWrapper = QueryHelper.build(query);
// 设置排序
Sort sort = sortQuery.getSort();
Sort sort = Opt.ofNullable(sortQuery).orElseGet(SortQuery::new).getSort();
for (Sort.Order order : sort) {
queryWrapper.orderBy(order != null, order.isAscending(), StrUtil.toUnderlineCase(order.getProperty()));
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import top.charles7c.cnadmin.common.base.BaseMapper;
import top.charles7c.cnadmin.system.model.entity.RoleDeptDO;
/**
* 角色和部门 Mapper
*
* @author Charles7c
* @since 2023/2/18 21:57
*/
public interface RoleDeptMapper extends BaseMapper<RoleDeptDO> {
/**
* 根据角色 ID 查询
*
* @param roleId
* 角色 ID
* @return 部门 ID 列表
*/
@Select("SELECT `dept_id` FROM `sys_role_dept` WHERE `role_id` = #{roleId}")
List<Long> selectDeptIdsByRoleId(@Param("roleId") Long roleId);
}

View File

@ -16,8 +16,12 @@
package top.charles7c.cnadmin.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import top.charles7c.cnadmin.common.base.BaseMapper;
import top.charles7c.cnadmin.system.model.entity.RoleMenuDO;
/**
@ -26,4 +30,15 @@ import top.charles7c.cnadmin.system.model.entity.RoleMenuDO;
* @author Charles7c
* @since 2023/2/15 20:30
*/
public interface RoleMenuMapper extends BaseMapper<RoleMenuDO> {}
public interface RoleMenuMapper extends BaseMapper<RoleMenuDO> {
/**
* 根据角色 ID 查询
*
* @param roleId
* 角色 ID
* @return 菜单 ID 列表
*/
@Select("SELECT `menu_id` FROM `sys_role_menu` WHERE `role_id` = #{roleId}")
List<Long> selectMenuIdsByRoleId(@Param("roleId") Long roleId);
}

View File

@ -16,14 +16,10 @@
package top.charles7c.cnadmin.system.model.entity;
import java.util.List;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import top.charles7c.cnadmin.common.base.BaseDO;
import top.charles7c.cnadmin.common.enums.DataScopeEnum;
@ -62,12 +58,6 @@ public class RoleDO extends BaseDO {
*/
private DataScopeEnum dataScope;
/**
* 数据权限范围部门 ID 数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<Long> dataScopeDeptIds;
/**
* 描述
*/

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.model.entity;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* 角色和部门实体
*
* @author Charles7c
* @since 2023/2/18 21:57
*/
@Data
@NoArgsConstructor
@TableName("sys_role_dept")
public class RoleDeptDO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 角色 ID
*/
private Long roleId;
/**
* 部门 ID
*/
private Long deptId;
public RoleDeptDO(Long roleId, Long deptId) {
this.roleId = roleId;
this.deptId = deptId;
}
}

View File

@ -19,6 +19,7 @@ package top.charles7c.cnadmin.system.model.entity;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.baomidou.mybatisplus.annotation.TableName;
@ -29,6 +30,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
* @since 2023/2/15 20:20
*/
@Data
@NoArgsConstructor
@TableName("sys_role_menu")
public class RoleMenuDO implements Serializable {
@ -43,4 +45,9 @@ public class RoleMenuDO implements Serializable {
* 菜单 ID
*/
private Long menuId;
public RoleMenuDO(Long roleId, Long menuId) {
this.roleId = roleId;
this.menuId = menuId;
}
}

View File

@ -43,7 +43,7 @@ public class RoleQuery implements Serializable {
* 角色名称
*/
@Schema(description = "角色名称")
@Query(type = Query.Type.INNER_LIKE)
@Query(blurry = "roleName,roleCode")
private String roleName;
/**

View File

@ -66,17 +66,11 @@ public class RoleRequest extends BaseRequest {
private String roleCode;
/**
* 数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限
* 角色排序
*/
@Schema(description = "数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限", type = "Integer",
allowableValues = {"1", "2", "3", "4", "5"})
private DataScopeEnum dataScope;
/**
* 数据权限范围部门 ID 数组
*/
@Schema(description = "数据权限范围(部门 ID 数组)")
private List<Long> dataScopeDeptIds;
@Schema(description = "角色排序")
@NotNull(message = "角色排序不能为空")
private Integer roleSort;
/**
* 描述
@ -86,11 +80,23 @@ public class RoleRequest extends BaseRequest {
private String description;
/**
* 角色排序
* 功能权限菜单 ID 列表
*/
@Schema(description = "角色排序")
@NotNull(message = "角色排序不能为空")
private Integer roleSort;
@Schema(description = "功能权限:菜单 ID 列表")
private List<Long> menuIds;
/**
* 数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限
*/
@Schema(description = "数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限", type = "Integer",
allowableValues = {"1", "2", "3", "4", "5"})
private DataScopeEnum dataScope;
/**
* 权限范围部门 ID 列表
*/
@Schema(description = "权限范围:部门 ID 列表")
private List<Long> deptIds;
/**
* 状态1启用 2禁用

View File

@ -71,19 +71,6 @@ public class RoleDetailVO extends BaseDetailVO {
@ExcelProperty(value = "数据权限", converter = ExcelBaseEnumConverter.class)
private DataScopeEnum dataScope;
/**
* 数据权限范围部门 ID 数组
*/
@Schema(description = "数据权限范围(部门 ID 数组)")
private List<Long> dataScopeDeptIds;
/**
* 描述
*/
@Schema(description = "描述")
@ExcelProperty(value = "描述")
private String description;
/**
* 角色排序
*/
@ -97,4 +84,23 @@ public class RoleDetailVO extends BaseDetailVO {
@Schema(description = "状态1启用 2禁用")
@ExcelProperty(value = "状态", converter = ExcelBaseEnumConverter.class)
private DisEnableStatusEnum status;
/**
* 描述
*/
@Schema(description = "描述")
@ExcelProperty(value = "描述")
private String description;
/**
* 功能权限菜单 ID 列表
*/
@Schema(description = "功能权限:菜单 ID 列表")
private List<Long> menuIds;
/**
* 权限范围部门 ID 列表
*/
@Schema(description = "权限范围:部门 ID 列表")
private List<Long> deptIds;
}

View File

@ -16,8 +16,6 @@
package top.charles7c.cnadmin.system.model.vo;
import java.util.List;
import lombok.Data;
import lombok.experimental.Accessors;
@ -67,18 +65,6 @@ public class RoleVO extends BaseVO {
@Schema(description = "数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限")
private DataScopeEnum dataScope;
/**
* 数据权限范围部门 ID 数组
*/
@Schema(description = "数据权限范围(部门 ID 数组)")
private List<Long> dataScopeDeptIds;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 角色排序
*/
@ -91,6 +77,12 @@ public class RoleVO extends BaseVO {
@Schema(description = "状态1启用 2禁用")
private DisEnableStatusEnum status;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 是否禁用修改
*/

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service;
import java.util.List;
/**
* 角色和部门业务接口
*
* @author Charles7c
* @since 2023/2/19 10:40
*/
public interface RoleDeptService {
/**
* 保存
*
* @param deptIds
* 部门 ID 列表
* @param roleId
* 角色 ID
*/
void save(List<Long> deptIds, Long roleId);
/**
* 根据角色 ID 查询
*
* @param roleId
* 角色 ID
* @return 部门 ID 列表
*/
List<Long> listDeptIdByRoleId(Long roleId);
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service;
import java.util.List;
/**
* 角色和菜单业务接口
*
* @author Charles7c
* @since 2023/2/19 10:40
*/
public interface RoleMenuService {
/**
* 保存
*
* @param menuIds
* 菜单 ID 列表
* @param roleId
* 角色 ID
*/
void save(List<Long> menuIds, Long roleId);
/**
* 根据角色 ID 查询
*
* @param roleId
* 角色 ID
* @return 菜单 ID 列表
*/
List<Long> listMenuIdByRoleId(Long roleId);
}

View File

@ -58,14 +58,14 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptVO,
@Override
@Transactional(rollbackFor = Exception.class)
public Long create(DeptRequest request) {
public Long add(DeptRequest request) {
String deptName = request.getDeptName();
boolean isExists = this.checkNameExists(deptName, request.getParentId(), request.getDeptId());
CheckUtils.throwIf(() -> isExists, String.format("新增失败,'%s'已存在", deptName));
// 保存信息
request.setStatus(DisEnableStatusEnum.ENABLE);
return super.create(request);
return super.add(request);
}
@Override

View File

@ -53,14 +53,14 @@ public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuVO,
@Override
@Transactional(rollbackFor = Exception.class)
public Long create(MenuRequest request) {
public Long add(MenuRequest request) {
String menuName = request.getMenuName();
boolean isExists = this.checkNameExists(menuName, request.getParentId(), request.getMenuId());
CheckUtils.throwIf(() -> isExists, String.format("新增失败,'%s'已存在", menuName));
// 保存信息
request.setStatus(DisEnableStatusEnum.ENABLE);
return super.create(request);
return super.add(request);
}
@Override

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service.impl;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.hutool.core.collection.CollUtil;
import top.charles7c.cnadmin.system.mapper.RoleDeptMapper;
import top.charles7c.cnadmin.system.model.entity.RoleDeptDO;
import top.charles7c.cnadmin.system.service.RoleDeptService;
/**
* 角色和部门业务实现类
*
* @author Charles7c
* @since 2023/2/19 10:47
*/
@Service
@RequiredArgsConstructor
public class RoleDeptServiceImpl implements RoleDeptService {
private final RoleDeptMapper roleDeptMapper;
@Override
public void save(List<Long> deptIds, Long roleId) {
if (CollUtil.isEmpty(deptIds)) {
return;
}
// 删除原有关联
roleDeptMapper.delete(Wrappers.<RoleDeptDO>lambdaQuery().eq(RoleDeptDO::getRoleId, roleId));
// 保存最新关联
List<RoleDeptDO> roleDeptList =
deptIds.stream().map(deptId -> new RoleDeptDO(roleId, deptId)).collect(Collectors.toList());
roleDeptMapper.insertBatch(roleDeptList);
}
@Override
public List<Long> listDeptIdByRoleId(Long roleId) {
return roleDeptMapper.selectDeptIdsByRoleId(roleId);
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.system.service.impl;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.hutool.core.collection.CollUtil;
import top.charles7c.cnadmin.system.mapper.RoleMenuMapper;
import top.charles7c.cnadmin.system.model.entity.RoleMenuDO;
import top.charles7c.cnadmin.system.service.RoleMenuService;
/**
* 角色和菜单业务实现类
*
* @author Charles7c
* @since 2023/2/19 10:43
*/
@Service
@RequiredArgsConstructor
public class RoleMenuServiceImpl implements RoleMenuService {
private final RoleMenuMapper roleMenuMapper;
@Override
public void save(List<Long> menuIds, Long roleId) {
if (CollUtil.isEmpty(menuIds)) {
return;
}
// 删除原有关联
roleMenuMapper.delete(Wrappers.<RoleMenuDO>lambdaQuery().eq(RoleMenuDO::getRoleId, roleId));
// 保存最新关联
List<RoleMenuDO> roleMenuList =
menuIds.stream().map(menuId -> new RoleMenuDO(roleId, menuId)).collect(Collectors.toList());
roleMenuMapper.insertBatch(roleMenuList);
}
@Override
public List<Long> listMenuIdByRoleId(Long roleId) {
return roleMenuMapper.selectMenuIdsByRoleId(roleId);
}
}

View File

@ -17,6 +17,7 @@
package top.charles7c.cnadmin.system.service.impl;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
@ -24,16 +25,17 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.charles7c.cnadmin.common.base.BaseServiceImpl;
import top.charles7c.cnadmin.common.consts.Constants;
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.system.mapper.RoleMapper;
import top.charles7c.cnadmin.system.model.entity.RoleDO;
import top.charles7c.cnadmin.system.model.query.RoleQuery;
import top.charles7c.cnadmin.system.model.request.RoleRequest;
import top.charles7c.cnadmin.system.model.vo.MenuVO;
import top.charles7c.cnadmin.system.model.vo.RoleDetailVO;
import top.charles7c.cnadmin.system.model.vo.RoleVO;
import top.charles7c.cnadmin.system.service.RoleService;
import top.charles7c.cnadmin.system.service.UserService;
import top.charles7c.cnadmin.system.service.*;
/**
* 角色业务实现类
@ -46,18 +48,26 @@ import top.charles7c.cnadmin.system.service.UserService;
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleVO, RoleDetailVO, RoleQuery, RoleRequest>
implements RoleService {
private final RoleMenuService roleMenuService;
private final RoleDeptService roleDeptService;
private final MenuService menuService;
private final UserService userService;
@Override
@Transactional(rollbackFor = Exception.class)
public Long create(RoleRequest request) {
public Long add(RoleRequest request) {
String roleName = request.getRoleName();
boolean isExist = this.checkNameExists(roleName, request.getRoleId());
CheckUtils.throwIf(() -> isExist, String.format("新增失败,'%s'已存在", roleName));
// 保存信息
// 新增角色
request.setStatus(DisEnableStatusEnum.ENABLE);
return super.create(request);
Long roleId = super.add(request);
// 保存角色和菜单关联
roleMenuService.save(request.getMenuIds(), roleId);
// 保存角色和部门关联
roleDeptService.save(request.getDeptIds(), roleId);
return roleId;
}
@Override
@ -67,7 +77,13 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleVO,
boolean isExist = this.checkNameExists(roleName, request.getRoleId());
CheckUtils.throwIf(() -> isExist, String.format("修改失败,'%s'已存在", roleName));
// 更新角色
super.update(request);
Long roleId = request.getRoleId();
// 保存角色和菜单关联
roleMenuService.save(request.getMenuIds(), roleId);
// 保存角色和部门关联
roleDeptService.save(request.getDeptIds(), roleId);
}
@Override
@ -89,4 +105,21 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleVO,
private boolean checkNameExists(String name, Long id) {
return super.lambdaQuery().eq(RoleDO::getRoleName, name).ne(id != null, RoleDO::getRoleId, id).exists();
}
@Override
public void fillDetail(Object detailObj) {
super.fillDetail(detailObj);
if (detailObj instanceof RoleDetailVO) {
RoleDetailVO detailVO = (RoleDetailVO)detailObj;
Long roleId = detailVO.getRoleId();
if (Constants.ADMIN_ROLE_CODE.equals(detailVO.getRoleCode())) {
List<MenuVO> list = menuService.list(null, null);
List<Long> menuIds = list.stream().map(MenuVO::getMenuId).collect(Collectors.toList());
detailVO.setMenuIds(menuIds);
} else {
detailVO.setMenuIds(roleMenuService.listMenuIdByRoleId(roleId));
}
detailVO.setDeptIds(roleDeptService.listDeptIdByRoleId(roleId));
}
}
}

View File

@ -7,10 +7,11 @@ export interface RoleRecord {
roleId?: number;
roleName: string;
roleCode?: string;
dataScope: number;
dataScopeDeptIds?: string;
roleSort?: number;
description?: string;
roleSort: number;
menuIds?: Array<number>;
dataScope: number;
deptIds?: Array<number>;
status?: number;
createUserString?: string;
createTime?: string;

View File

@ -120,3 +120,18 @@ body {
}
}
}
fieldset {
padding: 15px 15px 0 15px;
margin-bottom: 15px;
border: 1px solid #e4e7ed;
border-radius: 3px;
background: #fff;
}
fieldset legend {
color: #5e6d82;
padding: 2px 5px 2px 5px;
border: 1px solid #e4e7ed;
border-radius: 3px;
background: #fff;
}

View File

@ -178,9 +178,10 @@
</a-table>
<!-- 表单区域 -->
<a-modal
<a-drawer
:title="title"
:visible="visible"
:width="570"
:mask-closable="false"
unmount-on-close
render-to-body
@ -188,61 +189,91 @@
@cancel="handleCancel"
>
<a-form ref="formRef" :model="form" :rules="rules" size="large">
<a-form-item label="角色名称" field="roleName">
<a-input v-model="form.roleName" placeholder="请输入角色名称" />
</a-form-item>
<a-form-item label="角色编码" field="roleCode">
<a-input v-model="form.roleCode" placeholder="请输入角色编码" />
</a-form-item>
<a-form-item label="数据权限" field="dataScope">
<a-select
v-model="form.dataScope"
:options="dataScopeOptions"
placeholder="请选择数据权限"
/>
</a-form-item>
<a-form-item
v-if="form.dataScope === 5"
label="数据范围"
field="dataScopeDeptIds"
>
<a-tree-select
v-model="form.dataScopeDeptIds"
:data="treeData"
placeholder="请选择数据范围"
allow-search
allow-clear
tree-checkable
tree-check-strictly
:filter-tree-node="filterDeptTree"
:fallback-option="false"
/>
</a-form-item>
<a-form-item label="角色排序" field="roleSort">
<a-input-number
v-model="form.roleSort"
placeholder="请输入角色排序"
:min="1"
mode="button"
/>
</a-form-item>
<a-form-item label="描述" field="description">
<a-textarea
v-model="form.description"
:max-length="200"
placeholder="请输入描述"
:auto-size="{
minRows: 3,
}"
show-word-limit
/>
</a-form-item>
<fieldset>
<legend>基础信息</legend>
<a-form-item label="角色名称" field="roleName">
<a-input v-model="form.roleName" placeholder="请输入角色名称" />
</a-form-item>
<a-form-item label="角色编码" field="roleCode">
<a-input v-model="form.roleCode" placeholder="请输入角色编码" />
</a-form-item>
<a-form-item label="角色排序" field="roleSort">
<a-input-number
v-model="form.roleSort"
placeholder="请输入角色排序"
:min="1"
mode="button"
/>
</a-form-item>
<a-form-item label="描述" field="description">
<a-textarea
v-model="form.description"
:max-length="200"
placeholder="请输入描述"
:auto-size="{
minRows: 3,
}"
show-word-limit
/>
</a-form-item>
</fieldset>
<fieldset>
<legend>功能权限</legend>
<a-form-item label="功能权限">
<a-space style="margin-top: 2px">
<a-checkbox v-model="menuExpandAll" @change="handleExpandAll('menu')">展开/折叠</a-checkbox>
<a-checkbox v-model="menuCheckAll" @change="handleCheckAll('menu')">全选/全不选</a-checkbox>
<a-checkbox v-model="menuCheckStrictly">父子联动</a-checkbox>
</a-space>
<template #extra>
<a-spin v-if="menuLoading" />
<a-tree
v-if="!menuLoading"
ref="menuRef"
:data="menuOptions"
:default-checked-keys="form.menuIds"
:check-strictly="!menuCheckStrictly"
:default-expand-all="menuExpandAll"
checkable
/>
</template>
</a-form-item>
</fieldset>
<fieldset>
<legend>数据权限</legend>
<a-form-item label="数据权限" field="dataScope">
<a-select
v-model="form.dataScope"
:options="dataScopeOptions"
placeholder="请选择数据权限"
/>
</a-form-item>
<a-form-item v-if="form.dataScope === 5" label="权限范围">
<a-space style="margin-top: 2px">
<a-checkbox v-model="deptExpandAll" @change="handleExpandAll('dept')">展开/折叠</a-checkbox>
<a-checkbox v-model="deptCheckAll" @change="handleCheckAll('dept')">全选/全不选</a-checkbox>
<a-checkbox v-model="deptCheckStrictly">父子联动</a-checkbox>
</a-space>
<template #extra>
<a-spin v-if="deptLoading" />
<a-tree
v-if="!deptLoading"
ref="deptRef"
:data="deptOptions"
:default-checked-keys="form.deptIds"
:check-strictly="!deptCheckStrictly"
:default-expand-all="deptExpandAll"
checkable
/>
</template>
</a-form-item>
</fieldset>
</a-form>
</a-modal>
</a-drawer>
<!-- 详情区域 -->
<a-drawer
title="部门详情"
title="角色详情"
:visible="detailVisible"
:width="570"
:footer="false"
@ -250,88 +281,96 @@
render-to-body
@cancel="handleDetailCancel"
>
<a-descriptions title="基础信息" :column="2" bordered size="large">
<a-descriptions-item label="角色名称">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.roleName }}</span>
</a-descriptions-item>
<a-descriptions-item label="角色编码">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.roleCode }}</span>
</a-descriptions-item>
<a-descriptions-item label="状态">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>
<a-tag v-if="role.status === 1" color="green">启用</a-tag>
<a-tag v-else color="red">禁用</a-tag>
</span>
</a-descriptions-item>
<a-descriptions-item label="数据权限">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>
<span v-if="role.dataScope === 1">全部数据权限</span>
<span v-else-if="role.dataScope === 2">本部门及以下数据权限</span>
<span v-else-if="role.dataScope === 3">本部门数据权限</span>
<span v-else-if="role.dataScope === 4">仅本人数据权限</span>
<span v-else>自定义数据权限</span>
</span>
</a-descriptions-item>
<a-descriptions-item label="创建人">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.createUserString }}</span>
</a-descriptions-item>
<a-descriptions-item label="创建时间">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.createTime }}</span>
</a-descriptions-item>
<a-descriptions-item label="修改人">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.updateUserString }}</span>
</a-descriptions-item>
<a-descriptions-item label="修改时间">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.updateTime }}</span>
</a-descriptions-item>
<a-descriptions-item label="描述">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.description }}</span>
</a-descriptions-item>
</a-descriptions>
<a-descriptions
<a-card title="基础信息" :bordered="false">
<a-descriptions :column="2" bordered size="large">
<a-descriptions-item label="角色名称">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.roleName }}</span>
</a-descriptions-item>
<a-descriptions-item label="角色编码">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.roleCode }}</span>
</a-descriptions-item>
<a-descriptions-item label="状态">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>
<a-tag v-if="role.status === 1" color="green">启用</a-tag>
<a-tag v-else color="red">禁用</a-tag>
</span>
</a-descriptions-item>
<a-descriptions-item label="数据权限">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>
<span v-if="role.dataScope === 1">全部数据权限</span>
<span v-else-if="role.dataScope === 2">本部门及以下数据权限</span>
<span v-else-if="role.dataScope === 3">本部门数据权限</span>
<span v-else-if="role.dataScope === 4">仅本人数据权限</span>
<span v-else>自定义数据权限</span>
</span>
</a-descriptions-item>
<a-descriptions-item label="创建人">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.createUserString }}</span>
</a-descriptions-item>
<a-descriptions-item label="创建时间">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.createTime }}</span>
</a-descriptions-item>
<a-descriptions-item label="修改人">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.updateUserString }}</span>
</a-descriptions-item>
<a-descriptions-item label="修改时间">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.updateTime }}</span>
</a-descriptions-item>
<a-descriptions-item label="描述">
<a-skeleton v-if="detailLoading" :animation="true">
<a-skeleton-line :rows="1" />
</a-skeleton>
<span v-else>{{ role.description }}</span>
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card :loading="menuLoading" title="功能权限" :bordered="false">
<a-tree
:data="menuOptions"
:checked-keys="role.menuIds"
:default-expand-all="false"
check-strictly
checkable
/>
</a-card>
<a-card
v-if="role.dataScope === 5"
:loading="deptLoading"
title="数据权限"
:column="2"
bordered
size="large"
style="margin-top: 25px"
:bordered="false"
>
<a-descriptions-item label="数据范围">
<a-tree-select
v-model="role.dataScopeDeptIds"
:data="treeData"
tree-checkable
disabled
/>
</a-descriptions-item>
</a-descriptions>
<a-tree
:data="deptOptions"
:checked-keys="role.deptIds"
default-expand-all
check-strictly
checkable
/>
</a-card>
</a-drawer>
</a-card>
</div>
@ -349,7 +388,7 @@
updateRole,
deleteRole,
} from '@/api/system/role';
import { listDeptTree } from '@/api/common';
import { listMenuTree, listDeptTree } from '@/api/common';
const { proxy } = getCurrentInstance() as any;
@ -357,14 +396,15 @@
const role = ref<RoleRecord>({
roleName: '',
roleCode: '',
dataScope: 1,
description: '',
roleSort: 0,
status: 1,
dataScope: 1,
createUserString: '',
createTime: '',
updateUserString: '',
updateTime: '',
description: '',
menuIds: undefined,
deptIds: undefined,
});
const total = ref(0);
const ids = ref<Array<number>>([]);
@ -388,7 +428,16 @@
{ label: '仅本人数据权限', value: 4 },
{ label: '自定义数据权限', value: 5 },
]);
const treeData = ref<TreeNodeData[]>();
const menuLoading = ref(false);
const deptLoading = ref(false);
const menuOptions = ref<TreeNodeData[]>([]);
const deptOptions = ref<TreeNodeData[]>([]);
const menuExpandAll = ref(false);
const deptExpandAll = ref(true);
const menuCheckAll = ref(false);
const deptCheckAll = ref(false);
const menuCheckStrictly = ref(true);
const deptCheckStrictly = ref(true);
const data = reactive({
//
@ -405,7 +454,6 @@
rules: {
roleName: [{ required: true, message: '请输入角色名称' }],
dataScope: [{ required: true, message: '请选择数据权限' }],
dataScopeDeptIds: [{ required: true, message: '请选择数据范围' }],
roleSort: [{ required: true, message: '请输入角色排序' }],
},
});
@ -434,11 +482,10 @@
*/
const toCreate = () => {
reset();
listDeptTree({ status: 1 }).then((res) => {
treeData.value = res.data;
});
getMenuTree();
title.value = '新增角色';
visible.value = true;
getDeptTree();
};
/**
@ -448,9 +495,10 @@
*/
const toUpdate = (id: number) => {
reset();
listDeptTree({}).then((res) => {
treeData.value = res.data;
});
menuCheckStrictly.value = false;
deptCheckStrictly.value = false;
getMenuTree();
getDeptTree();
getRole(id).then((res) => {
form.value = res.data;
title.value = '修改角色';
@ -458,19 +506,60 @@
});
};
/**
* 查询菜单树
*/
const getMenuTree = () => {
if (menuOptions.value.length <= 0) {
menuLoading.value = true;
}
listMenuTree({})
.then((res) => {
menuOptions.value = res.data;
})
.finally(() => {
menuLoading.value = false;
});
};
/**
* 查询部门树
*/
const getDeptTree = () => {
if (deptOptions.value.length <= 0) {
deptLoading.value = true;
}
listDeptTree({})
.then((res) => {
deptOptions.value = res.data;
})
.finally(() => {
deptLoading.value = false;
});
};
/**
* 重置表单
*/
const reset = () => {
menuExpandAll.value = false;
menuCheckAll.value = false;
menuCheckStrictly.value = true;
deptExpandAll.value = true;
deptCheckAll.value = false;
deptCheckStrictly.value = true;
proxy.$refs.menuRef?.expandAll(menuExpandAll.value);
proxy.$refs.deptRef?.expandAll(deptExpandAll.value);
form.value = {
roleId: undefined,
roleName: '',
roleCode: undefined,
dataScope: 4,
dataScopeDeptIds: undefined,
description: '',
roleSort: 999,
status: 1,
menuIds: [],
deptIds: [],
};
proxy.$refs.formRef?.resetFields();
};
@ -483,6 +572,38 @@
proxy.$refs.formRef.resetFields();
};
/**
* 获取所有选中的菜单
*/
const getMenuAllCheckedKeys = () => {
//
const checkedNodes = proxy.$refs.menuRef.getCheckedNodes();
const checkedKeys = checkedNodes.map((item: TreeNodeData) => item.key);
//
const halfCheckedNodes = proxy.$refs.menuRef.getHalfCheckedNodes();
const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key);
// eslint-disable-next-line prefer-spread
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
};
/**
* 获取所有选中的部门
*/
const getDeptAllCheckedKeys = () => {
//
const checkedNodes = proxy.$refs.deptRef.getCheckedNodes();
const checkedKeys = checkedNodes.map((item: TreeNodeData) => item.key);
//
const halfCheckedNodes = proxy.$refs.deptRef.getHalfCheckedNodes();
const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key);
// eslint-disable-next-line prefer-spread
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
};
/**
* 确定
*/
@ -490,12 +611,16 @@
proxy.$refs.formRef.validate((valid: any) => {
if (!valid) {
if (form.value.roleId !== undefined) {
form.value.menuIds = getMenuAllCheckedKeys();
form.value.deptIds = getDeptAllCheckedKeys();
updateRole(form.value).then((res) => {
handleCancel();
getList();
proxy.$message.success(res.msg);
});
} else {
form.value.menuIds = getMenuAllCheckedKeys();
form.value.deptIds = getDeptAllCheckedKeys();
createRole(form.value).then((res) => {
handleCancel();
getList();
@ -513,6 +638,8 @@
*/
const toDetail = async (id: number) => {
if (detailLoading.value) return;
getMenuTree();
getDeptTree();
detailLoading.value = true;
detailVisible.value = true;
getRole(id)
@ -603,18 +730,29 @@
};
/**
* 过滤部门树
* 展开/折叠
*
* @param searchValue 搜索值
* @param nodeData 节点值
* @param type 类型菜单/部门
*/
const filterDeptTree = (searchValue: string, nodeData: TreeNodeData) => {
if (nodeData.title) {
return (
nodeData.title.toLowerCase().indexOf(searchValue.toLowerCase()) > -1
);
const handleExpandAll = (type: string) => {
if (type === 'menu') {
proxy.$refs.menuRef.expandAll(menuExpandAll.value);
} else if (type === 'dept') {
proxy.$refs.deptRef.expandAll(deptExpandAll.value);
}
};
/**
* 全选/全不选
*
* @param type 类型菜单/部门
*/
const handleCheckAll = (type: string) => {
if (type === 'menu') {
proxy.$refs.menuRef.checkAll(menuCheckAll.value);
} else if (type === 'dept') {
proxy.$refs.deptRef.checkAll(deptCheckAll.value);
}
return false;
};
/**

View File

@ -44,7 +44,7 @@ import top.charles7c.cnadmin.system.service.DeptService;
*/
@Tag(name = "部门管理 API")
@RestController
@CrudRequestMapping(value = "/system/dept", api = {Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT})
@CrudRequestMapping(value = "/system/dept", api = {Api.LIST, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
public class DeptController extends BaseController<DeptService, DeptVO, DeptDetailVO, DeptQuery, DeptRequest> {
@Override

View File

@ -43,7 +43,7 @@ import top.charles7c.cnadmin.system.service.MenuService;
*/
@Tag(name = "菜单管理 API")
@RestController
@CrudRequestMapping(value = "/system/menu", api = {Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT})
@CrudRequestMapping(value = "/system/menu", api = {Api.LIST, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
public class MenuController extends BaseController<MenuService, MenuVO, MenuVO, MenuQuery, MenuRequest> {
@Override

View File

@ -1,28 +1,6 @@
-- liquibase formatted sql
-- changeset Charles7c:1
-- 初始化默认部门
INSERT IGNORE INTO `sys_dept` VALUES (1, 'Xxx科技有限公司', 0, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (2, '天津总部', 1, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (3, '研发部', 2, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (4, 'UI部', 2, '系统初始部门', 2, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (5, '测试部', 2, '系统初始部门', 3, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (6, '运维部', 2, '系统初始部门', 4, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (7, '研发一组', 3, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (8, '研发二组', 3, '系统初始部门', 2, 2, 1, NOW(), 1, NOW());
-- 初始化默认用户admin/admin123test/123456
INSERT IGNORE INTO `sys_user` VALUES (1, 'admin', '超级管理员', '9802815bcc5baae7feb1ae0d0566baf2', 1, '18888888888', 'charles7c@126.com', NULL, '系统初始用户', 1, NOW(), 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_user` VALUES (2, 'test', '测试员', '8e114197e1b33783a00542ad67e80516', 0, NULL, NULL, NULL, '系统初始用户', 2, NOW(), 2, 1, NOW(), 1, NOW());
-- 初始化默认角色
INSERT IGNORE INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, NULL, '系统初始角色', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_role` VALUES (2, '测试人员', 'test', 4, NULL, '系统初始角色', 2, 2, 1, NOW(), 1, NOW());
-- 初始化默认用户和角色关联数据
INSERT IGNORE INTO `sys_user_role` VALUES (1, 1);
INSERT IGNORE INTO `sys_user_role` VALUES (2, 2);
-- 初始化默认菜单
INSERT IGNORE INTO `sys_menu` VALUES (1000, '系统管理', 0, 1, 'system', NULL, NULL, 'settings', b'0', b'0', b'0', NULL, 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_menu` VALUES (1010, '角色管理', 1000, 2, '/system/role', 'Role', 'system/role/index', NULL, b'0', b'0', b'0', 'system:role:list', 2, 1, 1, NOW(), 1, NOW());
@ -48,3 +26,46 @@ INSERT IGNORE INTO `sys_menu` VALUES (2050, '操作日志', 2000, 2, '/monitor/l
INSERT IGNORE INTO `sys_menu` VALUES (2070, '系统日志', 2000, 2, '/monitor/log/system', 'SystemLog', 'monitor/log/system/index', NULL, b'0', b'0', b'0', 'monitor:log:system:list', 4, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_menu` VALUES (10000, 'Arco Design Vue', 0, 1, 'https://arco.design/vue/docs/start', NULL, NULL, 'link', b'1', b'0', b'0', NULL, 100, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_menu` VALUES (10001, 'GitHub', 0, 1, 'https://github.com/Charles7c/continew-admin', NULL, NULL, 'github', b'1', b'0', b'0', NULL, 101, 1, 1, NOW(), 1, NOW());
-- 初始化默认部门
INSERT IGNORE INTO `sys_dept` VALUES (1, 'Xxx科技有限公司', 0, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (2, '天津总部', 1, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (3, '研发部', 2, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (4, 'UI部', 2, '系统初始部门', 2, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (5, '测试部', 2, '系统初始部门', 3, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (6, '运维部', 2, '系统初始部门', 4, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (7, '研发一组', 3, '系统初始部门', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_dept` VALUES (8, '研发二组', 3, '系统初始部门', 2, 2, 1, NOW(), 1, NOW());
-- 初始化默认角色
INSERT IGNORE INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '系统初始角色', 1, 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_role` VALUES (2, '测试人员', 'test', 5, '系统初始角色', 2, 2, 1, NOW(), 1, NOW());
-- 初始化默认用户admin/admin123test/123456
INSERT IGNORE INTO `sys_user` VALUES (1, 'admin', '超级管理员', '9802815bcc5baae7feb1ae0d0566baf2', 1, '18888888888', 'charles7c@126.com', NULL, '系统初始用户', 1, NOW(), 1, 1, NOW(), 1, NOW());
INSERT IGNORE INTO `sys_user` VALUES (2, 'test', '测试员', '8e114197e1b33783a00542ad67e80516', 0, NULL, NULL, NULL, '系统初始用户', 2, NOW(), 2, 1, NOW(), 1, NOW());
-- 初始化默认角色和菜单关联数据
INSERT INTO `sys_role_menu` VALUES (2, 1000);
INSERT INTO `sys_role_menu` VALUES (2, 1010);
INSERT INTO `sys_role_menu` VALUES (2, 1011);
INSERT INTO `sys_role_menu` VALUES (2, 1012);
INSERT INTO `sys_role_menu` VALUES (2, 1013);
INSERT INTO `sys_role_menu` VALUES (2, 1014);
INSERT INTO `sys_role_menu` VALUES (2, 1030);
INSERT INTO `sys_role_menu` VALUES (2, 1031);
INSERT INTO `sys_role_menu` VALUES (2, 1032);
INSERT INTO `sys_role_menu` VALUES (2, 1033);
INSERT INTO `sys_role_menu` VALUES (2, 1034);
INSERT INTO `sys_role_menu` VALUES (2, 1050);
INSERT INTO `sys_role_menu` VALUES (2, 1051);
INSERT INTO `sys_role_menu` VALUES (2, 1052);
INSERT INTO `sys_role_menu` VALUES (2, 1053);
INSERT INTO `sys_role_menu` VALUES (2, 1054);
-- 初始化默认角色和部门关联数据
INSERT INTO `sys_role_dept` VALUES (2, 5);
-- 初始化默认用户和角色关联数据
INSERT IGNORE INTO `sys_user_role` VALUES (1, 1);
INSERT IGNORE INTO `sys_user_role` VALUES (2, 2);

View File

@ -1,6 +1,31 @@
-- liquibase formatted sql
-- changeset Charles7c:1
CREATE TABLE IF NOT EXISTS `sys_menu` (
`menu_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '菜单ID',
`menu_name` varchar(255) NOT NULL COMMENT '菜单名称',
`parent_id` bigint(20) unsigned DEFAULT 0 COMMENT '上级菜单ID',
`menu_type` tinyint(1) unsigned DEFAULT 1 COMMENT '菜单类型1目录 2菜单 3按钮',
`path` varchar(512) DEFAULT NULL COMMENT '路由地址',
`name` varchar(255) DEFAULT NULL COMMENT '组件名称',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
`icon` varchar(255) DEFAULT NULL COMMENT '菜单图标',
`is_external` bit(1) DEFAULT b'0' COMMENT '是否外链',
`is_cache` bit(1) DEFAULT b'0' COMMENT '是否缓存',
`is_hidden` bit(1) DEFAULT b'0' COMMENT '是否隐藏',
`permission` varchar(255) DEFAULT NULL COMMENT '权限标识',
`menu_sort` int(11) unsigned DEFAULT 999 COMMENT '菜单排序',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_user` bigint(20) unsigned NOT NULL COMMENT '修改人',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`menu_id`) USING BTREE,
INDEX `idx_parent_id`(`parent_id`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';
CREATE TABLE IF NOT EXISTS `sys_dept` (
`dept_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '部门ID',
`dept_name` varchar(255) NOT NULL COMMENT '部门名称',
@ -18,6 +43,35 @@ CREATE TABLE IF NOT EXISTS `sys_dept` (
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
CREATE TABLE IF NOT EXISTS `sys_role` (
`role_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '角色ID',
`role_name` varchar(255) NOT NULL COMMENT '角色名称',
`role_code` varchar(255) DEFAULT NULL COMMENT '角色编码',
`data_scope` tinyint(1) DEFAULT 4 COMMENT '数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限',
`description` varchar(512) DEFAULT NULL COMMENT '描述',
`role_sort` int(11) unsigned DEFAULT 999 COMMENT '角色排序',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_user` bigint(20) unsigned NOT NULL COMMENT '修改人',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`role_id`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
CREATE TABLE IF NOT EXISTS `sys_role_menu` (
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色ID',
`menu_id` bigint(20) unsigned NOT NULL COMMENT '菜单ID',
PRIMARY KEY (`role_id`,`menu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和菜单关联表';
CREATE TABLE IF NOT EXISTS `sys_role_dept` (
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色ID',
`dept_id` bigint(20) unsigned NOT NULL COMMENT '部门ID',
PRIMARY KEY (`role_id`,`dept_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和部门关联表';
CREATE TABLE IF NOT EXISTS `sys_user` (
`user_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(255) NOT NULL COMMENT '用户名',
@ -43,61 +97,12 @@ CREATE TABLE IF NOT EXISTS `sys_user` (
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
CREATE TABLE IF NOT EXISTS `sys_role` (
`role_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '角色ID',
`role_name` varchar(255) NOT NULL COMMENT '角色名称',
`role_code` varchar(255) DEFAULT NULL COMMENT '角色编码',
`data_scope` tinyint(1) DEFAULT 4 COMMENT '数据权限1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限 5自定义数据权限',
`data_scope_dept_ids` json DEFAULT NULL COMMENT '数据权限范围部门ID数组',
`description` varchar(512) DEFAULT NULL COMMENT '描述',
`role_sort` int(11) unsigned DEFAULT 999 COMMENT '角色排序',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_user` bigint(20) unsigned NOT NULL COMMENT '修改人',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`role_id`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
CREATE TABLE IF NOT EXISTS `sys_user_role` (
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户ID',
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色ID',
PRIMARY KEY (`user_id`,`role_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和角色关联表';
CREATE TABLE IF NOT EXISTS `sys_menu` (
`menu_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '菜单ID',
`menu_name` varchar(255) NOT NULL COMMENT '菜单名称',
`parent_id` bigint(20) unsigned DEFAULT 0 COMMENT '上级菜单ID',
`menu_type` tinyint(1) unsigned DEFAULT 1 COMMENT '菜单类型1目录 2菜单 3按钮',
`path` varchar(512) DEFAULT NULL COMMENT '路由地址',
`name` varchar(255) DEFAULT NULL COMMENT '组件名称',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
`icon` varchar(255) DEFAULT NULL COMMENT '菜单图标',
`is_external` bit(1) DEFAULT b'0' COMMENT '是否外链',
`is_cache` bit(1) DEFAULT b'0' COMMENT '是否缓存',
`is_hidden` bit(1) DEFAULT b'0' COMMENT '是否隐藏',
`permission` varchar(255) DEFAULT NULL COMMENT '权限标识',
`menu_sort` int(11) unsigned DEFAULT 999 COMMENT '菜单排序',
`status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态1启用 2禁用',
`create_user` bigint(20) unsigned NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_user` bigint(20) unsigned NOT NULL COMMENT '修改人',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`menu_id`) USING BTREE,
INDEX `idx_parent_id`(`parent_id`) USING BTREE,
INDEX `idx_create_user`(`create_user`) USING BTREE,
INDEX `idx_update_user`(`update_user`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';
CREATE TABLE IF NOT EXISTS `sys_role_menu` (
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色ID',
`menu_id` bigint(20) unsigned NOT NULL COMMENT '菜单ID',
PRIMARY KEY (`role_id`,`menu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和菜单关联表';
CREATE TABLE IF NOT EXISTS `sys_log` (
`log_id` bigint(20) unsigned AUTO_INCREMENT COMMENT '日志ID',
`description` varchar(255) NOT NULL COMMENT '日志描述',