VUE:SpringBoot + Vue 菜单管理

简单的记录下菜单前后端实现,比较基础,仅供参考
vue请求需要根据情况自行封装,代码中的请求需要自行实现

效果

在这里插入图片描述

数据库结构

CREATE TABLE `menus` (
	`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键,菜单id',
	`name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单名称' COLLATE 'utf8_general_ci',
	`icon` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单图标' COLLATE 'utf8_general_ci',
	`route` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单路由' COLLATE 'utf8_general_ci',
	`superior_menu` INT(11) NOT NULL DEFAULT '0' COMMENT '上级菜单',
	`sort_number` INT(11) NOT NULL DEFAULT '0' COMMENT '排序',
	`show_level` INT(11) NOT NULL DEFAULT '0' COMMENT '权限级别',
	`create_time` TIMESTAMP NULL DEFAULT '1970-01-01 08:00:01' COMMENT '创建时间',
	`update_time` TIMESTAMP NULL DEFAULT '1970-01-01 08:00:01' ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
	`status` INT(11) NOT NULL DEFAULT '0' COMMENT '是否启用,0:启用,1禁用',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `u_key_s_n` (`superior_menu`, `name`) USING BTREE,
	UNIQUE INDEX `u_key_s_s` (`superior_menu`, `sort_number`) USING BTREE
)
COMMENT='侧边栏菜单'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

Java对象

package com.xiaobai.test;

import java.util.Date;
import java.util.List;

public class Menu {
    private Integer id;

    private String name;

    private String icon;

    private String route;

    private Integer superior_menu;

    private Integer sort_number;

    private Integer show_level;

    private Date create_time;

    private Date update_time;

    private Integer status;

    private List<Menu> subMenus;

    public Menu() {

    }

    public Menu(Integer id, String name, String icon, String route, Integer superior_menu, Integer sort_number, Integer show_level, Integer status) {
        this.id = id;
        this.name = name;
        this.icon = icon;
        this.route = route;
        this.superior_menu = superior_menu;
        this.sort_number = sort_number;
        this.show_level = show_level;
        this.status = status;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public String getRoute() {
        return route;
    }

    public void setRoute(String route) {
        this.route = route;
    }

    public Integer getSuperior_menu() {
        return superior_menu;
    }

    public void setSuperior_menu(Integer superior_menu) {
        this.superior_menu = superior_menu;
    }

    public Integer getSort_number() {
        return sort_number;
    }

    public void setSort_number(Integer sort_number) {
        this.sort_number = sort_number;
    }

    public Integer getShow_level() {
        return show_level;
    }

    public void setShow_level(Integer show_level) {
        this.show_level = show_level;
    }

    public Date getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Date create_time) {
        this.create_time = create_time;
    }

    public Date getUpdate_time() {
        return update_time;
    }

    public void setUpdate_time(Date update_time) {
        this.update_time = update_time;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public List<Menu> getSubMenus() {
        return subMenus;
    }

    public void setSubMenus(List<Menu> subMenus) {
        this.subMenus = subMenus;
    }
}

Controller

@Controller
@RequestMapping("/menu")
public class MenuController {

    @Autowired
    MenuService menuService;

    @RequestMapping("/queryMenus")
    @ResponseBody
    public ResponseEntity queryMenus(@RequestParam(value = "id", required = false) Integer id,
                                     @RequestParam(value = "level", required = false, defaultValue = "0") Integer level,
                                     @RequestParam(value = "status", required = false) Integer status,
                                     @RequestParam(value = "querySubMenus", required = false, defaultValue = "true") Boolean querySubMenus) {
        // 如果为系统管理员,不受菜单禁用限制,枚举类型,请根据情况自行定义,如无特殊要求注释掉该条件判断
        if (level == LevelType.TYPE.SYSTEM.getCode()) {
            status = null;
        }

        List<Menu> menus = menuService.queryMenus(null, id, level, status);
        menus.sort(Comparator.comparingInt(Menu::getSort_number));
        // 判断是否查询子菜单
        if (querySubMenus != null && querySubMenus == true) for (Menu menu : menus) {
            List<Menu> subMenus = querySubMenus(menu, level, status);
            menu.setSubMenus(subMenus);
        }
        Map<String, Object> response = new HashMap<>();
        response.put("msg", "查询成功");
        response.put("code", 200);
        response.put("data", menus);
        return new ResponseEntity(response, HttpStatus.OK);
    }


