摘要:权限模块确实有点难,跟老师敲了一遍,虽然磕磕绊绊,不过还是做出来了,一些自定义的函数,如果没有老师的想法,也许自己根本不会这么去做,这也许就是经验吧,下面开始捋一下.一.菜单列表页面 菜单列表页面,依旧是查询表,然后模板赋值,不过需要注意的是首先查询的是第一层级的菜单,也就是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		
						
老师总结:不要一上来就写代码,写之前,画个图,想一下流程,再写,先写简单功能,再写复杂的.  把每个操作,把架构写出来,内容为空放在那,从全局上掌握你的代码					
 
                 
 
 
  
            