博客列表 >CMS后台管理系统(二) 管理员管理 菜单管理 2019年4月2日

CMS后台管理系统(二) 管理员管理 菜单管理 2019年4月2日

小明的博客
小明的博客原创
2020年02月12日 13:17:282273浏览

完善cms后台,完成管理员管理,菜单管理功能。

一、管理员管理功能
新建Admin类,添加index方法

在Baseadmin类中添加判断用户是否具有权限的功能和当前访问菜单功能

  1. // 判断用户是否有权限
  2. $this->db = new Sysdb;
  3. $group = $this->db->table('admin_groups')->where(array('gid'=>$this->_admin['gid']))->item();
  4. if(!$group){
  5. $this->request_error('对不起,您没有权限');
  6. }
  7. $rights = json_decode($group['rights']);
  8. // 当前访问菜单
  9. $controller = request()->controller();
  10. $action = request()->action();
  11. $res = $this->db->table('admin_menus')->where(array('controller'=>$controller,'method'=>$action))->item();
  12. if(!$res){
  13. $this->request_error('对不起,您访问的功能不存在');
  14. }
  15. if($res['status']==1){
  16. $this->request_error('对不起,该功能已禁止使用');
  17. }
  18. if(!in_array($res['mid'],$rights)){
  19. $this->request_error('对不起,您没有权限');
  20. }
admin类继承自BaseAdmin,用来获取权限控制功能

index方法主要是将所有管理员展示出来,查询出所有的管理员信息、查询出所有的角色信息(用gid作为自定义索引),发送给前端

  1. //管理员列表
  2. public function index() {
  3. //13 查询管理员表admins 将所有信息都查询出来
  4. $data['lists'] = $this->db->table('admins')->lists();
  5. //13 加载所有角色
  6. $data['group'] = $this->db->table('admin_groups')->cates('gid');
  7. //将数据发送给前端
  8. $this->assign('data', $data);
  9. return $this->fetch();
  10. }

