Our general background management projects are configured in the background to configure routing and permissions, and if we need to add menus in the front end, we need to write a menu management page for configuration.
1. New menu management page
Create a new menu package under views, and create a new SysMenu.vue page under this package
2. Menu management page code
<!-- Menu management page --> <template> <div> <!-- 1. Add button area --> <div style="display: flex;justify-content: flex-start"> <el-button type="primary" icon="el-icon-plus" size="small" @click="addFolder">Add</el-button> </div> <!-- 2. Divider area --> <el-divider style="margin-top: 20px"></el-divider> <!-- 3. Menu table area --> <el-table :data="menuTreeList" style="width: 100%; margin-bottom: 20px;" row-key="id" border :default-expand-all="false" height="72vh" :tree-props="{children: 'children'}"> <el-table-column prop="name" label="menu name" > </el-table-column> <el-table-column prop="type" label="type"> <!--Conditional judgment--> <template slot-scope="scope"> <!--Get the type attribute and make a conditional judgment --> <el-tag v-if="scope.row.type===0">Directory</el-tag> <el-tag type="success" v-else-if="scope.row.type===1">menu</el-tag> <el-tag type="info" v-else>button</el-tag> </template> </el-table-column> <el-table-column prop="icon" label="icon"> <template slot-scope="scope"> <i :class="scope.row.icon"></i> </template> </el-table-column> <el-table-column prop="perms" label="permission identification"/> <el-table-column prop="path" label="routing address"/> <el-table-column prop="component" label="component path"/> <el-table-column prop="sortValue" label="sort"/> <el-table-column label="status" width="80"> <template slot-scope="scope"> <el-switch :value="scope.row.status === 1" :disabled="true"> </el-switch> </template> </el-table-column> <el-table-column prop="createTime" label="create time" width="160"/> <el-table-column label="Operation" width="180" fixed="right"> <template slot-scope="scope"> <el-button type="success" v-if="scope.row.type !== 2" icon="el-icon-plus" size="mini" @click=\ "addLastNode(scope.row)" title="Add"/> <el-button type="primary" icon="el-icon-edit" size="mini" @click="alertNode(scope.row)" title="Edit"/ > <el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteMenuData(scope.row.id)" title="Delete" " :disabled="scope.row.children.length > 0"/> </template> </el-table-column> </el-table> <!-- 4. Add and update the pop-up window area --> <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="40%" @open="onOpen" @close="onClose"> <el-form ref="menuForm" :model="menu" :rules="menuRules" size="small" label-width="150px"> <el-form-item v-if="menu.parentName !== undefined" label="Superior Directory" prop="parentName"> <el-input v-model="menu.parentName" :disabled='true' clearable :style="{width: '100%'}"></el-input> </el-form-item> <el-form-item label="menu type" prop="type"> <el-radio-group v-model="menu.type" size="mini" :disabled='typeDisabled'> <el-radio :label="0" :disabled="typeDisabled0">Directory</el-radio> <el-radio :label="1" :disabled="typeDisabled1">Menu</el-radio> <el-radio :label="2" :disabled="typeDisabled2">button</el-radio> </el-radio-group> </el-form-item> <el-form-item label="menu name" prop="name"> <el-input v-model="menu.name" clearable :style="{width: '100%'}"></el-input> </el-form-item> <el-form-item v-if="menu.type !== 2" label="icon" prop="icon"> <el-select v-model="menu.icon" placeholder="Please select" filterable clearable :style="{width: '100%'}"> <el-option v-for="(item, index) in iconOptions" :key="index" :value="item.class" :disabled="item.disabled"> <span style="float: left;"> <i :class="item. class"></i> </span> <span style="padding-left: 6px;">{<!-- -->{<!-- --> item.class }}</span> </el-option> </el-select> </el-form-item> <el-form-item label="sort" prop="sortValue"> <el-input-number v-model="menu.sortValue" placeholder="sort" :step='1' step-strictly :min='1'> </el-input-number> </el-form-item> <el-form-item v-if="menu.type === 2" label="permission character" prop="perms"> <span slot="label"> <el-tooltip content="Authority characters defined in the Controller layer, such as: @PreAuthorize(hasAuthority('bnt.sysMenu.add'))" placement="top"> <i></i> </el-tooltip> permission character </span> <el-input v-model="menu.perms" placeholder="Please enter permission characters" clearable :style="{width: '100%'}"></el-input> </el-form-item> <el-form-item v-if="menu.type === 1" label="component address" prop="component"> <span slot="label"> <el-tooltip content="component address, such as: views/main/menu/SysMenu" placement="top"> <i></i> </el-tooltip> component address </span> <el-input v-model="menu.component" placeholder="Please enter the component address" clearable :style="{width: '100%'}"></el-input> </el-form-item> <el-form-item v-if="menu.type === 1" label="routing address" prop="path"> <span slot="label"> <el-tooltip content="routing address, such as: sysMenu" placement="top"> <i></i> </el-tooltip> routing address </span> <el-input v-model="menu.path" placeholder="Please enter the routing address" clearable :style="{width: '100%'}"></el-input> </el-form-item> <el-form-item label="status" prop="status" required> <el-switch v-model="menu.status" :active-value='1' :inactive-value='0'></el-switch> </el-form-item> </el-form> <div slot="footer"> <el-button @click="close">Cancel</el-button> <el-button type="primary" @click="handelConfirm" :disabled="saveBtnDisabled">OK</el-button> </div> </el-dialog> </div> </template> <script> /* Introduce menu management api interface */ import menu from '../../../api/menu/menu' // menu form const menuFrom = {<!-- --> parentName: undefined, type: 0, name: undefined, icon: undefined, sortValue: undefined, perms: undefined, component: undefined, path: undefined, status: 1, }; export default {<!-- --> name: "SysMenu", data() {<!-- --> return {<!-- --> menuTreeList: [], /* popup area field */ dialogVisible: false, dialogTitle: '', // Controls whether the menu type radio button is available typeDisabled: false, typeDisabled0: false, typeDisabled1: false, typeDisabled2: false, // Control the popup window to determine whether the button is available saveBtnDisabled: false, menu: menuFrom, menuRules: {<!-- --> parentName: [{<!-- --> required: true, message: '', trigger: 'blur' }], type: [{<!-- --> required: true, message: 'The menu type cannot be empty', trigger: 'change' }], name: [{<!-- --> required: true, message: '', trigger: 'blur' }], icon: [{<!-- --> required: true, message: 'Please choose', trigger: 'change' }], sortValue: [{<!-- --> required: true, message: 'Sorting', trigger: 'blur' }], perms: [{<!-- --> required: true, message: 'Please enter the permission character', trigger: 'blur' }], component: [{<!-- --> required: true, message: 'Please enter the component address', trigger: 'blur' }], path: [{<!-- --> required: true, message: 'Please enter the routing address', trigger: 'blur' }], }, iconOptions: [ {<!-- --> class: "el-icon-s-tools", }, {<!-- --> class: "el-icon-s-custom", }, {<!-- --> class: "el-icon-setting", }, {<!-- --> class: "el-icon-user-solid", }, {<!-- --> class: "el-icon-s-help", }, {<!-- --> class: "el-icon-phone", }, {<!-- --> class: "el-icon-s-unfold", }, {<!-- --> class: "el-icon-s-operation", }, {<!-- --> class: "el-icon-more-outline", }, {<!-- --> class: "el-icon-s-check", }, {<!-- --> class: "el-icon-tickets", }, {<!-- --> class: "el-icon-s-goods", }, {<!-- --> class: "el-icon-document-remove", }, {<!-- --> class: "el-icon-warning", }, {<!-- --> class: "el-icon-warning-outline", }, {<!-- --> class: "el-icon-question", }, {<!-- --> class: "el-icon-info", }] } }, methods: {<!-- --> /* get menu tree */ async getMenuTree() {<!-- --> const {<!-- --> data } = await menu.getMenuTree(); this.menuTreeList = data.data.result }, /* New menu */ async addMenuData(menuVo) {<!-- --> const {<!-- --> data } = await menu.addMenuData(menuVo); this.$message({<!-- --> message: data.message || 'operation succeeded', type: data.code === 200?'success':'error' }); // refresh page this. getMenuTree() }, /* update menu */ async updateMenuData(menuVo) {<!-- --> const {<!-- --> data } = await menu.updateMenuData(menuVo); this.$message({<!-- --> message: data.message || 'operation succeeded', type: data.code === 200?'success':'error' }); // refresh page this. getMenuTree() }, /* delete menu */ deleteMenuData(id) {<!-- --> this.$confirm('This operation will permanently delete the file, do you want to continue?', 'Prompt', {<!-- --> confirmButtonText: 'OK', cancelButtonText: 'Cancel', type: 'warning' }).then(() => {<!-- --> return menu.deleteMenuData(id) }).then((res) => {<!-- --> // refresh page this. getMenuTree() this.$message({<!-- --> message: res.data.message || 'Operation succeeded', type: res.data.code === 200?'success':'error' }); }).catch(() => {<!-- --> this.$message({<!-- --> type: 'info', message: 'Delete canceled' }); }); }, /* Popup area method */ // add directory/menu addFolder() {<!-- --> // Clear the menu form content this.menu = Object.assign({<!-- -->},menuFrom); this.dialogVisible = true; this.dialogTitle = 'Add directory/menu node' // disable button radio button this.typeDisabled = false; this.typeDisabled2 = true; // The default menu type radio button selects the directory this.menu.type = Number(0) }, // Add a lower-level node method addLastNode(row) {<!-- --> // Clear the menu form content this.menu = Object.assign({<!-- -->},menuFrom); this.dialogVisible = true; switch (row.type) {<!-- --> case 0: // On behalf of the directory, you can add menu nodes or directory nodes under the directory this.dialogTitle = 'Add directory/menu node'; // Assign values to the parent directory this.menu.parentName = row.name; this.menu.parentId = row.id; // disable button radio button this. typeDisabled = false; this.typeDisabled2 = true; // default menu type single button check menu this.menu.type = Number(1); break; case 1: // Represents the menu, only button nodes can be added under the menu this.dialogTitle = 'Add button node'; // Assign values to the parent directory this.menu.parentId = row.id; this.menu.parentName = row.name; // add button by default this.menu.type = Number(2); // disable menu type radio button this.typeDisabled = true; break; } }, // modify node method alertNode(row) {<!-- --> // Assign the current row data to the menu form this.menu = Object.assign({<!-- -->},row); this.dialogVisible = true; switch (row.type) {<!-- --> case 0: // Represents a directory, there may be directories and menus under the directory this.dialogTitle = 'Edit directory node'; // disable button radio button this.typeDisabled = true; break; case 1: // On behalf of the menu, there are only buttons under the menu this.dialogTitle = 'Edit menu node'; // disable menu type radio button this.typeDisabled = true; break; case 2: // On behalf of the menu, there are only buttons under the menu this.dialogTitle = 'Edit button node'; // disable menu type radio button this.typeDisabled = true; break; } }, onOpen() {<!-- -->}, onClose() {<!-- --> this.$refs['menuForm'].resetFields() }, close() {<!-- --> // Restore form submit button usage this. saveBtnDisabled = false this.dialogVisible = false }, // Confirm button in the popup page handelConfirm() {<!-- --> this.$refs['menuForm'].validate(valid => {<!-- --> if (!valid) return; // Call backend new menu and modify menu methods // Prevent form from being submitted repeatedly this. saveBtnDisabled = true if (!this.menu.id) {<!-- --> // Indicates the new menu this.addMenuData(this.menu) } else {<!-- --> // Represents the update menu this. updateMenuData(this. menu) } this. close() }) } }, // Get data when the page loads created () {<!-- --> // Get menu tree list this. getMenuTree() } } </script> <style scoped> /* divider style */ .el-divider --horizontal {<!-- --> display: block; height: 1px; width: 100%; margin: 10px 0; } </style>
3. Configure the routing of your menu management page
Add menu management page routing information in the index.js main page framework routing under router
{<!-- --> /* Menu management route */ path: '/sysMenu', name: 'SysMenu', component: () => import('../views/menu/SysMenu') }
4. Icon content
iconOptions: [ {<!-- --> class: "el-icon-s-tools", }, {<!-- --> class: "el-icon-s-custom", }, {<!-- --> class: "el-icon-setting", }, {<!-- --> class: "el-icon-user-solid", }, {<!-- --> class: "el-icon-s-help", }, {<!-- --> class: "el-icon-phone", }, {<!-- --> class: "el-icon-s-unfold", }, {<!-- --> class: "el-icon-s-operation", }, {<!-- --> class: "el-icon-more-outline", }, {<!-- --> class: "el-icon-s-check", }, {<!-- --> class: "el-icon-tickets", }, {<!-- --> class: "el-icon-s-goods", }, {<!-- --> class: "el-icon-document-remove", }, {<!-- --> class: "el-icon-warning", }, {<!-- --> class: "el-icon-warning-outline", }, {<!-- --> class: "el-icon-question", }, {<!-- --> class: "el-icon-info", }]
Icon drop-down box
<el-select v-model="menu.icon" placeholder="Please select" filterable clearable :style="{width: '100%'}"> <el-option v-for="(item, index) in iconOptions" :key="index" :label="item.class" :value="item.class" :disabled="item.disabled"> <span style="float: left;"> <i :class="item. class"></i> </span> <span style="padding-left: 6px;">{<!-- -->{<!-- --> item.class }}</span> </el-option> </el-select>
5. Menu management api
/* import axios instance */ import request from '../../utils/request' /* API request function related to menu management */ const api_path = '/admin/system/menu' export default {<!-- --> /* Get the background menu tree list */ getMenuTree() {<!-- --> return request({<!-- --> method: 'get', url: `${<!-- -->api_path}/getMenuTree` }) }, /** * Add menu data * @param menuVo menu form content */ addMenuData(menuVo) {<!-- --> return request({<!-- --> method: 'post', url: `${<!-- -->api_path}/addMenuData`, data: menuVo }) }, /** * Update menu data * @param menuVo menu form content */ updateMenuData(menuVo) {<!-- --> return request({<!-- --> method: 'put', url: `${<!-- -->api_path}/updateMenuData`, data: menuVo }) }, /** * Delete menu data * @param id menu id */ deleteMenuData(id) {<!-- --> return request({<!-- --> method: 'delete', url: `${<!-- -->api_path}/remove/${<!-- -->id}`, }) } }
final effect