Blogger Information
Blog 42
fans 2
comment 0
visits 53937
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
CMS后台管理系统(二) 管理员管理 菜单管理 2019年4月2日
小明的博客
Original
2272 people have browsed it

完善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的值组成的而为数组 自定义索引要和数据库字段一致
Correction status:Uncorrected

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments