第一章:后台管理系统 功能 简单梳理
第二章 数据库表的设计
第三章:对数据库权限相关的表进行重新设计
第四章:用idea 创建后台系统工程,并完成项目配置
第五章:实现后台登录,完成前后验证登录,并深入讲解captcha.js的使用方法和入‘坑‘指南
第六章:初始化后台首页左侧导航菜单nav,增加权限控制
需求分析:
用户登录后根据用户的主键id再利用mysql递归查询(根据用户挂接的角色去查询角色挂接的根菜单id,再根据根菜单id递归查询子菜单)
由于MySQL没有自己的递归函数,因此需要自己编写递归函数:
可以看我的这篇文章(有详细讲解):
mysql 实现树形递归查询 适合分级菜单、层级权限等查询
分级菜单的数据库表设计:
前端源代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 后台大布局 - Layui</title>
<link rel="stylesheet" href="/future/util/layui/css/layui.css">
<link rel="stylesheet" href="/future/css/index.css">
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin" id="page" v-cloak>
<div class="layui-header">
<div class="layui-logo">未来商城</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item"><a href="">控制台</a></li>
<li class="layui-nav-item"><a href="">商品管理</a></li>
<li class="layui-nav-item"><a href="">用户</a></li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd><a href="">邮件管理</a></dd>
<dd><a href="">消息管理</a></dd>
<dd><a href="">授权管理</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="http://t.cn/RCzsdCq" class="layui-nav-img">
<text id="managername"></text>
</a>
<dl class="layui-nav-child">
<dd><a href="">基本资料</a></dd>
<dd><a href="">安全设置</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="">退了</a></li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul id="leftNav" class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item" ref="model" v-for="(item,i) in menuList">
<a :class="item.htmlpath?'layui-nav-child':'layui-nav-title'" @click="setAframe(item.htmlpath,true,i)" href="javascript:;">{{item.menuname}}</a>
<dl class="layui-nav-child" v-for="(menu,j) in item.mm">
<dd><a @click="setAframe(menu.htmlpath,false,j)" href="javascript:;">{{menu.menuname}}</a></dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<iframe style="padding: 15px; width: 100%;height: 100%;" scrolling="false" id="framePage" :src="htmlpath"></iframe>
</div>
<div class="layui-footer">
<!-- 底部固定区域 -->
</div>
</div>
</body>
</html>
<script src="/future/util/layui/layui.js"></script>
<script src="/future/js/jquery.js"></script>
<script src="/future/vue/vue.min.js"></script>
<script src="/future/vue/vue.resource.js"></script>
<script src="/future/js/main.js"></script>
function getMid() {
return JSON.parse(sessionStorage.getItem("manageInfo")).mid;
}
layui.use(['layer', 'form', 'element'], function () {
var layer = layui.layer;
var element = layui.element;
var form = layui.form;
// (function ($) {
// funObj = {
// timeUserFun: 'timeUserFun',
// }
// $[funObj.timeUserFun] = function (time) {
// var time = time || 2; // 默认参数
// var userTime = time * 60;
// var objTime = {
// init: 0,
// time: function () {
// objTime.init += 1;
// if (objTime.init == userTime) {
// // 用户到达未操作事件 做一些处理
// update();
// }
// },
// eventFun: function () {
// clearInterval(testUser);
// objTime.init = 0;
// testUser = setInterval(objTime.time, 1000);
// }
// }
//
// var testUser = setInterval(objTime.time, 1000);
//
// var body = document.querySelector('html');
// body.addEventListener("click", objTime.eventFun);
// body.addEventListener("keydown", objTime.eventFun);
// body.addEventListener("mousemove", objTime.eventFun);
// body.addEventListener("mousewheel", objTime.eventFun);
// }
// })(window)
function update() {
let mid = getMid();
$.ajax({
url: "/future/manager/saveLoginStatus/" + mid,
type: "POST",
contentType: "application/json;charset=utf-8",
dataType: "json",
async: false,
success(res) {
if (res.code == "200") {
sessionStorage.setItem("manageInfo", "null");
layer.msg("由于您长时间未操作页面,请重新登录", {icon: 2, time: 2000});
setTimeout(function () {
window.location.reload();
}, 2000);
}
}
})
}
// 直接调用 参数代表分钟数,可以有一位小数,不传参默认2分钟
// timeUserFun(0.2);
let vm = new Vue({
el: "#page",
data: {
manageInfo: {},
menuList: [],
htmlpath: "welcome.html",
},
ready() {
},
mounted() {
this.manageInfo = JSON.parse(sessionStorage.getItem("manageInfo"));
if (undefined == this.manageInfo || null == this.manageInfo) {
layer.msg("登录状态已过期,请重新登录", {icon: 2, time: 2000});
window.location.href = "login.html";
} else {
$("#managername").html(this.manageInfo.mno);
this.manageInfo.mrole === 0 ? layer.msg("欢迎管理员" + this.manageInfo.mno + "登录", {
icon: 1,
time: 2000
}) : layer.msg("欢迎超级管理员:" + this.manageInfo.mno + "登录", {icon: 1, time: 2000});
}
this.getMenuList(this.manageInfo.mid);
},
destroy() {
},
methods: {
getMenuList(managerid) {
var that = this;
$.ajax({
url: "/future/manager/getMenuTree/" + managerid,
dataType: "json",
async: false,
success(res) {
that.menuList = res.objList;
}
})
},
}
})
});
但是渲染出来会发现导航菜单无法展开,经过分析发现,控制展示和隐藏下级菜单的主要是 样式类
名为layui-nav-itemed,因此通过判断这个类名是否存在来实现菜单的显示与隐藏:
setAframe(path, isTitle, i) {
if (isTitle) {
let navTitle = this.$refs.model[i];
if ("" != path && null != path && undefined != path) {
this.htmlpath = path;
}
if (navTitle.className.indexOf("layui-nav-itemed") > -1) {
$(navTitle).removeClass("layui-nav-itemed");
} else {
$(navTitle).addClass("layui-nav-itemed");
}
} else {
this.htmlpath = path;
}
}
这里再说一下vue的 v-cloak,主要是为了解决在页面加载出来前,出现小胡子语法的闪现
将v-cloak放在body内最外层的标签上,并编写css:
[v-cloak]{
display:none;
}
这条css应该写在link引用的样式表文件中。
实现效果:
20220109_220541