作者 Karson

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

新增全局的Template
新增自定义通用搜索表单内容
新增通用搜索按钮显示配置
新增单独清除模板、插件缓存
新增后台登录失败重试配置
优化通用搜索,搜索元素支持自动绑定元素事件
优化本地插件显示
优化前台首页和API文档字体显示
修复元素验证指定data-target不生效的BUG
修复插件命令行添加--force不生效的BUG
修复noNeedLogin和noNeedRight大小写的BUG
修复fieldlist无法挺拽的BUG
修复一键CRUD后指定字段显示后无法显示关联数据的BUG
@@ -19,14 +19,14 @@ class Addon extends Command @@ -19,14 +19,14 @@ class Addon extends Command
19 protected function configure() 19 protected function configure()
20 { 20 {
21 $this 21 $this
22 - ->setName('addon')  
23 - ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)  
24 - ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')  
25 - ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)  
26 - ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)  
27 - ->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)  
28 - ->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)  
29 - ->setDescription('Addon manager'); 22 + ->setName('addon')
  23 + ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
  24 + ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
  25 + ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
  26 + ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
  27 + ->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
  28 + ->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
  29 + ->setDescription('Addon manager');
30 } 30 }
31 31
32 protected function execute(Input $input, Output $output) 32 protected function execute(Input $input, Output $output)
@@ -44,12 +44,10 @@ class Addon extends Command @@ -44,12 +44,10 @@ class Addon extends Command
44 44
45 include dirname(__DIR__) . DS . 'common.php'; 45 include dirname(__DIR__) . DS . 'common.php';
46 46
47 - if (!$name)  
48 - { 47 + if (!$name) {
49 throw new Exception('Addon name could not be empty'); 48 throw new Exception('Addon name could not be empty');
50 } 49 }
51 - if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package']))  
52 - { 50 + if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package'])) {
53 throw new Exception('Please input correct action name'); 51 throw new Exception('Please input correct action name');
54 } 52 }
55 53
@@ -57,17 +55,14 @@ class Addon extends Command @@ -57,17 +55,14 @@ class Addon extends Command
57 Db::execute("SELECT 1"); 55 Db::execute("SELECT 1");
58 56
59 $addonDir = ADDON_PATH . $name . DS; 57 $addonDir = ADDON_PATH . $name . DS;
60 - switch ($action)  
61 - { 58 + switch ($action) {
62 case 'create': 59 case 'create':
63 //非覆盖模式时如果存在则报错 60 //非覆盖模式时如果存在则报错
64 - if (is_dir($addonDir) && !$force)  
65 - { 61 + if (is_dir($addonDir) && !$force) {
66 throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true "); 62 throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true ");
67 } 63 }
68 //如果存在先移除 64 //如果存在先移除
69 - if (is_dir($addonDir))  
70 - { 65 + if (is_dir($addonDir)) {
71 rmdirs($addonDir); 66 rmdirs($addonDir);
72 } 67 }
73 mkdir($addonDir); 68 mkdir($addonDir);
@@ -76,16 +71,12 @@ class Addon extends Command @@ -76,16 +71,12 @@ class Addon extends Command
76 $createMenu = $this->getCreateMenu($menuList); 71 $createMenu = $this->getCreateMenu($menuList);
77 $prefix = Config::get('database.prefix'); 72 $prefix = Config::get('database.prefix');
78 $createTableSql = ''; 73 $createTableSql = '';
79 - try  
80 - { 74 + try {
81 $result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;"); 75 $result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;");
82 - if (isset($result[0]) && isset($result[0]['Create Table']))  
83 - { 76 + if (isset($result[0]) && isset($result[0]['Create Table'])) {
84 $createTableSql = $result[0]['Create Table']; 77 $createTableSql = $result[0]['Create Table'];
85 } 78 }
86 - }  
87 - catch (PDOException $e)  
88 - { 79 + } catch (PDOException $e) {
89 80
90 } 81 }
91 82
@@ -102,8 +93,7 @@ class Addon extends Command @@ -102,8 +93,7 @@ class Addon extends Command
102 $this->writeToFile("config", $data, $addonDir . 'config.php'); 93 $this->writeToFile("config", $data, $addonDir . 'config.php');
103 $this->writeToFile("info", $data, $addonDir . 'info.ini'); 94 $this->writeToFile("info", $data, $addonDir . 'info.ini');
104 $this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php'); 95 $this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php');
105 - if ($createTableSql)  
106 - { 96 + if ($createTableSql) {
107 $createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql); 97 $createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql);
108 file_put_contents($addonDir . 'install.sql', $createTableSql); 98 file_put_contents($addonDir . 'install.sql', $createTableSql);
109 } 99 }
@@ -112,75 +102,61 @@ class Addon extends Command @@ -112,75 +102,61 @@ class Addon extends Command
112 break; 102 break;
113 case 'disable': 103 case 'disable':
114 case 'enable': 104 case 'enable':
115 - try  
116 - { 105 + try {
117 //调用启用、禁用的方法 106 //调用启用、禁用的方法
118 Service::$action($name, 0); 107 Service::$action($name, 0);
119 - }  
120 - catch (AddonException $e)  
121 - {  
122 - if ($e->getCode() != -3)  
123 - { 108 + } catch (AddonException $e) {
  109 + if ($e->getCode() != -3) {
124 throw new Exception($e->getMessage()); 110 throw new Exception($e->getMessage());
125 } 111 }
126 - //如果有冲突文件则提醒  
127 - $data = $e->getData();  
128 - foreach ($data['conflictlist'] as $k => $v)  
129 - {  
130 - $output->warning($v);  
131 - }  
132 - $output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files? Type 'yes' to continue: ");  
133 - $line = fgets(STDIN);  
134 - if (trim($line) != 'yes')  
135 - {  
136 - throw new Exception("Operation is aborted!"); 112 + if (!$force) {
  113 + //如果有冲突文件则提醒
  114 + $data = $e->getData();
  115 + foreach ($data['conflictlist'] as $k => $v) {
  116 + $output->warning($v);
  117 + }
  118 + $output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files? Type 'yes' to continue: ");
  119 + $line = fgets(STDIN);
  120 + if (trim($line) != 'yes') {
  121 + throw new Exception("Operation is aborted!");
  122 + }
137 } 123 }
138 //调用启用、禁用的方法 124 //调用启用、禁用的方法
139 Service::$action($name, 1); 125 Service::$action($name, 1);
140 - }  
141 - catch (Exception $e)  
142 - { 126 + } catch (Exception $e) {
143 throw new Exception($e->getMessage()); 127 throw new Exception($e->getMessage());
144 } 128 }
145 $output->info(ucfirst($action) . " Successed!"); 129 $output->info(ucfirst($action) . " Successed!");
146 break; 130 break;
147 case 'install': 131 case 'install':
148 //非覆盖模式时如果存在则报错 132 //非覆盖模式时如果存在则报错
149 - if (is_dir($addonDir) && !$force)  
150 - { 133 + if (is_dir($addonDir) && !$force) {
151 throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true "); 134 throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
152 } 135 }
153 //如果存在先移除 136 //如果存在先移除
154 - if (is_dir($addonDir))  
155 - { 137 + if (is_dir($addonDir)) {
156 rmdirs($addonDir); 138 rmdirs($addonDir);
157 } 139 }
158 - try  
159 - { 140 + try {
160 Service::install($name, 0, ['version' => $release]); 141 Service::install($name, 0, ['version' => $release]);
161 - }  
162 - catch (AddonException $e)  
163 - {  
164 - if ($e->getCode() != -3)  
165 - { 142 + } catch (AddonException $e) {
  143 + if ($e->getCode() != -3) {
166 throw new Exception($e->getMessage()); 144 throw new Exception($e->getMessage());
167 } 145 }
168 - //如果有冲突文件则提醒  
169 - $data = $e->getData();  
170 - foreach ($data['conflictlist'] as $k => $v)  
171 - {  
172 - $output->warning($v);  
173 - }  
174 - $output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");  
175 - $line = fgets(STDIN);  
176 - if (trim($line) != 'yes')  
177 - {  
178 - throw new Exception("Operation is aborted!"); 146 + if (!$force) {
  147 + //如果有冲突文件则提醒
  148 + $data = $e->getData();
  149 + foreach ($data['conflictlist'] as $k => $v) {
  150 + $output->warning($v);
  151 + }
  152 + $output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");
  153 + $line = fgets(STDIN);
  154 + if (trim($line) != 'yes') {
  155 + throw new Exception("Operation is aborted!");
  156 + }
179 } 157 }
180 Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token]); 158 Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token]);
181 - }  
182 - catch (Exception $e)  
183 - { 159 + } catch (Exception $e) {
184 throw new Exception($e->getMessage()); 160 throw new Exception($e->getMessage());
185 } 161 }
186 162
@@ -188,36 +164,29 @@ class Addon extends Command @@ -188,36 +164,29 @@ class Addon extends Command
188 break; 164 break;
189 case 'uninstall': 165 case 'uninstall':
190 //非覆盖模式时如果存在则报错 166 //非覆盖模式时如果存在则报错
191 - if (!$force)  
192 - { 167 + if (!$force) {
193 throw new Exception("If you need to uninstall addon, use the parameter --force=true "); 168 throw new Exception("If you need to uninstall addon, use the parameter --force=true ");
194 } 169 }
195 - try  
196 - { 170 + try {
197 Service::uninstall($name, 0); 171 Service::uninstall($name, 0);
198 - }  
199 - catch (AddonException $e)  
200 - {  
201 - if ($e->getCode() != -3)  
202 - { 172 + } catch (AddonException $e) {
  173 + if ($e->getCode() != -3) {
203 throw new Exception($e->getMessage()); 174 throw new Exception($e->getMessage());
204 } 175 }
205 - //如果有冲突文件则提醒  
206 - $data = $e->getData();  
207 - foreach ($data['conflictlist'] as $k => $v)  
208 - {  
209 - $output->warning($v);  
210 - }  
211 - $output->info("Are you sure you want to delete all those files? Type 'yes' to continue: ");  
212 - $line = fgets(STDIN);  
213 - if (trim($line) != 'yes')  
214 - {  
215 - throw new Exception("Operation is aborted!"); 176 + if (!$force) {
  177 + //如果有冲突文件则提醒
  178 + $data = $e->getData();
  179 + foreach ($data['conflictlist'] as $k => $v) {
  180 + $output->warning($v);
  181 + }
  182 + $output->info("Are you sure you want to delete all those files? Type 'yes' to continue: ");
  183 + $line = fgets(STDIN);
  184 + if (trim($line) != 'yes') {
  185 + throw new Exception("Operation is aborted!");
  186 + }
216 } 187 }
217 Service::uninstall($name, 1); 188 Service::uninstall($name, 1);
218 - }  
219 - catch (Exception $e)  
220 - { 189 + } catch (Exception $e) {
221 throw new Exception($e->getMessage()); 190 throw new Exception($e->getMessage());
222 } 191 }
223 192
@@ -233,53 +202,44 @@ class Addon extends Command @@ -233,53 +202,44 @@ class Addon extends Command
233 break; 202 break;
234 case 'package': 203 case 'package':
235 $infoFile = $addonDir . 'info.ini'; 204 $infoFile = $addonDir . 'info.ini';
236 - if (!is_file($infoFile))  
237 - { 205 + if (!is_file($infoFile)) {
238 throw new Exception(__('Addon info file was not found')); 206 throw new Exception(__('Addon info file was not found'));
239 } 207 }
240 208
241 $info = get_addon_info($name); 209 $info = get_addon_info($name);
242 - if (!$info)  
243 - { 210 + if (!$info) {
244 throw new Exception(__('Addon info file data incorrect')); 211 throw new Exception(__('Addon info file data incorrect'));
245 } 212 }
246 $infoname = isset($info['name']) ? $info['name'] : ''; 213 $infoname = isset($info['name']) ? $info['name'] : '';
247 - if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name)  
248 - { 214 + if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) {
249 throw new Exception(__('Addon info name incorrect')); 215 throw new Exception(__('Addon info name incorrect'));
250 } 216 }
251 217
252 $infoversion = isset($info['version']) ? $info['version'] : ''; 218 $infoversion = isset($info['version']) ? $info['version'] : '';
253 - if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion))  
254 - { 219 + if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) {
255 throw new Exception(__('Addon info version incorrect')); 220 throw new Exception(__('Addon info version incorrect'));
256 } 221 }
257 222
258 $addonTmpDir = RUNTIME_PATH . 'addons' . DS; 223 $addonTmpDir = RUNTIME_PATH . 'addons' . DS;
259 - if (!is_dir($addonTmpDir))  
260 - { 224 + if (!is_dir($addonTmpDir)) {
261 @mkdir($addonTmpDir, 0755, true); 225 @mkdir($addonTmpDir, 0755, true);
262 } 226 }
263 $addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip'; 227 $addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip';
264 - if (!class_exists('ZipArchive'))  
265 - { 228 + if (!class_exists('ZipArchive')) {
266 throw new Exception(__('ZinArchive not install')); 229 throw new Exception(__('ZinArchive not install'));
267 } 230 }
268 $zip = new \ZipArchive; 231 $zip = new \ZipArchive;
269 $zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); 232 $zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
270 233
271 $files = new \RecursiveIteratorIterator( 234 $files = new \RecursiveIteratorIterator(
272 - new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY 235 + new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
273 ); 236 );
274 237
275 - foreach ($files as $name => $file)  
276 - {  
277 - if (!$file->isDir())  
278 - { 238 + foreach ($files as $name => $file) {
  239 + if (!$file->isDir()) {
279 $filePath = $file->getRealPath(); 240 $filePath = $file->getRealPath();
280 $relativePath = substr($filePath, strlen($addonDir)); 241 $relativePath = substr($filePath, strlen($addonDir));
281 - if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db']))  
282 - { 242 + if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) {
283 $zip->addFile($filePath, $relativePath); 243 $zip->addFile($filePath, $relativePath);
284 } 244 }
285 } 245 }
@@ -301,22 +261,18 @@ class Addon extends Command @@ -301,22 +261,18 @@ class Addon extends Command
301 protected function getCreateMenu($menu) 261 protected function getCreateMenu($menu)
302 { 262 {
303 $result = []; 263 $result = [];
304 - foreach ($menu as $k => & $v)  
305 - { 264 + foreach ($menu as $k => & $v) {
306 $arr = [ 265 $arr = [
307 'name' => $v['name'], 266 'name' => $v['name'],
308 'title' => $v['title'], 267 'title' => $v['title'],
309 ]; 268 ];
310 - if ($v['icon'] != 'fa fa-circle-o')  
311 - { 269 + if ($v['icon'] != 'fa fa-circle-o') {
312 $arr['icon'] = $v['icon']; 270 $arr['icon'] = $v['icon'];
313 } 271 }
314 - if ($v['ismenu'])  
315 - { 272 + if ($v['ismenu']) {
316 $arr['ismenu'] = $v['ismenu']; 273 $arr['ismenu'] = $v['ismenu'];
317 } 274 }
318 - if (isset($v['childlist']) && $v['childlist'])  
319 - { 275 + if (isset($v['childlist']) && $v['childlist']) {
320 $arr['sublist'] = $this->getCreateMenu($v['childlist']); 276 $arr['sublist'] = $this->getCreateMenu($v['childlist']);
321 } 277 }
322 $result[] = $arr; 278 $result[] = $arr;
@@ -334,16 +290,14 @@ class Addon extends Command @@ -334,16 +290,14 @@ class Addon extends Command
334 protected function writeToFile($name, $data, $pathname) 290 protected function writeToFile($name, $data, $pathname)
335 { 291 {
336 $search = $replace = []; 292 $search = $replace = [];
337 - foreach ($data as $k => $v)  
338 - { 293 + foreach ($data as $k => $v) {
339 $search[] = "{%{$k}%}"; 294 $search[] = "{%{$k}%}";
340 $replace[] = $v; 295 $replace[] = $v;
341 } 296 }
342 $stub = file_get_contents($this->getStub($name)); 297 $stub = file_get_contents($this->getStub($name));
343 $content = str_replace($search, $replace, $stub); 298 $content = str_replace($search, $replace, $stub);
344 299
345 - if (!is_dir(dirname($pathname)))  
346 - { 300 + if (!is_dir(dirname($pathname))) {
347 mkdir(strtolower(dirname($pathname)), 0755, true); 301 mkdir(strtolower(dirname($pathname)), 0755, true);
348 } 302 }
349 return file_put_contents($pathname, $content); 303 return file_put_contents($pathname, $content);
@@ -9,7 +9,15 @@ @@ -9,7 +9,15 @@
9 <title>{$config.title}</title> 9 <title>{$config.title}</title>
10 <link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> 10 <link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
11 <style type="text/css"> 11 <style type="text/css">
12 - body { padding-top: 70px; margin-bottom: 15px; } 12 + body {
  13 + padding-top: 70px; margin-bottom: 15px;
  14 + -webkit-font-smoothing: antialiased;
  15 + -moz-osx-font-smoothing: grayscale;
  16 + 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;
  17 + font-weight: 400;
  18 + }
  19 + h2 { font-size: 1.6em; }
  20 + hr { margin-top: 10px; }
13 .tab-pane { padding-top: 10px; } 21 .tab-pane { padding-top: 10px; }
14 .mt0 { margin-top: 0px; } 22 .mt0 { margin-top: 0px; }
15 .footer { font-size: 12px; color: #666; } 23 .footer { font-size: 12px; color: #666; }
@@ -654,9 +654,10 @@ class Crud extends Command @@ -654,9 +654,10 @@ class Crud extends Command
654 $priDefined = TRUE; 654 $priDefined = TRUE;
655 $javascriptList[] = "{checkbox: true}"; 655 $javascriptList[] = "{checkbox: true}";
656 } 656 }
657 - //构造JS列信息  
658 - $javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);  
659 - 657 + if (!$fields || in_array($field, explode(',', $fields))) {
  658 + //构造JS列信息
  659 + $javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);
  660 + }
660 //排序方式,如果有指定排序字段,否则按主键排序 661 //排序方式,如果有指定排序字段,否则按主键排序
661 $order = $field == $this->sortField ? $this->sortField : $order; 662 $order = $field == $this->sortField ? $this->sortField : $order;
662 } 663 }
@@ -767,6 +768,11 @@ class Crud extends Command @@ -767,6 +768,11 @@ class Crud extends Command
767 //构造关联模型的方法 768 //构造关联模型的方法
768 $relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod', $relation); 769 $relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod', $relation);
769 770
  771 + //如果设置了显示主表字段,则必须显式将关联表字段显示
  772 + if ($fields) {
  773 + $relationVisibleFieldList[] = "\$row->visible(['{$relation['relationMethod']}']);";
  774 + }
  775 +
770 //显示的字段 776 //显示的字段
771 if ($relation['relationFields']) { 777 if ($relation['relationFields']) {
772 $relationVisibleFieldList[] = "\$row->getRelation('" . $relation['relationMethod'] . "')->visible(['" . implode("','", $relation['relationFields']) . "']);"; 778 $relationVisibleFieldList[] = "\$row->getRelation('" . $relation['relationMethod'] . "')->visible(['" . implode("','", $relation['relationFields']) . "']);";
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 namespace app\admin\controller; 3 namespace app\admin\controller;
4 4
5 use app\common\controller\Backend; 5 use app\common\controller\Backend;
  6 +use fast\Http;
6 use think\addons\AddonException; 7 use think\addons\AddonException;
7 use think\addons\Service; 8 use think\addons\Service;
8 use think\Cache; 9 use think\Cache;
@@ -31,8 +32,7 @@ class Addon extends Backend @@ -31,8 +32,7 @@ class Addon extends Backend
31 public function index() 32 public function index()
32 { 33 {
33 $addons = get_addon_list(); 34 $addons = get_addon_list();
34 - foreach ($addons as $k => &$v)  
35 - { 35 + foreach ($addons as $k => &$v) {
36 $config = get_addon_config($v['name']); 36 $config = get_addon_config($v['name']);
37 $v['config'] = $config ? 1 : 0; 37 $v['config'] = $config ? 1 : 0;
38 } 38 }
@@ -46,60 +46,31 @@ class Addon extends Backend @@ -46,60 +46,31 @@ class Addon extends Backend
46 public function config($ids = NULL) 46 public function config($ids = NULL)
47 { 47 {
48 $name = $this->request->get("name"); 48 $name = $this->request->get("name");
49 - if (!$name)  
50 - { 49 + if (!$name) {
51 $this->error(__('Parameter %s can not be empty', $ids ? 'id' : 'name')); 50 $this->error(__('Parameter %s can not be empty', $ids ? 'id' : 'name'));
52 } 51 }
53 - if (!is_dir(ADDON_PATH . $name))  
54 - { 52 + if (!is_dir(ADDON_PATH . $name)) {
55 $this->error(__('Directory not found')); 53 $this->error(__('Directory not found'));
56 } 54 }
57 $info = get_addon_info($name); 55 $info = get_addon_info($name);
58 $config = get_addon_fullconfig($name); 56 $config = get_addon_fullconfig($name);
59 if (!$info) 57 if (!$info)
60 $this->error(__('No Results were found')); 58 $this->error(__('No Results were found'));
61 - if ($this->request->isPost())  
62 - { 59 + if ($this->request->isPost()) {
63 $params = $this->request->post("row/a"); 60 $params = $this->request->post("row/a");
64 - if ($params)  
65 - {  
66 - foreach ($config as $k => &$v)  
67 - {  
68 - if (isset($params[$v['name']]))  
69 - {  
70 - if ($v['type'] == 'array')  
71 - {  
72 - $fieldarr = $valuearr = [];  
73 - $field = $params[$v['name']]['field'];  
74 - $value = $params[$v['name']]['value'];  
75 -  
76 - foreach ($field as $m => $n)  
77 - {  
78 - if ($n != '')  
79 - {  
80 - $fieldarr[] = $field[$m];  
81 - $valuearr[] = $value[$m];  
82 - }  
83 - }  
84 - $params[$v['name']] = array_combine($fieldarr, $valuearr);  
85 - $value = $params[$v['name']];  
86 - }  
87 - else  
88 - {  
89 - $value = is_array($params[$v['name']]) ? implode(',', $params[$v['name']]) : $params[$v['name']];  
90 - }  
91 - 61 + if ($params) {
  62 + foreach ($config as $k => &$v) {
  63 + if (isset($params[$v['name']])) {
  64 + $value = is_array($params[$v['name']]) ? implode(',', $params[$v['name']]) : $params[$v['name']];
92 $v['value'] = $value; 65 $v['value'] = $value;
93 } 66 }
94 } 67 }
95 - try  
96 - { 68 + try {
97 //更新配置文件 69 //更新配置文件
98 set_addon_fullconfig($name, $config); 70 set_addon_fullconfig($name, $config);
  71 + Service::refresh();
99 $this->success(); 72 $this->success();
100 - }  
101 - catch (Exception $e)  
102 - { 73 + } catch (Exception $e) {
103 $this->error($e->getMessage()); 74 $this->error($e->getMessage());
104 } 75 }
105 } 76 }
@@ -115,13 +86,11 @@ class Addon extends Backend @@ -115,13 +86,11 @@ class Addon extends Backend
115 public function install() 86 public function install()
116 { 87 {
117 $name = $this->request->post("name"); 88 $name = $this->request->post("name");
118 - $force = (int) $this->request->post("force");  
119 - if (!$name)  
120 - { 89 + $force = (int)$this->request->post("force");
  90 + if (!$name) {
121 $this->error(__('Parameter %s can not be empty', 'name')); 91 $this->error(__('Parameter %s can not be empty', 'name'));
122 } 92 }
123 - try  
124 - { 93 + try {
125 $uid = $this->request->post("uid"); 94 $uid = $this->request->post("uid");
126 $token = $this->request->post("token"); 95 $token = $this->request->post("token");
127 $version = $this->request->post("version"); 96 $version = $this->request->post("version");
@@ -137,13 +106,9 @@ class Addon extends Backend @@ -137,13 +106,9 @@ class Addon extends Backend
137 $info['config'] = get_addon_config($name) ? 1 : 0; 106 $info['config'] = get_addon_config($name) ? 1 : 0;
138 $info['state'] = 1; 107 $info['state'] = 1;
139 $this->success(__('Install successful'), null, ['addon' => $info]); 108 $this->success(__('Install successful'), null, ['addon' => $info]);
140 - }  
141 - catch (AddonException $e)  
142 - { 109 + } catch (AddonException $e) {
143 $this->result($e->getData(), $e->getCode(), $e->getMessage()); 110 $this->result($e->getData(), $e->getCode(), $e->getMessage());
144 - }  
145 - catch (Exception $e)  
146 - { 111 + } catch (Exception $e) {
147 $this->error($e->getMessage(), $e->getCode()); 112 $this->error($e->getMessage(), $e->getCode());
148 } 113 }
149 } 114 }
@@ -154,22 +119,16 @@ class Addon extends Backend @@ -154,22 +119,16 @@ class Addon extends Backend
154 public function uninstall() 119 public function uninstall()
155 { 120 {
156 $name = $this->request->post("name"); 121 $name = $this->request->post("name");
157 - $force = (int) $this->request->post("force");  
158 - if (!$name)  
159 - { 122 + $force = (int)$this->request->post("force");
  123 + if (!$name) {
160 $this->error(__('Parameter %s can not be empty', 'name')); 124 $this->error(__('Parameter %s can not be empty', 'name'));
161 } 125 }
162 - try  
163 - { 126 + try {
164 Service::uninstall($name, $force); 127 Service::uninstall($name, $force);
165 $this->success(__('Uninstall successful')); 128 $this->success(__('Uninstall successful'));
166 - }  
167 - catch (AddonException $e)  
168 - { 129 + } catch (AddonException $e) {
169 $this->result($e->getData(), $e->getCode(), $e->getMessage()); 130 $this->result($e->getData(), $e->getCode(), $e->getMessage());
170 - }  
171 - catch (Exception $e)  
172 - { 131 + } catch (Exception $e) {
173 $this->error($e->getMessage()); 132 $this->error($e->getMessage());
174 } 133 }
175 } 134 }
@@ -181,25 +140,19 @@ class Addon extends Backend @@ -181,25 +140,19 @@ class Addon extends Backend
181 { 140 {
182 $name = $this->request->post("name"); 141 $name = $this->request->post("name");
183 $action = $this->request->post("action"); 142 $action = $this->request->post("action");
184 - $force = (int) $this->request->post("force");  
185 - if (!$name)  
186 - { 143 + $force = (int)$this->request->post("force");
  144 + if (!$name) {
187 $this->error(__('Parameter %s can not be empty', 'name')); 145 $this->error(__('Parameter %s can not be empty', 'name'));
188 } 146 }
189 - try  
190 - { 147 + try {
191 $action = $action == 'enable' ? $action : 'disable'; 148 $action = $action == 'enable' ? $action : 'disable';
192 //调用启用、禁用的方法 149 //调用启用、禁用的方法
193 Service::$action($name, $force); 150 Service::$action($name, $force);
194 Cache::rm('__menu__'); 151 Cache::rm('__menu__');
195 $this->success(__('Operate successful')); 152 $this->success(__('Operate successful'));
196 - }  
197 - catch (AddonException $e)  
198 - { 153 + } catch (AddonException $e) {
199 $this->result($e->getData(), $e->getCode(), $e->getMessage()); 154 $this->result($e->getData(), $e->getCode(), $e->getMessage());
200 - }  
201 - catch (Exception $e)  
202 - { 155 + } catch (Exception $e) {
203 $this->error($e->getMessage()); 156 $this->error($e->getMessage());
204 } 157 }
205 } 158 }
@@ -213,55 +166,46 @@ class Addon extends Backend @@ -213,55 +166,46 @@ class Addon extends Backend
213 166
214 $file = $this->request->file('file'); 167 $file = $this->request->file('file');
215 $addonTmpDir = RUNTIME_PATH . 'addons' . DS; 168 $addonTmpDir = RUNTIME_PATH . 'addons' . DS;
216 - if (!is_dir($addonTmpDir))  
217 - { 169 + if (!is_dir($addonTmpDir)) {
218 @mkdir($addonTmpDir, 0755, true); 170 @mkdir($addonTmpDir, 0755, true);
219 } 171 }
220 $info = $file->rule('uniqid')->validate(['size' => 10240000, 'ext' => 'zip'])->move($addonTmpDir); 172 $info = $file->rule('uniqid')->validate(['size' => 10240000, 'ext' => 'zip'])->move($addonTmpDir);
221 - if ($info)  
222 - { 173 + if ($info) {
223 $tmpName = substr($info->getFilename(), 0, stripos($info->getFilename(), '.')); 174 $tmpName = substr($info->getFilename(), 0, stripos($info->getFilename(), '.'));
224 $tmpAddonDir = ADDON_PATH . $tmpName . DS; 175 $tmpAddonDir = ADDON_PATH . $tmpName . DS;
225 $tmpFile = $addonTmpDir . $info->getSaveName(); 176 $tmpFile = $addonTmpDir . $info->getSaveName();
226 - try  
227 - { 177 + try {
228 Service::unzip($tmpName); 178 Service::unzip($tmpName);
229 @unlink($tmpFile); 179 @unlink($tmpFile);
230 $infoFile = $tmpAddonDir . 'info.ini'; 180 $infoFile = $tmpAddonDir . 'info.ini';
231 - if (!is_file($infoFile))  
232 - { 181 + if (!is_file($infoFile)) {
233 throw new Exception(__('Addon info file was not found')); 182 throw new Exception(__('Addon info file was not found'));
234 } 183 }
235 184
236 $config = Config::parse($infoFile, '', $tmpName); 185 $config = Config::parse($infoFile, '', $tmpName);
237 $name = isset($config['name']) ? $config['name'] : ''; 186 $name = isset($config['name']) ? $config['name'] : '';
238 - if (!$name)  
239 - { 187 + if (!$name) {
240 throw new Exception(__('Addon info file data incorrect')); 188 throw new Exception(__('Addon info file data incorrect'));
241 } 189 }
242 190
243 $newAddonDir = ADDON_PATH . $name . DS; 191 $newAddonDir = ADDON_PATH . $name . DS;
244 - if (is_dir($newAddonDir))  
245 - { 192 + if (is_dir($newAddonDir)) {
246 throw new Exception(__('Addon already exists')); 193 throw new Exception(__('Addon already exists'));
247 } 194 }
248 195
249 //重命名插件文件夹 196 //重命名插件文件夹
250 rename($tmpAddonDir, $newAddonDir); 197 rename($tmpAddonDir, $newAddonDir);
251 - try  
252 - { 198 + try {
253 //默认禁用该插件 199 //默认禁用该插件
254 $info = get_addon_info($name); 200 $info = get_addon_info($name);
255 - if ($info['state'])  
256 - { 201 + if ($info['state']) {
257 $info['state'] = 0; 202 $info['state'] = 0;
258 set_addon_info($name, $info); 203 set_addon_info($name, $info);
259 } 204 }
260 205
261 //执行插件的安装方法 206 //执行插件的安装方法
262 $class = get_addon_class($name); 207 $class = get_addon_class($name);
263 - if (class_exists($class))  
264 - { 208 + if (class_exists($class)) {
265 $addon = new $class(); 209 $addon = new $class();
266 $addon->install(); 210 $addon->install();
267 } 211 }
@@ -271,22 +215,16 @@ class Addon extends Backend @@ -271,22 +215,16 @@ class Addon extends Backend
271 215
272 $info['config'] = get_addon_config($name) ? 1 : 0; 216 $info['config'] = get_addon_config($name) ? 1 : 0;
273 $this->success(__('Offline installed tips'), null, ['addon' => $info]); 217 $this->success(__('Offline installed tips'), null, ['addon' => $info]);
274 - }  
275 - catch (Exception $e)  
276 - { 218 + } catch (Exception $e) {
277 @rmdirs($newAddonDir); 219 @rmdirs($newAddonDir);
278 throw new Exception($e->getMessage()); 220 throw new Exception($e->getMessage());
279 } 221 }
280 - }  
281 - catch (Exception $e)  
282 - { 222 + } catch (Exception $e) {
283 @unlink($tmpFile); 223 @unlink($tmpFile);
284 @rmdirs($tmpAddonDir); 224 @rmdirs($tmpAddonDir);
285 $this->error($e->getMessage()); 225 $this->error($e->getMessage());
286 } 226 }
287 - }  
288 - else  
289 - { 227 + } else {
290 // 上传失败获取错误信息 228 // 上传失败获取错误信息
291 $this->error($file->getError()); 229 $this->error($file->getError());
292 } 230 }
@@ -298,12 +236,10 @@ class Addon extends Backend @@ -298,12 +236,10 @@ class Addon extends Backend
298 public function upgrade() 236 public function upgrade()
299 { 237 {
300 $name = $this->request->post("name"); 238 $name = $this->request->post("name");
301 - if (!$name)  
302 - { 239 + if (!$name) {
303 $this->error(__('Parameter %s can not be empty', 'name')); 240 $this->error(__('Parameter %s can not be empty', 'name'));
304 } 241 }
305 - try  
306 - { 242 + try {
307 $uid = $this->request->post("uid"); 243 $uid = $this->request->post("uid");
308 $token = $this->request->post("token"); 244 $token = $this->request->post("token");
309 $version = $this->request->post("version"); 245 $version = $this->request->post("version");
@@ -318,29 +254,9 @@ class Addon extends Backend @@ -318,29 +254,9 @@ class Addon extends Backend
318 Service::upgrade($name, $extend); 254 Service::upgrade($name, $extend);
319 Cache::rm('__menu__'); 255 Cache::rm('__menu__');
320 $this->success(__('Operate successful')); 256 $this->success(__('Operate successful'));
321 - }  
322 - catch (AddonException $e)  
323 - { 257 + } catch (AddonException $e) {
324 $this->result($e->getData(), $e->getCode(), $e->getMessage()); 258 $this->result($e->getData(), $e->getCode(), $e->getMessage());
325 - }  
326 - catch (Exception $e)  
327 - {  
328 - $this->error($e->getMessage());  
329 - }  
330 - }  
331 -  
332 - /**  
333 - * 刷新缓存  
334 - */  
335 - public function refresh()  
336 - {  
337 - try  
338 - {  
339 - Service::refresh();  
340 - $this->success(__('Operate successful'));  
341 - }  
342 - catch (Exception $e)  
343 - { 259 + } catch (Exception $e) {
344 $this->error($e->getMessage()); 260 $this->error($e->getMessage());
345 } 261 }
346 } 262 }
@@ -350,31 +266,51 @@ class Addon extends Backend @@ -350,31 +266,51 @@ class Addon extends Backend
350 */ 266 */
351 public function downloaded() 267 public function downloaded()
352 { 268 {
353 - $offset = (int) $this->request->get("offset");  
354 - $limit = (int) $this->request->get("limit"); 269 + $offset = (int)$this->request->get("offset");
  270 + $limit = (int)$this->request->get("limit");
  271 + $filter = $this->request->get("filter");
355 $search = $this->request->get("search"); 272 $search = $this->request->get("search");
356 $search = htmlspecialchars(strip_tags($search)); 273 $search = htmlspecialchars(strip_tags($search));
357 - 274 + $onlineaddons = Cache::get("onlineaddons");
  275 + if (!is_array($onlineaddons)) {
  276 + $onlineaddons = [];
  277 + $result = Http::sendRequest(config('fastadmin.api_url') . '/addon/index');
  278 + if ($result['ret']) {
  279 + $json = json_decode($result['msg'], TRUE);
  280 + $rows = isset($json['rows']) ? $json['rows'] : [];
  281 + foreach ($rows as $index => $row) {
  282 + $onlineaddons[$row['name']] = $row;
  283 + }
  284 + }
  285 + Cache::set("onlineaddons", $onlineaddons, 600);
  286 + }
  287 + $filter = (array)json_decode($filter, true);
358 $addons = get_addon_list(); 288 $addons = get_addon_list();
359 $list = []; 289 $list = [];
360 - foreach ($addons as $k => $v)  
361 - { 290 + foreach ($addons as $k => $v) {
362 if ($search && stripos($v['name'], $search) === FALSE && stripos($v['intro'], $search) === FALSE) 291 if ($search && stripos($v['name'], $search) === FALSE && stripos($v['intro'], $search) === FALSE)
363 continue; 292 continue;
364 293
365 - $v['flag'] = '';  
366 - $v['banner'] = '';  
367 - $v['image'] = '';  
368 - $v['donateimage'] = '';  
369 - $v['demourl'] = '';  
370 - $v['price'] = '0.00'; 294 + if (isset($onlineaddons[$v['name']])) {
  295 + $v = array_merge($onlineaddons[$v['name']], $v);
  296 + } else {
  297 + $v['category_id'] = 0;
  298 + $v['flag'] = '';
  299 + $v['banner'] = '';
  300 + $v['image'] = '';
  301 + $v['donateimage'] = '';
  302 + $v['demourl'] = '';
  303 + $v['price'] = '0.00';
  304 + }
371 $v['url'] = addon_url($v['name']); 305 $v['url'] = addon_url($v['name']);
372 $v['createtime'] = filemtime(ADDON_PATH . $v['name']); 306 $v['createtime'] = filemtime(ADDON_PATH . $v['name']);
  307 + if ($filter && isset($filter['category_id']) && is_numeric($filter['category_id']) && $filter['category_id'] != $v['category_id']) {
  308 + continue;
  309 + }
373 $list[] = $v; 310 $list[] = $v;
374 } 311 }
375 $total = count($list); 312 $total = count($list);
376 - if ($limit)  
377 - { 313 + if ($limit) {
378 $list = array_slice($list, $offset, $limit); 314 $list = array_slice($list, $offset, $limit);
379 } 315 }
380 $result = array("total" => $total, "rows" => $list); 316 $result = array("total" => $total, "rows" => $list);
@@ -4,6 +4,7 @@ namespace app\admin\controller; @@ -4,6 +4,7 @@ namespace app\admin\controller;
4 4
5 use app\common\controller\Backend; 5 use app\common\controller\Backend;
6 use fast\Random; 6 use fast\Random;
  7 +use think\addons\Service;
7 use think\Cache; 8 use think\Cache;
8 use think\Config; 9 use think\Config;
9 use think\Db; 10 use think\Db;
@@ -47,8 +48,7 @@ class Ajax extends Backend @@ -47,8 +48,7 @@ class Ajax extends Backend
47 { 48 {
48 Config::set('default_return_type', 'json'); 49 Config::set('default_return_type', 'json');
49 $file = $this->request->file('file'); 50 $file = $this->request->file('file');
50 - if (empty($file))  
51 - { 51 + if (empty($file)) {
52 $this->error(__('No file upload or server upload limit exceeded')); 52 $this->error(__('No file upload or server upload limit exceeded'));
53 } 53 }
54 54
@@ -60,7 +60,7 @@ class Ajax extends Backend @@ -60,7 +60,7 @@ class Ajax extends Backend
60 preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches); 60 preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
61 $type = strtolower($matches[2]); 61 $type = strtolower($matches[2]);
62 $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; 62 $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
63 - $size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); 63 + $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
64 $fileInfo = $file->getInfo(); 64 $fileInfo = $file->getInfo();
65 $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); 65 $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
66 $suffix = $suffix ? $suffix : 'file'; 66 $suffix = $suffix ? $suffix : 'file';
@@ -68,8 +68,7 @@ class Ajax extends Backend @@ -68,8 +68,7 @@ class Ajax extends Backend
68 $mimetypeArr = explode(',', $upload['mimetype']); 68 $mimetypeArr = explode(',', $upload['mimetype']);
69 $typeArr = explode('/', $fileInfo['type']); 69 $typeArr = explode('/', $fileInfo['type']);
70 //验证文件后缀 70 //验证文件后缀
71 - if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))  
72 - { 71 + if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)) {
73 $this->error(__('Uploaded file format is limited')); 72 $this->error(__('Uploaded file format is limited'));
74 } 73 }
75 $replaceArr = [ 74 $replaceArr = [
@@ -93,11 +92,9 @@ class Ajax extends Backend @@ -93,11 +92,9 @@ class Ajax extends Backend
93 $fileName = substr($savekey, strripos($savekey, '/') + 1); 92 $fileName = substr($savekey, strripos($savekey, '/') + 1);
94 // 93 //
95 $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName); 94 $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
96 - if ($splInfo)  
97 - { 95 + if ($splInfo) {
98 $imagewidth = $imageheight = 0; 96 $imagewidth = $imageheight = 0;
99 - if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']))  
100 - { 97 + if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
101 $imgInfo = getimagesize($splInfo->getPathname()); 98 $imgInfo = getimagesize($splInfo->getPathname());
102 $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth; 99 $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
103 $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; 100 $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
@@ -121,9 +118,7 @@ class Ajax extends Backend @@ -121,9 +118,7 @@ class Ajax extends Backend
121 $this->success(__('Upload successful'), null, [ 118 $this->success(__('Upload successful'), null, [
122 'url' => $uploadDir . $splInfo->getSaveName() 119 'url' => $uploadDir . $splInfo->getSaveName()
123 ]); 120 ]);
124 - }  
125 - else  
126 - { 121 + } else {
127 // 上传失败获取错误信息 122 // 上传失败获取错误信息
128 $this->error($file->getError()); 123 $this->error($file->getError());
129 } 124 }
@@ -153,12 +148,10 @@ class Ajax extends Backend @@ -153,12 +148,10 @@ class Ajax extends Backend
153 $field = in_array($field, ['weigh']) ? $field : 'weigh'; 148 $field = in_array($field, ['weigh']) ? $field : 'weigh';
154 149
155 // 如果设定了pid的值,此时只匹配满足条件的ID,其它忽略 150 // 如果设定了pid的值,此时只匹配满足条件的ID,其它忽略
156 - if ($pid !== '')  
157 - { 151 + if ($pid !== '') {
158 $hasids = []; 152 $hasids = [];
159 $list = Db::name($table)->where($prikey, 'in', $ids)->where('pid', 'in', $pid)->field('id,pid')->select(); 153 $list = Db::name($table)->where($prikey, 'in', $ids)->where('pid', 'in', $pid)->field('id,pid')->select();
160 - foreach ($list as $k => $v)  
161 - { 154 + foreach ($list as $k => $v) {
162 $hasids[] = $v['id']; 155 $hasids[] = $v['id'];
163 } 156 }
164 $ids = array_values(array_intersect($ids, $hasids)); 157 $ids = array_values(array_intersect($ids, $hasids));
@@ -166,20 +159,15 @@ class Ajax extends Backend @@ -166,20 +159,15 @@ class Ajax extends Backend
166 159
167 //直接修复排序 160 //直接修复排序
168 $one = Db::name($table)->field("{$field},COUNT(*) AS nums")->group($field)->having('nums > 1')->find(); 161 $one = Db::name($table)->field("{$field},COUNT(*) AS nums")->group($field)->having('nums > 1')->find();
169 - if ($one)  
170 - { 162 + if ($one) {
171 $list = Db::name($table)->field("$prikey,$field")->order($field, $orderway)->select(); 163 $list = Db::name($table)->field("$prikey,$field")->order($field, $orderway)->select();
172 - foreach ($list as $k => $v)  
173 - { 164 + foreach ($list as $k => $v) {
174 Db::name($table)->where($prikey, $v[$prikey])->update([$field => $k + 1]); 165 Db::name($table)->where($prikey, $v[$prikey])->update([$field => $k + 1]);
175 } 166 }
176 $this->success(); 167 $this->success();
177 - }  
178 - else  
179 - { 168 + } else {
180 $list = Db::name($table)->field("$prikey,$field")->where($prikey, 'in', $ids)->order($field, $orderway)->select(); 169 $list = Db::name($table)->field("$prikey,$field")->where($prikey, 'in', $ids)->order($field, $orderway)->select();
181 - foreach ($list as $k => $v)  
182 - { 170 + foreach ($list as $k => $v) {
183 $sour[] = $v[$prikey]; 171 $sour[] = $v[$prikey];
184 $weighdata[$v[$prikey]] = $v[$field]; 172 $weighdata[$v[$prikey]] = $v[$field];
185 } 173 }
@@ -192,20 +180,13 @@ class Ajax extends Backend @@ -192,20 +180,13 @@ class Ajax extends Backend
192 //echo "替换的ID:{$desc_id}\n"; 180 //echo "替换的ID:{$desc_id}\n";
193 $weighids = array(); 181 $weighids = array();
194 $temp = array_values(array_diff_assoc($ids, $sour)); 182 $temp = array_values(array_diff_assoc($ids, $sour));
195 - foreach ($temp as $m => $n)  
196 - {  
197 - if ($n == $sour_id)  
198 - { 183 + foreach ($temp as $m => $n) {
  184 + if ($n == $sour_id) {
199 $offset = $desc_id; 185 $offset = $desc_id;
200 - }  
201 - else  
202 - {  
203 - if ($sour_id == $temp[0])  
204 - { 186 + } else {
  187 + if ($sour_id == $temp[0]) {
205 $offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id; 188 $offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id;
206 - }  
207 - else  
208 - { 189 + } else {
209 $offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id; 190 $offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id;
210 } 191 }
211 } 192 }
@@ -221,15 +202,23 @@ class Ajax extends Backend @@ -221,15 +202,23 @@ class Ajax extends Backend
221 */ 202 */
222 public function wipecache() 203 public function wipecache()
223 { 204 {
224 - $wipe_cache_type = ['TEMP_PATH', 'LOG_PATH', 'CACHE_PATH'];  
225 - foreach ($wipe_cache_type as $item)  
226 - {  
227 - $dir = constant($item);  
228 - if (!is_dir($dir))  
229 - continue;  
230 - rmdirs($dir); 205 + $type = $this->request->request("type");
  206 + switch ($type) {
  207 + case 'content' || 'all':
  208 + rmdirs(CACHE_PATH, false);
  209 + Cache::clear();
  210 + if ($type == 'content')
  211 + break;
  212 + case 'template' || 'all':
  213 + rmdirs(TEMP_PATH, false);
  214 + if ($type == 'template')
  215 + break;
  216 + case 'addons' || 'all':
  217 + Service::refresh();
  218 + if ($type == 'addons')
  219 + break;
231 } 220 }
232 - Cache::clear(); 221 +
233 \think\Hook::listen("wipecache_after"); 222 \think\Hook::listen("wipecache_after");
234 $this->success(); 223 $this->success();
235 } 224 }
@@ -243,14 +232,11 @@ class Ajax extends Backend @@ -243,14 +232,11 @@ class Ajax extends Backend
243 $pid = $this->request->get('pid'); 232 $pid = $this->request->get('pid');
244 $where = ['status' => 'normal']; 233 $where = ['status' => 'normal'];
245 $categorylist = null; 234 $categorylist = null;
246 - if ($pid !== '')  
247 - {  
248 - if ($type)  
249 - { 235 + if ($pid !== '') {
  236 + if ($type) {
250 $where['type'] = $type; 237 $where['type'] = $type;
251 } 238 }
252 - if ($pid)  
253 - { 239 + if ($pid) {
254 $where['pid'] = $pid; 240 $where['pid'] = $pid;
255 } 241 }
256 242
@@ -268,17 +254,13 @@ class Ajax extends Backend @@ -268,17 +254,13 @@ class Ajax extends Backend
268 $city = $this->request->get('city'); 254 $city = $this->request->get('city');
269 $where = ['pid' => 0, 'level' => 1]; 255 $where = ['pid' => 0, 'level' => 1];
270 $provincelist = null; 256 $provincelist = null;
271 - if ($province !== '')  
272 - {  
273 - if ($province)  
274 - { 257 + if ($province !== '') {
  258 + if ($province) {
275 $where['pid'] = $province; 259 $where['pid'] = $province;
276 $where['level'] = 2; 260 $where['level'] = 2;
277 } 261 }
278 - if ($city !== '')  
279 - {  
280 - if ($city)  
281 - { 262 + if ($city !== '') {
  263 + if ($city) {
282 $where['pid'] = $city; 264 $where['pid'] = $city;
283 $where['level'] = 3; 265 $where['level'] = 3;
284 } 266 }
@@ -30,6 +30,8 @@ return [ @@ -30,6 +30,8 @@ return [
30 'Please disable addon first' => '请先禁用插件再进行升级', 30 'Please disable addon first' => '请先禁用插件再进行升级',
31 'Login now' => '立即登录', 31 'Login now' => '立即登录',
32 'Continue install' => '不登录,继续安装', 32 'Continue install' => '不登录,继续安装',
  33 + 'All' => '全部',
  34 + 'Uncategoried' => '未归类',
33 'Recommend' => '推荐', 35 'Recommend' => '推荐',
34 'Hot' => '热门', 36 'Hot' => '热门',
35 'New' => '新', 37 'New' => '新',
@@ -33,6 +33,10 @@ return [ @@ -33,6 +33,10 @@ return [
33 'Wipe cache completed' => '清除缓存成功', 33 'Wipe cache completed' => '清除缓存成功',
34 'Wipe cache failed' => '清除缓存失败', 34 'Wipe cache failed' => '清除缓存失败',
35 'Wipe cache' => '清空缓存', 35 'Wipe cache' => '清空缓存',
  36 + 'Wipe all cache' => '一键清除缓存',
  37 + 'Wipe content cache' => '清空内容缓存',
  38 + 'Wipe template cache' => '清除模板缓存',
  39 + 'Wipe addons cache' => '清除插件缓存',
36 'Check for updates' => '检测更新', 40 'Check for updates' => '检测更新',
37 'Latest news' => '最新消息', 41 'Latest news' => '最新消息',
38 'View more' => '查看更多', 42 'View more' => '查看更多',
@@ -30,7 +30,7 @@ class Auth extends \fast\Auth @@ -30,7 +30,7 @@ class Auth extends \fast\Auth
30 30
31 /** 31 /**
32 * 管理员登录 32 * 管理员登录
33 - * 33 + *
34 * @param string $username 用户名 34 * @param string $username 用户名
35 * @param string $password 密码 35 * @param string $password 密码
36 * @param int $keeptime 有效时长 36 * @param int $keeptime 有效时长
@@ -44,7 +44,7 @@ class Auth extends \fast\Auth @@ -44,7 +44,7 @@ class Auth extends \fast\Auth
44 $this->setError('Username is incorrect'); 44 $this->setError('Username is incorrect');
45 return false; 45 return false;
46 } 46 }
47 - if ($admin->loginfailure >= 3 && time() - $admin->updatetime < 86400) 47 + if (Config::get('fastadmin.login_failure_retry') && $admin->loginfailure >= 10 && time() - $admin->updatetime < 86400)
48 { 48 {
49 $this->setError('Please try again after 1 day'); 49 $this->setError('Please try again after 1 day');
50 return false; 50 return false;
@@ -119,7 +119,7 @@ class Auth extends \fast\Auth @@ -119,7 +119,7 @@ class Auth extends \fast\Auth
119 119
120 /** 120 /**
121 * 刷新保持登录的Cookie 121 * 刷新保持登录的Cookie
122 - * 122 + *
123 * @param int $keeptime 123 * @param int $keeptime
124 * @return boolean 124 * @return boolean
125 */ 125 */
@@ -155,6 +155,7 @@ class Auth extends \fast\Auth @@ -155,6 +155,7 @@ class Auth extends \fast\Auth
155 return FALSE; 155 return FALSE;
156 } 156 }
157 157
  158 + $arr = array_map('strtolower', $arr);
158 // 是否存在 159 // 是否存在
159 if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) 160 if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
160 { 161 {
@@ -21,20 +21,13 @@ @@ -21,20 +21,13 @@
21 <textarea name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}" {$item.extend}>{$item.value}</textarea> 21 <textarea name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}" {$item.extend}>{$item.value}</textarea>
22 {/case} 22 {/case}
23 {case array} 23 {case array}
24 - <dl class="fieldlist" rel="{$item.value|count}" data-name="row[{$item.name}]"> 24 + <dl class="fieldlist" data-name="row[{$item.name}]">
25 <dd> 25 <dd>
26 <ins>{:__('Array key')}</ins> 26 <ins>{:__('Array key')}</ins>
27 <ins>{:__('Array value')}</ins> 27 <ins>{:__('Array value')}</ins>
28 </dd> 28 </dd>
29 - {foreach $item.value as $key => $vo}  
30 - <dd class="form-inline">  
31 - <input type="text" name="row[{$item.name}][field][{$key}]" class="form-control" value="{$key}" size="10" />  
32 - <input type="text" name="row[{$item.name}][value][{$key}]" class="form-control" value="{$vo}" size="30" />  
33 - <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>  
34 - <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>  
35 - </dd>  
36 - {/foreach}  
37 - <dd><a href="javascript:;" class="append btn btn-sm btn-success"><i class="fa fa-plus"></i> {:__('Append')}</a></dd> 29 + <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
  30 + <textarea name="row[{$item.name}]" cols="30" rows="5" class="hide">{$item.value|json_encode}</textarea>
38 </dl> 31 </dl>
39 {/case} 32 {/case}
40 {case datetime} 33 {case datetime}
1 <style type="text/css"> 1 <style type="text/css">
2 .noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;} 2 .noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;}
3 .noimage > div {position: absolute;top:48%;width:100%;text-align:center;} 3 .noimage > div {position: absolute;top:48%;width:100%;text-align:center;}
4 - .addon {position: relative;} 4 + .addon {position: relative;border-color:#e4e4e4;}
5 .addon > span {position:absolute;left:15px;top:15px;z-index:9;} 5 .addon > span {position:absolute;left:15px;top:15px;z-index:9;}
6 .addon > span a{opacity: 0.5;border:none;color:#fff;} 6 .addon > span a{opacity: 0.5;border:none;color:#fff;}
7 .layui-layer-pay .layui-layer-content {padding:0;height:600px!important;} 7 .layui-layer-pay .layui-layer-content {padding:0;height:600px!important;}
@@ -16,9 +16,34 @@ @@ -16,9 +16,34 @@
16 .status-disabled .noimage { 16 .status-disabled .noimage {
17 background:#d2d6de; 17 background:#d2d6de;
18 } 18 }
  19 + @media (min-width: 992px) {
  20 + .addon {
  21 + -webkit-transition:all 0.3s ease;
  22 + -moz-transition: all 0.3s ease;
  23 + -o-transition: all 0.3s ease;
  24 + transition: all 0.3s ease;
  25 + }
  26 + .addon:hover {
  27 + border-color: #dddddd;
  28 + -webkit-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
  29 + -moz-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
  30 + box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
  31 + -webkit-transition: all 0.3s ease;
  32 + -moz-transition: all 0.3s ease;
  33 + -o-transition: all 0.3s ease;
  34 + transition: all 0.3s ease;
  35 + }
  36 + }
19 </style> 37 </style>
20 <div class="panel panel-default panel-intro"> 38 <div class="panel panel-default panel-intro">
21 - {:build_heading()} 39 + <div class="panel-heading">
  40 + {:build_heading(null,FALSE)}
  41 + <ul class="nav nav-tabs nav-category">
  42 + <li class="active"><a href="javascript:;" data-id="">{:__('All')}</a></li>
  43 + <li><a href="javascript:;" data-id="0">{:__('Uncategoried')}</a></li>
  44 + </ul>
  45 +
  46 + </div>
22 47
23 <div class="panel-body"> 48 <div class="panel-body">
24 <div id="myTabContent" class="tab-content"> 49 <div id="myTabContent" class="tab-content">
@@ -27,10 +52,11 @@ @@ -27,10 +52,11 @@
27 <div id="toolbar" class="toolbar"> 52 <div id="toolbar" class="toolbar">
28 {:build_toolbar('refresh')} 53 {:build_toolbar('refresh')}
29 <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> 54 <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>
30 - <a class="btn btn-success btn-ajax" href="addon/refresh"><i class="fa fa-refresh"></i> {:__('Refresh addon cache')}</a>  
31 <div class="btn-group"> 55 <div class="btn-group">
32 - <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>  
33 - <a href="#" class="btn btn-info btn-switch" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a> 56 + <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>
  57 + <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>
  58 + <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>
  59 + <a href="#" class="btn btn-info btn-switch" data-type="local" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a>
34 </div> 60 </div>
35 <a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a> 61 <a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a>
36 </div> 62 </div>
@@ -44,6 +70,55 @@ @@ -44,6 +70,55 @@
44 </div> 70 </div>
45 </div> 71 </div>
46 </div> 72 </div>
  73 +<script id="searchformtpl" type="text/html">
  74 + <form action="" class="form-commonsearch hide">
  75 + <div class="well" style="box-shadow:none;border-radius:2px;margin-bottom:10px;">
  76 + <div class="row">
  77 + <div class="col-xs-12 col-sm-6 col-md-3">
  78 + <div class="form-group">
  79 + <label class="control-label">标题</label>
  80 + <input class="operate" type="hidden" data-name="title" value="like"/>
  81 + <input class="form-control" type="text" name="title" placeholder="请输入查找的标题" value=""/>
  82 + </div>
  83 + </div>
  84 + <div class="col-xs-12 col-sm-6 col-md-3">
  85 + <div class="form-group">
  86 + <label class="control-label">类型</label>
  87 + <input class="operate" type="hidden" data-name="type" value="="/>
  88 + <input class="form-control" type="text" name="type" placeholder="all" value=""/>
  89 + </div>
  90 + </div>
  91 + <div class="col-xs-12 col-sm-6 col-md-3">
  92 + <div class="form-group">
  93 + <label class="control-label">分类</label>
  94 + <input type="hidden" class="operate" data-name="category_id" value="="/>
  95 + <input class="form-control" name="category_id" type="text" value="">
  96 + </div>
  97 + </div>
  98 + <div class="col-xs-12 col-sm-6 col-md-3">
  99 + <div class="form-group">
  100 + <label class="control-label">版本号</label>
  101 + <input type="hidden" class="operate" data-name="faversion" value="="/>
  102 + <input class="form-control" name="faversion" type="text" value="{$config.fastadmin.version}">
  103 + </div>
  104 + </div>
  105 + <div class="col-xs-12 col-sm-6 col-md-3">
  106 + <div class="form-group">
  107 + <label class="control-label"></label>
  108 + <div class="row">
  109 + <div class="col-xs-6">
  110 + <input type="submit" class="btn btn-success btn-block" value="提交"/>
  111 + </div>
  112 + <div class="col-xs-6">
  113 + <input type="reset" class="btn btn-primary btn-block" value="重置"/>
  114 + </div>
  115 + </div>
  116 + </div>
  117 + </div>
  118 + </div>
  119 + </div>
  120 + </form>
  121 +</script>
47 <script id="logintpl" type="text/html"> 122 <script id="logintpl" type="text/html">
48 <div> 123 <div>
49 <form class="form-horizontal"> 124 <form class="form-horizontal">
@@ -180,7 +255,7 @@ @@ -180,7 +255,7 @@
180 <%}%> 255 <%}%>
181 </a> 256 </a>
182 <div class="caption"> 257 <div class="caption">
183 - <h4><%=item.title?item.title:'{:__('None')}'%> 258 + <h4><%=item.title?item.title:'{:__('None')}'%>
184 <% if(item.flag.indexOf("recommend")>-1){%> 259 <% if(item.flag.indexOf("recommend")>-1){%>
185 <span class="label label-success">{:__('Recommend')}</span> 260 <span class="label label-success">{:__('Recommend')}</span>
186 <% } %> 261 <% } %>
@@ -203,7 +278,7 @@ @@ -203,7 +278,7 @@
203 <% if(!addon){ %> 278 <% if(!addon){ %>
204 <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%> 279 <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
205 <span class="btn-group"> 280 <span class="btn-group">
206 - <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> 281 + <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>
207 <a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;"> 282 <a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
208 <span class="fa fa-caret-down"></span> 283 <span class="fa fa-caret-down"></span>
209 </a> 284 </a>
@@ -214,10 +289,10 @@ @@ -214,10 +289,10 @@
214 </ul> 289 </ul>
215 </span> 290 </span>
216 <% }else{%> 291 <% }else{%>
217 - <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> 292 + <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>
218 <% } %> 293 <% } %>
219 <% if(item.demourl){ %> 294 <% if(item.demourl){ %>
220 - <a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a> 295 + <a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a>
221 <% } %> 296 <% } %>
222 <% } %> 297 <% } %>
223 298
@@ -235,7 +310,7 @@ @@ -235,7 +310,7 @@
235 <% if(addon && item && addon.version!=item.version){%> 310 <% if(addon && item && addon.version!=item.version){%>
236 <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%> 311 <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
237 <span class="btn-group"> 312 <span class="btn-group">
238 - <a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a> 313 + <a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
239 <a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="javascript:;"> 314 <a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="javascript:;">
240 <span class="fa fa-caret-down"></span> 315 <span class="fa fa-caret-down"></span>
241 </a> 316 </a>
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 <a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i></a> 25 <a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i></a>
26 </li> 26 </li>
27 27
28 - <li class="dropdown notifications-menu"> 28 + <li class="dropdown notifications-menu hidden-xs">
29 <a href="#" class="dropdown-toggle" data-toggle="dropdown"> 29 <a href="#" class="dropdown-toggle" data-toggle="dropdown">
30 <i class="fa fa-bell-o"></i> 30 <i class="fa fa-bell-o"></i>
31 <span class="label label-warning"></span> 31 <span class="label label-warning"></span>
@@ -41,19 +41,26 @@ @@ -41,19 +41,26 @@
41 <li class="footer"><a href="#" target="_blank">{:__('View more')}</a></li> 41 <li class="footer"><a href="#" target="_blank">{:__('View more')}</a></li>
42 </ul> 42 </ul>
43 </li> 43 </li>
44 -  
45 - <li> 44 +
  45 + <li class="hidden-xs">
46 <a href="javascript:;" data-toggle="checkupdate" title="{:__('Check for updates')}"> 46 <a href="javascript:;" data-toggle="checkupdate" title="{:__('Check for updates')}">
47 <i class="fa fa-refresh"></i> 47 <i class="fa fa-refresh"></i>
48 </a> 48 </a>
49 </li> 49 </li>
50 - 50 +
51 <li> 51 <li>
52 - <a href="javascript:;" data-toggle="wipecache" title="{:__('Wipe cache')}"> 52 + <a href="javascript:;" data-toggle="dropdown" title="{:__('Wipe cache')}">
53 <i class="fa fa-trash"></i> 53 <i class="fa fa-trash"></i>
54 </a> 54 </a>
  55 + <ul class="dropdown-menu wipecache">
  56 + <li><a href="javascript:;" data-type="all"><i class="fa fa-trash"></i> {:__('Wipe all cache')}</a></li>
  57 + <li><a href="javascript:;" data-type="content"><i class="fa fa-file-text"></i> {:__('Wipe content cache')}</a></li>
  58 + <li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o"></i> {:__('Wipe template cache')}</a></li>
  59 + <li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket"></i> {:__('Wipe addons cache')}</a></li>
  60 + </ul>
55 </li> 61 </li>
56 62
  63 + {if $Think.config.lang_switch_on}
57 <li class="hidden-xs"> 64 <li class="hidden-xs">
58 <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-language"></i></a> 65 <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-language"></i></a>
59 <ul class="dropdown-menu"> 66 <ul class="dropdown-menu">
@@ -65,6 +72,7 @@ @@ -65,6 +72,7 @@
65 </li> 72 </li>
66 </ul> 73 </ul>
67 </li> 74 </li>
  75 + {/if}
68 76
69 <li class="hidden-xs"> 77 <li class="hidden-xs">
70 <a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a> 78 <a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a>
@@ -103,16 +111,18 @@ @@ -103,16 +111,18 @@
103 <!-- Menu Footer--> 111 <!-- Menu Footer-->
104 <li class="user-footer"> 112 <li class="user-footer">
105 <div class="pull-left"> 113 <div class="pull-left">
106 - <a href="general/profile" class="btn btn-primary addtabsit"><i class="fa fa-user"></i> {:__('Profile')}</a> 114 + <a href="general/profile" class="btn btn-primary addtabsit"><i class="fa fa-user"></i>
  115 + {:__('Profile')}</a>
107 </div> 116 </div>
108 <div class="pull-right"> 117 <div class="pull-right">
109 - <a href="{:url('index/logout')}" class="btn btn-danger"><i class="fa fa-sign-out"></i> {:__('Logout')}</a> 118 + <a href="{:url('index/logout')}" class="btn btn-danger"><i class="fa fa-sign-out"></i>
  119 + {:__('Logout')}</a>
110 </div> 120 </div>
111 </li> 121 </li>
112 </ul> 122 </ul>
113 </li> 123 </li>
114 <!-- 控制栏切换按钮 --> 124 <!-- 控制栏切换按钮 -->
115 - <li> 125 + <li class="hidden-xs">
116 <a href="javascript:;" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a> 126 <a href="javascript:;" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
117 </li> 127 </li>
118 </ul> 128 </ul>
@@ -80,7 +80,7 @@ @@ -80,7 +80,7 @@
80 <div class="input-group"> 80 <div class="input-group">
81 <div class="input-group-addon"><span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span></div> 81 <div class="input-group-addon"><span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span></div>
82 <input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="{:__('Captcha')}:required;length(4)" /> 82 <input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="{:__('Captcha')}:required;length(4)" />
83 - <span class="input-group-addon" style="padding:0;border:none;"> 83 + <span class="input-group-addon" style="padding:0;border:none;cursor:pointer;">
84 <img src="{:captcha_src()}" width="100" height="30" onclick="this.src = '{:captcha_src()}?r=' + Math.random();"/> 84 <img src="{:captcha_src()}" width="100" height="30" onclick="this.src = '{:captcha_src()}?r=' + Math.random();"/>
85 </span> 85 </span>
86 </div> 86 </div>
@@ -97,7 +97,7 @@ @@ -97,7 +97,7 @@
97 </form> 97 </form>
98 </div> 98 </div>
99 </div> 99 </div>
100 - <p class="copyright"><a href="https://www.fastadmin.net?ref=demo">Powered By FastAdmin</a></p> 100 + <p class="copyright"><a href="https://www.fastadmin.net">Powered By FastAdmin</a></p>
101 </div> 101 </div>
102 </div> 102 </div>
103 </div> 103 </div>
@@ -279,6 +279,7 @@ class Backend extends Controller @@ -279,6 +279,7 @@ class Backend extends Controller
279 { 279 {
280 $k = $tableName . $k; 280 $k = $tableName . $k;
281 } 281 }
  282 + $v = !is_array($v) ? trim($v) : $v;
282 $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym); 283 $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
283 switch ($sym) 284 switch ($sym)
284 { 285 {
@@ -306,7 +307,7 @@ class Backend extends Controller @@ -306,7 +307,7 @@ class Backend extends Controller
306 case 'IN(...)': 307 case 'IN(...)':
307 case 'NOT IN': 308 case 'NOT IN':
308 case 'NOT IN(...)': 309 case 'NOT IN(...)':
309 - $where[] = [$k, str_replace('(...)', '', $sym), explode(',', $v)]; 310 + $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
310 break; 311 break;
311 case 'BETWEEN': 312 case 'BETWEEN':
312 case 'NOT BETWEEN': 313 case 'NOT BETWEEN':
@@ -382,6 +382,7 @@ class Auth @@ -382,6 +382,7 @@ class Auth
382 $rules[] = $v['name']; 382 $rules[] = $v['name'];
383 } 383 }
384 $url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path); 384 $url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path);
  385 + $url = strtolower(str_replace('.', '/', $url));
385 return in_array($url, $rules) ? TRUE : FALSE; 386 return in_array($url, $rules) ? TRUE : FALSE;
386 } 387 }
387 388
@@ -539,6 +540,7 @@ class Auth @@ -539,6 +540,7 @@ class Auth
539 { 540 {
540 return FALSE; 541 return FALSE;
541 } 542 }
  543 + $arr = array_map('strtolower', $arr);
542 // 是否存在 544 // 是否存在
543 if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) 545 if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
544 { 546 {
@@ -21,6 +21,13 @@ class Category Extends Model @@ -21,6 +21,13 @@ class Category Extends Model
21 'flag_text', 21 'flag_text',
22 ]; 22 ];
23 23
  24 + protected static function init()
  25 + {
  26 + self::afterInsert(function ($row) {
  27 + $row->save(['weigh' => $row['id']]);
  28 + });
  29 + }
  30 +
24 public function setFlagAttr($value, $data) 31 public function setFlagAttr($value, $data)
25 { 32 {
26 return is_array($value) ? implode(',', $value) : $value; 33 return is_array($value) ? implode(',', $value) : $value;
@@ -258,18 +258,20 @@ return [ @@ -258,18 +258,20 @@ return [
258 //FastAdmin配置 258 //FastAdmin配置
259 'fastadmin' => [ 259 'fastadmin' => [
260 //是否开启前台会员中心 260 //是否开启前台会员中心
261 - 'usercenter' => true, 261 + 'usercenter' => true,
262 //登录验证码 262 //登录验证码
263 - 'login_captcha' => false, 263 + 'login_captcha' => true,
  264 + //登录失败超过10则1天后重试
  265 + 'login_failure_retry' => true,
264 //是否同一账号同一时间只能在一个地方登录 266 //是否同一账号同一时间只能在一个地方登录
265 - 'login_unique' => false, 267 + 'login_unique' => false,
266 //登录页默认背景图 268 //登录页默认背景图
267 - 'login_background' => "/assets/img/loginbg.jpg", 269 + 'login_background' => "/assets/img/loginbg.jpg",
268 //自动检测更新 270 //自动检测更新
269 - 'checkupdate' => false, 271 + 'checkupdate' => false,
270 //版本号 272 //版本号
271 - 'version' => '1.0.0.20180401_beta', 273 + 'version' => '1.0.0.20180406_beta',
272 //API接口地址 274 //API接口地址
273 - 'api_url' => 'https://api.fastadmin.net', 275 + 'api_url' => 'https://api.fastadmin.net',
274 ], 276 ],
275 ]; 277 ];
@@ -9,7 +9,15 @@ @@ -9,7 +9,15 @@
9 <title>FastAdmin</title> 9 <title>FastAdmin</title>
10 <link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> 10 <link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
11 <style type="text/css"> 11 <style type="text/css">
12 - body { padding-top: 70px; margin-bottom: 15px; } 12 + body {
  13 + padding-top: 70px; margin-bottom: 15px;
  14 + -webkit-font-smoothing: antialiased;
  15 + -moz-osx-font-smoothing: grayscale;
  16 + 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;
  17 + font-weight: 400;
  18 + }
  19 + h2 { font-size: 1.6em; }
  20 + hr { margin-top: 10px; }
13 .tab-pane { padding-top: 10px; } 21 .tab-pane { padding-top: 10px; }
14 .mt0 { margin-top: 0px; } 22 .mt0 { margin-top: 0px; }
15 .footer { font-size: 12px; color: #666; } 23 .footer { font-size: 12px; color: #666; }
@@ -3351,7 +3359,7 @@ @@ -3351,7 +3359,7 @@
3351 3359
3352 <div class="row mt0 footer"> 3360 <div class="row mt0 footer">
3353 <div class="col-md-6" align="left"> 3361 <div class="col-md-6" align="left">
3354 - Generated on 2018-04-01 15:11:14 </div> 3362 + Generated on 2018-04-06 19:15:01 </div>
3355 <div class="col-md-6" align="right"> 3363 <div class="col-md-6" align="right">
3356 <a href="https://www.fastadmin.net" target="_blank">FastAdmin</a> 3364 <a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
3357 </div> 3365 </div>
@@ -807,4 +807,6 @@ form.form-horizontal .control-label { @@ -807,4 +807,6 @@ form.form-horizontal .control-label {
807 .checkbox > label > input { 807 .checkbox > label > input {
808 margin: 2px 0 0; 808 margin: 2px 0 0;
809 } 809 }
810 -/*# sourceMappingURL=backend.css.map */  
  810 +.wipecache li a {
  811 + color: #444444!important;
  812 +}
@@ -4,7 +4,10 @@ body { @@ -4,7 +4,10 @@ body {
4 width: 100%; 4 width: 100%;
5 } 5 }
6 body { 6 body {
7 - font-family: 'Muli', 'Helvetica', 'Arial', 'sans-serif'; 7 + -webkit-font-smoothing: antialiased;
  8 + -moz-osx-font-smoothing: grayscale;
  9 + 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;
  10 + font-weight: 400;
8 } 11 }
9 a { 12 a {
10 -webkit-transition: all 0.35s; 13 -webkit-transition: all 0.35s;
1 -define(['fast', 'moment'], function (Fast, Moment) { 1 +define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
2 var Backend = { 2 var Backend = {
3 api: { 3 api: {
4 sidebar: function (params) { 4 sidebar: function (params) {
@@ -8,13 +8,11 @@ define(['fast', 'moment'], function (Fast, Moment) { @@ -8,13 +8,11 @@ define(['fast', 'moment'], function (Fast, Moment) {
8 $.each(params, function (k, v) { 8 $.each(params, function (k, v) {
9 $url = Fast.api.fixurl(k); 9 $url = Fast.api.fixurl(k);
10 10
11 - if ($.isArray(v))  
12 - { 11 + if ($.isArray(v)) {
13 $nums = typeof v[0] !== 'undefined' ? v[0] : 0; 12 $nums = typeof v[0] !== 'undefined' ? v[0] : 0;
14 $color = typeof v[1] !== 'undefined' ? v[1] : colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums]; 13 $color = typeof v[1] !== 'undefined' ? v[1] : colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums];
15 $class = typeof v[2] !== 'undefined' ? v[2] : 'label'; 14 $class = typeof v[2] !== 'undefined' ? v[2] : 'label';
16 - } else  
17 - { 15 + } else {
18 $nums = v; 16 $nums = v;
19 $color = colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums]; 17 $color = colorArr[(!isNaN($nums) ? $nums : $nums.length) % $colorNums];
20 $class = 'label'; 18 $class = 'label';
@@ -58,7 +56,10 @@ define(['fast', 'moment'], function (Fast, Moment) { @@ -58,7 +56,10 @@ define(['fast', 'moment'], function (Fast, Moment) {
58 var id = Math.floor(new Date().valueOf() * Math.random()); 56 var id = Math.floor(new Date().valueOf() * Math.random());
59 icon = typeof icon !== 'undefined' ? icon : 'fa fa-circle-o'; 57 icon = typeof icon !== 'undefined' ? icon : 'fa fa-circle-o';
60 title = typeof title !== 'undefined' ? title : ''; 58 title = typeof title !== 'undefined' ? title : '';
61 - 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"); 59 + top.window.$("<a />").append('<i class="' + icon + '"></i> <span>' + title + '</span>').prop("href", url).attr({
  60 + url: url,
  61 + addtabs: id
  62 + }).addClass("hide").appendTo(top.window.document.body).trigger("click");
62 } 63 }
63 } 64 }
64 } 65 }
@@ -227,6 +228,8 @@ define(['fast', 'moment'], function (Fast, Moment) { @@ -227,6 +228,8 @@ define(['fast', 'moment'], function (Fast, Moment) {
227 } 228 }
228 }; 229 };
229 Backend.api = $.extend(Fast.api, Backend.api); 230 Backend.api = $.extend(Fast.api, Backend.api);
  231 + //将Template渲染至全局,以便于在子框架中调用
  232 + window.Template = Template;
230 //将Moment渲染至全局,以便于在子框架中调用 233 //将Moment渲染至全局,以便于在子框架中调用
231 window.Moment = Moment; 234 window.Moment = Moment;
232 //将Backend渲染至全局,以便于在子框架中调用 235 //将Backend渲染至全局,以便于在子框架中调用
@@ -14,6 +14,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function @@ -14,6 +14,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
14 14
15 var table = $("#table"); 15 var table = $("#table");
16 16
  17 + table.on('load-success.bs.table', function (e, json) {
  18 + if (json && typeof json.category != 'undefined' && $(".nav-category li").size() == 2) {
  19 + $.each(json.category, function (i, j) {
  20 + $("<li><a href='javascript:;' data-id='" + j.id + "'>" + j.name + "</a></li>").insertBefore($(".nav-category li:last"));
  21 + });
  22 + }
  23 + });
17 table.on('post-body.bs.table', function (e, settings, json, xhr) { 24 table.on('post-body.bs.table', function (e, settings, json, xhr) {
18 var parenttable = table.closest('.bootstrap-table'); 25 var parenttable = table.closest('.bootstrap-table');
19 var d = $(".fixed-table-toolbar", parenttable).find(".search input"); 26 var d = $(".fixed-table-toolbar", parenttable).find(".search input");
@@ -53,19 +60,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function @@ -53,19 +60,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
53 showColumns: false, 60 showColumns: false,
54 showToggle: false, 61 showToggle: false,
55 showExport: false, 62 showExport: false,
56 - commonSearch: false,  
57 - searchFormVisible: false, 63 + showSearch: false,
  64 + commonSearch: true,
  65 + searchFormVisible: true,
  66 + searchFormTemplate: 'searchformtpl',
58 pageSize: 12, 67 pageSize: 12,
59 pagination: false, 68 pagination: false,
60 - queryParams: function (params) {  
61 - var filter = params.filter ? JSON.parse(params.filter) : {};  
62 - var op = params.op ? JSON.parse(params.op) : {};  
63 - filter.faversion = Config.fastadmin.version;  
64 - op.faversion = "=";  
65 - params.filter = JSON.stringify(filter);  
66 - params.op = JSON.stringify(op);  
67 - return params;  
68 - }  
69 }); 69 });
70 70
71 // 为表格绑定事件 71 // 为表格绑定事件
@@ -124,14 +124,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function @@ -124,14 +124,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
124 return false; 124 return false;
125 } 125 }
126 }); 126 });
127 -  
128 - // 切换URL 127 +
  128 + // 切换
129 $(document).on("click", ".btn-switch", function () { 129 $(document).on("click", ".btn-switch", function () {
130 $(".btn-switch").removeClass("active"); 130 $(".btn-switch").removeClass("active");
131 $(this).addClass("active"); 131 $(this).addClass("active");
  132 + $("form.form-commonsearch input[name='type']").val($(this).data("type"));
132 table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1}); 133 table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1});
  134 + return false;
133 }); 135 });
134 - 136 + $(document).on("click", ".nav-category li a", function () {
  137 + $(".nav-category li").removeClass("active");
  138 + $(this).parent().addClass("active");
  139 + $("form.form-commonsearch input[name='category_id']").val($(this).data("id"));
  140 + table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1});
  141 + return false;
  142 + });
  143 +
135 // 会员信息 144 // 会员信息
136 $(document).on("click", ".btn-userinfo", function () { 145 $(document).on("click", ".btn-userinfo", function () {
137 var userinfo = Controller.api.userinfo.get(); 146 var userinfo = Controller.api.userinfo.get();
@@ -146,7 +155,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function @@ -146,7 +155,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
146 Fast.api.ajax({ 155 Fast.api.ajax({
147 url: Config.fastadmin.api_url + '/user/login', 156 url: Config.fastadmin.api_url + '/user/login',
148 dataType: 'jsonp', 157 dataType: 'jsonp',
149 - data: {account: $("#inputAccount", layero).val(), password: $("#inputPassword", layero).val(), _method: 'POST'} 158 + data: {
  159 + account: $("#inputAccount", layero).val(),
  160 + password: $("#inputPassword", layero).val(),
  161 + _method: 'POST'
  162 + }
150 }, function (data, ret) { 163 }, function (data, ret) {
151 Controller.api.userinfo.set(data); 164 Controller.api.userinfo.set(data);
152 Layer.closeAll(); 165 Layer.closeAll();
@@ -199,7 +212,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function @@ -199,7 +212,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
199 var token = userinfo ? userinfo.token : ''; 212 var token = userinfo ? userinfo.token : '';
200 Fast.api.ajax({ 213 Fast.api.ajax({
201 url: 'addon/install', 214 url: 'addon/install',
202 - data: {name: name, force: force ? 1 : 0, uid: uid, token: token, version: version, faversion: Config.fastadmin.version} 215 + data: {
  216 + name: name,
  217 + force: force ? 1 : 0,
  218 + uid: uid,
  219 + token: token,
  220 + version: version,
  221 + faversion: Config.fastadmin.version
  222 + }
203 }, function (data, ret) { 223 }, function (data, ret) {
204 Layer.closeAll(); 224 Layer.closeAll();
205 Config['addons'][data.addon.name] = ret.data.addon; 225 Config['addons'][data.addon.name] = ret.data.addon;
@@ -180,10 +180,11 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi @@ -180,10 +180,11 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
180 }); 180 });
181 181
182 //清除缓存 182 //清除缓存
183 - $(document).on('click', "[data-toggle='wipecache']", function () { 183 + $(document).on('click', "ul.wipecache li a", function () {
184 $.ajax({ 184 $.ajax({
185 url: 'ajax/wipecache', 185 url: 'ajax/wipecache',
186 dataType: 'json', 186 dataType: 'json',
  187 + data: {type: $(this).data("type")},
187 cache: false, 188 cache: false,
188 success: function (ret) { 189 success: function (ret) {
189 if (ret.hasOwnProperty("code")) { 190 if (ret.hasOwnProperty("code")) {
1 /** 1 /**
  2 + * FastAdmin通用搜索
  3 + *
2 * @author: pppscn <35696959@qq.com> 4 * @author: pppscn <35696959@qq.com>
3 - * @version: v0.0.1 5 + * @update 2017-05-07 <https://gitee.com/pp/fastadmin>
4 * 6 *
5 - * @update 2017-05-07 <http://git.oschina.net/pp/fastadmin>  
6 - * @update 2017-09-17 <http://git.oschina.net/karson/fastadmin> 7 + * @author: Karson <karsonzhang@163.com>
  8 + * @update 2018-04-05 <https://gitee.com/karson/fastadmin>
7 */ 9 */
8 10
9 !function ($) { 11 !function ($) {
@@ -17,75 +19,16 @@ @@ -17,75 +19,16 @@
17 var vFormCommon = createFormCommon(pColumns, that); 19 var vFormCommon = createFormCommon(pColumns, that);
18 20
19 var vModal = sprintf("<div class=\"commonsearch-table %s\">", that.options.searchFormVisible ? "" : "hidden"); 21 var vModal = sprintf("<div class=\"commonsearch-table %s\">", that.options.searchFormVisible ? "" : "hidden");
20 - vModal += vFormCommon.join(''); 22 + vModal += vFormCommon;
21 vModal += "</div>"; 23 vModal += "</div>";
22 that.$container.prepend($(vModal)); 24 that.$container.prepend($(vModal));
23 that.$commonsearch = $(".commonsearch-table", that.$container); 25 that.$commonsearch = $(".commonsearch-table", that.$container);
24 var form = $("form.form-commonsearch", that.$commonsearch); 26 var form = $("form.form-commonsearch", that.$commonsearch);
25 27
26 - //绑定日期时间元素事件  
27 - if ($(".datetimepicker", form).size() > 0) {  
28 -  
29 - require(['bootstrap-datetimepicker'], function () {  
30 - $('.datetimepicker', form).parent().css('position', 'relative');  
31 - $('.datetimepicker', form).datetimepicker({  
32 - //format: 'YYYY-MM-DD',  
33 - icons: {  
34 - time: 'fa fa-clock-o',  
35 - date: 'fa fa-calendar',  
36 - up: 'fa fa-chevron-up',  
37 - down: 'fa fa-chevron-down',  
38 - previous: 'fa fa-chevron-left',  
39 - next: 'fa fa-chevron-right',  
40 - today: 'fa fa-history',  
41 - clear: 'fa fa-trash',  
42 - close: 'fa fa-remove'  
43 - },  
44 - showTodayButton: true,  
45 - showClose: true  
46 - });  
47 - });  
48 - }  
49 - if ($(".datetimerange", form).size() > 0) {  
50 - var ranges = {};  
51 - ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];  
52 - ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];  
53 - ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')];  
54 - ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')];  
55 - ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')];  
56 - ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')];  
57 - var options = {  
58 - timePicker: false,  
59 - autoUpdateInput: false,  
60 - timePickerSeconds: true,  
61 - timePicker24Hour: true,  
62 - autoApply: true,  
63 - locale: {  
64 - format: 'YYYY-MM-DD HH:mm:ss',  
65 - customRangeLabel: __("Custom Range"),  
66 - applyLabel: __("Apply"),  
67 - cancelLabel: __("Clear"),  
68 - },  
69 - ranges: ranges,  
70 - };  
71 - var callback = function (start, end) {  
72 - $(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));  
73 - };  
74 - var column, index;  
75 - require(['bootstrap-daterangepicker'], function () {  
76 - $(".datetimerange", form).each(function () {  
77 - $(this).on('apply.daterangepicker', function (ev, picker) {  
78 - callback.call(picker, picker.startDate, picker.endDate);  
79 - });  
80 - $(this).on('cancel.daterangepicker', function (ev, picker) {  
81 - $(this).val('');  
82 - });  
83 - index = $(this).data("index");  
84 - column = pColumns[index];  
85 - $(this).daterangepicker($.extend({}, options, column.options || {}), callback);  
86 - });  
87 - });  
88 - } 28 + require(['form'], function (Form) {
  29 + Form.api.bindevent(form);
  30 + form.validator("destroy");
  31 + });
89 32
90 // 表单提交 33 // 表单提交
91 form.on("submit", function (event) { 34 form.on("submit", function (event) {
@@ -103,9 +46,12 @@ @@ -103,9 +46,12 @@
103 }; 46 };
104 47
105 var createFormCommon = function (pColumns, that) { 48 var createFormCommon = function (pColumns, that) {
  49 + // 如果有使用模板则直接返回模板的内容
  50 + if (that.options.searchFormTemplate) {
  51 + return Template(that.options.searchFormTemplate, {columns: pColumns, table: that});
  52 + }
106 var htmlForm = []; 53 var htmlForm = [];
107 - 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'];  
108 - htmlForm.push(sprintf('<form class="form-horizontal form-commonsearch" action="%s" >', that.options.actionForm)); 54 + htmlForm.push(sprintf('<form class="form-horizontal form-commonsearch" novalidate method="post" action="%s" >', that.options.actionForm));
109 htmlForm.push('<fieldset>'); 55 htmlForm.push('<fieldset>');
110 if (that.options.titleForm.length > 0) 56 if (that.options.titleForm.length > 0)
111 htmlForm.push(sprintf("<legend>%s</legend>", that.options.titleForm)); 57 htmlForm.push(sprintf("<legend>%s</legend>", that.options.titleForm));
@@ -114,24 +60,28 @@ @@ -114,24 +60,28 @@
114 var vObjCol = pColumns[i]; 60 var vObjCol = pColumns[i];
115 if (!vObjCol.checkbox && vObjCol.field !== 'operate' && vObjCol.searchable && vObjCol.operate !== false) { 61 if (!vObjCol.checkbox && vObjCol.field !== 'operate' && vObjCol.searchable && vObjCol.operate !== false) {
116 var query = Backend.api.query(vObjCol.field); 62 var query = Backend.api.query(vObjCol.field);
117 - query = query ? query : '';  
118 - vObjCol.defaultValue = that.options.renderDefault && query != '' ? query : (typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue); 63 + var operate = Backend.api.query(vObjCol.field + "-operate");
  64 +
  65 + vObjCol.defaultValue = that.options.renderDefault && query ? query : (typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue);
  66 + vObjCol.operate = that.options.renderDefault && operate ? operate : (typeof vObjCol.operate === 'undefined' ? '=' : vObjCol.operate);
119 ColumnsForSearch.push(vObjCol); 67 ColumnsForSearch.push(vObjCol);
120 68
121 htmlForm.push('<div class="form-group col-xs-12 col-sm-6 col-md-4 col-lg-3">'); 69 htmlForm.push('<div class="form-group col-xs-12 col-sm-6 col-md-4 col-lg-3">');
122 htmlForm.push(sprintf('<label for="%s" class="control-label col-xs-4">%s</label>', vObjCol.field, vObjCol.title)); 70 htmlForm.push(sprintf('<label for="%s" class="control-label col-xs-4">%s</label>', vObjCol.field, vObjCol.title));
123 htmlForm.push('<div class="col-xs-8">'); 71 htmlForm.push('<div class="col-xs-8">');
124 72
125 - vObjCol.operate = (typeof vObjCol.operate === 'undefined' || $.inArray(vObjCol.operate.toUpperCase(), opList) === -1) ? '=' : vObjCol.operate.toUpperCase();  
126 - 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)); 73 + vObjCol.operate = vObjCol.operate ? vObjCol.operate.toUpperCase() : '=';
  74 + 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));
127 75
  76 + var addClass = typeof vObjCol.addClass === 'undefined' ? (typeof vObjCol.addclass === 'undefined' ? 'form-control' : 'form-control ' + vObjCol.addclass) : 'form-control ' + vObjCol.addClass;
  77 + var extend = typeof vObjCol.extend === 'undefined' ? '' : vObjCol.extend;
128 var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style); 78 var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style);
  79 + extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend;
129 if (vObjCol.searchList) { 80 if (vObjCol.searchList) {
130 if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') { 81 if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') {
131 - htmlForm.push(sprintf('<select class="form-control" name="%s" %s>%s</select>', vObjCol.field, style, sprintf('<option value="">%s</option>', that.options.formatCommonChoose()))); 82 + 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())));
132 (function (vObjCol, that) { 83 (function (vObjCol, that) {
133 $.when(vObjCol.searchList).done(function (ret) { 84 $.when(vObjCol.searchList).done(function (ret) {
134 -  
135 var isArray = false; 85 var isArray = false;
136 if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) { 86 if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
137 var resultlist = {}; 87 var resultlist = {};
@@ -160,23 +110,21 @@ @@ -160,23 +110,21 @@
160 var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : ''; 110 var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : '';
161 searchList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect)); 111 searchList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect));
162 }); 112 });
163 - htmlForm.push(sprintf('<select class="form-control" name="%s" %s>%s</select>', vObjCol.field, style, searchList.join(''))); 113 + htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, searchList.join('')));
164 } 114 }
165 } else { 115 } else {
166 var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder; 116 var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder;
167 var type = typeof vObjCol.type === 'undefined' ? 'text' : vObjCol.type; 117 var type = typeof vObjCol.type === 'undefined' ? 'text' : vObjCol.type;
168 - var addclass = typeof vObjCol.addclass === 'undefined' ? 'form-control' : 'form-control ' + vObjCol.addclass;  
169 - var data = typeof vObjCol.data === 'undefined' ? '' : vObjCol.data;  
170 var defaultValue = typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue; 118 var defaultValue = typeof vObjCol.defaultValue === 'undefined' ? '' : vObjCol.defaultValue;
171 if (/BETWEEN$/.test(vObjCol.operate)) { 119 if (/BETWEEN$/.test(vObjCol.operate)) {
172 var defaultValueArr = defaultValue.toString().match(/\|/) ? defaultValue.split('|') : ['', '']; 120 var defaultValueArr = defaultValue.toString().match(/\|/) ? defaultValue.split('|') : ['', ''];
173 var placeholderArr = placeholder.toString().match(/\|/) ? placeholder.split('|') : [placeholder, placeholder]; 121 var placeholderArr = placeholder.toString().match(/\|/) ? placeholder.split('|') : [placeholder, placeholder];
174 htmlForm.push('<div class="row row-between">'); 122 htmlForm.push('<div class="row row-between">');
175 - 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));  
176 - 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)); 123 + 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));
  124 + 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));
177 htmlForm.push('</div>'); 125 htmlForm.push('</div>');
178 } else { 126 } else {
179 - 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)); 127 + 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));
180 } 128 }
181 } 129 }
182 130
@@ -191,7 +139,7 @@ @@ -191,7 +139,7 @@
191 htmlForm.push('</fieldset>'); 139 htmlForm.push('</fieldset>');
192 htmlForm.push('</form>'); 140 htmlForm.push('</form>');
193 141
194 - return htmlForm; 142 + return htmlForm.join('');
195 }; 143 };
196 144
197 var createFormBtn = function (that) { 145 var createFormBtn = function (that) {
@@ -199,7 +147,7 @@ @@ -199,7 +147,7 @@
199 var searchSubmit = that.options.formatCommonSubmitButton(); 147 var searchSubmit = that.options.formatCommonSubmitButton();
200 var searchReset = that.options.formatCommonResetButton(); 148 var searchReset = that.options.formatCommonResetButton();
201 htmlBtn.push('<div class="col-sm-8 col-xs-offset-4">'); 149 htmlBtn.push('<div class="col-sm-8 col-xs-offset-4">');
202 - htmlBtn.push(sprintf('<button type="submit" class="btn btn-success" >%s</button> ', searchSubmit)); 150 + htmlBtn.push(sprintf('<button type="submit" class="btn btn-success" formnovalidate>%s</button> ', searchSubmit));
203 htmlBtn.push(sprintf('<button type="reset" class="btn btn-default" >%s</button> ', searchReset)); 151 htmlBtn.push(sprintf('<button type="reset" class="btn btn-default" >%s</button> ', searchReset));
204 htmlBtn.push('</div>'); 152 htmlBtn.push('</div>');
205 return htmlBtn; 153 return htmlBtn;
@@ -219,16 +167,17 @@ @@ -219,16 +167,17 @@
219 var op = {}; 167 var op = {};
220 var filter = {}; 168 var filter = {};
221 var value = ''; 169 var value = '';
222 - $("form.form-commonsearch input.operate", that.$commonsearch).each(function (i) { 170 + $("form.form-commonsearch .operate", that.$commonsearch).each(function (i) {
223 var name = $(this).data("name"); 171 var name = $(this).data("name");
224 - var sym = $(this).val().toUpperCase(); 172 + var sym = $(this).is("select") ? $("option:selected", this).val() : $(this).val().toUpperCase();
225 var obj = $("[name='" + name + "']", that.$commonsearch); 173 var obj = $("[name='" + name + "']", that.$commonsearch);
226 if (obj.size() == 0) 174 if (obj.size() == 0)
227 return true; 175 return true;
228 var vObjCol = ColumnsForSearch[i]; 176 var vObjCol = ColumnsForSearch[i];
229 if (obj.size() > 1) { 177 if (obj.size() > 1) {
230 if (/BETWEEN$/.test(sym)) { 178 if (/BETWEEN$/.test(sym)) {
231 - var value_begin = $.trim($("[name='" + name + "']:first", that.$commonsearch).val()), value_end = $.trim($("[name='" + name + "']:last", that.$commonsearch).val()); 179 + var value_begin = $.trim($("[name='" + name + "']:first", that.$commonsearch).val()),
  180 + value_end = $.trim($("[name='" + name + "']:last", that.$commonsearch).val());
232 if (value_begin.length || value_end.length) { 181 if (value_begin.length || value_end.length) {
233 if (typeof vObjCol.process === 'function') { 182 if (typeof vObjCol.process === 'function') {
234 value_begin = vObjCol.process(value_begin, 'begin'); 183 value_begin = vObjCol.process(value_begin, 'begin');
@@ -244,11 +193,12 @@ @@ -244,11 +193,12 @@
244 } 193 }
245 } else { 194 } else {
246 value = $("[name='" + name + "']:checked", that.$commonsearch).val(); 195 value = $("[name='" + name + "']:checked", that.$commonsearch).val();
  196 + value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : obj.val();
247 } 197 }
248 } else { 198 } else {
249 - value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : (sym == 'LIKE %...%' ? obj.val().replace(/\*/g, '%') : obj.val()); 199 + value = (vObjCol && typeof vObjCol.process === 'function') ? vObjCol.process(obj.val()) : obj.val();
250 } 200 }
251 - if (removeempty && value == '' && sym.indexOf("NULL") == -1) { 201 + if (removeempty && (value == '' || value == null || ($.isArray(value) && value.length == 0)) && !sym.match(/null/i)) {
252 return true; 202 return true;
253 } 203 }
254 204
@@ -267,7 +217,7 @@ @@ -267,7 +217,7 @@
267 //移除empty的值 217 //移除empty的值
268 if (removeempty) { 218 if (removeempty) {
269 $.each(params.filter, function (i, j) { 219 $.each(params.filter, function (i, j) {
270 - if (j === '') { 220 + if ((j == '' || j == null || ($.isArray(j) && j.length == 0)) && !params.op[i].match(/null/i)) {
271 delete params.filter[i]; 221 delete params.filter[i];
272 delete params.op[i]; 222 delete params.op[i];
273 } 223 }
@@ -282,8 +232,10 @@ @@ -282,8 +232,10 @@
282 commonSearch: false, 232 commonSearch: false,
283 titleForm: "Common search", 233 titleForm: "Common search",
284 actionForm: "", 234 actionForm: "",
  235 + searchFormTemplate: "",
285 searchFormVisible: true, 236 searchFormVisible: true,
286 searchClass: 'searchit', 237 searchClass: 'searchit',
  238 + showSearch: true,
287 renderDefault: true, 239 renderDefault: true,
288 onCommonSearch: function (field, text) { 240 onCommonSearch: function (field, text) {
289 return false; 241 return false;
@@ -322,10 +274,10 @@ @@ -322,10 +274,10 @@
322 $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales); 274 $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
323 275
324 var BootstrapTable = $.fn.bootstrapTable.Constructor, 276 var BootstrapTable = $.fn.bootstrapTable.Constructor,
325 - _initHeader = BootstrapTable.prototype.initHeader,  
326 - _initToolbar = BootstrapTable.prototype.initToolbar,  
327 - _load = BootstrapTable.prototype.load,  
328 - _initSearch = BootstrapTable.prototype.initSearch; 277 + _initHeader = BootstrapTable.prototype.initHeader,
  278 + _initToolbar = BootstrapTable.prototype.initToolbar,
  279 + _load = BootstrapTable.prototype.load,
  280 + _initSearch = BootstrapTable.prototype.initSearch;
329 281
330 BootstrapTable.prototype.initHeader = function () { 282 BootstrapTable.prototype.initHeader = function () {
331 _initHeader.apply(this, Array.prototype.slice.apply(arguments)); 283 _initHeader.apply(this, Array.prototype.slice.apply(arguments));
@@ -344,12 +296,13 @@ @@ -344,12 +296,13 @@
344 } 296 }
345 297
346 var that = this, 298 var that = this,
347 - html = [];  
348 - html.push(sprintf('<div class="columns-%s pull-%s" style="margin-top:10px;margin-bottom:10px;">', this.options.buttonsAlign, this.options.buttonsAlign));  
349 - 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()));  
350 - html.push(sprintf('<i class="%s %s"></i>', that.options.iconsPrefix, that.options.icons.commonSearchIcon))  
351 - html.push('</button></div>');  
352 - 299 + html = [];
  300 + if(that.options.showSearch){
  301 + html.push(sprintf('<div class="columns-%s pull-%s" style="margin-top:10px;margin-bottom:10px;">', this.options.buttonsAlign, this.options.buttonsAlign));
  302 + 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()));
  303 + html.push(sprintf('<i class="%s %s"></i>', that.options.iconsPrefix, that.options.icons.commonSearchIcon))
  304 + html.push('</button></div>');
  305 + }
353 if (that.$toolbar.find(".pull-right").size() > 0) { 306 if (that.$toolbar.find(".pull-right").size() > 0) {
354 $(html.join('')).insertBefore(that.$toolbar.find(".pull-right:first")); 307 $(html.join('')).insertBefore(that.$toolbar.find(".pull-right:first"));
355 } else { 308 } else {
@@ -359,7 +312,7 @@ @@ -359,7 +312,7 @@
359 initCommonSearch(that.columns, that); 312 initCommonSearch(that.columns, that);
360 313
361 that.$toolbar.find('button[name="commonSearch"]') 314 that.$toolbar.find('button[name="commonSearch"]')
362 - .off('click').on('click', function () { 315 + .off('click').on('click', function () {
363 that.$commonsearch.toggleClass("hidden"); 316 that.$commonsearch.toggleClass("hidden");
364 return; 317 return;
365 }); 318 });
@@ -374,7 +327,7 @@ @@ -374,7 +327,7 @@
374 var queryParams = that.options.queryParams; 327 var queryParams = that.options.queryParams;
375 //匹配默认搜索值 328 //匹配默认搜索值
376 this.options.queryParams = function (params) { 329 this.options.queryParams = function (params) {
377 - return queryParams(getQueryParams(params, getSearchQuery(this, true))); 330 + return queryParams(getQueryParams(params, getSearchQuery(that, true)));
378 }; 331 };
379 this.trigger('post-common-search', that); 332 this.trigger('post-common-search', that);
380 333
@@ -409,8 +362,8 @@ @@ -409,8 +362,8 @@
409 var fval = fp[key].toLowerCase(); 362 var fval = fp[key].toLowerCase();
410 var value = item[key]; 363 var value = item[key];
411 value = $.fn.bootstrapTable.utils.calculateObjectValue(that.header, 364 value = $.fn.bootstrapTable.utils.calculateObjectValue(that.header,
412 - that.header.formatters[$.inArray(key, that.header.fields)],  
413 - [value, item, i], value); 365 + that.header.formatters[$.inArray(key, that.header.fields)],
  366 + [value, item, i], value);
414 367
415 if (!($.inArray(key, that.header.fields) !== -1 && 368 if (!($.inArray(key, that.header.fields) !== -1 &&
416 (typeof value === 'string' || typeof value === 'number') && 369 (typeof value === 'string' || typeof value === 'number') &&
1 -define(['fast'], function (Fast) { 1 +define(['fast', 'template'], function (Fast, Template) {
2 var Frontend = { 2 var Frontend = {
3 api: Fast.api, 3 api: Fast.api,
4 init: function () { 4 init: function () {
@@ -53,6 +53,8 @@ define(['fast'], function (Fast) { @@ -53,6 +53,8 @@ define(['fast'], function (Fast) {
53 } 53 }
54 }; 54 };
55 Frontend.api = $.extend(Fast.api, Frontend.api); 55 Frontend.api = $.extend(Fast.api, Frontend.api);
  56 + //将Template渲染至全局,以便于在子框架中调用
  57 + window.Template = Template;
56 //将Frontend渲染至全局,以便于在子框架中调用 58 //将Frontend渲染至全局,以便于在子框架中调用
57 window.Frontend = Frontend; 59 window.Frontend = Frontend;
58 60
1 define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) { 1 define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
2 var Form = { 2 var Form = {
3 config: { 3 config: {
4 - 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>' 4 + 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>'
5 }, 5 },
6 events: { 6 events: {
7 validator: function (form, success, error, submit) { 7 validator: function (form, success, error, submit) {
@@ -26,6 +26,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U @@ -26,6 +26,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
26 } 26 }
27 }, 27 },
28 target: function (input) { 28 target: function (input) {
  29 + var target = $(input).data("target");
  30 + if (target && $(target).size() > 0) {
  31 + return $(target);
  32 + }
29 var $formitem = $(input).closest('.form-group'), 33 var $formitem = $(input).closest('.form-group'),
30 $msgbox = $formitem.find('span.msg-box'); 34 $msgbox = $formitem.find('span.msg-box');
31 if (!$msgbox.length) { 35 if (!$msgbox.length) {
@@ -282,7 +286,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U @@ -282,7 +286,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
282 refresh($(this).closest("dl").data("name")); 286 refresh($(this).closest("dl").data("name"));
283 }); 287 });
284 //追加控制 288 //追加控制
285 - $(".fieldlist", form).on("click", ".btn-append", function (e, row) { 289 + $(".fieldlist", form).on("click", ".btn-append,.append", function (e, row) {
286 var container = $(this).closest("dl"); 290 var container = $(this).closest("dl");
287 var index = container.data("index"); 291 var index = container.data("index");
288 var name = container.data("name"); 292 var name = container.data("name");
@@ -305,7 +309,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U @@ -305,7 +309,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
305 //拖拽排序 309 //拖拽排序
306 $("dl.fieldlist", form).dragsort({ 310 $("dl.fieldlist", form).dragsort({
307 itemSelector: 'dd', 311 itemSelector: 'dd',
308 - dragSelector: ".btn-fdragsort", 312 + dragSelector: ".btn-dragsort",
309 dragEnd: function () { 313 dragEnd: function () {
310 refresh($(this).closest("dl").data("name")); 314 refresh($(this).closest("dl").data("name"));
311 }, 315 },
@@ -319,8 +323,13 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U @@ -319,8 +323,13 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
319 return true; 323 return true;
320 } 324 }
321 var template = $(this).data("template"); 325 var template = $(this).data("template");
322 - $.each(JSON.parse(textarea.val()), function (i, j) {  
323 - $(".btn-append", container).trigger('click', template ? j : { 326 + var json = {};
  327 + try {
  328 + json = JSON.parse(textarea.val());
  329 + } catch (e) {
  330 + }
  331 + $.each(json, function (i, j) {
  332 + $(".btn-append,.append", container).trigger('click', template ? j : {
324 key: i, 333 key: i,
325 value: j 334 value: j
326 }); 335 });
@@ -973,7 +973,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u @@ -973,7 +973,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
973 return Fast; 973 return Fast;
974 }); 974 });
975 975
976 -define('frontend',['fast'], function (Fast) { 976 +/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
  977 +!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}();
  978 +define('frontend',['fast', 'template'], function (Fast, Template) {
977 var Frontend = { 979 var Frontend = {
978 api: Fast.api, 980 api: Fast.api,
979 init: function () { 981 init: function () {
@@ -1028,6 +1030,8 @@ define('frontend',['fast'], function (Fast) { @@ -1028,6 +1030,8 @@ define('frontend',['fast'], function (Fast) {
1028 } 1030 }
1029 }; 1031 };
1030 Frontend.api = $.extend(Fast.api, Frontend.api); 1032 Frontend.api = $.extend(Fast.api, Frontend.api);
  1033 + //将Template渲染至全局,以便于在子框架中调用
  1034 + window.Template = Template;
1031 //将Frontend渲染至全局,以便于在子框架中调用 1035 //将Frontend渲染至全局,以便于在子框架中调用
1032 window.Frontend = Frontend; 1036 window.Frontend = Frontend;
1033 1037
@@ -847,4 +847,8 @@ form.form-horizontal .control-label { @@ -847,4 +847,8 @@ form.form-horizontal .control-label {
847 margin: 2px 0 0; 847 margin: 2px 0 0;
848 } 848 }
849 } 849 }
  850 +}
  851 +
  852 +.wipecache li a {
  853 + color:#444444!important;
850 } 854 }