作者 Karson

新增插件分类、免费插件搜索

新增全局的Template
新增自定义通用搜索表单内容
新增通用搜索按钮显示配置
新增单独清除模板、插件缓存
新增后台登录失败重试配置
优化通用搜索,搜索元素支持自动绑定元素事件
优化本地插件显示
优化前台首页和API文档字体显示
修复元素验证指定data-target不生效的BUG
修复插件命令行添加--force不生效的BUG
修复noNeedLogin和noNeedRight大小写的BUG
修复fieldlist无法挺拽的BUG
修复一键CRUD后指定字段显示后无法显示关联数据的BUG
... ... @@ -19,14 +19,14 @@ class Addon extends Command
protected function configure()
{
$this
->setName('addon')
->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
->setDescription('Addon manager');
->setName('addon')
->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
->setDescription('Addon manager');
}
protected function execute(Input $input, Output $output)
... ... @@ -44,12 +44,10 @@ class Addon extends Command
include dirname(__DIR__) . DS . 'common.php';
if (!$name)
{
if (!$name) {
throw new Exception('Addon name could not be empty');
}
if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package']))
{
if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package'])) {
throw new Exception('Please input correct action name');
}
... ... @@ -57,17 +55,14 @@ class Addon extends Command
Db::execute("SELECT 1");
$addonDir = ADDON_PATH . $name . DS;
switch ($action)
{
switch ($action) {
case 'create':
//非覆盖模式时如果存在则报错
if (is_dir($addonDir) && !$force)
{
if (is_dir($addonDir) && !$force) {
throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true ");
}
//如果存在先移除
if (is_dir($addonDir))
{
if (is_dir($addonDir)) {
rmdirs($addonDir);
}
mkdir($addonDir);
... ... @@ -76,16 +71,12 @@ class Addon extends Command
$createMenu = $this->getCreateMenu($menuList);
$prefix = Config::get('database.prefix');
$createTableSql = '';
try
{
try {
$result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;");
if (isset($result[0]) && isset($result[0]['Create Table']))
{
if (isset($result[0]) && isset($result[0]['Create Table'])) {
$createTableSql = $result[0]['Create Table'];
}
}
catch (PDOException $e)
{
} catch (PDOException $e) {
}
... ... @@ -102,8 +93,7 @@ class Addon extends Command
$this->writeToFile("config", $data, $addonDir . 'config.php');
$this->writeToFile("info", $data, $addonDir . 'info.ini');
$this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php');
if ($createTableSql)
{
if ($createTableSql) {
$createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql);
file_put_contents($addonDir . 'install.sql', $createTableSql);
}
... ... @@ -112,75 +102,61 @@ class Addon extends Command
break;
case 'disable':
case 'enable':
try
{
try {
//调用启用、禁用的方法
Service::$action($name, 0);
}
catch (AddonException $e)
{
if ($e->getCode() != -3)
{
} catch (AddonException $e) {
if ($e->getCode() != -3) {
throw new Exception($e->getMessage());
}
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v)
{
$output->warning($v);
}
$output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes')
{
throw new Exception("Operation is aborted!");
if (!$force) {
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v) {
$output->warning($v);
}
$output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes') {
throw new Exception("Operation is aborted!");
}
}
//调用启用、禁用的方法
Service::$action($name, 1);
}
catch (Exception $e)
{
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
$output->info(ucfirst($action) . " Successed!");
break;
case 'install':
//非覆盖模式时如果存在则报错
if (is_dir($addonDir) && !$force)
{
if (is_dir($addonDir) && !$force) {
throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
}
//如果存在先移除
if (is_dir($addonDir))
{
if (is_dir($addonDir)) {
rmdirs($addonDir);
}
try
{
try {
Service::install($name, 0, ['version' => $release]);
}
catch (AddonException $e)
{
if ($e->getCode() != -3)
{
} catch (AddonException $e) {
if ($e->getCode() != -3) {
throw new Exception($e->getMessage());
}
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v)
{
$output->warning($v);
}
$output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes')
{
throw new Exception("Operation is aborted!");
if (!$force) {
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v) {
$output->warning($v);
}
$output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes') {
throw new Exception("Operation is aborted!");
}
}
Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token]);
}
catch (Exception $e)
{
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
... ... @@ -188,36 +164,29 @@ class Addon extends Command
break;
case 'uninstall':
//非覆盖模式时如果存在则报错
if (!$force)
{
if (!$force) {
throw new Exception("If you need to uninstall addon, use the parameter --force=true ");
}
try
{
try {
Service::uninstall($name, 0);
}
catch (AddonException $e)
{
if ($e->getCode() != -3)
{
} catch (AddonException $e) {
if ($e->getCode() != -3) {
throw new Exception($e->getMessage());
}
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v)
{
$output->warning($v);
}
$output->info("Are you sure you want to delete all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes')
{
throw new Exception("Operation is aborted!");
if (!$force) {
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v) {
$output->warning($v);
}
$output->info("Are you sure you want to delete all those files? Type 'yes' to continue: ");
$line = fgets(STDIN);
if (trim($line) != 'yes') {
throw new Exception("Operation is aborted!");
}
}
Service::uninstall($name, 1);
}
catch (Exception $e)
{
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
... ... @@ -233,53 +202,44 @@ class Addon extends Command
break;
case 'package':
$infoFile = $addonDir . 'info.ini';
if (!is_file($infoFile))
{
if (!is_file($infoFile)) {
throw new Exception(__('Addon info file was not found'));
}
$info = get_addon_info($name);
if (!$info)
{
if (!$info) {
throw new Exception(__('Addon info file data incorrect'));
}
$infoname = isset($info['name']) ? $info['name'] : '';
if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name)
{
if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) {
throw new Exception(__('Addon info name incorrect'));
}
$infoversion = isset($info['version']) ? $info['version'] : '';
if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion))
{
if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) {
throw new Exception(__('Addon info version incorrect'));
}
$addonTmpDir = RUNTIME_PATH . 'addons' . DS;
if (!is_dir($addonTmpDir))
{
if (!is_dir($addonTmpDir)) {
@mkdir($addonTmpDir, 0755, true);
}
$addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip';
if (!class_exists('ZipArchive'))
{
if (!class_exists('ZipArchive')) {
throw new Exception(__('ZinArchive not install'));
}
$zip = new \ZipArchive;
$zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
if (!$file->isDir())
{
foreach ($files as $name => $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($addonDir));
if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db']))
{
if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) {
$zip->addFile($filePath, $relativePath);
}
}
... ... @@ -301,22 +261,18 @@ class Addon extends Command
protected function getCreateMenu($menu)
{
$result = [];
foreach ($menu as $k => & $v)
{
foreach ($menu as $k => & $v) {
$arr = [
'name' => $v['name'],
'title' => $v['title'],
];
if ($v['icon'] != 'fa fa-circle-o')
{
if ($v['icon'] != 'fa fa-circle-o') {
$arr['icon'] = $v['icon'];
}
if ($v['ismenu'])
{
if ($v['ismenu']) {
$arr['ismenu'] = $v['ismenu'];
}
if (isset($v['childlist']) && $v['childlist'])
{
if (isset($v['childlist']) && $v['childlist']) {
$arr['sublist'] = $this->getCreateMenu($v['childlist']);
}
$result[] = $arr;
... ... @@ -334,16 +290,14 @@ class Addon extends Command
protected function writeToFile($name, $data, $pathname)
{
$search = $replace = [];
foreach ($data as $k => $v)
{
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)))
{
if (!is_dir(dirname($pathname))) {
mkdir(strtolower(dirname($pathname)), 0755, true);
}
return file_put_contents($pathname, $content);
... ...
... ... @@ -9,7 +9,15 @@
<title>{$config.title}</title>
<link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
body { padding-top: 70px; margin-bottom: 15px; }
body {
padding-top: 70px; margin-bottom: 15px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-weight: 400;
}
h2 { font-size: 1.6em; }
hr { margin-top: 10px; }
.tab-pane { padding-top: 10px; }
.mt0 { margin-top: 0px; }
.footer { font-size: 12px; color: #666; }
... ...
... ... @@ -654,9 +654,10 @@ class Crud extends Command
$priDefined = TRUE;
$javascriptList[] = "{checkbox: true}";
}
//构造JS列信息
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);
if (!$fields || in_array($field, explode(',', $fields))) {
//构造JS列信息
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);
}
//排序方式,如果有指定排序字段,否则按主键排序
$order = $field == $this->sortField ? $this->sortField : $order;
}
... ... @@ -767,6 +768,11 @@ class Crud extends Command
//构造关联模型的方法
$relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod', $relation);
//如果设置了显示主表字段,则必须显式将关联表字段显示
if ($fields) {
$relationVisibleFieldList[] = "\$row->visible(['{$relation['relationMethod']}']);";
}
//显示的字段
if ($relation['relationFields']) {
$relationVisibleFieldList[] = "\$row->getRelation('" . $relation['relationMethod'] . "')->visible(['" . implode("','", $relation['relationFields']) . "']);";
... ...
... ... @@ -3,6 +3,7 @@
namespace app\admin\controller;
use app\common\controller\Backend;
use fast\Http;
use think\addons\AddonException;
use think\addons\Service;
use think\Cache;
... ... @@ -31,8 +32,7 @@ class Addon extends Backend
public function index()
{
$addons = get_addon_list();
foreach ($addons as $k => &$v)
{
foreach ($addons as $k => &$v) {
$config = get_addon_config($v['name']);
$v['config'] = $config ? 1 : 0;
}
... ... @@ -46,60 +46,31 @@ class Addon extends Backend
public function config($ids = NULL)
{
$name = $this->request->get("name");
if (!$name)
{
if (!$name) {
$this->error(__('Parameter %s can not be empty', $ids ? 'id' : 'name'));
}
if (!is_dir(ADDON_PATH . $name))
{
if (!is_dir(ADDON_PATH . $name)) {
$this->error(__('Directory not found'));
}
$info = get_addon_info($name);
$config = get_addon_fullconfig($name);
if (!$info)
$this->error(__('No Results were found'));
if ($this->request->isPost())
{
if ($this->request->isPost()) {
$params = $this->request->post("row/a");
if ($params)
{
foreach ($config as $k => &$v)
{
if (isset($params[$v['name']]))
{
if ($v['type'] == 'array')
{
$fieldarr = $valuearr = [];
$field = $params[$v['name']]['field'];
$value = $params[$v['name']]['value'];
foreach ($field as $m => $n)
{
if ($n != '')
{
$fieldarr[] = $field[$m];
$valuearr[] = $value[$m];
}
}
$params[$v['name']] = array_combine($fieldarr, $valuearr);
$value = $params[$v['name']];
}
else
{
$value = is_array($params[$v['name']]) ? implode(',', $params[$v['name']]) : $params[$v['name']];
}
if ($params) {
foreach ($config as $k => &$v) {
if (isset($params[$v['name']])) {
$value = is_array($params[$v['name']]) ? implode(',', $params[$v['name']]) : $params[$v['name']];
$v['value'] = $value;
}
}
try
{
try {
//更新配置文件
set_addon_fullconfig($name, $config);
Service::refresh();
$this->success();
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -115,13 +86,11 @@ class Addon extends Backend
public function install()
{
$name = $this->request->post("name");
$force = (int) $this->request->post("force");
if (!$name)
{
$force = (int)$this->request->post("force");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
try
{
try {
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
... ... @@ -137,13 +106,9 @@ class Addon extends Backend
$info['config'] = get_addon_config($name) ? 1 : 0;
$info['state'] = 1;
$this->success(__('Install successful'), null, ['addon' => $info]);
}
catch (AddonException $e)
{
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage(), $e->getCode());
}
}
... ... @@ -154,22 +119,16 @@ class Addon extends Backend
public function uninstall()
{
$name = $this->request->post("name");
$force = (int) $this->request->post("force");
if (!$name)
{
$force = (int)$this->request->post("force");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
try
{
try {
Service::uninstall($name, $force);
$this->success(__('Uninstall successful'));
}
catch (AddonException $e)
{
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -181,25 +140,19 @@ class Addon extends Backend
{
$name = $this->request->post("name");
$action = $this->request->post("action");
$force = (int) $this->request->post("force");
if (!$name)
{
$force = (int)$this->request->post("force");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
try
{
try {
$action = $action == 'enable' ? $action : 'disable';
//调用启用、禁用的方法
Service::$action($name, $force);
Cache::rm('__menu__');
$this->success(__('Operate successful'));
}
catch (AddonException $e)
{
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -213,55 +166,46 @@ class Addon extends Backend
$file = $this->request->file('file');
$addonTmpDir = RUNTIME_PATH . 'addons' . DS;
if (!is_dir($addonTmpDir))
{
if (!is_dir($addonTmpDir)) {
@mkdir($addonTmpDir, 0755, true);
}
$info = $file->rule('uniqid')->validate(['size' => 10240000, 'ext' => 'zip'])->move($addonTmpDir);
if ($info)
{
if ($info) {
$tmpName = substr($info->getFilename(), 0, stripos($info->getFilename(), '.'));
$tmpAddonDir = ADDON_PATH . $tmpName . DS;
$tmpFile = $addonTmpDir . $info->getSaveName();
try
{
try {
Service::unzip($tmpName);
@unlink($tmpFile);
$infoFile = $tmpAddonDir . 'info.ini';
if (!is_file($infoFile))
{
if (!is_file($infoFile)) {
throw new Exception(__('Addon info file was not found'));
}
$config = Config::parse($infoFile, '', $tmpName);
$name = isset($config['name']) ? $config['name'] : '';
if (!$name)
{
if (!$name) {
throw new Exception(__('Addon info file data incorrect'));
}
$newAddonDir = ADDON_PATH . $name . DS;
if (is_dir($newAddonDir))
{
if (is_dir($newAddonDir)) {
throw new Exception(__('Addon already exists'));
}
//重命名插件文件夹
rename($tmpAddonDir, $newAddonDir);
try
{
try {
//默认禁用该插件
$info = get_addon_info($name);
if ($info['state'])
{
if ($info['state']) {
$info['state'] = 0;
set_addon_info($name, $info);
}
//执行插件的安装方法
$class = get_addon_class($name);
if (class_exists($class))
{
if (class_exists($class)) {
$addon = new $class();
$addon->install();
}
... ... @@ -271,22 +215,16 @@ class Addon extends Backend
$info['config'] = get_addon_config($name) ? 1 : 0;
$this->success(__('Offline installed tips'), null, ['addon' => $info]);
}
catch (Exception $e)
{
} catch (Exception $e) {
@rmdirs($newAddonDir);
throw new Exception($e->getMessage());
}
}
catch (Exception $e)
{
} catch (Exception $e) {
@unlink($tmpFile);
@rmdirs($tmpAddonDir);
$this->error($e->getMessage());
}
}
else
{
} else {
// 上传失败获取错误信息
$this->error($file->getError());
}
... ... @@ -298,12 +236,10 @@ class Addon extends Backend
public function upgrade()
{
$name = $this->request->post("name");
if (!$name)
{
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
try
{
try {
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
... ... @@ -318,29 +254,9 @@ class Addon extends Backend
Service::upgrade($name, $extend);
Cache::rm('__menu__');
$this->success(__('Operate successful'));
}
catch (AddonException $e)
{
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
}
catch (Exception $e)
{
$this->error($e->getMessage());
}
}
/**
* 刷新缓存
*/
public function refresh()
{
try
{
Service::refresh();
$this->success(__('Operate successful'));
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -350,31 +266,51 @@ class Addon extends Backend
*/
public function downloaded()
{
$offset = (int) $this->request->get("offset");
$limit = (int) $this->request->get("limit");
$offset = (int)$this->request->get("offset");
$limit = (int)$this->request->get("limit");
$filter = $this->request->get("filter");
$search = $this->request->get("search");
$search = htmlspecialchars(strip_tags($search));
$onlineaddons = Cache::get("onlineaddons");
if (!is_array($onlineaddons)) {
$onlineaddons = [];
$result = Http::sendRequest(config('fastadmin.api_url') . '/addon/index');
if ($result['ret']) {
$json = json_decode($result['msg'], TRUE);
$rows = isset($json['rows']) ? $json['rows'] : [];
foreach ($rows as $index => $row) {
$onlineaddons[$row['name']] = $row;
}
}
Cache::set("onlineaddons", $onlineaddons, 600);
}
$filter = (array)json_decode($filter, true);
$addons = get_addon_list();
$list = [];
foreach ($addons as $k => $v)
{
foreach ($addons as $k => $v) {
if ($search && stripos($v['name'], $search) === FALSE && stripos($v['intro'], $search) === FALSE)
continue;
$v['flag'] = '';
$v['banner'] = '';
$v['image'] = '';
$v['donateimage'] = '';
$v['demourl'] = '';
$v['price'] = '0.00';
if (isset($onlineaddons[$v['name']])) {
$v = array_merge($onlineaddons[$v['name']], $v);
} else {
$v['category_id'] = 0;
$v['flag'] = '';
$v['banner'] = '';
$v['image'] = '';
$v['donateimage'] = '';
$v['demourl'] = '';
$v['price'] = '0.00';
}
$v['url'] = addon_url($v['name']);
$v['createtime'] = filemtime(ADDON_PATH . $v['name']);
if ($filter && isset($filter['category_id']) && is_numeric($filter['category_id']) && $filter['category_id'] != $v['category_id']) {
continue;
}
$list[] = $v;
}
$total = count($list);
if ($limit)
{
if ($limit) {
$list = array_slice($list, $offset, $limit);
}
$result = array("total" => $total, "rows" => $list);
... ...
... ... @@ -4,6 +4,7 @@ namespace app\admin\controller;
use app\common\controller\Backend;
use fast\Random;
use think\addons\Service;
use think\Cache;
use think\Config;
use think\Db;
... ... @@ -47,8 +48,7 @@ class Ajax extends Backend
{
Config::set('default_return_type', 'json');
$file = $this->request->file('file');
if (empty($file))
{
if (empty($file)) {
$this->error(__('No file upload or server upload limit exceeded'));
}
... ... @@ -60,7 +60,7 @@ class Ajax extends Backend
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
$type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$fileInfo = $file->getInfo();
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file';
... ... @@ -68,8 +68,7 @@ class Ajax extends Backend
$mimetypeArr = explode(',', $upload['mimetype']);
$typeArr = explode('/', $fileInfo['type']);
//验证文件后缀
if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))
{
if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)) {
$this->error(__('Uploaded file format is limited'));
}
$replaceArr = [
... ... @@ -93,11 +92,9 @@ class Ajax extends Backend
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo)
{
if ($splInfo) {
$imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']))
{
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
$imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
... ... @@ -121,9 +118,7 @@ class Ajax extends Backend
$this->success(__('Upload successful'), null, [
'url' => $uploadDir . $splInfo->getSaveName()
]);
}
else
{
} else {
// 上传失败获取错误信息
$this->error($file->getError());
}
... ... @@ -153,12 +148,10 @@ class Ajax extends Backend
$field = in_array($field, ['weigh']) ? $field : 'weigh';
// 如果设定了pid的值,此时只匹配满足条件的ID,其它忽略
if ($pid !== '')
{
if ($pid !== '') {
$hasids = [];
$list = Db::name($table)->where($prikey, 'in', $ids)->where('pid', 'in', $pid)->field('id,pid')->select();
foreach ($list as $k => $v)
{
foreach ($list as $k => $v) {
$hasids[] = $v['id'];
}
$ids = array_values(array_intersect($ids, $hasids));
... ... @@ -166,20 +159,15 @@ class Ajax extends Backend
//直接修复排序
$one = Db::name($table)->field("{$field},COUNT(*) AS nums")->group($field)->having('nums > 1')->find();
if ($one)
{
if ($one) {
$list = Db::name($table)->field("$prikey,$field")->order($field, $orderway)->select();
foreach ($list as $k => $v)
{
foreach ($list as $k => $v) {
Db::name($table)->where($prikey, $v[$prikey])->update([$field => $k + 1]);
}
$this->success();
}
else
{
} else {
$list = Db::name($table)->field("$prikey,$field")->where($prikey, 'in', $ids)->order($field, $orderway)->select();
foreach ($list as $k => $v)
{
foreach ($list as $k => $v) {
$sour[] = $v[$prikey];
$weighdata[$v[$prikey]] = $v[$field];
}
... ... @@ -192,20 +180,13 @@ class Ajax extends Backend
//echo "替换的ID:{$desc_id}\n";
$weighids = array();
$temp = array_values(array_diff_assoc($ids, $sour));
foreach ($temp as $m => $n)
{
if ($n == $sour_id)
{
foreach ($temp as $m => $n) {
if ($n == $sour_id) {
$offset = $desc_id;
}
else
{
if ($sour_id == $temp[0])
{
} else {
if ($sour_id == $temp[0]) {
$offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id;
}
else
{
} else {
$offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id;
}
}
... ... @@ -221,15 +202,23 @@ class Ajax extends Backend
*/
public function wipecache()
{
$wipe_cache_type = ['TEMP_PATH', 'LOG_PATH', 'CACHE_PATH'];
foreach ($wipe_cache_type as $item)
{
$dir = constant($item);
if (!is_dir($dir))
continue;
rmdirs($dir);
$type = $this->request->request("type");
switch ($type) {
case 'content' || 'all':
rmdirs(CACHE_PATH, false);
Cache::clear();
if ($type == 'content')
break;
case 'template' || 'all':
rmdirs(TEMP_PATH, false);
if ($type == 'template')
break;
case 'addons' || 'all':
Service::refresh();
if ($type == 'addons')
break;
}
Cache::clear();
\think\Hook::listen("wipecache_after");
$this->success();
}
... ... @@ -243,14 +232,11 @@ class Ajax extends Backend
$pid = $this->request->get('pid');
$where = ['status' => 'normal'];
$categorylist = null;
if ($pid !== '')
{
if ($type)
{
if ($pid !== '') {
if ($type) {
$where['type'] = $type;
}
if ($pid)
{
if ($pid) {
$where['pid'] = $pid;
}
... ... @@ -268,17 +254,13 @@ class Ajax extends Backend
$city = $this->request->get('city');
$where = ['pid' => 0, 'level' => 1];
$provincelist = null;
if ($province !== '')
{
if ($province)
{
if ($province !== '') {
if ($province) {
$where['pid'] = $province;
$where['level'] = 2;
}
if ($city !== '')
{
if ($city)
{
if ($city !== '') {
if ($city) {
$where['pid'] = $city;
$where['level'] = 3;
}
... ...
... ... @@ -30,6 +30,8 @@ return [
'Please disable addon first' => '请先禁用插件再进行升级',
'Login now' => '立即登录',
'Continue install' => '不登录,继续安装',
'All' => '全部',
'Uncategoried' => '未归类',
'Recommend' => '推荐',
'Hot' => '热门',
'New' => '新',
... ...
... ... @@ -33,6 +33,10 @@ return [
'Wipe cache completed' => '清除缓存成功',
'Wipe cache failed' => '清除缓存失败',
'Wipe cache' => '清空缓存',
'Wipe all cache' => '一键清除缓存',
'Wipe content cache' => '清空内容缓存',
'Wipe template cache' => '清除模板缓存',
'Wipe addons cache' => '清除插件缓存',
'Check for updates' => '检测更新',
'Latest news' => '最新消息',
'View more' => '查看更多',
... ...
... ... @@ -30,7 +30,7 @@ class Auth extends \fast\Auth
/**
* 管理员登录
*
*
* @param string $username 用户名
* @param string $password 密码
* @param int $keeptime 有效时长
... ... @@ -44,7 +44,7 @@ class Auth extends \fast\Auth
$this->setError('Username is incorrect');
return false;
}
if ($admin->loginfailure >= 3 && time() - $admin->updatetime < 86400)
if (Config::get('fastadmin.login_failure_retry') && $admin->loginfailure >= 10 && time() - $admin->updatetime < 86400)
{
$this->setError('Please try again after 1 day');
return false;
... ... @@ -119,7 +119,7 @@ class Auth extends \fast\Auth
/**
* 刷新保持登录的Cookie
*
*
* @param int $keeptime
* @return boolean
*/
... ... @@ -155,6 +155,7 @@ class Auth extends \fast\Auth
return FALSE;
}
$arr = array_map('strtolower', $arr);
// 是否存在
if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
{
... ...
... ... @@ -21,20 +21,13 @@
<textarea name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}" {$item.extend}>{$item.value}</textarea>
{/case}
{case array}
<dl class="fieldlist" rel="{$item.value|count}" data-name="row[{$item.name}]">
<dl class="fieldlist" data-name="row[{$item.name}]">
<dd>
<ins>{:__('Array key')}</ins>
<ins>{:__('Array value')}</ins>
</dd>
{foreach $item.value as $key => $vo}
<dd class="form-inline">
<input type="text" name="row[{$item.name}][field][{$key}]" class="form-control" value="{$key}" size="10" />
<input type="text" name="row[{$item.name}][value][{$key}]" class="form-control" value="{$vo}" size="30" />
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</dd>
{/foreach}
<dd><a href="javascript:;" class="append btn btn-sm btn-success"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
<dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
<textarea name="row[{$item.name}]" cols="30" rows="5" class="hide">{$item.value|json_encode}</textarea>
</dl>
{/case}
{case datetime}
... ...
<style type="text/css">
.noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;}
.noimage > div {position: absolute;top:48%;width:100%;text-align:center;}
.addon {position: relative;}
.addon {position: relative;border-color:#e4e4e4;}
.addon > span {position:absolute;left:15px;top:15px;z-index:9;}
.addon > span a{opacity: 0.5;border:none;color:#fff;}
.layui-layer-pay .layui-layer-content {padding:0;height:600px!important;}
... ... @@ -16,9 +16,34 @@
.status-disabled .noimage {
background:#d2d6de;
}
@media (min-width: 992px) {
.addon {
-webkit-transition:all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.addon:hover {
border-color: #dddddd;
-webkit-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
-moz-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
}
</style>
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-heading">
{:build_heading(null,FALSE)}
<ul class="nav nav-tabs nav-category">
<li class="active"><a href="javascript:;" data-id="">{:__('All')}</a></li>
<li><a href="javascript:;" data-id="0">{:__('Uncategoried')}</a></li>
</ul>
</div>
<div class="panel-body">
<div id="myTabContent" class="tab-content">
... ... @@ -27,10 +52,11 @@
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh')}
<button type="button" id="plupload-addon" class="btn btn-danger plupload" data-url="addon/local" data-mimetype="application/zip" data-multiple="false"><i class="fa fa-upload"></i> {:__('Offline install')}</button>
<a class="btn btn-success btn-ajax" href="addon/refresh"><i class="fa fa-refresh"></i> {:__('Refresh addon cache')}</a>
<div class="btn-group">
<a href="#" class="btn btn-info btn-switch active" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-cloud"></i> {:__('Online store')}</a>
<a href="#" class="btn btn-info btn-switch" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a>
<a href="#" class="btn btn-info btn-switch active" data-type="all" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-list"></i> {:__('全部')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="free" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-gift"></i> {:__('免费')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="price" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-rmb"></i> {:__('付费')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="local" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a>
</div>
<a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a>
</div>
... ... @@ -44,6 +70,55 @@
</div>
</div>
</div>
<script id="searchformtpl" type="text/html">
<form action="" class="form-commonsearch hide">
<div class="well" style="box-shadow:none;border-radius:2px;margin-bottom:10px;">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group">
<label class="control-label">标题</label>
<input class="operate" type="hidden" data-name="title" value="like"/>
<input class="form-control" type="text" name="title" placeholder="请输入查找的标题" value=""/>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group">
<label class="control-label">类型</label>
<input class="operate" type="hidden" data-name="type" value="="/>
<input class="form-control" type="text" name="type" placeholder="all" value=""/>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group">
<label class="control-label">分类</label>
<input type="hidden" class="operate" data-name="category_id" value="="/>
<input class="form-control" name="category_id" type="text" value="">
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group">
<label class="control-label">版本号</label>
<input type="hidden" class="operate" data-name="faversion" value="="/>
<input class="form-control" name="faversion" type="text" value="{$config.fastadmin.version}">
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group">
<label class="control-label"></label>
<div class="row">
<div class="col-xs-6">
<input type="submit" class="btn btn-success btn-block" value="提交"/>
</div>
<div class="col-xs-6">
<input type="reset" class="btn btn-primary btn-block" value="重置"/>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</script>
<script id="logintpl" type="text/html">
<div>
<form class="form-horizontal">
... ... @@ -180,7 +255,7 @@
<%}%>
</a>
<div class="caption">
<h4><%=item.title?item.title:'{:__('None')}'%>
<h4><%=item.title?item.title:'{:__('None')}'%>
<% if(item.flag.indexOf("recommend")>-1){%>
<span class="label label-success">{:__('Recommend')}</span>
<% } %>
... ... @@ -203,7 +278,7 @@
<% if(!addon){ %>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<span class="btn-group">
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
<span class="fa fa-caret-down"></span>
</a>
... ... @@ -214,10 +289,10 @@
</ul>
</span>
<% }else{%>
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<% } %>
<% if(item.demourl){ %>
<a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a>
<a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a>
<% } %>
<% } %>
... ... @@ -235,7 +310,7 @@
<% if(addon && item && addon.version!=item.version){%>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<span class="btn-group">
<a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="javascript:;">
<span class="fa fa-caret-down"></span>
</a>
... ...
... ... @@ -25,7 +25,7 @@
<a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i></a>
</li>
<li class="dropdown notifications-menu">
<li class="dropdown notifications-menu hidden-xs">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bell-o"></i>
<span class="label label-warning"></span>
... ... @@ -41,19 +41,26 @@
<li class="footer"><a href="#" target="_blank">{:__('View more')}</a></li>
</ul>
</li>
<li>
<li class="hidden-xs">
<a href="javascript:;" data-toggle="checkupdate" title="{:__('Check for updates')}">
<i class="fa fa-refresh"></i>
</a>
</li>
<li>
<a href="javascript:;" data-toggle="wipecache" title="{:__('Wipe cache')}">
<a href="javascript:;" data-toggle="dropdown" title="{:__('Wipe cache')}">
<i class="fa fa-trash"></i>
</a>
<ul class="dropdown-menu wipecache">
<li><a href="javascript:;" data-type="all"><i class="fa fa-trash"></i> {:__('Wipe all cache')}</a></li>
<li><a href="javascript:;" data-type="content"><i class="fa fa-file-text"></i> {:__('Wipe content cache')}</a></li>
<li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o"></i> {:__('Wipe template cache')}</a></li>
<li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket"></i> {:__('Wipe addons cache')}</a></li>
</ul>
</li>
{if $Think.config.lang_switch_on}
<li class="hidden-xs">
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-language"></i></a>
<ul class="dropdown-menu">
... ... @@ -65,6 +72,7 @@
</li>
</ul>
</li>
{/if}
<li class="hidden-xs">
<a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a>
... ... @@ -103,16 +111,18 @@
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="general/profile" class="btn btn-primary addtabsit"><i class="fa fa-user"></i> {:__('Profile')}</a>
<a href="general/profile" class="btn btn-primary addtabsit"><i class="fa fa-user"></i>
{:__('Profile')}</a>
</div>
<div class="pull-right">
<a href="{:url('index/logout')}" class="btn btn-danger"><i class="fa fa-sign-out"></i> {:__('Logout')}</a>
<a href="{:url('index/logout')}" class="btn btn-danger"><i class="fa fa-sign-out"></i>
{:__('Logout')}</a>
</div>
</li>
</ul>
</li>
<!-- 控制栏切换按钮 -->
<li>
<li class="hidden-xs">
<a href="javascript:;" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
</li>
</ul>
... ...
... ... @@ -80,7 +80,7 @@
<div class="input-group">
<div class="input-group-addon"><span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span></div>
<input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="{:__('Captcha')}:required;length(4)" />
<span class="input-group-addon" style="padding:0;border:none;">
<span class="input-group-addon" style="padding:0;border:none;cursor:pointer;">
<img src="{:captcha_src()}" width="100" height="30" onclick="this.src = '{:captcha_src()}?r=' + Math.random();"/>
</span>
</div>
... ... @@ -97,7 +97,7 @@
</form>
</div>
</div>
<p class="copyright"><a href="https://www.fastadmin.net?ref=demo">Powered By FastAdmin</a></p>
<p class="copyright"><a href="https://www.fastadmin.net">Powered By FastAdmin</a></p>
</div>
</div>
</div>
... ...
... ... @@ -279,6 +279,7 @@ class Backend extends Controller
{
$k = $tableName . $k;
}
$v = !is_array($v) ? trim($v) : $v;
$sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
switch ($sym)
{
... ... @@ -306,7 +307,7 @@ class Backend extends Controller
case 'IN(...)':
case 'NOT IN':
case 'NOT IN(...)':
$where[] = [$k, str_replace('(...)', '', $sym), explode(',', $v)];
$where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
break;
case 'BETWEEN':
case 'NOT BETWEEN':
... ...
... ... @@ -382,6 +382,7 @@ class Auth
$rules[] = $v['name'];
}
$url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path);
$url = strtolower(str_replace('.', '/', $url));
return in_array($url, $rules) ? TRUE : FALSE;
}
... ... @@ -539,6 +540,7 @@ class Auth
{
return FALSE;
}
$arr = array_map('strtolower', $arr);
// 是否存在
if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
{
... ...
... ... @@ -21,6 +21,13 @@ class Category Extends Model
'flag_text',
];
protected static function init()
{
self::afterInsert(function ($row) {
$row->save(['weigh' => $row['id']]);
});
}
public function setFlagAttr($value, $data)
{
return is_array($value) ? implode(',', $value) : $value;
... ...
... ... @@ -258,18 +258,20 @@ return [
//FastAdmin配置
'fastadmin' => [
//是否开启前台会员中心
'usercenter' => true,
'usercenter' => true,
//登录验证码
'login_captcha' => false,
'login_captcha' => true,
//登录失败超过10则1天后重试
'login_failure_retry' => true,
//是否同一账号同一时间只能在一个地方登录
'login_unique' => false,
'login_unique' => false,
//登录页默认背景图
'login_background' => "/assets/img/loginbg.jpg",
'login_background' => "/assets/img/loginbg.jpg",
//自动检测更新
'checkupdate' => false,
'checkupdate' => false,
//版本号
'version' => '1.0.0.20180401_beta',
'version' => '1.0.0.20180406_beta',
//API接口地址
'api_url' => 'https://api.fastadmin.net',
'api_url' => 'https://api.fastadmin.net',
],
];
... ...
... ... @@ -9,7 +9,15 @@
<title>FastAdmin</title>
<link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
body { padding-top: 70px; margin-bottom: 15px; }
body {
padding-top: 70px; margin-bottom: 15px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-weight: 400;
}
h2 { font-size: 1.6em; }
hr { margin-top: 10px; }
.tab-pane { padding-top: 10px; }
.mt0 { margin-top: 0px; }
.footer { font-size: 12px; color: #666; }
... ... @@ -3351,7 +3359,7 @@
<div class="row mt0 footer">
<div class="col-md-6" align="left">
Generated on 2018-04-01 15:11:14 </div>
Generated on 2018-04-06 19:15:01 </div>
<div class="col-md-6" align="right">
<a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
</div>
... ...
... ... @@ -807,4 +807,6 @@ form.form-horizontal .control-label {
.checkbox > label > input {
margin: 2px 0 0;
}
/*# sourceMappingURL=backend.css.map */
\ No newline at end of file
.wipecache li a {
color: #444444!important;
}
... ...
... ... @@ -4,7 +4,10 @@ body {
width: 100%;
}
body {
font-family: 'Muli', 'Helvetica', 'Arial', 'sans-serif';
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-weight: 400;
}
a {
-webkit-transition: all 0.35s;
... ...
define(['fast', 'moment'], function (Fast, Moment) {
define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
var Backend = {
api: {
sidebar: function (params) {
... ... @@ -8,13 +8,11 @@ define(['fast', 'moment'], function (Fast, Moment) {
$.each(params, function (k, v) {
$url = Fast.api.fixurl(k);
if ($.isArray(v))
{
if ($.isArray(v)) {
$nums = typeof v[0] !== 'undefined' ? v[0] : 0;
$color = typeof v[1] !== 'undefined' ? v[1] : colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums];
$class = typeof v[2] !== 'undefined' ? v[2] : 'label';
} else
{
} else {
$nums = v;
$color = colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums];
$class = 'label';
... ... @@ -58,7 +56,10 @@ define(['fast', 'moment'], function (Fast, Moment) {
var id = Math.floor(new Date().valueOf() * Math.random());
icon = typeof icon !== 'undefined' ? icon : 'fa fa-circle-o';
title = typeof title !== 'undefined' ? title : '';
top.window.$("<a />").append('<i class="' + icon + '"></i> <span>' + title + '</span>').prop("href", url).attr({url: url, addtabs: id}).addClass("hide").appendTo(top.window.document.body).trigger("click");
top.window.$("<a />").append('<i class="' + icon + '"></i> <span>' + title + '</span>').prop("href", url).attr({
url: url,
addtabs: id
}).addClass("hide").appendTo(top.window.document.body).trigger("click");
}
}
}
... ... @@ -227,6 +228,8 @@ define(['fast', 'moment'], function (Fast, Moment) {
}
};
Backend.api = $.extend(Fast.api, Backend.api);
//将Template渲染至全局,以便于在子框架中调用
window.Template = Template;
//将Moment渲染至全局,以便于在子框架中调用
window.Moment = Moment;
//将Backend渲染至全局,以便于在子框架中调用
... ...
... ... @@ -14,6 +14,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
var table = $("#table");
table.on('load-success.bs.table', function (e, json) {
if (json && typeof json.category != 'undefined' && $(".nav-category li").size() == 2) {
$.each(json.category, function (i, j) {
$("<li><a href='javascript:;' data-id='" + j.id + "'>" + j.name + "</a></li>").insertBefore($(".nav-category li:last"));
});
}
});
table.on('post-body.bs.table', function (e, settings, json, xhr) {
var parenttable = table.closest('.bootstrap-table');
var d = $(".fixed-table-toolbar", parenttable).find(".search input");
... ... @@ -53,19 +60,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
showColumns: false,
showToggle: false,
showExport: false,
commonSearch: false,
searchFormVisible: false,
showSearch: false,
commonSearch: true,
searchFormVisible: true,
searchFormTemplate: 'searchformtpl',
pageSize: 12,
pagination: false,
queryParams: function (params) {
var filter = params.filter ? JSON.parse(params.filter) : {};
var op = params.op ? JSON.parse(params.op) : {};
filter.faversion = Config.fastadmin.version;
op.faversion = "=";
params.filter = JSON.stringify(filter);
params.op = JSON.stringify(op);
return params;
}
});
// 为表格绑定事件
... ... @@ -124,14 +124,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
return false;
}
});
// 切换URL
// 切换
$(document).on("click", ".btn-switch", function () {
$(".btn-switch").removeClass("active");
$(this).addClass("active");
$("form.form-commonsearch input[name='type']").val($(this).data("type"));
table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1});
return false;
});
$(document).on("click", ".nav-category li a", function () {
$(".nav-category li").removeClass("active");
$(this).parent().addClass("active");
$("form.form-commonsearch input[name='category_id']").val($(this).data("id"));
table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1});
return false;
});
// 会员信息
$(document).on("click", ".btn-userinfo", function () {
var userinfo = Controller.api.userinfo.get();
... ... @@ -146,7 +155,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Fast.api.ajax({
url: Config.fastadmin.api_url + '/user/login',
dataType: 'jsonp',
data: {account: $("#inputAccount", layero).val(), password: $("#inputPassword", layero).val(), _method: 'POST'}
data: {
account: $("#inputAccount", layero).val(),
password: $("#inputPassword", layero).val(),
_method: 'POST'
}
}, function (data, ret) {
Controller.api.userinfo.set(data);
Layer.closeAll();
... ... @@ -199,7 +212,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
var token = userinfo ? userinfo.token : '';
Fast.api.ajax({
url: 'addon/install',
data: {name: name, force: force ? 1 : 0, uid: uid, token: token, version: version, faversion: Config.fastadmin.version}
data: {
name: name,
force: force ? 1 : 0,
uid: uid,
token: token,
version: version,
faversion: Config.fastadmin.version
}
}, function (data, ret) {
Layer.closeAll();
Config['addons'][data.addon.name] = ret.data.addon;
... ...
... ... @@ -180,10 +180,11 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
});
//清除缓存
$(document).on('click', "[data-toggle='wipecache']", function () {
$(document).on('click', "ul.wipecache li a", function () {
$.ajax({
url: 'ajax/wipecache',
dataType: 'json',
data: {type: $(this).data("type")},
cache: false,
success: function (ret) {
if (ret.hasOwnProperty("code")) {
... ...
/**
* FastAdmin通用搜索
*
* @author: pppscn <35696959@qq.com>
* @version: v0.0.1
* @update 2017-05-07 <https://gitee.com/pp/fastadmin>
*
* @update 2017-05-07 <http://git.oschina.net/pp/fastadmin>
* @update 2017-09-17 <http://git.oschina.net/karson/fastadmin>
* @author: Karson <karsonzhang@163.com>
* @update 2018-04-05 <https://gitee.com/karson/fastadmin>
*/
!function ($) {
... ... @@ -17,75 +19,16 @@
var vFormCommon = createFormCommon(pColumns, that);
var vModal = sprintf("<div class=\"commonsearch-table %s\">", that.options.searchFormVisible ? "" : "hidden");
vModal += vFormCommon.join('');
vModal += vFormCommon;
vModal += "</div>";
that.$container.prepend($(vModal));
that.$commonsearch = $(".commonsearch-table", that.$container);
var form = $("form.form-commonsearch", that.$commonsearch);
//绑定日期时间元素事件
if ($(".datetimepicker", form).size() > 0) {
require(['bootstrap-datetimepicker'], function () {
$('.datetimepicker', form).parent().css('position', 'relative');
$('.datetimepicker', form).datetimepicker({
//format: 'YYYY-MM-DD',
icons: {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
today: 'fa fa-history',
clear: 'fa fa-trash',
close: 'fa fa-remove'
},
showTodayButton: true,
showClose: true
});
});
}
if ($(".datetimerange", form).size() > 0) {
var ranges = {};
ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')];
ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')];
ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')];
ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')];
var options = {
timePicker: false,
autoUpdateInput: false,
timePickerSeconds: true,
timePicker24Hour: true,
autoApply: true,
locale: {
format: 'YYYY-MM-DD HH:mm:ss',
customRangeLabel: __("Custom Range"),
applyLabel: __("Apply"),
cancelLabel: __("Clear"),
},
ranges: ranges,
};
var callback = function (start, end) {
$(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));
};
var column, index;
require(['bootstrap-daterangepicker'], function () {
$(".datetimerange", form).each(function () {
$(this).on('apply.daterangepicker', function (ev, picker) {
callback.call(picker, picker.startDate, picker.endDate);
});
$(this).on('cancel.daterangepicker', function (ev, picker) {
$(this).val('');
});
index = $(this).data("index");
column = pColumns[index];
$(this).daterangepicker($.extend({}, options, column.options || {}), callback);
});
});
}
require(['form'], function (Form) {
Form.api.bindevent(form);
form.validator("destroy");
});
// 表单提交
form.on("submit", function (event) {
... ... @@ -103,9 +46,12 @@
};
var createFormCommon = function (pColumns, that) {
// 如果有使用模板则直接返回模板的内容
if (that.options.searchFormTemplate) {
return Template(that.options.searchFormTemplate, {columns: pColumns, table: that});
}
var htmlForm = [];
var opList = ['=', '>', '>=', '<', '<=', '!=', 'FIND_IN_SET', 'LIKE', 'LIKE %...%', 'NOT LIKE', 'IN', 'NOT IN', 'IN(...)', 'NOT IN(...)', 'BETWEEN', 'NOT BETWEEN', 'RANGE', 'NOT RANGE', 'IS NULL', 'IS NOT NULL'];
htmlForm.push(sprintf('<form class="form-horizontal form-commonsearch" action="%s" >', that.options.actionForm));
htmlForm.push(sprintf('<form class="form-horizontal form-commonsearch" novalidate method="post" action="%s" >', that.options.actionForm));
htmlForm.push('<fieldset>');
if (that.options.titleForm.length > 0)
htmlForm.push(sprintf("<legend>%s</legend>", that.options.titleForm));
... ... @@ -114,24 +60,28 @@
var vObjCol = pColumns[i];
if (!vObjCol.checkbox && vObjCol.field !== 'operate' && vObjCol.searchable && vObjCol.operate !== false) {
var query = Backend.api.query(vObjCol.field);
query = query ? query : '';
vObjCol.defaultValue = that.options.renderDefault && query != '' ? query : (typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue);
var operate = Backend.api.query(vObjCol.field + "-operate");
vObjCol.defaultValue = that.options.renderDefault && query ? query : (typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue);
vObjCol.operate = that.options.renderDefault && operate ? operate : (typeof vObjCol.operate === 'undefined' ? '=' : vObjCol.operate);
ColumnsForSearch.push(vObjCol);
htmlForm.push('<div class="form-group col-xs-12 col-sm-6 col-md-4 col-lg-3">');
htmlForm.push(sprintf('<label for="%s" class="control-label col-xs-4">%s</label>', vObjCol.field, vObjCol.title));
htmlForm.push('<div class="col-xs-8">');
vObjCol.operate = (typeof vObjCol.operate === 'undefined' || $.inArray(vObjCol.operate.toUpperCase(), opList) === -1) ? '=' : vObjCol.operate.toUpperCase();
htmlForm.push(sprintf('<input type="hidden" class="form-control operate" name="field-%s" data-name="%s" value="%s" readonly>', vObjCol.field, vObjCol.field, vObjCol.operate));
vObjCol.operate = vObjCol.operate ? vObjCol.operate.toUpperCase() : '=';
htmlForm.push(sprintf('<input type="hidden" class="form-control operate" name="%s-operate" data-name="%s" value="%s" readonly>', vObjCol.field, vObjCol.field, vObjCol.operate));
var addClass = typeof vObjCol.addClass === 'undefined' ? (typeof vObjCol.addclass === 'undefined' ? 'form-control' : 'form-control ' + vObjCol.addclass) : 'form-control ' + vObjCol.addClass;
var extend = typeof vObjCol.extend === 'undefined' ? '' : vObjCol.extend;
var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style);
extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend;
if (vObjCol.searchList) {
if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') {
htmlForm.push(sprintf('<select class="form-control" name="%s" %s>%s</select>', vObjCol.field, style, sprintf('<option value="">%s</option>', that.options.formatCommonChoose())));
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, sprintf('<option value="">%s</option>', that.options.formatCommonChoose())));
(function (vObjCol, that) {
$.when(vObjCol.searchList).done(function (ret) {
var isArray = false;
if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
var resultlist = {};
... ... @@ -160,23 +110,21 @@
var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : '';
searchList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect));
});
htmlForm.push(sprintf('<select class="form-control" name="%s" %s>%s</select>', vObjCol.field, style, searchList.join('')));
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, searchList.join('')));
}
} else {
var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder;
var type = typeof vObjCol.type === 'undefined' ? 'text' : vObjCol.type;
var addclass = typeof vObjCol.addclass === 'undefined' ? 'form-control' : 'form-control ' + vObjCol.addclass;
var data = typeof vObjCol.data === 'undefined' ? '' : vObjCol.data;
var defaultValue = typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue;
if (/BETWEEN$/.test(vObjCol.operate)) {
var defaultValueArr = defaultValue.toString().match(/\|/) ? defaultValue.split('|') : ['', ''];
var placeholderArr = placeholder.toString().match(/\|/) ? placeholder.split('|') : [placeholder, placeholder];
htmlForm.push('<div class="row row-between">');
htmlForm.push(sprintf('<div class="col-xs-6 11"><input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s></div>', type, addclass, vObjCol.field, defaultValueArr[0], placeholderArr[0], vObjCol.field, i, style, data));
htmlForm.push(sprintf('<div class="col-xs-6 22"><input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s></div>', type, addclass, vObjCol.field, defaultValueArr[1], placeholderArr[1], vObjCol.field, i, style, data));
htmlForm.push(sprintf('<div class="col-xs-6"><input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s></div>', type, addClass, vObjCol.field, defaultValueArr[0], placeholderArr[0], vObjCol.field, i, style, extend));
htmlForm.push(sprintf('<div class="col-xs-6"><input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s></div>', type, addClass, vObjCol.field, defaultValueArr[1], placeholderArr[1], vObjCol.field, i, style, extend));
htmlForm.push('</div>');
} else {
htmlForm.push(sprintf('<input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s>', type, addclass, vObjCol.field, defaultValue, placeholder, vObjCol.field, i, style, data));
htmlForm.push(sprintf('<input type="%s" class="%s" name="%s" value="%s" placeholder="%s" id="%s" data-index="%s" %s %s>', type, addClass, vObjCol.field, defaultValue, placeholder, vObjCol.field, i, style, extend));
}
}
... ... @@ -191,7 +139,7 @@
htmlForm.push('</fieldset>');
htmlForm.push('</form>');
return htmlForm;
return htmlForm.join('');
};
var createFormBtn = function (that) {
... ... @@ -199,7 +147,7 @@
var searchSubmit = that.options.formatCommonSubmitButton();
var searchReset = that.options.formatCommonResetButton();
htmlBtn.push('<div class="col-sm-8 col-xs-offset-4">');
htmlBtn.push(sprintf('<button type="submit" class="btn btn-success" >%s</button> ', searchSubmit));
htmlBtn.push(sprintf('<button type="submit" class="btn btn-success" formnovalidate>%s</button> ', searchSubmit));
htmlBtn.push(sprintf('<button type="reset" class="btn btn-default" >%s</button> ', searchReset));
htmlBtn.push('</div>');
return htmlBtn;
... ... @@ -219,16 +167,17 @@
var op = {};
var filter = {};
var value = '';
$("form.form-commonsearch input.operate", that.$commonsearch).each(function (i) {
$("form.form-commonsearch .operate", that.$commonsearch).each(function (i) {
var name = $(this).data("name");
var sym = $(this).val().toUpperCase();
var sym = $(this).is("select") ? $("option:selected", this).val() : $(this).val().toUpperCase();
var obj = $("[name='" + name + "']", that.$commonsearch);
if (obj.size() == 0)
return true;
var vObjCol = ColumnsForSearch[i];
if (obj.size() > 1) {
if (/BETWEEN$/.test(sym)) {
var value_begin = $.trim($("[name='" + name + "']:first", that.$commonsearch).val()), value_end = $.trim($("[name='" + name + "']:last", that.$commonsearch).val());
var value_begin = $.trim($("[name='" + name + "']:first", that.$commonsearch).val()),
value_end = $.trim($("[name='" + name + "']:last", that.$commonsearch).val());
if (value_begin.length || value_end.length) {
if (typeof vObjCol.process === 'function') {
value_begin = vObjCol.process(value_begin, 'begin');
... ... @@ -244,11 +193,12 @@
}
} else {
value = $("[name='" + name + "']:checked", that.$commonsearch).val();
value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : obj.val();
}
} else {
value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : (sym == 'LIKE %...%' ? obj.val().replace(/\*/g, '%') : obj.val());
value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : obj.val();
}
if (removeempty && value == '' && sym.indexOf("NULL") == -1) {
if (removeempty && (value == '' || value == null || ($.isArray(value) && value.length == 0)) && !sym.match(/null/i)) {
return true;
}
... ... @@ -267,7 +217,7 @@
//移除empty的值
if (removeempty) {
$.each(params.filter, function (i, j) {
if (j === '') {
if ((j == '' || j == null || ($.isArray(j) && j.length == 0)) && !params.op[i].match(/null/i)) {
delete params.filter[i];
delete params.op[i];
}
... ... @@ -282,8 +232,10 @@
commonSearch: false,
titleForm: "Common search",
actionForm: "",
searchFormTemplate: "",
searchFormVisible: true,
searchClass: 'searchit',
showSearch: true,
renderDefault: true,
onCommonSearch: function (field, text) {
return false;
... ... @@ -322,10 +274,10 @@
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initHeader = BootstrapTable.prototype.initHeader,
_initToolbar = BootstrapTable.prototype.initToolbar,
_load = BootstrapTable.prototype.load,
_initSearch = BootstrapTable.prototype.initSearch;
_initHeader = BootstrapTable.prototype.initHeader,
_initToolbar = BootstrapTable.prototype.initToolbar,
_load = BootstrapTable.prototype.load,
_initSearch = BootstrapTable.prototype.initSearch;
BootstrapTable.prototype.initHeader = function () {
_initHeader.apply(this, Array.prototype.slice.apply(arguments));
... ... @@ -344,12 +296,13 @@
}
var that = this,
html = [];
html.push(sprintf('<div class="columns-%s pull-%s" style="margin-top:10px;margin-bottom:10px;">', this.options.buttonsAlign, this.options.buttonsAlign));
html.push(sprintf('<button class="btn btn-default%s' + '" type="button" name="commonSearch" title="%s">', that.options.iconSize === undefined ? '' : ' btn-' + that.options.iconSize, that.options.formatCommonSearch()));
html.push(sprintf('<i class="%s %s"></i>', that.options.iconsPrefix, that.options.icons.commonSearchIcon))
html.push('</button></div>');
html = [];
if(that.options.showSearch){
html.push(sprintf('<div class="columns-%s pull-%s" style="margin-top:10px;margin-bottom:10px;">', this.options.buttonsAlign, this.options.buttonsAlign));
html.push(sprintf('<button class="btn btn-default%s' + '" type="button" name="commonSearch" title="%s">', that.options.iconSize === undefined ? '' : ' btn-' + that.options.iconSize, that.options.formatCommonSearch()));
html.push(sprintf('<i class="%s %s"></i>', that.options.iconsPrefix, that.options.icons.commonSearchIcon))
html.push('</button></div>');
}
if (that.$toolbar.find(".pull-right").size() > 0) {
$(html.join('')).insertBefore(that.$toolbar.find(".pull-right:first"));
} else {
... ... @@ -359,7 +312,7 @@
initCommonSearch(that.columns, that);
that.$toolbar.find('button[name="commonSearch"]')
.off('click').on('click', function () {
.off('click').on('click', function () {
that.$commonsearch.toggleClass("hidden");
return;
});
... ... @@ -374,7 +327,7 @@
var queryParams = that.options.queryParams;
//匹配默认搜索值
this.options.queryParams = function (params) {
return queryParams(getQueryParams(params, getSearchQuery(this, true)));
return queryParams(getQueryParams(params, getSearchQuery(that, true)));
};
this.trigger('post-common-search', that);
... ... @@ -409,8 +362,8 @@
var fval = fp[key].toLowerCase();
var value = item[key];
value = $.fn.bootstrapTable.utils.calculateObjectValue(that.header,
that.header.formatters[$.inArray(key, that.header.fields)],
[value, item, i], value);
that.header.formatters[$.inArray(key, that.header.fields)],
[value, item, i], value);
if (!($.inArray(key, that.header.fields) !== -1 &&
(typeof value === 'string' || typeof value === 'number') &&
... ...
define(['fast'], function (Fast) {
define(['fast', 'template'], function (Fast, Template) {
var Frontend = {
api: Fast.api,
init: function () {
... ... @@ -53,6 +53,8 @@ define(['fast'], function (Fast) {
}
};
Frontend.api = $.extend(Fast.api, Frontend.api);
//将Template渲染至全局,以便于在子框架中调用
window.Template = Template;
//将Frontend渲染至全局,以便于在子框架中调用
window.Frontend = Frontend;
... ...
define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
var Form = {
config: {
fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="30" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
},
events: {
validator: function (form, success, error, submit) {
... ... @@ -26,6 +26,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
}
},
target: function (input) {
var target = $(input).data("target");
if (target && $(target).size() > 0) {
return $(target);
}
var $formitem = $(input).closest('.form-group'),
$msgbox = $formitem.find('span.msg-box');
if (!$msgbox.length) {
... ... @@ -282,7 +286,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
refresh($(this).closest("dl").data("name"));
});
//追加控制
$(".fieldlist", form).on("click", ".btn-append", function (e, row) {
$(".fieldlist", form).on("click", ".btn-append,.append", function (e, row) {
var container = $(this).closest("dl");
var index = container.data("index");
var name = container.data("name");
... ... @@ -305,7 +309,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
//拖拽排序
$("dl.fieldlist", form).dragsort({
itemSelector: 'dd',
dragSelector: ".btn-fdragsort",
dragSelector: ".btn-dragsort",
dragEnd: function () {
refresh($(this).closest("dl").data("name"));
},
... ... @@ -319,8 +323,13 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
return true;
}
var template = $(this).data("template");
$.each(JSON.parse(textarea.val()), function (i, j) {
$(".btn-append", container).trigger('click', template ? j : {
var json = {};
try {
json = JSON.parse(textarea.val());
} catch (e) {
}
$.each(json, function (i, j) {
$(".btn-append,.append", container).trigger('click', template ? j : {
key: i,
value: j
});
... ...
... ... @@ -973,7 +973,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
return Fast;
});
define('frontend',['fast'], function (Fast) {
/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(/<!--[\w\W]*?-->/g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(a){throw a.temp="function anonymous($data,$filename) {"+z+"}",a}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a)(b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","&":"&#38;"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;c<d;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(a){return a.filename=h||"anonymous",a.name="Syntax Error",p(a)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;"object"==typeof exports&&"undefined"!=typeof module?module.exports=d:"function"==typeof define?define('template',[],function(){return d}):this.template=d}();
define('frontend',['fast', 'template'], function (Fast, Template) {
var Frontend = {
api: Fast.api,
init: function () {
... ... @@ -1028,6 +1030,8 @@ define('frontend',['fast'], function (Fast) {
}
};
Frontend.api = $.extend(Fast.api, Frontend.api);
//将Template渲染至全局,以便于在子框架中调用
window.Template = Template;
//将Frontend渲染至全局,以便于在子框架中调用
window.Frontend = Frontend;
... ...
... ... @@ -847,4 +847,8 @@ form.form-horizontal .control-label {
margin: 2px 0 0;
}
}
}
.wipecache li a {
color:#444444!important;
}
\ No newline at end of file
... ...