然后新建前端页面 admin/index.php,通过表单把每个管理员的信息展示出来;需要对管理员进行添加、编辑、删除操作。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
  6. <script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
  7. <style type="text/css">
  8. .header span{background: #009688;margin-left: 30px;padding: 10px;color:#ffffff;}
  9. .header div{border-bottom: solid 2px #009688;margin-top: 8px;}
  10. .header button{float: right;margin-top: -5px;}
  11. </style>
  12. </head>
  13. <body style="padding: 10px;">
  14. <div class="header">
  15. <span>管理员列表</span>
  16. <button class="layui-btn layui-btn-sm" onclick="add()">添加</button>
  17. <div></div>
  18. </div>
  19. <table class="layui-table">
  20. <thead>
  21. <tr>
  22. <th>ID</th>
  23. <th>用户名</th>
  24. <th>真实姓名</th>
  25. <th>角色</th>
  26. <th>状态</th>
  27. <th>添加时间</th>
  28. <th>操作</th>
  29. </tr>
  30. </thead>
  31. <tbody>
  32. <!-- 循环出所有管理员 -->
  33. {volist name="data.lists" id="vo"}
  34. <tr>
  35. <td>{$vo.id}</td>
  36. <td>{$vo.username}</td>
  37. <td>{$vo.truename}</td>
  38. <!-- 三元运算 如果$data['group'][$vo.gid]有对应值那么就显示他的title 否则为空 -->
  39. <td>{:isset($data['group'][$vo.gid]) ? $data['group'][$vo.gid]['title'] : ''}</td>
  40. <!-- 三元运算 如果status为0 为绿色 -->
  41. <td>{$vo.status == 0 ? '<span style="color: green">正常</span>' : '<span style="color: red">禁用</span>'}</td>
  42. <td>{:date('Y-m-d H:i:s', $vo.add_time)}</td>
  43. <td>
  44. <button class="layui-btn layui-btn-xs" onclick="add({$vo.id})">编辑</button>
  45. <button class="layui-btn layui-btn-danger layui-btn-xs" onclick="del({$vo.id})">删除</button>
  46. </td>
  47. </tr>
  48. {/volist}
  49. </tbody>
  50. </table>
  51. <script type="text/javascript">
  52. layui.use(['layer'],function(){
  53. layer = layui.layer;
  54. $ = layui.jquery;
  55. });
  56. // 添加编辑
  57. function add(id) {
  58. layer.open({
  59. type: 2,
  60. title: id>0 ? '编辑管理员' : '添加管理员',
  61. shade: 0.3,
  62. area: ['480px', '420px'],
  63. content: '/index.php/admins/Admin/add?id='+id
  64. });
  65. }
  66. // 删除
  67. function del(id) {
  68. layer.confirm('确定要删除吗?', {
  69. icon: 3,
  70. btn: ['确定', '取消']
  71. }, function () {
  72. $.post('/index.php/admins/Admin/delete', {'id':id}, function (res) {
  73. if (res.code > 0) {
  74. layer.alert(res.msg, {icon:2});
  75. } else {
  76. layer.msg(res.msg);
  77. setTimeout(function () {
  78. window.location.reload();
  79. }, 1000)
  80. }
  81. }, 'json');
  82. });
  83. }
  84. </script>
  85. </body>
  86. </html>

编辑和添加功能都用add方法实现,用传过来的id区分,>0为编辑,否则就是添加。id值通过get方法传给Admin类下的add方法。add方法将此id的管理员信息和所有角色信息发给前端。这的编辑、添加,通过弹框一个新页面,这里新建前端页面admin/add.php。

  1. public function add() {
  2. //14 接收前端get过来的id值,确定是那个管理员,如果是0那么就是添加 ,大于0就是编辑
  3. $id = (int)input('get.id');
  4. // 14 加载管理员
  5. // 14 用id在admins表中查询出该管理员的信息
  6. $data['item'] = $this->db->table('admins')->where(array('id'=>$id))->item();
  7. //加载出角色信息
  8. $data['groups'] = $this->db->table('admin_groups')->cates('gid');
  9. $this->assign('data', $data);
  10. return $this->fetch();
  11. }

前端页面根据传过来的id进行展示,如果是编辑里面的用户名不能更改,然后通过save方法将数据发送给Admin类下的save方法处理

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
  6. <script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
  7. </head>
  8. <body style="padding: 10px;">
  9. <form class="layui-form">
  10. <!-- hidden 是把input框隐藏,它的作用是把一些隐藏信息传值到接口中 -->
  11. <input type="hidden" name="id" value="{$data.item.id}">
  12. <div class="layui-form-item">
  13. <label class="layui-form-label">用户名</label>
  14. <div class="layui-input-inline">
  15. <!-- value 是默认值 -->
  16. <!-- 当添加时,传值是0,默认值是空 -->
  17. <!-- readonly 是input里的一个参数,可以禁用input框,只有在修改用户时,才使用 -->
  18. <input type="text" class="layui-input" name="username" value="{$data.item.username}" {$data.item.id>0?'readonly':''}>
  19. </div>
  20. </div>
  21. <div class="layui-form-item">
  22. <label class="layui-form-label">角&nbsp;&nbsp;&nbsp;&nbsp;色</label>
  23. <div class="layui-input-inline">
  24. <select name="gid">
  25. <option value=0></option>
  26. <!-- 循环角色数据 -->
  27. <!-- value 是角色的ID -->
  28. <!-- selected 是默认选中,用三元进行判断,判断条件是用户gid和角色gid -->
  29. <!-- 用户gid和角色gid 只有一次相等的机会 -->
  30. {volist name="data.groups" id="vo"}
  31. <option value="{$vo.gid}" {$vo.gid == $data.item.gid ? 'selected' : ''}>{$vo.title}</option>
  32. {/volist}
  33. </select>
  34. </div>
  35. </div>
  36. <div class="layui-form-item">
  37. <label class="layui-form-label">密&nbsp;&nbsp;&nbsp;&nbsp;码</label>
  38. <div class="layui-input-inline">
  39. <input type="text" class="layui-input" name="pwd">
  40. </div>
  41. </div>
  42. <div class="layui-form-item">
  43. <label class="layui-form-label">姓&nbsp;&nbsp;&nbsp;&nbsp;名</label>
  44. <div class="layui-input-inline">
  45. <input type="text" class="layui-input" name="truename" value="{$data.item.truename}">
  46. </div>
  47. </div>
  48. <div class="layui-form-item">
  49. <label class="layui-form-label">状&nbsp;&nbsp;&nbsp;&nbsp;态</label>
  50. <div class="layui-input-inline">
  51. <input type="checkbox" name="status" lay-skin="primary" title="禁用" value="1" {$data.item.status?'checked':''}>
  52. </div>
  53. </div>
  54. </form>
  55. <div class="layui-form-item">
  56. <div class="layui-input-block">
  57. <button class="layui-btn" onclick="save()">保存</button>
  58. </div>
  59. </div>
  60. <script type="text/javascript">
  61. layui.use(['layer','form'],function(){
  62. form = layui.form;
  63. layer = layui.layer;
  64. $ = layui.jquery;
  65. });
  66. // 保存管理员
  67. function save(){
  68. // 用js 获取id、用户名、密码、角色、真实姓名
  69. var id = parseInt($('input[name="id"]').val());
  70. var username = $.trim($('input[name="username"]').val());
  71. var pwd = $.trim($('input[name="pwd"]').val());
  72. var gid = $('select[name="gid"]').val();
  73. var truename = $.trim($('input[name="truename"]').val());
  74. var status = parseInt($('input[name="truename"]').val());
  75. if(username==''){
  76. layer.alert('请输入用户名',{icon:2});
  77. return;
  78. }
  79. if(isNaN(id) && pwd==''){
  80. layer.alert('请输入密码',{icon:2});
  81. return;
  82. }
  83. if(gid==0){
  84. layer.alert('请选择角色',{icon:2});
  85. return;
  86. }
  87. if(truename==''){
  88. layer.alert('请输入姓名',{icon:2});
  89. return;
  90. }
  91. // 请求保存接口,把数据传值到接口中。
  92. $.post('/index.php/admins/Admin/save',$('form').serialize(),function(res){
  93. if(res.code>0){
  94. layer.alert(res.msg,{icon:2});
  95. }else{
  96. layer.msg(res.msg);
  97. setTimeout(function(){parent.window.location.reload();},1000);
  98. }
  99. },'json');
  100. }
  101. </script>
  102. </body>
  103. </html>

save方法接收post传过来的各种信息,经过控制判断,密码加密处理后,将id==0的是为添加,进行账号重复判断,将添加时间整合,进行insert操作,返回一个布尔值给$res;id不为0就进行编辑操作,update,返回一个$res;最后将$res为false的给到code:1 msg:保存失败,true的给到0和保存成功,发送给前端页面,前端页面进行展示

删除功能。

在admin/index页面有del方法,确认删除后将id值传给Admin类下的delete方法,然后执行delete操作

  1. //保存管理员
  2. public function save() {
  3. // 15 将post传过来的ID 账号 角色id 密码 真实姓名状态保存在变量中
  4. $id = (int)input('post.id');
  5. $data['username'] = trim(input('post.username'));
  6. $data['gid'] = (int)(input('post.gid'));
  7. $password = trim(input('post.pwd'));
  8. $data['truename'] = trim(input('post.truename'));
  9. $data['status'] = (int)(input('post.status'));
  10. //判空排除
  11. if (!$data['username']) {
  12. exit(json_encode(array('code'=>1, 'msg'=>'用户名不能为空')));
  13. }
  14. if (!$data['gid']) {
  15. exit(json_encode(array('code'=>1, 'msg'=>'角色不能为空')));
  16. }
  17. if ($id==0 && !$password) {
  18. exit(json_encode(array('code'=>1, 'msg'=>'密码不能为空')));
  19. }
  20. if (!$data['truename']) {
  21. exit(json_encode(array('code'=>1, 'msg'=>'姓名不能为空')));
  22. }
  23. //给密码md5加密
  24. if ($password) {
  25. $data['password'] = md5($data['username'] . $password);
  26. }
  27. //初始化 数据库操作成功与否的变量 $res
  28. $res = true;
  29. // 15 判断用户id是否为0 0的话是添加 否则是修改
  30. if ($id == 0) {
  31. //检查账户是否重复 保证账号的唯一性
  32. $item = $this->db->table('admins')->where(array('id'=>$id))->item();
  33. if ($item) {
  34. exit(json_encode(array('code'=>1, 'msg'=>'该用户已经存在')));
  35. }
  36. // 15 添加时间 给当前的时间戳
  37. $data['add_time'] = time();
  38. // 15 执行插入语句
  39. $res = $this->db->table('admins')->insert($data);
  40. }else {
  41. // 15 不是0的情况执行修改语句
  42. $res = $this->db->table('admins')->where(array('id'=>$id))->update($data);
  43. }
  44. if (!$res) {
  45. exit(json_encode(array('code'=>1, 'msg'=>'保存失败')));
  46. }
  47. exit(json_encode(array('code'=>0, 'msg'=>'保存成功')));
  48. }

二、菜单管理功能

新建Menu类index方法,新建menu/index.php页面。

通过get获得pid值,这里默认为0,然后通过pid找到所有pid为0的菜单信息,也就是一级菜单。初始化返回上一级的id即backid为0,然后当pid>0也就是进入二级菜单时,通过点击子菜单,获得的pid也就是上一级的mid,然后在找到他的pid,也就是二级菜单的爷爷辈菜单

  1. public function index() {
  2. //17 当点击菜单管理时 通过get得到pid 默认是管理pid为0的菜单
  3. $pid = (int)input('get.pid');
  4. //17 以得到的pid为条件查处与之相等的pid值的所有菜单信息
  5. $data['lists'] = $this->db->table('admin_menus')->where(array('pid'=>$pid))->lists();
  6. $backid = 0;
  7. //19 如果是pid大于0 那就是二级菜单 再点击二级菜单就得到了pid也就是一级菜单的mid找到一级菜单 返回的id就是一级菜单的pid
  8. if ($pid > 0) {
  9. $parent = $this->db->table('admin_menus')->where(array('mid'=>$pid))->item();
  10. $backid = $parent['pid'];
  11. }
  12. $this->assign('backid', $backid);
  13. $this->assign('pid', $pid);
  14. $this->assign('data', $data);
  15. return $this->fetch();
  16. }
将pid backid 和二级菜单内容(data)传给前端,前端页面menu/index.php,直接就是form表单,将菜单的mid ord title controller method status信息展示出来
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
  6. <script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
  7. <style type="text/css">
  8. .header span{background: #009688;margin-left: 30px;padding: 10px;color:#ffffff;}
  9. .header div{border-bottom: solid 2px #009688;margin-top: 8px;}
  10. </style>
  11. </head>
  12. <body style="padding: 10px;">
  13. <div class="header">
  14. <span>菜单管理</span>
  15. <div></div>
  16. </div>
  17. <form class="layui-form">
  18. {if condition="$pid>0"}
  19. <button class="layui-btn layui-btn-primary layui-btn-sm" style="float: right;margin:5px 0px;" onclick="back({$backid});return false;">返回上级</button>
  20. {/if}
  21. <!-- 隐藏pid -->
  22. <input type="hidden" name="pid" value="{$pid}">
  23. <table class="layui-table">
  24. <thead>
  25. <tr>
  26. <th>ID</th>
  27. <th>排序</th>
  28. <th>菜单名称</th>
  29. <th>controller</th>
  30. <th>method</th>
  31. <th>是否隐藏</th>
  32. <th>是否禁用</th>
  33. <th>操作</th>
  34. </tr>
  35. </thead>
  36. <tbody>
  37. <!-- 循环菜单列表 -->
  38. {volist name="data.lists" id="vo"}
  39. <tr>
  40. <td>{$vo.mid}</td>
  41. <td><input type="text" class="layui-input" name="ords[{$vo.mid}]" value="{$vo.ord}"></td>
  42. <td><input type="text" class="layui-input" name="titles[{$vo.mid}]" value="{$vo.title}"></td>
  43. <td><input type="text" class="layui-input" name="controllers[{$vo.mid}]" value="{$vo.controller}"></td>
  44. <td><input type="text" class="layui-input" name="methods[{$vo.mid}]" value="{$vo.method}"></td>
  45. <td><input type="checkbox" lay-skin="primary" name="ishiddens[{$vo.mid}]" title="隐藏" {$vo.ishidden?'checked':''} value=1></td>
  46. <td><input type="checkbox" lay-skin="primary" name="status[{$vo.mid}]" title="禁用" {$vo.status?'checked':''} value=1></td>
  47. <td><button class="layui-btn layui-btn-xs" onclick="child({$vo.mid});return false;">子菜单</button></td>
  48. </tr>
  49. {/volist}
  50. <!-- 这个是新增的空输入框 -->
  51. <tr>
  52. <td></td>
  53. <td><input type="text" class="layui-input" name="ords[0]"></td>
  54. <td><input type="text" class="layui-input" name="titles[0]"></td>
  55. <td><input type="text" class="layui-input" name="controllers[0]"></td>
  56. <td><input type="text" class="layui-input" name="methods[0]"></td>
  57. <td><input type="checkbox" lay-skin="primary" name="ishiddens[0]" title="隐藏" value=1></td>
  58. <td><input type="checkbox" lay-skin="primary" name="status[0]" title="禁用" value=1></td>
  59. <td></td>
  60. </tr>
  61. </tbody>
  62. </table>
  63. </form>
  64. <button class="layui-btn" onclick="save()">保存</button>
  65. <script type="text/javascript">
  66. layui.use(['layer','form'],function(){
  67. $ = layui.jquery;
  68. layer = layui.layer;
  69. form = layui.form;
  70. });
  71. // 子菜单
  72. function child(pid){
  73. window.location.href="/index.php/admins/Menu/index?pid="+pid;
  74. }
  75. // 返回上一级
  76. function back(pid){
  77. window.location.href="/index.php/admins/Menu/index?pid="+pid;
  78. }
  79. // 保存
  80. function save(){
  81. $.post('/index.php/admins/Menu/save',$('form').serialize(),function(res){
  82. if(res.code>0){
  83. layer.alert(res.msg,{'icon':2});
  84. }else{
  85. layer.msg(res.msg,{'icon':1});
  86. setTimeout(function(){window.location.reload();},1000);
  87. }
  88. },'json');
  89. }
  90. </script>
  91. </body>
  92. </html>

前端页面,有save child back 方法,child通过当前菜单的mid作为pid传递给menu类的index,back是将backid传给index方法。save是将所有信息传给menu的save方法,这里数据都是将当前的mid作为下标然后将所有的菜单分类组成数组,传递给后段menu下save方法。

  1. public function save() {
  2. //18 接收post传过来的 pid ords titles controllers methods ishidden status
  3. $pid = (int)input('post.pid');
  4. $ords = input('post.ords/a');
  5. $titles = input('post.titles/a');
  6. $controllers = input('post.controllers/a');
  7. $methods = input('post.methods/a');
  8. $ishiddens = input('post.ishiddens/a');
  9. $status = input('post.status/a');
  10. //18循环任何一个数组 因为前端的name值都是以菜单的mid作为下标的
  11. foreach ($ords as $key => $value) {
  12. //18将传过来的值组装成一个二维数组
  13. $data['pid'] = $pid;
  14. $data['ord'] = $value;
  15. $data['title'] = $titles[$key];
  16. $data['controller'] = $controllers[$key];
  17. $data['method'] = $methods[$key];
  18. $data['ishidden'] = isset($ishiddens[$key]) ? 1 : 0;
  19. $data['status'] = isset($status[$key]) ? 1 : 0;
  20. //18 $key为0 且 title有值 那么就是新增
  21. if ($key==0 && $data['title']) {
  22. $this->db->table('admin_menus')->insert($data);
  23. }
  24. //18 $key大于0 就是修改已经存在的菜单
  25. if ($key > 0) {
  26. //18 如果titles controllers methods都为空就是删除
  27. if ($data['title'] == '' && $data['controller'] == '' && $data['method'] == '') {
  28. //执行删除语句
  29. $this->db->table('admin_menus')->where(array('mid'=>$key))->delete();
  30. }else {
  31. //修改语句
  32. $this->db->table('admin_menus')->where(array('mid'=>$key))->update($data);
  33. }
  34. }
  35. }
  36. exit(json_encode(array('code'=>0, 'msg'=>'保存成功')));
接收post信息,然后循环任意一个数组,组和成二维数组data,例如ords(前端数据组和时都是把他们的mid作为下标,所以都一样),单项数据的下标$key如果为零并且title存在,那么就是新增,执行新增操作,如果$key》0那么就是编辑,title controller method都为空就是删除,之外的情况就是修改。最后就将code msg json化传递给前端展示。

三、踩过的坑

菜单管理 刚开始我认为 pid本就没值,通过get传过来不对,后来发现,确实需要默认为0,然后展示出来pid为0的一级菜单
通过post从前端传回menu下save的值组成的而为数组 自定义索引要和数据库字段一致
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议