权限管理手册现成代码网址https://www.kancloud.cn/hongweizhiyuan/thinkphp5_auth/

录 附录
逻辑与数据模型
HTML约定-bootstrap
HTML约定-LayUI
角色管理 role
数据表
列表
控制器
视图
视图-layui
角色添加
控制器
视图
角色添加提交
控制器
验证
角色修改
控制器
视图
角色修改提交
控制器
角色删除
控制器
权限设置
控制器
视图
模型
权限设置提交
用户 user
数据表
列表
控制器
视图
模型
- 2 - 本文档使用 看云 构建添加
控制器
视图
添加提交
控制器
验证器
编辑
控制器
视图
编辑提交
控制器
验证器
删除
停用启用
角色用户中间表role_user
菜单管理
数据表
表格折叠列表
控制器
视图
全部列表
控制器
视图
填加
控制器
视图
填加提交
控制器
验证器
编辑
控制器
视图
编辑提交
控制器
验证器
删除
- 3 - 本文档使用 看云 构建控制器
视图
导入菜单
视图
控制器
特别注意
annotation
导出菜单
视图
控制器
排序
控制器
视图
模型
- 4 - 本文档使用 看云 构建附录
这就是最后的模块儿,一共就这几个,很简单!
1、角色管理
2、添加角色
附录
- 5 - 本文档使用 看云 构建3、权限编辑
4、权限设置
附录
- 6 - 本文档使用 看云 构建附录
- 7 - 本文档使用 看云 构建逻辑与数据模型
逻辑
1、向 role 表插入一个角色
2、为角色赋予权限,权限内容从菜单表 admin_menu 中获取,向 auth_access 插入角
色权限信息!
3、新增管理员时,向 user 表插入数据,同时向 role_user 插入相关角色详细内容(先
删除相关后增加),以赋予每个人相关角色 的全部权利!
>注:auth_rule 表目前好像没什么用。另外, Auth 类也没有用到一定要注意!!
数据模型
逻辑与数据模型
- 8 - 本文档使用 看云 构建逻辑与数据模型
- 9 - 本文档使用 看云 构建HTML约定-bootstrap
每个HTML文件头部和尾部的代码,中间的自己写。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<!--中间内容/end-->
</body>
</html>
HTML约定-bootstrap
- 10 - 本文档使用 看云 构建HTML约定-LayUI
HTML 主要代码
下边有很多代码没用,但为了各种开发方便,先约定都加上了!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="http://www.ijquery.cn/ui/layui/layui-v2.1.5/css/layui.css
" rel="stylesheet">
</head>
<body style="padding: 15px;">
<!--中间内容/start-->
<!--中间内容/end-->
<script src="http://www.ijquery.cn/ui/layui/layui-v2.1.5/layui.js"></scri
pt>
<script>
layui.use(['laydate','form', 'laypage', 'layer', 'table', 'carousel',
'upload', 'element'],function(){
var laydate = layui.laydate //日期
,form = layui.form //分页
,laypage = layui.laypage //分页
,layer = layui.layer //弹层
,table = layui.table //表格
,carousel = layui.carousel //轮播
,upload = layui.upload //上传
,element = layui.element; //元素操作
});
</script>
</body>
</html>
HTML约定-LayUI
- 11 - 本文档使用 看云 构建角色管理 role
角色管理 role
- 12 - 本文档使用 看云 构建数据表
数据表
DROP TABLE IF EXISTS `cmf_role`;
CREATE TABLE `cmf_role` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父角色ID',
`status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态;0:禁用;1
:正常',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
`list_order` float NOT NULL DEFAULT '0' COMMENT '排序',
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT
NULL DEFAULT '' COMMENT '角色名称',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
PRIMARY KEY (`id`),
KEY `parentId` (`parent_id`),
KEY `status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
测试数据
INSERT INTO `cmf_role` VALUES ('1', '0', '1', '1329633709', '1329633709',
'0', '超级管理员', '拥有网站最高管理员权限!');
INSERT INTO `cmf_role` VALUES ('2', '0', '1', '1329633709', '1329633709',
'0', '普通管理员', '权限由最高管理员分配!');
数据表
- 13 - 本文档使用 看云 构建列表
控制器
视图
视图-layui
列表
- 14 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class RbacController extends Controller
{
/**
* 角色管理列表
*/
public function index()
{
$data = Db::name('role')->order(["list_order"=>"ASC","id"=>"DESC"
])->select();
$this->assign('roles',$data);
return $this->fetch();
}
}
控制器
- 15 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<table class="table table-hover table-bordered table-list">
<thead>
<tr>
<th width="40">ID</th>
<th align="left">角色名称</th>
<th align="left">角色描述 </th>
<th width="60" align="left">状态</th>
<th width="160">操作</th>
</tr>
</thead>
<tbody>
<foreach name="roles" item="vo">
<tr>
<td>{$vo.id}</td>
<td>{$vo.name}</td>
<td>{$vo.remark}</td>
<td>
<if condition="$vo['status'] eq 1">
<font color="red">√</font>
<else />
<font color="red">╳</font>
</if>
</td>
<td>
<if condition="$vo['id'] eq 1">
<font color="#cccccc">权限设置</font>
<font color="#cccccc">编辑</font>
<font color="#cccccc">删除</font>
<else />
视图
- 16 - 本文档使用 看云 构建 <a href="{:url('Rbac/authorize',array('id'=>$vo['id']
))}">权限设置</a>
<a href="{:url('Rbac/roleedit',array('id'=>$vo['id'])
)}">编辑</a>
<a class="js-ajax-delete" href="{:url('Rbac/roledelet
e',array('id'=>$vo['id']))}">删除</a>
</if>
</td>
</tr>
</foreach>
</tbody>
</table>
</body>
</html>
视图
- 17 - 本文档使用 看云 构建视图-layui
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="http://www.ijquery.cn/ui/layui/layui-v2.1.5/css/layui.css
" rel="stylesheet">
</head>
<body style="padding: 15px;">
<!--中间内容/start-->
<table class="layui-table">
<thead>
<tr>
<th width="40">ID</th>
<th align="left">角色名称</th>
<th align="left">角色描述</th>
<th width="60" align="left">状态</th>
<th width="160">操作</th>
</tr>
</thead>
<tbody>
<foreach name="agent_roles" item="vo">
<tr>
<td>{$vo.id}</td>
<td>{$vo.name}</td>
<td>{$vo.remark}</td>
<td>
<if condition="$vo['status'] eq 1">
<font color="red">√</font>
<else/>
<font color="red">╳</font>
</if>
</td>
<td>
<a href="{:url('Rbac/authorize',array('id'=>$vo['id']))}"
>权限设置</a>
<a href="{:url('Rbac/roleedit',array('id'=>$vo['id']))}">
编辑</a>
<a class="js-ajax-delete" href="{:url('Rbac/roledelete',a
rray('id'=>$vo['id']))}">删除</a>
</td>
</tr>
</foreach>
</tbody>
</table>
<!--中间内容/end-->
视图-layui
- 18 - 本文档使用 看云 构建<script src="http://www.ijquery.cn/ui/layui/layui-v2.1.5/layui.js"></scri
pt>
<script>
layui.use(['laydate','form', 'laypage', 'layer', 'table', 'carousel',
'upload', 'element'],function(){
var laydate = layui.laydate //日期
,form = layui.form //分页
,laypage = layui.laypage //分页
,layer = layui.layer //弹层
,table = layui.table //表格
,carousel = layui.carousel //轮播
,upload = layui.upload //上传
,element = layui.element; //元素操作
});
</script>
</body>
</html>
视图-layui
- 19 - 本文档使用 看云 构建角色添加
控制器
视图
角色添加
- 20 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
class RbacController extends Controller
{
/**
* 添加角色
*/
public function roleAdd()
{
return $this->fetch();
}
}
控制器
- 21 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<form class="form-horizontal js-ajax-form margin-top-20" action="{:url('r
bac/roleAddPost')}" method="post">
<div class="form-group">
<label for="input-name" class="col-sm-2 control-label"><span clas
s="form-required">*</span>角色名称</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-name" name=
"name">
</div>
</div>
<div class="form-group">
<label for="input-remark" class="col-sm-2 control-label">角色描述<
/label>
<div class="col-md-6 col-sm-10">
<textarea type="text" class="form-control" id="input-remark"
name="remark"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">状态</label>
<div class="col-md-6 col-sm-10">
<label class="radio-inline">
<input type="radio" name="status" value="1"> 开启
</label>
<label class="radio-inline">
<input type="radio" name="status" value="0"> 禁用
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary js-ajax-submit">
添加</button>
</div>
</div>
</form>
</body>
视图
- 22 - 本文档使用 看云 构建</html>
视图
- 23 - 本文档使用 看云 构建角色添加提交
控制器
验证
角色添加提交
- 24 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
class RbacController extends Controller
{
/**
* 添加角色提交
*/
public function roleAddPost()
{
if ($this->request->isPost()) {
$data = $this->request->param();
$result = $this->validate($data, 'role');
if ($result !== true) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$result = Db::name('role')->insert($data);
if ($result) {
$this->success("添加角色成功", url("rbac/index"));
} else {
$this->error("添加角色失败");
}
}
}
}
}
控制器
- 25 - 本文档使用 看云 构建验证
代码
<?php
namespace app\agent\validate;
use think\Validate;
class RoleValidate extends Validate
{
protected $rule = [
'name' => 'require',
];
protected $message = [
'name.require' => '角色名称不能为空',
];
protected $scene = [
'add' => ['name'],
];
}
验证
- 26 - 本文档使用 看云 构建角色修改
控制器
视图
角色修改
- 27 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class RbacController extends Controller
{
/**
* 编辑角色
*/
public function roleEdit()
{
$id = $this->request->param("id", 0, 'intval');
if ($id == 1) {
$this->error("超级管理员角色不能被修改!");
}
$data = Db::name('role')->where(["id" => $id])->find();
if (!$data) {
$this->error("该角色不存在!");
}
$this->assign("data", $data);
return $this->fetch();
}
}
控制器
- 28 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap
.min.css" rel="stylesheet">
</head>
<body>
<form class="form-horizontal js-ajax-form margin-top-20"
action="{:url('rbac/roleeditpost')}" method="post">
<div class="form-group">
<label for="input-name" class="col-sm-2 c
ontrol-label"><span class="form-required">*</span>角色名称</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-co
ntrol" id="input-name" name="name" value="{$data.name}">
</div>
</div>
<div class="form-group">
<label for="input-remark" class="col-sm-2
control-label">角色描述</label>
<div class="col-md-6 col-sm-10">
<textarea type="text" class="form
-control" id="input-remark" name="remark">{$data.remark}</textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">状态
</label>
<div class="col-md-6 col-sm-10">
<label class="radio-inline">
<php>$active_true_checked
=($data['status']==1)?"checked":"";</php>
<input type="radio" name=
"status" value="1" {$active_true_checked}> 开启
</label>
<label class="radio-inline">
<php>$active_false_checke
d=($data['status']==0)?"checked":"";</php>
<input type="radio" name=
"status" value="0" {$active_false_checked}> 禁用
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="hidden" name="id" va
视图
- 29 - 本文档使用 看云 构建lue="{$data.id}"/>
<button type="submit" class="btn
btn-primary js-ajax-submit">保存</button>
<a class="btn btn-default" href="
{:url('admin/rbac/index')}">返回</a>
</div>
</div>
</form>
</div>
</body>
</html>
视图
- 30 - 本文档使用 看云 构建角色修改提交
控制器
角色修改提交
- 31 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class RbacController extends Controller
{
/**
* 编辑角色提交
*/
public function roleEditPost()
{
$id = $this->request->param("id", 0, 'intval');
if ($id == 1) {
$this->error("超级管理员角色不能被修改!");
}
if ($this->request->isPost()) {
$data = $this->request->param();
$result = $this->validate($data, 'role');
if ($result !== true) {
// 验证失败 输出错误信息
$this->error($result);
} else {
if (Db::name('role')->update($data) !== false) {
$this->success("保存成功!", url('rbac/index'));
} else {
$this->error("保存失败!");
}
}
}
}
}
控制器
- 32 - 本文档使用 看云 构建角色删除
控制器
角色删除
- 33 - 本文档使用 看云 构建控制器
>注:删除时和 RoleUser 关联!
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class RbacController extends Controller
{
/**
* 删除角色
*/
public function roleDelete()
{
$id = $this->request->param("id", 0, 'intval');
if ($id == 1) {
$this->error("超级管理员角色不能被删除!");
}
$count = Db::name('RoleUser')->where(['role_id' => $id])->count()
;
if ($count > 0) {
$this->error("该角色已经有用户!");
} else {
$status = Db::name('role')->delete($id);
if (!empty($status)) {
$this->success("删除成功!", url('rbac/index'));
} else {
$this->error("删除失败!");
}
}
}
}
控制器
- 34 - 本文档使用 看云 构建权限设置
控制器
视图
模型
权限设置
- 35 - 本文档使用 看云 构建控制器
代码
>注:需要类库 Tree ,和模型 AdminMenuModel
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
use tree\Tree;
use app\agent\model\AdminMenuModel;
class RbacController extends Controller
{
/**
* 设置角色权限
*/
public function authorize()
{
$AuthAccess = Db::name("AuthAccess");
$adminMenuModel = new AdminMenuModel();
//角色ID
$roleId = $this->request->param("id", 0, 'intval');
if (empty($roleId)) {
$this->error("参数错误!");
}
$tree = new Tree();
$tree->icon = ['│ ', '├─ ', '└─ '];
$tree->nbsp = '&nbsp;&nbsp;&nbsp;';
$result = $adminMenuModel->menuCache();
$newMenus = [];
$privilegeData = $AuthAccess->where(["role_id" => $roleId])->colu
mn("rule_name");//获取权限表数据
foreach ($result as $m) {
$newMenus[$m['id']] = $m;
}
foreach ($result as $n => $t) {
$result[$n]['checked'] = ($this->_isChecked($t, $privile
geData)) ? ' checked' : '';
$result[$n]['level'] = $this->_getLevel($t['id'], $new
Menus);
$result[$n]['style'] = empty($t['parent_id']) ? '' : '
控制器
- 36 - 本文档使用 看云 构建display:none;';
$result[$n]['parentIdNode'] = ($t['parent_id']) ? ' class="ch
ild-of-node-' . $t['parent_id'] . '"' : '';
}
$str = "<tr id='node-\$id'\$parentIdNode style='\$style'>
<td style='padding-left:30px;'>\$spacer<input type='ch
eckbox' name='menuId[]' value='\$id' level='\$level' \$checked onclick='j
avascript:checknode(this);'> \$name</td>
</tr>";
$tree->init($result);
$category = $tree->getTree(0, $str);
$this->assign("category", $category);
$this->assign("roleId", $roleId);
return $this->fetch();
}
/**
* 检查指定菜单是否有权限
* @param array $menu menu表中数组
* @param $privData
* @return bool
*/
private function _isChecked($menu, $privData)
{
$app = $menu['app'];
$model = $menu['controller'];
$action = $menu['action'];
$name = strtolower("$app/$model/$action");
if ($privData) {
if (in_array($name, $privData)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* 获取菜单深度
* @param $id
* @param array $array
* @param int $i
* @return int
*/
protected function _getLevel($id, $array = [], $i = 0)
{
if ($array[$id]['parent_id'] == 0 || empty($array[$array[$id]['pa
rent_id']]) || $array[$id]['parent_id'] == $id) {
return $i;
} else {
控制器
- 37 - 本文档使用 看云 构建 $i++;
return $this->_getLevel($array[$id]['parent_id'], $array, $i)
;
}
}
}
控制器
- 38 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.js"></scrip
t>
</head>
<body>
<form class="js-ajax-form" action="{:url('rbac/authorizePost')}" method="
post">
<div class="table_full">
<table class="table table-bordered" id="authrule-tree">
<tbody>
{$category}
</tbody>
</table>
</div>
<div class="form-actions">
<input type="hidden" name="roleId" value="{$roleId}"/>
<button class="btn btn-primary js-ajax-submit" type="submit">保存<
/button>
</div>
</form>
<script src="/static/js/treeTable/treeTable.js"></script>
<link rel="stylesheet" href="/static/js/treeTable/treeTable.css">
<script type="text/javascript">
//treeeTable初始化
$(function () {
$("#authrule-tree").treeTable({
indent: 20
});
})
//选择
function checknode(obj) {
var chk = $("input[type='checkbox']");
var count = chk.length;
var num = chk.index(obj);
var level_top = level_bottom = chk.eq(num).attr('level');
视图
- 39 - 本文档使用 看云 构建 for (var i = num; i >= 0; i--) {
var le = chk.eq(i).attr('level');
if (le < level_top) {
chk.eq(i).prop("checked", true);
var level_top = level_top - 1;
}
}
for (var j = num + 1; j < count; j++) {
var le = chk.eq(j).attr('level');
if (chk.eq(num).prop("checked")) {
if (le > level_bottom) {
chk.eq(j).prop("checked", true);
}
else if (le == level_bottom) {
break;
}
} else {
if (le > level_bottom) {
chk.eq(j).prop("checked", false);
} else if (le == level_bottom) {
break;
}
}
}
}
</script>
</body>
</html>
而如果运用的是 thinkcmf 的wind.js话,加载CSS和JS,必须这样用
$(function () {
Wind.css('treeTable');
Wind.use('treeTable', function () {
$("#authrule-tree").treeTable({
indent: 20
});
});
});
视图
- 40 - 本文档使用 看云 构建模型
代码
>注:需要引用 Cache 缓存机制,所取 admin_menu 表
<?php
namespace app\agent\model;
use think\Model;
use think\Cache;
class AdminMenuModel extends Model
{
/**
* 更新缓存
* @param $data
* @return array
*/
public function menuCache($data = null)
{
if (empty($data)) {
$data = $this->order("list_order", "ASC")->column('');
Cache::set('Menu', $data, 0);
} else {
Cache::set('Menu', $data, 0);
}
return $data;
}
}
模型
- 41 - 本文档使用 看云 构建权限设置提交
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class RbacController extends Controller
{
/**
* 角色授权提交
*/
public function authorizePost()
{
if ($this->request->isPost()) {
$roleId = $this->request->param("roleId", 0, 'intval');
if (!$roleId) {
$this->error("需要授权的角色不存在!");
}
if (is_array($this->request->param('menuId/a')) && count($thi
s->request->param('menuId/a')) > 0) {
//先删除后插入
Db::name("authAccess")->where(["role_id" => $roleId, 'typ
e' => 'admin_url'])->delete();
foreach ($_POST['menuId'] as $menuId) {
$menu = Db::name("adminMenu")->where(["id" => $menuId
])->field("app,controller,action")->find();
if ($menu) {
$app = $menu['app'];
$model = $menu['controller'];
$action = $menu['action'];
$name = strtolower("$app/$model/$action");
Db::name("authAccess")->insert(["role_id" => $rol
eId, "rule_name" => $name, 'type' => 'admin_url']);
}
}
$this->success("授权成功!");
} else {
//当没有数据时,清除当前角色授权
Db::name("authAccess")->where(["role_id" => $roleId])->de
lete();
$this->error("没有接收到数据,执行清除授权成功!");
}
}
}
权限设置提交
- 42 - 本文档使用 看云 构建}
权限设置提交
- 43 - 本文档使用 看云 构建用户 user
用户 user
- 44 - 本文档使用 看云 构建数据表

-- ----------------------------
-- Table structure for cmf_user
-- ----------------------------
DROP TABLE IF EXISTS `cmf_user`;
CREATE TABLE `cmf_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_type` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '用户类型;1
:admin;2:会员',
`sex` tinyint(2) NOT NULL DEFAULT '0' COMMENT '性别;0:保密,1:男,2:女',
`birthday` int(11) NOT NULL DEFAULT '0' COMMENT '生日',
`last_login_time` int(11) NOT NULL DEFAULT '0' COMMENT '最后登录时间',
`score` int(11) NOT NULL DEFAULT '0' COMMENT '用户积分',
`coin` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '金币',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '注册时间',
`user_status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '用户状态
;0:禁用,1:正常,2:未验证',
`user_login` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_
ci NOT NULL DEFAULT '' COMMENT '用户名',
`user_pass` varchar(64) NOT NULL DEFAULT '' COMMENT '登录密码;cmf_passwo
rd加密',
`user_nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unico
de_ci NOT NULL DEFAULT '' COMMENT '用户昵称',
`user_email` varchar(100) NOT NULL DEFAULT '' COMMENT '用户登录邮箱',
`user_url` varchar(100) NOT NULL DEFAULT '' COMMENT '用户个人网址',
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '用户头像',
`signature` varchar(255) NOT NULL DEFAULT '' COMMENT '个性签名',
`last_login_ip` varchar(15) NOT NULL DEFAULT '' COMMENT '最后登录ip',
`user_activation_key` varchar(60) NOT NULL DEFAULT '' COMMENT '激活码',
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '用户手机号',
`more` text COMMENT '扩展属性',
PRIMARY KEY (`id`),
KEY `user_login` (`user_login`),
KEY `user_nickname` (`user_nickname`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- ----------------------------
-- Records of cmf_user
-- ----------------------------
INSERT INTO `cmf_user` VALUES ('1', '1', '0', '0', '1508116965', '0', '0'
, '1508116894', '1', 'admin', '###f12c0841f51eab7e6e33b8b9204b05d7', 'adm
in', '[email protected]', '', '', '', '127.0.0.1', '', '', null);
数据表
- 45 - 本文档使用 看云 构建数据表
- 46 - 本文档使用 看云 构建列表
列表
- 47 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use app\agent\model\UserModel as UserModel;
use think\Controller;
class UserController extends Controller
{
/**
* 管理员列表
*/
public function index()
{
$userModel = new UserModel();
$where = ["user_type" => 1];
/**搜索条件**/
$user_login = $this->request->param('user_login');
$user_email = trim($this->request->param('user_email'));
if ($user_login) {
$where['user_login'] = ['like', "%$user_login%"];
}
if ($user_email) {
$where['user_email'] = ['like', "%$user_email%"];;
}
$users = $userModel
->where($where)
->order("id DESC")
->paginate(10);
// 获取分页显示
$page = $users->render();
$this->assign("page", $page);
$this->assign("users", $users);
return $this->fetch();
}
}
控制器
- 48 - 本文档使用 看云 构建控制器
- 49 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<form class="well form-inline margin-top-20" method="post" action="{:url(
'User/index')}">
用户名:
<input type="text" class="form-control" name="user_login" style="widt
h: 120px;" value="{:input('request.user_login/s','')}" placeholder="请输入
用户名">
邮箱:
<input type="text" class="form-control" name="user_email" style="widt
h: 120px;" value="{:input('request.user_email/s','')}" placeholder="请输入
邮箱">
<input type="submit" class="btn btn-primary" value="搜索" />
<a class="btn btn-danger" href="{:url('User/index')}">清空</a>
</form>
<table class="table table-hover table-bordered">
<thead>
<tr>
<th width="50">ID</th>
<th>用户名</th>
<th>最后登录IP</th>
<th>最后登录时间</th>
<th>邮箱</th>
<th>状态</th>
<th width="130">操作</th>
</tr>
</thead>
<tbody>
<foreach name="users" item="vo">
<tr>
<td>{$vo.id}</td>
<td><if condition="$vo['user_url']"><a href="{$vo.user_url}"
target="_blank" title="{$vo.signature}">{$vo.user_login}</a><else />{$vo.
user_login}</if></td>
<td>{$vo.last_login_ip}</td>
<td>
<if condition="$vo['last_login_time'] eq 0">
该用户还没登陆过
<else />
视图
- 50 - 本文档使用 看云 构建 {$vo.last_login_time}
</if>
</td>
<td>{$vo.user_email}</td>
<td>{$vo.user_status}</td>
<td>
<if condition="$vo['id'] eq 1 || $vo['id'] eq cmf_get_cur
rent_admin_id()">
<font color="#cccccc">编辑</font> <font color="#ccccc
c">删除</font>
<if condition="$vo['user_status'] eq 1">
<font color="#cccccc">已拉黑</font>
<else />
<font color="#cccccc">正常</font>
</if>
<else />
<a href='{:url("user/edit",array("id"=>$vo["id"]))}'>
编辑</a>
<a class="js-ajax-delete" href="{:url('user/delete',a
rray('id'=>$vo['id']))}">删除</a>
<if condition="$vo['user_status'] eq 1">
<a href="{:url('user/ban',array('id'=>$vo['id']))
}" class="js-ajax-dialog-btn" data-msg="您确定要拉黑此用户吗?">拉黑</a>
<else />
<a href="{:url('user/cancelban',array('id'=>$vo['
id']))}" class="js-ajax-dialog-btn" data-msg="您确定要启用此用户吗?">启用</a
>
</if>
</if>
</td>
</tr>
</foreach>
</tbody>
</table>
<div class="pagination">{$page}</div>
</body>
</html>
视图
- 51 - 本文档使用 看云 构建模型
代码
<?php
namespace app\agent\model;
use think\Model;
class UserModel extends Model
{
protected function getUserStatusAttr($value)
{
$status = [0=>'已拉黑',1=>'正常',2=>'未验证'];
return $status[$value];
}
// 合约开始时间 读取器
protected function getLastLoginTimeAttr($value)
{
return date('Y-m-d H:i:s', $value);
}
}
模型
- 52 - 本文档使用 看云 构建添加
控制器
视图
添加
- 53 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class UserController extends Controller
{
/**
* 管理员添加
*/
public function add()
{
$roles = Db::name('role')->where(['status' => 1])->order("id DESC
")->select();
$this->assign("roles", $roles);
return $this->fetch();
}
}
控制器
- 54 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<form method="post" class="form-horizontal js-ajax-form margin-top-20" ac
tion="{:url('user/addpost')}">
<div class="form-group">
<label for="input-user_login" class="col-sm-2 control-label"><spa
n class="form-required">*</span>用户名</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_login"
name="user_login">
</div>
</div>
<div class="form-group">
<label for="input-user_pass" class="col-sm-2 control-label"><span
class="form-required">*</span>密码</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_pass"
name="user_pass" placeholder="******">
</div>
</div>
<div class="form-group">
<label for="input-user_email" class="col-sm-2 control-label"><spa
n class="form-required">*</span>邮箱</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_email"
name="user_email">
</div>
</div>
<div class="form-group">
<label for="input-user_email" class="col-sm-2 control-label"><spa
n class="form-required">*</span>角色</label>
<div class="col-md-6 col-sm-10">
<foreach name="roles" item="vo">
<label class="checkbox-inline">
<input value="{$vo.id}" type="checkbox" name="role_id
[]" <if condition="cmf_get_current_admin_id() neq 1 && $vo['id'] eq 1">di
sabled="true"</if>>{$vo.name}
</label>
</foreach>
</div>
视图
- 55 - 本文档使用 看云 构建 </div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary js-ajax-submit">
填加</button>
</div>
</div>
</form>
</body>
</html>
视图
- 56 - 本文档使用 看云 构建添加提交
控制器
验证器
添加提交
- 57 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class UserController extends Controller
{
/**
* 管理员添加提交
*/
public function addPost()
{
if ($this->request->isPost()) {
if (!empty($_POST['role_id']) && is_array($_POST['role_id']))
{
$role_ids = $_POST['role_id'];
unset($_POST['role_id']);
$result = $this->validate($this->request->param(), 'User'
);
if ($result !== true) {
$this->error($result);
} else {
$_POST['user_pass'] = cmf_password($_POST['user_pass'
]);
$result = DB::name('user')->insertGetId($
_POST);
if ($result !== false) {
foreach ($role_ids as $role_id) {
if (cmf_get_current_admin_id() != 1 && $role_
id == 1) {
$this->error("为了网站的安全,非网站创建者不可
创建超级管理员!");
}
Db::name('RoleUser')->insert(["role_id" => $r
ole_id, "user_id" => $result]);
}
$this->success("添加成功!", url("user/index"));
} else {
$this->error("添加失败!");
}
}
} else {
$this->error("请为此用户指定角色!");
}
控制器
- 58 - 本文档使用 看云 构建 }
}
}
控制器
- 59 - 本文档使用 看云 构建验证器
代码
<?php
namespace app\agent\validate;
use think\Validate;
class UserValidate extends Validate
{
protected $rule = [
'user_login' => 'require|unique:user,user_login',
'user_pass' => 'require',
'user_email' => 'require|email|unique:user,user_email',
];
protected $message = [
'user_login.require' => '用户不能为空',
'user_login.unique' => '用户名已存在',
'user_pass.require' => '密码不能为空',
'user_email.require' => '邮箱不能为空',
'user_email.email' => '邮箱不正确',
'user_email.unique' => '邮箱已经存在',
];
protected $scene = [
'add' => ['user_login', 'user_pass', 'user_email'],
'edit' => ['user_login', 'user_email'],
];
}
验证器
- 60 - 本文档使用 看云 构建编辑
控制器
视图
编辑
- 61 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class UserController extends Controller
{
/**
* 管理员编辑
*/
public function edit()
{
$id = $this->request->param('id', 0, 'intval');
$roles = DB::name('role')->where(['status' => 1])->order("id DESC
")->select();
$this->assign("roles", $roles);
$role_ids = DB::name('RoleUser')->where(["user_id" => $id])->colu
mn("role_id");
$this->assign("role_ids", $role_ids);
$user = DB::name('user')->where(["id" => $id])->find();
$this->assign($user);
return $this->fetch();
}
}
控制器
- 62 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<form method="post" class="form-horizontal js-ajax-form margin-top-20" ac
tion="{:url('User/editPost')}">
<div class="form-group">
<label for="input-user_login" class="col-sm-2 control-label"><spa
n class="form-required">*</span>用户名</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_login"
name="user_login" value="{$user_login}">
</div>
</div>
<div class="form-group">
<label for="input-user_pass" class="col-sm-2 control-label"><span
class="form-required">*</span>密码</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_pass"
name="user_pass" value="" placeholder="******">
</div>
</div>
<div class="form-group">
<label for="input-user_email" class="col-sm-2 control-label"><spa
n class="form-required">*</span>邮箱</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-user_email"
name="user_email" value="{$user_email}">
</div>
</div>
<div class="form-group">
<label for="input-user_email" class="col-sm-2 control-label"><spa
n class="form-required">*</span>角色</label>
<div class="col-md-6 col-sm-10">
<foreach name="roles" item="vo">
<label class="checkbox-inline">
<php>$role_id_checked=in_array($vo['id'],$role_ids)?"
checked":"";</php>
<input value="{$vo.id}" type="checkbox" name="role_id
[]" {$role_id_checked} <if condition="cmf_get_current_admin_id() neq 1 &&
$vo['id'] eq 1">disabled="true"</if>>{$vo.name}
</label>
</foreach>
视图
- 63 - 本文档使用 看云 构建 </div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="hidden" name="id" value="{$id}" />
<button type="submit" class="btn btn-primary js-ajax-submit">
保存</button>
<a class="btn btn-default" href="javascript:history.back(-1);
">返回</a>
</div>
</div>
</form>
</body>
</html>
视图
- 64 - 本文档使用 看云 构建编辑提交
控制器
验证器
编辑提交
- 65 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class UserController extends Controller
{
/**
* 管理员编辑提交
*/
public function editPost()
{
if ($this->request->isPost()) {
if (!empty($_POST['role_id']) && is_array($_POST['role_id']))
{
if (empty($_POST['user_pass'])) {
unset($_POST['user_pass']);
} else {
$_POST['user_pass'] = cmf_password($_POST['user_pass'
]);
}
$role_ids = $this->request->param('role_id/a');
unset($_POST['role_id']);
$result = $this->validate($this->request->param(), 'User.
edit');
if ($result !== true) {
// 验证失败 输出错误信息
$this->error($result);
} else {
$result = DB::name('user')->update($_POST);
if ($result !== false) {
$uid = $this->request->param('id', 0, 'intval');
DB::name("RoleUser")->where(["user_id" => $uid])-
>delete();
foreach ($role_ids as $role_id) {
if (cmf_get_current_admin_id() != 1 && $role_
id == 1) {
$this->error("为了网站的安全,非网站创建者不可
创建超级管理员!");
}
DB::name("RoleUser")->insert(["role_id" => $r
ole_id, "user_id" => $uid]);
}
$this->success("保存成功!");
控制器
- 66 - 本文档使用 看云 构建 } else {
$this->error("保存失败!");
}
}
} else {
$this->error("请为此用户指定角色!");
}
}
}
}
控制器
- 67 - 本文档使用 看云 构建验证器
代码
注意,看 edit 场景
<?php
namespace app\agent\validate;
use think\Validate;
class UserValidate extends Validate
{
protected $rule = [
'user_login' => 'require|unique:user,user_login',
'user_pass' => 'require',
'user_email' => 'require|email|unique:user,user_email',
];
protected $message = [
'user_login.require' => '用户不能为空',
'user_login.unique' => '用户名已存在',
'user_pass.require' => '密码不能为空',
'user_email.require' => '邮箱不能为空',
'user_email.email' => '邮箱不正确',
'user_email.unique' => '邮箱已经存在',
];
protected $scene = [
'add' => ['user_login', 'user_pass', 'user_email'],
'edit' => ['user_login', 'user_email'],
];
}
验证器
- 68 - 本文档使用 看云 构建删除
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class UserController extends Controller
{
/**
* 管理员删除
*/
public function delete()
{
$id = $this->request->param('id', 0, 'intval');
if ($id == 1) {
$this->error("最高管理员不能删除!");
}
if (Db::name('user')->delete($id) !== false) {
Db::name("RoleUser")->where(["user_id" => $id])->delete();
$this->success("删除成功!");
} else {
$this->error("删除失败!");
}
}
}
删除
- 69 - 本文档使用 看云 构建停用启用
停用启用
- 70 - 本文档使用 看云 构建角色用户中间表role_user
数据表
DROP TABLE IF EXISTS `cmf_role_user`;
CREATE TABLE `cmf_role_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`role_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '角色 id',
`user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
PRIMARY KEY (`id`),
KEY `group_id` (`role_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户角色对应
表';
角色用户中间表role_user
- 71 - 本文档使用 看云 构建菜单管理
数据表
表格折叠列表
全部列表
填加
填加提交
编辑
编辑提交
删除
导入菜单
导出菜单
排序
菜单管理
- 72 - 本文档使用 看云 构建数据表
数据字典
字段 说明
id
parent_id 父菜单id
type 菜单类型;1:有界面可访问菜单,2:无界面可访问菜单,0:只作为菜单
status 状态;1:显示,0:不显示
list_order 排序
app 应用名
controller 控制器名
action 操作名称
param 额外参数
name 菜单名称
icon 菜单图标
remark 备注
数据表
DROP TABLE IF EXISTS `cmf_admin_menu`;
CREATE TABLE `cmf_admin_menu` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父菜单id',
`type` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '菜单类型;1:有界
面可访问菜单,2:无界面可访问菜单,0:只作为菜单',
`status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态;1:显示,0
:不显示',
`list_order` float NOT NULL DEFAULT '10000' COMMENT '排序',
数据表
- 73 - 本文档使用 看云 构建 `app` varchar(15) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '应用名
',
`controller` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT
'控制器名',
`action` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '操
作名称',
`param` varchar(50) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '额外
参数',
`name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT
NULL DEFAULT '' COMMENT '菜单名称',
`icon` varchar(20) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '菜单
图标',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
NOT NULL DEFAULT '' COMMENT '备注',
PRIMARY KEY (`id`),
KEY `status` (`status`),
KEY `parentid` (`parent_id`),
KEY `model` (`controller`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台菜单表';
数据表
- 74 - 本文档使用 看云 构建表格折叠列表
折叠表格
展开表格
表格折叠列表
- 75 - 本文档使用 看云 构建控制器
思路
一:存储 session名admin_menu_index ,有什么用?
二:查询 AdminMenu 表得到数组
三:利用 Tree 变换的数组 形成树状结构
四:组合成 treeTable 插件的形式(这里可能是比较旧的方式)
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
use tree\Tree;
class MenuController extends Controller
{
/**
* 后台菜单管理
*/
public function index()
{
session('admin_menu_index', 'Menu/index');
$result = Db::name('AdminMenu')->order(["list_order" => "ASC"
])->select()->toArray();
$tree = new Tree();
$tree->icon = ['&nbsp;&nbsp;&nbsp;│ ', '&nbsp;&nbsp;&nbsp;├─ ', '
&nbsp;&nbsp;&nbsp;└─ '];
$tree->nbsp = '&nbsp;&nbsp;&nbsp;';
$newMenus = [];
foreach ($result as $m) {
$newMenus[$m['id']] = $m;
}
foreach ($result as $key => $value) {
$result[$key]['parent_id_node'] = ($value['parent_id']) ? ' c
lass="child-of-node-' . $value['parent_id'] . '"' : '';
$result[$key]['style'] = empty($value['parent_id'])
? '' : 'display:none;';
$result[$key]['str_manage'] = '<a href="' . url("Menu/add
", ["parent_id" => $value['id'], "menu_id" => $this->request->param("menu
_id")])
. '">添加子菜单</a> <a href="' . url("Menu/edit", ["id" =>
$value['id'], "menu_id" => $this->request->param("menu_id")])
. '">编辑</a> <a class="js-ajax-delete" href="' . url("Me
控制器
- 76 - 本文档使用 看云 构建nu/delete", ["id" => $value['id'], "menu_id" => $this->request->param("me
nu_id")]) . '">删除</a> ';
$result[$key]['status'] = $value['status'] ? '显示' :
'隐藏';
if (APP_DEBUG) {
$result[$key]['app'] = $value['app'] . "/" . $value['cont
roller'] . "/" . $value['action'];
}
}
$tree->init($result);
$str = "<tr id='node-\$id' \$parent_id_node style='\$style'>
<td style='padding-left:20px;'><input name='list_
orders[\$id]' type='text' size='3' value='\$list_order' class='input inpu
t-order'></td>
<td>\$id</td>
<td>\$spacer\$name</td>
<td>\$app</td>
<td>\$status</td>
<td>\$str_manage</td>
</tr>";
$category = $tree->getTree(0, $str);
$this->assign("category", $category);
return $this->fetch();
}
}
控制器
- 77 - 本文档使用 看云 构建视图
思路
一:循环得到数据
二:加载 jquery , treeTable 插件 相关,并初始化
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<table class="table table-hover table-bordered table-list" id="menus-tabl
e">
<thead>
<tr>
<th width="80">排序</th>
<th width="50">ID</th>
<th>菜单名称</th>
<th>操作</th>
<th width="80">状态</th>
<th width="180">操作</th>
</tr>
</thead>
<tbody>
{$category}
</tbody>
</table>
<!--中间内容/end-->
<!--js/start-->
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<!--tree/start-->
<script src="http://www.ijquery.cn/js/treeTable/treeTable.js"></script>
<link href="http://www.ijquery.cn/js/treeTable/treeTable.css" rel="styles
heet">
<!--tree/end-->
<script>
$(function() {
$("#menus-table").treeTable({
expandable: true
视图
- 78 - 本文档使用 看云 构建 });
})
</script>
<!--js/end-->
</body>
</html>
说明
如果用 thinkcmf 的封装内容的话,需要这样加载!
<script src="__TMPL__/public/assets/js/jquery-1.10.2.min.js"></script>
<script src="__STATIC__/js/wind.js"></script>
<script>
$(document).ready(function() {
Wind.css('treeTable');
Wind.use('treeTable', function() {
$("#menus-table").treeTable({
indent : 20
});
});
});
</script>
视图
- 79 - 本文档使用 看云 构建全部列表
图示
全部列表
- 80 - 本文档使用 看云 构建控制器
思路
比较简单,查询 并赋值。
这里也保存 admin_menu_index Menu/lists ,什么作用呢?
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class MenuController extends Controller
{
/**
* 后台所有菜单列表
*/
public function lists()
{
session('admin_menu_index', 'Menu/lists');
$result = Db::name('AdminMenu')->order(["app" => "ASC", "controll
er" => "ASC", "action" => "ASC"])->select();
$this->assign("menus", $result);
return $this->fetch();
}
}
控制器
- 81 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<form class="form-horizontal js-ajax-form" action="{:url('menu/listorders
')}" method="post">
<div class="table-actions">
<a class="btn btn-primary btn-sm js-ajax-dialog-btn" href
="{:url('menu/exportAppMenuDefaultLang')}" data-msg="您确定生成菜单多语言包吗
?请确保应用目录下lang目录可写!">生成菜单多语言包</a>
<a class="btn btn-warning btn-sm" href="{:url('menu/getac
tions')}">导入新菜单</a>
</div>
<div class="alert alert-warning" style="margin: 0 0 5px 0;">
请在开发人员指导下进行以上操作!
</div>
<table class="table table-hover table-bordered table-list">
<thead>
<tr>
<th width="50">ID</th>
<th>菜单英文名称</th>
<th width="50">状态</th>
<th width="90">管理操作</th>
</tr>
</thead>
<foreach name="menus" item="vo">
<tr>
<td>{$vo.id}</td>
<td>{$vo.name}:{$vo.app}/{$vo.controller}/{$vo.ac
tion}</td>
<td>
<if condition="$vo['status'] eq 1">
显示
<else />
隐藏
</if>
</td>
<td>
<a href="{:url('menu/edit',array('id'=>$v
o['id']))}">编辑</a>
<a class="js-ajax-delete" href="{:url('me
视图
- 82 - 本文档使用 看云 构建nu/delete',array('id'=>$vo['id']))}">删除</a>
</td>
</tr>
</foreach>
<tfoot>
<tr>
<th width="50">ID</th>
<th>菜单英文名称</th>
<th width="40">状态</th>
<th width="80">管理操作</th>
</tr>
</tfoot>
</table>
</form>
<!--中间内容/end-->
</body>
</html>
视图
- 83 - 本文档使用 看云 构建填加
图示
填加一级菜单入口
http://thinkcmf/admin/menu/add
填加二三级菜单入口
链接:http://thinkcmf/admin/menu/add/parent_id/71.html
填加内容
填加
- 84 - 本文档使用 看云 构建填加
- 85 - 本文档使用 看云 构建控制器
思路
一:获取 parent_id ,默认为0
二:查询全部菜单,
三: foreach 形成带有 selected 的新数组
四:用 Tree 类形成带有树形结构结构的内容
五:赋值
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
use tree\Tree;
class MenuController extends Controller
{
/**
* 后台菜单添加
*/
public function add()
{
$tree = new Tree();
$parentId = $this->request->param("parent_id", 0, 'intval');
$result = Db::name('AdminMenu')->order(["list_order" => "ASC"])
->select();
$array = [];
foreach ($result as $r) {
$r['selected'] = $r['id'] == $parentId ? 'selected' : '';
$array[] = $r;
}
$str = "<option value='\$id' \$selected>\$spacer \$name</option>"
;
$tree->init($array);
$selectCategory = $tree->getTree(0, $str);
$this->assign("select_category", $selectCategory);
return $this->fetch();
}
}
要点解析
控制器
- 86 - 本文档使用 看云 构建如图所示,这里是关键,形成一个带 selected 的新数组
控制器
- 87 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<form method="post" class="form-horizontal js-ajax-form margin-top-20" ac
tion="{:url('menu/addPost')}">
<div class="form-group">
<label for="input-parent_id" class="col-sm-2 control-label"><span
class="form-required">*</span>上级</label>
<div class="col-md-6 col-sm-10">
<select class="form-control" name="parent_id" id="input-paren
t_id">
<option value="0">作为一级菜单</option>{$select_category}
</select>
</div>
</div>
<div class="form-group">
<label for="input-name" class="col-sm-2 control-label"><span clas
s="form-required">*</span>名称</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-name" name=
"name">
</div>
</div>
<div class="form-group">
<label for="input-app" class="col-sm-2 control-label"><span class
="form-required">*</span>应用</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-app" name="
app">
</div>
</div>
<div class="form-group">
<label for="input-controller" class="col-sm-2 control-label"><spa
n class="form-required">*</span>控制器</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-controller"
name="controller">
</div>
</div>
<div class="form-group">
视图
- 88 - 本文档使用 看云 构建 <label for="input-action" class="col-sm-2 control-label"><span cl
ass="form-required">*</span>方法</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-action" nam
e="action">
</div>
</div>
<div class="form-group">
<label for="input-param" class="col-sm-2 control-label">参数</labe
l>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-param" name
="param">
<p class="help-block">例:id=3&amp;p=3</p>
</div>
</div>
<div class="form-group">
<label for="input-icon" class="col-sm-2 control-label">图标</label
>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-icon" name=
"icon">
<p class="help-block">
<a href="http://www.thinkcmf.com/font/icons" target="_bla
nk">选择图标</a> 不带前缀fa-,如fa-user => user
</p>
</div>
</div>
<div class="form-group">
<label for="input-remark" class="col-sm-2 control-label">备注</lab
el>
<div class="col-md-6 col-sm-10">
<textarea class="form-control" id="input-remark" name="remark
"></textarea>
</div>
</div>
<div class="form-group">
<label for="input-status" class="col-sm-2 control-label">状态</lab
el>
<div class="col-md-6 col-sm-10" id="input-status">
<select class="form-control" name="status">
<option value="1">在左侧菜单显示</option>
<option value="0">在左侧菜单隐藏</option>
</select>
</div>
</div>
<div class="form-group">
<label for="input-type" class="col-sm-2 control-label">类型</label
>
<div class="col-md-6 col-sm-10">
<select class="form-control" name="type" id="input-type">
<option value="1">有界面可访问菜单</option>
<option value="2">无界面可访问菜单</option>
<option value="0">只作为菜单</option>
</select>
</div>
视图
- 89 - 本文档使用 看云 构建 </div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary js-ajax-submit">
填加</button>
</div>
</div>
</form>
<!--中间内容/end-->
</body>
</html>
视图
- 90 - 本文档使用 看云 构建填加提交
控制器
验证器
填加提交
- 91 - 本文档使用 看云 构建控制器
思路
比较简单
一:提交验证器验证
二:插入到数据表 admin_menu
三:插入到 auth_rule 表(可选)
四:导出到 admin_menu.php 语言包!(可选)
代码
>特别注意下边的注释代码
> 注释一 的代码是为了写入到 auth_rule 表当中的,如果想写入的话,这里可以把注释
去掉,如果不用可以删除!
> 注释二 的代码是为了导出语言包的!如果不用可以删除!导出需要方法
_exportAppMenuDefaultLang !
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class MenuController extends Controller
{
/**
* 后台菜单添加提交保存
*/
public function addPost()
{
if ($this->request->isPost()) {
$result = $this->validate($this->request->param(), 'AdminMenu
');
if ($result !== true) {
$this->error($result);
} else {
$data = $this->request->param();
Db::name('AdminMenu')->strict(false)->field(true)->insert
($data);

// 注释一:这里写入到 auth_rule
控制器
- 92 - 本文档使用 看云 构建// $app = $this->request->param("app");
// $controller = $this->request->param("controller");
// $action = $this->request->param("action");
// $param = $this->request->param("param");
// $authRuleName = "$app/$controller/$action";
// $menuName = $this->request->param("name");
// $findAuthRuleCount = Db::name('AuthRule')->where([
// 'app' => $app,
// 'name' => $authRuleName,
// 'type' => 'admin_url'
// ])->count();
// if (empty($findAuthRuleCount)) {
// Db::name('AuthRule')->insert([
// "name" => $authRuleName,
// "app" => $app,
// "type" => "admin_url",
// "title" => $menuName,
// 'param' => $param,
// ]);
// }
$sessionAdminMenuIndex = session('admin_menu_index');
$to = empty($sessionAdminMenuIndex) ?
"Menu/index" : $sessionAdminMenuIndex;

// 注释二:这里导出表
// $this->_exportAppMenuDefaultLang();
$this->success("添加成功!", url($to));
}
}
}
}
导出后台菜单语言包方法
/**
* 导出后台菜单语言包
*/
private function _exportAppMenuDefaultLang()
{
$menus = Db::name('AdminMenu')->order(["app" => "ASC", "contr
oller" => "ASC", "action" => "ASC"])->select();
$langDir = config('DEFAULT_LANG');
$adminMenuLang = CMF_ROOT . "data/lang/" . $langDir . "/admin_menu.ph
p";
if (!empty($adminMenuLang) && !file_exists_case($adminMenuLang)) {
mkdir(dirname($adminMenuLang), 0777, true);
}
控制器
- 93 - 本文档使用 看云 构建 $lang = [];
foreach ($menus as $menu) {
$lang_key = strtoupper($menu['app'] . '_' . $menu['control
ler'] . '_' . $menu['action']);
$lang[$lang_key] = $menu['name'];
}
$langStr = var_export($lang, true);
$langStr = preg_replace("/\s+\d+\s=>\s(\n|\r)/", "\n", $langStr);
if (!empty($adminMenuLang)) {
file_put_contents($adminMenuLang, "<?php\nreturn $langStr;");
}
}
>问一:那数据导出到哪了?
答:在 /data/lang/zh-cn/admin_menu.php
>问二:数据表及文件数据格式是什么呢?
答:如图:
1、操作完成列表显示
2、数据库
控制器
- 94 - 本文档使用 看云 构建3、admin_menu.php 文件
控制器
- 95 - 本文档使用 看云 构建验证器
代码
<?php
namespace app\admin\validate;
use think\Validate;
use think\Db;
class AdminMenuValidate extends Validate
{
protected $rule = [
'name' => 'require',
'app' => 'require',
'controller' => 'require',
'parent_id' => 'checkParentId',
'action' => 'require|unique:AdminMenu,app^controller^action',
];
protected $message = [
'name.require' => '名称不能为空',
'app.require' => '应用不能为空',
'parent_id' => '超过了4级',
'controller.require' => '名称不能为空',
'action.require' => '名称不能为空',
'action.unique' => '同样的记录已经存在!',
];
protected $scene = [
'add' => ['name', 'app', 'controller', 'action', 'parent_id'],
'edit' => ['name', 'app', 'controller', 'action', 'id', 'parent_i
d'],
];
// 自定义验证规则:菜单只能三级
protected function checkParentId($value)
{
$find = Db::name('AdminMenu')->where(["id" => $value])->value('pa
rent_id');
if ($find) {
$find2 = Db::name('AdminMenu')->where(["id" => $find])->value
('parent_id');
if ($find2) {
$find3 = Db::name('AdminMenu')->where(["id" => $find2])->
value('parent_id');
if ($find3) {
return false;
}
验证器
- 96 - 本文档使用 看云 构建 }
}
return true;
}
}
验证器
- 97 - 本文档使用 看云 构建编辑
控制器
视图
编辑
- 98 - 本文档使用 看云 构建控制器
例如访问: http://thinkcmf/agent/menu/edit/id/10
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
use tree\Tree;
class MenuController extends Controller
{
/**
* 后台菜单编辑
*/
public function edit()
{
$tree = new Tree();
$id = $this->request->param("id", 0, 'intval');
$rs = Db::name('AdminMenu')->where(["id" => $id])->find();
$result = Db::name('AdminMenu')->order(["list_order" => "ASC"])->
select();
$array = [];
foreach ($result as $r) {
$r['selected'] = $r['id'] == $rs['parent_id'] ? 'selected' :
'';
$array[] = $r;
}
$str = "<option value='\$id' \$selected>\$spacer \$name</option>"
;
$tree->init($array);
$selectCategory = $tree->getTree(0, $str);
$this->assign("data", $rs);
$this->assign("select_category", $selectCategory);
return $this->fetch();
}

}
要点解析
不多说,如图:
控制器
- 99 - 本文档使用 看云 构建控制器
- 100 - 本文档使用 看云 构建视图
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<form method="post" class="form-horizontal js-ajax-form margin-top-20" ac
tion="{:url('menu/editPost')}">
<div class="form-group">
<label for="input-parent_id" class="col-sm-2 control-label"><span
class="form-required">*</span>上级</label>
<div class="col-md-6 col-sm-10">
<select class="form-control" name="parent_id" id="input-paren
t_id">
<option value="0">作为一级菜单</option>{$select_category}
</select>
</div>
</div>
<div class="form-group">
<label for="input-name" class="col-sm-2 control-label"><span clas
s="form-required">*</span>名称</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-name" name=
"name" value="{$data.name}">
</div>
</div>
<div class="form-group">
<label for="input-app" class="col-sm-2 control-label"><span class
="form-required">*</span>应用</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-app" name="
app" value="{$data.app}">
</div>
</div>
<div class="form-group">
<label for="input-controller" class="col-sm-2 control-label"><spa
n class="form-required">*</span>控制器</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-controller"
name="controller" value="{$data.controller}">
</div>
</div>
<div class="form-group">
视图
- 101 - 本文档使用 看云 构建 <label for="input-action" class="col-sm-2 control-label"><span cl
ass="form-required">*</span>方法</label>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-action" nam
e="action" value="{$data.action}">
</div>
</div>
<div class="form-group">
<label for="input-param" class="col-sm-2 control-label">参数</labe
l>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-param" name
="param" value="{$data.param}">
<p class="help-block">例:id=3&amp;p=3</p>
</div>
</div>
<div class="form-group">
<label for="input-icon" class="col-sm-2 control-label">图标</label
>
<div class="col-md-6 col-sm-10">
<input type="text" class="form-control" id="input-icon" name=
"icon" value="{$data.icon}">
<p class="help-block">
<a href="http://www.thinkcmf.com/font/icons" target="_bla
nk">选择图标</a> 不带前缀fa-,如fa-user => user
</p>
</div>
</div>
<div class="form-group">
<label for="input-remark" class="col-sm-2 control-label">备注</lab
el>
<div class="col-md-6 col-sm-10">
<textarea class="form-control" id="input-remark" name="remark
">{$data.remark}</textarea>
</div>
</div>
<div class="form-group">
<label for="input-status" class="col-sm-2 control-label">状态</lab
el>
<div class="col-md-6 col-sm-10" id="input-status">
<select class="form-control" name="status">
<option value="1">在左侧菜单显示</option>
<php>$status_selected=empty($data['status'])?"selected":"
";</php>
<option value="0" {$status_selected}>在左侧菜单隐藏</option
>
</select>
</div>
</div>
<div class="form-group">
<label for="input-type" class="col-sm-2 control-label">类型</label
>
<div class="col-md-6 col-sm-10">
<select class="form-control" name="type" id="input-type">
<option value="1">有界面可访问菜单</option>
<php>$type2_selected=$data['type']==2?"selected":"";</php
视图
- 102 - 本文档使用 看云 构建>
<option value="2" {$type2_selected}>无界面可访问菜单</option
>
<php>$type_selected=$data['type']==0?"selected":"";</php>
<option value="0" {$type_selected}>只作为菜单</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="hidden" name="id" value="{$data.id}" />
<button type="submit" class="btn btn-primary js-ajax-submit">
{:lang('SAVE')}</button>
<a class="btn btn-default" href="{:url('menu/index')}">{:lang
('BACK')}</a>
</div>
</div>
</form>
<!--中间内容/end-->
</body>
</html>
视图
- 103 - 本文档使用 看云 构建编辑提交
控制器
验证器
编辑提交
- 104 - 本文档使用 看云 构建控制器
代码
注意:如果不需要插入 auth_rule 表, 注释一 部分代码可以不要
注意:如果不需要导出, 注释二 部分代码可以不要
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class MenuController extends Controller
{
/**
* 后台菜单编辑提交保存
*/
public function editPost()
{
if ($this->request->isPost()) {
$id = $this->request->param('id', 0, 'intval');
$oldMenu = Db::name('AdminMenu')->where(['id' => $id])->find(
);
$result = $this->validate($this->request->param(), 'AdminMenu
.edit');
if ($result !== true) {
$this->error($result);
} else {
Db::name('AdminMenu')->strict(false)->field(true)->update
($this->request->param());
// 注释一:下边全部是对 auth_rule 操作
// $app = $this->request->param("app");
// $controller = $this->request->param("controller");
// $action = $this->request->param("action");
// $param = $this->request->param("param");
// $authRuleName = "$app/$controller/$action";
// $menuName = $this->request->param("name");
//
// $findAuthRuleCount = Db::name('auth_rule')->where([
// 'app' => $app,
// 'name' => $authRuleName,
// 'type' => 'admin_url'
控制器
- 105 - 本文档使用 看云 构建// ])->count();
// if (empty($findAuthRuleCount)) {
// $oldApp = $oldMenu['app'];
// $oldController = $oldMenu['controller'];
// $oldAction = $oldMenu['action'];
// $oldName = "$oldApp/$oldController/$oldAction
";
// $findOldRuleId = Db::name('AuthRule')->where(["name
" => $oldName])->value('id');
// if (empty($findOldRuleId)) {
// Db::name('AuthRule')->insert([
// "name" => $authRuleName,
// "app" => $app,
// "type" => "admin_url",
// "title" => $menuName,
// "param" => $param
// ]);
// } else {
// Db::name('AuthRule')->where(['id' => $findOldRu
leId])->update([
// "name" => $authRuleName,
// "app" => $app,
// "type" => "admin_url",
// "title" => $menuName,
// "param" => $param]);
// }
// } else {
// Db::name('AuthRule')->where([
// 'app' => $app,
// 'name' => $authRuleName,
// 'type' => 'admin_url'
// ])->update(["title" => $menuName, 'param' => $param
]);
// }
// 注释二:导出数据
// $this->_exportAppMenuDefaultLang();
$this->success("保存成功!");
}
}
}
}
控制器
- 106 - 本文档使用 看云 构建验证器
代码
>这里的代码,和提交的一样,这里复制一份!不过要注意 验证场景
<?php
namespace app\admin\validate;
use think\Validate;
use think\Db;
class AdminMenuValidate extends Validate
{
protected $rule = [
'name' => 'require',
'app' => 'require',
'controller' => 'require',
'parent_id' => 'checkParentId',
'action' => 'require|unique:AdminMenu,app^controller^action',
];
protected $message = [
'name.require' => '名称不能为空',
'app.require' => '应用不能为空',
'parent_id' => '超过了4级',
'controller.require' => '名称不能为空',
'action.require' => '名称不能为空',
'action.unique' => '同样的记录已经存在!',
];
protected $scene = [
'add' => ['name', 'app', 'controller', 'action', 'parent_id'],
'edit' => ['name', 'app', 'controller', 'action', 'id', 'parent_i
d'],
];
// 自定义验证规则:菜单只能三级
protected function checkParentId($value)
{
$find = Db::name('AdminMenu')->where(["id" => $value])->value('pa
rent_id');
if ($find) {
$find2 = Db::name('AdminMenu')->where(["id" => $find])->value
('parent_id');
if ($find2) {
$find3 = Db::name('AdminMenu')->where(["id" => $find2])->
value('parent_id');
验证器
- 107 - 本文档使用 看云 构建 if ($find3) {
return false;
}
}
}
return true;
}
}
验证器
- 108 - 本文档使用 看云 构建删除
控制器
视图
删除
- 109 - 本文档使用 看云 构建控制器
思路
一:获得ID
二:获得该ID下的 parent_id 数量是否大于0
三:大于0,提示不能删除
四:否则 删除
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class MenuController extends Controller
{
/**
* 后台菜单删除
*/
public function delete()
{
$id = $this->request->param("id", 0, 'intval');
$count = Db::name('AdminMenu')->where(["parent_id" => $id])->coun
t();
if ($count > 0) {
$this->error("该菜单下还有子菜单,无法删除!");
}
if (Db::name('AdminMenu')->delete($id) !== false) {
$this->success("删除菜单成功!");
} else {
$this->error("删除失败!");
}
}
}
控制器
- 110 - 本文档使用 看云 构建视图
代码
如果干净的删除,是这样的
<a href="' . url("Menu/delete", ["id" => $value['id']) . '">删除</a>
视图
- 111 - 本文档使用 看云 构建导入菜单
导入的总体目录结构
导入菜单
- 112 - 本文档使用 看云 构建视图
执行URL
<a class="btn btn-warning btn-sm" href="{:url('menu/getactions')}">导入新
菜单</a>
代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<div class="wrap">
<div id="error_tips">
<h2>应用{$app}菜单导入成功!</h2>
<div class="error_cont">
<ul>
<if condition="!empty($new_menus)">
<foreach name="new_menus" item="vo">
<li>{$vo}</li>
</foreach>
<else/>
<li>应用{$app}没有新菜单导入!</li>
</if>
</ul>
<if condition="!empty($next_app)">
<script>
setTimeout(function () {
location.href = "{:url('agent/menu/getactions',ar
ray('app'=>$next_app))}";
}, 1000);
</script>
<div class="error_return">
<a href="{:url('agent/menu/getActions',array('app'=>$
next_app))}" class="btn btn-primary">下一个应用</a>
<a href="{:url('admin/menu/index')}" class="btn btn-d
efault" style="margin-left: 10px;">返回</a>
</div>
<else/>
<div>全部导入成功!</div>
<div class="error_return">
视图
- 113 - 本文档使用 看云 构建 <a href="{:url('agent/menu/index')}" class="btn btn-d
efault">返回</a>
</div>
</if>
</div>
</div>
</div>
<!--中间内容/end-->
</body>
</html>
视图
- 114 - 本文档使用 看云 构建控制器
思路
一:将每一个控制器方法上放一个注释说明
二:循环遍历所有模块儿及下边每一个控制器的方法
二:用 Annotations 将每一个方法读出并写入到 auth_rule
代码
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
use mindplay\annotations\Annotations;
class MenuController extends Controller
{
/**
* agent测试
* @adminMenu(
* 'name' => '钩子管理',
* 'parent' => 'admin/Plugin/default',
* 'display'=> true,
* 'hasView'=> true,
* 'order' => 10000,
* 'icon' => '',
* 'remark' => 'agent测试描述',
* 'param' => ''
* )
*/
public function getActions()
{
Annotations::$config['cache'] = false;
$annotationManager = Annotations::getM
anager();
$annotationManager->registry['adminMenu'] = 'app\agent\annota
tion\AdminMenuAnnotation';
$annotationManager->registry['adminMenuRoot'] = 'app\agent\annota
tion\AdminMenuRootAnnotation';
$newMenus = [];
$apps = cmf_scan_dir(APP_PATH . '*', GLOB_ONLYDIR);
$app = $this->request->param('app', '');
if (empty($app)) {
$app = $apps[0];
}
控制器
- 115 - 本文档使用 看云 构建 if (!in_array($app, $apps)) {
$this->error('应用' . $app . '不存在!');
}
if ($app == 'agent') {
$filePatten = APP_PATH . $app . '/controller/*Controller.php'
;
} else {
$filePatten = APP_PATH . $app . '/controller/Admin*Controller
.php';
}
$controllers = cmf_scan_dir($filePatten);
if (!empty($controllers)) {
foreach ($controllers as $controller) {
$controller = preg_replace('/\.php$/', '', $controll
er);
$controllerName = preg_replace('/\Controller$/', '', $co
ntroller);
$controllerClass = "app\\$app\\controller\\$controller";
$menuAnnotations = Annotations::ofClass($controllerClass,
'@adminMenuRoot');
if (!empty($menuAnnotations)) {
foreach ($menuAnnotations as $menuAnnotation) {
$name = $menuAnnotation->name;
$icon = $menuAnnotation->icon;
$type = 0;//1:有界面可访问菜单,2:无界面可访问菜单
,0:只作为菜单
$action = $menuAnnotation->action;
$status = empty($menuAnnotation->display) ? 0
: 1;
$listOrder = floatval($menuAnnotation->order);
$param = $menuAnnotation->param;
$remark = $menuAnnotation->remark;
if (empty($menuAnnotation->parent)) {
$parentId = 0;
} else {
$parent = explode('/', $menuAnnotation->
parent);
$countParent = count($parent);
if ($countParent > 3) {
throw new \Exception($controllerClass . '
:' . $action . ' @adminMenuRoot parent格式不正确!');
}
$parentApp = $app;
$parentController = $controllerName;
$parentAction = '';
控制器
- 116 - 本文档使用 看云 构建 switch ($countParent) {
case 1:
$parentAction = $parent[0];
break;
case 2:
$parentController = $parent[0];
$parentAction = $parent[1];
break;
case 3:
$parentApp = $parent[0];
$parentController = $parent[1];
$parentAction = $parent[2];
break;
}
$findParentAdminMenu = Db::name('admin_menu')
->where([
'app' => $parentApp,
'controller' => $parentController,
'action' => $parentAction
])->find();
if (empty($findParentAdminMenu)) {
$parentId = Db::name('admin_menu')->inser
tGetId([
'app' => $parentApp,
'controller' => $parentController,
'action' => $parentAction,
'name' => '--new--'
]);
} else {
$parentId = $findParentAdminMenu['id'];
}
}
$findAdminMenu = Db::name('admin_menu')->where([
'app' => $app,
'controller' => $controllerName,
'action' => $action
])->find();
if (empty($findAdminMenu)) {
Db::name('admin_menu')->insert([
'parent_id' => $parentId,
'type' => $type,
'status' => $status,
'list_order' => $listOrder,
'app' => $app,
'controller' => $controllerName,
'action' => $action,
'param' => $param,
'name' => $name,
'icon' => $icon,
'remark' => $remark
]);
控制器
- 117 - 本文档使用 看云 构建 $menuName = $name;
array_push($newMenus, "$app/$controllerName/$
action 已导入");
} else {
if ($findAdminMenu['name'] == '--new--') {
Db::name('admin_menu')->where([
'app' => $app,
'controller' => $controllerName,
'action' => $action
])->update([
'parent_id' => $parentId,
'type' => $type,
'status' => $status,
'list_order' => $listOrder,
'param' => $param,
'name' => $name,
'icon' => $icon,
'remark' => $remark
]);
$menuName = $name;
} else {
// 只关注菜单层级关系,是否有视图
Db::name('admin_menu')->where([
'app' => $app,
'controller' => $controllerName,
'action' => $action
])->update([
'parent_id' => $parentId,
'type' => $type,
]);
$menuName = $findAdminMenu['name'];
}
array_push($newMenus, "$app/$controllerName/$
action 层级关系已更新");
}
$authRuleName = "{$app}/{$controllerName}/{$
action}";
$findAuthRuleCount = Db::name('auth_rule')->where
([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url'
])->count();
if ($findAuthRuleCount == 0) {
Db::name('auth_rule')->insert([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url',
'param' => $param,
控制器
- 118 - 本文档使用 看云 构建 'title' => $menuName
]);
} else {
Db::name('auth_rule')->where([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url',
])->update([
'param' => $param,
'title' => $menuName
]);
}
}
}
$reflect = new \ReflectionClass($controllerClass);
$methods = $reflect->getMethods(\ReflectionMethod::IS_PUB
LIC);
if (!empty($methods)) {
foreach ($methods as $method) {
if ($method->class == $controllerClass && strpos(
$method->name, '_') !== 0) {
$menuAnnotations = Annotations::ofMethod($con
trollerClass, $method->name, '@adminMenu');
if (!empty($menuAnnotations)) {
$menuAnnotation = $menuAnnotations[0];
$name = $menuAnnotation->name;
$icon = $menuAnnotation->icon;
$type = $menuAnnotation->hasView ? 1
: 2;//1:有界面可访问菜单,2:无界面可访问菜单,0:只作为菜单
$action = $method->name;
$status = empty($menuAnnotation->displ
ay) ? 0 : 1;
$listOrder = floatval($menuAnnotation->or
der);
$param = $menuAnnotation->param;
$remark = $menuAnnotation->remark;
if (empty($menuAnnotation->parent)) {
$parentId = 0;
} else {
$parent = explode('/', $menuAnno
tation->parent);
$countParent = count($parent);
if ($countParent > 3) {
throw new \Exception($controllerC
lass . ':' . $action . ' @menuRoot parent格式不正确!');
}
$parentApp = $app;
控制器
- 119 - 本文档使用 看云 构建 $parentController = $controllerName;
$parentAction = '';
switch ($countParent) {
case 1:
$parentAction = $parent[0];
break;
case 2:
$parentController = $parent[0
];
$parentAction = $parent[1
];
break;
case 3:
$parentApp = $parent[0
];
$parentController = $parent[1
];
$parentAction = $parent[2
];
break;
}
$findParentAdminMenu = Db::name('admi
n_menu')->where([
'app' => $parentApp,
'controller' => $parentController
,
'action' => $parentAction
])->find();
if (empty($findParentAdminMenu)) {
$parentId = Db::name('admin_menu'
)->insertGetId([
'app' => $parentApp,
'controller' => $parentContro
ller,
'action' => $parentAction
,
'name' => '--new--'
]);
} else {
$parentId = $findParentAdminMenu[
'id'];
}
}
$findAdminMenu = Db::name('admin_menu')->
where([
'app' => $app,
'controller' => $controllerName,
'action' => $action
])->find();
if (empty($findAdminMenu)) {
控制器
- 120 - 本文档使用 看云 构建 Db::name('admin_menu')->insert([
'parent_id' => $parentId,
'type' => $type,
'status' => $status,
'list_order' => $listOrder,
'app' => $app,
'controller' => $controllerName,
'action' => $action,
'param' => $param,
'name' => $name,
'icon' => $icon,
'remark' => $remark
]);
$menuName = $name;
array_push($newMenus, "$app/$controll
erName/$action 已导入");
} else {
if ($findAdminMenu['name'] == '--new-
-') {
Db::name('admin_menu')->where([
'app' => $app,
'controller' => $controllerNa
me,
'action' => $action
])->update([
'parent_id' => $parentId,
'type' => $type,
'status' => $status,
'list_order' => $listOrder,
'param' => $param,
'name' => $name,
'icon' => $icon,
'remark' => $remark
]);
$menuName = $name;
} else {
// 只关注菜单层级关系,是否有视图
Db::name('admin_menu')->where([
'app' => $app,
'controller' => $controllerNa
me,
'action' => $action
])->update([
'parent_id' => $parentId,
'type' => $type,
]);
$menuName = $findAdminMenu['name'
];
}
array_push($newMenus, "$app/$controll
erName/$action 已更新");
控制器
- 121 - 本文档使用 看云 构建 }
$authRuleName = "{$app}/{$controller
Name}/{$action}";
$findAuthRuleCount = Db::name('auth_rule'
)->where([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url'
])->count();
if ($findAuthRuleCount == 0) {
Db::name('auth_rule')->insert([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url',
'param' => $param,
'title' => $menuName
]);
} else {
Db::name('auth_rule')->where([
'app' => $app,
'name' => $authRuleName,
'type' => 'admin_url',
])->update([
'param' => $param,
'title' => $menuName
]);
}
}
}
}
}
}
}
$index = array_search($app, $apps);
$nextIndex = $index + 1;
$nextIndex = $nextIndex >= count($apps) ? 0 : $nextIndex;
if ($nextIndex) {
$this->assign("next_app", $apps[$nextIndex]);
}
$this->assign("app", $app);
$this->assign("new_menus", $newMenus);
return $this->fetch();
}
}
控制器
- 122 - 本文档使用 看云 构建控制器
- 123 - 本文档使用 看云 构建特别注意
特别注意
菜单格式
定制需要修改的
(一) 命名空间
(二)定制哪类需要导入
(三)相关数据表
(四)引入 `annotation` 类和文件
`vendor` 中的 `mindplay`
新建的 `annotation`
特别注意
这里引用了 vdenor 下的代码注释类 Annotations ,如图:
一开始我看了这个类,没当回事儿,准备就此通过,不再看了,看了 thinkcmf 类后,我
才发现,这个类有多强大!
菜单格式
参考: https://www.kancloud.cn/thinkcmf/doc/299310
特别注意
- 124 - 本文档使用 看云 构建/**
* @adminMenu(
* 'name' => '密码修改', // 菜单名称
* 'parent' => 'default', //菜单父级,格式有三种:应用名/控制器/操作,控制器/操
作,操作
* 'display'=> false, //菜单是否显示
* 'hasView'=> false,//菜单是否有界面
* 'order' => 10000, //菜单排序
* 'icon' => '', //图标
* 'remark' => '密码修改', //菜单备注
* 'param' => '' //菜单额外参数,一般没有
* )
*/
定制需要修改的
(一) 命名空间
(二)定制哪类需要导入
(三)相关数据表
特别注意
- 125 - 本文档使用 看云 构建(四)引入 annotation 类和文件
vendor 中的 mindplay
新建的 annotation
特别注意
- 126 - 本文档使用 看云 构建特别注意
- 127 - 本文档使用 看云 构建annotation
AdminMenuAnnotation.php
<?php
namespace app\agent\annotation;
use mindplay\annotations\Annotation;
/**
* Specifies validation of a string, requiring a minimum and/or maximum l
ength.
*
* @usage('method'=>true, 'inherited'=>true, 'multiple'=>false)
*/
class AdminMenuAnnotation extends Annotation
{
public $remark = '';
public $icon = '';
public $name = '';
public $param = '';
public $parent = '';
public $display = false;
public $order = 10000;
public $hasView = true;
/**
* Initialize the annotation.
* @param array $properties
*/
public function initAnnotation(array $properties)
{
parent::initAnnotation($properties);
}
}
AdminMenuRootAnnotation.php
<?php
namespace app\agent\annotation;
annotation
- 128 - 本文档使用 看云 构建use mindplay\annotations\AnnotationException;
use mindplay\annotations\Annotation;
/**
* Specifies validation of a string, requiring a minimum and/or maximum l
ength.
*
* @usage('class'=>true, 'inherited'=>true, 'multiple'=>true)
*/
class AdminMenuRootAnnotation extends Annotation
{
/**
* @var int|null Minimum string length (or null, if no minimum)
*/
public $remark = '';
/**
* @var int|null Maximum string length (or null, if no maximum)
*/
public $icon = '';
/**
* @var int|null Minimum string length (or null, if no minimum)
*/
public $name = '';
public $action = '';
public $param = '';
public $parent = '';
public $display = false;
public $order = 10000;
/**
* Initialize the annotation.
* @param array $properties
*/
public function initAnnotation(array $properties)
{
parent::initAnnotation($properties);
}
}
annotation
- 129 - 本文档使用 看云 构建导出菜单
导出菜单在前边的方法里,已经说明了,只不过在注释里写的,这里简单再写一下。
导出菜单
- 130 - 本文档使用 看云 构建视图
<a class="btn btn-primary btn-sm js-ajax-dialog-btn" href="{:url('menu/ex
portMenuLang')}"
data-msg="您确定生成菜单多语言包吗?请确保应用目录下lang目录可写!">
生成菜单多语言包
</a>
视图
- 131 - 本文档使用 看云 构建控制器
代码
注意:这里这个是 public ,而不是 private
<?php
namespace app\agent\controller;
use think\Controller;
use think\Db;
class MenuController extends Controller
{
/**
* 导出后台菜单语言包
*/
public function _exportAppMenuDefaultLang()
{
$menus = Db::name('AdminMenu')->order(["app" => "ASC", "c
ontroller" => "ASC", "action" => "ASC"])->select();
$langDir = config('DEFAULT_LANG');
$adminMenuLang = CMF_ROOT . "data/lang/" . $langDir . "/admin_men
u.php";
if (!empty($adminMenuLang) && !file_exists_case($adminMenuLang))
{
mkdir(dirname($adminMenuLang), 0777, true);
}
$lang = [];
foreach ($menus as $menu) {
$lang_key = strtoupper($menu['app'] . '_' . $menu['con
troller'] . '_' . $menu['action']);
$lang[$lang_key] = $menu['name'];
}
$langStr = var_export($lang, true);
$langStr = preg_replace("/\s+\d+\s=>\s(\n|\r)/", "\n", $langStr);
if (!empty($adminMenuLang)) {
file_put_contents($adminMenuLang, "<?php\nreturn $langStr;");
}
}
}
控制器
- 132 - 本文档使用 看云 构建控制器
- 133 - 本文档使用 看云 构建排序
控制器
视图
模型
排序
- 134 - 本文档使用 看云 构建控制器
代码
<?php
namespace app\agent\controller;
use think\Controller;
use app\agent\model\AdminMenuModel;
class MenuController extends Controller
{
/**
* 后台菜单排序
*/
public function listOrder()
{
$adminMenuModel = new AdminMenuModel();
parent::listOrders($adminMenuModel);
$this->success("排序更新成功!");
}

}
控制器
- 135 - 本文档使用 看云 构建视图
注:这里的排序界面是参考 友情链接 里写的!因为排序的相关写到控制器里了!道理相
同!
如图:
代码
只要 action="{:url('Link/listOrder')}" 写上 listOrder 就可以了!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min
.css" rel="stylesheet">
</head>
<body>
<!--中间内容/start-->
<form method="post" class="js-ajax-form margin-top-20" action="{:url('Lin
k/listOrder')}">
<button class="btn btn-primary btn-sm js-ajax-submit" type="submit">
排序</button>
<table class="table table-hover table-bordered table-list">
<thead>
<tr>
<td><input name='list_orders[{$vo.id}]' class="input input-or
der mr5" type='text' size='3'
value='{$vo.list_order}'></td>
</tr>
</thead>
视图
- 136 - 本文档使用 看云 构建 <tbody>
<foreach name="links" item="vo">
<tr>
<td><input type="checkbox" class="js-check" data-yid="js-
check-y" data-xid="js-check-x" name="ids[]"
value="{$vo.id}"></td>
</tr>
</foreach>
</tbody>

</table>

</form>
<!--中间内容/end-->
</body>
</html>
视图
- 137 - 本文档使用 看云 构建模型
代码
<?php
namespace app\agent\model;
use think\Model;
class AdminMenuModel extends Model
{
}
模型
- 138 - 本文档使用 看云 构建

猜你喜欢

转载自blog.csdn.net/chengjianghao/article/details/80784401
今日推荐