mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 10:57:13 +08:00 
			
		
		
		
	重构:重构系统管理/角色管理功能
1. 使用抽屉代替对话框 2. 优化数据权限权限范围存储,新增角色和部门关联表 3. 新增角色和菜单关联表 4. 部分细节优化
This commit is contained in:
		| @@ -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, | ||||
|         /** | ||||
|          * 修改 | ||||
|          */ | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -78,7 +78,7 @@ public interface BaseService<V, D, Q, C extends BaseRequest> { | ||||
|      *            创建信息 | ||||
|      * @return 自增 ID | ||||
|      */ | ||||
|     Long create(C request); | ||||
|     Long add(C request); | ||||
|  | ||||
|     /** | ||||
|      * 修改 | ||||
|   | ||||
| @@ -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())); | ||||
|         } | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|     /** | ||||
|      * 描述 | ||||
|      */ | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -43,7 +43,7 @@ public class RoleQuery implements Serializable { | ||||
|      * 角色名称 | ||||
|      */ | ||||
|     @Schema(description = "角色名称") | ||||
|     @Query(type = Query.Type.INNER_LIKE) | ||||
|     @Query(blurry = "roleName,roleCode") | ||||
|     private String roleName; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -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禁用) | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|     /** | ||||
|      * 是否禁用修改 | ||||
|      */ | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
| @@ -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,36 +189,14 @@ | ||||
|         @cancel="handleCancel" | ||||
|       > | ||||
|         <a-form ref="formRef" :model="form" :rules="rules" size="large"> | ||||
|           <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="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" | ||||
| @@ -237,12 +216,64 @@ | ||||
|                 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,7 +281,8 @@ | ||||
|         render-to-body | ||||
|         @cancel="handleDetailCancel" | ||||
|       > | ||||
|         <a-descriptions title="基础信息" :column="2" bordered size="large"> | ||||
|         <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" /> | ||||
| @@ -315,23 +347,30 @@ | ||||
|               <span v-else>{{ role.description }}</span> | ||||
|             </a-descriptions-item> | ||||
|           </a-descriptions> | ||||
|         <a-descriptions | ||||
|           v-if="role.dataScope === 5" | ||||
|           title="数据权限" | ||||
|           :column="2" | ||||
|           bordered | ||||
|           size="large" | ||||
|           style="margin-top: 25px" | ||||
|         > | ||||
|           <a-descriptions-item label="数据范围"> | ||||
|             <a-tree-select | ||||
|               v-model="role.dataScopeDeptIds" | ||||
|               :data="treeData" | ||||
|               tree-checkable | ||||
|               disabled | ||||
|         </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-descriptions-item> | ||||
|         </a-descriptions> | ||||
|         </a-card> | ||||
|         <a-card | ||||
|           v-if="role.dataScope === 5" | ||||
|           :loading="deptLoading" | ||||
|           title="数据权限" | ||||
|           :bordered="false" | ||||
|         > | ||||
|           <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; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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/admin123;test/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/admin123;test/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); | ||||
| @@ -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 '日志描述', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user