目录
1、权限菜单后端接口
2、查询权限菜单列表
2.1 设计效果图
3、 新增权限菜单
3.1 新增权限菜单窗口代码
3.2 选择所属菜单代码
3.3 封装图标选择器
3.4 新增、编辑和删除权限菜单
package com.cizhu.service;
import com.cizhu.entity.Permission;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cizhu.vo.query.PermissionQueryVo;
import java.util.List;
/**
*
* 服务类
*
*
* @author cizhu
* @since 2023-12-14
*/
public interface IPermissionService extends IService {
/**
* 根据用户ID查询菜单列表
* @param userId
* @return
*/
List findPermissionListByUserId(Long userId);
List findPermissionList(PermissionQueryVo permissionQueryVo);
boolean hasChildrenOfPermission(Long id);
List findParentPermissionList();
}
package com.cizhu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cizhu.entity.Permission;
import com.cizhu.mapper.PermissionMapper;
import com.cizhu.service.IPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cizhu.utils.MenuTree;
import com.cizhu.vo.query.PermissionQueryVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
/**
*
* 服务实现类
*
*
* @author cizhu
* @since 2023-12-14
*/
@Service
@Transactional
public class PermissionServiceImpl extends ServiceImpl implements IPermissionService {
@Override
public List findPermissionListByUserId(Long userId) {
return baseMapper.findPermissionListByUserId(userId);
}
@Override
public List findPermissionList(PermissionQueryVo permissionQueryVo) {
//创建条件构造器对象
QueryWrapper queryWrapper = new QueryWrapper();
//排序
queryWrapper.orderByAsc("order_num");
//调用查询菜单列表的方法
List permissionList = baseMapper.selectList(queryWrapper);
//生成菜单树
List menuTree = MenuTree.makeMenuTree(permissionList, 0L);
//返回数据
return menuTree;
}
@Override
public boolean hasChildrenOfPermission(Long id) {
return false;
}
@Override
public List findParentPermissionList() {
QueryWrapper queryWrapper = new QueryWrapper();
//只查询type为目录和菜单的数据(type=0或type=1)
queryWrapper.in("type", Arrays.asList(0,1));
//排序
queryWrapper.orderByAsc("order_num");
//查询菜单数据
List permissionList = baseMapper.selectList(queryWrapper);
//构造顶级菜单信息,如果数据库中的菜单表没有数据,选择上级菜单时则显示顶级菜单
Permission permission = new Permission();
permission.setId(0L);
permission.setParentId(-1L);
permission.setLabel("顶级菜单");
permissionList.add(permission);//将顶级菜单添加到集合
//生成菜单数据
List menuTree = MenuTree.makeMenuTree(permissionList, -1L);
//返回数据
return menuTree;
}
}
package com.cizhu.controller;
import com.cizhu.entity.Permission;
import com.cizhu.service.IPermissionService;
import com.cizhu.utils.Result;
import com.cizhu.vo.query.PermissionQueryVo;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
*
* 前端控制器
*
*
* @author cizhu
* @since 2023-12-14
*/
@RestController
@RequestMapping("/api/permission")
public class PermissionController {
@Resource
private IPermissionService permissionService;
/**
* 查询菜单列表
* @param permissionQueryVo
* @return
*/
@GetMapping("/getPermissionList")
@PreAuthorize("hasAuthority('sys:menu:select')")
public Result getPermissionList(PermissionQueryVo permissionQueryVo){
List resultPermissionList = permissionService.findPermissionList(permissionQueryVo);
return Result.ok(resultPermissionList);
}
/**
* 查询上级菜单列表
* @return
*/
@GetMapping("/parent/list")
public Result getParentPermissionList(){
List parentPermissionList = permissionService.findParentPermissionList();
return Result.ok(parentPermissionList);
}
/**
* 根据id查询菜单信息
* @param id
* @return
*/
@GetMapping("/{id}")
public Result getMenuById(@PathVariable Long id){
return Result.ok(permissionService.getById(id));
}
/**
* 添加菜单
* @param permission
* @return
*/
@PostMapping("/addPermission")
@PreAuthorize("hasAuthority('sys:menu:add')")
public Result addPermission(@RequestBody Permission permission){
if (permissionService.save(permission)) return Result.ok().message("菜单新增成功!");
return Result.error().message("菜单新增失败!");
}
/**
* 修改菜单
* @param permission
* @return
*/
@PutMapping("/editPermission")
@PreAuthorize("hasAuthority('sys:menu:edit')")
public Result editPermission(@RequestBody Permission permission){
if(permissionService.updateById(permission)) return Result.ok().message("修改菜单成功!");
return Result.error().message("修改菜单失败!");
}
/**
* 根据id删除菜单
* @param id
* @return
*/
@DeleteMapping("/delete/{id}")
@PreAuthorize("hasAuthority('sys:menu:delete')")
public Result deletePermissionById(@PathVariable Long id){
if (permissionService.removeById(id)) return Result.ok().message("删除菜单成功!");
return Result.ok().message("删除菜单失败!");
}
/**
* 检查菜单是否有子菜单
* @param id
* @return
*/
@GetMapping("/check/{id}")
public Result hasChildrenOfPermission(@PathVariable Long id){
if (permissionService.hasChildrenOfPermission(id)) {
return Result.exist().message("该菜单下有子菜单,不能删除!");
}
return Result.ok();
}
}
package com.cizhu.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
*
*
* @author cizhu
* @since 2023-12-14
*/
@Getter
@Setter
@TableName("sys_role_permission")
@ApiModel(value = "RolePermission对象", description = "")
public class RolePermission implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("角色ID")
private Long roleId;
@ApiModelProperty("权限ID")
private Long permissionId;
}
package com.cizhu.vo.query;
import com.cizhu.entity.Permission;
import lombok.Data;
@Data
public class PermissionQueryVo extends Permission {
}
package com.cizhu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
*
*
* @author cizhu
* @since 2023-12-14
*/
@Getter
@Setter
@TableName("sys_permission")
@ApiModel(value = "Permission对象", description = "")
public class Permission implements Serializable {
/**
* 子菜单列表
*/
@JsonInclude(JsonInclude.Include.NON_NULL) //属性值为null不进行序列化操作
@TableField(exist = false)
private List children = new ArrayList();
/**
* 用于前端判断是菜单、目录或按钮
*/
@TableField(exist = false)
private String value;
/**
* 是否展开
*/
@TableField(exist = false)
private Boolean open;
private static final long serialVersionUID = 1L;
@ApiModelProperty("权限编号")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("权限名称")
private String label;
@ApiModelProperty("父权限ID")
private Long parentId;
@ApiModelProperty("父权限名称")
private String parentName;
@ApiModelProperty("授权标识符")
private String code;
@ApiModelProperty("路由地址")
private String path;
@ApiModelProperty("路由名称")
private String name;
@ApiModelProperty("授权路径")
private String url;
@ApiModelProperty("权限类型(0-目录 1-菜单 2-按钮)")
private Integer type;
@ApiModelProperty("图标")
private String icon;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("排序")
private Integer orderNum;
@ApiModelProperty("是否删除(0-未删除,1-已删除)")
private Integer isDelete;
}
列表页面原型代码,编写前端api脚本和页面组件代码
新增
目录
菜单
按钮
编辑
删除
menu.js
import http from '@/utils/request'
export default {
/**
* 查询权限菜单列表
* @param params
*/
async getMenuList(params){
return await http.get("/api/permission/list",params);
},
/**
* 获取上级菜单
* @returns
*/
async getParentMenuList(params) {
return await http.get("/api/permission/parent/list", params)
},
/**
* 添加菜单
* @returns
*/
async addMenu(params){
return await http.post("/api/permission/add",params)
},
/**
* 修改菜单
* @returns
*/
async updateMenu(params) {
return await http.put("/api/permission/update", params);
},
/**
* 检查菜单下是否存在子菜单
*/
async checkPermission(param){
return await http.getRestApi("/api/permission/check",param);
},
/**
* 删除菜单
* @returns
*/
async deleteById(params) {
return await http.delete("/api/permission/delete", params);
}
}
1) 菜单类型,图标
2)滚动条样式
public/index.html
::-webkit-scrollbar{
width: 5px;
height: 5px;
background-color: #F5F5F5;
}
::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 8px;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb{
border-radius: 8px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
background-color: #c8c8c8;
}
目录
菜单
按钮
{{ node.label }}
utils/icons.js
export const elementIcons = ["platform-eleme", "eleme", "delete-solid", "delete",
"s-tools", "setting", "user-solid", "user", "phone", "phone-outline", "more",
"more-outline", "star-on", "star-off", "s-goods", "goods", "warning", "warningoutline", "question", "info", "remove", "circle-plus", "success", "error", "zoomin", "zoom-out", "remove-outline", "circle-plus-outline", "circle-check", "circleclose", "s-help", "help", "minus", "plus", "check", "close", "picture", "pictureoutline", "picture-outline-round", "upload", "upload2", "download", "camerasolid", "camera", "video-camera-solid", "video-camera", "message-solid", "bell",
"s-cooperation", "s-order", "s-platform", "s-fold", "s-unfold", "s-operation", "spromotion", "s-home", "s-release", "s-ticket", "s-management", "s-open", "s-shop",
"s-marketing", "s-flag", "s-comment", "s-finance", "s-claim", "s-custom", "sopportunity", "s-data", "s-check", "s-grid", "menu", "share", "d-caret", "caretleft", "caret-right", "caret-bottom", "caret-top", "bottom-left", "bottom-right",
"back", "right", "bottom", "top", "top-left", "top-right", "arrow-left", "arrowright", "arrow-down", "arrow-up", "d-arrow-left", "d-arrow-right", "video-pause",
"video-play", "refresh", "refresh-right", "refresh-left", "finished", "sort",
"sort-up", "sort-down", "rank", "loading", "view", "c-scale-to-original", "date",
"edit", "edit-outline", "folder", "folder-opened", "folder-add", "folder-remove",
"folder-delete", "folder-checked", "tickets", "document-remove", "documentdelete", "document-copy", "document-checked", "document", "document-add",
"printer", "paperclip", "takeaway-box", "search", "monitor", "attract", "mobile",
"scissors", "umbrella", "headset", "brush", "mouse", "coordinate", "magic-stick",
"reading", "data-line", "data-board", "pie-chart", "data-analysis", "collectiontag", "film", "suitcase", "suitcase-1", "receiving", "collection", "files",
"notebook-1", "notebook-2", "toilet-paper", "office-building", "school", "tablelamp", "house", "no-smoking", "smoking", "shopping-cart-full", "shopping-cart-1",
"shopping-cart-2", "shopping-bag-1", "shopping-bag-2", "sold-out", "sell",
"present", "box", "bank-card", "money", "coin", "wallet", "discount", "price-tag",
"news", "guide", "male", "female", "thumb", "cpu", "link", "connection", "open",
"turn-off", "set-up", "chat-round", "chat-line-round", "chat-square", "chat-dotround", "chat-dot-square", "chat-line-square", "message", "postcard", "position",
"turn-off-microphone", "microphone", "close-notification", "bangzhu", "time",
"odometer", "crop", "aim", "switch-button", "full-screen", "copy-document", "mic",
"stopwatch", "medal-1", "medal", "trophy", "trophy-1", "first-aid-kit",
"discover", "place", "location", "location-outline", "location-information", "addlocation", "delete-location", "map-location", "alarm-clock", "timer", "watch-1",
"watch", "lock", "unlock", "key", "service", "mobile-phone", "bicycle", "truck",
"ship", "basketball", "football", "soccer", "baseball", "wind-power", "lightrain", "lightning", "heavy-rain", "sunrise", "sunrise-1", "sunset", "sunny",
"cloudy", "partly-cloudy", "cloudy-and-sunny", "moon", "moon-night", "dish",
"dish-1", "food", "chicken", "fork-spoon", "knife-fork", "burger", "tableware",
"sugar", "dessert", "ice-cream", "hot-water", "water-cup", "coffee-cup", "colddrink", "goblet", "goblet-full", "goblet-square", "goblet-square-full",
"refrigerator", "grape", "watermelon", "cherry", "apple", "pear", "orange",
"coffee", "ice-tea", "ice-drink", "milk-tea", "potato-strips", "lollipop", "icecream-square", "ice-cream-round"].map(s => "el-icon-" + s);
/**
* 切换图标
* @param data
*/
changeIcon(data) {
data.ope = !data.open
this.$refs.parentTree.store.nodesMap[data.id].expanded = !data.open
},
//给icon绑定的点击事件
setIcon(icon) {
this.menu.icon = icon;
},
{{ userChooseIcon }}
新增
目录
菜单
按钮
编辑
删除
目录
菜单
按钮
{{ node.label }}