今天完成角色管理功能,网站配置功能。
一、角色管理
新建Roles.php下面index方法,roles/index.php前端页面,展示角色列表
查询admin_groups理所有的角色信息,发送给前端。
//角色列表
public function index() {
//20 查询角色表(admin_group),全部数据
$data['roles'] = $this->db->table('admin_groups')->lists();
$this->assign('data', $data);
return $this->fetch();
}
前端页面通过传过来的数据,循环出角色列表,有编辑、添加,删除按钮,用js设置相应的方法add,delete。这里和之前一样,编辑和添加用一个方法,用传入的gid值来区分,add方法将传入的gid,转给Roles类下的add方法,跳转到roles/add.php。delete是将gid通过post转给Roles下的delete方法处理。```html
<!DOCTYPE html>
<html>
<head>
<title>角色管理</title>
<link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
<script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
<style type="text/css">
.header span{background: #009688;margin-left: 30px;padding: 10px;color:#ffffff;}
.header div{border-bottom: solid 2px #009688;margin-top: 8px;}
</style>
</head>
<body style="padding: 10px;">
<div class="header">
<span>角色列表</span>
<button class="layui-btn layui-btn-xs" style="float: right;" onclick="add()">添加</button>
<div></div>
</div>
<table class="layui-table">
<thead>
<tr>
<th>ID</th>
<td>角色名称</td>
<td>操作</td>
</tr>
</thead>
<tbody>
{volist name=”data.roles” id=”vo”}
<tr>
<td>{$vo.gid}</td>
<td>{$vo.title}</td>
<td>
<button class="layui-btn layui-btn-warm layui-btn-xs" onclick="add({$vo.gid})">编辑</button>
<button class="layui-btn layui-btn-danger layui-btn-xs" onclick="del({$vo.gid})">删除</button>
</td>
</tr>
{/volist}
</tbody>
</table>
</body>
</html>
<script type="text/javascript">
layui.use([‘layer’],function(){
$ = layui.jquery;
layer = layui.layer;
});
// 添加
function add(gid){
layer.open({
type: 2,
title: gid>0?’编辑角色’:’添加角色’,
shade: 0.3,
area: [‘580px’, ‘520px’],
content: ‘/index.php/admins/Roles/add?gid=’+gid
});
}
// 删除
function del(gid){
layer.confirm(‘确定要删除吗?’, {
icon:3,
btn: [‘确定’,’取消’]
}, function(){
$.post(‘/index.php/admins/roles/delete’,{‘gid’:gid},function(res){
if(res.code>0){
layer.alert(res.msg,{icon:2});
}else{
layer.msg(res.msg);
setTimeout(function(){window.location.reload();},1000);
}
},’json’);
});
}
</script>###### 增加Roles下的add方法,新建roles/add.php。
add方法通过get过来的gid判断,有值为修改,0是新增;通过gid查询出符合条件的单条记录,然后通过判断该条记录是否为空且是否存在,且记录里面的权限转换为数组后是否存在,都为真的话,将该条数据传给前端;
查询出状态正常的所有菜单列表(也就是权限值对应的菜单),整理菜单列表,就是让二级菜单移动他所属的一级菜单下的children数组。对每个一级菜单下面的所有菜单进行递归,让二级菜单及其子菜单都成为children里面的子项且都平级。返回到add.php前端
php
//编辑添加角色
public function add() {
//21 通过get传值 获取到gid 也就是角色id
//21 没有传值就是新增 有值就是修改
$gid = (int)input(‘get.gid’);
//21 查询admin_groups 找到gid对应的那条信息
$role = $this->db->table(‘admin_groups’)->where(array(‘gid’=>$gid))->item();
//21 查询的单条信息$role存在且里面有权限$role[‘rights’]且将权限的内容解析为数组且有值
$role && $role[‘rights’] && $role[‘rights’]=json_decode($role[‘rights’]);
//21 把查询出的单条记录传给前端
$this->assign(‘role’, $role);
//21 查询菜单表显示状态正常的所有信息
$menu_list = $this->db->table(‘admin_menus’)->where(array(‘status’=>0))->cates(‘mid’);
//21 整理菜单列表
$menus = $this->gettreeitems($menu_list);
// print_r($menus);
//21 空数组用来装整理好的菜单
$results = [];
foreach ($menus as $value) {
// 21,判断菜单是否有权限,有权限给值,没权限给false
// 21,尽量把一些逻辑性的代码,在php里处理好。前端页面,最后只用作展示数据
$value[‘children’] = isset($value[‘children’]) ? $this->formatMenus($value[‘children’]) : false;
$results[] = $value;
}
// print_r($results);
$this->assign(‘menus’,$results);
return $this->fetch();
}
// 递归处理菜单
// 22,为什么要使用递归,不使用两次循环。 因为递归可以处理,多维循环。
// 22,比如6维数组, 那你要循环6次(要写6次foreach),递归就可以解决代码多的问题。
private function formatMenus($items,&$res = array()){
// 22,处理菜单方法,接收2个变量,一个是数组(是权限这个字段,rights),第二个默认返回值
// 22,& 接收的值$res,有变化,传过来的值,也会跟着改变。
// 22,循环权限字段(rights) 值: [1,4,5,6,2] 整合单条菜单,形成二维数组
foreach($items as $item){
// 22,如果children没有的话,我们直接把数组 赋值给$res
// 22,children 是子菜单,如果子菜单有,重新执行本方法,就是递归。
if(!isset($item[‘children’])){
$res[] = $item;
}else{
// 22,如果children有值,把数组赋值给$tem,然后在重新执行 本方法
$tem = $item[‘children’];
// 22,unset函数 是删除数据。 $item[‘children’]是数组。
// 22,为什么要删除children,因为当children有值得时,要把它删除,把剩下的数据,复制给$res 变量。 如果不删除,会进行死循环。 因为不删除$item[‘children’],它会一直判断$item[‘children’]里面有值,一直递归下去,无限递归,导致电脑奔溃。
unset($item[‘children’]);
$res[] = $item;
// 22,回调本方法,就是自己。
$this->formatMenus($tem,$res);
}
}
return $res;
}
//整理菜单
private function gettreeitems($items) {
//初始化$tree 作为整理好的菜单容齐
$tree = array();
foreach ($items as $item) {
//如果二级数组里的pid值作为下标的,有值,那么他必定是二级菜单
//那么就让二级菜单所属的一级菜单自定义下标children 然后将二级菜单的信息移动过来
if (isset($items[$item[‘pid’]])) {
//这里用引用符号&就是后面的值变化前面也变,
//意思就是将二级菜单整个移动到所属的一级菜单以前的结构就变了
$items[$item[‘pid’]][‘children’][] = &$items[$item[‘mid’]];
} else {
//把最终的一级菜单包括下面的二级菜单全部组装
$tree[] = &$items[$item[‘mid’]];
}
}
return $tree;
}add前端,把传过来的数据展示出来,循环出1级菜单,把当前角色有的权限搭上对号,循环出二级及以下菜单,把角色对应个的权限对应打上对号。保存按钮调用js中save方法,把表单中所有的信息post到Roles下的save方法。
html
<!DOCTYPE html>
<html>
<head>
<title>角色添加</title>
<link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
<script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
</head>
<body style="padding: 10px;">
<form class="layui-form">
<input type="hidden" name="gid" value="{$role.gid}">
<div class="layui-form-item">
<label class="layui-form-label">角色名称</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="title" value="{$role.title}">
</div>
</div>
<div class="layui-form-itme">
<label class="layui-form-label">权限菜单</label>
{volist name="menus" id="vo"}
<hr>
<div class="layui-input-block">
<!-- in_array 查询值是否存在这个数组里 -->
<input type="checkbox" name="menu[{$vo.mid}]" lay-skin="primary" title="{$vo.title}" {:isset($role['rights']) && $role['rights'] && in_array($vo.mid,$role['rights'])?'checked':''}>
<hr>
{volist name="vo.children" id="cvo"}
<input type="checkbox" name="menu[{$cvo.mid}]" lay-skin="primary" title="{$cvo.title}" {:isset($role['rights']) && $role['rights'] && in_array($cvo.mid,$role['rights'])?'checked':''}>
{/volist}
</div>
{/volist}
</div>
</form>
<div class="layui-form-item" style="margin-top:10px;">
<div class="layui-input-block">
<button class="layui-btn" onclick="save()">保存</button>
</div>
</div>
</body>
</html>
<script type="text/javascript">
layui.use([‘layer’,’form’],function(){
var form = layui.form;
layer = layui.layer;
$ = layui.jquery;
});
function save(){
var title = $.trim($('input[name="title"]').val());
if(title==''){
layer.msg('请填写角色名称',{'icon':2});
return;
}
$.post('/index.php/admins/roles/save',$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){parent.window.location.reload();},1000);
}
},'json');
}
</script>
###### 新建Roles下的save
save方法储存post过来的gid,title,menu/a,对title判空,然后如果menu有数据,就把menu中的数组的key存到data['right']。接这对gid进行判断,存在的话就是修改执行修改操作,否则就是添加,执行添加操作,最后数据库操作执行成功输出成功的json数据。
```php
//保存菜单
public function save() {
//23 保存post过来的gid
$gid = (int)input('post.gid');
//23 保存post过来的title
$data['title'] = trim(input('post.title'));
//23 保存post过来的menu 强制数组
$menus = input('post.menu/a');
//23 角色名称判空(权限可以为空 名称不能)
if (!$data['title']) {
exit(json_encode(array('code'=>1, 'msg'=>'角色名称不能为空')));
}
//23 如果权限不为空,把权限的下标给到$data['rights']
$menus && $data['rights'] = json_encode(array_keys($menus));
//23 如果有gid那么就是修改 如果不是就是插入
if ($gid) {
$this->db->table('admin_groups')->where(array('gid'=>$gid))->update($data);
} else {
//插入
$this->db->table('admin_groups')->insert($data);
}
exit(json_encode(array('code'=>0, 'msg'=>'保存成功')));
}
删除操作,在Roles下新家delete方法。
将传过来的gid为条件,找到admin_groups中的该条记录,进行删除操作,返回数据库操作成功与否的json。
//删除操作
public function delete() {
//接收gid
$gid = (int)input('post.gid');
//执行删除操作
$res = $this->db->table('admin_groups')->where(array('gid'=>$gid))->delete();
//根据结果输出给前端
if ($res) {
exit(json_encode(array('code'=>0, 'msg'=>'删除成功')));
} else {
exit(json_encode(array('code'=>1, 'msg'=>'删除失败')));
}
}
二、网站配置
新建Config类,用index方法展示数据,新建config/index.php前端
index方法查询出config表中的所有记录,如果存在记录,那么就把记录里面的value值json接续成数组,然后传给前端,前端循环展示出来。前端中用save保存数据传给Config里新建的save方法
public function index(){
//24 查询配置表config 获得所有数据
$site = $this->db->table('config')->lists();
//如果有值就把每条记录理的values值json化
if ($site) {
foreach ($site as &$v) {
$v['values'] = json_decode($v['values']);
}
}
$this->assign('site', $site);
return $this->fetch();
}
<!DOCTYPE html>
<html>
<head>
<title>网站设置</title>
<link rel="stylesheet" type="text/css" href="/static/plugins/layui/css/layui.css">
<script type="text/javascript" src="/static/plugins/layui/layui.js"></script>
<style type="text/css">
.header span{background: #009688;margin-left: 30px;padding: 10px;color:#ffffff;}
.header div{border-bottom: solid 2px #009688;margin-top: 8px;}
.header button{float: right;margin-top: -5px;}
</style>
</head>
<body style="padding: 10px;">
<div class="header">
<span>网站设置</span>
<div></div>
</div>
<form class="layui-form" style="margin-top: 10px;">
{volist name="site" id="site_v"}
<div class="layui-form-item">
<label class="layui-form-label">{$site_v.names}</label>
<div class="layui-input-inline">
<input type="text" class="layui-input" name="{$site_v.yingwen}" value="{$site_v.values}">
</div>
</div>
{/volist}
</form>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" onclick="save()">提交</button>
</div>
</div>
</body>
</html>
<script type="text/javascript">
layui.use(['layer'],function(){
$ = layui.jquery;
layer = layui.layer;
});
function save(){
var site = $.trim($('input[name="site"]').val());
if(site==''){
layer.msg('网站名称不能为空',{'icon':2});
return;
}
$.post('/index.php/admins/config/save',$('form').serialize(),function(res){
if(res.code>0){
layer.msg(res.msg,{'icon':2});
}else{
layer.msg(res.msg,{'icon':1});
setTimeout(function(){window.location.reload();},1000);
}
},'json');
}
</script>
新增Roles下的save方法
在save方法中循环post过来的所有信息,把信息的值json化然后,在config表中进行修改,输出数据库成功的json化数据
三、踩过的坑
- 把所有菜单信息进行整理得,思路是:进行循环,判断单条记录中的pid放在真个数组中是否存在,如果存在的化就是二级菜单,那么就把二级菜单放在他对应的一级菜单[‘children’]下,如果是一级菜单的化就直接放在整理列表的第一级
- 还有递归方法,实际上如果是多维数据的化可以省去好多级的循环,而且你也不知道他是几纬数组,只能用递归,只不过最后返回的结果就是二级菜单级一下的菜单都平级的放在一级菜单下,这个是把数据的形式转化了,实际的数据库数据是没有变的