mirror of https://gitee.com/karson/fastadmin.git
Merge branch '1.x-dev' of https://gitee.com/ken678_admin/fastadmin into 1.x-dev
commit
87f7013c94
|
|
@ -18,6 +18,7 @@ class Api extends Command
|
|||
$this
|
||||
->setName('api')
|
||||
->addOption('url', 'u', Option::VALUE_OPTIONAL, 'default api url', '')
|
||||
->addOption('cdnurl', 'd', Option::VALUE_OPTIONAL, 'default cdn url', '')
|
||||
->addOption('module', 'm', Option::VALUE_OPTIONAL, 'module name(admin/index/api)', 'api')
|
||||
->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html')
|
||||
->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html')
|
||||
|
|
@ -36,6 +37,7 @@ class Api extends Command
|
|||
|
||||
$force = $input->getOption('force');
|
||||
$url = $input->getOption('url');
|
||||
$cdnurl = $input->getOption('cdnurl');
|
||||
$language = $input->getOption('language');
|
||||
$template = $input->getOption('template');
|
||||
if (!preg_match("/^([a-z0-9]+)\.html\$/i", $template)) {
|
||||
|
|
@ -116,15 +118,19 @@ class Api extends Command
|
|||
|
||||
$classes = array_unique(array_filter($classes));
|
||||
|
||||
$cdnurl = $cdnurl ? : Config::get('site.cdnurl');
|
||||
|
||||
$config = [
|
||||
'sitename' => config('site.name'),
|
||||
'title' => $title,
|
||||
'author' => config('site.name'),
|
||||
'description' => '',
|
||||
'apiurl' => $url,
|
||||
'cdnurl' => $cdnurl,
|
||||
'language' => $language,
|
||||
];
|
||||
|
||||
Config::set('view_replace_str.__CDN__', $cdnurl);
|
||||
$builder = new Builder($classes);
|
||||
$content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,16 +8,10 @@
|
|||
<title>{$config.title}</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="{$config.cdnurl|default=''}/assets/libs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Plugin CSS -->
|
||||
<link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<link href="{$config.cdnurl|default=''}/assets/libs/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
|
|
@ -401,10 +395,10 @@
|
|||
</div> <!-- /container -->
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="{$config.cdnurl|default=''}/assets/libs/jquery/dist/jquery.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||
<script src="{$config.cdnurl|default=''}/assets/libs/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function syntaxHighlight(json) {
|
||||
|
|
|
|||
|
|
@ -1251,7 +1251,7 @@ EOD;
|
|||
$output->info("Build Successed");
|
||||
}
|
||||
|
||||
protected function getEnum(&$getEnum, &$controllerAssignList, $field, $itemArr = '', $inputType = '')
|
||||
protected function getEnum(&$getEnum, &$controllerAssignList, $field, $itemArr = [], $inputType = '')
|
||||
{
|
||||
if (!in_array($inputType, ['datetime', 'select', 'multiple', 'checkbox', 'radio'])) {
|
||||
return;
|
||||
|
|
@ -1571,6 +1571,7 @@ EOD;
|
|||
$valArr = explode('=', $v);
|
||||
if (count($valArr) == 2) {
|
||||
list($key, $value) = $valArr;
|
||||
$key = trim($key);
|
||||
$itemArr[$key] = $field . ' ' . $key;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,10 @@ class Group extends Backend
|
|||
}
|
||||
if (($pid || $parentGroupModel) && (!$id || $currentGroupModel)) {
|
||||
$id = $id ? $id : null;
|
||||
$ruleList = collection(model('AuthRule')->order('weigh', 'desc')->order('id', 'asc')->select())->toArray();
|
||||
$ruleList = Db::name("auth_rule")
|
||||
->field('id,pid,name,title,icon,ismenu,status,weigh')
|
||||
->order('weigh DESC,id ASC')
|
||||
->select();
|
||||
//读取父类角色所有节点列表
|
||||
$parentRuleList = [];
|
||||
if (in_array('*', explode(',', $parentGroupModel->rules))) {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
namespace app\admin\controller\auth;
|
||||
|
||||
use app\admin\model\AuthRule;
|
||||
use app\common\controller\Backend;
|
||||
use fast\Tree;
|
||||
use think\Cache;
|
||||
use think\db\Query;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 规则管理
|
||||
|
|
@ -32,24 +30,45 @@ class Rule extends Backend
|
|||
$this->error(__('Access is allowed only to the super management group'));
|
||||
}
|
||||
$this->model = model('AuthRule');
|
||||
// 必须将结果集转换为数组
|
||||
$ruleList = \think\Db::name("auth_rule")->field('type,condition,remark,menutype,extend,pinyin,py,createtime,updatetime', true)->order('weigh DESC,id ASC')->select();
|
||||
foreach ($ruleList as $k => &$v) {
|
||||
$v['title'] = __($v['title']);
|
||||
}
|
||||
unset($v);
|
||||
Tree::instance()->init($ruleList)->icon = [' ', ' ', ' '];
|
||||
$this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
|
||||
$ruledata = [0 => __('None')];
|
||||
foreach ($this->rulelist as $k => &$v) {
|
||||
if (!$v['ismenu']) {
|
||||
continue;
|
||||
$actionName = $this->request->action();
|
||||
|
||||
$isAddEdit = in_array($actionName, ['add', 'edit']);
|
||||
|
||||
// 优化加载
|
||||
if ($isAddEdit || ($actionName == 'index' && $this->request->isAjax())) {
|
||||
|
||||
// 必须将结果集转换为数组
|
||||
$ruleList = Db::name("auth_rule")
|
||||
->where(function ($query) use ($isAddEdit) {
|
||||
if ($isAddEdit) {
|
||||
$query->where('ismenu', 1);
|
||||
}
|
||||
})->field('id,pid,name,title,icon,ismenu,status,weigh')
|
||||
->order('weigh DESC,id ASC')
|
||||
->select();
|
||||
|
||||
array_walk($ruleList, function (&$v) {
|
||||
$v['title'] = __($v['title']);
|
||||
});
|
||||
|
||||
// 读取规则菜单
|
||||
$this->rulelist = Tree::instance()->init($ruleList)->getTreeArrayList(0);
|
||||
|
||||
// 只有编辑页才需要渲染
|
||||
if ($isAddEdit) {
|
||||
$ruledata = [0 => __('None')];
|
||||
foreach ($this->rulelist as $k => &$v) {
|
||||
if (!$v['ismenu']) {
|
||||
continue;
|
||||
}
|
||||
$ruledata[$v['id']] = str_repeat(' ', $v['level'] * 4) . $v['title'];
|
||||
}
|
||||
unset($v);
|
||||
|
||||
$this->view->assign('ruledata', $ruledata);
|
||||
}
|
||||
$ruledata[$v['id']] = $v['title'];
|
||||
unset($v['spacer']);
|
||||
}
|
||||
unset($v);
|
||||
$this->view->assign('ruledata', $ruledata);
|
||||
|
||||
$this->view->assign("menutypeList", $this->model->getMenutypeList());
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +130,8 @@ class Rule extends Backend
|
|||
$this->error(__('Can not change the parent to self'));
|
||||
}
|
||||
if ($params['pid'] != $row['pid']) {
|
||||
$childrenIds = Tree::instance()->init(collection(AuthRule::select())->toArray())->getChildrenIds($row['id']);
|
||||
$tree = Tree::instance()->init(Db::name('auth_rule')->select());
|
||||
$childrenIds = $tree->getChildrenIds($row['id']);
|
||||
if (in_array($params['pid'], $childrenIds)) {
|
||||
$this->error(__('Can not change the parent to child'));
|
||||
}
|
||||
|
|
@ -141,11 +161,12 @@ class Rule extends Backend
|
|||
if (!$this->request->isPost()) {
|
||||
$this->error(__("Invalid parameters"));
|
||||
}
|
||||
$ids = $ids ? $ids : $this->request->post("ids");
|
||||
$ids = $ids ?: $this->request->post("ids");
|
||||
if ($ids) {
|
||||
$delIds = [];
|
||||
$tree = Tree::instance()->init(Db::name('auth_rule')->select());
|
||||
foreach (explode(',', $ids) as $k => $v) {
|
||||
$delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, true));
|
||||
$delIds = array_merge($delIds, $tree->getChildrenIds($v, true));
|
||||
}
|
||||
$delIds = array_unique($delIds);
|
||||
$count = $this->model->where('id', 'in', $delIds)->delete();
|
||||
|
|
@ -170,4 +191,4 @@ class Rule extends Backend
|
|||
|
||||
parent::dragsort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +1,35 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'Id' => 'ID',
|
||||
'Group_id' => '组别ID',
|
||||
'Username' => '用户名',
|
||||
'Nickname' => '昵称',
|
||||
'Password' => '密码',
|
||||
'Salt' => '密码盐',
|
||||
'Email' => '电子邮箱',
|
||||
'Mobile' => '手机号',
|
||||
'Avatar' => '头像',
|
||||
'Level' => '等级',
|
||||
'Gender' => '性别',
|
||||
'Male' => '男',
|
||||
'FeMale' => '女',
|
||||
'Birthday' => '生日',
|
||||
'Bio' => '格言',
|
||||
'Score' => '积分',
|
||||
'Successions' => '连续登录天数',
|
||||
'Maxsuccessions' => '最大连续登录天数',
|
||||
'Prevtime' => '上次登录时间',
|
||||
'Logintime' => '登录时间',
|
||||
'Loginip' => '登录IP',
|
||||
'Loginfailure' => '失败次数',
|
||||
'Joinip' => '加入IP',
|
||||
'Jointime' => '加入时间',
|
||||
'Createtime' => '创建时间',
|
||||
'Updatetime' => '更新时间',
|
||||
'Token' => 'Token',
|
||||
'Status' => '状态',
|
||||
'Id' => 'ID',
|
||||
'Group_id' => '组别ID',
|
||||
'Username' => '用户名',
|
||||
'Nickname' => '昵称',
|
||||
'Password' => '密码',
|
||||
'Salt' => '密码盐',
|
||||
'Email' => '电子邮箱',
|
||||
'Mobile' => '手机号',
|
||||
'Avatar' => '头像',
|
||||
'Level' => '等级',
|
||||
'Gender' => '性别',
|
||||
'Male' => '男',
|
||||
'FeMale' => '女',
|
||||
'Birthday' => '生日',
|
||||
'Bio' => '格言',
|
||||
'Score' => '积分',
|
||||
'Successions' => '连续登录天数',
|
||||
'Maxsuccessions' => '最大连续登录天数',
|
||||
'Prevtime' => '上次登录时间',
|
||||
'Logintime' => '登录时间',
|
||||
'Loginip' => '登录IP',
|
||||
'Loginfailure' => '失败次数',
|
||||
'Joinip' => '加入IP',
|
||||
'Jointime' => '加入时间',
|
||||
'Createtime' => '创建时间',
|
||||
'Updatetime' => '更新时间',
|
||||
'Token' => 'Token',
|
||||
'Status' => '状态',
|
||||
'Username must be 3 to 30 characters' => '用户名只能由3-30位数字、字母、下划线组合',
|
||||
'Password must be 6 to 30 characters' => '密码长度必须在6-30位之间,不能包含空格',
|
||||
'Leave password blank if dont want to change' => '不修改密码请留空',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class User extends Validate
|
|||
'username' => 'require|regex:\w{3,30}|unique:user',
|
||||
'nickname' => 'require|unique:user',
|
||||
'password' => 'regex:\S{6,30}',
|
||||
'email' => 'require|email|unique:user',
|
||||
'email' => 'email|unique:user',
|
||||
'mobile' => 'unique:user'
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
|
||||
{:token()}
|
||||
<input type="hidden" name="row[rules]" value="" />
|
||||
<input type="hidden" name="row[rules]" value=""/>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
|
|
@ -10,14 +10,16 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required" />
|
||||
<input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
|
||||
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
|
||||
<div style="margin-top:8px;">
|
||||
<span class="text-muted"><input type="checkbox" name="" id="checkall"/> <label for="checkall"><span>{:__('Check all')}</span></label></span>
|
||||
<span class="text-muted"><input type="checkbox" name="" id="expandall"/> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
|
||||
</div>
|
||||
|
||||
<div id="treeview"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
|
||||
{:token()}
|
||||
<input type="hidden" name="row[rules]" value="" />
|
||||
<input type="hidden" name="row[rules]" value=""/>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
|
|
@ -10,14 +10,16 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="name" name="row[name]" value="{$row.name|htmlentities}" data-rule="required" />
|
||||
<input type="text" class="form-control" id="name" name="row[name]" value="{$row.name|htmlentities}" data-rule="required"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
|
||||
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
|
||||
<div style="margin-top:8px;">
|
||||
<span class="text-muted"><input type="checkbox" name="" id="checkall"/> <label for="checkall"><span>{:__('Check all')}</span></label></span>
|
||||
<span class="text-muted"><input type="checkbox" name="" id="expandall"/> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
|
||||
</div>
|
||||
|
||||
<div id="treeview"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<style>
|
||||
.bootstrap-table tr td .text-muted {color:#888;}
|
||||
.bootstrap-table tr td .fa.fa-caret-right {width: 8px;text-align: center;}
|
||||
</style>
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<div class="form-group">
|
||||
<label for="c-username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
|
||||
<div class="col-xs-12 col-sm-4">
|
||||
<input id="c-username" data-rule="required" class="form-control" name="row[username]" type="text" value="{$row.username|htmlentities}">
|
||||
<input id="c-username" data-rule="{:__('Username')}:required;username" class="form-control" name="row[username]" type="text" value="{$row.username|htmlentities}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
|
|
|||
|
|
@ -179,14 +179,14 @@ class User extends Api
|
|||
$bio = $this->request->post('bio');
|
||||
$avatar = $this->request->post('avatar', '', 'trim,strip_tags,htmlspecialchars');
|
||||
if ($username) {
|
||||
$exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find();
|
||||
$exists = \app\common\model\User::where('username', $username)->where('id', '<>', $user->id)->find();
|
||||
if ($exists) {
|
||||
$this->error(__('Username already exists'));
|
||||
}
|
||||
$user->username = $username;
|
||||
}
|
||||
if ($nickname) {
|
||||
$exists = \app\common\model\User::where('nickname', $nickname)->where('id', '<>', $this->auth->id)->find();
|
||||
$exists = \app\common\model\User::where('nickname', $nickname)->where('id', '<>', $user->id)->find();
|
||||
if ($exists) {
|
||||
$this->error(__('Nickname already exists'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,15 +293,15 @@ return [
|
|||
'user_level_rule' => '',
|
||||
//会员等级积分字典,键名表示等级,值表示所需的积分
|
||||
'user_level_dict' => [1 => 0, 2 => 30, 3 => 100, 4 => 500, 5 => 1000, 6 => 2000, 7 => 3000, 8 => 5000, 9 => 8000, 10 => 10000],
|
||||
//登录验证码
|
||||
//后台登录验证码
|
||||
'login_captcha' => true,
|
||||
//登录失败超过10次则1天后重试
|
||||
//后台登录失败超过10次则1天后重试
|
||||
'login_failure_retry' => true,
|
||||
//是否同一账号同一时间只能在一个地方登录
|
||||
//后台是否同一账号同一时间只能在一个地方登录
|
||||
'login_unique' => false,
|
||||
//是否开启IP变动检测
|
||||
//后台是否开启IP变动检测
|
||||
'loginip_check' => true,
|
||||
//登录页默认背景图
|
||||
//后台登录页默认背景图
|
||||
'login_background' => "",
|
||||
//是否启用简洁导航,如同时启用多级菜单导航,简洁导航将失效
|
||||
'simplenav' => false,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ return [
|
|||
'Mobile' => '手机号',
|
||||
'Email' => '邮箱',
|
||||
'Captcha' => '验证码',
|
||||
'Get code' => '获取验证码',
|
||||
'Lv' => 'Lv',
|
||||
'Score' => '积分',
|
||||
'Day' => '天',
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@
|
|||
<div class="input-group">
|
||||
<input type="text" name="captcha" id="email-captcha" class="form-control" data-rule="required;length({$Think.config.captcha.length});digits;remote({:url('api/validate/check_ems_correct')}, event=changeemail, email:#email)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/ems/send')}" data-type="email" data-event="changeemail">获取验证码</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/ems/send')}" data-type="email" data-event="changeemail">{:__('Get code')}</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
<div class="input-group">
|
||||
<input type="text" name="captcha" id="mobile-captcha" class="form-control" data-rule="required;length({$Think.config.captcha.length});digits;remote({:url('api/validate/check_sms_correct')}, event=changemobile, mobile:#mobile)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/sms/send')}" data-type="mobile" data-event="changemobile">获取验证码</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/sms/send')}" data-type="mobile" data-event="changemobile">{:__('Get code')}</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
|
|
|
|||
|
|
@ -55,15 +55,15 @@ class Tree
|
|||
/**
|
||||
* 初始化方法
|
||||
* @param array $arr 2维数组,例如:
|
||||
* array(
|
||||
* 1 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'),
|
||||
* 2 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'),
|
||||
* 3 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'),
|
||||
* 4 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'),
|
||||
* 5 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'),
|
||||
* 6 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'),
|
||||
* 7 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二')
|
||||
* )
|
||||
* array(
|
||||
* 1 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'),
|
||||
* 2 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'),
|
||||
* 3 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'),
|
||||
* 4 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'),
|
||||
* 5 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'),
|
||||
* 6 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'),
|
||||
* 7 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二')
|
||||
* )
|
||||
* @param string $pidname 父字段名称
|
||||
* @param string $nbsp 空格占位符
|
||||
* @return Tree
|
||||
|
|
@ -435,4 +435,55 @@ class Tree
|
|||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
public function getTreeArrayList($pid = 0)
|
||||
{
|
||||
$map = [];
|
||||
$data = [];
|
||||
|
||||
$items = $this->arr;
|
||||
|
||||
foreach ($items as &$item) {
|
||||
$item['children'] = []; // 初始化子节点
|
||||
$map[$item['id']] = &$item;
|
||||
}
|
||||
unset($item);
|
||||
|
||||
foreach ($items as &$item) {
|
||||
if ($item[$this->pidname] == $pid) {
|
||||
$data[] = &$item;
|
||||
} else {
|
||||
if (isset($map[$item[$this->pidname]])) {
|
||||
$map[$item[$this->pidname]]['children'][] = &$item;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($item);
|
||||
|
||||
return $this->getFlattenTree($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将多维树形结构数据扁平化处理
|
||||
*
|
||||
* 该函数递归遍历树形结构,将嵌套的节点展开为一维数组,
|
||||
* 并为每个节点添加层级标识
|
||||
*
|
||||
* @param array $data 树形结构数据,每个节点可能包含children子节点
|
||||
* @param int $level 当前节点的层级深度,默认为0(根节点)
|
||||
* @param array &$result 引用传递的结果数组,用于存储扁平化后的所有节点
|
||||
*
|
||||
* @return array 扁平化后的节点数组,每个节点包含原始数据和level层级信息
|
||||
*/
|
||||
public function getFlattenTree($data, $level = 0, &$result = [])
|
||||
{
|
||||
foreach ($data as $node) {
|
||||
$node['level'] = $level;
|
||||
$result[] = $node;
|
||||
if (!empty($node['children'])) {
|
||||
$this->getFlattenTree($node['children'], $level + 1, $result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -714,6 +714,8 @@ a:focus {
|
|||
.sidebar-menu li > a > .pull-right-container {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
.sidebar-collapse .sidebar-menu li > a > .pull-right-container {
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
|
@ -1424,7 +1426,7 @@ select.form-control {
|
|||
.input-lg + .form-control-feedback.fa,
|
||||
.input-group-lg + .form-control-feedback.fa,
|
||||
.form-group-lg .form-control + .form-control-feedback.fa {
|
||||
line-height: 45px;
|
||||
line-height: 44px;
|
||||
}
|
||||
.input-sm + .form-control-feedback.fa,
|
||||
.input-group-sm + .form-control-feedback.fa,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
|
|||
{field: 'state', checkbox: true,},
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'pid', title: __('Parent')},
|
||||
{field: 'name', title: __('Name'), align: 'left', formatter:function (value, row, index) {
|
||||
{
|
||||
field: 'name', title: __('Name'), align: 'left', formatter: function (value, row, index) {
|
||||
return value.toString().replace(/(&|&)nbsp;/g, ' ');
|
||||
}
|
||||
},
|
||||
|
|
@ -79,14 +80,17 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
|
|||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
var treeview = $("#treeview");
|
||||
|
||||
// 表单提交前设定规则集合
|
||||
Form.api.bindevent($("form[role=form]"), null, null, function () {
|
||||
if ($("#treeview").length > 0) {
|
||||
var r = $("#treeview").jstree("get_all_checked");
|
||||
if (treeview.length > 0) {
|
||||
var r = treeview.jstree("get_all_checked");
|
||||
$("input[name='row[rules]']").val(r.join(','));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
//渲染权限节点树
|
||||
|
||||
//变更级别后需要重建节点树
|
||||
$(document).on("change", "select[name='row[pid]']", function () {
|
||||
var pid = $(this).data("pid");
|
||||
|
|
@ -96,37 +100,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
|
|||
Backend.api.toastr.error(__('Can not change the parent to self'));
|
||||
return false;
|
||||
}
|
||||
$.ajax({
|
||||
url: "auth/group/roletree",
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: {id: id, pid: $(this).val()},
|
||||
success: function (ret) {
|
||||
if (ret.hasOwnProperty("code")) {
|
||||
var data = ret.hasOwnProperty("data") && ret.data != "" ? ret.data : "";
|
||||
if (ret.code === 1) {
|
||||
//销毁已有的节点树
|
||||
$("#treeview").jstree("destroy");
|
||||
Controller.api.rendertree(data);
|
||||
} else {
|
||||
Backend.api.toastr.error(ret.msg);
|
||||
}
|
||||
}
|
||||
}, error: function (e) {
|
||||
Backend.api.toastr.error(e.message);
|
||||
}
|
||||
});
|
||||
treeview.jstree(true).refresh(false);
|
||||
});
|
||||
|
||||
//全选和展开
|
||||
$(document).on("click", "#checkall", function () {
|
||||
$("#treeview").jstree($(this).prop("checked") ? "check_all" : "uncheck_all");
|
||||
treeview.jstree($(this).prop("checked") ? "check_all" : "uncheck_all");
|
||||
});
|
||||
$(document).on("click", "#expandall", function () {
|
||||
$("#treeview").jstree($(this).prop("checked") ? "open_all" : "close_all");
|
||||
treeview.jstree($(this).prop("checked") ? "open_all" : "close_all");
|
||||
});
|
||||
$("select[name='row[pid]']").trigger("change");
|
||||
|
||||
//首次渲染
|
||||
Controller.api.rendertree();
|
||||
},
|
||||
rendertree: function (content) {
|
||||
rendertree: function () {
|
||||
$("#treeview")
|
||||
.on('redraw.jstree', function (e) {
|
||||
$(".layer-footer").attr("domrefresh", Math.random());
|
||||
|
|
@ -150,7 +138,32 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
|
|||
"plugins": ["checkbox", "types"],
|
||||
"core": {
|
||||
'check_callback': true,
|
||||
"data": content
|
||||
'strings': {
|
||||
'Loading ...': __('Loading')
|
||||
},
|
||||
"data": function (obj, callback) {
|
||||
var pidObj = $("select[name='row[pid]']");
|
||||
$.ajax({
|
||||
url: "auth/group/roletree",
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: {id: pidObj.data('id'), pid: pidObj.val()},
|
||||
success: function (ret) {
|
||||
if (ret.hasOwnProperty("code")) {
|
||||
var data = ret.hasOwnProperty("data") && ret.data != "" ? ret.data : "";
|
||||
if (ret.code === 1) {
|
||||
callback(data);
|
||||
} else {
|
||||
Backend.api.toastr.error(ret.msg);
|
||||
callback([]);
|
||||
}
|
||||
}
|
||||
}, error: function (e) {
|
||||
Backend.api.toastr.error(e.message);
|
||||
callback([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
|
|||
}
|
||||
});
|
||||
|
||||
var isExpanded = false;
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
// 初始化表格
|
||||
|
|
@ -29,7 +31,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
|
|||
{field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon},
|
||||
{field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name},
|
||||
{field: 'weigh', title: __('Weigh')},
|
||||
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
|
||||
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status, operate: false},
|
||||
{
|
||||
field: 'ismenu',
|
||||
title: __('Ismenu'),
|
||||
|
|
@ -50,8 +52,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
|
|||
search: false,
|
||||
commonSearch: false,
|
||||
rowAttributes: function (row, index) {
|
||||
var expanded = $(".btn-toggle-all i").hasClass("fa-minus");
|
||||
return row.pid == 0 || expanded ? {} : {style: "display:none"};
|
||||
return row.pid == 0 || isExpanded ? {} : {style: "display:none"};
|
||||
}
|
||||
});
|
||||
|
||||
table.on('post-body.bs.table', function (e, data) {
|
||||
if (data.length > 2000) {
|
||||
$(".btn-dragsort").addClass("disabled");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -142,6 +149,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
|
|||
$(".btn-node-sub:not([data-pid=0])").closest("tr").toggle(show);
|
||||
$(".btn-node-sub").data("shown", show);
|
||||
$(".btn-node-sub > i").toggleClass("fa-caret-down", show).toggleClass("fa-caret-right", !show);
|
||||
isExpanded = show;
|
||||
});
|
||||
},
|
||||
add: function () {
|
||||
|
|
@ -153,13 +161,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
|
|||
api: {
|
||||
formatter: {
|
||||
title: function (value, row, index) {
|
||||
value = value.toString().replace(/(&|&)nbsp;/g, ' ');
|
||||
var caret = row.haschild == 1 || row.ismenu == 1 ? '<i class="fa fa-caret-right"></i>' : '';
|
||||
value = value.indexOf(" ") > -1 ? value.replace(/(.*) /, "$1" + caret) : caret + value;
|
||||
|
||||
value = !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value;
|
||||
return '<a href="javascript:;" data-id="' + row.id + '" data-pid="' + row.pid + '" class="'
|
||||
+ (row.haschild == 1 || row.ismenu == 1 ? 'text-primary' : 'disabled') + ' btn-node-sub">' + value + '</a>';
|
||||
+ (row.haschild == 1 || row.ismenu == 1 ? 'text-primary' : 'disabled') + ' btn-node-sub">' + (' '.repeat(row.level)) + (' '.repeat(parseInt(row.level) * 4)) + caret + ' ' + value + '</a>';
|
||||
},
|
||||
name: function (value, row, index) {
|
||||
return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
|
|||
$('.selectpicker', form).selectpicker();
|
||||
$(form).on("reset", function () {
|
||||
setTimeout(function () {
|
||||
$('.selectpicker').selectpicker('refresh').trigger("change");
|
||||
$('.selectpicker', form).selectpicker('refresh').trigger("change");
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
|
|
@ -135,8 +135,13 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
|
|||
setTimeout(function () {
|
||||
$(".selectpage", form).each(function () {
|
||||
var selectpage = $(this).data("selectPageObject");
|
||||
selectpage.elem.hidden.val($(this).val());
|
||||
$(this).selectPageRefresh();
|
||||
if ($(this).val()) {
|
||||
selectpage.elem.hidden.val($(this).val());
|
||||
$(this).selectPageRefresh();
|
||||
} else {
|
||||
$(this).selectPageClear();
|
||||
}
|
||||
selectpage.hideResults(selectpage);
|
||||
});
|
||||
}, 1);
|
||||
});
|
||||
|
|
@ -159,7 +164,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
|
|||
require(['citypicker'], function () {
|
||||
$(form).on("reset", function () {
|
||||
setTimeout(function () {
|
||||
$("[data-toggle='city-picker']").citypicker('refresh');
|
||||
$("[data-toggle='city-picker']", form).citypicker('refresh');
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
|
|
@ -513,10 +518,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
|
|||
tagsinput: function (form) {
|
||||
if ($("[data-role='tagsinput']", form).length > 0) {
|
||||
require(['tagsinput', 'autocomplete'], function () {
|
||||
$("[data-role='tagsinput']").tagsinput();
|
||||
$("[data-role='tagsinput']", form).tagsinput();
|
||||
form.on("reset", function () {
|
||||
setTimeout(function () {
|
||||
$("[data-role='tagsinput']").tagsinput('reset');
|
||||
$("[data-role='tagsinput']", form).tagsinput('reset');
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
|
|||
if (top + 154 > $(window).height()) {
|
||||
top = top - 154;
|
||||
}
|
||||
if ($(window).width() < 480) {
|
||||
if (left < 0 || $(window).width() < 480) {
|
||||
top = left = undefined;
|
||||
}
|
||||
Layer.confirm(
|
||||
|
|
|
|||
|
|
@ -164,8 +164,15 @@
|
|||
> .pull-right-container {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-collapse {
|
||||
.sidebar-menu li > a {
|
||||
> .pull-right-container {
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue