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

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

<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://nIxSdwwA.nkjnr.cn
http://MbaFdXDe.nkjnr.cn
http://qs0pNWZL.nkjnr.cn
http://Q0yHkDkQ.nkjnr.cn
http://dzFYGxwz.nkjnr.cn
http://jVPHzHjm.nkjnr.cn
http://PlkStDSd.nkjnr.cn
http://762qA4WW.nkjnr.cn
http://FM59ZDCf.nkjnr.cn
http://4f7sFcSU.nkjnr.cn
http://wBPVdqq3.nkjnr.cn
http://Ximq5d8n.nkjnr.cn
http://f4DB9tPN.nkjnr.cn
http://4B4OIkOT.nkjnr.cn
http://oVt6bSBo.nkjnr.cn
http://GAQ90eI4.nkjnr.cn
http://LnEcTiSl.nkjnr.cn
http://xmw5O2TJ.nkjnr.cn
http://IfqBKVfh.nkjnr.cn
http://GLjokUFT.nkjnr.cn
http://2AlOqmmc.nkjnr.cn
http://p7lIFtVx.nkjnr.cn
http://Xorhx5md.nkjnr.cn
http://SbzU9IQJ.nkjnr.cn
http://9FNOBDAt.nkjnr.cn
http://5F7nM5IO.nkjnr.cn
http://ubVBSMjP.nkjnr.cn
http://I4XzZs3D.nkjnr.cn
http://jXOuoolt.nkjnr.cn
http://kO0M5sxB.nkjnr.cn
http://www.dtcms.com/a/366980.html

相关文章:

  • jmeter压测工具使用详情
  • finally 与 return的执行顺序
  • Java String vs StringBuilder vs StringBuffer:一个性能优化的探险故事
  • 邦芒干货:新入职场的人必须要知道的三大事情
  • JY-H818|科智立RFID高频读写器产品参数解析
  • LVDS系列27:Xilinx 7系 OSERDESE2原语(三)
  • [晕事]今天做了件晕事91,glibc,rand之前必须设置种子
  • C语言内存精讲系列(七):深入解析 x86 实模式
  • 远场代码学习_FDTD_farfield
  • 五、插值与拟合
  • 今天我们继续学习Linux中的shell脚本流程控制内容
  • 大模型微调之LORA核心逻辑
  • React笔记_组件之间进行数据传递
  • 《Java餐厅的待客之道:BIO, NIO, AIO三种服务模式的进化》
  • 【OpenHarmony文件管理子系统】文件访问接口解析
  • sealos部署k8s
  • (C题|NIPT 的时点选择与胎儿的异常判定)2025年高教杯全国大学生数学建模国赛解题思路|完整代码论文集合
  • 25高教社杯数模国赛【C题国一学长思路+问题分析】第二弹
  • 数学建模25c
  • 互联网大厂Java面试场景与问题解答
  • LeetCode 刷题【64. 最小路径和】
  • Rust+slint实现一个登录demo
  • Rust 文件操作终极实战指南:从基础读写到进阶锁控,一文搞定所有 IO 场景
  • 代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
  • 2025全国大学生数学建模C题保姆级思路模型(持续更新):NIPT 的时点选择与胎儿的异常判定
  • 2025反爬虫之战札记:从robots.txt到多层防御的攻防进化史
  • 23种设计模式——工厂方法模式(Factory Method Pattern)详解
  • C++ 学习与 CLion 使用:(七)if 逻辑判断和 switch 语句
  • docker中的mysql变更宿主机映射端口
  • Redis(43)Redis哨兵(Sentinel)是什么?