    private List<Menu> querySubMenus(Menu menu, Integer level, Integer status) {
        List<Menu> subMenus = menuService.queryMenus(menu, null, level, status);
        if (subMenus.size() > 0) {
            subMenus.sort(Comparator.comparingInt(Menu::getSort_number));
            menu.setSubMenus(subMenus);
            for (Menu subMenu : subMenus) {
                List<Menu> menus = querySubMenus(subMenu, level, status);
                subMenu.setSubMenus(menus);
            }
        }
        return subMenus;
    }


    @RequestMapping("/queryMenuById")
    @ResponseBody
    public ResponseEntity queryMenuById(@RequestParam(value = "id", required = false) Integer id,
                                        @RequestParam(value = "level", required = false, defaultValue = "0") Integer level) {

        Menu menu = menuService.queryMenuById(id);
        Map<String, Object> response = new HashMap<>();
        response.put("msg", "查询成功");
        response.put("code", 200);
        response.put("data", menu);
        return new ResponseEntity(response, HttpStatus.OK);
    }

    @RequestMapping("/addMenu")
    @ResponseBody
    public ResponseEntity addMenu(@RequestParam(value = "name", required = false) String name,
                                  @RequestParam(value = "icon", required = false) String icon,
                                  @RequestParam(value = "route", required = false) String route,
                                  @RequestParam(value = "superior_menu", required = false) Integer superior_menu,
                                  @RequestParam(value = "sort_number", required = false) Integer sort_number,
                                  @RequestParam(value = "level", required = false) Integer level,
                                  @RequestParam(value = "status", required = false) Integer status) {
        // 修改当前菜单状态
        Menu menu = new Menu(null, name, icon, route, superior_menu, sort_number, level, status);
        menuService.insertMenu(menu);

        Map<String, Object> response = new HashMap<>();
        response.put("msg", "添加成功");
        response.put("code", 200);
        return new ResponseEntity(response, HttpStatus.OK);
    }
}

mapper

public interface MenuMapper {
    List<Menu> queryMenus(@Param("menu") Menu menu, @Param("id") Integer id, @Param("level") Integer level, @Param("status") Integer status);

    Integer insertMenu(Menu menu);

    Integer updateMenu(Menu menu);

    Menu queryMenuById(@Param("id") Integer id);
}

service

public interface MenuService {
    List<Menu> queryMenus(Menu menu, Integer id, Integer level, Integer status);

    Integer updateMenu(Menu menu);

    Integer insertMenu(Menu menu);

    Menu queryMenuById(Integer id);
}

serviceImpl

@Service("MenuService")
public class MenuServiceImpl implements MenuService {
    @Resource
    private MenuMapper menuMapper;

    @Override
    public List<Menu> queryMenus(Menu menu, Integer id, Integer level, Integer status) {
        return menuMapper.queryMenus(menu, id, level, status);
    }

    @Override
    public Integer insertMenu(Menu menu) {
        return menuMapper.insertMenu(menu);
    }

    @Override
    public Integer updateMenu(Menu menu) {
        return menuMapper.updateMenu(menu);
    }

