作者 Karson

init

正在显示 60 个修改的文件 包含 4605 行增加0 行删除

要显示太多修改。

为保证性能只显示 60 of 60+ 个文件。

{
"directory" : "public/assets/libs"
}
\ No newline at end of file
... ...
/nbproject/
.idea
composer.lock
*.log
thinkphp
vendor
runtime
public/assets/libs/
\ No newline at end of file
... ...
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true
... ...
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2017 Karson
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
... ...
deny from all
\ No newline at end of file
... ...
<?php
namespace app\admin\command;
use fast\Form;
use think\Config;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Db;
use think\Lang;
class Crud extends Command
{
protected function configure()
{
$this
->setName('crud')
->addOption('table', 't', Option::VALUE_REQUIRED, 'table name without prefix', null)
->addOption('controller', 'c', Option::VALUE_OPTIONAL, 'controller name', null)
->addOption('model', 'm', Option::VALUE_OPTIONAL, 'model name', null)
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local model', 1)
->setDescription('Build CRUD controller and model from table');
}
protected function execute(Input $input, Output $output)
{
$adminPath = dirname(__DIR__) . DS;
//表名
$table = $input->getOption('table') ? : '';
//自定义控制器
$controller = $input->getOption('controller');
//自定义模型
$model = $input->getOption('model');
//强制覆盖
$force = $input->getOption('force');
//是否为本地model,为0时表示为全局model将会把model放在app/common/model中
$local = $input->getOption('local');
if (!$table)
{
$output->error('table name can\'t empty');
return;
}
$dbname = Config::get('database.database');
$prefix = Config::get('database.prefix');
$tableName = $prefix . $table;
$tableInfo = Db::query("SHOW TABLE STATUS LIKE '{$tableName}'", [], TRUE);
if (!$tableInfo)
{
$output->error("table not found");
return;
}
$tableInfo = $tableInfo[0];
//根据表名匹配对应的Fontawesome图标
$iconPath = ROOT_PATH . '/public/assets/libs/font-awesome/less/variables.less';
$iconName = is_file($iconPath) && stripos(file_get_contents($iconPath), '@fa-var-' . $table . ':') ? $table : 'fa fa-circle-o';
//控制器默认以表名进行处理,以下划线进行分隔,如果需要自定义则需要传入controller,格式为目录层级
$controllerArr = !$controller ? explode('_', strtolower($table)) : explode('/', strtolower($controller));
$controllerUrl = implode('/', $controllerArr);
$controllerName = ucfirst(array_pop($controllerArr));
$controllerDir = implode('/', $controllerArr);
$controllerFile = ($controllerDir ? $controllerDir . '/' : '') . $controllerName . '.php';
//非覆盖模式时如果存在控制器文件则报错
if (is_file($controllerFile) && !$force)
{
$output->error('controller already exists');
return;
}
//模型默认以表名进行处理,以下划线进行分隔,如果需要自定义则需要传入model,不支持目录层级
if (!$model)
{
$modelarr = explode('_', strtolower($table));
foreach ($modelarr as $k => &$v)
$v = ucfirst($v);
unset($v);
$modelName = implode('', $modelarr);
}
else
{
$modelName = ucfirst($model);
}
$modelFile = ($local ? $adminPath : APP_PATH . 'common' . DS) . 'model' . DS . $modelName . '.php';
//非覆盖模式时如果存在模型文件则报错
if (is_file($modelFile) && !$force)
{
$output->error('model already exists');
return;
}
//从数据库中获取表字段信息
$columnList = Db::query("SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND table_name = ? ORDER BY ORDINAL_POSITION", [$dbname, $tableName]);
$fields = [];
foreach ($columnList as $k => $v)
{
$fields[] = $v['COLUMN_NAME'];
}
$addList = [];
$editList = [];
$javascriptList = [];
$langList = [];
$field = 'id';
$order = 'id';
//循环所有字段,开始构造视图的HTML和JS信息
foreach ($columnList as $k => $v)
{
$field = $v['COLUMN_NAME'];
$fieldLang = ucfirst($field);
// 语言列表
if ($v['COLUMN_COMMENT'] != '')
{
$langList[] = $this->getLangItem($field, $v['COLUMN_COMMENT']);
}
if ($v['COLUMN_KEY'] != 'PRI')
{
$inputType = 'text';
$step = 0;
switch ($v['DATA_TYPE'])
{
case 'bigint':
case 'int':
case 'mediumint':
case 'smallint':
case 'tinyint':
$inputType = 'number';
break;
case 'enum':
case 'set':
$inputType = 'select';
break;
case 'decimal':
case 'double':
case 'float':
$inputType = 'number';
$step = "0." . str_repeat(0, $v['NUMERIC_SCALE'] - 1) . "1";
case 'text':
$inputType = 'textarea';
default:
break;
}
if (substr($field, -4) == 'time')
{
$inputType = 'datetime';
}
if ($inputType == 'select')
{
$itemlist = substr($v['COLUMN_TYPE'], strlen($v['DATA_TYPE']) + 1, -1);
$itemlist = str_replace("'", '', $itemlist);
$attr = "'id'=>'c-$field','class'=>'form-control selectpicker'";
if ($v['DATA_TYPE'] == 'enum')
{
$attr .= ",'multiple'=>''";
}
if ($v['COLUMN_DEFAULT'] == '')
{
$attr .= ",'required'=>''";
}
$formAddElement = "{:build_select('row[$field]', '{$itemlist}', null, [{$attr}])}";
$formEditElement = "{:build_select('row[$field]', '{$itemlist}', \$row['$field'], [{$attr}])}";
}
else
{
//CSS类名
$cssClass = ['form-control'];
$cssClass[] = substr($field, -4) == 'time' ? 'datetimepicker' : '';
$cssClass[] = $v['DATA_TYPE'] == 'text' ? 'summernote' : '';
$cssClass[] = substr($field, -3) == '_id' ? 'typeahead' : '';
$cssClass[] = substr($field, -4) == '_ids' ? 'tagsinput' : '';
$cssClass = array_filter($cssClass);
//因为有自动完成可输入其它内容
if (array_intersect($cssClass, ['typeahead', 'tagsinput']))
{
$inputType = 'text';
$step = 0;
}
$attr = ['id' => "c-{$field}", 'class' => implode(' ', $cssClass)];
if ($step)
{
$attr['step'] = $step;
}
//如果是图片则额外附加
if (substr($field, -5) == 'image' || substr($field, -6) == 'avatar')
{
$attr['data-plupload-id'] = "plupload-{$field}-text";
$attr['size'] = 50;
}
$fieldFunc = substr($field, -4) == 'time' ? "|datetime" : "";
if ($inputType == 'textarea')
{
$formAddElement = Form::textarea("row[{$field}]", $v['COLUMN_DEFAULT'], $attr);
$formEditElement = Form::textarea("row[{$field}]", "{\$row.{$field}{$fieldFunc}}", $attr);
}
else
{
$formAddElement = Form::input($inputType, "row[{$field}]", $v['COLUMN_DEFAULT'], $attr);
$formEditElement = Form::input($inputType, "row[{$field}]", "{\$row.{$field}{$fieldFunc}}", $attr);
}
if (substr($field, -5) == 'image' || substr($field, -6) == 'avatar')
{
//如果是图片或头像
$formAddElement = $this->getImageUpload($field, $formAddElement);
$formEditElement = $this->getImageUpload($field, $formEditElement);
}
else if ($field == 'status')
{
//如果是状态字段
$formAddElement = "{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}";
$formEditElement = "{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], \$row['status'])}";
}
}
//构造添加和编辑HTML信息
$addList[] = $this->getFormGroup($field, $formAddElement);
$editList[] = $this->getFormGroup($field, $formEditElement);
}
//过滤text类型字段
if ($v['DATA_TYPE'] != 'text')
{
//主键
if ($v['COLUMN_KEY'] == 'PRI')
{
$javascriptList[] = "{field: 'state', checkbox: true}";
}
//构造JS列信息
$javascriptList[] = $this->getJsColumn($field);
//排序方式,如果有weigh则按weigh,否则按主键排序
$order = $field == 'weigh' ? 'weigh' : $order;
}
}
//JS最后一列加上操作列
$javascriptList[] = str_repeat(" ", 24) . "{field: 'operate', title: __('Operate'), events: Table.api.events.operate, formatter: Table.api.formatter.operate}";
$addList = implode("\n", array_filter($addList));
$editList = implode("\n", array_filter($editList));
$javascriptList = implode(",\n", array_filter($javascriptList));
$langList = implode(",\n", array_filter($langList));
//表注释
$tableComment = $tableInfo['Comment'];
$tableComment = mb_substr($tableComment, -1) == '表' ? mb_substr($tableComment, 0, -1) . '管理' : $tableComment;
//最终将生成的文件路径
$controllerFile = $adminPath . 'controller' . DS . $controllerFile;
$javascriptFile = ROOT_PATH . 'public' . DS . 'assets' . DS . 'js' . DS . 'backend' . DS . $controllerUrl . '.js';
$addFile = $adminPath . 'view' . DS . $controllerUrl . DS . 'add.html';
$editFile = $adminPath . 'view' . DS . $controllerUrl . DS . 'edit.html';
$indexFile = $adminPath . 'view' . DS . $controllerUrl . DS . 'index.html';
$langFile = $adminPath . 'lang' . DS . Lang::detect() . DS . $controllerUrl . '.php';
$appNamespace = Config::get('app_namespace');
$moduleName = 'admin';
$controllerNamespace = "{$appNamespace}\\{$moduleName}\\controller" . ($controllerDir ? "\\" : "") . str_replace('/', "\\", $controllerDir);
$modelNamespace = "{$appNamespace}\\" . ($local ? $moduleName : "common") . "\\model";
$data = [
'controllerNamespace' => $controllerNamespace,
'modelNamespace' => $modelNamespace,
'controllerUrl' => $controllerUrl,
'controllerDir' => $controllerDir,
'controllerName' => $controllerName,
'modelName' => $modelName,
'tableComment' => $tableComment,
'iconName' => $iconName,
'order' => $order,
'table' => $table,
'tableName' => $tableName,
'addList' => $addList,
'editList' => $editList,
'javascriptList' => $javascriptList,
'langList' => $langList,
'modelAutoWriteTimestamp' => in_array('createtime', $fields) || in_array('updatetime', $fields) ? "'int'" : 'false',
'createTime' => in_array('createtime', $fields) ? "'createtime'" : 'false',
'updateTime' => in_array('updatetime', $fields) ? "'updatetime'" : 'false',
];
// 生成控制器文件
$result = $this->writeToFile('controller', $data, $controllerFile);
// 生成模型文件
$result = $this->writeToFile('model', $data, $modelFile);
// 生成视图文件
$result = $this->writeToFile('add', $data, $addFile);
$result = $this->writeToFile('edit', $data, $editFile);
$result = $this->writeToFile('index', $data, $indexFile);
// 生成JS文件
$result = $this->writeToFile('javascript', $data, $javascriptFile);
// 生成语言文件
if ($langList)
{
$result = $this->writeToFile('lang', $data, $langFile);
}
$output->writeln("<info>Build Successed</info>");
}
/**
* 写入到文件
* @param string $name
* @param array $data
* @param string $pathname
* @return mixed
*/
protected function writeToFile($name, $data, $pathname)
{
$search = $replace = [];
foreach ($data as $k => $v)
{
$search[] = "{%{$k}%}";
$replace[] = $v;
}
$stub = file_get_contents($this->getStub($name));
$content = str_replace($search, $replace, $stub);
if (!is_dir(dirname($pathname)))
{
mkdir(strtolower(dirname($pathname)), 0755, true);
}
return file_put_contents($pathname, $content);
}
/**
* 获取基础模板
* @param string $name
* @return string
*/
protected function getStub($name)
{
return __DIR__ . '/Crud/stubs/' . $name . '.stub';
}
protected function getLangItem($field, $content)
{
if (!Lang::has($field))
{
return <<<EOD
'{$field}' => '{$content}'
EOD;
}
else
{
return '';
}
}
/**
* 获取表单分组数据
* @param string $field
* @param string $content
* @return string
*/
protected function getFormGroup($field, $content)
{
$langField = ucfirst($field);
return<<<EOD
<div class="form-group">
<label for="c-{$field}" class="control-label col-xs-12 col-sm-2">{:__('{$langField}')}:</label>
<div class="col-xs-12 col-sm-8">
{$content}
</div>
</div>
EOD;
}
/**
* 获取图片模板数据
* @param string $field
* @param string $content
* @return array
*/
protected function getImageUpload($field, $content)
{
return <<<EOD
<div class="form-inline">
{$content}
<span><button id="plupload-{$field}" class="btn btn-danger plupload" ><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
</div>
EOD;
}
/**
* 获取JS列数据
* @param string $field
* @return string
*/
protected function getJsColumn($field)
{
$lang = ucfirst($field);
$html = str_repeat(" ", 24) . "{field: '{$field}', title: __('{$lang}')";
$formatter = '';
if ($field == 'status')
$formatter = 'status';
else if ($field == 'icon')
$formatter = 'icon';
else if ($field == 'flag')
$formatter = 'flag';
else if (substr($field, -4) == 'time')
$formatter = 'datetime';
else if (substr($field, -3) == 'url')
$formatter = 'url';
else if (substr($field, -5) == 'image')
$formatter = 'image';
if ($formatter)
$html .= ", formatter: Table.api.formatter." . $formatter . "}";
else
$html .= "}";
return $html;
}
}
... ...
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
{%addList%}
<div class="form-group hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<?php
namespace {%controllerNamespace%};
use app\common\controller\Backend;
use think\Controller;
use think\Request;
/**
* {%tableComment%}
*
* @icon {%iconName%}
*/
class {%controllerName%} extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('{%modelName%}');
}
}
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
{%editList%}
<div class="form-group hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading($heading.name, $heading.intro)}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<div class="dropdown btn-group">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> 设为正常</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> 设为隐藏</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: '{%controllerUrl%}/index',
add_url: '{%controllerUrl%}/add',
edit_url: '{%controllerUrl%}/edit',
del_url: '{%controllerUrl%}/del',
multi_url: '{%controllerUrl%}/multi',
table: '{%table%}',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
sortName: '{%order%}',
columns: [
[
{%javascriptList%}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return Controller;
});
\ No newline at end of file
... ...
<?php
return [
{%langList%}
];
... ...
<?php
namespace {%modelNamespace%};
use think\Model;
class {%modelName%} extends Model
{
// 自动写入时间戳字段
protected $autoWriteTimestamp = {%modelAutoWriteTimestamp%};
// 定义时间戳字段名
protected $createTime = {%createTime%};
protected $updateTime = {%updateTime%};
}
... ...
<?php
namespace app\admin\command;
use app\admin\model\AuthRule;
use ReflectionClass;
use ReflectionMethod;
use think\Cache;
use think\Config;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class Menu extends Command
{
protected $model = null;
protected function configure()
{
$this
->setName('menu')
->addOption('controller', 'c', Option::VALUE_REQUIRED, 'controller name,use \'all-controller\' when build all menu', null)
->setDescription('Build auth menu from controller');
}
protected function execute(Input $input, Output $output)
{
$this->model = new AuthRule();
$adminPath = dirname(__DIR__) . DS;
//控制器名
$controller = $input->getOption('controller') ? : '';
if (!$controller)
{
$output->error("please input controller name");
return;
}
if ($controller != 'all-controller')
{
$controllerArr = explode('/', $controller);
end($controllerArr);
$key = key($controllerArr);
$controllerArr[$key] = ucfirst($controllerArr[$key]);
$adminPath = dirname(__DIR__) . DS . 'controller' . DS . implode('/', $controllerArr) . '.php';
if (!is_file($adminPath))
{
$output->error("controller not found");
return;
}
$this->importRule($controller);
}
else
{
$this->model->destroy([]);
$controllerDir = $adminPath . 'controller' . DS;
// 扫描新的节点信息并导入
$treelist = $this->import($this->scandir($controllerDir));
}
Cache::rm("__menu__");
$output->info("Build Successed!");
}
/**
* 递归扫描文件夹
* @param string $dir
* @return array
*/
public function scandir($dir)
{
$result = [];
$cdir = scandir($dir);
foreach ($cdir as $value)
{
if (!in_array($value, array(".", "..")))
{
if (is_dir($dir . '/' . $value))
{
$result[$value] = $this->scandir($dir . '/' . $value);
}
else
{
$result[] = $value;
}
}
}
return $result;
}
/**
* 导入规则节点
* @param array $dirarr
* @param array $parentdir
* @return array
*/
public function import($dirarr, $parentdir = [])
{
$menuarr = [];
foreach ($dirarr as $k => $v)
{
if (is_array($v))
{
//当前是文件夹
$nowparentdir = array_merge($parentdir, [$k]);
$this->import($v, $nowparentdir);
}
else
{
//只匹配PHP文件
if (!preg_match('/^(\w+)\.php$/', $v, $matchone))
{
continue;
}
//导入文件
$controller = ($parentdir ? implode('/', $parentdir) . '/' : '') . $matchone[1];
$this->importRule($controller);
}
}
return $menuarr;
}
protected function importRule($controller)
{
$controllerArr = explode('/', $controller);
end($controllerArr);
$key = key($controllerArr);
$controllerArr[$key] = ucfirst($controllerArr[$key]);
//反射机制调用类的注释和方法名
$reflector = new ReflectionClass("\\app\\admin\\controller\\" . implode("\\", $controllerArr) . (Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : ''));
//只匹配公共的方法
$methods = $reflector->getMethods(ReflectionMethod::IS_PUBLIC);
$classComment = $reflector->getDocComment();
//忽略的类
if (stripos($classComment, "@internal") !== FALSE)
{
return;
}
preg_match_all('#(@.*?)\n#s', $classComment, $annotations);
$controllerIcon = 'fa fa-circle-o';
$controllerRemark = '';
//判断注释中是否设置了icon值
if (isset($annotations[1]))
{
foreach ($annotations[1] as $tag)
{
if (stripos($tag, '@icon') !== FALSE)
{
$controllerIcon = substr($tag, stripos($tag, ' ') + 1);
}
if (stripos($tag, '@remark') !== FALSE)
{
$controllerRemark = substr($tag, stripos($tag, ' ') + 1);
}
}
}
//过滤掉其它字符
$controllerTitle = trim(preg_replace(array('/^\/\*\*(.*)[\n\r\t]/', '/[\s]+\*\//', '/\*\s@(.*)/', '/[\s|\*]+/'), '', $classComment));
//先定入菜单的数据
$pid = 0;
$name = "/admin";
foreach (explode('/', $controller) as $k => $v)
{
$name .= '/' . strtolower($v);
$title = (!isset($controllerArr[$k + 1]) ? $controllerTitle : ucfirst($v));
$icon = (!isset($controllerArr[$k + 1]) ? $controllerIcon : 'fa fa-list');
$remark = (!isset($controllerArr[$k + 1]) ? $controllerRemark : '');
$title = $title ? $title : ucfirst($v);
$rulemodel = $this->model->get(['name' => $name]);
if (!$rulemodel)
{
$this->model
->data(['pid' => $pid, 'name' => $name, 'title' => $title, 'icon' => $icon, 'remark' => $remark, 'ismenu' => 1, 'status' => 'normal'])
->isUpdate(false)
->save();
$pid = $this->model->id;
}
else
{
$pid = $rulemodel->id;
}
}
$ruleArr = [];
foreach ($methods as $m => $n)
{
//过滤特殊的类
if (substr($n->name, 0, 2) == '__' || $n->name == '_initialize')
{
continue;
}
//只匹配符合的方法
if (!preg_match('/^(\w+)' . Config::get('action_suffix') . '/', $n->name, $matchtwo))
{
unset($methods[$m]);
continue;
}
$comment = $reflector->getMethod($n->name)->getDocComment();
//忽略的方法
if (stripos($comment, "@internal") !== FALSE)
{
continue;
}
//过滤掉其它字符
$comment = preg_replace(array('/^\/\*\*(.*)[\n\r\t]/', '/[\s]+\*\//', '/\*\s@(.*)/', '/[\s|\*]+/'), '', $comment);
$ruleArr[] = array('pid' => $pid, 'name' => $name . "/" . strtolower($n->name), 'icon' => 'fa fa-circle-o', 'title' => $comment ? $comment : $n->name, 'ismenu' => 0, 'status' => 'normal');
}
$this->model->saveAll($ruleArr);
}
}
... ...
<?php
use app\admin\library\Auth;
use app\common\model\Configvalue;
use fast\Form;
use think\Db;
function get_upload_multipart($savekey = '', $mimetype = '', $maxsize = '')
{
// 加载配置
$configvalue = new Configvalue;
// 上传参数配置配置
$uploadcfg = $configvalue->upload($savekey, $mimetype, $maxsize);
return json_encode(['policy' => $uploadcfg['policy'], 'signature' => $uploadcfg['signature']]);
}
function get_flag_list()
{
return [
'h' => __('Hot'),
'i' => __('Index'),
'r' => __('Recommend'),
];
}
/**
* 生成下拉列表
* @param string $name
* @param mixed $options
* @param mixed $selected
* @param mixed $attr
* @return string
*/
function build_select($name, $options, $selected = [], $attr = [])
{
$options = is_array($options) ? $options : explode(',', $options);
$selected = is_array($selected) ? $selected : explode(',', $selected);
return Form::select($name, $options, $selected, $attr);
}
/**
* 生成单选按钮组
* @param string $name
* @param array $list
* @param mixed $selected
* @return string
*/
function build_radios($name, $list = [], $selected = null)
{
$html = [];
$selected = is_null($selected) ? key($list) : $selected;
foreach ($list as $k => $v)
{
$html[] = sprintf(Form::label("{$name}-{$k}", "%s {$v}"), Form::radio($name, $k, $k == $selected, ['id' => "{$name}-{$k}"]));
}
return implode(' ', $html);
}
/**
* 生成复选按钮组
* @param string $name
* @param array $list
* @param mixed $selected
* @return string
*/
function build_checkboxs($name, $list = [], $selected = null)
{
$html = [];
$selected = is_null($selected) ? [] : $selected;
foreach ($list as $k => $v)
{
$html[] = sprintf(Form::label("{$name}-{$k}", "%s {$v}"), Form::checkbox($name, $k, $k == $selected, ['id' => "{$name}-{$k}"]));
}
return implode(' ', $html);
}
/**
* 生成表格操作按钮栏
* @param array $btns
* @return string
*/
function build_toolbar($btns = NULL)
{
$btns = $btns ? $btns : ['refresh', 'add', 'edit', 'delete'];
$btns = is_array($btns) ? $btns : explode(',', $btns);
$addbtn = __('Add');
$editbtn = __('Edit');
$deletebtn = __('Delete');
$html = [];
if (in_array('refresh', $btns))
{
$html[] = '<a class="btn btn-primary btn-refresh" ><i class="fa fa-refresh"></i></a>';
}
if (in_array('add', $btns))
{
$html[] = '<a class="btn btn-success btn-add" ><i class="fa fa-plus"></i> ' . $addbtn . '</a>';
}
if (in_array('edit', $btns))
{
$html[] = '<a class="btn btn-success btn-edit btn-disabled disabled" ><i class="fa fa-pencil"></i> ' . $editbtn . '</a>';
}
if (in_array('delete', $btns))
{
$html[] = '<a class="btn btn-danger btn-del btn-disabled disabled" ><i class="fa fa-trash"></i> ' . $deletebtn . '</a>';
}
return implode(' ', $html);
}
/**
* 生成页面Heading
*
* @param string $title
* @param string $content
* @return string
*/
function build_heading($title = NULL, $content = NULL)
{
if (is_null($title) && is_null($content))
{
// 根据当前的URI自动匹配父节点的标题和备注
$path = Auth::instance()->getRequestUri();
$data = Db::name('auth_rule')->where('id', 'IN', function($query) use($path)
{
$query->name('auth_rule')->where('name', $path)->field('pid');
})->find();
if ($data)
{
$title = $data['title'];
$content = $data['remark'];
}
}
if (!$content)
return '';
return '<div class="panel-heading"><div class="panel-lead"><em>' . $title . '</em>' . $content . '</div></div>';
}
... ...
<?php
//配置文件
return [
'url_common_param' => true,
'url_html_suffix' => '',
'controller_auto_search' => true,
];
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use fast\Http;
use fast\Tree;
use think\Db;
use think\Lang;
/**
* Ajax异步请求接口
* @internal
*/
class Ajax extends Backend
{
protected $noNeedLogin = ['dailybg', 'lang'];
protected $noNeedRight = ['*'];
protected $layout = '';
/**
* 自动完成
*/
public function typeahead()
{
$search = $this->_request->getRequest("search");
$field = $this->_request->getRequest("field");
$field = str_replace(['row[', ']'], '', $field);
if (substr($field, -3) !== '_id' && substr($field, -4) !== '_ids')
{
$this->code = -1;
return;
}
$searchfield = 'name';
$field = substr($field, 0, -3);
switch ($field)
{
case 'category':
$field = 'category';
$searchfield = 'name';
break;
case 'user':
$searchfield = 'nickname';
break;
}
$searchlist = Db::table($field)
->orWhere($searchfield, 'like', "%{$search}%")
->orWhere('id', 'like', "%{$search}%")
->limit(10)
->select("id,{$searchfield} AS name");
foreach ($searchlist as $k => &$v)
{
$v['name'] = $v['name'] . "[id:{$v['id']}]";
}
unset($v);
$this->code = 1;
$this->data = ['searchlist' => $searchlist];
}
/**
* 加载语言包
*/
public function lang()
{
header('Content-Type: application/javascript');
$modulename = $this->request->module();
$callback = $this->request->get('callback');
$controllername = input("controllername");
Lang::load(APP_PATH . $modulename . '/lang/' . Lang::detect() . '/' . str_replace('.', '/', $controllername) . '.php');
//强制输出JSON Object
// $result = 'define(' . json_encode(Lang::get(), JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE) . ');';
return jsonp(Lang::get());
}
/**
* 每日一图
*/
public function dailybg()
{
//采用Infinty的图片
$this->code = 1;
$this->data = [
'url' => 'http://img.infinitynewtab.com/wallpaper/' . (date("Ymd") % 4000) . '.jpg'
];
return;
//采用Bing每日一图
$ret = Http::sendRequest("http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1", [], 'GET');
if ($ret['ret'])
{
$json = json_decode($ret['msg'], TRUE);
if ($json && isset($json['images'][0]))
{
$url = $json['images'][0]['url'];
$startdate = $json['images'][0]['startdate'];
$enddate = $json['images'][0]['enddate'];
$copyright = $json['images'][0]['copyright'];
$url = substr($url, 0, 4) != 'http' ? 'http://cn.bing.com' . $url : $url;
$title = '';
$intro = '';
$ret = Http::sendRequest("http://cn.bing.com/cnhp/coverstory/", [], 'GET');
if ($ret['ret'])
{
$info = json_decode($ret['msg'], TRUE);
if (isset($info['title']))
{
$title = $info['title'];
$intro = $info['para1'];
}
}
$this->code = 1;
$this->data = [
'title' => $title,
'intro' => $intro,
'url' => $url,
'startdate' => $startdate,
'enddate' => $enddate,
'copyright' => $copyright,
];
}
}
}
/**
* 读取角色权限树
*/
public function roletree()
{
$model = model('AuthGroup');
$id = $this->request->post("id");
$pid = $this->request->post("pid");
$parentgroupmodel = $model->get($pid);
$currentgroupmodel = NULL;
if ($id)
{
$currentgroupmodel = $model->get($id);
}
if (($pid || $parentgroupmodel) && (!$id || $currentgroupmodel))
{
$id = $id ? $id : NULL;
//读取父类角色所有节点列表
$parentrulelist = model('AuthRule')->all(in_array('*', explode(',', $parentgroupmodel->rules)) ? NULL : $parentgroupmodel->rules);
//读取当前角色下规则ID集合
$admin_rule_ids = $this->auth->getRuleIds();
$superadmin = $this->auth->isSuperAdmin();
$current_rule_ids = $id ? explode(',', $currentgroupmodel->rules) : [];
if (!$id || !array_key_exists($pid, Tree::instance()->init($model->all(['status' => 'normal']))->getChildrenIds($id, TRUE)))
{
//构造jstree所需的数据
$nodelist = [];
foreach ($parentrulelist as $k => $v)
{
if (!$superadmin && !in_array($v['id'], $admin_rule_ids))
continue;
$state = array('selected' => !$v['ismenu'] && in_array($v['id'], $current_rule_ids));
$nodelist[] = array('id' => $v['id'], 'parent' => $v['pid'] ? $v['pid'] : '#', 'text' => $v['title'], 'type' => 'menu', 'state' => $state);
}
$this->code = 1;
$this->data = $nodelist;
}
else
{
$this->code = -1;
$this->data = __('Can not change the parent to child');
}
}
else
{
$this->code = -1;
$this->data = __('Group not found');
}
}
/**
* 上传文件
*/
public function upload()
{
$this->code = -1;
$this->data = NULL;
$file = $this->request->file('file');
dump($file);
$uploaddir = '/public/uploads/';
$info = $file->move(ROOT_PATH . $uploaddir);
if ($info)
{
$this->code = 1;
$this->data = $uploaddir . $info->getSaveName();
}
else
{
// 上传失败获取错误信息
$this->data = $file->getError();
}
}
/**
* 通用排序
*/
public function weigh()
{
//排序的数组
$ids = $this->request->post("ids");
//拖动的记录ID
$changeid = $this->request->post("changeid");
//操作字段
$field = $this->request->post("field");
//操作的数据表
$table = $this->request->post("table");
//排序的方式
$orderway = $this->request->post("orderway", 'strtolower');
$orderway = $orderway == 'asc' ? 'ASC' : 'DESC';
$sour = $weighdata = [];
$ids = explode(',', $ids);
$prikey = 'id';
$pid = $this->request->post("pid");
// 如果设定了pid的值,此时只匹配满足条件的ID,其它忽略
if ($pid !== '')
{
$hasids = [];
$list = Db::name($table)->where($prikey, 'in', $ids)->where('pid', 'in', $pid)->field('id,pid')->select();
foreach ($list as $k => $v)
{
$hasids[] = $v['id'];
}
$ids = array_values(array_intersect($ids, $hasids));
}
//直接修复排序
$one = Db::name($table)->field("{$field},COUNT(*) AS nums")->group($field)->having('nums > 1')->find();
if ($one)
{
$list = Db::name($table)->field("$prikey,$field")->order($field, $orderway)->select();
foreach ($list as $k => $v)
{
Db::name($table)->where($prikey, $v[$prikey])->update([$field => $k + 1]);
}
$this->code = 1;
}
else
{
$list = Db::name($table)->field("$prikey,$field")->where($prikey, 'in', $ids)->order($field, $orderway)->select();
foreach ($list as $k => $v)
{
$sour[] = $v[$prikey];
$weighdata[$v[$prikey]] = $v[$field];
}
$position = array_search($changeid, $ids);
$desc_id = $sour[$position]; //移动到目标的ID值,取出所处改变前位置的值
$sour_id = $changeid;
$desc_value = $weighdata[$desc_id];
$sour_value = $weighdata[$sour_id];
//echo "移动的ID:{$sour_id}\n";
//echo "替换的ID:{$desc_id}\n";
$weighids = array();
$temp = array_values(array_diff_assoc($ids, $sour));
foreach ($temp as $m => $n)
{
if ($n == $sour_id)
{
$offset = $desc_id;
}
else
{
if ($sour_id == $temp[0])
{
$offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id;
}
else
{
$offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id;
}
}
$weighids[$n] = $weighdata[$offset];
Db::name($table)->where($prikey, $n)->update([$field => $weighdata[$offset]]);
}
$this->code = 1;
}
}
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
* 控制台
*
* @icon fa fa-dashboard
* @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据
*/
class Dashboard extends Backend
{
public function index()
{
$seventtime = \fast\Date::unixtime('day', -7);
$paylist = $createlist = [];
for ($i = 0; $i < 7; $i++)
{
$day = date("Y-m-d", $seventtime + ($i * 86400));
$createlist[$day] = mt_rand(20, 200);
$paylist[$day] = mt_rand(1, mt_rand(1, $createlist[$day]));
}
$this->view->assign([
'totaluser' => 3500,
'totalviews' => 219390,
'totalorder' => 32143,
'totalorderamount' => 174800,
'todayuserlogin' => 321,
'todayusersignup' => 430,
'todayorder' => 2324,
'todayunsettleorder' => 132,
'sevendnu' => '80%',
'sevendau' => '32%',
'paylist' => $paylist,
'createlist' => $createlist,
]);
return $this->view->fetch();
}
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use fast\Menu;
use think\Validate;
/**
* 后台首页
* @internal
*/
class Index extends Backend
{
protected $noNeedLogin = ['login', 'logout'];
protected $noNeedRight = ['index'];
protected $layout = '';
public function _initialize()
{
parent::_initialize();
}
/**
* 后台首页
*/
public function index()
{
//
$menulist = Menu::instance()->sidebar([
'dashboard' => 'hot',
'auth' => ['new', 'red', 'badge'],
'auth/admin' => 12,
'auth/rule' => 4,
'general' => ['18', 'purple'],
]);
$this->view->assign('menulist', $menulist);
$this->view->assign('title', __('Home'));
return $this->view->fetch();
}
/**
* 管理员登录
*/
public function login()
{
$url = $this->request->get('url', 'index/index');
if ($this->auth->isLogin())
{
$this->error(__("You've logged in, do not login again"), $url);
return;
}
if ($this->request->isPost())
{
$username = $this->request->post('username');
$password = $this->request->post('password');
$keeplogin = $this->request->post('keeplogin');
$token = $this->request->post('__token__');
$rule = [
'username' => 'require|length:3,30',
'password' => 'require|length:3,30',
'__token__' => 'token',
];
$data = [
'username' => $username,
'password' => $password,
'__token__' => $token,
];
$validate = new Validate($rule);
$result = $validate->check($data);
if (!$result)
{
$this->error($validate->getError());
return;
}
$result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
if ($result === true)
{
$this->success(__('Login success'), $url);
return;
}
else
{
$this->success(__('Username or password is incorrect'), $url);
}
return;
}
// 根据客户端的cookie,判断是否可以自动登录
if ($this->auth->autologin())
{
$this->redirect($url);
}
$this->view->assign('title', __('Login'));
return $this->view->fetch();
}
/**
* 注销登录
*/
public function logout()
{
$this->auth->logout();
$this->success(__('Logout success!'), 'index/login');
return;
}
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
* 单页管理
*
* @icon fa fa-circle-o
* @remark 用于管理普通的单页面,通常用于关于我们、联系我们、商务合作等单一页面
*/
class Page extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('Page');
}
}
... ...
<?php
namespace app\admin\controller\auth;
use app\common\controller\Backend;
use fast\Random;
use fast\Tree;
/**
* 管理员管理
*
* @icon fa fa-users
* @remark 一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成
*/
class Admin extends Backend
{
protected $model = null;
//当前登录管理员所有子节点组别
protected $childrenIds = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('Admin');
$groups = $this->auth->getGroups();
// 取出所有分组
$grouplist = model('AuthGroup')->all(['status' => 'normal']);
$objlist = [];
foreach ($groups as $K => $v)
{
// 取出包含自己的所有子节点
$childrenlist = Tree::instance()->init($grouplist)->getChildren($v['id'], TRUE);
$obj = Tree::instance()->init($childrenlist)->getTreeArray($v['pid']);
$objlist = array_merge($objlist, Tree::instance()->getTreeList($obj));
}
$groupdata = [];
foreach ($objlist as $k => $v)
{
$groupdata[$v['id']] = $v['name'];
}
$this->childrenIds = array_keys($groupdata);
$this->view->assign('groupdata', $groupdata);
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$params['salt'] = Random::basic(4);
$params['password'] = md5(md5($params['password']) . $params['salt']);
$admin = $this->model->create($params);
$group = $this->request->post("group/a");
//过滤不允许的组别,避免越权
$group = array_intersect($this->childrenIds, $group);
$dataset = [];
foreach ($group as $value)
{
$dataset[] = ['uid' => $admin->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
if ($params['password'])
{
$params['salt'] = Random::basic(4);
$params['password'] = md5(md5($params['password']) . $params['salt']);
}
$row->save($params);
// 先移除所有权限
model('AuthGroupAccess')->where('uid', $row->id)->delete();
$group = $this->request->post("group/a");
// 过滤不允许的组别,避免越权
$group = array_intersect($this->childrenIds, $group);
$dataset = [];
foreach ($group as $value)
{
$dataset[] = ['uid' => $row->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
$this->code = 1;
}
return;
}
$grouplist = $this->auth->getGroups($row['id']);
$groupids = [];
foreach ($grouplist as $k => $v)
{
$groupids[] = $v['id'];
}
$this->view->assign("row", $row);
$this->view->assign("groupids", $groupids);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
model('AuthGroupAccess')->where('uid', 'in', $ids)->delete();
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\auth;
use app\common\controller\Backend;
use fast\Tree;
/**
* 角色组
*
* @icon fa fa-group
* @remark 角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别下级的角色组或管理员
*/
class Group extends Backend
{
protected $model = null;
//当前登录管理员所有子节点组别
protected $childrenIds = [];
//当前组别列表数据
protected $groupdata = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('AuthGroup');
$groups = $this->auth->getGroups();
// 取出所有分组
$grouplist = model('AuthGroup')->all(['status' => 'normal']);
$objlist = [];
foreach ($groups as $K => $v)
{
// 取出包含自己的所有子节点
$childrenlist = Tree::instance()->init($grouplist)->getChildren($v['id'], TRUE);
$obj = Tree::instance()->init($childrenlist)->getTreeArray($v['pid']);
$objlist = array_merge($objlist, Tree::instance()->getTreeList($obj));
}
$groupdata = [];
foreach ($objlist as $k => $v)
{
$groupdata[$v['id']] = $v['name'];
}
$this->groupdata = $groupdata;
$this->childrenIds = array_keys($groupdata);
$this->view->assign('groupdata', $groupdata);
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
$list = [];
foreach ($this->groupdata as $k => $v)
{
$data = $this->model->get($k);
$data->name = $v;
$list[] = $data;
}
$total = count($list);
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
$params['rules'] = explode(',', $params['rules']);
if (!in_array($params['pid'], $this->childrenIds))
{
$this->code = -1;
return;
}
$parentmodel = model("AuthGroup")->get($params['pid']);
if (!$parentmodel)
{
$this->code = -1;
return;
}
// 父级别的规则节点
$parentrules = explode(',', $parentmodel->rules);
// 当前组别的规则节点
$currentrules = $this->auth->getRuleIds();
$rules = $params['rules'];
// 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限
$rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules);
// 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限
$rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules);
$params['rules'] = implode(',', $rules);
if ($params)
{
$this->model->create($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
// 复节点不能是它自身的子节点
if (!in_array($params['pid'], $this->childrenIds))
{
$this->code = -1;
return;
}
$params['rules'] = explode(',', $params['rules']);
$parentmodel = model("AuthGroup")->get($params['pid']);
if (!$parentmodel)
{
$this->code = -1;
return;
}
// 父级别的规则节点
$parentrules = explode(',', $parentmodel->rules);
// 当前组别的规则节点
$currentrules = $this->auth->getRuleIds();
$rules = $params['rules'];
// 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限
$rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules);
// 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限
$rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules);
$params['rules'] = implode(',', $rules);
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$ids = explode(',', $ids);
$grouplist = $this->auth->getGroups();
$group_ids = array_map(function($group)
{
return $group['id'];
}, $grouplist);
// 移除掉当前管理员所在组别
$ids = array_diff($ids, $group_ids);
// 循环判断每一个组别是否可删除
$grouplist = $this->model->where('id', 'in', $ids)->select();
$groupaccessmodel = model('AuthGroupAccess');
foreach ($grouplist as $k => $v)
{
// 当前组别下有管理员
$groupone = $groupaccessmodel->get(['group_id' => $v['id']]);
if ($groupone)
{
$ids = array_diff($ids, [$v['id']]);
continue;
}
// 当前组别下有子组别
$groupone = $this->model->get(['pid' => $v['id']]);
if ($groupone)
{
$ids = array_diff($ids, [$v['id']]);
continue;
}
}
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
// 组别禁止批量操作
$this->code = -1;
return;
}
}
... ...
<?php
namespace app\admin\controller\auth;
use app\common\controller\Backend;
use fast\Tree;
/**
* 规则管理
*
* @icon fa fa-list
* @remark 规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过控制台进行生成规则节点
*/
class Rule extends Backend
{
protected $model = null;
protected $rulelist = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('AuthRule');
// 必须将结果集转换为数组
Tree::instance()->init(collection($this->model->order('weigh', 'desc')->select())->toArray());
$this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
$ruledata = [];
foreach ($this->rulelist as $k => $v)
{
$ruledata[$v['id']] = $v['title'];
}
$this->view->assign('ruledata', $ruledata);
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
$list = $this->rulelist;
$total = count($this->rulelist);
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$this->model->create($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 附件管理
*
* @icon fa fa-circle-o
* @remark 主要用于管理上传到又拍云的数据或上传至本服务的上传数据
*/
class Attachment extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('Attachment');
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
if ($this->request->has('field'))
{
//JSON字段
$fieldarr = $valuearr = [];
$field = $this->request->post('field/a');
$value = $this->request->post('value/a');
foreach ($field as $k => $v)
{
if ($v != '')
{
$fieldarr[] = $field[$k];
$valuearr[] = $value[$k];
}
}
$params['content'] = array_combine($fieldarr, $valuearr);
}
$this->model->save($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
$this->code = -1;
$ids = $ids ? $ids : $this->request->param("ids");
if ($ids)
{
if ($this->request->has('params'))
{
parse_str($this->request->post("params"), $values);
$values = array_intersect_key($values, array_flip(array('status')));
if ($values)
{
$count = $this->model->where('id', 'in', $ids)->update($values);
if ($count)
{
$this->code = 1;
}
}
}
else
{
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 基本配置
*
* @icon fa fa-cog
* @remark 用于管理一些字典数据,通常以键值格式进行录入,保存的数据格式为JSON
*/
class Configvalue extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('Configvalue');
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
if ($this->request->has('field'))
{
//JSON字段
$fieldarr = $valuearr = [];
$field = $this->request->post('field/a');
$value = $this->request->post('value/a');
foreach ($field as $k => $v)
{
if ($v != '')
{
$fieldarr[] = $field[$k];
$valuearr[] = $value[$k];
}
}
$params['content'] = array_combine($fieldarr, $valuearr);
}
$this->model->save($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
if ($this->request->has('field'))
{
//JSON字段
$fieldarr = $valuearr = [];
$field = $this->request->post('field/a');
$value = $this->request->post('value/a');
foreach ($field as $k => $v)
{
if ($v != '')
{
$fieldarr[] = $field[$k];
$valuearr[] = $value[$k];
}
}
$params['content'] = array_combine($fieldarr, $valuearr);
}
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
$this->code = -1;
$ids = $ids ? $ids : $this->request->param("ids");
if ($ids)
{
if ($this->request->has('params'))
{
parse_str($this->request->post("params"), $values);
$values = array_intersect_key($values, array_flip(array('status')));
if ($values)
{
$count = $this->model->where('id', 'in', $ids)->update($values);
if ($count)
{
$this->code = 1;
}
}
}
else
{
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 定时任务
*
* @icon fa fa-tasks
* @remark 类似于Linux的Crontab定时任务,可以按照设定的时间进行任务的执行,目前仅支持三种任务:请求URL、执行SQL、执行Shell
*/
class Crontab extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('Crontab');
$this->view->assign('typedata', [
'url' => __('Request Url'),
'sql' => __('Execute Sql Script'),
'shell' => __('Execute Shell'),
]);
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$this->model->create($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
$this->code = -1;
$ids = $ids ? $ids : $this->request->param("ids");
if ($ids)
{
if ($this->request->has('params'))
{
parse_str($this->request->post("params"), $values);
$values = array_intersect_key($values, array_flip(array('status')));
if ($values)
{
$count = $this->model->where('id', 'in', $ids)->update($values);
if ($count)
{
$this->code = 1;
}
}
}
else
{
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use think\Db;
use think\Debug;
/**
* 数据库管理
*
* @icon fa fa-database
* @remark 可在线进行一些简单的数据库表优化或修复,查看表结构和数据。也可以进行SQL语句的操作
*/
class Database extends Backend
{
/**
* 查看
*/
function index()
{
$tables_data_length = $tables_index_length = $tables_free_length = $tables_data_count = 0;
$tables = $list = [];
$list = Db::query("SHOW TABLES");
foreach ($list as $key => $row)
{
$tables[] = ['name' => reset($row), 'rows' => 0];
}
$data['tables'] = $tables;
/*
$one = Db::table('configvalue')->where('name', 'sql')->find();
$saved_sql = [];
if ($one && $one['content'])
$saved_sql = explode('###', $one['content']);
$data['saved_sql'] = array_values(array_filter($saved_sql));
* */
$data['saved_sql'] = [];
$this->view->assign($data);
return $this->view->fetch();
}
/**
* SQL查询
*/
public function query()
{
$do_action = $this->request->post('do_action');
echo '<style type="text/css">
xmp,body{margin:0;padding:0;line-height:18px;font-size:12px;font-family:"Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;}
hr{height:1px;margin:5px 1px;background:#e3e3e3;border:none;}
</style>';
if ($do_action == '')
exit(__('Invalid parameters'));
$tablename = $this->request->post("tablename/a");
if (in_array($do_action, array('doquery', 'optimizeall', 'repairall')))
{
$this->$do_action();
}
else if (count($tablename) == 0)
{
exit(__('Invalid parameters'));
}
else
{
foreach ($tablename as $table)
{
$this->$do_action($table);
echo "<br />";
}
}
}
private function viewinfo($name)
{
$row = Db::query("SHOW CREATE TABLE `{$name}`");
$row = array_values($row[0]);
$info = $row[1];
echo "<xmp>{$info};</xmp>";
}
private function viewdata($name = '')
{
$sqlquery = "SELECT * FROM `{$name}`";
$this->doquery($sqlquery);
}
private function optimize($name = '')
{
if (Db::execute("OPTIMIZE TABLE `{$name}`"))
{
echo __('Optimize table %s done', $name);
}
else
{
echo __('Optimize table %s fail', $name);
}
}
private function optimizeall($name = '')
{
$list = Db::query("SHOW TABLES");
foreach ($list as $key => $row)
{
$name = reset($row);
if (Db::execute("OPTIMIZE TABLE {$name}"))
{
echo __('Optimize table %s done', $name);
}
else
{
echo __('Optimize table %s fail', $name);
}
echo "<br />";
}
}
private function repair($name = '')
{
if (Db::execute("REPAIR TABLE `{$name}`"))
{
echo __('Repair table %s done', $name);
}
else
{
echo __('Repair table %s fail', $name);
}
}
private function repairall($name = '')
{
$list = Db::query("SHOW TABLES");
foreach ($list as $key => $row)
{
$name = reset($row);
if (Db::execute("REPAIR TABLE {$name}"))
{
echo __('Repair table %s done', $name);
}
else
{
echo __('Repair table %s fail', $name);
}
echo "<br />";
}
}
private function doquery($sql = null)
{
$sqlquery = $sql ? $sql : $this->request->post('sqlquery');
if ($sqlquery == '')
exit(__('SQL can not be empty'));
$sqlquery = str_replace("\r", "", $sqlquery);
$sqls = preg_split("/;[ \t]{0,}\n/i", $sqlquery);
$maxreturn = 100;
$r = '';
foreach ($sqls as $key => $val)
{
if (trim($val) == '')
continue;
$val = rtrim($val, ';');
$r .= "SQL:<span style='color:green;'>{$val}</span> ";
if (preg_match("/^(select|explain)(.*)/i ", $val))
{
Debug::remark("begin");
$limit = stripos(strtolower($val), "limit") !== false ? true : false;
$count = Db::execute($val);
if ($count > 0)
{
$resultlist = Db::query($val . (!$limit && $count > $maxreturn ? ' LIMIT ' . $maxreturn : ''));
}
else
{
$resultlist = [];
}
Debug::remark("end");
$time = Debug::getRangeTime('begin', 'end', 4);
$usedseconds = __('Query took %s seconds', $time) . "<br />";
if ($count <= 0)
{
$r .= __('Query returned an empty result');
}
else
{
$r .= (__('Total:%s', $count) . (!$limit && $count > $maxreturn ? ',' . __('Max output:%s', $maxreturn) : ""));
}
$r = $r . ',' . $usedseconds;
$j = 0;
foreach ($resultlist as $m => $n)
{
$j++;
if (!$limit && $j > $maxreturn)
break;
$r .= "<hr/>";
$r .= "<font color='red'>" . __('Row:%s', $j) . "</font><br />";
foreach ($n as $k => $v)
{
$r .= "<font color='blue'>{$k}:</font>{$v}<br/>\r\n";
}
}
}
else
{
Debug::remark("begin");
$count = Db::execute($val);
Debug::remark("end");
$time = Debug::getRangeTime('begin', 'end', 4);
$r .= __('Query affected %s rows and took %s seconds', $count, $time) . "<br />";
}
}
echo $r;
}
}
... ...
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 个人配置
*
* @icon fa fa-user
*/
class Profile extends Backend
{
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
$model = model('AdminLog');
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $model
->where($where)
->order($sort, $order)
->count();
$list = $model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 更新个人信息
*/
public function update()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
$params = array_filter(array_intersect_key($params, array_flip(array('email', 'nickname', 'password'))));
unset($v);
if (isset($params['password']))
{
$params['salt'] = Random::basic(4);
$params['password'] = md5(md5($params['password']) . $params['salt']);
}
if ($params)
{
model('admin')->where('id', Auth::id())->update($params);
$this->code = 0;
}
}
return;
}
}
... ...
<?php
namespace app\admin\controller\wechat;
use app\common\controller\Backend;
use app\common\model\WechatResponse;
use think\Db;
/**
* 微信自动回复管理
*
* @icon fa fa-circle-o
*/
class Autoreply extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('WechatAutoreply');
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = Db::table($this->table)->where('id', $ids)->get();
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$row->save($params);
$this->code = 1;
}
return FALSE;
}
$response = WechatResponse::get(['eventkey' => $row['eventkey']]);
$this->view->assign("response", $response);
$this->view->assign("row", $row);
}
}
... ...
<?php
namespace app\admin\controller\wechat;
use app\common\controller\Backend;
use app\common\model\Configvalue;
/**
* 配置管理
*
* @icon fa fa-list-alt
*/
class Config extends Backend
{
protected $wechatcfg = NULL;
protected $obj = [];
public function _initialize()
{
parent::_initialize();
$this->wechatcfg = Configvalue::get('wechat');
$this->obj = $this->wechatcfg->content;
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
$configlist = isset($this->obj['config']) ? $this->obj['config'] : [];
$list = array();
foreach ($configlist as $row)
{
$list[] = $row;
}
$total = count($list);
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->obj['config'][] = $this->request->post('row/a');
$this->wechatcfg->content = $this->obj;
$this->wechatcfg->save();
$this->code = 1;
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = [];
foreach ($this->obj['config'] as $k => $v)
{
if ($v['id'] == $ids)
{
$row = $v;
break;
}
}
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$params = $this->request->post('row/a');
$this->obj['config'][$k] = $params;
$this->obj['config'] = array_values($this->obj['config']);
$this->wechatcfg->content = $this->obj;
$this->wechatcfg->save();
$this->code = 1;
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$ids = is_array($ids) ? $ids : explode(',', $ids);
foreach ($this->obj['config'] as $k => $v)
{
if (in_array($v['id'], $ids))
{
unset($this->obj['config'][$k]);
}
}
$this->wechatcfg->content = $this->obj;
$this->wechatcfg->save();
$this->code = 1;
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
$this->code = -1;
//不支持指操作
return;
}
}
... ...
<?php
namespace app\admin\controller\wechat;
use app\common\controller\Backend;
use app\common\model\Configvalue;
use app\common\model\WechatResponse;
use EasyWeChat\Foundation\Application;
use think\Exception;
/**
* 菜单管理
*
* @icon fa fa-list-alt
*/
class Menu extends Backend
{
protected $wechatcfg = NULL;
public function _initialize()
{
parent::_initialize();
$this->wechatcfg = Configvalue::get('wechat');
}
/**
* 查看
*/
public function index()
{
$responselist = array();
$all = WechatResponse::all();
foreach ($all as $k => $v)
{
$responselist[$v['eventkey']] = $v['title'];
}
$this->view->assign('responselist', $responselist);
$this->view->assign('menu', $this->wechatcfg->content['menu']);
return $this->view->fetch();
}
/**
* 修改
*/
public function edit($ids = NULL)
{
$menu = $this->request->post("menu");
$menu = (array) json_decode($menu, TRUE);
$content = $this->wechatcfg->content;
$content['menu'] = $menu;
$this->wechatcfg->content = $content;
$this->wechatcfg->save();
$this->code = 1;
return;
}
/**
* 同步
*/
public function sync($ids = NULL)
{
$this->code = -1;
$app = new Application(Config::get('wechat')->toArray());
try
{
$ret = $app->menu->add($this->wechatcfg->content['menu']);
if ($ret->errcode == 0)
{
$this->code = 1;
}
else
{
$this->content = $ret->errmsg;
}
}
catch (Exception $e)
{
$this->content = $e->getMessage();
}
return;
}
}
... ...
<?php
namespace app\admin\controller\wechat;
use app\common\controller\Backend;
use fast\service\Wechat;
/**
* 资源管理
*
* @icon fa fa-list-alt
*/
class Response extends Backend
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('WechatResponse');
}
/**
* 选择素材
*/
public function select()
{
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
$params['eventkey'] = $params['eventkey'] ? $params['eventkey'] : uniqid();
$params['content'] = json_encode($params['content']);
$params['createtime'] = time();
if ($params)
{
$this->model->save($params);
$this->code = 1;
$this->content = $params;
}
return;
}
$appConfig = Wechat::appConfig();
$this->view->applist = $appConfig;
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get($ids);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
$params['eventkey'] = $params['eventkey'] ? $params['eventkey'] : uniqid();
$params['content'] = json_encode($params['content']);
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
$appConfig = Wechat::appConfig();
$this->view->applist = $appConfig;
return $this->view->fetch();
}
}
... ...
<?php
return [
'Keep login' => '保持会话',
'Sign in' => '登入',
'Username' => '用户名',
'User id' => '会员ID',
'Username' => '用户名',
'Nickname' => '昵称',
'Password' => '密码',
'Sign up' => '注 册',
'Sign in' => '登 录',
'Sign out' => '注 销',
'Keep login' => '保持会话',
'Guest' => '游客',
'Welcome' => '%s,你好!',
'Add' => '添加',
'Edit' => '编辑',
'Delete' => '删除',
'Move' => '移动',
'Name' => '名称',
'Status' => '状态',
'Weigh' => '权重',
'Operate' => '操作',
'Warning' => '温馨提示',
'Default' => '默认',
'Article' => '文章',
'Page' => '单页',
'OK' => '确定',
'Cancel' => '取消',
'Loading' => '加载中',
'More' => '更多',
'Normal' => '正常',
'Hidden' => '隐藏',
'Submit' => '提交',
'Reset' => '重置',
'Execute' => '执行',
'Close' => '关闭',
'Search' => '搜索',
'Refresh' => '刷新',
'First' => '首页',
'Previous' => '上一页',
'Next' => '下一页',
'Last' => '末页',
'None' => '无',
'Home' => '主页',
'Online' => '在线',
'Logout' => '注销',
'Profile' => '个人资料',
'Index' => '首页',
'Hot' => '热门',
'Recommend' => '推荐',
'Dashboard' => '控制台',
'Code' => '编号',
'Message' => '内容',
'Line' => '行号',
'File' => '文件',
'Menu' => '菜单',
'Name' => '名称',
'Weigh' => '权重',
'Type' => '类型',
'Title' => '标题',
'Content' => '内容',
'Status' => '状态',
'Operate' => '操作',
'Append' => '追加',
'Memo' => '备注',
'Parent' => '父级',
'Params' => '参数',
'Permission' => '权限',
'Advance search' => '高级搜索',
'Check all' => '选中全部',
'Expand all' => '展开全部',
'Begin time' => '开始时间',
'End time' => '结束时间',
'Create time' => '创建时间',
'Flag' => '标志',
'Redirect now' => '立即跳转',
'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!',
'Unknown data format' => '未知的数据格式!',
'Network error' => '网络错误!',
'Issues & Wiki' => '问题交流',
'Advanced search' => '高级搜索',
'%d second%s ago' => '%d秒前',
'%d minute%s ago' => '%d分钟前',
'%d hour%s ago' => '%d小时前',
'%d day%s ago' => '%d天前',
'%d week%s ago' => '%d周前',
'%d month%s ago' => '%d月前',
'%d year%s ago' => '%d年前',
//
'Invalid parameters' => '未知参数',
'No results were found' => '记录未找到',
'Parameter %s can not be empty' => '参数%s不能为空',
'Are you sure you want to delete the %s selected item?' => '确定删除选中的 %s 项?',
'Are you sure you want to delete this item?' => '确定删除此项?',
'Are you sure you want to delete or turncate?' => '确定删除或清空?',
'You have no permission' => '你没有权限访问',
'Please enter your username' => '请输入你的用户名',
'Please enter your password' => '请输入你的密码',
'Please login first' => '请登录后操作',
'You\'ve logged in, do not login again' => '你已经登录,无需重复登录',
'Username or password can not be empty' => '用户名密码不能为空',
'Username or password is incorrect' => '用户名或密码不正确',
'Username is incorrect' => '用户名不正确',
'Password is incorrect' => '密码不正确',
'Verification code is incorrect' => '验证码不正确',
'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中',
'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
];
... ...
<?php
return [
'Url' => '物理路径',
'Imagewidth' => '宽度',
'Imageheight' => '宽度',
'Imagetype' => '图片类型',
'Imageframes' => '图片帧数',
'Filesize' => '文件大小',
'Mimetype' => 'mime类型',
'Extparam' => '透传数据',
'Createtime' => '创建日期',
'Uploadtime' => '上传时间'
];
... ...
<?php
return [
'SQL Result' => '查询结果',
'Basic query' => '基础查询',
'View structure' => '基础查询',
'View data' => '基础查询',
'Optimize' => '优化表',
'Repair' => '修复表',
'Optimize all' => '优化全部表',
'Repair all' => '修复全部表',
'Table:%s' => '总计:%s个表',
'Record:%s' => '记录:%s条',
'Data:%s' => '占用:%s',
'Index:%s' => '索引:%s',
'SQL Result:' => '查询结果:',
'SQL can not be empty' => 'SQL语句不能为空',
'Max output:%s' => '最大返回%s条',
'Total:%s' => '共有%s条记录! ',
'Row:%s' => '记录:%s',
'Executes one or multiple queries which are concatenated by a semicolon' => '请输入SQL语句,支持批量查询,多条SQL以分号(,)分格',
'Query affected %s rows and took %s seconds' => '共影响%s条记录! 耗时:%s秒!',
'Query returned an empty result' => '返回结果为空!',
'Query took %s seconds' => '耗时%s秒!',
'Optimize table %s done' => '优化表[%s]成功',
'Repair table %s done' => '修复表[%s]成功',
'Optimize table %s fail' => '优化表[%s]失败',
'Repair table %s fail' => '修复表[%s]失败'
];
... ...
<?php
return [
'Title' => '标题',
'Layout Options' => '布局设定',
'Fixed Layout' => '固定布局',
'You can\'t use fixed and boxed layouts together' => '盒子模型和固定布局不能同时启作用',
'Boxed Layout' => '盒子布局',
'Activate the boxed layout' => '盒子布局最大宽度将被限定为1250px',
'Toggle Sidebar' => '切换菜单栏',
'Toggle the left sidebar\'s state (open or collapse)' => '切换菜单栏的展示或收起',
'Sidebar Expand on Hover' => '菜单栏自动展开',
'Let the sidebar mini expand on hover' => '鼠标移到菜单栏自动展开',
'Toggle Right Sidebar Slide' => '切换右侧操作栏',
'Toggle between slide over content and push content effects' => '切换右侧操作栏覆盖或独占',
'Toggle Right Sidebar Skin' => '切换右侧操作栏背景',
'Toggle between dark and light skins for the right sidebar' => '将右侧操作栏背景亮色或深色切换',
'Show sub menu' => '显示菜单栏子菜单',
'Always show sub menu' => '菜单栏子菜单将始终显示',
'Disable top menu badge' => '禁用顶部彩色小角标',
'Disable top menu badge without left menu' => '左边菜单栏的彩色小角标不受影响',
'Skins' => '皮肤',
];
... ...
<?php
return [
'id' => 'ID',
'category_id' => '分类ID',
'title' => '标题',
'keywords' => '关键字',
'flag' => '标志',
'image' => '头像',
'content' => '内容',
'icon' => '图标',
'views' => '点击',
'comments' => '评论',
'weigh' => '权重',
'status' => '状态'
];
... ...
<?php
namespace app\admin\library;
use app\admin\model\Admin;
use fast\Random;
use think\Cookie;
use think\Request;
use think\Session;
class Auth extends \fast\Auth
{
protected $requestUri = '';
public function __construct()
{
parent::__construct();
}
public function __get($name)
{
return Session::get('admin.' . $name);
}
public function login($username, $password, $keeptime = 0)
{
$admin = Admin::get(['username' => $username]);
if (!$admin)
{
return false;
}
if ($admin->password != md5(md5($password) . $admin->salt))
{
$admin->loginfailure++;
$admin->save();
return false;
}
$admin->loginfailure = 0;
$admin->logintime = time();
$admin->token = Random::uuid();
$admin->save();
Session::set("admin", $admin);
$this->keeplogin($keeptime);
return true;
}
/**
* 注销登录
*/
public function logout()
{
$admin = Admin::get(intval($this->id));
if (!$admin)
{
return true;
}
$admin->token = '';
$admin->save();
Session::delete("admin");
Cookie::delete("keeplogin");
return true;
}
/**
* 自动登录
* @return boolean
*/
public function autologin()
{
$keeplogin = Cookie::get('keeplogin');
if (!$keeplogin)
{
return false;
}
list($id, $keeptime, $expiretime, $key) = explode('|', $keeplogin);
if ($id && $keeptime && $expiretime && $key && $expiretime > time())
{
$admin = Admin::get($id);
if (!$admin)
{
return false;
}
//token有变更
if ($key != md5(md5($id) . md5($keeptime) . md5($expiretime) . $admin->token))
{
return false;
}
Session::set("admin", $admin);
//刷新自动登录的时效
$this->keeplogin($keeptime);
return true;
}
else
{
return false;
}
}
/**
* 刷新保持登录的Cookie
* @param int $keeptime
* @return boolean
*/
protected function keeplogin($keeptime = 0)
{
if ($keeptime)
{
$expiretime = time() + $keeptime;
$key = md5(md5($this->id) . md5($keeptime) . md5($expiretime) . $this->token);
$data = [$this->id, $keeptime, $expiretime, $key];
Cookie::set('keeplogin', implode('|', $data));
return true;
}
return false;
}
public function check($name, $uid = '', $relation = 'or', $mode = 'url')
{
return parent::check($name, $this->id, $relation, $mode);
}
/**
* 检测当前控制器和方法是否匹配传递的数组
*
* @param array $arr 需要验证权限的数组
*/
public function match($arr = [])
{
$request = Request::instance();
$arr = is_array($arr) ? $arr : explode(',', $arr);
if (!$arr)
{
return FALSE;
}
// 是否存在
if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
{
return TRUE;
}
// 没找到匹配
return FALSE;
}
/**
* 检测是否登录
*
* @return boolean
*/
public function isLogin()
{
return Session::get('admin') ? true : false;
}
/**
* 获取当前请求的URI
* @return string
*/
public function getRequestUri()
{
return $this->requestUri;
}
/**
* 设置当前请求的URI
* @param string $uri
*/
public function setRequestUri($uri)
{
$this->requestUri = $uri;
}
public function getGroups($uid = null)
{
$uid = is_null($uid) ? $this->id : $uid;
return parent::getGroups($uid);
}
public function getRuleList($uid = null)
{
$uid = is_null($uid) ? $this->id : $uid;
return parent::getRuleList($uid);
}
public function getUserInfo($uid = null)
{
$uid = is_null($uid) ? $this->id : $uid;
return $uid != $this->id ? Admin::get(intval($uid)) : Session::get('admin');
}
public function getRuleIds($uid = null)
{
$uid = is_null($uid) ? $this->id : $uid;
return parent::getRuleIds($uid);
}
public function isSuperAdmin()
{
return in_array('*', $this->getRuleIds()) ? TRUE : FALSE;
}
}
... ...
<?php
namespace app\admin\library\traits;
trait Backend
{
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$this->model->create($params);
$this->code = 1;
}
return;
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get(['id' => $ids]);
if (!$row)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
$this->code = -1;
$params = $this->request->post("row/a");
if ($params)
{
$row->save($params);
$this->code = 1;
}
return;
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
$this->code = -1;
if ($ids)
{
$count = $this->model->where('id', 'in', $ids)->delete();
if ($count)
{
$this->code = 1;
}
}
return;
}
/**
* 批量更新
*/
public function multi($ids = "")
{
$this->code = -1;
$ids = $ids ? $ids : $this->request->param("ids");
if ($ids)
{
if ($this->request->has('params'))
{
parse_str($this->request->post("params"), $values);
$values = array_intersect_key($values, array_flip(array('status')));
if ($values)
{
$count = $this->model->where('id', 'in', $ids)->update($values);
if ($count)
{
$this->code = 1;
}
}
}
else
{
$this->code = 1;
}
}
return;
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
use think\Session;
class Admin extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
/**
* 重置用户密码
* @author baiyouwen
*/
public function resetPassword($uid, $NewPassword)
{
$passwd = $this->encryptPassword($NewPassword);
$ret = $this->where(['id' => $uid])->update(['password' => $passwd]);
return $ret;
}
// 密码加密
protected function encryptPassword($password, $salt = '', $encrypt = 'md5')
{
return $encrypt($password . $salt);
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class AdminLog extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = '';
public static function record($title, $content = '', $username = '')
{
$admin = \think\Session::get('admin');
$admin_id = $admin ? $admin->id : 0;
$username = $username ? $username : ($admin ? $admin->username : __(''));
self::create([
'title' => $title,
'content' => $content,
'url' => request()->url(),
'admin_id' => $admin_id,
'username' => $username
]);
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class AuthGroup extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class AuthGroupAccess extends Model
{
//
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class AuthRule extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class Page extends Model
{
// 自动写入时间戳字段
protected $autoWriteTimestamp = false;
// 定义时间戳字段名
protected $createTime = false;
protected $updateTime = false;
}
... ...
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="role_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="username" name="row[username]" value="" pattern="[A-Za-z0-9_]{3,}" required="required" />
</div>
</div>
<div class="form-group">
<label for="email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="email" class="form-control" id="email" name="row[email]" value="" required="required" />
</div>
</div>
<div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="nickname" name="row[nickname]" value="" required="required" />
</div>
</div>
<div class="form-group">
<label for="password" class="control-label col-xs-12 col-sm-2">{:__('Password')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="password" class="form-control" id="password" name="row[password]" value="" required="required" />
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
\ No newline at end of file
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="role_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>''])}
</div>
</div>
<div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="username" name="row[username]" value="{$row.username}" pattern="[A-Za-z0-9_]{3,}" required="required" />
</div>
</div>
<div class="form-group">
<label for="email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="email" class="form-control" id="email" name="row[email]" value="{$row.email}" required="required" />
</div>
</div>
<div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="nickname" name="row[nickname]" value="{$row.nickname}" required="required" />
</div>
</div>
<div class="form-group">
<label for="password" class="control-label col-xs-12 col-sm-2">{:__('Password')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="password" class="form-control" id="password" name="row[password]" value="" />
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
\ No newline at end of file
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
</div>
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
... ...
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" data-before-submit="refreshrules" action="">
<input type="hidden" name="row[rules]" value="" />
<div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="username" 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="" required="required" />
</div>
</div>
<div class="form-group">
<label for="nickname" 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"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" data-before-submit="refreshrules" action="">
<input type="hidden" name="row[rules]" value="" />
<div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, $row['pid'], ['class'=>'form-control selectpicker', 'required'=>'', 'data-id'=>$row['id'], 'data-pid'=>$row['pid']])}
</div>
</div>
<div class="form-group">
<label for="username" 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}" required="required" />
</div>
</div>
<div class="form-group">
<label for="nickname" 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"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2 col-xs-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
</div>
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<div class="callout callout-info">
<h4>{:__('Alert')}!</h4>
{:__('If not necessary, use the rebuild node feature directly')}
</div>
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, null, ['class'=>'form-control selectpicker', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="name" 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="" required="required" />
</div>
</div>
<div class="form-group">
<label for="module" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="" required="required" />
</div>
</div>
<div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md">
<input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-dot" />
<a href="javascript:;" class="btn-search-icon input-group-addon">搜索图标</a>
</div>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" required="required" />
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]"></textarea>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]"></textarea>
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hidden layer-footer">
<div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
{include file="auth/rule/tpl" /}
\ No newline at end of file
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
<div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control selectpicker', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="action" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" required="required" />
</div>
</div>
<div class="form-group">
<label for="name" 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}" required="required" />
</div>
</div>
<div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md">
<input type="text" class="form-control" id="icon" name="row[icon]" value="{$row.icon}" />
<a href="javascript:;" class="btn-search-icon input-group-addon">搜索图标</a>
</div>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" required="required" />
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]">{$row.condition}</textarea>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]">{$row.remark}</textarea>
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hidden layer-footer">
<div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
{include file="auth/rule/tpl" /}
\ No newline at end of file
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a>
<a href="javascript:;" class="btn btn-danger btn-rebuild">{:__('Rebuild node')}</a>
</div>
<table id="table" class="table table-bordered table-hover" width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<style>
#chooseicon {
margin:10px;
}
#chooseicon ul {
margin:5px 0 0 0;
}
#chooseicon ul li{
width:30px;height:30px;
line-height:30px;
border:1px solid #ddd;
padding:1px;
margin:1px;
text-align: center;
}
#chooseicon ul li:hover{
border:1px solid #2c3e50;
cursor:pointer;
}
</style>
<script id="chooseicontpl" type="text/html">
<div id="chooseicon">
<div>
<form onsubmit="return false;">
<div class="input-group input-groupp-md">
<div class="input-group-addon">搜索图标</div>
<input class="js-icon-search form-control" type="text" placeholder="">
</div>
</form>
</div>
<div>
<ul class="list-inline">
<% for(var i=0; i<iconlist.length; i++){ %>
<li data-font="<%=iconlist[i]%>" title="<%=iconlist[i]%>">
<i class="fa fa-<%=iconlist[i]%>"></i>
</li>
<% } %>
</ul>
</div>
</div>
</script>
\ No newline at end of file
... ...
<style>
.skin-list li{
float:left; width: 33.33333%; padding: 5px;
}
.skin-list li a{
display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4);
}
</style>
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Create the tabs -->
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
<li class="active"><a href="#control-sidebar-setting-tab" data-toggle="tab" aria-expanded="true"><i class="fa fa-wrench"></i></a></li>
<li><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-setting-tab">
<h4 class="control-sidebar-heading">{:__('Layout Options')}</h4>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="fixed" class="pull-right"> {:__('Fixed Layout')}</label><p>{:__("You can't use fixed and boxed layouts together")}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="layout-boxed" class="pull-right"> {:__('Boxed Layout')}</label><p>{:__('Activate the boxed layout')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="sidebar-collapse" class="pull-right"> {:__('Toggle Sidebar')}</label><p>{:__("Toggle the left sidebar's state (open or collapse)")}</p></div>
<!--<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-enable="expandOnHover" class="pull-right"> {:__('Sidebar Expand on Hover')}</label><p>{:__('Let the sidebar mini expand on hover')}</p></div>-->
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-menu="show-submenu" class="pull-right"> {:__('Show sub menu')}</label><p>{:__('Always show sub menu')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-menu="disable-top-badge" class="pull-right"> {:__('Disable top menu badge')}</label><p>{:__('Disable top menu badge without left menu')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-controlsidebar="control-sidebar-open" class="pull-right"> {:__('Toggle Right Sidebar Slide')}</label><p>{:__('Toggle between slide over content and push content effects')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-sidebarskin="toggle" class="pull-right"> {:__('Toggle Right Sidebar Skin')}</label><p>{:__('Toggle between dark and light skins for the right sidebar')}</p></div>
<h4 class="control-sidebar-heading">{:__('Skins')}</h4>
<ul class="list-unstyled clearfix skin-list">
<li><a href="javascript:;" data-skin="skin-blue" style="" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px; background: #367fa9;"></span><span class="bg-light-blue" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Blue</p></li>
<li><a href="javascript:;" data-skin="skin-black" class="clearfix full-opacity-hover"><div style="box-shadow: 0 0 2px rgba(0,0,0,0.1)" class="clearfix"><span style="display:block; width: 20%; float: left; height: 7px; background: #fefefe;"></span><span style="display:block; width: 80%; float: left; height: 7px; background: #fefefe;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black</p></li>
<li><a href="javascript:;" data-skin="skin-purple" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-purple-active"></span><span class="bg-purple" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Purple</p></li>
<li><a href="javascript:;" data-skin="skin-green" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Green</p></li>
<li><a href="javascript:;" data-skin="skin-red" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Red</p></li>
<li><a href="javascript:;" data-skin="skin-yellow" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Yellow</p></li>
<li><a href="javascript:;" data-skin="skin-blue-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px; background: #367fa9;"></span><span class="bg-light-blue" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Blue Light</p></li>
<li><a href="javascript:;" data-skin="skin-black-light" class="clearfix full-opacity-hover"><div style="box-shadow: 0 0 2px rgba(0,0,0,0.1)" class="clearfix"><span style="display:block; width: 20%; float: left; height: 7px; background: #fefefe;"></span><span style="display:block; width: 80%; float: left; height: 7px; background: #fefefe;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Black Light</p></li>
<li><a href="javascript:;" data-skin="skin-purple-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-purple-active"></span><span class="bg-purple" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Purple Light</p></li>
<li><a href="javascript:;" data-skin="skin-green-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Green Light</p></li>
<li><a href="javascript:;" data-skin="skin-red-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Red Light</p></li>
<li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px;">Yellow Light</p></li>
</ul>
</div>
<div class="tab-pane" id="control-sidebar-home-tab">
<h3 class="control-sidebar-heading">{:__('Recent Activity')}</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:void(0)">
<i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Langdon's Birthday</h4>
<p>Will be 23 on April 24th</p>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<i class="menu-icon fa fa-user bg-yellow"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Frodo Updated His Profile</h4>
<p>New phone +1(800)555-1234</p>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<i class="menu-icon fa fa-envelope-o bg-light-blue"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Nora Joined Mailing List</h4>
<p>nora@example.com</p>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<i class="menu-icon fa fa-file-code-o bg-green"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Cron Job 254 Executed</h4>
<p>Execution time 5 seconds</p>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
<h3 class="control-sidebar-heading">{:__('Tasks Progress')}</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:void(0)">
<h4 class="control-sidebar-subheading">
Custom Template Design
<span class="label label-danger pull-right">70%</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-danger" style="width: 70%"></div>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<h4 class="control-sidebar-subheading">
Update Resume
<span class="label label-success pull-right">95%</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-success" style="width: 95%"></div>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<h4 class="control-sidebar-subheading">
Laravel Integration
<span class="label label-warning pull-right">50%</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-warning" style="width: 50%"></div>
</div>
</a>
</li>
<li>
<a href="javascript:void(0)">
<h4 class="control-sidebar-subheading">
Back End Framework
<span class="label label-primary pull-right">68%</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-primary" style="width: 68%"></div>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
</div>
<!-- /.tab-pane -->
<!-- Stats tab content -->
<div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div>
<!-- /.tab-pane -->
<!-- Settings tab content -->
<div class="tab-pane" id="control-sidebar-settings-tab">
<form method="post">
<h3 class="control-sidebar-heading">General Settings</h3>
<!-- /.form-group -->
<div class="form-group">
<label class="control-sidebar-subheading">
Allow mail redirect
<input type="checkbox" class="pull-right" checked>
</label>
<p>
Other sets of options are available
</p>
</div>
<!-- /.form-group -->
<div class="form-group">
<label class="control-sidebar-subheading">
Expose author name in posts
<input type="checkbox" class="pull-right" checked>
</label>
<p>
Allow the user to show his name in blog posts
</p>
</div>
<!-- /.form-group -->
<!-- /.form-group -->
</form>
</div>
<!-- /.tab-pane -->
</div>
</aside>
<!-- /.control-sidebar -->
\ No newline at end of file
... ...
<!-- Logo -->
<a href="javascript:;" class="logo">
<!-- 迷你模式下Logo的大小为50X50 -->
<span class="logo-mini"><b>F</b>AST</span>
<!-- 普通模式下Logo -->
<span class="logo-lg"><b>Fast</b>Admin</span>
</a>
<!-- 顶部通栏样式 -->
<nav class="navbar navbar-static-top">
<!-- 边栏切换按钮-->
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">{:__('Toggle navigation')}</span>
</a>
<div id="nav" class="pull-left">
<!--如果不想在顶部显示角标,则给ul加上disable-top-badge类即可-->
<ul class="nav nav-tabs nav-addtabs disable-top-badge" role="tablist">
</ul>
</div>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li>
<a href="{:url('index/index/index')}" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i></a>
</li>
<!-- 通栏下拉框样式 -->
<li class="dropdown notifications-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bell-o"></i>
<span class="label label-warning">2</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 10 notifications</li>
<li>
<!-- 下拉条目样式 -->
<ul class="menu">
<li>
<a href="#">
<i class="fa fa-users text-aqua"></i> 5 new members joined today
</a>
</li>
<li>
<a href="#">
<i class="fa fa-warning text-yellow"></i> Very long description here that may not fit into the
page and may cause design problems
</a>
</li>
</ul>
</li>
<li class="footer"><a href="#">View all</a></li>
</ul>
</li>
<li>
<a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a>
</li>
<!-- 账号信息下拉框 -->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{$admin.avatar}" class="user-image" alt="User Image">
<span class="hidden-xs">{$admin.nickname}</span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img src="{$admin.avatar}" class="img-circle" alt="">
<p>
{$admin.nickname}
<small>{$admin.logintime|date="Y-m-d H:i:s",###}</small>
</p>
</li>
<!-- Menu Body -->
<li class="user-body">
<div class="row">
<div class="col-xs-4 text-center">
<a href="#">Followers</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Sales</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Friends</a>
</div>
</div>
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="{:url('general.profile/index')}" class="btn btn-default btn-flat">{:__('Profile')}</a>
</div>
<div class="pull-right">
<a href="{:url('index/logout')}" class="btn btn-default btn-flat">{:__('Logout')}</a>
</div>
</li>
</ul>
</li>
<!-- 控制栏切换按钮 -->
<li>
<a href="javascript:;" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
</li>
</ul>
</div>
</nav>
\ No newline at end of file
... ...
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel hidden-xs">
<div class="pull-left image">
<img src="{$admin.avatar}" class="img-circle" />
</div>
<div class="pull-left info">
<p>{$admin.nickname}</p>
<i class="fa fa-circle text-success"></i> {:__('Online')}
</div>
</div>
<!-- search form -->
<form action="#" method="get" class="sidebar-form hidden-xs" style="overflow:visible;border:none;">
<select class="form-control fastmenujump btn">
<option value="">{:__('Shortcut')}</option>
</select>
</form>
<!-- /.search form -->
<!-- sidebar menu: : style can be found in sidebar.less -->
<!--如果想始终显示子菜单,则给ul加上show-submenu类即可-->
<ul class="sidebar-menu">
{$menulist}
</ul>
</section>
<!-- /.sidebar -->
\ No newline at end of file
... ...
<meta charset="utf-8">
<title>{$title|default=''}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<!-- Loading Bootstrap -->
<link href="__CDN__/assets/build/backend.css?v={$Think.config.site.version}" rel="stylesheet">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. -->
<!--[if lt IE 9]>
<script src="__CDN__/assets/js/html5shiv.js"></script>
<script src="__CDN__/assets/js/respond.min.js"></script>
<![endif]-->
<script type="text/javascript">
var require = {
config: {
'config': {$config|json_encode}
}
};
</script>
\ No newline at end of file
... ...
<script src="__CDN__/assets/js/require.js" data-main="__CDN__/assets/js/require-backend.js?v={$site.version}"></script>
\ No newline at end of file
... ...