diff --git a/opsli-api/src/main/java/org/opsli/api/web/system/menu/MenuApi.java b/opsli-api/src/main/java/org/opsli/api/web/system/menu/MenuApi.java index c3fbe522..8f9df22d 100644 --- a/opsli-api/src/main/java/org/opsli/api/web/system/menu/MenuApi.java +++ b/opsli-api/src/main/java/org/opsli/api/web/system/menu/MenuApi.java @@ -16,6 +16,7 @@ package org.opsli.api.web.system.menu; import org.opsli.api.base.result.ResultVo; +import org.opsli.api.wrapper.system.menu.MenuFullModel; import org.opsli.api.wrapper.system.menu.MenuModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -179,10 +180,18 @@ public interface MenuApi { // ================= 普通 + /** * 根据菜单权限 获得菜单 * @param permissions 菜单权限 * @return ResultVo */ ResultVo getByPermissions(String permissions); + + /** + * 菜单完整 新增 + * @param menuFullModel 模型 + * @return ResultVo + */ + ResultVo saveMenuByFull(@RequestBody MenuFullModel menuFullModel); } diff --git a/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuFullModel.java b/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuFullModel.java new file mode 100644 index 00000000..a5fc2631 --- /dev/null +++ b/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuFullModel.java @@ -0,0 +1,69 @@ +/** + * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com + *

+ * 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 org.opsli.api.wrapper.system.menu; + +import com.alibaba.excel.annotation.ExcelIgnore; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.opsli.api.base.warpper.ApiWrapper; +import org.opsli.common.annotation.validation.ValidationArgs; +import org.opsli.common.annotation.validation.ValidationArgsLenMax; +import org.opsli.common.enums.ValiArgsType; + +import java.io.Serializable; + +/** + * @BelongsProject: opsli-boot + * @BelongsPackage: org.opsli.api.wrapper.system.menu + * @Author: Parker + * @CreateTime: 2020-09-16 17:33 + * @Description: 创建完整菜单 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class MenuFullModel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 上级菜单ID */ + @ApiModelProperty(value = "上级菜单ID") + @ExcelIgnore + @ValidationArgs({ValiArgsType.IS_NOT_NULL}) + @ValidationArgsLenMax(19) + private String parentId; + + /** 菜单名称 */ + @ApiModelProperty(value = "菜单名称") + @ExcelIgnore + @ValidationArgs({ValiArgsType.IS_NOT_NULL}) + @ValidationArgsLenMax(100) + private String title; + + /** 模块名 */ + @ApiModelProperty(value = "模块名") + @ExcelIgnore + @ValidationArgs({ValiArgsType.IS_NOT_NULL}) + @ValidationArgsLenMax(40) + private String moduleName; + + /** 子模块名 */ + @ApiModelProperty(value = "子模块名") + @ExcelIgnore + @ValidationArgsLenMax(40) + private String subModuleName; + +} diff --git a/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuModel.java b/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuModel.java index 78521f79..0c7fd6a7 100644 --- a/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuModel.java +++ b/opsli-api/src/main/java/org/opsli/api/wrapper/system/menu/MenuModel.java @@ -29,7 +29,7 @@ import org.opsli.plugins.excel.annotation.ExcelInfo; /** * @BelongsProject: opsli-boot - * @BelongsPackage: org.opsli.modulars.test.entity + * @BelongsPackage: org.opsli.api.wrapper.system.menu * @Author: Parker * @CreateTime: 2020-09-16 17:33 * @Description: 菜单表 diff --git a/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserInfo.java b/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserInfo.java index 6cba1271..d85a6870 100644 --- a/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserInfo.java +++ b/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserInfo.java @@ -91,9 +91,12 @@ public class UserInfo extends ApiWrapper { @ApiModelProperty(value = "权限列表") private List perms; - /** 是否是超级管理员 */ @ApiModelProperty(value = "是否是超级管理员") private boolean izSuperAdmin; + /** 密码强度 字典 password_level */ + @ApiModelProperty(value = "密码强度") + private String passwordLevel; + } diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MenuConstants.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MenuConstants.java index 8cb6b21c..c9136a1c 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MenuConstants.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MenuConstants.java @@ -23,6 +23,9 @@ package org.opsli.common.constants; */ public interface MenuConstants { + /** 菜单根节点ID */ + String GEN_ID = "0"; + /** 菜单类型 */ String MENU = "1"; diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/enums/DictType.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/enums/DictType.java index 3daf7809..40f37e08 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/enums/DictType.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/enums/DictType.java @@ -25,18 +25,24 @@ package org.opsli.common.enums; public enum DictType { /** 是否 */ - NO_YES_NO("no_yes","0"), - NO_YES_YES("no_yes","1"), + NO_YES_NO("no_yes","0", "否"), + NO_YES_YES("no_yes","1", "是"), + /** 菜单 */ + MENU_MENU("menu_type","1", "菜单"), + MENU_BUTTON("menu_type","2", "按钮"), + MENU_EXTERNAL("menu_type","3", "外链"), ; private final String type; private final String value; + private final String desc; - DictType(String type, String value){ + DictType(String type, String value, String desc){ this.type = type; this.value = value; + this.desc = desc; } public String getValue() { @@ -47,6 +53,10 @@ public enum DictType { return this.type; } + public String getDesc() { + return this.desc; + } + /** * 获得对应的字典 * @param type 类型 diff --git a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/core/creater/msg/CreaterMsg.java b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/core/creater/msg/CreaterMsg.java index da2b4734..0ed691f8 100644 --- a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/core/creater/msg/CreaterMsg.java +++ b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/core/creater/msg/CreaterMsg.java @@ -56,6 +56,8 @@ public enum CreaterMsg implements BaseMsg { EXCEPTION_CREATE_NULL(50140,"生成失败,数据为空"), EXCEPTION_CREATE_TABLE_NULL(50141,"生成失败,暂无表数据"), EXCEPTION_CREATE_FIELD_NULL(50142,"生成失败,暂无表字段"), + EXCEPTION_CREATE_MENU_CODE_NULL(50143,"生成菜单失败,请先生成代码"), + EXCEPTION_CREATE_MENU_PARENT_NULL(50144,"上级菜单不可为空"), /** * 其他 diff --git a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/api/CreaterLogsApi.java b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/api/CreaterLogsApi.java index c52a23f5..dcd7c6f4 100644 --- a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/api/CreaterLogsApi.java +++ b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/api/CreaterLogsApi.java @@ -56,12 +56,22 @@ public interface CreaterLogsApi { ResultVo getByTableId(String tableId); /** - * 生成记录 修改 + * 代码生成 修改 * @param model 模型 * @return ResultVo */ @GetMapping("/create") void create(CreaterLogsModel model, HttpServletResponse response); + /** + * 生成菜单 + * + * @param menuParentId 上级菜单ID + * @param tableId 表ID + * @return ResultVo + */ + @PostMapping("/createMenu") + ResultVo createMenu(String menuParentId, String tableId); + } diff --git a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/service/ICreateLogsService.java b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/service/ICreateLogsService.java index 32404e0c..2b782f65 100644 --- a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/service/ICreateLogsService.java +++ b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/service/ICreateLogsService.java @@ -44,14 +44,23 @@ public interface ICreateLogsService extends CrudServiceInterface insertRet = menuApi.saveMenuByFull(menuFullModel); + + return insertRet.isSuccess(); + } + + } diff --git a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/web/CreaterLogsRestController.java b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/web/CreaterLogsRestController.java index 64a4e042..472b7d5b 100644 --- a/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/web/CreaterLogsRestController.java +++ b/opsli-modulars/opsli-modulars-creater/src/main/java/org/opsli/modulars/creater/createrlogs/web/CreaterLogsRestController.java @@ -23,6 +23,8 @@ import org.opsli.api.base.result.ResultVo; import org.opsli.common.annotation.ApiRestController; import org.opsli.common.annotation.EnableLog; import org.opsli.core.base.controller.BaseRestController; +import org.opsli.core.creater.exception.CreaterException; +import org.opsli.core.creater.msg.CreaterMsg; import org.opsli.modulars.creater.createrlogs.api.CreaterLogsApi; import org.opsli.modulars.creater.createrlogs.entity.CreaterLogs; import org.opsli.modulars.creater.createrlogs.service.ICreateLogsService; @@ -69,4 +71,27 @@ public class CreaterLogsRestController extends BaseRestController createMenu(String menuParentId, String tableId) { + // 演示模式 不允许操作 + super.demoError(); + + // 调用生成菜单方法 + boolean menuFlag = IService.createMenu(menuParentId, tableId); + if(!menuFlag){ + return ResultVo.error(); + } + return ResultVo.success(); + } + } diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/factory/MenuFactory.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/factory/MenuFactory.java new file mode 100644 index 00000000..ae66f589 --- /dev/null +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/factory/MenuFactory.java @@ -0,0 +1,191 @@ +package org.opsli.modulars.system.menu.factory; + +import cn.hutool.core.collection.ListUtil; +import com.google.common.collect.Lists; +import lombok.Builder; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.opsli.api.wrapper.system.menu.MenuFullModel; +import org.opsli.api.wrapper.system.menu.MenuModel; +import org.opsli.common.enums.DictType; + +import java.util.List; + +/** + * 菜单生成工厂 + * + * @author 周鹏程 + * @date 2021-05-04 7:15 下午 + **/ +public enum MenuFactory { + + /** 实例 */ + INSTANCE; + + /** 菜单权限分割符 */ + private final static String MENU_DELIMITER = "_"; + /** 菜单按钮JSON 数组 */ + private final List menuBtnList; + + MenuFactory(){ + menuBtnList = Lists.newArrayList(); + + menuBtnList.add( + MenuBtn.builder() + .title("查看") + .permission("select") + .build() + ); + + + menuBtnList.add( + MenuBtn.builder() + .title("新增") + .permission("insert") + .build() + ); + + menuBtnList.add( + MenuBtn.builder() + .title("修改") + .permission("update") + .build() + ); + + menuBtnList.add( + MenuBtn.builder() + .title("删除") + .permission("delete") + .build() + ); + + menuBtnList.add( + MenuBtn.builder() + .title("导入") + .permission("import") + .build() + ); + + menuBtnList.add( + MenuBtn.builder() + .title("导出") + .permission("export") + .build() + ); + } + + /** + * 生成菜单模型集合 + * @param model 生成模型 + * @return MenuModel + */ + public MenuModel createMenu(MenuFullModel model){ + if(model == null){ + return new MenuModel(); + } + + // 标题 + String title = model.getTitle(); + // 子模块名 + String subModuleName = model.getSubModuleName(); + + MenuModel menu = new MenuModel(); + menu.setParentId(model.getParentId()); + menu.setMenuName(title); + menu.setAlwaysShow(DictType.NO_YES_NO.getValue()); + menu.setHidden(DictType.NO_YES_NO.getValue()); + menu.setUrl(subModuleName); + menu.setType(DictType.MENU_MENU.getValue()); + menu.setSortNo(1); + menu.setComponent("views/modules/"+model.getModuleName()+"/"+model.getSubModuleName()+"/index"); + + return menu; + } + + + /** + * 生成菜单按钮 + * @param model 生成模型 + * @return MenuModel + */ + public List createMenuBtnList(MenuFullModel model){ + if(model == null){ + return ListUtil.empty(); + } + + List menuBtnModelList = Lists.newArrayListWithCapacity(menuBtnList.size()); + for (int i = 0; i < menuBtnList.size(); i++) { + MenuBtn menuBtn = menuBtnList.get(i); + MenuModel menuBtnModel = this.createMenuBtn(model.getParentId(), model, menuBtn); + menuBtnModel.setSortNo(i+1); + menuBtnModelList.add(menuBtnModel); + } + return menuBtnModelList; + } + + /** + * 生成菜单按钮 + * @param menuParentId 上级菜单ID + * @param model 生成模型 + * @param menuBtn 菜单按钮 + * @return MenuModel + */ + private MenuModel createMenuBtn(String menuParentId, MenuFullModel model, MenuBtn menuBtn){ + // 标题 + String title = menuBtn.getTitle(); + // 模块名 + String moduleName = model.getModuleName(); + // 子模块名 + String subModuleName = model.getSubModuleName(); + // 权限 + String permission = menuBtn.getPermission(); + + MenuModel menu = new MenuModel(); + menu.setParentId(menuParentId); + menu.setMenuName(title); + menu.setAlwaysShow(DictType.NO_YES_NO.getValue()); + menu.setHidden(DictType.NO_YES_NO.getValue()); + menu.setType(DictType.MENU_BUTTON.getValue()); + menu.setPermissions( + this.createPermission(moduleName, subModuleName, permission) + ); + menu.setSortNo(1); + + return menu; + } + + /** + * 生成权限 + * @param moduleName 模块名 + * @param subModuleName 子模块名 + * @param permission 权限 + * @return String + */ + private String createPermission(String moduleName, String subModuleName, String permission){ + StringBuilder permissionSb = new StringBuilder(); + if(StringUtils.isNotEmpty(moduleName)){ + permissionSb.append(moduleName).append(MENU_DELIMITER); + } + if(StringUtils.isNotEmpty(subModuleName)){ + permissionSb.append(subModuleName).append(MENU_DELIMITER); + } + permissionSb.append(permission); + return permissionSb.toString(); + } + + + /** + * 菜单按钮 + */ + @Data + @Builder + private static class MenuBtn{ + + /** 标题 */ + private String title; + + /** 权限 */ + private String permission; + + } +} diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/IMenuService.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/IMenuService.java index d0cf952d..0ec453f3 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/IMenuService.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/IMenuService.java @@ -15,6 +15,7 @@ */ package org.opsli.modulars.system.menu.service; +import org.opsli.api.wrapper.system.menu.MenuFullModel; import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.core.base.entity.HasChildren; import org.opsli.core.base.service.interfaces.CrudServiceInterface; @@ -56,4 +57,11 @@ public interface IMenuService extends CrudServiceInterface { */ List hasChildrenByChoose(Set parentIds); + /** + * 保存完成菜单 + * @param menu 菜单 + * @return boolean + */ + void saveMenuByFull(MenuFullModel menu); + } diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java index 4bd9b0b2..3628440c 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java @@ -19,8 +19,10 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.commons.lang3.StringUtils; +import org.opsli.api.wrapper.system.menu.MenuFullModel; import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.user.UserModel; +import org.opsli.common.constants.MenuConstants; import org.opsli.common.constants.MyBatisConstants; import org.opsli.common.enums.DictType; import org.opsli.common.exception.ServiceException; @@ -34,6 +36,7 @@ import org.opsli.core.utils.MenuUtil; import org.opsli.core.utils.UserUtil; import org.opsli.modulars.system.SystemMsg; import org.opsli.modulars.system.menu.entity.SysMenu; +import org.opsli.modulars.system.menu.factory.MenuFactory; import org.opsli.modulars.system.menu.mapper.MenuMapper; import org.opsli.modulars.system.menu.service.IMenuService; import org.opsli.modulars.system.org.entity.SysOrg; @@ -86,16 +89,21 @@ public class MenuServiceImpl extends CrudServiceImpl 0){ -// // 重复 -// throw new ServiceException(SystemMsg.EXCEPTION_MENU_PERMISSIONS_UNIQUE); -// } - // 如果上级ID 为空 则默认为 0 if(StringUtils.isEmpty(model.getParentId())){ - model.setParentId("0"); + model.setParentId(MenuConstants.GEN_ID); + } + + // 容错处理 + // 如果根结点为0 且 为菜单类型 判断首位是否为 / 如果没有则自动加 / + if(MenuConstants.GEN_ID.equals(model.getParentId())){ + if(StringUtils.isNotEmpty(model.getUrl())){ + char firstChar = '/'; + char first = model.getUrl().charAt(0); + if(firstChar != first){ + model.setUrl("/"+model.getUrl()); + } + } } // 菜单有变动 直接刷新超级管理员 菜单缓存 @@ -130,12 +138,17 @@ public class MenuServiceImpl extends CrudServiceImpl 0){ -// // 重复 -// throw new ServiceException(SystemMsg.EXCEPTION_MENU_PERMISSIONS_UNIQUE); -// } + // 容错处理 + // 如果根结点为0 且 为菜单类型 判断首位是否为 / 如果没有则自动加 / + if(MenuConstants.GEN_ID.equals(model.getParentId())){ + if(StringUtils.isNotEmpty(model.getUrl())){ + char firstChar = '/'; + char first = model.getUrl().charAt(0); + if(firstChar != first){ + model.setUrl("/"+model.getUrl()); + } + } + } MenuModel menuModel = super.update(model); if(menuModel != null){ @@ -146,6 +159,46 @@ public class MenuServiceImpl extends CrudServiceImpl menuBtnList = MenuFactory.INSTANCE.createMenuBtnList(menuFullModel); + for (MenuModel btnModel : menuBtnList) { + this.insert(btnModel); + } + } + @Override @Transactional(rollbackFor = Exception.class) public boolean delete(String id) { diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/web/MenuRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/web/MenuRestController.java index a185c9c7..e19e4dd1 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/web/MenuRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/web/MenuRestController.java @@ -34,6 +34,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.opsli.api.base.result.ResultVo; import org.opsli.api.web.system.menu.MenuApi; +import org.opsli.api.wrapper.system.menu.MenuFullModel; import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.common.annotation.ApiRestController; @@ -93,8 +94,6 @@ public class MenuRestController extends BaseRestController get(MenuModel model) { if(model != null){ - if(StringUtils.equals(BASE_NODE, model.getId())){ + if(StringUtils.equals(MenuConstants.GEN_ID, model.getId())){ model.setMenuName("根节点"); model.setHidden("0"); model.setSortNo(-1); @@ -661,4 +660,15 @@ public class MenuRestController extends BaseRestController saveMenuByFull(MenuFullModel menuFullModel) { + IService.saveMenuByFull(menuFullModel); + return ResultVo.success(); + } }