    @Override
    public Menu queryMenuById(Integer id) {
        return menuMapper.queryMenuById(id);
    }
}

mybatis.xml

自行修改对应的namespaceresultType等参数

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxx.MenuMapper">
    <insert id="insertMenu" keyColumn="id" keyProperty="id"
            parameterType="xxx.Menu"
            useGeneratedKeys="true">
        insert into menus(`name`, `icon`, `route`, `superior_menu`, `sort_number`, `show_level`, `create_time`, `update_time`, `status`) values
            (#{name}, #{icon}, #{route}, #{superior_menu}, #{sort_number}, #{show_level}, now(), now(), #{status})
    </insert>

    <select id="queryMenus" resultType="xxx.Menu">
        select `id`, `name`, `icon`, `route`, `superior_menu`,`sort_number`, `show_level`, `status`, `create_time`, `update_time`
        from `menus`
        <where>
            show_level <![CDATA[ <= ]]> #{level}
            <if test="menu!=null and menu.id!=null">
                and `superior_menu`= #{menu.id}
            </if>
            <if test="id != null">
                and `id`= #{id}
            </if>
            <if test="menu==null or menu.superior_menu==null">
                and `superior_menu`= 0
            </if>
            <if test="status!=null">
                and `status`= #{status}
            </if>
        </where>
    </select>

    <select id="queryMenuById" resultType="xxx.Menu">
        select * from menus where id = #{id}
    </select>

    <update id="updateMenu">
        update menus
        <set>
            <if test="name != null">
                `name`=#{name,jdbcType=VARCHAR},
            </if>
            <if test="icon != null">
                icon=#{icon,jdbcType=VARCHAR},
            </if>
            <if test="route != null">
                route=#{route,jdbcType=VARCHAR},
            </if>
            <if test="superior_menu != null">
                superior_menu=#{superior_menu,jdbcType=INTEGER},
            </if>
            <if test="sort_number != null">
                sort_number=#{sort_number,jdbcType=INTEGER},
            </if>
            <if test="show_level != null">
                show_level=#{show_level,jdbcType=INTEGER},
            </if>
            <if test="status != null">
                status=#{status,jdbcType=INTEGER},
            </if>
        </set>
        where id = #{id,jdbcType=INTEGER}
    </update>

</mapper>

VUE前端

<template>
	<div>
		<div class="div-padding">
			<el-row :gutter="10" class="mgt20">
				<el-col>
					<i class="el-icon-menu" style="line-height: 30px; width: 30px; color:blue; font-size: 20px;"></i>
					<span class="span-page-title">菜单管理</span>
				</el-col>
			</el-row>
			<el-row :gutter="10">
				<el-col :span="2">
					<el-button style="width: 90px; line-height: 13px;" type="primary"
						@click="onOpenAddMenuDialogButtonClick()">新增</el-button>
				</el-col>
			</el-row>

			<el-row :gutter="10" class="mgt20">
				<el-col>
					<el-table border :data="menuList" class="table" border row-key="id"
						:tree-props="{children: 'subMenus'}" header-cell-class-name="table-header">
						<el-table-column prop="id" :show-overflow-tooltip="true" label="菜单编号"
							width="100px"></el-table-column>
						<el-table-column prop="name" :show-overflow-tooltip="true" label="菜单名称"></el-table-column>
						<el-table-column prop="icon" :show-overflow-tooltip="true" align="center" label="菜单图标">
							<template slot-scope="scope">
								<i :class="scope.row.icon"></i>
							</template>
						</el-table-column>
						<el-table-column prop="route" :show-overflow-tooltip="true" label="路由"
							width="130px"></el-table-column>
						<el-table-column prop="superior_menu" :show-overflow-tooltip="true" label="父菜单编号" width="90px">
						</el-table-column>
						<el-table-column prop="sort_number" :show-overflow-tooltip="true" label="菜单排序">
						</el-table-column>
						<el-table-column prop="show_level" :show-overflow-tooltip="true" label="显示级别">
						</el-table-column>
						<el-table-column prop="update_time" :show-overflow-tooltip="true" label="更新时间" width="160px">
							<template slot-scope="scope">
								{{$moment(scope.row.update_time).format("YYYY-MM-DD HH:mm:ss")}}
							</template>
						</el-table-column>
						<el-table-column prop="status" :show-overflow-tooltip="true" label="状态">
							<template slot-scope="scope">
								<el-tag type="success" v-if="scope.row.status == 0">已启用</el-tag>
								<el-tag type="danger" v-if="scope.row.status == 1">已禁用</el-tag>
							</template>
						</el-table-column>
						<el-table-column label="操作" width="200px">
							<template slot-scope="scope">
								<el-button v-if="scope.row.status==1" icon="el-icon-check" type="primary" plain
									size="mini" @click="enabledMenu(scope)">
									启用
								</el-button>
								<el-button v-if="scope.row.status==0" icon="el-icon-delete" type="danger" plain
									size="mini" @click="disabledMenu(scope)">
									禁用
								</el-button>
								<el-button icon="el-icon-edit" type="success" plain size="mini"
									@click="onOpenModifyMenuDialogButtonClick(scope)">
									编辑
								</el-button>
							</template>
						</el-table-column>
					</el-table>
				</el-col>
			</el-row>
		</div>

		<!-- ========================================================== 新增、修改对话框  ========================================================== -->
		<el-dialog width="30%" :title="menuDialog.title" :close-on-click-modal="false"
			@close="onCloseMenuDialogButtonClick()" :close-on-press-escape="false" :visible.sync="menuDialog.visible">
			<el-form :rules="rules" ref="ruleForm" :model="menuDialog.ruleForm" label-width="100px"
				class="demo-ruleForm">
				<el-row>
					<el-col :span="24">
						<el-form-item label="菜单名称" prop="name">
							<el-input style="width: 80%;" v-model="menuDialog.ruleForm.name"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="菜单图标" prop="icon">
							<el-input style="width: 80%;" v-model="menuDialog.ruleForm.icon"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="菜单路由" prop="route">
							<el-input style="width: 80%;" v-model="menuDialog.ruleForm.route"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="上级菜单" prop="superior_menu">
							<el-input style="width: 80%;" v-model="menuDialog.ruleForm.superior_menu"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="菜单排序" prop="sort_number">
							<el-input style="width: 80%;" v-model="menuDialog.ruleForm.sort_number"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="菜单权限" prop="show_level">
							<el-select style="width: 80%;" v-model="menuDialog.ruleForm.show_level" placeholder="请选择">
								<el-option v-for="data in authorityOption" :key="data.key" :label="data.label"
									:value="data.value"></el-option>
							</el-select>
						</el-form-item>
					</el-col>
					<el-col :span="24">
						<el-form-item label="是否启用" prop="status">
							<el-radio-group v-model="menuDialog.ruleForm.status">
								<el-radio :label="0">启用</el-radio>
								<el-radio :label="1">禁用</el-radio>
							</el-radio-group>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row>
					<el-col :span="10">
						<el-form-item>
							<el-button v-if="menuDialog.title == '菜单修改'" type="primary"
								@click="onModifyMenuButtonClick()">确定</el-button>
							<el-button v-if="menuDialog.title == '菜单新增'" type="primary"
								@click="onSubmitAddMenuButtonClick()">新增</el-button>
						</el-form-item>
					</el-col>
				</el-row>
			</el-form>
		</el-dialog>
	</div>
</template>

<script>
	import {
		addMenu,
		getMenus,
		updateMenus,
		enabledMenus,
		disableMenus
	} from '../../assets/js/api.js'

	export default {
		data() {
			return {
				id: this.$route.query.id, // 传入的路由id
				user: JSON.parse(sessionStorage.getItem("user")), // 用户信息,请自定义
				authorityOption: this.$globle.authorityOption, // 权限列表,如[{key:"0",label:"游客",value:0},{key:"1",label:"普通用户",value:1},{key:"2",label:"系统管理员",value:2},{key:"3",label:"超级管理员",value:3}]

				menuList: [],

				// 菜单弹窗
				menuDialog: {
					visible: false,
					title: "",
					ruleForm: {
						id: "",
						name: "",
						icon: "1",
						route: "",
						superior_menu: "",
						sort_number: "1",
						show_level: "",
						status: 0
					}
				},
				rules: {
					name: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					icon: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					route: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					superior_menu: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					sort_number: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					show_level: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}],
					status: [{
						required: true,
						message: '请输入完整信息',
						trigger: 'blur'
					}]
				}
			};
		},
		created() {
			this.getMenuList();
		},

