摘要:权限模块确实有点难,跟老师敲了一遍,虽然磕磕绊绊,不过还是做出来了,一些自定义的函数,如果没有老师的想法,也许自己根本不会这么去做,这也许就是经验吧,下面开始捋一下.一.菜单列表页面 菜单列表页面,依旧是查询表,然后模板赋值,不过需要注意的是首先查询的是第一层级的菜单,也就是pid为0的菜单,所有当获取pid时,做一个强制类型转换,将null转换为0来
权限模块确实有点难,跟老师敲了一遍,虽然磕磕绊绊,不过还是做出来了,一些自定义的函数,如果没有老师的想法,也许自己根本不会这么去做,这也许就是经验吧,下面开始捋一下.
一.菜单列表页面
菜单列表页面,依旧是查询表,然后模板赋值,不过需要注意的是首先查询的是第一层级的菜单,也就是pid为0的菜单,所有当获取pid时,做一个强制类型转换,将null转换为0来进行查询,
进到子菜单,也就是当前的id作为子元素的父级id的元素输出 即?pid=mid
返回上一级,即是返回当前元素的pid作为mid的元素的pid那一层(这块绕了好久才绕明白了)
当pid>0时 也就是有父级是显示返回上一级的按钮
namespace app\admins\controller;
use think\Facade\SysDb;
class Menu extends Base
{
public function index()
{
$pid = (int)input('get.pid');
//加载菜单列表
$data = SysDb::table('admin_menu')->order('ord asc')->where(['pid'=>$pid])->lists();
$this->view->assign('lists',$data);
//获取上一级id
$parent = SysDb::table('admin_menu')->where(['mid'=>$pid])->item();
$backMid = $parent['pid'];
$this->view->assign('pid',$pid);
$this->view->assign('backMid',$backMid);
return $this->view->fetch();
}

二.添加/更新菜单
获取当前的mid,为更新菜单准备,获取pid,如果有则显示上一级表单且不可编辑,没有的话则不显示,为一级菜单,更新的话需要获取mid,然后根据mid来查询数据,将数据渲染给模板,进行赋值
当通过表单传过来的数据有pid>0且控制器/方法为空时,提示错误,根据是否有提交的mid来判断为更新还是添加,有mid为更新.
public function add()
{
//获取当前id
$mid = (int)input('get.mid');
$menu = SysDb::table('admin_menu')->where(['mid'=>$mid])->item();
//获取父级id
$pid = (int)input('get.pid');
//根据父级id查询父级的mid的名称
$parentMenu = SysDb::table('admin_menu')->where(['mid'=>$pid])->item();
//赋值给模板
$this->view->assign('parentMenu',$parentMenu);
$this->view->assign('menu',$menu);
return $this->view->fetch();
}
//保存菜单方法
public function save()
{
//获取提交过来的数据
$data['mid'] = trim(input('post.mid'));
$data['title'] = trim(input('post.title'));
$data['controller'] = trim(input('post.controller'));
$data['method'] = trim(input('post.method'));
$data['ord'] = (int)input('post.ord');
$data['ishidden'] = (int)input('post.ishidden');
$data['status'] = (int)input('post.status');
$data['pid'] = (int)input('post.pid');
if($data['title'] == ''){
return ['res'=>1,'msg'=>'菜单名称不能为空'];
}
if($data['controller'] == ''&& $data['pid']>0 ){
return ['res'=>2,'msg'=>'控制器名称不能为空'];
}
if($data['method'] == '' && $data['pid']>0){
return ['res'=>3,'msg'=>'方法名称不能为空'];
}
//判断为更新还是新增
if($data['mid']){
$res = SysDb::table('admin_menu')->where(['mid'=>$data['mid']])->update($data);
}else{
$res = SysDb::table('admin_menu')->insert($data);
}
if($res){
return ['res'=>0,'msg'=>'保存成功'];
}else{
return ['res'=>4,'msg'=>'保存失败'];
}
}
![]()

三.删除菜单
删除菜单就比较简单了,通过mid来删除,有一点注意的,如果删除的mid查询有以mid作为pid的数据,就提示一下要删除子菜单之后再删除父元素
public function delete()
{
$mid = (int)input('post.mid');
$child = SysDb::table('admin_menu')->where(['pid'=>$mid])->item();
if($child){
return ['res'=>2,'msg'=>'有子菜单,请先删除子菜单!'];
}
$res = SysDb::table('admin_menu')->where(['mid'=>$mid])->delete();
if($res){
return ['res'=>0,'msg'=>'删除成功'];
}
return ['res'=>1,'msg'=>'删除失败'];
}


四.权限设置模块
1.添加权限
需要将菜单表中所有菜单遍历出来,然后将它进行分组,以父级--子级菜单的形式分组输出
//添加角色
public function add()
{
$gid = (int)input('get.gid');
$res = SysDb::table('admin_groups')->where(['gid'=>$gid])->item();
if($res['rights']){
$res['rights'] = json_decode($res['rights']);
}
$this->view->assign('res',$res);
//获取全部menu数据,并自定义索引
$menu_list = SysDb::table('admin_menu')->cates('mid');
// dump($menu_list);
//进行根据pid排序存储处理
$menu = $this->gettreeitems($menu_list);
//dump($menu); //返回多维数组,
$results = [];
//遍历返回的多层级关系的数组
foreach ($menu as $items){
//将含有children键名的数据进行操作,将多维数组,变为二维数组
$items['children'] = isset($items['children'])?$this->formatMenus($items['children']):false;
//将返回的数据存储到$results中
$results[] = $items;
}
$this->view->assign('menus',$results);
return $this->view->fetch();
}
//将菜单遍历,有父级id的放入其父级的children键名中.没有的直接存入数组将其返回
private function gettreeitems($items)
{
$tree = [];
foreach ($items as $item){
//如果遍历的元素的父id存在
if(isset($items[$item['pid']])){
//则将遍历的这个元素放在这个父id元素的children键中的一个元素中
$items[$item['pid']]['children'][] = &$items[$item['mid']];
}else{
//如果父id不存在,则没有父级,则引用存入tree中
$tree[] = &$items[$item['mid']];
}
}
return $tree;
}
//将children键中的值递归放在children第一层中
private function formatMenus($items,&$res=[])
{
foreach ($items as $item){
if(isset($item['children'])){
//将后代的children保存到一个变量中
$tem = $item['children'];
//把$item这个键名的数据删除删除这个数据
unset($item['children']);
//把删除后的数据放到这个数组中
$res[] = $item;
//继续递归删除存储到res中
$this->formatMenus($tem,$res);
}else{
//只到没有children了跳出递归
$res[] = $item;
}
}
return $res;
} 2.保存/更新操作
获取表单传过来的值,将多选框的值,也就是键名才是真正的值.转为json数数据,然后写入数据表
public function save()
{
$data['gid'] = (int)input('post.gid');
$data['title'] = trim(input('post.title'));
$menus = input('post.menu/a'); //不太明白/a是什么意思
if(!$data['title']){
exit(json_encode(['res'=>1,'msg'=>'角色名不能为空']));
}
if(!$menus){
exit(json_encode(['res'=>2,'msg'=>'权限不能为空']));
}
//转为json数据
$data['rights'] = json_encode(array_keys($menus));
//判断是更新还是新增
if($data['gid']){
$res = SysDb::table('admin_groups')->where(['gid'=>$data['gid']])->update($data);
}else{
$res = SysDb::table('admin_groups')->insert($data);
}
if($res){
exit(json_encode(['res'=>0,'msg'=>'保存成功']));
}else{
exit(json_encode(['res'=>3,'msg'=>'保存失败']));
}
} 3.删除操作
删除还是老样子删除
public function delete()
{
$gid = (int)input('post.gid');
$res = SysDb::table('admin_groups')->where(['gid'=>$gid])->delete();
if($res){
return ['res'=>0,'msg'=>'删除成功'];
}
return ['res'=>1,'msg'=>'删除失败'];
}
五.导航根据权限显示
根据session中的gid查询当前角色,在根据角色对应的权限显示菜单,当访问权限外的方法时,弹出错误信息
public function index()
{
//根据session中的gid来查询角色
$role = SysDb::table('admin_groups')->where(['gid'=>session('admin')['gid']])->item();
//如果角色存在则将角色中rights的值转为数组
if($role){
$role['rights'] = $role['rights']?json_decode($role['rights'],true):[];
}
//如果权限存在,当mid在这前线的rights数组中的这些值中且不隐藏,状态正常的查询出来,然后获取树形结构
if($role['rights']){
$where = 'mid in('.implode(',',$role['rights']).') and ishidden=0 and status=0';
$menus = SysDb::table('admin_menu')->where($where)->order('ord')->cates('mid');
$menus && $menus =$this->gettreeitems($menus);
}
$this->view->assign('menus',$menus);
$this->view->assign('role',$role);
return $this->view->fetch();
} 真心的难点就在这,实在是有些绕.跟着老师敲下来了.不过虽然都敲出来了,不过还是有不明白的地方,
1.为什么要自定义索引?自定义索引的好处是什么呢?
2.获取树形结构的时候为什么要用&引用传值.
3.input('post.menu/a') 这助手函数/a是什么意思呢
批改老师:天蓬老师批改时间:2018-12-28 15:26:31
老师总结:不要一上来就写代码,写之前,画个图,想一下流程,再写,先写简单功能,再写复杂的. 把每个操作,把架构写出来,内容为空放在那,从全局上掌握你的代码