当前位置: 首页 > ops >正文

高效菜单管理页面:一键增删改查

<template><div class="app-container"><el-card><!-- 搜索和操作区域 --><div class="filter-container"><el-button type="primary" icon="el-icon-plus" size="mini" @click="handleCreate">新增菜单</el-button><el-button icon="el-icon-refresh" size="mini" @click="getMenuList">刷新</el-button></div><!-- 菜单表格 --><el-tableheight="500":data="menuList"row-key="id"borderstripedefault-expand-all:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"v-loading="loading"><el-table-column prop="menuTitle" label="菜单名称" width="200" fixed="left" /><el-table-column prop="menuName" label="路由名称" width="150" /><el-table-column prop="menuPath" label="路由路径" width="150" /><el-table-column prop="component" label="组件路径" width="200" /><el-table-column prop="perm" label="权限标识" width="150" /><el-table-column prop="redirect" label="重定向路径" width="200" /><el-table-column label="图标" width="100"><template slot-scope="scope"><i :class="scope.row.iconClass" v-if="scope.row.iconClass"></i><span v-else>/</span></template></el-table-column><el-table-column prop="orderNum" label="排序" width="80" align="center" /><el-table-column label="是否可见" width="100" align="center"><template slot-scope="scope"><el-tag :type="scope.row.visible ? 'success' : 'danger'">{{ scope.row.visible ? '是' : '否' }}</el-tag></template></el-table-column><el-table-column label="操作" width="200" fixed="right"><template slot-scope="scope"><el-buttontype="text"icon="el-icon-edit"@click="handleEdit(scope.row)" >编辑</el-button><el-buttontype="text"icon="el-icon-delete"@click="handleDelete(scope.row)" >删除</el-button></template></el-table-column></el-table></el-card><!-- 新增/编辑对话框 --><el-dialog:title="dialogTitle":visible.sync="dialogVisible"width="600px"@close="resetForm"><el-formref="menuForm":model="form":rules="rules"label-width="100px"label-position="right"><el-form-item label="父级菜单" prop="parentId"><el-selectfilterablev-model="form.parentId"placeholder="选择父级菜单"style="width: 100%" ><el-optionv-for="item in menuTreeOptions":key="item.id":value="item.id":label="item.menuTitle"/></el-select></el-form-item><el-form-item label="菜单类型" prop="types"><el-radio-group v-model="form.types"><el-radio :label="0">目录</el-radio><el-radio :label="1">菜单</el-radio><el-radio :label="2">按钮</el-radio></el-radio-group></el-form-item><el-form-item label="菜单名称" prop="menuTitle"><el-input v-model="form.menuTitle" placeholder="请输入菜单名称" /><div class="form-tip">显示在侧边栏的名称</div></el-form-item><el-form-item label="路由名称" prop="menuName"><el-input v-model="form.menuName" placeholder="请输入路由名称" /><div class="form-tip">菜单的唯一标识名</div></el-form-item><el-form-item label="路由路径" prop="menuPath"><el-input v-model="form.menuPath" placeholder="请输入路由路径" /></el-form-item><el-form-itemlabel="组件路径"prop="component"v-if="form.types !== 2"><el-input v-model="form.component" placeholder="请输入组件路径" /><div class="form-tip">例如:@/views/system/user/index</div></el-form-item><el-form-itemlabel="重定向路径"><el-input v-model="form.redirect" placeholder="请输入重定向路径" /><div class="form-tip">例如:/user/index</div></el-form-item><el-form-item label="权限标识"><el-input v-model="form.perm" placeholder="请输入权限标识"  /></el-form-item><el-form-item label="图标" prop="iconClass"><el-input v-model="form.iconClass" placeholder="请输入图标类名"><template slot="prepend"><i :class="form.iconClass" v-if="form.iconClass"></i><i class="el-icon-picture" v-else></i></template></el-input><div class="form-tip">Element UI图标类名,如:el-icon-user</div></el-form-item><el-form-item label="排序" prop="orderNum"><el-input-number v-model="form.orderNum" :min="0" :max="10000" /></el-form-item><el-form-item label="是否可见" prop="visible"><el-switch v-model="form.visible" :active-value="1" :inactive-value="0" /></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button type="primary" @click="handleSubmit">确定</el-button><el-button @click="dialogVisible = false">取消</el-button></span></el-dialog></div>
</template><script>
import { reqMenuList, addMenu, updateMenu, deleteMenu } from '@/api/menu'
import { generatorTree, buildTreeOptions } from '@/utils/myUtils.js'export default {name: 'MenuManagement',data() {return {loading: false,menuList: [],menuTreeOptions: [],dialogVisible: false,dialogTitle: '新增菜单',form: {id: null,parentId: 0,types: 1,menuTitle: '',menuName: '',menuPath: '',component: '',perm: '',iconClass: '',orderNum: 0,visible: 1,redirect: '',},rules: {menuTitle: [{ required: true, message: '请输入菜单名称', trigger: 'blur' }],menuName: [{ required: true, message: '请输入路由名称', trigger: 'blur' }],menuPath: [{ required: true, message: '请输入路由路径', trigger: 'blur' }],component: [{ required: true, message: '请输入组件路径', trigger: 'blur' }]}}},mounted() {this.getMenuList()},methods: {// 获取菜单列表async getMenuList() {this.loading = truetry {const res = await reqMenuList()  // 获取菜单this.menuList = generatorTree(res.data, 0)   // 菜单列表this.menuTreeOptions = buildTreeOptions(res.data)  } catch (error) {console.error('获取菜单列表失败:', error)} finally {this.loading = false}},// 新增菜单handleCreate() {this.dialogTitle = '新增菜单'this.dialogVisible = true},// 编辑菜单handleEdit(row) {this.dialogTitle = '编辑菜单'this.form = { ...row }this.dialogVisible = true},// 删除菜单handleDelete(row) {this.$confirm(`确定删除菜单 "${row.menuTitle}" 吗?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {const {code, message} = await deleteMenu(row.id)if (code == 200) {this.$message.success(message)this.getMenuList()} else {this.$message.error(message)}})},// 提交表单handleSubmit() {this.$refs.menuForm.validate(async(valid) => {if (valid) {if (this.form.id) {const { code, message } = await updateMenu(this.form)if (code == 200) {this.$message.success(message)} else {this.$message.error(message)}} else {const { code, message } = await addMenu(this.form)if (code == 200) {this.$message.success(message)} else {this.$message.error(message)}}this.dialogVisible = falsethis.getMenuList()}})},// 重置表单resetForm() {this.$refs.menuForm.resetFields()this.form = {id: null,parentId: 0,types: 1,menuTitle: '',menuName: '',menuPath: '',component: '',iconClass: '',perm: '',orderNum: 0,visible: 1,redirect: '',}}}
}
</script><style scoped>
.filter-container {margin-bottom: 20px;
}.form-tip {font-size: 12px;color: #909399;margin-top: 4px;
}.app-container {padding: 20px;
}
</style>

工具类,生成树形结构及筛选出父级目录


// 筛选出父级目录
export function  buildTreeOptions(data) {const options = [{ id: 0, menuTitle: '根目录' }]data.forEach(item => {if (item.types === 0 || item.types == 1) { // 只显示目录类型或菜单类型options.push({ id: item.id, menuTitle: item.menuTitle})}})return options
}// 扁平化变成结构数据
export function generatorTree(list, rootValue) {const arr = []list.forEach(item => {if (item.parentId == rootValue) {// 找到了匹配的节点arr.push(item)// 当前节点的id 和 当前节点的子节点的pid是想等的const children = generatorTree(list, item.id) // 找到的节点的子节点if (children.length) { item.children = children } // 将子节点赋值给当前节点}})return arr
}

前端访问后端接口


// 获取菜单列表
export function reqMenuList() {return request({url: '/menu/getDataList',method: 'get'})
}// 新增菜单
export function addMenu(data) {return request({url: '/menu/addMenu',method: 'post',data})
}// 更新菜单
export function updateMenu(data) {return request({url: '/menu/updateMenu',method: 'put',data})
}// 删除菜单
export function deleteMenu(id) {return request({url: `/menu/deleteMenuById/${id}`,method: 'delete'})
}

后端接口

 // 获取菜单和操作权限@GetMapping("/getDataList")public ResultBean selectMenuList() {return ResultBean.success("获取成功", menuService.selectMenuList());}// 添加菜单@PostMapping("/addMenu")@ResponseBodypublic ResultBean addMenu(@RequestBody Menu menu) {menuService.addMenu(menu);return ResultBean.success("添加成功");}// 根据id删除菜单@DeleteMapping("/deleteMenuById/{id}")public ResultBean deleteMenuById(@PathVariable Integer id) {menuService.deleteMenuById(id);return ResultBean.success("删除成功");}// 根据id修改菜单@PutMapping("/updateMenu")public ResultBean updateMenu(@RequestBody Menu menu) {menuService.updateMenu(menu);return ResultBean.success("修改成功");}

业务逻辑

 // 添加菜单@Overridepublic void addMenu(Menu menu) {menuMapper.addMenu(menu);}// 根据 id 删除菜单@Transactional@Overridepublic void deleteMenuById(Integer id) {menuMapper.deleteMenuById(id);menuMapper.delPermByMenuId(id);}// 修改菜单@Transactional@Overridepublic void updateMenu(Menu menu) {menuMapper.updateMenu(menu);}

数据库设计

效果如下

http://www.xdnf.cn/news/19823.html

相关文章:

  • Word 常用快捷键大全:提升文档处理效率的必备技巧​
  • FastGPT源码解析 Agent工作流编排后端详解
  • Ansible自动化运维:从入门到精通
  • 【面试题】词汇表大小如何选择?
  • React实现点击按钮复制操作【navigator.clipboard与document.execCommand】
  • Elasticsearch面试精讲 Day 6:Query DSL查询语法详解
  • 【JAVA】windows本地跑zookeeper,然后使用代码连接服务获取znode数据
  • 【leetcode】130. 被围绕的区域
  • NLP插曲番外 · 猫猫狐狐问答夜话
  • 分词器详解(一)
  • 信息融智学=信息哲学+信息科学+信息技术+信息系统工程+信息处理之智
  • 组长跟我说,她招人看重的是数据分析能力
  • 计算机视觉(七):膨胀操作
  • 机器学习 - Kaggle项目实践(8)Spooky Author Identification 作者识别
  • awk命令
  • GitHub 上那些值得收藏的英文书籍推荐(计算机 非计算机类)
  • 逻辑回归:从原理到实战的完整指南
  • 刻意练习理论
  • 群晖为家纺企业 500 名员工打造企业网盘,赋能家纺制造效率飞跃
  • Python数据分析与处理(二):将数据写回.mat文件的不同方法【超详细】
  • 第二章 Windows 核心概念通俗解析
  • Linux 的 swap 是什么
  • Vue3 警告:Runtime directive used on component with non-element root node 解决方案
  • 16k+ star! 只需要DDL就能一键生成数据库关系图!
  • 正运动控制卡学习-网络连接
  • Java 黑马程序员(进阶篇1)
  • 从BERT到RoBERTa、ALBERT:揭秘Encoder-only预训练模型的进化之路
  • 【常用SQL语句和语法总结】
  • 数据科学家如何更好地展示自己的能力
  • 项目中 Spring Boot 配置文件未生效该如何解决