		methods: {
			getMenuList() {
				let params = {
					level: this.user.level,
					querySubMenus: true
				}
				getMenus(params).then((res) => {
					this.menuList = res.data
				});
			},

			//启用菜单
			enabledMenu(scope) {
				this.$confirm('确定启用该菜单吗, 是否继续?', '提示', {
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					type: 'warning'
				}).then(() => {
					let param = {
						id: scope.row.id,
						status: 0,
						syncSubMenus: true
					}
					enabledMenus(param).then((res) => {
						this.getMenuList();
					})
				}).catch(() => {

				})
			},

			//禁用菜单
			disabledMenu(scope) {
				this.$confirm('确定禁用该菜单吗, 是否继续?', '提示', {
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					type: 'warning'
				}).then(() => {
					let param = {
						id: scope.row.id,
						status: 1,
						syncSubMenus: true
					}
					enabledMenus(param).then((res) => {
						this.getMenuList();
					})
				}).catch(() => {

				})
			},

			// 修改
			onOpenModifyMenuDialogButtonClick(scope) {
				this.menuDialog.title = "菜单修改";
				this.menuDialog.visible = true;
				this.menuDialog.ruleForm.id = scope.row.id;
				this.menuDialog.ruleForm.name = scope.row.name;
				this.menuDialog.ruleForm.icon = scope.row.icon;
				this.menuDialog.ruleForm.route = scope.row.route;
				this.menuDialog.ruleForm.superior_menu = scope.row.superior_menu;
				this.menuDialog.ruleForm.sort_number = scope.row.sort_number;
				this.menuDialog.ruleForm.show_level = scope.row.show_level;
				this.menuDialog.ruleForm.status = scope.row.status;
			},

			onModifyMenuButtonClick() {
				this.$refs["ruleForm"].validate((valid) => {
					if (valid) {
						this.$confirm('确定修改菜单吗, 是否继续?', '提示', {
							confirmButtonText: '确定',
							cancelButtonText: '取消',
							type: 'warning'
						}).then(() => {
							let param = {
								id: this.menuDialog.ruleForm.id,
								name: this.menuDialog.ruleForm.name,
								icon: this.menuDialog.ruleForm.icon,
								route: this.menuDialog.ruleForm.route,
								superior_menu: this.menuDialog.ruleForm.superior_menu,
								sort_number: this.menuDialog.ruleForm.sort_number,
								level: this.menuDialog.ruleForm.show_level,
								status: this.menuDialog.ruleForm.status
							}
							updateMenus(param).then((res) => {
								if (res.code == "200") {
									this.$message({
										message: res.msg,
										type: "success",
									});
									this.getMenuList();
									this.closeMenuDialog();
								} else {
									this.$message({
										message: res.msg,
										type: "warning"
									});
								}
							})
						}).catch(() => {
							// 添加错误捕获
						})
					} else {
						return false;
					}
				});
			},

			// 新增
			onOpenAddMenuDialogButtonClick() {
				this.menuDialog.title = "菜单新增";
				this.menuDialog.visible = true;
				this.menuDialog.ruleForm.id = "";
				this.menuDialog.ruleForm.name = "";
				this.menuDialog.ruleForm.icon = "";
				this.menuDialog.ruleForm.route = "";
				this.menuDialog.ruleForm.superior_menu = "";
				this.menuDialog.ruleForm.sort_number = "";
				this.menuDialog.ruleForm.show_level = "";
				this.menuDialog.ruleForm.status = 0;
			},

			onSubmitAddMenuButtonClick() {
				this.$refs["ruleForm"].validate((valid) => {
					if (valid) {
						this.$confirm('确定新增菜单吗, 是否继续?', '提示', {
							confirmButtonText: '确定',
							cancelButtonText: '取消',
							type: 'warning'
						}).then(() => {
							let param = {
								name: this.menuDialog.ruleForm.name,
								icon: this.menuDialog.ruleForm.icon,
								route: this.menuDialog.ruleForm.route,
								superior_menu: this.menuDialog.ruleForm.superior_menu,
								sort_number: this.menuDialog.ruleForm.sort_number,
								level: this.menuDialog.ruleForm.show_level,
								status: this.menuDialog.ruleForm.status
							}
							addMenu(param).then((res) => {
								if (res.code == "200") {
									this.$message({
										message: res.msg,
										type: "success",
									});
									this.getMenuList();
									this.closeMenuDialog();
								} else {
									this.$message({
										message: res.msg,
										type: "warning"
									});
								}
							})
						}).catch(() => {
							// 添加错误捕获
						})
					} else {
						return false;
					}
				});
			},

			onCloseMenuDialogButtonClick() {
				this.closeMenuDialog();
			},


			closeMenuDialog() {
				this.$refs['ruleForm'].resetFields();
				this.menuDialog.title = "";
				this.menuDialog.visible = false;
				this.menuDialog.ruleForm.id = "";
				this.menuDialog.ruleForm.name = "";
				this.menuDialog.ruleForm.icon = "";
				this.menuDialog.ruleForm.route = "";
				this.menuDialog.ruleForm.superior_menu = "";
				this.menuDialog.ruleForm.sort_number = "";
				this.menuDialog.ruleForm.show_level = "";
				this.menuDialog.ruleForm.status = 0;
			},


			handleSizeChange(val) {

			},

			handlePageChange(val) {

			}
		},
	}
</script>

<style>
</style>
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值