新增命令行一键生成API文档功能
新增插件绑定二级域名功能 新增加载JS公用模块 新增命令行创建插件自动生成菜单功能 新增后台菜单Fast.api.refreshmenu 新增后台菜单在数据变更后自动刷新的功能 新增require.min.js压缩版 新增从Headers中读取授权token的功能 新增Form.events.daterangepicker时间区别事件 新增Form表单提示成功和失败的回调事件 新增Fast.api.getrowbyid和Fast.api.getrowbyindex方法 新增commonsearch的find_in_set类型搜索 新增Menu::export的方法 新增php think api一键生成API文档功能 新增php think min的压缩参数和调试功能 优化API模块生产环境下错误信息的显示 优化移动端显示移除顶部Logo一行 优化bower.json和composer.json的版本依赖 优化插件管理列表显示 优化后台控制区多作的选项卡数据 优化CRUD生成的复选框样式及文字 优化规则管理的列表显示 优化第三方前端资源,移除冗余资源 修复在启用域名部署下的BUG 修复API初始化接口的BUG 修复会员积分日志模型BUG 修复多语言切换不存在的BUG 修复Backend.php中multi操作不触发模型事件的BUG
正在显示
73 个修改的文件
包含
2193 行增加
和
390 行删除
@@ -16,10 +16,12 @@ FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。 | @@ -16,10 +16,12 @@ FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。 | ||
16 | * 基于`Bower`进行前端组件包管理 | 16 | * 基于`Bower`进行前端组件包管理 |
17 | * 数据库表一键生成`CRUD`,包括控制器、模型、视图、JS、语言包、菜单等 | 17 | * 数据库表一键生成`CRUD`,包括控制器、模型、视图、JS、语言包、菜单等 |
18 | * 一键压缩打包JS和CSS文件,一键CDN静态资源部署 | 18 | * 一键压缩打包JS和CSS文件,一键CDN静态资源部署 |
19 | +* 一键生成API接口文档 | ||
19 | * 强大的插件扩展功能,在线安装卸载升级插件 | 20 | * 强大的插件扩展功能,在线安装卸载升级插件 |
20 | * 共用同一账号体系的Web端会员中心权限验证和API接口会员权限验证 | 21 | * 共用同一账号体系的Web端会员中心权限验证和API接口会员权限验证 |
22 | +* 二级域名部署支持,同时域名支持绑定到插件 | ||
21 | * 多语言支持,服务端及客户端支持 | 23 | * 多语言支持,服务端及客户端支持 |
22 | -* 强大的第三方插件支持(CMS、博客、文档生成) | 24 | +* 强大的第三方模块支持(CMS、博客、文档生成) |
23 | * 整合第三方短信接口(阿里云、创蓝短信) | 25 | * 整合第三方短信接口(阿里云、创蓝短信) |
24 | * 无缝整合第三方云存储(七牛、阿里云OSS、又拍云)功能 | 26 | * 无缝整合第三方云存储(七牛、阿里云OSS、又拍云)功能 |
25 | * 第三方登录(QQ、微信、微博)整合 | 27 | * 第三方登录(QQ、微信、微博)整合 |
@@ -2,14 +2,17 @@ | @@ -2,14 +2,17 @@ | ||
2 | 2 | ||
3 | namespace app\admin\command; | 3 | namespace app\admin\command; |
4 | 4 | ||
5 | +use app\common\library\Menu; | ||
5 | use think\addons\AddonException; | 6 | use think\addons\AddonException; |
6 | use think\addons\Service; | 7 | use think\addons\Service; |
8 | +use think\Config; | ||
7 | use think\console\Command; | 9 | use think\console\Command; |
8 | use think\console\Input; | 10 | use think\console\Input; |
9 | use think\console\input\Option; | 11 | use think\console\input\Option; |
10 | use think\console\Output; | 12 | use think\console\Output; |
11 | use think\Db; | 13 | use think\Db; |
12 | use think\Exception; | 14 | use think\Exception; |
15 | +use think\exception\PDOException; | ||
13 | 16 | ||
14 | class Addon extends Command | 17 | class Addon extends Command |
15 | { | 18 | { |
@@ -63,14 +66,43 @@ class Addon extends Command | @@ -63,14 +66,43 @@ class Addon extends Command | ||
63 | rmdirs($addonDir); | 66 | rmdirs($addonDir); |
64 | } | 67 | } |
65 | mkdir($addonDir); | 68 | mkdir($addonDir); |
69 | + mkdir($addonDir . DS . 'controller'); | ||
70 | + $menuList = Menu::export($name); | ||
71 | + $createMenu = $this->getCreateMenu($menuList); | ||
72 | + $prefix = Config::get('database.prefix'); | ||
73 | + $createTableSql = ''; | ||
74 | + try | ||
75 | + { | ||
76 | + $result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;"); | ||
77 | + if (isset($result[0]) && isset($result[0]['Create Table'])) | ||
78 | + { | ||
79 | + $createTableSql = $result[0]['Create Table']; | ||
80 | + } | ||
81 | + } | ||
82 | + catch (PDOException $e) | ||
83 | + { | ||
84 | + | ||
85 | + } | ||
86 | + | ||
66 | $data = [ | 87 | $data = [ |
67 | 'name' => $name, | 88 | 'name' => $name, |
68 | 'addon' => $name, | 89 | 'addon' => $name, |
69 | - 'addonClassName' => ucfirst($name) | 90 | + 'addonClassName' => ucfirst($name), |
91 | + 'addonInstallMenu' => $createMenu ? "\$menu = " . var_export_short($createMenu, "\t") . ";\n\tMenu::create(\$menu);" : '', | ||
92 | + 'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '', | ||
93 | + 'addonEnableMenu' => $menuList ? 'Menu::enable("' . $name . '");' : '', | ||
94 | + 'addonDisableMenu' => $menuList ? 'Menu::disable("' . $name . '");' : '', | ||
70 | ]; | 95 | ]; |
71 | $this->writeToFile("addon", $data, $addonDir . ucfirst($name) . '.php'); | 96 | $this->writeToFile("addon", $data, $addonDir . ucfirst($name) . '.php'); |
72 | $this->writeToFile("config", $data, $addonDir . 'config.php'); | 97 | $this->writeToFile("config", $data, $addonDir . 'config.php'); |
73 | $this->writeToFile("info", $data, $addonDir . 'info.ini'); | 98 | $this->writeToFile("info", $data, $addonDir . 'info.ini'); |
99 | + $this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php'); | ||
100 | + if ($createTableSql) | ||
101 | + { | ||
102 | + $createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql); | ||
103 | + file_put_contents($addonDir . 'install.sql', $createTableSql); | ||
104 | + } | ||
105 | + | ||
74 | $output->info("Create Successed!"); | 106 | $output->info("Create Successed!"); |
75 | break; | 107 | break; |
76 | case 'disable': | 108 | case 'disable': |
@@ -257,6 +289,37 @@ class Addon extends Command | @@ -257,6 +289,37 @@ class Addon extends Command | ||
257 | } | 289 | } |
258 | 290 | ||
259 | /** | 291 | /** |
292 | + * 获取创建菜单的数组 | ||
293 | + * @param array $menu | ||
294 | + * @return array | ||
295 | + */ | ||
296 | + protected function getCreateMenu($menu) | ||
297 | + { | ||
298 | + $result = []; | ||
299 | + foreach ($menu as $k => & $v) | ||
300 | + { | ||
301 | + $arr = [ | ||
302 | + 'name' => $v['name'], | ||
303 | + 'title' => $v['title'], | ||
304 | + ]; | ||
305 | + if ($v['icon'] != 'fa fa-circle-o') | ||
306 | + { | ||
307 | + $arr['icon'] = $v['icon']; | ||
308 | + } | ||
309 | + if ($v['ismenu']) | ||
310 | + { | ||
311 | + $arr['ismenu'] = $v['ismenu']; | ||
312 | + } | ||
313 | + if (isset($v['childlist']) && $v['childlist']) | ||
314 | + { | ||
315 | + $arr['sublist'] = $this->getCreateMenu($v['childlist']); | ||
316 | + } | ||
317 | + $result[] = $arr; | ||
318 | + } | ||
319 | + return $result; | ||
320 | + } | ||
321 | + | ||
322 | + /** | ||
260 | * 写入到文件 | 323 | * 写入到文件 |
261 | * @param string $name | 324 | * @param string $name |
262 | * @param array $data | 325 | * @param array $data |
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | 2 | ||
3 | namespace addons\{%name%}; | 3 | namespace addons\{%name%}; |
4 | 4 | ||
5 | +use app\common\library\Menu; | ||
5 | use think\Addons; | 6 | use think\Addons; |
6 | 7 | ||
7 | /** | 8 | /** |
@@ -16,6 +17,7 @@ class {%addonClassName%} extends Addons | @@ -16,6 +17,7 @@ class {%addonClassName%} extends Addons | ||
16 | */ | 17 | */ |
17 | public function install() | 18 | public function install() |
18 | { | 19 | { |
20 | + {%addonInstallMenu%} | ||
19 | return true; | 21 | return true; |
20 | } | 22 | } |
21 | 23 | ||
@@ -25,6 +27,7 @@ class {%addonClassName%} extends Addons | @@ -25,6 +27,7 @@ class {%addonClassName%} extends Addons | ||
25 | */ | 27 | */ |
26 | public function uninstall() | 28 | public function uninstall() |
27 | { | 29 | { |
30 | + {%addonUninstallMenu%} | ||
28 | return true; | 31 | return true; |
29 | } | 32 | } |
30 | 33 | ||
@@ -34,6 +37,7 @@ class {%addonClassName%} extends Addons | @@ -34,6 +37,7 @@ class {%addonClassName%} extends Addons | ||
34 | */ | 37 | */ |
35 | public function enable() | 38 | public function enable() |
36 | { | 39 | { |
40 | + {%addonEnableMenu%} | ||
37 | return true; | 41 | return true; |
38 | } | 42 | } |
39 | 43 | ||
@@ -43,6 +47,7 @@ class {%addonClassName%} extends Addons | @@ -43,6 +47,7 @@ class {%addonClassName%} extends Addons | ||
43 | */ | 47 | */ |
44 | public function disable() | 48 | public function disable() |
45 | { | 49 | { |
50 | + {%addonDisableMenu%} | ||
46 | return true; | 51 | return true; |
47 | } | 52 | } |
48 | 53 |
application/admin/command/Api.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\command; | ||
4 | + | ||
5 | +use app\admin\command\Api\library\Builder; | ||
6 | +use think\Config; | ||
7 | +use think\console\Command; | ||
8 | +use think\console\Input; | ||
9 | +use think\console\input\Option; | ||
10 | +use think\console\Output; | ||
11 | +use think\Exception; | ||
12 | + | ||
13 | +class Api extends Command | ||
14 | +{ | ||
15 | + | ||
16 | + protected function configure() | ||
17 | + { | ||
18 | + $site = Config::get('site'); | ||
19 | + $this | ||
20 | + ->setName('api') | ||
21 | + ->addOption('url', 'u', Option::VALUE_OPTIONAL, 'default api url', '') | ||
22 | + ->addOption('module', 'm', Option::VALUE_OPTIONAL, 'module name(admin/index/api)', 'api') | ||
23 | + ->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html') | ||
24 | + ->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html') | ||
25 | + ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override general file', false) | ||
26 | + ->addOption('title', 't', Option::VALUE_OPTIONAL, 'document title', $site['name']) | ||
27 | + ->addOption('author', 'a', Option::VALUE_OPTIONAL, 'document author', $site['name']) | ||
28 | + ->addOption('class', 'c', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'extend class', null) | ||
29 | + ->addOption('language', 'l', Option::VALUE_OPTIONAL, 'language', 'zh-cn') | ||
30 | + ->setDescription('Compress js and css file'); | ||
31 | + } | ||
32 | + | ||
33 | + protected function execute(Input $input, Output $output) | ||
34 | + { | ||
35 | + $apiDir = __DIR__ . DS . 'Api' . DS; | ||
36 | + | ||
37 | + $force = $input->getOption('force'); | ||
38 | + $url = $input->getOption('url'); | ||
39 | + $language = $input->getOption('language'); | ||
40 | + $langFile = $apiDir . 'lang' . DS . $language . '.php'; | ||
41 | + if (!is_file($langFile)) | ||
42 | + { | ||
43 | + throw new Exception('language file not found'); | ||
44 | + } | ||
45 | + $lang = include $langFile; | ||
46 | + // 目标目录 | ||
47 | + $output_dir = ROOT_PATH . 'public' . DS; | ||
48 | + $output_file = $output_dir . $input->getOption('output'); | ||
49 | + if (is_file($output_file) && !$force) | ||
50 | + { | ||
51 | + throw new Exception("api index file already exists!\nIf you need to rebuild again, use the parameter --force=true "); | ||
52 | + } | ||
53 | + // 模板文件 | ||
54 | + $template_dir = $apiDir . 'template' . DS; | ||
55 | + $template_file = $template_dir . $input->getOption('template'); | ||
56 | + if (!is_file($template_file)) | ||
57 | + { | ||
58 | + throw new Exception('template file not found'); | ||
59 | + } | ||
60 | + // 额外的类 | ||
61 | + $classes = $input->getOption('class'); | ||
62 | + // 标题 | ||
63 | + $title = $input->getOption('title'); | ||
64 | + // 作者 | ||
65 | + $author = $input->getOption('author'); | ||
66 | + // 模块 | ||
67 | + $module = $input->getOption('module'); | ||
68 | + | ||
69 | + $moduleDir = APP_PATH . $module . DS; | ||
70 | + if (!is_dir($moduleDir)) | ||
71 | + { | ||
72 | + throw new Exception('module not found'); | ||
73 | + } | ||
74 | + $controllerDir = $moduleDir . Config::get('url_controller_layer') . DS; | ||
75 | + $files = new \RecursiveIteratorIterator( | ||
76 | + new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY | ||
77 | + ); | ||
78 | + | ||
79 | + foreach ($files as $name => $file) | ||
80 | + { | ||
81 | + if (!$file->isDir()) | ||
82 | + { | ||
83 | + $filePath = $file->getRealPath(); | ||
84 | + $classes[] = $this->get_class_from_file($filePath); | ||
85 | + } | ||
86 | + } | ||
87 | + | ||
88 | + $config = [ | ||
89 | + 'title' => $title, | ||
90 | + 'author' => $author, | ||
91 | + 'description' => '', | ||
92 | + 'apiurl' => $url, | ||
93 | + ]; | ||
94 | + $builder = new Builder($classes); | ||
95 | + $content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]); | ||
96 | + | ||
97 | + if (!file_put_contents($output_file, $content)) | ||
98 | + { | ||
99 | + throw new Exception('Cannot save the content to ' . $output_file); | ||
100 | + } | ||
101 | + $output->info("Build Successed!"); | ||
102 | + } | ||
103 | + | ||
104 | + /** | ||
105 | + * get full qualified class name | ||
106 | + * | ||
107 | + * @param string $path_to_file | ||
108 | + * @author JBYRNE http://jarretbyrne.com/2015/06/197/ | ||
109 | + * @return string | ||
110 | + */ | ||
111 | + protected function get_class_from_file($path_to_file) | ||
112 | + { | ||
113 | + //Grab the contents of the file | ||
114 | + $contents = file_get_contents($path_to_file); | ||
115 | + | ||
116 | + //Start with a blank namespace and class | ||
117 | + $namespace = $class = ""; | ||
118 | + | ||
119 | + //Set helper values to know that we have found the namespace/class token and need to collect the string values after them | ||
120 | + $getting_namespace = $getting_class = false; | ||
121 | + | ||
122 | + //Go through each token and evaluate it as necessary | ||
123 | + foreach (token_get_all($contents) as $token) | ||
124 | + { | ||
125 | + | ||
126 | + //If this token is the namespace declaring, then flag that the next tokens will be the namespace name | ||
127 | + if (is_array($token) && $token[0] == T_NAMESPACE) | ||
128 | + { | ||
129 | + $getting_namespace = true; | ||
130 | + } | ||
131 | + | ||
132 | + //If this token is the class declaring, then flag that the next tokens will be the class name | ||
133 | + if (is_array($token) && $token[0] == T_CLASS) | ||
134 | + { | ||
135 | + $getting_class = true; | ||
136 | + } | ||
137 | + | ||
138 | + //While we're grabbing the namespace name... | ||
139 | + if ($getting_namespace === true) | ||
140 | + { | ||
141 | + | ||
142 | + //If the token is a string or the namespace separator... | ||
143 | + if (is_array($token) && in_array($token[0], [T_STRING, T_NS_SEPARATOR])) | ||
144 | + { | ||
145 | + | ||
146 | + //Append the token's value to the name of the namespace | ||
147 | + $namespace .= $token[1]; | ||
148 | + } | ||
149 | + else if ($token === ';') | ||
150 | + { | ||
151 | + | ||
152 | + //If the token is the semicolon, then we're done with the namespace declaration | ||
153 | + $getting_namespace = false; | ||
154 | + } | ||
155 | + } | ||
156 | + | ||
157 | + //While we're grabbing the class name... | ||
158 | + if ($getting_class === true) | ||
159 | + { | ||
160 | + | ||
161 | + //If the token is a string, it's the name of the class | ||
162 | + if (is_array($token) && $token[0] == T_STRING) | ||
163 | + { | ||
164 | + | ||
165 | + //Store the token's value as the class name | ||
166 | + $class = $token[1]; | ||
167 | + | ||
168 | + //Got what we need, stope here | ||
169 | + break; | ||
170 | + } | ||
171 | + } | ||
172 | + } | ||
173 | + | ||
174 | + //Build the fully-qualified class name and return it | ||
175 | + return $namespace ? $namespace . '\\' . $class : $class; | ||
176 | + } | ||
177 | + | ||
178 | +} |
application/admin/command/Api/lang/zh-cn.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + 'Info' => '基础信息', | ||
5 | + 'Sandbox' => '在线测试', | ||
6 | + 'Sampleoutput' => '返回示例', | ||
7 | + 'Headers' => 'Headers', | ||
8 | + 'Parameters' => '参数', | ||
9 | + 'Body' => '正文', | ||
10 | + 'Name' => '名称', | ||
11 | + 'Type' => '类型', | ||
12 | + 'Required' => '必选', | ||
13 | + 'Description' => '描述', | ||
14 | + 'Send' => '提交', | ||
15 | + 'Tokentips' => 'Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中', | ||
16 | + 'Apiurltips' => 'API接口URL', | ||
17 | + 'Savetips' => '点击保存后Token和Api url都将保存在本地Localstorage中', | ||
18 | + 'ReturnHeaders' => '响应头', | ||
19 | + 'ReturnParameters' => '返回参数', | ||
20 | + 'Response' => '响应输出', | ||
21 | +]; |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\command\Api\library; | ||
4 | + | ||
5 | +use think\Config; | ||
6 | + | ||
7 | +/** | ||
8 | + * @website https://github.com/calinrada/php-apidoc | ||
9 | + * @author Calin Rada <rada.calin@gmail.com> | ||
10 | + * @author Karson <karsonzhang@163.com> | ||
11 | + */ | ||
12 | +class Builder | ||
13 | +{ | ||
14 | + | ||
15 | + /** | ||
16 | + * | ||
17 | + * @var \think\View | ||
18 | + */ | ||
19 | + public $view = null; | ||
20 | + | ||
21 | + /** | ||
22 | + * parse classes | ||
23 | + * @var array | ||
24 | + */ | ||
25 | + protected $classes = []; | ||
26 | + | ||
27 | + /** | ||
28 | + * | ||
29 | + * @param array $classes | ||
30 | + */ | ||
31 | + public function __construct($classes = []) | ||
32 | + { | ||
33 | + $this->classes = array_merge($this->classes, $classes); | ||
34 | + $this->view = \think\View::instance(Config::get('template'), Config::get('view_replace_str')); | ||
35 | + } | ||
36 | + | ||
37 | + protected function extractAnnotations() | ||
38 | + { | ||
39 | + $st_output = []; | ||
40 | + foreach ($this->classes as $class) | ||
41 | + { | ||
42 | + $st_output[] = Extractor::getAllClassAnnotations($class); | ||
43 | + } | ||
44 | + return end($st_output); | ||
45 | + } | ||
46 | + | ||
47 | + protected function generateHeadersTemplate($docs) | ||
48 | + { | ||
49 | + if (!isset($docs['ApiHeaders'])) | ||
50 | + { | ||
51 | + return []; | ||
52 | + } | ||
53 | + | ||
54 | + $headerslist = array(); | ||
55 | + foreach ($docs['ApiHeaders'] as $params) | ||
56 | + { | ||
57 | + $tr = array( | ||
58 | + 'name' => $params['name'], | ||
59 | + 'type' => $params['type'], | ||
60 | + 'sample' => isset($params['sample']) ? $params['sample'] : '', | ||
61 | + 'required' => isset($params['required']) ? $params['required'] : false, | ||
62 | + 'description' => isset($params['description']) ? $params['description'] : '', | ||
63 | + ); | ||
64 | + $headerslist[] = $tr; | ||
65 | + } | ||
66 | + | ||
67 | + return $headerslist; | ||
68 | + } | ||
69 | + | ||
70 | + protected function generateParamsTemplate($docs) | ||
71 | + { | ||
72 | + if (!isset($docs['ApiParams'])) | ||
73 | + { | ||
74 | + return []; | ||
75 | + } | ||
76 | + | ||
77 | + $paramslist = array(); | ||
78 | + foreach ($docs['ApiParams'] as $params) | ||
79 | + { | ||
80 | + $tr = array( | ||
81 | + 'name' => $params['name'], | ||
82 | + 'type' => isset($params['type']) ? $params['type'] : 'string', | ||
83 | + 'sample' => isset($params['sample']) ? $params['sample'] : '', | ||
84 | + 'required' => isset($params['required']) ? $params['required'] : true, | ||
85 | + 'description' => isset($params['description']) ? $params['description'] : '', | ||
86 | + ); | ||
87 | + $paramslist[] = $tr; | ||
88 | + } | ||
89 | + | ||
90 | + return $paramslist; | ||
91 | + } | ||
92 | + | ||
93 | + protected function generateReturnHeadersTemplate($docs) | ||
94 | + { | ||
95 | + if (!isset($docs['ApiReturnHeaders'])) | ||
96 | + { | ||
97 | + return []; | ||
98 | + } | ||
99 | + | ||
100 | + $headerslist = array(); | ||
101 | + foreach ($docs['ApiReturnHeaders'] as $params) | ||
102 | + { | ||
103 | + $tr = array( | ||
104 | + 'name' => $params['name'], | ||
105 | + 'type' => 'string', | ||
106 | + 'sample' => isset($params['sample']) ? $params['sample'] : '', | ||
107 | + 'required' => isset($params['required']) && $params['required'] ? 'Yes' : 'No', | ||
108 | + 'description' => isset($params['description']) ? $params['description'] : '', | ||
109 | + ); | ||
110 | + $headerslist[] = $tr; | ||
111 | + } | ||
112 | + | ||
113 | + return $headerslist; | ||
114 | + } | ||
115 | + | ||
116 | + protected function generateReturnParamsTemplate($st_params) | ||
117 | + { | ||
118 | + if (!isset($st_params['ApiReturnParams'])) | ||
119 | + { | ||
120 | + return []; | ||
121 | + } | ||
122 | + | ||
123 | + $paramslist = array(); | ||
124 | + foreach ($st_params['ApiReturnParams'] as $params) | ||
125 | + { | ||
126 | + $tr = array( | ||
127 | + 'name' => $params['name'], | ||
128 | + 'type' => isset($params['type']) ? $params['type'] : 'string', | ||
129 | + 'sample' => isset($params['sample']) ? $params['sample'] : '', | ||
130 | + 'description' => isset($params['description']) ? $params['description'] : '', | ||
131 | + ); | ||
132 | + $paramslist[] = $tr; | ||
133 | + } | ||
134 | + | ||
135 | + return $paramslist; | ||
136 | + } | ||
137 | + | ||
138 | + protected function generateBadgeForMethod($data) | ||
139 | + { | ||
140 | + $method = strtoupper(is_array($data['ApiMethod'][0]) ? $data['ApiMethod'][0]['data'] : $data['ApiMethod'][0]); | ||
141 | + $labes = array( | ||
142 | + 'POST' => 'label-primary', | ||
143 | + 'GET' => 'label-success', | ||
144 | + 'PUT' => 'label-warning', | ||
145 | + 'DELETE' => 'label-danger', | ||
146 | + 'PATCH' => 'label-default', | ||
147 | + 'OPTIONS' => 'label-info' | ||
148 | + ); | ||
149 | + | ||
150 | + return isset($labes[$method]) ? $labes[$method] : $labes['GET']; | ||
151 | + } | ||
152 | + | ||
153 | + public function parse() | ||
154 | + { | ||
155 | + $annotations = $this->extractAnnotations(); | ||
156 | + | ||
157 | + $counter = 0; | ||
158 | + $section = null; | ||
159 | + $docslist = []; | ||
160 | + foreach ($annotations as $class => $methods) | ||
161 | + { | ||
162 | + foreach ($methods as $name => $docs) | ||
163 | + { | ||
164 | + if (isset($docs['ApiSector'][0])) | ||
165 | + { | ||
166 | + $section = is_array($docs['ApiSector'][0]) ? $docs['ApiSector'][0]['data'] : $docs['ApiSector'][0]; | ||
167 | + } | ||
168 | + else | ||
169 | + { | ||
170 | + $section = $class; | ||
171 | + } | ||
172 | + if (0 === count($docs)) | ||
173 | + { | ||
174 | + continue; | ||
175 | + } | ||
176 | + | ||
177 | + $docslist[$section][] = [ | ||
178 | + 'id' => $counter, | ||
179 | + 'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0], | ||
180 | + 'method_label' => $this->generateBadgeForMethod($docs), | ||
181 | + 'section' => $section, | ||
182 | + 'route' => is_array($docs['ApiRoute'][0]) ? $docs['ApiRoute'][0]['data'] : $docs['ApiRoute'][0], | ||
183 | + 'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0], | ||
184 | + 'body' => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '', | ||
185 | + 'headerslist' => $this->generateHeadersTemplate($docs), | ||
186 | + 'paramslist' => $this->generateParamsTemplate($docs), | ||
187 | + 'returnheaderslist' => $this->generateReturnHeadersTemplate($docs), | ||
188 | + 'returnparamslist' => $this->generateReturnParamsTemplate($docs), | ||
189 | + 'return' => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '', | ||
190 | + ]; | ||
191 | + $counter++; | ||
192 | + } | ||
193 | + } | ||
194 | + | ||
195 | + return $docslist; | ||
196 | + } | ||
197 | + | ||
198 | + public function getView() | ||
199 | + { | ||
200 | + return $this->view; | ||
201 | + } | ||
202 | + | ||
203 | + /** | ||
204 | + * 渲染 | ||
205 | + * @param string $template | ||
206 | + * @param array $vars | ||
207 | + * @return string | ||
208 | + */ | ||
209 | + public function render($template, $vars = []) | ||
210 | + { | ||
211 | + $docslist = $this->parse(); | ||
212 | + | ||
213 | + return $this->view->display(file_get_contents($template), array_merge($vars, ['docslist' => $docslist])); | ||
214 | + } | ||
215 | + | ||
216 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\admin\command\Api\library; | ||
4 | + | ||
5 | +/** | ||
6 | + * Class imported from https://github.com/eriknyk/Annotations | ||
7 | + * @author Erik Amaru Ortiz https://github.com/eriknyk | ||
8 | + * | ||
9 | + * @license http://opensource.org/licenses/bsd-license.php The BSD License | ||
10 | + * @author Calin Rada <rada.calin@gmail.com> | ||
11 | + */ | ||
12 | +class Extractor | ||
13 | +{ | ||
14 | + | ||
15 | + /** | ||
16 | + * Static array to store already parsed annotations | ||
17 | + * @var array | ||
18 | + */ | ||
19 | + private static $annotationCache; | ||
20 | + | ||
21 | + /** | ||
22 | + * Indicates that annotations should has strict behavior, 'false' by default | ||
23 | + * @var boolean | ||
24 | + */ | ||
25 | + private $strict = false; | ||
26 | + | ||
27 | + /** | ||
28 | + * Stores the default namespace for Objects instance, usually used on methods like getMethodAnnotationsObjects() | ||
29 | + * @var string | ||
30 | + */ | ||
31 | + public $defaultNamespace = ''; | ||
32 | + | ||
33 | + /** | ||
34 | + * Sets strict variable to true/false | ||
35 | + * @param bool $value boolean value to indicate that annotations to has strict behavior | ||
36 | + */ | ||
37 | + public function setStrict($value) | ||
38 | + { | ||
39 | + $this->strict = (bool) $value; | ||
40 | + } | ||
41 | + | ||
42 | + /** | ||
43 | + * Sets default namespace to use in object instantiation | ||
44 | + * @param string $namespace default namespace | ||
45 | + */ | ||
46 | + public function setDefaultNamespace($namespace) | ||
47 | + { | ||
48 | + $this->defaultNamespace = $namespace; | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Gets default namespace used in object instantiation | ||
53 | + * @return string $namespace default namespace | ||
54 | + */ | ||
55 | + public function getDefaultAnnotationNamespace() | ||
56 | + { | ||
57 | + return $this->defaultNamespace; | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Gets all anotations with pattern @SomeAnnotation() from a given class | ||
62 | + * | ||
63 | + * @param string $className class name to get annotations | ||
64 | + * @return array self::$annotationCache all annotated elements | ||
65 | + */ | ||
66 | + public static function getClassAnnotations($className) | ||
67 | + { | ||
68 | + if (!isset(self::$annotationCache[$className])) | ||
69 | + { | ||
70 | + $class = new \ReflectionClass($className); | ||
71 | + self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment()); | ||
72 | + } | ||
73 | + | ||
74 | + return self::$annotationCache[$className]; | ||
75 | + } | ||
76 | + | ||
77 | + public static function getAllClassAnnotations($className) | ||
78 | + { | ||
79 | + $class = new \ReflectionClass($className); | ||
80 | + | ||
81 | + foreach ($class->getMethods() as $object) | ||
82 | + { | ||
83 | + self::$annotationCache['annotations'][$className][$object->name] = self::getMethodAnnotations($className, $object->name); | ||
84 | + } | ||
85 | + | ||
86 | + return self::$annotationCache['annotations']; | ||
87 | + } | ||
88 | + | ||
89 | + /** | ||
90 | + * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class | ||
91 | + * | ||
92 | + * @param string $className class name | ||
93 | + * @param string $methodName method name to get annotations | ||
94 | + * @return array self::$annotationCache all annotated elements of a method given | ||
95 | + */ | ||
96 | + public static function getMethodAnnotations($className, $methodName) | ||
97 | + { | ||
98 | + if (!isset(self::$annotationCache[$className . '::' . $methodName])) | ||
99 | + { | ||
100 | + try | ||
101 | + { | ||
102 | + $method = new \ReflectionMethod($className, $methodName); | ||
103 | + $class = new \ReflectionClass($className); | ||
104 | + if (!$method->isPublic() || $method->isConstructor()) | ||
105 | + { | ||
106 | + $annotations = array(); | ||
107 | + } | ||
108 | + else | ||
109 | + { | ||
110 | + $annotations = self::consolidateAnnotations($method, $class); | ||
111 | + } | ||
112 | + } | ||
113 | + catch (\ReflectionException $e) | ||
114 | + { | ||
115 | + $annotations = array(); | ||
116 | + } | ||
117 | + | ||
118 | + self::$annotationCache[$className . '::' . $methodName] = $annotations; | ||
119 | + } | ||
120 | + | ||
121 | + return self::$annotationCache[$className . '::' . $methodName]; | ||
122 | + } | ||
123 | + | ||
124 | + /** | ||
125 | + * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class | ||
126 | + * and instance its abcAnnotation class | ||
127 | + * | ||
128 | + * @param string $className class name | ||
129 | + * @param string $methodName method name to get annotations | ||
130 | + * @return array self::$annotationCache all annotated objects of a method given | ||
131 | + */ | ||
132 | + public function getMethodAnnotationsObjects($className, $methodName) | ||
133 | + { | ||
134 | + $annotations = $this->getMethodAnnotations($className, $methodName); | ||
135 | + $objects = array(); | ||
136 | + | ||
137 | + $i = 0; | ||
138 | + | ||
139 | + foreach ($annotations as $annotationClass => $listParams) | ||
140 | + { | ||
141 | + $annotationClass = ucfirst($annotationClass); | ||
142 | + $class = $this->defaultNamespace . $annotationClass . 'Annotation'; | ||
143 | + | ||
144 | + // verify is the annotation class exists, depending if Annotations::strict is true | ||
145 | + // if not, just skip the annotation instance creation. | ||
146 | + if (!class_exists($class)) | ||
147 | + { | ||
148 | + if ($this->strict) | ||
149 | + { | ||
150 | + throw new Exception(sprintf('Runtime Error: Annotation Class Not Found: %s', $class)); | ||
151 | + } | ||
152 | + else | ||
153 | + { | ||
154 | + // silent skip & continue | ||
155 | + continue; | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + if (empty($objects[$annotationClass])) | ||
160 | + { | ||
161 | + $objects[$annotationClass] = new $class(); | ||
162 | + } | ||
163 | + | ||
164 | + foreach ($listParams as $params) | ||
165 | + { | ||
166 | + if (is_array($params)) | ||
167 | + { | ||
168 | + foreach ($params as $key => $value) | ||
169 | + { | ||
170 | + $objects[$annotationClass]->set($key, $value); | ||
171 | + } | ||
172 | + } | ||
173 | + else | ||
174 | + { | ||
175 | + $objects[$annotationClass]->set($i++, $params); | ||
176 | + } | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + return $objects; | ||
181 | + } | ||
182 | + | ||
183 | + private static function consolidateAnnotations($method, $class) | ||
184 | + { | ||
185 | + $dockblockClass = $class->getDocComment(); | ||
186 | + $docblockMethod = $method->getDocComment(); | ||
187 | + $methodName = $method->getName(); | ||
188 | + | ||
189 | + $methodAnnotations = self::parseAnnotations($docblockMethod); | ||
190 | + $classAnnotations = self::parseAnnotations($dockblockClass); | ||
191 | + if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') | ||
192 | + { | ||
193 | + return []; | ||
194 | + } | ||
195 | + | ||
196 | + $properties = $class->getDefaultProperties(); | ||
197 | + $noNeedLogin = isset($properties['noNeedLogin']) ? is_array($properties['noNeedLogin']) ? $properties['noNeedLogin'] : [$properties['noNeedLogin']] : []; | ||
198 | + $noNeedRight = isset($properties['noNeedRight']) ? is_array($properties['noNeedRight']) ? $properties['noNeedRight'] : [$properties['noNeedRight']] : []; | ||
199 | + | ||
200 | + preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $docblockMethod), $methodArr); | ||
201 | + preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $dockblockClass), $classArr); | ||
202 | + | ||
203 | + $methodTitle = isset($methodArr[1]) && isset($methodArr[1][0]) ? $methodArr[1][0] : ''; | ||
204 | + $classTitle = isset($classArr[1]) && isset($classArr[1][0]) ? $classArr[1][0] : ''; | ||
205 | + | ||
206 | + if (!isset($methodAnnotations['ApiMethod'])) | ||
207 | + { | ||
208 | + $methodAnnotations['ApiMethod'] = ['get']; | ||
209 | + } | ||
210 | + if (!isset($methodAnnotations['ApiSummary'])) | ||
211 | + { | ||
212 | + $methodAnnotations['ApiSummary'] = [$methodTitle]; | ||
213 | + } | ||
214 | + | ||
215 | + if ($methodAnnotations) | ||
216 | + { | ||
217 | + foreach ($classAnnotations as $name => $valueClass) | ||
218 | + { | ||
219 | + if (count($valueClass) !== 1) | ||
220 | + { | ||
221 | + continue; | ||
222 | + } | ||
223 | + | ||
224 | + if ($name === 'ApiRoute') | ||
225 | + { | ||
226 | + if (isset($methodAnnotations[$name])) | ||
227 | + { | ||
228 | + $methodAnnotations[$name] = [rtrim($valueClass[0], '/') . $methodAnnotations[$name][0]]; | ||
229 | + } | ||
230 | + else | ||
231 | + { | ||
232 | + $methodAnnotations[$name] = [rtrim($valueClass[0], '/') . '/' . $method->getName()]; | ||
233 | + } | ||
234 | + } | ||
235 | + | ||
236 | + if ($name === 'ApiSector') | ||
237 | + { | ||
238 | + $methodAnnotations[$name] = $valueClass; | ||
239 | + } | ||
240 | + } | ||
241 | + } | ||
242 | + if (!isset($methodAnnotations['ApiTitle'])) | ||
243 | + { | ||
244 | + $methodAnnotations['ApiTitle'] = [$methodTitle]; | ||
245 | + } | ||
246 | + if (!isset($methodAnnotations['ApiRoute'])) | ||
247 | + { | ||
248 | + $urlArr = []; | ||
249 | + $className = $class->getName(); | ||
250 | + | ||
251 | + list($prefix, $suffix) = explode('\\' . \think\Config::get('url_controller_layer') . '\\', $className); | ||
252 | + $prefixArr = explode('\\', $prefix); | ||
253 | + $suffixArr = explode('\\', $suffix); | ||
254 | + if ($prefixArr[0] == \think\Config::get('app_namespace')) | ||
255 | + { | ||
256 | + $prefixArr[0] = ''; | ||
257 | + } | ||
258 | + $urlArr = array_merge($urlArr, $prefixArr); | ||
259 | + $urlArr[] = implode('.', array_map(function($item) { | ||
260 | + return \think\Loader::parseName($item); | ||
261 | + }, $suffixArr)); | ||
262 | + $urlArr[] = $method->getName(); | ||
263 | + $methodAnnotations['ApiRoute'] = [implode('/', $urlArr)]; | ||
264 | + } | ||
265 | + if (!isset($methodAnnotations['ApiSector'])) | ||
266 | + { | ||
267 | + $methodAnnotations['ApiSector'] = isset($classAnnotations['ApiSector']) ? $classAnnotations['ApiSector'] : [$classTitle]; | ||
268 | + } | ||
269 | + if (!isset($methodAnnotations['ApiParams'])) | ||
270 | + { | ||
271 | + $params = self::parseCustomAnnotations($docblockMethod, 'param'); | ||
272 | + foreach ($params as $k => $v) | ||
273 | + { | ||
274 | + $arr = explode(' ', preg_replace("/[\s]+/", " ", $v)); | ||
275 | + $methodAnnotations['ApiParams'][] = [ | ||
276 | + 'name' => isset($arr[1]) ? str_replace('$', '', $arr[1]) : '', | ||
277 | + 'nullable' => false, | ||
278 | + 'type' => isset($arr[0]) ? $arr[0] : 'string', | ||
279 | + 'description' => isset($arr[2]) ? $arr[2] : '' | ||
280 | + ]; | ||
281 | + } | ||
282 | + } | ||
283 | + $methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)]; | ||
284 | + $methodAnnotations['ApiPermissionRight'] = [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)]; | ||
285 | + return $methodAnnotations; | ||
286 | + } | ||
287 | + | ||
288 | + /** | ||
289 | + * Parse annotations | ||
290 | + * | ||
291 | + * @param string $docblock | ||
292 | + * @param string $name | ||
293 | + * @return array parsed annotations params | ||
294 | + */ | ||
295 | + private static function parseCustomAnnotations($docblock, $name = 'param') | ||
296 | + { | ||
297 | + $annotations = array(); | ||
298 | + | ||
299 | + $docblock = substr($docblock, 3, -2); | ||
300 | + if (preg_match_all('/@' . $name . '(?:\s*(?:\(\s*)?(.*?)(?:\s*\))?)??\s*(?:\n|\*\/)/', $docblock, $matches)) | ||
301 | + { | ||
302 | + foreach ($matches[1] as $k => $v) | ||
303 | + { | ||
304 | + $annotations[] = $v; | ||
305 | + } | ||
306 | + } | ||
307 | + return $annotations; | ||
308 | + } | ||
309 | + | ||
310 | + /** | ||
311 | + * Parse annotations | ||
312 | + * | ||
313 | + * @param string $docblock | ||
314 | + * @return array parsed annotations params | ||
315 | + */ | ||
316 | + private static function parseAnnotations($docblock) | ||
317 | + { | ||
318 | + $annotations = array(); | ||
319 | + | ||
320 | + // Strip away the docblock header and footer to ease parsing of one line annotations | ||
321 | + $docblock = substr($docblock, 3, -2); | ||
322 | + if (preg_match_all('/@(?<name>[A-Za-z_-]+)[\s\t]*\((?<args>(?:(?!\)).)*)\)\r?/s', $docblock, $matches)) | ||
323 | + { | ||
324 | + $numMatches = count($matches[0]); | ||
325 | + | ||
326 | + for ($i = 0; $i < $numMatches; ++$i) | ||
327 | + { | ||
328 | + // annotations has arguments | ||
329 | + if (isset($matches['args'][$i])) | ||
330 | + { | ||
331 | + $argsParts = trim($matches['args'][$i]); | ||
332 | + $name = $matches['name'][$i]; | ||
333 | + $value = self::parseArgs($argsParts); | ||
334 | + } | ||
335 | + else | ||
336 | + { | ||
337 | + $value = array(); | ||
338 | + } | ||
339 | + | ||
340 | + $annotations[$name][] = $value; | ||
341 | + } | ||
342 | + } | ||
343 | + | ||
344 | + return $annotations; | ||
345 | + } | ||
346 | + | ||
347 | + /** | ||
348 | + * Parse individual annotation arguments | ||
349 | + * | ||
350 | + * @param string $content arguments string | ||
351 | + * @return array annotated arguments | ||
352 | + */ | ||
353 | + private static function parseArgs($content) | ||
354 | + { | ||
355 | + // Replace initial stars | ||
356 | + $content = preg_replace('/^\s*\*/m', '', $content); | ||
357 | + | ||
358 | + $data = array(); | ||
359 | + $len = strlen($content); | ||
360 | + $i = 0; | ||
361 | + $var = ''; | ||
362 | + $val = ''; | ||
363 | + $level = 1; | ||
364 | + | ||
365 | + $prevDelimiter = ''; | ||
366 | + $nextDelimiter = ''; | ||
367 | + $nextToken = ''; | ||
368 | + $composing = false; | ||
369 | + $type = 'plain'; | ||
370 | + $delimiter = null; | ||
371 | + $quoted = false; | ||
372 | + $tokens = array('"', '"', '{', '}', ',', '='); | ||
373 | + | ||
374 | + while ($i <= $len) | ||
375 | + { | ||
376 | + $prev_c = substr($content, $i - 1, 1); | ||
377 | + $c = substr($content, $i++, 1); | ||
378 | + | ||
379 | + if ($c === '"' && $prev_c !== "\\") | ||
380 | + { | ||
381 | + $delimiter = $c; | ||
382 | + //open delimiter | ||
383 | + if (!$composing && empty($prevDelimiter) && empty($nextDelimiter)) | ||
384 | + { | ||
385 | + $prevDelimiter = $nextDelimiter = $delimiter; | ||
386 | + $val = ''; | ||
387 | + $composing = true; | ||
388 | + $quoted = true; | ||
389 | + } | ||
390 | + else | ||
391 | + { | ||
392 | + // close delimiter | ||
393 | + if ($c !== $nextDelimiter) | ||
394 | + { | ||
395 | + throw new Exception(sprintf( | ||
396 | + "Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c | ||
397 | + )); | ||
398 | + } | ||
399 | + | ||
400 | + // validating syntax | ||
401 | + if ($i < $len) | ||
402 | + { | ||
403 | + if (',' !== substr($content, $i, 1) && '\\' !== $prev_c) | ||
404 | + { | ||
405 | + throw new Exception(sprintf( | ||
406 | + "Parse Error: missing comma separator near: ...%s<--", substr($content, ($i - 10), $i) | ||
407 | + )); | ||
408 | + } | ||
409 | + } | ||
410 | + | ||
411 | + $prevDelimiter = $nextDelimiter = ''; | ||
412 | + $composing = false; | ||
413 | + $delimiter = null; | ||
414 | + } | ||
415 | + } | ||
416 | + elseif (!$composing && in_array($c, $tokens)) | ||
417 | + { | ||
418 | + switch ($c) | ||
419 | + { | ||
420 | + case '=': | ||
421 | + $prevDelimiter = $nextDelimiter = ''; | ||
422 | + $level = 2; | ||
423 | + $composing = false; | ||
424 | + $type = 'assoc'; | ||
425 | + $quoted = false; | ||
426 | + break; | ||
427 | + case ',': | ||
428 | + $level = 3; | ||
429 | + | ||
430 | + // If composing flag is true yet, | ||
431 | + // it means that the string was not enclosed, so it is parsing error. | ||
432 | + if ($composing === true && !empty($prevDelimiter) && !empty($nextDelimiter)) | ||
433 | + { | ||
434 | + throw new Exception(sprintf( | ||
435 | + "Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c | ||
436 | + )); | ||
437 | + } | ||
438 | + | ||
439 | + $prevDelimiter = $nextDelimiter = ''; | ||
440 | + break; | ||
441 | + case '{': | ||
442 | + $subc = ''; | ||
443 | + $subComposing = true; | ||
444 | + | ||
445 | + while ($i <= $len) | ||
446 | + { | ||
447 | + $c = substr($content, $i++, 1); | ||
448 | + | ||
449 | + if (isset($delimiter) && $c === $delimiter) | ||
450 | + { | ||
451 | + throw new Exception(sprintf( | ||
452 | + "Parse Error: Composite variable is not enclosed correctly." | ||
453 | + )); | ||
454 | + } | ||
455 | + | ||
456 | + if ($c === '}') | ||
457 | + { | ||
458 | + $subComposing = false; | ||
459 | + break; | ||
460 | + } | ||
461 | + $subc .= $c; | ||
462 | + } | ||
463 | + | ||
464 | + // if the string is composing yet means that the structure of var. never was enclosed with '}' | ||
465 | + if ($subComposing) | ||
466 | + { | ||
467 | + throw new Exception(sprintf( | ||
468 | + "Parse Error: Composite variable is not enclosed correctly. near: ...%s'", $subc | ||
469 | + )); | ||
470 | + } | ||
471 | + | ||
472 | + $val = self::parseArgs($subc); | ||
473 | + break; | ||
474 | + } | ||
475 | + } | ||
476 | + else | ||
477 | + { | ||
478 | + if ($level == 1) | ||
479 | + { | ||
480 | + $var .= $c; | ||
481 | + } | ||
482 | + elseif ($level == 2) | ||
483 | + { | ||
484 | + $val .= $c; | ||
485 | + } | ||
486 | + } | ||
487 | + | ||
488 | + if ($level === 3 || $i === $len) | ||
489 | + { | ||
490 | + if ($type == 'plain' && $i === $len) | ||
491 | + { | ||
492 | + $data = self::castValue($var); | ||
493 | + } | ||
494 | + else | ||
495 | + { | ||
496 | + $data[trim($var)] = self::castValue($val, !$quoted); | ||
497 | + } | ||
498 | + | ||
499 | + $level = 1; | ||
500 | + $var = $val = ''; | ||
501 | + $composing = false; | ||
502 | + $quoted = false; | ||
503 | + } | ||
504 | + } | ||
505 | + | ||
506 | + return $data; | ||
507 | + } | ||
508 | + | ||
509 | + /** | ||
510 | + * Try determinate the original type variable of a string | ||
511 | + * | ||
512 | + * @param string $val string containing possibles variables that can be cast to bool or int | ||
513 | + * @param boolean $trim indicate if the value passed should be trimmed after to try cast | ||
514 | + * @return mixed returns the value converted to original type if was possible | ||
515 | + */ | ||
516 | + private static function castValue($val, $trim = false) | ||
517 | + { | ||
518 | + if (is_array($val)) | ||
519 | + { | ||
520 | + foreach ($val as $key => $value) | ||
521 | + { | ||
522 | + $val[$key] = self::castValue($value); | ||
523 | + } | ||
524 | + } | ||
525 | + elseif (is_string($val)) | ||
526 | + { | ||
527 | + if ($trim) | ||
528 | + { | ||
529 | + $val = trim($val); | ||
530 | + } | ||
531 | + $val = stripslashes($val); | ||
532 | + $tmp = strtolower($val); | ||
533 | + | ||
534 | + if ($tmp === 'false' || $tmp === 'true') | ||
535 | + { | ||
536 | + $val = $tmp === 'true'; | ||
537 | + } | ||
538 | + elseif (is_numeric($val)) | ||
539 | + { | ||
540 | + return $val + 0; | ||
541 | + } | ||
542 | + | ||
543 | + unset($tmp); | ||
544 | + } | ||
545 | + | ||
546 | + return $val; | ||
547 | + } | ||
548 | + | ||
549 | +} |
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | + <head> | ||
4 | + <meta charset="utf-8"> | ||
5 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
7 | + <meta name="description" content=""> | ||
8 | + <meta name="author" content="{$config.author}"> | ||
9 | + <title>{$config.title}</title> | ||
10 | + <link href="https://cdn.bootcss.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> | ||
11 | + <style type="text/css"> | ||
12 | + body { padding-top: 70px; margin-bottom: 15px; } | ||
13 | + .tab-pane { padding-top: 10px; } | ||
14 | + .mt0 { margin-top: 0px; } | ||
15 | + .footer { font-size: 12px; color: #666; } | ||
16 | + .label { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; } | ||
17 | + .string { color: green; } | ||
18 | + .number { color: darkorange; } | ||
19 | + .boolean { color: blue; } | ||
20 | + .null { color: magenta; } | ||
21 | + .key { color: red; } | ||
22 | + .popover { max-width: 400px; max-height: 400px; overflow-y: auto;} | ||
23 | + </style> | ||
24 | + </head> | ||
25 | + <body> | ||
26 | + <!-- Fixed navbar --> | ||
27 | + <div class="navbar navbar-default navbar-fixed-top" role="navigation"> | ||
28 | + <div class="container"> | ||
29 | + <div class="navbar-header"> | ||
30 | + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> | ||
31 | + <span class="sr-only">Toggle navigation</span> | ||
32 | + <span class="icon-bar"></span> | ||
33 | + <span class="icon-bar"></span> | ||
34 | + <span class="icon-bar"></span> | ||
35 | + </button> | ||
36 | + <a class="navbar-brand" href="http://www.fastadmin.net" target="_blank">{$config.title}</a> | ||
37 | + </div> | ||
38 | + <div class="navbar-collapse collapse"> | ||
39 | + <form class="navbar-form navbar-right"> | ||
40 | + <div class="form-group"> | ||
41 | + Token: | ||
42 | + </div> | ||
43 | + <div class="form-group"> | ||
44 | + <input type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Tokentips}" placeholder="token" id="token" /> | ||
45 | + </div> | ||
46 | + <div class="form-group"> | ||
47 | + Apiurl: | ||
48 | + </div> | ||
49 | + <div class="form-group"> | ||
50 | + <input id="apiUrl" type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Apiurltips}" placeholder="https://api.mydomain.com" value="{$config.apiurl}" /> | ||
51 | + </div> | ||
52 | + <div class="form-group"> | ||
53 | + <button type="button" class="btn btn-success btn-sm" data-toggle="tooltip" title="{$lang.Savetips}" id="save_data"> | ||
54 | + <span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> | ||
55 | + </button> | ||
56 | + </div> | ||
57 | + </form> | ||
58 | + </div><!--/.nav-collapse --> | ||
59 | + </div> | ||
60 | + </div> | ||
61 | + | ||
62 | + <div class="container"> | ||
63 | + <div class="panel-group" id="accordion"> | ||
64 | + {foreach name="docslist" id="docs"} | ||
65 | + <h2>{$key}</h2> | ||
66 | + <hr> | ||
67 | + {foreach name="docs" id="api" } | ||
68 | + <div class="panel panel-default"> | ||
69 | + <div class="panel-heading"> | ||
70 | + <h4 class="panel-title"> | ||
71 | + <span class="label {$api.method_label}">{$api.method|strtoupper}</span> <a data-toggle="collapse" data-parent="#accordion{$api.id}" href="#collapseOne{$api.id}"> {$api.route}</a> | ||
72 | + </h4> | ||
73 | + </div> | ||
74 | + <div id="collapseOne{$api.id}" class="panel-collapse collapse"> | ||
75 | + <div class="panel-body"> | ||
76 | + | ||
77 | + <!-- Nav tabs --> | ||
78 | + <ul class="nav nav-tabs" id="doctab{$api.id}"> | ||
79 | + <li class="active"><a href="#info{$api.id}" data-toggle="tab">{$lang.Info}</a></li> | ||
80 | + <li><a href="#sandbox{$api.id}" data-toggle="tab">{$lang.Sandbox}</a></li> | ||
81 | + <li><a href="#sample{$api.id}" data-toggle="tab">{$lang.Sampleoutput}</a></li> | ||
82 | + </ul> | ||
83 | + | ||
84 | + <!-- Tab panes --> | ||
85 | + <div class="tab-content"> | ||
86 | + | ||
87 | + <div class="tab-pane active" id="info{$api.id}"> | ||
88 | + <div class="well"> | ||
89 | + {$api.summary} | ||
90 | + </div> | ||
91 | + <div class="panel panel-default"> | ||
92 | + <div class="panel-heading"><strong>{$lang.Headers}</strong></div> | ||
93 | + <div class="panel-body"> | ||
94 | + {if $api.headerslist} | ||
95 | + <table class="table table-hover"> | ||
96 | + <thead> | ||
97 | + <tr> | ||
98 | + <th>{$lang.Name}</th> | ||
99 | + <th>{$lang.Type}</th> | ||
100 | + <th>{$lang.Required}</th> | ||
101 | + <th>{$lang.Description}</th> | ||
102 | + </tr> | ||
103 | + </thead> | ||
104 | + <tbody> | ||
105 | + {foreach name="api['headerslist']" id="header"} | ||
106 | + <tr> | ||
107 | + <td>{$header.name}</td> | ||
108 | + <td>{$header.type}</td> | ||
109 | + <td>{$header.required?'是':'否'}</td> | ||
110 | + <td>{$header.description}</td> | ||
111 | + </tr> | ||
112 | + {/foreach} | ||
113 | + </tbody> | ||
114 | + </table> | ||
115 | + {else /} | ||
116 | + 无 | ||
117 | + {/if} | ||
118 | + </div> | ||
119 | + </div> | ||
120 | + <div class="panel panel-default"> | ||
121 | + <div class="panel-heading"><strong>{$lang.Parameters}</strong></div> | ||
122 | + <div class="panel-body"> | ||
123 | + {if $api.paramslist} | ||
124 | + <table class="table table-hover"> | ||
125 | + <thead> | ||
126 | + <tr> | ||
127 | + <th>{$lang.Name}</th> | ||
128 | + <th>{$lang.Type}</th> | ||
129 | + <th>{$lang.Required}</th> | ||
130 | + <th>{$lang.Description}</th> | ||
131 | + </tr> | ||
132 | + </thead> | ||
133 | + <tbody> | ||
134 | + {foreach name="api['paramslist']" id="param"} | ||
135 | + <tr> | ||
136 | + <td>{$param.name}</td> | ||
137 | + <td>{$param.type}</td> | ||
138 | + <td>{:$param.required?'是':'否'}</td> | ||
139 | + <td>{$param.description}</td> | ||
140 | + </tr> | ||
141 | + {/foreach} | ||
142 | + </tbody> | ||
143 | + </table> | ||
144 | + {else /} | ||
145 | + 无 | ||
146 | + {/if} | ||
147 | + </div> | ||
148 | + </div> | ||
149 | + <div class="panel panel-default"> | ||
150 | + <div class="panel-heading"><strong>{$lang.Body}</strong></div> | ||
151 | + <div class="panel-body"> | ||
152 | + {$api.body|default='无'} | ||
153 | + </div> | ||
154 | + </div> | ||
155 | + </div><!-- #info --> | ||
156 | + | ||
157 | + <div class="tab-pane" id="sandbox{$api.id}"> | ||
158 | + <div class="row"> | ||
159 | + <div class="col-md-12"> | ||
160 | + {if $api.headerslist} | ||
161 | + <div class="panel panel-default"> | ||
162 | + <div class="panel-heading"><strong>{$lang.Headers}</strong></div> | ||
163 | + <div class="panel-body"> | ||
164 | + <div class="headers"> | ||
165 | + {foreach name="api['headerslist']" id="param"} | ||
166 | + <div class="form-group"> | ||
167 | + <label class="control-label" for="{$param.name}">{$param.name}</label> | ||
168 | + <input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description} - Ex: {$param.sample}" name="{$param.name}"> | ||
169 | + </div> | ||
170 | + {/foreach} | ||
171 | + </div> | ||
172 | + </div> | ||
173 | + </div> | ||
174 | + {/if} | ||
175 | + <div class="panel panel-default"> | ||
176 | + <div class="panel-heading"><strong>{$lang.Parameters}</strong></div> | ||
177 | + <div class="panel-body"> | ||
178 | + <form enctype="application/x-www-form-urlencoded" role="form" action="{$api.route}" method="{$api.method}" name="form{$api.id}" id="form{$api.id}"> | ||
179 | + {if $api.paramslist} | ||
180 | + {foreach name="api['paramslist']" id="param"} | ||
181 | + <div class="form-group"> | ||
182 | + <label class="control-label" for="{$param.name}">{$param.name}</label> | ||
183 | + <input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description}{if $param.sample} - 例: {$param.sample}{/if}" name="{$param.name}"> | ||
184 | + </div> | ||
185 | + {/foreach} | ||
186 | + {else /} | ||
187 | + <div class="form-group"> | ||
188 | + 无 | ||
189 | + </div> | ||
190 | + {/if} | ||
191 | + <div class="form-group"> | ||
192 | + <button type="submit" class="btn btn-success send" rel="{$api.id}">{$lang.Send}</button> | ||
193 | + </div> | ||
194 | + </form> | ||
195 | + </div> | ||
196 | + </div> | ||
197 | + <div class="panel panel-default"> | ||
198 | + <div class="panel-heading"><strong>{$lang.Response}</strong></div> | ||
199 | + <div class="panel-body"> | ||
200 | + <div class="row"> | ||
201 | + <div class="col-md-12" style="overflow-x:auto"> | ||
202 | + <pre id="response_headers{$api.id}"></pre> | ||
203 | + <pre id="response{$api.id}"></pre> | ||
204 | + </div> | ||
205 | + </div> | ||
206 | + </div> | ||
207 | + </div> | ||
208 | + <div class="panel panel-default"> | ||
209 | + <div class="panel-heading"><strong>{$lang.ReturnParameters}</strong></div> | ||
210 | + <div class="panel-body"> | ||
211 | + {if $api.returnparamslist} | ||
212 | + <table class="table table-hover"> | ||
213 | + <thead> | ||
214 | + <tr> | ||
215 | + <th>{$lang.Name}</th> | ||
216 | + <th>{$lang.Type}</th> | ||
217 | + <th>{$lang.Description}</th> | ||
218 | + </tr> | ||
219 | + </thead> | ||
220 | + <tbody> | ||
221 | + {foreach name="api['returnparamslist']" id="param"} | ||
222 | + <tr> | ||
223 | + <td>{$param.name}</td> | ||
224 | + <td>{$param.type}</td> | ||
225 | + <td>{$param.description}</td> | ||
226 | + </tr> | ||
227 | + {/foreach} | ||
228 | + </tbody> | ||
229 | + </table> | ||
230 | + {else /} | ||
231 | + 无 | ||
232 | + {/if} | ||
233 | + </div> | ||
234 | + </div> | ||
235 | + </div> | ||
236 | + </div> | ||
237 | + </div><!-- #sandbox --> | ||
238 | + | ||
239 | + <div class="tab-pane" id="sample{$api.id}"> | ||
240 | + <div class="row"> | ||
241 | + <div class="col-md-12"> | ||
242 | + <pre id="sample_response{$api.id}">{$api.return|default='无'}</pre> | ||
243 | + </div> | ||
244 | + </div> | ||
245 | + </div><!-- #sample --> | ||
246 | + | ||
247 | + </div><!-- .tab-content --> | ||
248 | + </div> | ||
249 | + </div> | ||
250 | + </div> | ||
251 | + {/foreach} | ||
252 | + {/foreach} | ||
253 | + </div> | ||
254 | + | ||
255 | + <hr> | ||
256 | + | ||
257 | + <div class="row mt0 footer"> | ||
258 | + <div class="col-md-6" align="left"> | ||
259 | + Generated on {:date('Y-m-d H:i:s')} | ||
260 | + </div> | ||
261 | + <div class="col-md-6" align="right"> | ||
262 | + <a href="http://www.fastadmin.net" target="_blank">FastAdmin</a> | ||
263 | + </div> | ||
264 | + </div> | ||
265 | + | ||
266 | + </div> <!-- /container --> | ||
267 | + | ||
268 | + <script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script> | ||
269 | + <script src="https://cdn.bootcss.com/bootstrap/3.0.3/js/bootstrap.min.js"></script> | ||
270 | + <script type="text/javascript"> | ||
271 | + function syntaxHighlight(json) { | ||
272 | + if (typeof json != 'string') { | ||
273 | + json = JSON.stringify(json, undefined, 2); | ||
274 | + } | ||
275 | + json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
276 | + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { | ||
277 | + var cls = 'number'; | ||
278 | + if (/^"/.test(match)) { | ||
279 | + if (/:$/.test(match)) { | ||
280 | + cls = 'key'; | ||
281 | + } else { | ||
282 | + cls = 'string'; | ||
283 | + } | ||
284 | + } else if (/true|false/.test(match)) { | ||
285 | + cls = 'boolean'; | ||
286 | + } else if (/null/.test(match)) { | ||
287 | + cls = 'null'; | ||
288 | + } | ||
289 | + return '<span class="' + cls + '">' + match + '</span>'; | ||
290 | + }); | ||
291 | + } | ||
292 | + | ||
293 | + function prepareStr(str) { | ||
294 | + try { | ||
295 | + return syntaxHighlight(JSON.stringify(JSON.parse(str.replace(/'/g, '"')), null, 2)); | ||
296 | + } catch (e) { | ||
297 | + return str; | ||
298 | + } | ||
299 | + } | ||
300 | + var storage = (function () { | ||
301 | + var uid = new Date; | ||
302 | + var storage; | ||
303 | + var result; | ||
304 | + try { | ||
305 | + (storage = window.localStorage).setItem(uid, uid); | ||
306 | + result = storage.getItem(uid) == uid; | ||
307 | + storage.removeItem(uid); | ||
308 | + return result && storage; | ||
309 | + } catch (exception) { | ||
310 | + } | ||
311 | + }()); | ||
312 | + | ||
313 | + $.fn.serializeObject = function () | ||
314 | + { | ||
315 | + var o = {}; | ||
316 | + var a = this.serializeArray(); | ||
317 | + $.each(a, function () { | ||
318 | + if (!this.value) { | ||
319 | + return; | ||
320 | + } | ||
321 | + if (o[this.name] !== undefined) { | ||
322 | + if (!o[this.name].push) { | ||
323 | + o[this.name] = [o[this.name]]; | ||
324 | + } | ||
325 | + o[this.name].push(this.value || ''); | ||
326 | + } else { | ||
327 | + o[this.name] = this.value || ''; | ||
328 | + } | ||
329 | + }); | ||
330 | + return o; | ||
331 | + }; | ||
332 | + | ||
333 | + $(document).ready(function () { | ||
334 | + | ||
335 | + if (storage) { | ||
336 | + $('#token').val(storage.getItem('token')); | ||
337 | + $('#apiUrl').val(storage.getItem('apiUrl')); | ||
338 | + } | ||
339 | + | ||
340 | + $('[data-toggle="tooltip"]').tooltip({ | ||
341 | + placement: 'bottom' | ||
342 | + }); | ||
343 | + | ||
344 | + $('code[id^=response]').hide(); | ||
345 | + | ||
346 | + $.each($('pre[id^=sample_response],pre[id^=sample_post_body]'), function () { | ||
347 | + if ($(this).html() == 'NA') { | ||
348 | + return; | ||
349 | + } | ||
350 | + var str = prepareStr($(this).html()); | ||
351 | + $(this).html(str); | ||
352 | + }); | ||
353 | + | ||
354 | + $("[data-toggle=popover]").popover({placement: 'right'}); | ||
355 | + | ||
356 | + $('[data-toggle=popover]').on('shown.bs.popover', function () { | ||
357 | + var $sample = $(this).parent().find(".popover-content"), | ||
358 | + str = $(this).data('content'); | ||
359 | + if (typeof str == "undefined" || str === "") { | ||
360 | + return; | ||
361 | + } | ||
362 | + var str = prepareStr(str); | ||
363 | + $sample.html('<pre>' + str + '</pre>'); | ||
364 | + }); | ||
365 | + | ||
366 | + $('body').on('click', '#save_data', function (e) { | ||
367 | + if (storage) { | ||
368 | + storage.setItem('token', $('#token').val()); | ||
369 | + storage.setItem('apiUrl', $('#apiUrl').val()); | ||
370 | + } else { | ||
371 | + alert('Your browser does not support local storage'); | ||
372 | + } | ||
373 | + }); | ||
374 | + | ||
375 | + $('body').on('click', '.send', function (e) { | ||
376 | + e.preventDefault(); | ||
377 | + var form = $(this).closest('form'); | ||
378 | + //added /g to get all the matched params instead of only first | ||
379 | + var matchedParamsInRoute = $(form).attr('action').match(/[^{]+(?=\})/g); | ||
380 | + var theId = $(this).attr('rel'); | ||
381 | + //keep a copy of action attribute in order to modify the copy | ||
382 | + //instead of the initial attribute | ||
383 | + var url = $(form).attr('action'); | ||
384 | + | ||
385 | + var serializedData = new FormData(); | ||
386 | + | ||
387 | + $(form).find('input').each(function (i, input) { | ||
388 | + if ($(input).attr('type') == 'file') { | ||
389 | + serializedData.append($(input).attr('name'), $(input)[0].files[0]); | ||
390 | + } else { | ||
391 | + serializedData.append($(input).attr('name'), $(input).val()) | ||
392 | + } | ||
393 | + }); | ||
394 | + | ||
395 | + var index, key, value; | ||
396 | + | ||
397 | + if (matchedParamsInRoute) { | ||
398 | + for (index = 0; index < matchedParamsInRoute.length; ++index) { | ||
399 | + try { | ||
400 | + key = matchedParamsInRoute[index]; | ||
401 | + value = serializedData[key]; | ||
402 | + if (typeof value == "undefined") | ||
403 | + value = ""; | ||
404 | + url = url.replace("{" + key + "}", value); | ||
405 | + delete serializedData[key]; | ||
406 | + } catch (err) { | ||
407 | + console.log(err); | ||
408 | + } | ||
409 | + } | ||
410 | + } | ||
411 | + | ||
412 | + var headers = {}; | ||
413 | + | ||
414 | + var token = $('#token').val(); | ||
415 | + if (token.length > 0) { | ||
416 | + headers[token] = token; | ||
417 | + } | ||
418 | + | ||
419 | + $("#sandbox" + theId + " .headers input[type=text]").each(function () { | ||
420 | + val = $(this).val(); | ||
421 | + if (val.length > 0) { | ||
422 | + headers[$(this).prop('name')] = val; | ||
423 | + } | ||
424 | + }); | ||
425 | + | ||
426 | + $.ajax({ | ||
427 | + url: $('#apiUrl').val() + url, | ||
428 | + data: $(form).attr('method') == 'get' ? $(form).serialize() : serializedData, | ||
429 | + type: $(form).attr('method') + '', | ||
430 | + dataType: 'json', | ||
431 | + contentType: false, | ||
432 | + processData: false, | ||
433 | + headers: headers, | ||
434 | + success: function (data, textStatus, xhr) { | ||
435 | + if (typeof data === 'object') { | ||
436 | + var str = JSON.stringify(data, null, 2); | ||
437 | + $('#response' + theId).html(syntaxHighlight(str)); | ||
438 | + } else { | ||
439 | + $('#response' + theId).html(data || ''); | ||
440 | + } | ||
441 | + $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders()); | ||
442 | + $('#response' + theId).show(); | ||
443 | + }, | ||
444 | + error: function (xhr, textStatus, error) { | ||
445 | + try { | ||
446 | + var str = JSON.stringify($.parseJSON(xhr.responseText), null, 2); | ||
447 | + } catch (e) { | ||
448 | + var str = xhr.responseText; | ||
449 | + } | ||
450 | + $('#response_headers' + theId).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders()); | ||
451 | + $('#response' + theId).html(syntaxHighlight(str)); | ||
452 | + $('#response' + theId).show(); | ||
453 | + } | ||
454 | + }); | ||
455 | + return false; | ||
456 | + }); | ||
457 | + }); | ||
458 | + </script> | ||
459 | + </body> | ||
460 | +</html> |
@@ -580,8 +580,8 @@ class Crud extends Command | @@ -580,8 +580,8 @@ class Crud extends Command | ||
580 | } | 580 | } |
581 | $formAddElement = $formEditElement = Form::hidden($fieldName, $no, array_merge(['checked' => ''], $attrArr)); | 581 | $formAddElement = $formEditElement = Form::hidden($fieldName, $no, array_merge(['checked' => ''], $attrArr)); |
582 | $attrArr['id'] = $fieldName . "-switch"; | 582 | $attrArr['id'] = $fieldName . "-switch"; |
583 | - $formAddElement .= sprintf(Form::label("{$attrArr['id']}", "%s abcdefg"), Form::checkbox($fieldName, $yes, $defaultValue === $yes, $attrArr)); | ||
584 | - $formEditElement .= sprintf(Form::label("{$attrArr['id']}", "%s abcdefg"), Form::checkbox($fieldName, $yes, 0, $attrArr)); | 583 | + $formAddElement .= sprintf(Form::label("{$attrArr['id']}", "%s {:__('Yes')}", ['class'=>'control-label']), Form::checkbox($fieldName, $yes, $defaultValue === $yes, $attrArr)); |
584 | + $formEditElement .= sprintf(Form::label("{$attrArr['id']}", "%s {:__('Yes')}", ['class'=>'control-label']), Form::checkbox($fieldName, $yes, 0, $attrArr)); | ||
585 | $formEditElement = str_replace('type="checkbox"', 'type="checkbox" {in name="' . "\$row.{$field}" . '" value="' . $yes . '"}checked{/in}', $formEditElement); | 585 | $formEditElement = str_replace('type="checkbox"', 'type="checkbox" {in name="' . "\$row.{$field}" . '" value="' . $yes . '"}checked{/in}', $formEditElement); |
586 | } | 586 | } |
587 | else if ($inputType == 'citypicker') | 587 | else if ($inputType == 'citypicker') |
@@ -963,6 +963,7 @@ EOD; | @@ -963,6 +963,7 @@ EOD; | ||
963 | if ($content || !Lang::has($field)) | 963 | if ($content || !Lang::has($field)) |
964 | { | 964 | { |
965 | $itemArr = []; | 965 | $itemArr = []; |
966 | + $content = str_replace(',', ',', $content); | ||
966 | if (stripos($content, ':') !== false && stripos($content, ',') && stripos($content, '=') !== false) | 967 | if (stripos($content, ':') !== false && stripos($content, ',') && stripos($content, '=') !== false) |
967 | { | 968 | { |
968 | list($fieldLang, $item) = explode(':', $content); | 969 | list($fieldLang, $item) = explode(':', $content); |
@@ -997,6 +998,7 @@ EOD; | @@ -997,6 +998,7 @@ EOD; | ||
997 | /** | 998 | /** |
998 | * 读取数据和语言数组列表 | 999 | * 读取数据和语言数组列表 |
999 | * @param array $arr | 1000 | * @param array $arr |
1001 | + * @param boolean $withTpl | ||
1000 | * @return array | 1002 | * @return array |
1001 | */ | 1003 | */ |
1002 | protected function getLangArray($arr, $withTpl = TRUE) | 1004 | protected function getLangArray($arr, $withTpl = TRUE) |
@@ -1035,6 +1037,7 @@ EOD; | @@ -1035,6 +1037,7 @@ EOD; | ||
1035 | protected function getItemArray($item, $field, $comment) | 1037 | protected function getItemArray($item, $field, $comment) |
1036 | { | 1038 | { |
1037 | $itemArr = []; | 1039 | $itemArr = []; |
1040 | + $comment = str_replace(',', ',', $comment); | ||
1038 | if (stripos($comment, ':') !== false && stripos($comment, ',') && stripos($comment, '=') !== false) | 1041 | if (stripos($comment, ':') !== false && stripos($comment, ',') && stripos($comment, '=') !== false) |
1039 | { | 1042 | { |
1040 | list($fieldLang, $item) = explode(':', $comment); | 1043 | list($fieldLang, $item) = explode(':', $comment); |
@@ -1255,7 +1258,7 @@ EOD; | @@ -1255,7 +1258,7 @@ EOD; | ||
1255 | { | 1258 | { |
1256 | $html .= ", operate:'RANGE', addclass:'datetimerange'"; | 1259 | $html .= ", operate:'RANGE', addclass:'datetimerange'"; |
1257 | } | 1260 | } |
1258 | - else if (in_array($datatype,['float', 'double', 'decimal'])) | 1261 | + else if (in_array($datatype, ['float', 'double', 'decimal'])) |
1259 | { | 1262 | { |
1260 | $html .= ", operate:'BETWEEN'"; | 1263 | $html .= ", operate:'BETWEEN'"; |
1261 | } | 1264 | } |
@@ -81,6 +81,8 @@ class Install extends Command | @@ -81,6 +81,8 @@ class Install extends Command | ||
81 | // 写入数据库配置 | 81 | // 写入数据库配置 |
82 | file_put_contents($dbConfigFile, $config); | 82 | file_put_contents($dbConfigFile, $config); |
83 | 83 | ||
84 | + \think\Cache::rm('__menu__'); | ||
85 | + | ||
84 | $output->info("Install Successed!"); | 86 | $output->info("Install Successed!"); |
85 | } | 87 | } |
86 | 88 |
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | 官网: http://www.fastadmin.net | 4 | 官网: http://www.fastadmin.net |
5 | 演示: http://demo.fastadmin.net | 5 | 演示: http://demo.fastadmin.net |
6 | 6 | ||
7 | - Date: 2017年09月15日 | 7 | + Date: 2018年03月07日 |
8 | */ | 8 | */ |
9 | 9 | ||
10 | SET FOREIGN_KEY_CHECKS = 0; | 10 | SET FOREIGN_KEY_CHECKS = 0; |
@@ -396,6 +396,9 @@ BEGIN; | @@ -396,6 +396,9 @@ BEGIN; | ||
396 | INSERT INTO `fa_test` VALUES (1, 0, 12, '12,13', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '描述', '广西壮族自治区/百色市/平果县', 0.00, 0, '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1499682285, 1499682526, 1499682526, 0, 1, 'normal', '1'); | 396 | INSERT INTO `fa_test` VALUES (1, 0, 12, '12,13', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '描述', '广西壮族自治区/百色市/平果县', 0.00, 0, '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1499682285, 1499682526, 1499682526, 0, 1, 'normal', '1'); |
397 | COMMIT; | 397 | COMMIT; |
398 | 398 | ||
399 | +-- ---------------------------- | ||
400 | +-- Table structure for fa_user | ||
401 | +-- ---------------------------- | ||
399 | DROP TABLE IF EXISTS `fa_user`; | 402 | DROP TABLE IF EXISTS `fa_user`; |
400 | CREATE TABLE `fa_user` ( | 403 | CREATE TABLE `fa_user` ( |
401 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', | 404 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', |
@@ -431,10 +434,16 @@ CREATE TABLE `fa_user` ( | @@ -431,10 +434,16 @@ CREATE TABLE `fa_user` ( | ||
431 | KEY `mobile` (`mobile`) | 434 | KEY `mobile` (`mobile`) |
432 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员表'; | 435 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员表'; |
433 | 436 | ||
437 | +-- ---------------------------- | ||
438 | +-- Records of fa_user | ||
439 | +-- ---------------------------- | ||
434 | BEGIN; | 440 | BEGIN; |
435 | INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', 'c13f62012fd6a8fdf06b3452a94430e5', 'rpR6Bv', 'admin@163.com', '13888888888', '/assets/img/avatar.png', 0, 0, '2017-04-15', '', 0, 1, 1, 1516170492, 1516171614, '127.0.0.1', 0, '127.0.0.1', 1491461418, 0, 1516171614, '', 'normal',''); | 441 | INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', 'c13f62012fd6a8fdf06b3452a94430e5', 'rpR6Bv', 'admin@163.com', '13888888888', '/assets/img/avatar.png', 0, 0, '2017-04-15', '', 0, 1, 1, 1516170492, 1516171614, '127.0.0.1', 0, '127.0.0.1', 1491461418, 0, 1516171614, '', 'normal',''); |
436 | COMMIT; | 442 | COMMIT; |
437 | 443 | ||
444 | +-- ---------------------------- | ||
445 | +-- Table structure for fa_user_group | ||
446 | +-- ---------------------------- | ||
438 | DROP TABLE IF EXISTS `fa_user_group`; | 447 | DROP TABLE IF EXISTS `fa_user_group`; |
439 | CREATE TABLE `fa_user_group` ( | 448 | CREATE TABLE `fa_user_group` ( |
440 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | 449 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, |
@@ -446,10 +455,16 @@ CREATE TABLE `fa_user_group` ( | @@ -446,10 +455,16 @@ CREATE TABLE `fa_user_group` ( | ||
446 | PRIMARY KEY (`id`) | 455 | PRIMARY KEY (`id`) |
447 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='会员组表'; | 456 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='会员组表'; |
448 | 457 | ||
458 | +-- ---------------------------- | ||
459 | +-- Records of fa_user_group | ||
460 | +-- ---------------------------- | ||
449 | BEGIN; | 461 | BEGIN; |
450 | INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1515386468, 1516168298, 'normal'); | 462 | INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1515386468, 1516168298, 'normal'); |
451 | COMMIT; | 463 | COMMIT; |
452 | 464 | ||
465 | +-- ---------------------------- | ||
466 | +-- Table structure for fa_user_rule | ||
467 | +-- ---------------------------- | ||
453 | DROP TABLE IF EXISTS `fa_user_rule`; | 468 | DROP TABLE IF EXISTS `fa_user_rule`; |
454 | CREATE TABLE `fa_user_rule` ( | 469 | CREATE TABLE `fa_user_rule` ( |
455 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | 470 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, |
@@ -465,6 +480,9 @@ CREATE TABLE `fa_user_rule` ( | @@ -465,6 +480,9 @@ CREATE TABLE `fa_user_rule` ( | ||
465 | PRIMARY KEY (`id`) | 480 | PRIMARY KEY (`id`) |
466 | ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='会员规则表'; | 481 | ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='会员规则表'; |
467 | 482 | ||
483 | +-- ---------------------------- | ||
484 | +-- Records of fa_user_rule | ||
485 | +-- ---------------------------- | ||
468 | BEGIN; | 486 | BEGIN; |
469 | INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', '前台', '', 1, 1516168079, 1516168079, 1, 'normal'); | 487 | INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', '前台', '', 1, 1516168079, 1516168079, 1, 'normal'); |
470 | INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API接口', '', 1, 1516168062, 1516168062, 2, 'normal'); | 488 | INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API接口', '', 1, 1516168062, 1516168062, 2, 'normal'); |
@@ -480,6 +498,9 @@ INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', '会员中心', '', | @@ -480,6 +498,9 @@ INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', '会员中心', '', | ||
480 | INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 3, 'normal'); | 498 | INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 3, 'normal'); |
481 | COMMIT; | 499 | COMMIT; |
482 | 500 | ||
501 | +-- ---------------------------- | ||
502 | +-- Table structure for fa_user_score_log | ||
503 | +-- ---------------------------- | ||
483 | DROP TABLE IF EXISTS `fa_user_score_log`; | 504 | DROP TABLE IF EXISTS `fa_user_score_log`; |
484 | CREATE TABLE `fa_user_score_log` ( | 505 | CREATE TABLE `fa_user_score_log` ( |
485 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | 506 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, |
@@ -492,6 +513,9 @@ CREATE TABLE `fa_user_score_log` ( | @@ -492,6 +513,9 @@ CREATE TABLE `fa_user_score_log` ( | ||
492 | PRIMARY KEY (`id`) | 513 | PRIMARY KEY (`id`) |
493 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='会员积分变动表'; | 514 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='会员积分变动表'; |
494 | 515 | ||
516 | +-- ---------------------------- | ||
517 | +-- Table structure for fa_user_token | ||
518 | +-- ---------------------------- | ||
495 | DROP TABLE IF EXISTS `fa_user_token`; | 519 | DROP TABLE IF EXISTS `fa_user_token`; |
496 | CREATE TABLE `fa_user_token` ( | 520 | CREATE TABLE `fa_user_token` ( |
497 | `token` varchar(50) NOT NULL COMMENT 'Token', | 521 | `token` varchar(50) NOT NULL COMMENT 'Token', |
@@ -501,4 +525,30 @@ CREATE TABLE `fa_user_token` ( | @@ -501,4 +525,30 @@ CREATE TABLE `fa_user_token` ( | ||
501 | PRIMARY KEY (`token`) | 525 | PRIMARY KEY (`token`) |
502 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员Token表'; | 526 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员Token表'; |
503 | 527 | ||
528 | +-- ---------------------------- | ||
529 | +-- Table structure for fa_version | ||
530 | +-- ---------------------------- | ||
531 | +DROP TABLE IF EXISTS `fa_version`; | ||
532 | +CREATE TABLE `fa_version` ( | ||
533 | + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', | ||
534 | + `oldversion` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '旧版本号', | ||
535 | + `newversion` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '新版本号', | ||
536 | + `packagesize` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '包大小', | ||
537 | + `content` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '升级内容', | ||
538 | + `downloadurl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '下载地址', | ||
539 | + `enforce` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '强制更新', | ||
540 | + `createtime` int(10) NOT NULL DEFAULT 0 COMMENT '创建时间', | ||
541 | + `updatetime` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间', | ||
542 | + `weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重', | ||
543 | + `status` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '状态', | ||
544 | + PRIMARY KEY (`id`) USING BTREE | ||
545 | +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '版本表' ROW_FORMAT = Compact; | ||
546 | + | ||
547 | +-- ---------------------------- | ||
548 | +-- Table structure for fa_version | ||
549 | +-- ---------------------------- | ||
550 | +BEGIN; | ||
551 | +INSERT INTO `fa_version` (`id`, `oldversion`, `newversion`, `packagesize`, `content`, `downloadurl`, `enforce`, `createtime`, `updatetime`, `weigh`, `status`) VALUES | ||
552 | +(1, '1.1.1,2', '1.2.1', '20M', '更新内容', 'http://www.fastadmin.net/download.html', 1, 1520425318, 0, 0, 'normal'); | ||
553 | +COMMIT; | ||
504 | SET FOREIGN_KEY_CHECKS = 1; | 554 | SET FOREIGN_KEY_CHECKS = 1; |
@@ -56,7 +56,6 @@ class Menu extends Command | @@ -56,7 +56,6 @@ class Menu extends Command | ||
56 | { | 56 | { |
57 | throw new Exception("There is no menu to delete"); | 57 | throw new Exception("There is no menu to delete"); |
58 | } | 58 | } |
59 | - $readyMenu = []; | ||
60 | $output->info("Are you sure you want to delete all those menu? Type 'yes' to continue: "); | 59 | $output->info("Are you sure you want to delete all those menu? Type 'yes' to continue: "); |
61 | $line = fgets(STDIN); | 60 | $line = fgets(STDIN); |
62 | if (trim($line) != 'yes') | 61 | if (trim($line) != 'yes') |
@@ -27,6 +27,7 @@ class Min extends Command | @@ -27,6 +27,7 @@ class Min extends Command | ||
27 | ->setName('min') | 27 | ->setName('min') |
28 | ->addOption('module', 'm', Option::VALUE_REQUIRED, 'module name(frontend or backend),use \'all\' when build all modules', null) | 28 | ->addOption('module', 'm', Option::VALUE_REQUIRED, 'module name(frontend or backend),use \'all\' when build all modules', null) |
29 | ->addOption('resource', 'r', Option::VALUE_REQUIRED, 'resource name(js or css),use \'all\' when build all resources', null) | 29 | ->addOption('resource', 'r', Option::VALUE_REQUIRED, 'resource name(js or css),use \'all\' when build all resources', null) |
30 | + ->addOption('optimize', 'o', Option::VALUE_OPTIONAL, 'optimize type(uglify|closure|none)', 'none') | ||
30 | ->setDescription('Compress js and css file'); | 31 | ->setDescription('Compress js and css file'); |
31 | } | 32 | } |
32 | 33 | ||
@@ -34,6 +35,7 @@ class Min extends Command | @@ -34,6 +35,7 @@ class Min extends Command | ||
34 | { | 35 | { |
35 | $module = $input->getOption('module') ?: ''; | 36 | $module = $input->getOption('module') ?: ''; |
36 | $resource = $input->getOption('resource') ?: ''; | 37 | $resource = $input->getOption('resource') ?: ''; |
38 | + $optimize = $input->getOption('optimize') ?: 'none'; | ||
37 | 39 | ||
38 | if (!$module || !in_array($module, ['frontend', 'backend', 'all'])) | 40 | if (!$module || !in_array($module, ['frontend', 'backend', 'all'])) |
39 | { | 41 | { |
@@ -89,6 +91,7 @@ class Min extends Command | @@ -89,6 +91,7 @@ class Min extends Command | ||
89 | 'cssBaseUrl' => $this->options['cssBaseUrl'], | 91 | 'cssBaseUrl' => $this->options['cssBaseUrl'], |
90 | 'jsBasePath' => str_replace(DS, '/', ROOT_PATH . $this->options['jsBaseUrl']), | 92 | 'jsBasePath' => str_replace(DS, '/', ROOT_PATH . $this->options['jsBaseUrl']), |
91 | 'cssBasePath' => str_replace(DS, '/', ROOT_PATH . $this->options['cssBaseUrl']), | 93 | 'cssBasePath' => str_replace(DS, '/', ROOT_PATH . $this->options['cssBaseUrl']), |
94 | + 'optimize' => $optimize, | ||
92 | 'ds' => DS, | 95 | 'ds' => DS, |
93 | ]; | 96 | ]; |
94 | 97 | ||
@@ -117,11 +120,19 @@ class Min extends Command | @@ -117,11 +120,19 @@ class Min extends Command | ||
117 | $output->info("Compress " . $data["{$res}BaseName"] . ".{$res}"); | 120 | $output->info("Compress " . $data["{$res}BaseName"] . ".{$res}"); |
118 | 121 | ||
119 | // 执行压缩 | 122 | // 执行压缩 |
120 | - echo exec("{$nodeExec} \"{$minPath}r.js\" -o \"{$tempFile}\" >> \"{$minPath}node.log\""); | 123 | + $command = "{$nodeExec} \"{$minPath}r.js\" -o \"{$tempFile}\" >> \"{$minPath}node.log\""; |
124 | + if ($output->isDebug()) | ||
125 | + { | ||
126 | + $output->warning($command); | ||
127 | + } | ||
128 | + echo exec($command); | ||
121 | } | 129 | } |
122 | } | 130 | } |
123 | 131 | ||
132 | + if (!$output->isDebug()) | ||
133 | + { | ||
124 | @unlink($tempFile); | 134 | @unlink($tempFile); |
135 | + } | ||
125 | 136 | ||
126 | $output->info("Build Successed!"); | 137 | $output->info("Build Successed!"); |
127 | } | 138 | } |
@@ -2,7 +2,8 @@ | @@ -2,7 +2,8 @@ | ||
2 | {%config%} | 2 | {%config%} |
3 | , | 3 | , |
4 | optimizeCss: "standard", | 4 | optimizeCss: "standard", |
5 | - optimize: "none", //可使用uglify|closure|none | 5 | + optimize: "{%optimize%}", //可使用uglify|closure|none |
6 | + preserveLicenseComments: false, | ||
6 | removeCombined: false, | 7 | removeCombined: false, |
7 | baseUrl: "{%jsBasePath%}", //JS文件所在的基础目录 | 8 | baseUrl: "{%jsBasePath%}", //JS文件所在的基础目录 |
8 | name: "{%jsBaseName%}", //来源文件,不包含后缀 | 9 | name: "{%jsBaseName%}", //来源文件,不包含后缀 |
@@ -5,6 +5,7 @@ namespace app\admin\controller; | @@ -5,6 +5,7 @@ namespace app\admin\controller; | ||
5 | use app\common\controller\Backend; | 5 | use app\common\controller\Backend; |
6 | use think\addons\AddonException; | 6 | use think\addons\AddonException; |
7 | use think\addons\Service; | 7 | use think\addons\Service; |
8 | +use think\Cache; | ||
8 | use think\Config; | 9 | use think\Config; |
9 | use think\Exception; | 10 | use think\Exception; |
10 | 11 | ||
@@ -190,6 +191,7 @@ class Addon extends Backend | @@ -190,6 +191,7 @@ class Addon extends Backend | ||
190 | $action = $action == 'enable' ? $action : 'disable'; | 191 | $action = $action == 'enable' ? $action : 'disable'; |
191 | //调用启用、禁用的方法 | 192 | //调用启用、禁用的方法 |
192 | Service::$action($name, $force); | 193 | Service::$action($name, $force); |
194 | + Cache::rm('__menu__'); | ||
193 | $this->success(__('Operate successful')); | 195 | $this->success(__('Operate successful')); |
194 | } | 196 | } |
195 | catch (AddonException $e) | 197 | catch (AddonException $e) |
@@ -314,6 +316,7 @@ class Addon extends Backend | @@ -314,6 +316,7 @@ class Addon extends Backend | ||
314 | ]; | 316 | ]; |
315 | //调用更新的方法 | 317 | //调用更新的方法 |
316 | Service::upgrade($name, $extend); | 318 | Service::upgrade($name, $extend); |
319 | + Cache::rm('__menu__'); | ||
317 | $this->success(__('Operate successful')); | 320 | $this->success(__('Operate successful')); |
318 | } | 321 | } |
319 | catch (AddonException $e) | 322 | catch (AddonException $e) |
@@ -370,7 +373,10 @@ class Addon extends Backend | @@ -370,7 +373,10 @@ class Addon extends Backend | ||
370 | $list[] = $v; | 373 | $list[] = $v; |
371 | } | 374 | } |
372 | $total = count($list); | 375 | $total = count($list); |
376 | + if ($limit) | ||
377 | + { | ||
373 | $list = array_slice($list, $offset, $limit); | 378 | $list = array_slice($list, $offset, $limit); |
379 | + } | ||
374 | $result = array("total" => $total, "rows" => $list); | 380 | $result = array("total" => $total, "rows" => $list); |
375 | 381 | ||
376 | $callback = $this->request->get('callback') ? "jsonp" : "json"; | 382 | $callback = $this->request->get('callback') ? "jsonp" : "json"; |
@@ -29,13 +29,21 @@ class Index extends Backend | @@ -29,13 +29,21 @@ class Index extends Backend | ||
29 | */ | 29 | */ |
30 | public function index() | 30 | public function index() |
31 | { | 31 | { |
32 | - // | 32 | + //左侧菜单 |
33 | $menulist = $this->auth->getSidebar([ | 33 | $menulist = $this->auth->getSidebar([ |
34 | 'dashboard' => 'hot', | 34 | 'dashboard' => 'hot', |
35 | 'addon' => ['new', 'red', 'badge'], | 35 | 'addon' => ['new', 'red', 'badge'], |
36 | - 'auth/rule' => 'side', | 36 | + 'auth/rule' => __('Menu'), |
37 | 'general' => ['new', 'purple'], | 37 | 'general' => ['new', 'purple'], |
38 | ], $this->view->site['fixedpage']); | 38 | ], $this->view->site['fixedpage']); |
39 | + $action = $this->request->request('action'); | ||
40 | + if ($this->request->isPost()) | ||
41 | + { | ||
42 | + if ($action == 'refreshmenu') | ||
43 | + { | ||
44 | + $this->success('', null, ['menulist' => $menulist]); | ||
45 | + } | ||
46 | + } | ||
39 | $this->view->assign('menulist', $menulist); | 47 | $this->view->assign('menulist', $menulist); |
40 | $this->view->assign('title', __('Home')); | 48 | $this->view->assign('title', __('Home')); |
41 | return $this->view->fetch(); | 49 | return $this->view->fetch(); |
@@ -13,6 +13,6 @@ return [ | @@ -13,6 +13,6 @@ return [ | ||
13 | 'Menu tips' => '规则任意,不可重复,仅做层级显示,无需匹配控制器和方法', | 13 | 'Menu tips' => '规则任意,不可重复,仅做层级显示,无需匹配控制器和方法', |
14 | 'Node tips' => '控制器/方法名', | 14 | 'Node tips' => '控制器/方法名', |
15 | 'The non-menu rule must have parent' => '非菜单规则节点必须有父级', | 15 | 'The non-menu rule must have parent' => '非菜单规则节点必须有父级', |
16 | - 'If not necessary, use the command line to build rule' => '非必要情况下请直接使用命令行php think menu来生成', | 16 | + 'If not necessary, use the command line to build rule' => '非必要情况下请直接使用命令行<a href="http://doc.fastadmin.net/docs/command.html#一键生成菜单" target="_blank">php think menu</a>来生成', |
17 | 'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成', | 17 | 'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成', |
18 | ]; | 18 | ]; |
@@ -12,6 +12,8 @@ return [ | @@ -12,6 +12,8 @@ return [ | ||
12 | 'Avatar' => '头像', | 12 | 'Avatar' => '头像', |
13 | 'Level' => '等级', | 13 | 'Level' => '等级', |
14 | 'Gender' => '性别', | 14 | 'Gender' => '性别', |
15 | + 'Male' => '男', | ||
16 | + 'FeMale' => '女', | ||
15 | 'Birthday' => '生日', | 17 | 'Birthday' => '生日', |
16 | 'Bio' => '格言', | 18 | 'Bio' => '格言', |
17 | 'Score' => '积分', | 19 | 'Score' => '积分', |
@@ -273,7 +273,7 @@ class Auth extends \fast\Auth | @@ -273,7 +273,7 @@ class Auth extends \fast\Auth | ||
273 | $groupIds[] = $v['id']; | 273 | $groupIds[] = $v['id']; |
274 | } | 274 | } |
275 | // 取出所有分组 | 275 | // 取出所有分组 |
276 | - $groupList = model('AuthGroup')->all(['status' => 'normal']); | 276 | + $groupList = \app\admin\model\AuthGroup::where(['status' => 'normal'])->select(); |
277 | $objList = []; | 277 | $objList = []; |
278 | foreach ($groups as $K => $v) | 278 | foreach ($groups as $K => $v) |
279 | { | 279 | { |
@@ -310,8 +310,8 @@ class Auth extends \fast\Auth | @@ -310,8 +310,8 @@ class Auth extends \fast\Auth | ||
310 | if (!$this->isSuperAdmin()) | 310 | if (!$this->isSuperAdmin()) |
311 | { | 311 | { |
312 | $groupIds = $this->getChildrenGroupIds(false); | 312 | $groupIds = $this->getChildrenGroupIds(false); |
313 | - $authGroupList = model('AuthGroupAccess') | ||
314 | - ->field('uid,group_id') | 313 | + $authGroupList = \app\admin\model\AuthGroupAccess:: |
314 | + field('uid,group_id') | ||
315 | ->where('group_id', 'in', $groupIds) | 315 | ->where('group_id', 'in', $groupIds) |
316 | ->select(); | 316 | ->select(); |
317 | 317 | ||
@@ -407,7 +407,7 @@ class Auth extends \fast\Auth | @@ -407,7 +407,7 @@ class Auth extends \fast\Auth | ||
407 | $select_id = 0; | 407 | $select_id = 0; |
408 | $pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader'); | 408 | $pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader'); |
409 | // 必须将结果集转换为数组 | 409 | // 必须将结果集转换为数组 |
410 | - $ruleList = collection(model('AuthRule')->where('status', 'normal')->where('ismenu', 1)->order('weigh', 'desc')->cache("__menu__")->select())->toArray(); | 410 | + $ruleList = collection(\app\admin\model\AuthRule::where('status', 'normal')->where('ismenu', 1)->order('weigh', 'desc')->cache("__menu__")->select())->toArray(); |
411 | foreach ($ruleList as $k => &$v) | 411 | foreach ($ruleList as $k => &$v) |
412 | { | 412 | { |
413 | if (!in_array($v['name'], $userRule)) | 413 | if (!in_array($v['name'], $userRule)) |
@@ -267,7 +267,8 @@ trait Backend | @@ -267,7 +267,8 @@ trait Backend | ||
267 | { | 267 | { |
268 | $this->model->where($this->dataLimitField, 'in', $adminIds); | 268 | $this->model->where($this->dataLimitField, 'in', $adminIds); |
269 | } | 269 | } |
270 | - $count = $this->model->where($this->model->getPk(), 'in', $ids)->update($values); | 270 | + $this->model->where($this->model->getPk(), 'in', $ids); |
271 | + $count = $this->model->allowField(true)->isUpdate(true)->save($values); | ||
271 | if ($count) | 272 | if ($count) |
272 | { | 273 | { |
273 | $this->success(); | 274 | $this->success(); |
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | 2 | ||
3 | namespace app\admin\model; | 3 | namespace app\admin\model; |
4 | 4 | ||
5 | +use think\Cache; | ||
5 | use think\Model; | 6 | use think\Model; |
6 | 7 | ||
7 | class AuthRule extends Model | 8 | class AuthRule extends Model |
@@ -13,8 +14,16 @@ class AuthRule extends Model | @@ -13,8 +14,16 @@ class AuthRule extends Model | ||
13 | protected $createTime = 'createtime'; | 14 | protected $createTime = 'createtime'; |
14 | protected $updateTime = 'updatetime'; | 15 | protected $updateTime = 'updatetime'; |
15 | 16 | ||
17 | + protected static function init() | ||
18 | + { | ||
19 | + self::afterWrite(function ($row) { | ||
20 | + Cache::rm('__menu__'); | ||
21 | + }); | ||
22 | + } | ||
23 | + | ||
16 | public function getTitleAttr($value, $data) | 24 | public function getTitleAttr($value, $data) |
17 | { | 25 | { |
18 | return __($value); | 26 | return __($value); |
19 | } | 27 | } |
28 | + | ||
20 | } | 29 | } |
@@ -10,6 +10,12 @@ | @@ -10,6 +10,12 @@ | ||
10 | .payimg .alipaycode {position:absolute;left:265px;top:442px;} | 10 | .payimg .alipaycode {position:absolute;left:265px;top:442px;} |
11 | .payimg .wechatcode {position:absolute;left:660px;top:442px;} | 11 | .payimg .wechatcode {position:absolute;left:660px;top:442px;} |
12 | .thumbnail img{width:100%;} | 12 | .thumbnail img{width:100%;} |
13 | + .fixed-table-toolbar .pull-right.search { | ||
14 | + min-width: 300px; | ||
15 | + } | ||
16 | + .status-disabled .noimage { | ||
17 | + background:#d2d6de; | ||
18 | + } | ||
13 | </style> | 19 | </style> |
14 | <div id="warmtips" class="alert alert-dismissable alert-danger hide"> | 20 | <div id="warmtips" class="alert alert-dismissable alert-danger hide"> |
15 | <button type="button" class="close" data-dismiss="alert">×</button> | 21 | <button type="button" class="close" data-dismiss="alert">×</button> |
@@ -158,10 +164,10 @@ | @@ -158,10 +164,10 @@ | ||
158 | </table> | 164 | </table> |
159 | </script> | 165 | </script> |
160 | <script id="itemtpl" type="text/html"> | 166 | <script id="itemtpl" type="text/html"> |
161 | - <div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 mt-4"> | ||
162 | <% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %> | 167 | <% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %> |
163 | <% var label = labelarr[item.id % 5]; %> | 168 | <% var label = labelarr[item.id % 5]; %> |
164 | <% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %> | 169 | <% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %> |
170 | + <div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 mt-4 status-<%=addon ? (addon.state==1?'enabled':'disabled') : 'uninstalled'%>"> | ||
165 | <div class="thumbnail addon"> | 171 | <div class="thumbnail addon"> |
166 | <%if(addon){%> | 172 | <%if(addon){%> |
167 | <span> | 173 | <span> |
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | <label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label> | 31 | <label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label> |
32 | <div class="col-xs-12 col-sm-8"> | 32 | <div class="col-xs-12 col-sm-8"> |
33 | <div class="input-group input-groupp-md"> | 33 | <div class="input-group input-groupp-md"> |
34 | - <input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-dot" /> | 34 | + <input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-circle-o" /> |
35 | <a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a> | 35 | <a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a> |
36 | </div> | 36 | </div> |
37 | </div> | 37 | </div> |
1 | +<style> | ||
2 | + .bootstrap-table tr td .text-muted {color:#888;} | ||
3 | +</style> | ||
1 | <div class="panel panel-default panel-intro"> | 4 | <div class="panel panel-default panel-intro"> |
2 | {:build_heading()} | 5 | {:build_heading()} |
3 | 6 | ||
@@ -6,7 +9,17 @@ | @@ -6,7 +9,17 @@ | ||
6 | <div class="tab-pane fade active in" id="one"> | 9 | <div class="tab-pane fade active in" id="one"> |
7 | <div class="widget-body no-padding"> | 10 | <div class="widget-body no-padding"> |
8 | <div id="toolbar" class="toolbar"> | 11 | <div id="toolbar" class="toolbar"> |
9 | - {:build_toolbar()} | 12 | + <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> |
13 | + <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('auth/rule/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> | ||
14 | + <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('auth/rule/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> | ||
15 | + <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('auth/rule/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> | ||
16 | + <div class="dropdown btn-group {:$auth->check('auth/rule/multi')?'':'hide'}"> | ||
17 | + <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a> | ||
18 | + <ul class="dropdown-menu text-left" role="menu"> | ||
19 | + <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li> | ||
20 | + <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li> | ||
21 | + </ul> | ||
22 | + </div> | ||
10 | <a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a> | 23 | <a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a> |
11 | </div> | 24 | </div> |
12 | <table id="table" class="table table-bordered table-hover" | 25 | <table id="table" class="table table-bordered table-hover" |
1 | <div class="panel panel-default panel-intro"> | 1 | <div class="panel panel-default panel-intro"> |
2 | <div class="panel-heading"> | 2 | <div class="panel-heading"> |
3 | - {:build_heading()} | 3 | + {:build_heading(null,FALSE)} |
4 | <ul class="nav nav-tabs"> | 4 | <ul class="nav nav-tabs"> |
5 | <li class="active"><a href="#all" data-toggle="tab">{:__('All')}</a></li> | 5 | <li class="active"><a href="#all" data-toggle="tab">{:__('All')}</a></li> |
6 | {foreach name="typeList" item="vo"} | 6 | {foreach name="typeList" item="vo"} |
@@ -43,147 +43,15 @@ | @@ -43,147 +43,15 @@ | ||
43 | <li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px;">Yellow Light</p></li> | 43 | <li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px;">Yellow Light</p></li> |
44 | </ul> | 44 | </ul> |
45 | </div> | 45 | </div> |
46 | + <!-- /.tab-pane --> | ||
47 | + <!-- Home tab content --> | ||
46 | <div class="tab-pane" id="control-sidebar-home-tab"> | 48 | <div class="tab-pane" id="control-sidebar-home-tab"> |
47 | - <h3 class="control-sidebar-heading">{:__('Recent Activity')}</h3> | ||
48 | - <ul class="control-sidebar-menu"> | ||
49 | - <li> | ||
50 | - <a href="javascript:void(0)"> | ||
51 | - <i class="menu-icon fa fa-birthday-cake bg-red"></i> | ||
52 | - | ||
53 | - <div class="menu-info"> | ||
54 | - <h4 class="control-sidebar-subheading">Langdon's Birthday</h4> | ||
55 | - | ||
56 | - <p>Will be 23 on April 24th</p> | ||
57 | - </div> | ||
58 | - </a> | ||
59 | - </li> | ||
60 | - <li> | ||
61 | - <a href="javascript:void(0)"> | ||
62 | - <i class="menu-icon fa fa-user bg-yellow"></i> | ||
63 | - | ||
64 | - <div class="menu-info"> | ||
65 | - <h4 class="control-sidebar-subheading">Frodo Updated His Profile</h4> | ||
66 | - | ||
67 | - <p>New phone +1(800)555-1234</p> | ||
68 | - </div> | ||
69 | - </a> | ||
70 | - </li> | ||
71 | - <li> | ||
72 | - <a href="javascript:void(0)"> | ||
73 | - <i class="menu-icon fa fa-envelope-o bg-light-blue"></i> | ||
74 | - | ||
75 | - <div class="menu-info"> | ||
76 | - <h4 class="control-sidebar-subheading">Nora Joined Mailing List</h4> | ||
77 | - | ||
78 | - <p>nora@example.com</p> | ||
79 | - </div> | ||
80 | - </a> | ||
81 | - </li> | ||
82 | - <li> | ||
83 | - <a href="javascript:void(0)"> | ||
84 | - <i class="menu-icon fa fa-file-code-o bg-green"></i> | ||
85 | - | ||
86 | - <div class="menu-info"> | ||
87 | - <h4 class="control-sidebar-subheading">Cron Job 254 Executed</h4> | ||
88 | - | ||
89 | - <p>Execution time 5 seconds</p> | ||
90 | - </div> | ||
91 | - </a> | ||
92 | - </li> | ||
93 | - </ul> | ||
94 | - <!-- /.control-sidebar-menu --> | ||
95 | - | ||
96 | - <h3 class="control-sidebar-heading">{:__('Tasks Progress')}</h3> | ||
97 | - <ul class="control-sidebar-menu"> | ||
98 | - <li> | ||
99 | - <a href="javascript:void(0)"> | ||
100 | - <h4 class="control-sidebar-subheading"> | ||
101 | - Custom Template Design | ||
102 | - <span class="label label-danger pull-right">70%</span> | ||
103 | - </h4> | ||
104 | - | ||
105 | - <div class="progress progress-xxs"> | ||
106 | - <div class="progress-bar progress-bar-danger" style="width: 70%"></div> | ||
107 | - </div> | ||
108 | - </a> | ||
109 | - </li> | ||
110 | - <li> | ||
111 | - <a href="javascript:void(0)"> | ||
112 | - <h4 class="control-sidebar-subheading"> | ||
113 | - Update Resume | ||
114 | - <span class="label label-success pull-right">95%</span> | ||
115 | - </h4> | ||
116 | - | ||
117 | - <div class="progress progress-xxs"> | ||
118 | - <div class="progress-bar progress-bar-success" style="width: 95%"></div> | ||
119 | - </div> | ||
120 | - </a> | ||
121 | - </li> | ||
122 | - <li> | ||
123 | - <a href="javascript:void(0)"> | ||
124 | - <h4 class="control-sidebar-subheading"> | ||
125 | - Laravel Integration | ||
126 | - <span class="label label-warning pull-right">50%</span> | ||
127 | - </h4> | ||
128 | - | ||
129 | - <div class="progress progress-xxs"> | ||
130 | - <div class="progress-bar progress-bar-warning" style="width: 50%"></div> | ||
131 | - </div> | ||
132 | - </a> | ||
133 | - </li> | ||
134 | - <li> | ||
135 | - <a href="javascript:void(0)"> | ||
136 | - <h4 class="control-sidebar-subheading"> | ||
137 | - Back End Framework | ||
138 | - <span class="label label-primary pull-right">68%</span> | ||
139 | - </h4> | ||
140 | - | ||
141 | - <div class="progress progress-xxs"> | ||
142 | - <div class="progress-bar progress-bar-primary" style="width: 68%"></div> | ||
143 | - </div> | ||
144 | - </a> | ||
145 | - </li> | ||
146 | - </ul> | ||
147 | - <!-- /.control-sidebar-menu --> | ||
148 | - | 49 | + <h4 class="control-sidebar-heading">{:__('Home')}</h4> |
149 | </div> | 50 | </div> |
150 | <!-- /.tab-pane --> | 51 | <!-- /.tab-pane --> |
151 | - <!-- Stats tab content --> | ||
152 | - <div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div> | ||
153 | - <!-- /.tab-pane --> | ||
154 | <!-- Settings tab content --> | 52 | <!-- Settings tab content --> |
155 | <div class="tab-pane" id="control-sidebar-settings-tab"> | 53 | <div class="tab-pane" id="control-sidebar-settings-tab"> |
156 | - <form method="post"> | ||
157 | - <h3 class="control-sidebar-heading">General Settings</h3> | ||
158 | - | ||
159 | - <!-- /.form-group --> | ||
160 | - | ||
161 | - <div class="form-group"> | ||
162 | - <label class="control-sidebar-subheading"> | ||
163 | - Allow mail redirect | ||
164 | - <input type="checkbox" class="pull-right" checked> | ||
165 | - </label> | ||
166 | - | ||
167 | - <p> | ||
168 | - Other sets of options are available | ||
169 | - </p> | ||
170 | - </div> | ||
171 | - <!-- /.form-group --> | ||
172 | - | ||
173 | - <div class="form-group"> | ||
174 | - <label class="control-sidebar-subheading"> | ||
175 | - Expose author name in posts | ||
176 | - <input type="checkbox" class="pull-right" checked> | ||
177 | - </label> | ||
178 | - | ||
179 | - <p> | ||
180 | - Allow the user to show his name in blog posts | ||
181 | - </p> | ||
182 | - </div> | ||
183 | - <!-- /.form-group --> | ||
184 | - | ||
185 | - <!-- /.form-group --> | ||
186 | - </form> | 54 | + <h4 class="control-sidebar-heading">{:__('Setting')}</h4> |
187 | </div> | 55 | </div> |
188 | <!-- /.tab-pane --> | 56 | <!-- /.tab-pane --> |
189 | </div> | 57 | </div> |
1 | <!-- Logo --> | 1 | <!-- Logo --> |
2 | -<a href="javascript:;" class="logo"> | 2 | +<a href="javascript:;" class="logo hidden-xs"> |
3 | <!-- 迷你模式下Logo的大小为50X50 --> | 3 | <!-- 迷你模式下Logo的大小为50X50 --> |
4 | <span class="logo-mini">{$site.name|mb_substr=0,4,'utf-8'|mb_strtoupper='utf-8'}</span> | 4 | <span class="logo-mini">{$site.name|mb_substr=0,4,'utf-8'|mb_strtoupper='utf-8'}</span> |
5 | <!-- 普通模式下Logo --> | 5 | <!-- 普通模式下Logo --> |
@@ -29,10 +29,10 @@ | @@ -29,10 +29,10 @@ | ||
29 | <!--如果想始终显示子菜单,则给ul加上show-submenu类即可--> | 29 | <!--如果想始终显示子菜单,则给ul加上show-submenu类即可--> |
30 | <ul class="sidebar-menu"> | 30 | <ul class="sidebar-menu"> |
31 | {$menulist} | 31 | {$menulist} |
32 | - <li class="header">{:__('Links')}</li> | ||
33 | - <li><a href="http://doc.fastadmin.net" target="_blank"><i class="fa fa-list text-red"></i> <span>{:__('Docs')}</span></a></li> | ||
34 | - <li><a href="http://forum.fastadmin.net" target="_blank"><i class="fa fa-comment text-yellow"></i> <span>{:__('Forum')}</span></a></li> | ||
35 | - <li><a href="https://jq.qq.com/?_wv=1027&k=487PNBb" target="_blank"><i class="fa fa-qq text-aqua"></i> <span>{:__('QQ qun')}</span></a></li> | 32 | + <li class="header" data-rel="external">{:__('Links')}</li> |
33 | + <li data-rel="external"><a href="http://doc.fastadmin.net" target="_blank"><i class="fa fa-list text-red"></i> <span>{:__('Docs')}</span></a></li> | ||
34 | + <li data-rel="external"><a href="http://forum.fastadmin.net" target="_blank"><i class="fa fa-comment text-yellow"></i> <span>{:__('Forum')}</span></a></li> | ||
35 | + <li data-rel="external"><a href="https://jq.qq.com/?_wv=1027&k=487PNBb" target="_blank"><i class="fa fa-qq text-aqua"></i> <span>{:__('QQ qun')}</span></a></li> | ||
36 | </ul> | 36 | </ul> |
37 | </section> | 37 | </section> |
38 | <!-- /.sidebar --> | 38 | <!-- /.sidebar --> |
1 | -<script src="__CDN__/assets/js/require.js" data-main="__CDN__/assets/js/require-backend{$Think.config.app_debug?'':'.min'}.js?v={$site.version}"></script> | ||
1 | +<script src="__CDN__/assets/js/require{$Think.config.app_debug?'':'.min'}.js" data-main="__CDN__/assets/js/require-backend{$Think.config.app_debug?'':'.min'}.js?v={$site.version}"></script> |
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | <div class="tab-pane fade active in" id="one"> | 6 | <div class="tab-pane fade active in" id="one"> |
7 | <div class="widget-body no-padding"> | 7 | <div class="widget-body no-padding"> |
8 | <div id="toolbar" class="toolbar"> | 8 | <div id="toolbar" class="toolbar"> |
9 | - {:build_toolbar()} | 9 | + {:build_toolbar('refresh,add,edit,del')} |
10 | <div class="dropdown btn-group {:$auth->check('user/rule/multi')?'':'hide'}"> | 10 | <div class="dropdown btn-group {:$auth->check('user/rule/multi')?'':'hide'}"> |
11 | <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a> | 11 | <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a> |
12 | <ul class="dropdown-menu text-left" role="menu"> | 12 | <ul class="dropdown-menu text-left" role="menu"> |
@@ -2,9 +2,9 @@ | @@ -2,9 +2,9 @@ | ||
2 | 2 | ||
3 | namespace app\api\controller; | 3 | namespace app\api\controller; |
4 | 4 | ||
5 | -use app\api\model\Area; | ||
6 | use app\common\controller\Api; | 5 | use app\common\controller\Api; |
7 | -use fast\Version; | 6 | +use app\common\model\Area; |
7 | +use app\common\model\Version; | ||
8 | use fast\Random; | 8 | use fast\Random; |
9 | use think\Config; | 9 | use think\Config; |
10 | 10 |
application/api/library/ExceptionHandle.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\api\library; | ||
4 | + | ||
5 | +use Exception; | ||
6 | +use think\exception\Handle; | ||
7 | + | ||
8 | +/** | ||
9 | + * 自定义API模块的错误显示 | ||
10 | + */ | ||
11 | +class ExceptionHandle extends Handle | ||
12 | +{ | ||
13 | + | ||
14 | + public function render(Exception $e) | ||
15 | + { | ||
16 | + // 在生产环境下返回code信息 | ||
17 | + if (!\think\Config::get('app_debug')) | ||
18 | + { | ||
19 | + $statuscode = $code = 500; | ||
20 | + $msg = 'An error occurred'; | ||
21 | + // 验证异常 | ||
22 | + if ($e instanceof \think\exception\ValidateException) | ||
23 | + { | ||
24 | + $code = 0; | ||
25 | + $statuscode = 200; | ||
26 | + $msg = $e->getError(); | ||
27 | + } | ||
28 | + // Http异常 | ||
29 | + if ($e instanceof \think\exception\HttpException) | ||
30 | + { | ||
31 | + $statuscode = $code = $e->getStatusCode(); | ||
32 | + } | ||
33 | + return json(['code' => $code, 'msg' => $msg, 'time' => time(), 'data' => null], $statuscode); | ||
34 | + } | ||
35 | + | ||
36 | + //其它此交由系统处理 | ||
37 | + return parent::render($e); | ||
38 | + } | ||
39 | + | ||
40 | +} |
@@ -22,7 +22,7 @@ if (!function_exists('__')) | @@ -22,7 +22,7 @@ if (!function_exists('__')) | ||
22 | array_shift($vars); | 22 | array_shift($vars); |
23 | $lang = ''; | 23 | $lang = ''; |
24 | } | 24 | } |
25 | - return think\Lang::get($name, $vars, $lang); | 25 | + return \think\Lang::get($name, $vars, $lang); |
26 | } | 26 | } |
27 | 27 | ||
28 | } | 28 | } |
@@ -89,7 +89,7 @@ if (!function_exists('cdnurl')) | @@ -89,7 +89,7 @@ if (!function_exists('cdnurl')) | ||
89 | */ | 89 | */ |
90 | function cdnurl($url) | 90 | function cdnurl($url) |
91 | { | 91 | { |
92 | - return preg_match("/^https?:\/\/(.*)/i", $url) ? $url : think\Config::get('upload.cdnurl') . $url; | 92 | + return preg_match("/^https?:\/\/(.*)/i", $url) ? $url : \think\Config::get('upload.cdnurl') . $url; |
93 | } | 93 | } |
94 | 94 | ||
95 | } | 95 | } |
@@ -208,7 +208,6 @@ if (!function_exists('mb_ucfirst')) | @@ -208,7 +208,6 @@ if (!function_exists('mb_ucfirst')) | ||
208 | 208 | ||
209 | } | 209 | } |
210 | 210 | ||
211 | - | ||
212 | if (!function_exists('addtion')) | 211 | if (!function_exists('addtion')) |
213 | { | 212 | { |
214 | 213 | ||
@@ -300,3 +299,37 @@ if (!function_exists('addtion')) | @@ -300,3 +299,37 @@ if (!function_exists('addtion')) | ||
300 | } | 299 | } |
301 | 300 | ||
302 | } | 301 | } |
302 | + | ||
303 | +if (!function_exists('var_export_short')) | ||
304 | +{ | ||
305 | + | ||
306 | + /** | ||
307 | + * 返回打印数组结构 | ||
308 | + * @param string $var 数组 | ||
309 | + * @param string $indent 缩进字符 | ||
310 | + * @return string | ||
311 | + */ | ||
312 | + function var_export_short($var, $indent = "") | ||
313 | + { | ||
314 | + switch (gettype($var)) | ||
315 | + { | ||
316 | + case "string": | ||
317 | + return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"'; | ||
318 | + case "array": | ||
319 | + $indexed = array_keys($var) === range(0, count($var) - 1); | ||
320 | + $r = []; | ||
321 | + foreach ($var as $key => $value) | ||
322 | + { | ||
323 | + $r[] = "$indent " | ||
324 | + . ($indexed ? "" : var_export_short($key) . " => ") | ||
325 | + . var_export_short($value, "$indent "); | ||
326 | + } | ||
327 | + return "[\n" . implode(",\n", $r) . "\n" . $indent . "]"; | ||
328 | + case "boolean": | ||
329 | + return $var ? "TRUE" : "FALSE"; | ||
330 | + default: | ||
331 | + return var_export($var, TRUE); | ||
332 | + } | ||
333 | + } | ||
334 | + | ||
335 | +} |
@@ -52,6 +52,11 @@ class Common | @@ -52,6 +52,11 @@ class Common | ||
52 | { | 52 | { |
53 | Config::set('app_trace', false); | 53 | Config::set('app_trace', false); |
54 | } | 54 | } |
55 | + // 切换多语言 | ||
56 | + if (Config::get('lang_switch_on') && $request->get('lang')) | ||
57 | + { | ||
58 | + \think\Cookie::set('think_var', $request->get('lang')); | ||
59 | + } | ||
55 | } | 60 | } |
56 | 61 | ||
57 | public function addonBegin(&$request) | 62 | public function addonBegin(&$request) |
@@ -91,7 +91,7 @@ class Api | @@ -91,7 +91,7 @@ class Api | ||
91 | $actionname = strtolower($this->request->action()); | 91 | $actionname = strtolower($this->request->action()); |
92 | 92 | ||
93 | // token | 93 | // token |
94 | - $token = $this->request->request('token') ?: $this->request->cookie('token'); | 94 | + $token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token'))); |
95 | 95 | ||
96 | $path = str_replace('.', '/', $controllername) . '/' . $actionname; | 96 | $path = str_replace('.', '/', $controllername) . '/' . $actionname; |
97 | // 设置当前请求的URI | 97 | // 设置当前请求的URI |
@@ -104,7 +104,7 @@ class Api | @@ -104,7 +104,7 @@ class Api | ||
104 | //检测是否登录 | 104 | //检测是否登录 |
105 | if (!$this->auth->isLogin()) | 105 | if (!$this->auth->isLogin()) |
106 | { | 106 | { |
107 | - $this->error(__('Please login first')); | 107 | + $this->error(__('Please login first'), null, 401); |
108 | } | 108 | } |
109 | // 判断是否需要验证权限 | 109 | // 判断是否需要验证权限 |
110 | if (!$this->auth->match($this->noNeedRight)) | 110 | if (!$this->auth->match($this->noNeedRight)) |
@@ -112,7 +112,7 @@ class Api | @@ -112,7 +112,7 @@ class Api | ||
112 | // 判断控制器和方法判断是否有对应权限 | 112 | // 判断控制器和方法判断是否有对应权限 |
113 | if (!$this->auth->check($path)) | 113 | if (!$this->auth->check($path)) |
114 | { | 114 | { |
115 | - $this->error(__('You have no permission')); | 115 | + $this->error(__('You have no permission'), null, 403); |
116 | } | 116 | } |
117 | } | 117 | } |
118 | } | 118 | } |
@@ -141,38 +141,40 @@ class Api | @@ -141,38 +141,40 @@ class Api | ||
141 | * 操作成功返回的数据 | 141 | * 操作成功返回的数据 |
142 | * @param string $msg 提示信息 | 142 | * @param string $msg 提示信息 |
143 | * @param mixed $data 要返回的数据 | 143 | * @param mixed $data 要返回的数据 |
144 | + * @param int $code 错误码,默认为1 | ||
144 | * @param string $type 输出类型 | 145 | * @param string $type 输出类型 |
145 | * @param array $header 发送的 Header 信息 | 146 | * @param array $header 发送的 Header 信息 |
146 | */ | 147 | */ |
147 | - protected function success($msg = '', $data = '', $type = 'json', array $header = []) | 148 | + protected function success($msg = '', $data = null, $code = 1, $type = 'json', array $header = []) |
148 | { | 149 | { |
149 | - $this->result($data, 1, $msg, $type, $header); | 150 | + $this->result($msg, $data, $code, $type, $header); |
150 | } | 151 | } |
151 | 152 | ||
152 | /** | 153 | /** |
153 | * 操作失败返回的数据 | 154 | * 操作失败返回的数据 |
154 | * @param string $msg 提示信息 | 155 | * @param string $msg 提示信息 |
155 | * @param mixed $data 要返回的数据 | 156 | * @param mixed $data 要返回的数据 |
157 | + * @param int $code 错误码,默认为0 | ||
156 | * @param string $type 输出类型 | 158 | * @param string $type 输出类型 |
157 | * @param array $header 发送的 Header 信息 | 159 | * @param array $header 发送的 Header 信息 |
158 | */ | 160 | */ |
159 | - protected function error($msg = '', $data = '', $type = 'json', array $header = []) | 161 | + protected function error($msg = '', $data = null, $code = 0, $type = 'json', array $header = []) |
160 | { | 162 | { |
161 | - $this->result($data, 0, $msg, $type, $header); | 163 | + $this->result($msg, $data, $code, $type, $header); |
162 | } | 164 | } |
163 | 165 | ||
164 | /** | 166 | /** |
165 | * 返回封装后的 API 数据到客户端 | 167 | * 返回封装后的 API 数据到客户端 |
166 | * @access protected | 168 | * @access protected |
169 | + * @param mixed $msg 提示信息 | ||
167 | * @param mixed $data 要返回的数据 | 170 | * @param mixed $data 要返回的数据 |
168 | * @param int $code 返回的 code | 171 | * @param int $code 返回的 code |
169 | - * @param mixed $msg 提示信息 | ||
170 | * @param string $type 返回数据格式 | 172 | * @param string $type 返回数据格式 |
171 | * @param array $header 发送的 Header 信息 | 173 | * @param array $header 发送的 Header 信息 |
172 | * @return void | 174 | * @return void |
173 | * @throws HttpResponseException | 175 | * @throws HttpResponseException |
174 | */ | 176 | */ |
175 | - protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) | 177 | + protected function result($msg, $data = null, $code = 0, $type = 'json', array $header = []) |
176 | { | 178 | { |
177 | $result = [ | 179 | $result = [ |
178 | 'code' => $code, | 180 | 'code' => $code, |
@@ -181,17 +183,18 @@ class Api | @@ -181,17 +183,18 @@ class Api | ||
181 | 'data' => $data, | 183 | 'data' => $data, |
182 | ]; | 184 | ]; |
183 | $type = $type ?: $this->getResponseType(); | 185 | $type = $type ?: $this->getResponseType(); |
184 | - $response = Response::create($result, $type)->header($header); | ||
185 | - | ||
186 | - throw new HttpResponseException($response); | 186 | + if (isset($header['statuscode'])) |
187 | + { | ||
188 | + $code = $header['statuscode']; | ||
189 | + unset($header['statuscode']); | ||
187 | } | 190 | } |
188 | - | ||
189 | - /** | ||
190 | - * 未找到请求的接口 | ||
191 | - */ | ||
192 | - public function _empty() | 191 | + else |
193 | { | 192 | { |
194 | - return $this->error('Api not found'); | 193 | + $code = $code >= 1000 ? 200 : $code; |
194 | + } | ||
195 | + $response = Response::create($result, $type, $code)->header($header); | ||
196 | + | ||
197 | + throw new HttpResponseException($response); | ||
195 | } | 198 | } |
196 | 199 | ||
197 | /** | 200 | /** |
@@ -144,6 +144,7 @@ class Backend extends Controller | @@ -144,6 +144,7 @@ class Backend extends Controller | ||
144 | $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function($matches) { | 144 | $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function($matches) { |
145 | return $matches[2] == '&' ? $matches[1] : ''; | 145 | return $matches[2] == '&' ? $matches[1] : ''; |
146 | }, $this->request->url()); | 146 | }, $this->request->url()); |
147 | + $url = url($url, '', false); | ||
147 | $this->redirect('index/index', [], 302, ['referer' => $url]); | 148 | $this->redirect('index/index', [], 302, ['referer' => $url]); |
148 | exit; | 149 | exit; |
149 | } | 150 | } |
@@ -290,6 +291,10 @@ class Backend extends Controller | @@ -290,6 +291,10 @@ class Backend extends Controller | ||
290 | case '<=': | 291 | case '<=': |
291 | $where[] = [$k, $sym, intval($v)]; | 292 | $where[] = [$k, $sym, intval($v)]; |
292 | break; | 293 | break; |
294 | + case 'FINDIN': | ||
295 | + case 'FIND_IN_SET': | ||
296 | + $where[] = "FIND_IN_SET('{$v}', `{$k}`)"; | ||
297 | + break; | ||
293 | case 'IN': | 298 | case 'IN': |
294 | case 'IN(...)': | 299 | case 'IN(...)': |
295 | case 'NOT IN': | 300 | case 'NOT IN': |
@@ -401,21 +406,21 @@ class Backend extends Controller | @@ -401,21 +406,21 @@ class Backend extends Controller | ||
401 | //搜索关键词,客户端输入以空格分开,这里接收为数组 | 406 | //搜索关键词,客户端输入以空格分开,这里接收为数组 |
402 | $word = (array) $this->request->request("q_word/a"); | 407 | $word = (array) $this->request->request("q_word/a"); |
403 | //当前页 | 408 | //当前页 |
404 | - $page = $this->request->request("page"); | 409 | + $page = $this->request->request("pageNumber"); |
405 | //分页大小 | 410 | //分页大小 |
406 | - $pagesize = $this->request->request("per_page"); | 411 | + $pagesize = $this->request->request("pageSize"); |
407 | //搜索条件 | 412 | //搜索条件 |
408 | - $andor = $this->request->request("and_or"); | 413 | + $andor = $this->request->request("andOr"); |
409 | //排序方式 | 414 | //排序方式 |
410 | - $orderby = (array) $this->request->request("order_by/a"); | 415 | + $orderby = (array) $this->request->request("orderBy/a"); |
411 | //显示的字段 | 416 | //显示的字段 |
412 | - $field = $this->request->request("field"); | 417 | + $field = $this->request->request("showField"); |
413 | //主键 | 418 | //主键 |
414 | - $primarykey = $this->request->request("pkey_name"); | 419 | + $primarykey = $this->request->request("keyField"); |
415 | //主键值 | 420 | //主键值 |
416 | - $primaryvalue = $this->request->request("pkey_value"); | 421 | + $primaryvalue = $this->request->request("keyValue"); |
417 | //搜索字段 | 422 | //搜索字段 |
418 | - $searchfield = (array) $this->request->request("search_field/a"); | 423 | + $searchfield = (array) $this->request->request("searchField/a"); |
419 | //自定义搜索条件 | 424 | //自定义搜索条件 |
420 | $custom = (array) $this->request->request("custom/a"); | 425 | $custom = (array) $this->request->request("custom/a"); |
421 | $order = []; | 426 | $order = []; |
@@ -58,8 +58,7 @@ class Frontend extends Controller | @@ -58,8 +58,7 @@ class Frontend extends Controller | ||
58 | $actionname = strtolower($this->request->action()); | 58 | $actionname = strtolower($this->request->action()); |
59 | 59 | ||
60 | // token | 60 | // token |
61 | - $token = $this->request->request('token'); | ||
62 | - $token = $token ? $token : \think\Cookie::get('token'); | 61 | + $token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token'))); |
63 | 62 | ||
64 | $path = str_replace('.', '/', $controllername) . '/' . $actionname; | 63 | $path = str_replace('.', '/', $controllername) . '/' . $actionname; |
65 | // 设置当前请求的URI | 64 | // 设置当前请求的URI |
@@ -6,4 +6,97 @@ return [ | @@ -6,4 +6,97 @@ return [ | ||
6 | 'addon controller %s not found' => '插件控制器未找到', | 6 | 'addon controller %s not found' => '插件控制器未找到', |
7 | 'addon action %s not found' => '插件控制器方法未找到', | 7 | 'addon action %s not found' => '插件控制器方法未找到', |
8 | 'addon can not be empty' => '插件不能为空', | 8 | 'addon can not be empty' => '插件不能为空', |
9 | + 'Keep login' => '保持会话', | ||
10 | + 'Forgot password' => '忘记密码?', | ||
11 | + 'Sign in' => '登入', | ||
12 | + 'Username' => '用户名', | ||
13 | + 'User id' => '会员ID', | ||
14 | + 'Username' => '用户名', | ||
15 | + 'Nickname' => '昵称', | ||
16 | + 'Password' => '密码', | ||
17 | + 'Sign up' => '注 册', | ||
18 | + 'Sign in' => '登 录', | ||
19 | + 'Sign out' => '注 销', | ||
20 | + 'Guest' => '游客', | ||
21 | + 'Welcome' => '%s,你好!', | ||
22 | + 'Add' => '添加', | ||
23 | + 'Edit' => '编辑', | ||
24 | + 'Delete' => '删除', | ||
25 | + 'Move' => '移动', | ||
26 | + 'Name' => '名称', | ||
27 | + 'Status' => '状态', | ||
28 | + 'Weigh' => '权重', | ||
29 | + 'Operate' => '操作', | ||
30 | + 'Warning' => '温馨提示', | ||
31 | + 'Default' => '默认', | ||
32 | + 'Article' => '文章', | ||
33 | + 'Page' => '单页', | ||
34 | + 'OK' => '确定', | ||
35 | + 'Cancel' => '取消', | ||
36 | + 'Loading' => '加载中', | ||
37 | + 'More' => '更多', | ||
38 | + 'Normal' => '正常', | ||
39 | + 'Hidden' => '隐藏', | ||
40 | + 'Submit' => '提交', | ||
41 | + 'Reset' => '重置', | ||
42 | + 'Execute' => '执行', | ||
43 | + 'Close' => '关闭', | ||
44 | + 'Search' => '搜索', | ||
45 | + 'Refresh' => '刷新', | ||
46 | + 'First' => '首页', | ||
47 | + 'Previous' => '上一页', | ||
48 | + 'Next' => '下一页', | ||
49 | + 'Last' => '末页', | ||
50 | + 'None' => '无', | ||
51 | + 'Home' => '主页', | ||
52 | + 'Online' => '在线', | ||
53 | + 'Logout' => '注销', | ||
54 | + 'Profile' => '个人资料', | ||
55 | + 'Index' => '首页', | ||
56 | + 'Hot' => '热门', | ||
57 | + 'Recommend' => '推荐', | ||
58 | + 'Dashboard' => '控制台', | ||
59 | + 'Code' => '编号', | ||
60 | + 'Message' => '内容', | ||
61 | + 'Line' => '行号', | ||
62 | + 'File' => '文件', | ||
63 | + 'Menu' => '菜单', | ||
64 | + 'Name' => '名称', | ||
65 | + 'Weigh' => '权重', | ||
66 | + 'Type' => '类型', | ||
67 | + 'Title' => '标题', | ||
68 | + 'Content' => '内容', | ||
69 | + 'Status' => '状态', | ||
70 | + 'Operate' => '操作', | ||
71 | + 'Append' => '追加', | ||
72 | + 'Memo' => '备注', | ||
73 | + 'Parent' => '父级', | ||
74 | + 'Params' => '参数', | ||
75 | + 'Permission' => '权限', | ||
76 | + 'Begin time' => '开始时间', | ||
77 | + 'End time' => '结束时间', | ||
78 | + 'Create time' => '创建时间', | ||
79 | + 'Flag' => '标志', | ||
80 | + 'Home' => '首页', | ||
81 | + 'Store' => '插件市场', | ||
82 | + 'Services' => '服务', | ||
83 | + 'Download' => '下载', | ||
84 | + 'Demo' => '演示', | ||
85 | + 'Donation' => '捐赠', | ||
86 | + 'Forum' => '社区', | ||
87 | + 'Docs' => '文档', | ||
88 | + 'Please login first' => '请登录后再操作', | ||
89 | + 'Send verification code' => '发送验证码', | ||
90 | + 'Redirect now' => '立即跳转', | ||
91 | + 'Operation completed' => '操作成功!', | ||
92 | + 'Operation failed' => '操作失败!', | ||
93 | + 'Unknown data format' => '未知的数据格式!', | ||
94 | + 'Network error' => '网络错误!', | ||
95 | + 'Advanced search' => '高级搜索', | ||
96 | + 'Invalid parameters' => '未知参数', | ||
97 | + 'No results were found' => '记录未找到', | ||
98 | + 'Parameter %s can not be empty' => '参数%s不能为空', | ||
99 | + 'You have no permission' => '你没有权限访问', | ||
100 | + 'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中', | ||
101 | + 'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转', | ||
9 | ]; | 102 | ]; |
@@ -101,6 +101,28 @@ class Menu | @@ -101,6 +101,28 @@ class Menu | ||
101 | } | 101 | } |
102 | 102 | ||
103 | /** | 103 | /** |
104 | + * 导出指定名称的菜单规则 | ||
105 | + * @param string $name | ||
106 | + * @return array | ||
107 | + */ | ||
108 | + public static function export($name) | ||
109 | + { | ||
110 | + $ids = self::getAuthRuleIdsByName($name); | ||
111 | + if (!$ids) | ||
112 | + { | ||
113 | + return []; | ||
114 | + } | ||
115 | + $menuList = []; | ||
116 | + $menu = AuthRule::getByName($name); | ||
117 | + if ($menu) | ||
118 | + { | ||
119 | + $ruleList = collection(AuthRule::where('id', 'in', $ids)->select())->toArray(); | ||
120 | + $menuList = Tree::instance()->init($ruleList)->getTreeArray($menu['id']); | ||
121 | + } | ||
122 | + return $menuList; | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
104 | * 根据名称获取规则IDS | 126 | * 根据名称获取规则IDS |
105 | * @param string $name | 127 | * @param string $name |
106 | * @return array | 128 | * @return array |
@@ -112,7 +134,7 @@ class Menu | @@ -112,7 +134,7 @@ class Menu | ||
112 | if ($menu) | 134 | if ($menu) |
113 | { | 135 | { |
114 | // 必须将结果集转换为数组 | 136 | // 必须将结果集转换为数组 |
115 | - $ruleList = collection(model('AuthRule')->order('weigh', 'desc')->field('id,pid,name')->select())->toArray(); | 137 | + $ruleList = collection(AuthRule::order('weigh', 'desc')->field('id,pid,name')->select())->toArray(); |
116 | // 构造菜单数据 | 138 | // 构造菜单数据 |
117 | $ids = Tree::instance()->init($ruleList)->getChildrenIds($menu['id'], true); | 139 | $ids = Tree::instance()->init($ruleList)->getChildrenIds($menu['id'], true); |
118 | } | 140 | } |
@@ -11,7 +11,7 @@ class ScoreLog Extends Model | @@ -11,7 +11,7 @@ class ScoreLog Extends Model | ||
11 | { | 11 | { |
12 | 12 | ||
13 | // 表名 | 13 | // 表名 |
14 | - protected $name = 'score_log'; | 14 | + protected $name = 'user_score_log'; |
15 | // 开启自动写入时间戳字段 | 15 | // 开启自动写入时间戳字段 |
16 | protected $autoWriteTimestamp = 'int'; | 16 | protected $autoWriteTimestamp = 'int'; |
17 | // 定义时间戳字段名 | 17 | // 定义时间戳字段名 |
application/common/model/Version.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace app\common\model; | ||
4 | + | ||
5 | +use think\Model; | ||
6 | + | ||
7 | +class Version extends Model | ||
8 | +{ | ||
9 | + | ||
10 | + // 开启自动写入时间戳字段 | ||
11 | + protected $autoWriteTimestamp = 'int'; | ||
12 | + // 定义时间戳字段名 | ||
13 | + protected $createTime = 'createtime'; | ||
14 | + protected $updateTime = 'updatetime'; | ||
15 | + // 定义字段类型 | ||
16 | + protected $type = [ | ||
17 | + ]; | ||
18 | + | ||
19 | + /** | ||
20 | + * 检测版本号 | ||
21 | + * | ||
22 | + * @param string $version 客户端版本号 | ||
23 | + * @return array | ||
24 | + */ | ||
25 | + public static function check($version) | ||
26 | + { | ||
27 | + $versionlist = self::where('status', 'normal')->cache('__version__')->order('weigh desc,id desc')->select(); | ||
28 | + foreach ($versionlist as $k => $v) | ||
29 | + { | ||
30 | + // 版本正常且新版本号不等于验证的版本号且找到匹配的旧版本 | ||
31 | + if ($v['status'] == 'normal' && $v['newversion'] !== $version && \fast\Version::check($version, $v['oldversion'])) | ||
32 | + { | ||
33 | + $updateversion = $v; | ||
34 | + break; | ||
35 | + } | ||
36 | + } | ||
37 | + if (isset($updateversion)) | ||
38 | + { | ||
39 | + $search = ['{version}', '{newversion}', '{downloadurl}', '{url}', '{packagesize}']; | ||
40 | + $replace = [$version, $updateversion['newversion'], $updateversion['downloadurl'], $updateversion['downloadurl'], $updateversion['packagesize']]; | ||
41 | + $upgradetext = str_replace($search, $replace, $updateversion['content']); | ||
42 | + return [ | ||
43 | + "enforce" => $updateversion['enforce'], | ||
44 | + "version" => $version, | ||
45 | + "newversion" => $updateversion['newversion'], | ||
46 | + "downloadurl" => $updateversion['downloadurl'], | ||
47 | + "packagesize" => $updateversion['packagesize'], | ||
48 | + "upgradetext" => $upgradetext | ||
49 | + ]; | ||
50 | + } | ||
51 | + return NULL; | ||
52 | + } | ||
53 | + | ||
54 | +} |
@@ -253,7 +253,7 @@ return [ | @@ -253,7 +253,7 @@ return [ | ||
253 | //自动检测更新 | 253 | //自动检测更新 |
254 | 'checkupdate' => false, | 254 | 'checkupdate' => false, |
255 | //版本号 | 255 | //版本号 |
256 | - 'version' => '1.0.0.20180227_beta', | 256 | + 'version' => '1.0.0.20180308_beta', |
257 | 'api_url' => 'http://api.fastadmin.net', | 257 | 'api_url' => 'http://api.fastadmin.net', |
258 | ], | 258 | ], |
259 | ]; | 259 | ]; |
@@ -97,7 +97,7 @@ return [ | @@ -97,7 +97,7 @@ return [ | ||
97 | 'Forum' => '社区', | 97 | 'Forum' => '社区', |
98 | 'Docs' => '文档', | 98 | 'Docs' => '文档', |
99 | 'Please login first' => '请登录后再操作', | 99 | 'Please login first' => '请登录后再操作', |
100 | - 'Send verification code' => '发磅验证码', | 100 | + 'Send verification code' => '发送验证码', |
101 | 'Redirect now' => '立即跳转', | 101 | 'Redirect now' => '立即跳转', |
102 | 'Operation completed' => '操作成功!', | 102 | 'Operation completed' => '操作成功!', |
103 | 'Operation failed' => '操作失败!', | 103 | 'Operation failed' => '操作失败!', |
1 | -<script src="__CDN__/assets/js/require.js" data-main="__CDN__/assets/js/require-frontend{$Think.config.app_debug?'':'.min'}.js?v={$site.version}"></script> | ||
1 | +<script src="__CDN__/assets/js/require{$Think.config.app_debug?'':'.min'}.js" data-main="__CDN__/assets/js/require-frontend{$Think.config.app_debug?'':'.min'}.js?v={$site.version}"></script> |
@@ -174,11 +174,9 @@ | @@ -174,11 +174,9 @@ | ||
174 | $("#mainNav").toggleClass("affix", $(window).height() - $(window).scrollTop() <= 50); | 174 | $("#mainNav").toggleClass("affix", $(window).height() - $(window).scrollTop() <= 50); |
175 | }); | 175 | }); |
176 | 176 | ||
177 | - | ||
178 | //发送版本统计信息 | 177 | //发送版本统计信息 |
179 | try { | 178 | try { |
180 | var installed = localStorage.getItem("installed"); | 179 | var installed = localStorage.getItem("installed"); |
181 | - console.log(installed); | ||
182 | if (!installed) { | 180 | if (!installed) { |
183 | $.ajax({ | 181 | $.ajax({ |
184 | url: "{$Think.config.fastadmin.api_url}/statistics/installed", | 182 | url: "{$Think.config.fastadmin.api_url}/statistics/installed", |
@@ -8,37 +8,31 @@ | @@ -8,37 +8,31 @@ | ||
8 | "dependencies": { | 8 | "dependencies": { |
9 | "jquery": "^2.1.4", | 9 | "jquery": "^2.1.4", |
10 | "bootstrap": "^3.3.7", | 10 | "bootstrap": "^3.3.7", |
11 | - "font-awesome": "fontawesome#^4.6.1", | 11 | + "font-awesome": "^4.6.1", |
12 | "bootstrap-table": "^1.11.0", | 12 | "bootstrap-table": "^1.11.0", |
13 | - "layer": "*", | 13 | + "layer": "^3.0", |
14 | "jstree": "^3.3.2", | 14 | "jstree": "^3.3.2", |
15 | - "summernote": "^0.8.2", | ||
16 | - "jquery-pjax": "^1.9.6", | ||
17 | "moment": "^2.15.2", | 15 | "moment": "^2.15.2", |
18 | "plupload": "^2.2.0", | 16 | "plupload": "^2.2.0", |
19 | "toastr": "^2.1.3", | 17 | "toastr": "^2.1.3", |
20 | - "devbridge-autocomplete": "^1.2.26", | ||
21 | - "jcrop": "jcrop#^2.0.4", | ||
22 | - "jquery-qrcode": "*", | 18 | + "jcrop": "^2.0.4", |
23 | "eonasdan-bootstrap-datetimepicker": "^4.17.43", | 19 | "eonasdan-bootstrap-datetimepicker": "^4.17.43", |
24 | "bootstrap-select": "^1.11.2", | 20 | "bootstrap-select": "^1.11.2", |
25 | "require-css": "^0.1.8", | 21 | "require-css": "^0.1.8", |
26 | "less": "^2.7.1", | 22 | "less": "^2.7.1", |
27 | "tableExport.jquery.plugin": "^1.9.0", | 23 | "tableExport.jquery.plugin": "^1.9.0", |
28 | - "jquery-slimscroll": "slimscroll#^1.3.8", | 24 | + "jquery-slimscroll": "^1.3.8", |
29 | "jquery.cookie": "^1.4.1", | 25 | "jquery.cookie": "^1.4.1", |
30 | "Sortable": "^1.5.0", | 26 | "Sortable": "^1.5.0", |
31 | "nice-validator": "^1.1.1", | 27 | "nice-validator": "^1.1.1", |
32 | "art-template": "^3.0.1", | 28 | "art-template": "^3.0.1", |
33 | "requirejs-plugins": "^1.0.3", | 29 | "requirejs-plugins": "^1.0.3", |
34 | "bootstrap-daterangepicker": "^2.1.25", | 30 | "bootstrap-daterangepicker": "^2.1.25", |
35 | - "city-picker":"^1.1.0" | ||
36 | - }, | ||
37 | - "devDependencies": { | ||
38 | - "dragsort": "https://github.com/karsonzhang/dragsort.git", | ||
39 | - "jquery-addtabs": "https://github.com/karsonzhang/jquery-addtabs.git", | ||
40 | - "jquery-cxselect": "https://github.com/karsonzhang/cxSelect.git", | ||
41 | - "selectpage": "https://github.com/karsonzhang/selectpage.git" | 31 | + "city-picker": "^1.1.0", |
32 | + "fastadmin-cxselect": "~1.4.0", | ||
33 | + "fastadmin-dragsort": "~1.0.0", | ||
34 | + "fastadmin-addtabs": "~1.0.0", | ||
35 | + "fastadmin-selectpage": "~1.0.0" | ||
42 | }, | 36 | }, |
43 | "resolutions": { | 37 | "resolutions": { |
44 | "jspdf": "1.1.239 || 1.3.2" | 38 | "jspdf": "1.1.239 || 1.3.2" |
@@ -10,7 +10,7 @@ | @@ -10,7 +10,7 @@ | ||
10 | "license": "Apache-2.0", | 10 | "license": "Apache-2.0", |
11 | "authors": [ | 11 | "authors": [ |
12 | { | 12 | { |
13 | - "name": "karson", | 13 | + "name": "Karson", |
14 | "email": "karsonzhang@163.com" | 14 | "email": "karsonzhang@163.com" |
15 | } | 15 | } |
16 | ], | 16 | ], |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | "topthink/think-captcha": "^1.0", | 22 | "topthink/think-captcha": "^1.0", |
23 | "mtdowling/cron-expression": "^1.2", | 23 | "mtdowling/cron-expression": "^1.2", |
24 | "phpmailer/phpmailer": "^5.2", | 24 | "phpmailer/phpmailer": "^5.2", |
25 | - "karsonzhang/fastadmin-addons": "dev-master", | 25 | + "karsonzhang/fastadmin-addons": "~1.1.0", |
26 | "overtrue/pinyin": "~3.0", | 26 | "overtrue/pinyin": "~3.0", |
27 | "phpoffice/phpexcel": "^1.8" | 27 | "phpoffice/phpexcel": "^1.8" |
28 | }, | 28 | }, |
public/api.html
0 → 100644
此 diff 太大无法显示。
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | @import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"); | 9 | @import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"); |
10 | @import url("../libs/bootstrap-daterangepicker/daterangepicker.css"); | 10 | @import url("../libs/bootstrap-daterangepicker/daterangepicker.css"); |
11 | @import url("../libs/nice-validator/dist/jquery.validator.css"); | 11 | @import url("../libs/nice-validator/dist/jquery.validator.css"); |
12 | -@import url("../libs/selectpage/selectpage.css"); | 12 | +@import url("../libs/fastadmin-selectpage/selectpage.css"); |
13 | body { | 13 | body { |
14 | background: #f1f4f6; | 14 | background: #f1f4f6; |
15 | } | 15 | } |
@@ -44,9 +44,6 @@ body.is-dialog { | @@ -44,9 +44,6 @@ body.is-dialog { | ||
44 | position: absolute; | 44 | position: absolute; |
45 | right: 0; | 45 | right: 0; |
46 | } | 46 | } |
47 | -.note-dialog .modal { | ||
48 | - z-index: 1060; | ||
49 | -} | ||
50 | .bootstrap-dialog .modal-dialog { | 47 | .bootstrap-dialog .modal-dialog { |
51 | /*width: 70%;*/ | 48 | /*width: 70%;*/ |
52 | max-width: 885px; | 49 | max-width: 885px; |
@@ -645,13 +642,16 @@ form.form-horizontal .control-label { | @@ -645,13 +642,16 @@ form.form-horizontal .control-label { | ||
645 | overflow: hidden; | 642 | overflow: hidden; |
646 | } | 643 | } |
647 | .layui-layer-fast .layui-layer-btn a { | 644 | .layui-layer-fast .layui-layer-btn a { |
648 | - background-color: #95a5a6!important; | ||
649 | - border-color: #95a5a6!important; | 645 | + background-color: #95a5a6; |
646 | + border-color: #95a5a6; | ||
650 | color: #fff!important; | 647 | color: #fff!important; |
648 | + height: 31px; | ||
649 | + margin-top: 0; | ||
650 | + border: 1px solid transparent; | ||
651 | } | 651 | } |
652 | .layui-layer-fast .layui-layer-btn .layui-layer-btn0 { | 652 | .layui-layer-fast .layui-layer-btn .layui-layer-btn0 { |
653 | - background-color: #18bc9c!important; | ||
654 | - border-color: #18bc9c!important; | 653 | + background-color: #18bc9c; |
654 | + border-color: #18bc9c; | ||
655 | } | 655 | } |
656 | .layui-layer-fast .layui-layer-footer { | 656 | .layui-layer-fast .layui-layer-footer { |
657 | padding: 8px 20px; | 657 | padding: 8px 20px; |
@@ -731,6 +731,14 @@ form.form-horizontal .control-label { | @@ -731,6 +731,14 @@ form.form-horizontal .control-label { | ||
731 | .n-bootstrap .input-group > .n-right { | 731 | .n-bootstrap .input-group > .n-right { |
732 | position: absolute; | 732 | position: absolute; |
733 | } | 733 | } |
734 | +@media (min-width: 564px) { | ||
735 | + body.is-dialog .daterangepicker { | ||
736 | + min-width: 130px; | ||
737 | + } | ||
738 | + body.is-dialog .daterangepicker .ranges ul { | ||
739 | + width: 130px; | ||
740 | + } | ||
741 | +} | ||
734 | /*手机版样式*/ | 742 | /*手机版样式*/ |
735 | @media (max-width: 480px) { | 743 | @media (max-width: 480px) { |
736 | .nav-addtabs { | 744 | .nav-addtabs { |
@@ -739,6 +747,10 @@ form.form-horizontal .control-label { | @@ -739,6 +747,10 @@ form.form-horizontal .control-label { | ||
739 | .fixed-table-toolbar .columns-right.btn-group { | 747 | .fixed-table-toolbar .columns-right.btn-group { |
740 | display: none; | 748 | display: none; |
741 | } | 749 | } |
750 | + .fixed .content-wrapper, | ||
751 | + .fixed .right-side { | ||
752 | + padding-top: 50px; | ||
753 | + } | ||
742 | } | 754 | } |
743 | /*平板样式*/ | 755 | /*平板样式*/ |
744 | @media (max-width: 768px) { | 756 | @media (max-width: 768px) { |
此 diff 太大无法显示。
@@ -41,14 +41,6 @@ body { | @@ -41,14 +41,6 @@ body { | ||
41 | -moz-box-shadow: none; | 41 | -moz-box-shadow: none; |
42 | box-shadow: none; | 42 | box-shadow: none; |
43 | } | 43 | } |
44 | -.layui-layer-fast { | ||
45 | - -webkit-animation-fill-mode: both; | ||
46 | - animation-fill-mode: both; | ||
47 | - -webkit-animation-duration: .3s; | ||
48 | - animation-duration: .3s; | ||
49 | - -webkit-animation-name: layer-bounceIn; | ||
50 | - animation-name: layer-bounceIn; | ||
51 | -} | ||
52 | /*修复nice-validator和summernote的编辑框冲突*/ | 44 | /*修复nice-validator和summernote的编辑框冲突*/ |
53 | .nice-validator .note-editor .note-editing-area .note-editable { | 45 | .nice-validator .note-editor .note-editing-area .note-editable { |
54 | display: inherit; | 46 | display: inherit; |
@@ -317,6 +309,8 @@ footer.footer { | @@ -317,6 +309,8 @@ footer.footer { | ||
317 | color: #aaa; | 309 | color: #aaa; |
318 | background: #555; | 310 | background: #555; |
319 | margin-top: 25px; | 311 | margin-top: 25px; |
312 | + position: fixed; | ||
313 | + bottom: 0; | ||
320 | } | 314 | } |
321 | footer.footer ul { | 315 | footer.footer ul { |
322 | margin: 60px 0 30px 0; | 316 | margin: 60px 0 30px 0; |
此 diff 太大无法显示。
public/assets/js/backend-init.js
0 → 100644
@@ -99,6 +99,9 @@ define(['fast', 'moment'], function (Fast, Moment) { | @@ -99,6 +99,9 @@ define(['fast', 'moment'], function (Fast, Moment) { | ||
99 | url = url.replace(/\{ids\}/g, ids); | 99 | url = url.replace(/\{ids\}/g, ids); |
100 | } | 100 | } |
101 | return url; | 101 | return url; |
102 | + }, | ||
103 | + refreshmenu: function () { | ||
104 | + top.window.$(".sidebar-menu").trigger("refresh"); | ||
102 | } | 105 | } |
103 | }, | 106 | }, |
104 | init: function () { | 107 | init: function () { |
@@ -56,6 +56,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -56,6 +56,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
56 | commonSearch: false, | 56 | commonSearch: false, |
57 | searchFormVisible: false, | 57 | searchFormVisible: false, |
58 | pageSize: 12, | 58 | pageSize: 12, |
59 | + pagination: false, | ||
59 | queryParams: function (params) { | 60 | queryParams: function (params) { |
60 | var filter = params.filter ? JSON.parse(params.filter) : {}; | 61 | var filter = params.filter ? JSON.parse(params.filter) : {}; |
61 | var op = params.op ? JSON.parse(params.op) : {}; | 62 | var op = params.op ? JSON.parse(params.op) : {}; |
@@ -111,15 +112,16 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -111,15 +112,16 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
111 | $(".btn-switch,.btn-userinfo").addClass("disabled"); | 112 | $(".btn-switch,.btn-userinfo").addClass("disabled"); |
112 | } | 113 | } |
113 | 114 | ||
115 | + // 离线安装 | ||
114 | require(['upload'], function (Upload) { | 116 | require(['upload'], function (Upload) { |
115 | Upload.api.plupload("#plupload-addon", function (data, ret) { | 117 | Upload.api.plupload("#plupload-addon", function (data, ret) { |
116 | Config['addons'][data.addon.name] = data.addon; | 118 | Config['addons'][data.addon.name] = data.addon; |
117 | - $('.btn-refresh').trigger('click'); | ||
118 | Toastr.success(ret.msg); | 119 | Toastr.success(ret.msg); |
120 | + operate(data.addon.name, 'enable', false); | ||
119 | }); | 121 | }); |
120 | }); | 122 | }); |
121 | 123 | ||
122 | - //查看插件首页 | 124 | + // 查看插件首页 |
123 | $(document).on("click", ".btn-addonindex", function () { | 125 | $(document).on("click", ".btn-addonindex", function () { |
124 | if ($(this).attr("href") == 'javascript:;') { | 126 | if ($(this).attr("href") == 'javascript:;') { |
125 | Layer.msg(__('Not installed tips'), {icon: 7}); | 127 | Layer.msg(__('Not installed tips'), {icon: 7}); |
@@ -128,12 +130,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -128,12 +130,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
128 | return false; | 130 | return false; |
129 | } | 131 | } |
130 | }); | 132 | }); |
131 | - //切换URL | 133 | + |
134 | + // 切换URL | ||
132 | $(document).on("click", ".btn-switch", function () { | 135 | $(document).on("click", ".btn-switch", function () { |
133 | $(".btn-switch").removeClass("active"); | 136 | $(".btn-switch").removeClass("active"); |
134 | $(this).addClass("active"); | 137 | $(this).addClass("active"); |
135 | table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1}); | 138 | table.bootstrapTable('refresh', {url: $(this).data("url"), pageNumber: 1}); |
136 | }); | 139 | }); |
140 | + | ||
137 | // 会员信息 | 141 | // 会员信息 |
138 | $(document).on("click", ".btn-userinfo", function () { | 142 | $(document).on("click", ".btn-userinfo", function () { |
139 | var userinfo = Controller.api.userinfo.get(); | 143 | var userinfo = Controller.api.userinfo.get(); |
@@ -195,15 +199,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -195,15 +199,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
195 | } | 199 | } |
196 | }); | 200 | }); |
197 | 201 | ||
198 | - // 点击安装 | ||
199 | - $(document).on("click", ".btn-install", function () { | ||
200 | - var that = this; | ||
201 | - var name = $(this).closest(".operate").data("name"); | ||
202 | - var version = $(this).data("version"); | 202 | + var install = function (name, version, force) { |
203 | var userinfo = Controller.api.userinfo.get(); | 203 | var userinfo = Controller.api.userinfo.get(); |
204 | var uid = userinfo ? userinfo.id : 0; | 204 | var uid = userinfo ? userinfo.id : 0; |
205 | var token = userinfo ? userinfo.token : ''; | 205 | var token = userinfo ? userinfo.token : ''; |
206 | - var install = function (name, force) { | ||
207 | Fast.api.ajax({ | 206 | Fast.api.ajax({ |
208 | url: 'addon/install', | 207 | url: 'addon/install', |
209 | data: {name: name, force: force ? 1 : 0, uid: uid, token: token, version: version, faversion: Config.fastadmin.version} | 208 | data: {name: name, force: force ? 1 : 0, uid: uid, token: token, version: version, faversion: Config.fastadmin.version} |
@@ -229,6 +228,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -229,6 +228,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
229 | } | 228 | } |
230 | }); | 229 | }); |
231 | $('.btn-refresh').trigger('click'); | 230 | $('.btn-refresh').trigger('click'); |
231 | + Fast.api.refreshmenu(); | ||
232 | }, function (data, ret) { | 232 | }, function (data, ret) { |
233 | //如果是需要购买的插件则弹出二维码提示 | 233 | //如果是需要购买的插件则弹出二维码提示 |
234 | if (ret && ret.code === -1) { | 234 | if (ret && ret.code === -1) { |
@@ -280,26 +280,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -280,26 +280,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
280 | return false; | 280 | return false; |
281 | }); | 281 | }); |
282 | }; | 282 | }; |
283 | - if ($(that).data("type") !== 'free') { | ||
284 | - if (parseInt(uid) === 0) { | ||
285 | - return Layer.alert(__('Not login tips'), { | ||
286 | - title: __('Warning'), | ||
287 | - btn: [__('Login now'), __('Continue install')], | ||
288 | - yes: function (index, layero) { | ||
289 | - $(".btn-userinfo").trigger("click"); | ||
290 | - }, | ||
291 | - btn2: function () { | ||
292 | - install(name, false); | ||
293 | - } | ||
294 | - }); | ||
295 | - } | ||
296 | - } | ||
297 | - install(name, false); | ||
298 | - }); | ||
299 | 283 | ||
300 | - //点击卸载 | ||
301 | - $(document).on("click", ".btn-uninstall", function () { | ||
302 | - var name = $(this).closest(".operate").data("name"); | ||
303 | var uninstall = function (name, force) { | 284 | var uninstall = function (name, force) { |
304 | Fast.api.ajax({ | 285 | Fast.api.ajax({ |
305 | url: 'addon/uninstall', | 286 | url: 'addon/uninstall', |
@@ -308,6 +289,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -308,6 +289,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
308 | delete Config['addons'][name]; | 289 | delete Config['addons'][name]; |
309 | Layer.closeAll(); | 290 | Layer.closeAll(); |
310 | $('.btn-refresh').trigger('click'); | 291 | $('.btn-refresh').trigger('click'); |
292 | + Fast.api.refreshmenu(); | ||
311 | }, function (data, ret) { | 293 | }, function (data, ret) { |
312 | if (ret && ret.code === -3) { | 294 | if (ret && ret.code === -3) { |
313 | //插件目录发现影响全局的文件 | 295 | //插件目录发现影响全局的文件 |
@@ -331,21 +313,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -331,21 +313,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
331 | return false; | 313 | return false; |
332 | }); | 314 | }); |
333 | }; | 315 | }; |
334 | - Layer.confirm(__('Uninstall tips'), function () { | ||
335 | - uninstall(name, false); | ||
336 | - }); | ||
337 | - }); | ||
338 | - | ||
339 | - //点击配置 | ||
340 | - $(document).on("click", ".btn-config", function () { | ||
341 | - var name = $(this).closest(".operate").data("name"); | ||
342 | - Fast.api.open("addon/config?name=" + name, __('Setting')); | ||
343 | - }); | ||
344 | 316 | ||
345 | - //点击启用/禁用 | ||
346 | - $(document).on("click", ".btn-enable,.btn-disable", function () { | ||
347 | - var name = $(this).closest(".operate").data("name"); | ||
348 | - var action = $(this).data("action"); | ||
349 | var operate = function (name, action, force) { | 317 | var operate = function (name, action, force) { |
350 | Fast.api.ajax({ | 318 | Fast.api.ajax({ |
351 | url: 'addon/state', | 319 | url: 'addon/state', |
@@ -355,6 +323,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -355,6 +323,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
355 | addon.state = action === 'enable' ? 1 : 0; | 323 | addon.state = action === 'enable' ? 1 : 0; |
356 | Layer.closeAll(); | 324 | Layer.closeAll(); |
357 | $('.btn-refresh').trigger('click'); | 325 | $('.btn-refresh').trigger('click'); |
326 | + Fast.api.refreshmenu(); | ||
358 | }, function (data, ret) { | 327 | }, function (data, ret) { |
359 | if (ret && ret.code === -3) { | 328 | if (ret && ret.code === -3) { |
360 | //插件目录发现影响全局的文件 | 329 | //插件目录发现影响全局的文件 |
@@ -378,21 +347,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -378,21 +347,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
378 | return false; | 347 | return false; |
379 | }); | 348 | }); |
380 | }; | 349 | }; |
381 | - operate(name, action, false); | ||
382 | - }); | ||
383 | 350 | ||
384 | - //点击升级 | ||
385 | - $(document).on("click", ".btn-upgrade", function () { | ||
386 | - if ($(this).closest(".operate").find("a.btn-disable").size() > 0) { | ||
387 | - Layer.alert(__('Please disable addon first'), {icon: 7}); | ||
388 | - return false; | ||
389 | - } | ||
390 | - var name = $(this).closest(".operate").data("name"); | ||
391 | - var version = $(this).data("version"); | 351 | + var upgrade = function (name, version) { |
392 | var userinfo = Controller.api.userinfo.get(); | 352 | var userinfo = Controller.api.userinfo.get(); |
393 | var uid = userinfo ? userinfo.id : 0; | 353 | var uid = userinfo ? userinfo.id : 0; |
394 | var token = userinfo ? userinfo.token : ''; | 354 | var token = userinfo ? userinfo.token : ''; |
395 | - var upgrade = function (name) { | ||
396 | Fast.api.ajax({ | 355 | Fast.api.ajax({ |
397 | url: 'addon/upgrade', | 356 | url: 'addon/upgrade', |
398 | data: {name: name, uid: uid, token: token, version: version, faversion: Config.fastadmin.version} | 357 | data: {name: name, uid: uid, token: token, version: version, faversion: Config.fastadmin.version} |
@@ -400,13 +359,71 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -400,13 +359,71 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
400 | Config['addons'][name].version = version; | 359 | Config['addons'][name].version = version; |
401 | Layer.closeAll(); | 360 | Layer.closeAll(); |
402 | $('.btn-refresh').trigger('click'); | 361 | $('.btn-refresh').trigger('click'); |
362 | + Fast.api.refreshmenu(); | ||
403 | }, function (data, ret) { | 363 | }, function (data, ret) { |
404 | Layer.alert(ret.msg); | 364 | Layer.alert(ret.msg); |
405 | return false; | 365 | return false; |
406 | }); | 366 | }); |
407 | }; | 367 | }; |
368 | + | ||
369 | + // 点击安装 | ||
370 | + $(document).on("click", ".btn-install", function () { | ||
371 | + var that = this; | ||
372 | + var name = $(this).closest(".operate").data("name"); | ||
373 | + var version = $(this).data("version"); | ||
374 | + | ||
375 | + var userinfo = Controller.api.userinfo.get(); | ||
376 | + var uid = userinfo ? userinfo.id : 0; | ||
377 | + | ||
378 | + if ($(that).data("type") !== 'free') { | ||
379 | + if (parseInt(uid) === 0) { | ||
380 | + return Layer.alert(__('Not login tips'), { | ||
381 | + title: __('Warning'), | ||
382 | + btn: [__('Login now'), __('Continue install')], | ||
383 | + yes: function (index, layero) { | ||
384 | + $(".btn-userinfo").trigger("click"); | ||
385 | + }, | ||
386 | + btn2: function () { | ||
387 | + install(name, version, false); | ||
388 | + } | ||
389 | + }); | ||
390 | + } | ||
391 | + } | ||
392 | + install(name, version, false); | ||
393 | + }); | ||
394 | + | ||
395 | + // 点击卸载 | ||
396 | + $(document).on("click", ".btn-uninstall", function () { | ||
397 | + var name = $(this).closest(".operate").data("name"); | ||
398 | + Layer.confirm(__('Uninstall tips'), function () { | ||
399 | + uninstall(name, false); | ||
400 | + }); | ||
401 | + }); | ||
402 | + | ||
403 | + // 点击配置 | ||
404 | + $(document).on("click", ".btn-config", function () { | ||
405 | + var name = $(this).closest(".operate").data("name"); | ||
406 | + Fast.api.open("addon/config?name=" + name, __('Setting')); | ||
407 | + }); | ||
408 | + | ||
409 | + // 点击启用/禁用 | ||
410 | + $(document).on("click", ".btn-enable,.btn-disable", function () { | ||
411 | + var name = $(this).closest(".operate").data("name"); | ||
412 | + var action = $(this).data("action"); | ||
413 | + operate(name, action, false); | ||
414 | + }); | ||
415 | + | ||
416 | + // 点击升级 | ||
417 | + $(document).on("click", ".btn-upgrade", function () { | ||
418 | + if ($(this).closest(".operate").find("a.btn-disable").size() > 0) { | ||
419 | + Layer.alert(__('Please disable addon first'), {icon: 7}); | ||
420 | + return false; | ||
421 | + } | ||
422 | + var name = $(this).closest(".operate").data("name"); | ||
423 | + var version = $(this).data("version"); | ||
424 | + | ||
408 | Layer.confirm(__('Upgrade tips'), function () { | 425 | Layer.confirm(__('Upgrade tips'), function () { |
409 | - upgrade(name); | 426 | + upgrade(name, version); |
410 | }); | 427 | }); |
411 | }); | 428 | }); |
412 | 429 |
@@ -20,7 +20,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -20,7 +20,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
20 | table.bootstrapTable({ | 20 | table.bootstrapTable({ |
21 | url: $.fn.bootstrapTable.defaults.extend.index_url, | 21 | url: $.fn.bootstrapTable.defaults.extend.index_url, |
22 | sortName: 'weigh', | 22 | sortName: 'weigh', |
23 | - escape:false, | 23 | + escape: false, |
24 | columns: [ | 24 | columns: [ |
25 | [ | 25 | [ |
26 | {field: 'state', checkbox: true, }, | 26 | {field: 'state', checkbox: true, }, |
@@ -41,10 +41,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -41,10 +41,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
41 | }); | 41 | }); |
42 | 42 | ||
43 | // 为表格绑定事件 | 43 | // 为表格绑定事件 |
44 | - Table.api.bindevent(table);//当内容渲染完成后 | 44 | + Table.api.bindevent(table); |
45 | 45 | ||
46 | - //默认隐藏所有子节点 | 46 | + //当内容渲染完成后 |
47 | table.on('post-body.bs.table', function (e, settings, json, xhr) { | 47 | table.on('post-body.bs.table', function (e, settings, json, xhr) { |
48 | + //默认隐藏所有子节点 | ||
48 | //$("a.btn[data-id][data-pid][data-pid!=0]").closest("tr").hide(); | 49 | //$("a.btn[data-id][data-pid][data-pid!=0]").closest("tr").hide(); |
49 | $(".btn-node-sub.disabled").closest("tr").hide(); | 50 | $(".btn-node-sub.disabled").closest("tr").hide(); |
50 | 51 | ||
@@ -57,8 +58,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -57,8 +58,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
57 | $(this).data("shown", !status); | 58 | $(this).data("shown", !status); |
58 | return false; | 59 | return false; |
59 | }); | 60 | }); |
61 | + $(".btn-change[data-id],.btn-delone,.btn-dragsort").data("success", function (data, ret) { | ||
62 | + Fast.api.refreshmenu(); | ||
63 | + }); | ||
60 | 64 | ||
61 | }); | 65 | }); |
66 | + //批量删除后的回调 | ||
67 | + $(".toolbar > .btn-del,.toolbar .btn-more~ul>li>a").data("success", function (e) { | ||
68 | + Fast.api.refreshmenu(); | ||
69 | + }); | ||
62 | //展开隐藏一级 | 70 | //展开隐藏一级 |
63 | $(document.body).on("click", ".btn-toggle", function (e) { | 71 | $(document.body).on("click", ".btn-toggle", function (e) { |
64 | $("a.btn[data-id][data-pid][data-pid!=0].disabled").closest("tr").hide(); | 72 | $("a.btn[data-id][data-pid][data-pid!=0].disabled").closest("tr").hide(); |
@@ -88,21 +96,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -88,21 +96,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
88 | api: { | 96 | api: { |
89 | formatter: { | 97 | formatter: { |
90 | title: function (value, row, index) { | 98 | title: function (value, row, index) { |
91 | - return !row.ismenu ? "<span class='text-muted'>" + value + "</span>" : value; | 99 | + return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value; |
92 | }, | 100 | }, |
93 | name: function (value, row, index) { | 101 | name: function (value, row, index) { |
94 | - return !row.ismenu ? "<span class='text-muted'>" + value + "</span>" : value; | 102 | + return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value; |
95 | }, | 103 | }, |
96 | menu: function (value, row, index) { | 104 | menu: function (value, row, index) { |
97 | return "<a href='javascript:;' class='btn btn-" + (value ? "info" : "default") + " btn-xs btn-change' data-id='" | 105 | return "<a href='javascript:;' class='btn btn-" + (value ? "info" : "default") + " btn-xs btn-change' data-id='" |
98 | + row.id + "' data-params='ismenu=" + (value ? 0 : 1) + "'>" + (value ? __('Yes') : __('No')) + "</a>"; | 106 | + row.id + "' data-params='ismenu=" + (value ? 0 : 1) + "'>" + (value ? __('Yes') : __('No')) + "</a>"; |
99 | }, | 107 | }, |
100 | icon: function (value, row, index) { | 108 | icon: function (value, row, index) { |
101 | - return '<i class="' + value + '"></i>'; | 109 | + return '<span class="' + (!row.ismenu || row.status == 'hidden' ? 'text-muted' : '') + '"><i class="' + value + '"></i></span>'; |
102 | }, | 110 | }, |
103 | subnode: function (value, row, index) { | 111 | subnode: function (value, row, index) { |
104 | - return '<a href="javascript:;" data-id="' + row['id'] + '" data-pid="' + row['pid'] + '" class="btn btn-xs ' | ||
105 | - + (row['haschild'] == 1 ? 'btn-success' : 'btn-default disabled') + ' btn-node-sub"><i class="fa fa-sitemap"></i></a>'; | 112 | + return '<a href="javascript:;" data-id="' + row.id + '" data-pid="' + row.pid + '" class="btn btn-xs ' |
113 | + + (row.haschild == 1 || row.ismenu == 1 ? 'btn-success' : 'btn-default disabled') + ' btn-node-sub"><i class="fa fa-sitemap"></i></a>'; | ||
106 | } | 114 | } |
107 | }, | 115 | }, |
108 | bindevent: function () { | 116 | bindevent: function () { |
@@ -113,7 +121,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | @@ -113,7 +121,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function | ||
113 | $("input[name='row[ismenu]']:checked").trigger("click"); | 121 | $("input[name='row[ismenu]']:checked").trigger("click"); |
114 | 122 | ||
115 | var iconlist = []; | 123 | var iconlist = []; |
116 | - Form.api.bindevent($("form[role=form]")); | 124 | + Form.api.bindevent($("form[role=form]"), function (data) { |
125 | + Fast.api.refreshmenu(); | ||
126 | + }); | ||
117 | $(document).on('click', ".btn-search-icon", function () { | 127 | $(document).on('click', ".btn-search-icon", function () { |
118 | if (iconlist.length == 0) { | 128 | if (iconlist.length == 0) { |
119 | $.get(Config.site.cdnurl + "/assets/libs/font-awesome/less/variables.less", function (ret) { | 129 | $.get(Config.site.cdnurl + "/assets/libs/font-awesome/less/variables.less", function (ret) { |
@@ -178,6 +178,21 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | @@ -178,6 +178,21 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | ||
178 | } | 178 | } |
179 | }); | 179 | }); |
180 | 180 | ||
181 | + //刷新菜单事件 | ||
182 | + $(document).on('refresh', '.sidebar-menu', function () { | ||
183 | + Fast.api.ajax({ | ||
184 | + url: 'index/index', | ||
185 | + data: {action: 'refreshmenu'} | ||
186 | + }, function (data) { | ||
187 | + $(".sidebar-menu li:not([data-rel='external'])").remove(); | ||
188 | + $(data.menulist).insertBefore($(".sidebar-menu li:first")); | ||
189 | + $("#nav ul li[role='presentation'].active a").trigger('click'); | ||
190 | + return false; | ||
191 | + }, function () { | ||
192 | + return false; | ||
193 | + }); | ||
194 | + }); | ||
195 | + | ||
181 | //这一行需要放在点击左侧链接事件之前 | 196 | //这一行需要放在点击左侧链接事件之前 |
182 | var addtabs = Config.referer ? localStorage.getItem("addtabs") : null; | 197 | var addtabs = Config.referer ? localStorage.getItem("addtabs") : null; |
183 | 198 | ||
@@ -188,6 +203,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | @@ -188,6 +203,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | ||
188 | } else { | 203 | } else { |
189 | $("ul.sidebar-menu li a[url!='javascript:;']:first").trigger("click"); | 204 | $("ul.sidebar-menu li a[url!='javascript:;']:first").trigger("click"); |
190 | } | 205 | } |
206 | + | ||
191 | //如果是刷新操作则直接返回刷新前的页面 | 207 | //如果是刷新操作则直接返回刷新前的页面 |
192 | if (Config.referer) { | 208 | if (Config.referer) { |
193 | if (Config.referer === $(addtabs).attr("url")) { | 209 | if (Config.referer === $(addtabs).attr("url")) { |
@@ -203,11 +219,6 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | @@ -203,11 +219,6 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | ||
203 | } | 219 | } |
204 | } | 220 | } |
205 | 221 | ||
206 | - /** | ||
207 | - * List of all the available skins | ||
208 | - * | ||
209 | - * @type Array | ||
210 | - */ | ||
211 | var my_skins = [ | 222 | var my_skins = [ |
212 | "skin-blue", | 223 | "skin-blue", |
213 | "skin-white", | 224 | "skin-white", |
@@ -224,19 +235,13 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | @@ -224,19 +235,13 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | ||
224 | ]; | 235 | ]; |
225 | setup(); | 236 | setup(); |
226 | 237 | ||
227 | - /** | ||
228 | - * Toggles layout classes | ||
229 | - * | ||
230 | - * @param String cls the layout class to toggle | ||
231 | - * @returns void | ||
232 | - */ | ||
233 | function change_layout(cls) { | 238 | function change_layout(cls) { |
234 | $("body").toggleClass(cls); | 239 | $("body").toggleClass(cls); |
235 | AdminLTE.layout.fixSidebar(); | 240 | AdminLTE.layout.fixSidebar(); |
236 | //Fix the problem with right sidebar and layout boxed | 241 | //Fix the problem with right sidebar and layout boxed |
237 | if (cls == "layout-boxed") | 242 | if (cls == "layout-boxed") |
238 | AdminLTE.controlSidebar._fix($(".control-sidebar-bg")); | 243 | AdminLTE.controlSidebar._fix($(".control-sidebar-bg")); |
239 | - if ($('body').hasClass('fixed') && cls == 'fixed' && false) { | 244 | + if ($('body').hasClass('fixed') && cls == 'fixed') { |
240 | AdminLTE.pushMenu.expandOnHover(); | 245 | AdminLTE.pushMenu.expandOnHover(); |
241 | AdminLTE.layout.activate(); | 246 | AdminLTE.layout.activate(); |
242 | } | 247 | } |
@@ -244,61 +249,18 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | @@ -244,61 +249,18 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi | ||
244 | AdminLTE.controlSidebar._fix($(".control-sidebar")); | 249 | AdminLTE.controlSidebar._fix($(".control-sidebar")); |
245 | } | 250 | } |
246 | 251 | ||
247 | - /** | ||
248 | - * Replaces the old skin with the new skin | ||
249 | - * @param String cls the new skin class | ||
250 | - * @returns Boolean false to prevent link's default action | ||
251 | - */ | ||
252 | function change_skin(cls) { | 252 | function change_skin(cls) { |
253 | if (!$("body").hasClass(cls)) { | 253 | if (!$("body").hasClass(cls)) { |
254 | - $.each(my_skins, function (i) { | ||
255 | - $("body").removeClass(my_skins[i]); | ||
256 | - }); | ||
257 | - | ||
258 | - $("body").addClass(cls); | ||
259 | - store('skin', cls); | 254 | + $("body").removeClass(my_skins.join(' ')).addClass(cls); |
255 | + localStorage.setItem('skin', cls); | ||
260 | var cssfile = Config.site.cdnurl + "/assets/css/skins/" + cls + ".css"; | 256 | var cssfile = Config.site.cdnurl + "/assets/css/skins/" + cls + ".css"; |
261 | $('head').append('<link rel="stylesheet" href="' + cssfile + '" type="text/css" />'); | 257 | $('head').append('<link rel="stylesheet" href="' + cssfile + '" type="text/css" />'); |
262 | } | 258 | } |
263 | return false; | 259 | return false; |
264 | } | 260 | } |
265 | 261 | ||
266 | - /** | ||
267 | - * Store a new settings in the browser | ||
268 | - * | ||
269 | - * @param String name Name of the setting | ||
270 | - * @param String val Value of the setting | ||
271 | - * @returns void | ||
272 | - */ | ||
273 | - function store(name, val) { | ||
274 | - if (typeof (Storage) !== "undefined") { | ||
275 | - localStorage.setItem(name, val); | ||
276 | - } else { | ||
277 | - window.alert('Please use a modern browser to properly view this template!'); | ||
278 | - } | ||
279 | - } | ||
280 | - | ||
281 | - /** | ||
282 | - * Get a prestored setting | ||
283 | - * | ||
284 | - * @param String name Name of of the setting | ||
285 | - * @returns String The value of the setting | null | ||
286 | - */ | ||
287 | - function get(name) { | ||
288 | - if (typeof (Storage) !== "undefined") { | ||
289 | - return localStorage.getItem(name); | ||
290 | - } else { | ||
291 | - window.alert('Please use a modern browser to properly view this template!'); | ||
292 | - } | ||
293 | - } | ||
294 | - | ||
295 | - /** | ||
296 | - * Retrieve default settings and apply them to the template | ||
297 | - * | ||
298 | - * @returns void | ||
299 | - */ | ||
300 | function setup() { | 262 | function setup() { |
301 | - var tmp = get('skin'); | 263 | + var tmp = localStorage.getItem('skin'); |
302 | if (tmp && $.inArray(tmp, my_skins)) | 264 | if (tmp && $.inArray(tmp, my_skins)) |
303 | change_skin(tmp); | 265 | change_skin(tmp); |
304 | 266 |
@@ -28,7 +28,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin | @@ -28,7 +28,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin | ||
28 | {field: 'id', title: __('Id')}, | 28 | {field: 'id', title: __('Id')}, |
29 | {field: 'pid', title: __('Pid'), visible: false}, | 29 | {field: 'pid', title: __('Pid'), visible: false}, |
30 | {field: 'title', title: __('Title'), align: 'left'}, | 30 | {field: 'title', title: __('Title'), align: 'left'}, |
31 | - {field: 'name', title: __('Name')}, | 31 | + {field: 'name', title: __('Name'), align: 'left'}, |
32 | {field: 'remark', title: __('Remark')}, | 32 | {field: 'remark', title: __('Remark')}, |
33 | {field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle}, | 33 | {field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle}, |
34 | {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, visible: false}, | 34 | {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, visible: false}, |
@@ -104,7 +104,7 @@ | @@ -104,7 +104,7 @@ | ||
104 | 104 | ||
105 | var createFormCommon = function (pColumns, that) { | 105 | var createFormCommon = function (pColumns, that) { |
106 | var htmlForm = []; | 106 | var htmlForm = []; |
107 | - var opList = ['=', '>', '>=', '<', '<=', '!=', 'LIKE', 'LIKE %...%', 'NOT LIKE', 'IN', 'NOT IN', 'IN(...)', 'NOT IN(...)', 'BETWEEN', 'NOT BETWEEN', 'RANGE', 'NOT RANGE', 'IS NULL', 'IS NOT NULL']; | 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)); | 108 | htmlForm.push(sprintf('<form class="form-horizontal form-commonsearch" action="%s" >', that.options.actionForm)); |
109 | htmlForm.push('<fieldset>'); | 109 | htmlForm.push('<fieldset>'); |
110 | if (that.options.titleForm.length > 0) | 110 | if (that.options.titleForm.length > 0) |
@@ -164,8 +164,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine | @@ -164,8 +164,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine | ||
164 | options.area = [top.$(".tab-pane.active").width() + "px", top.$(".tab-pane.active").height() + "px"]; | 164 | options.area = [top.$(".tab-pane.active").width() + "px", top.$(".tab-pane.active").height() + "px"]; |
165 | options.offset = [top.$(".tab-pane.active").scrollTop() + "px", "0px"]; | 165 | options.offset = [top.$(".tab-pane.active").scrollTop() + "px", "0px"]; |
166 | } | 166 | } |
167 | - Layer.open(options); | ||
168 | - return false; | 167 | + return Layer.open(options); |
169 | }, | 168 | }, |
170 | //关闭窗口并回传数据 | 169 | //关闭窗口并回传数据 |
171 | close: function (data) { | 170 | close: function (data) { |
public/assets/js/frontend-init.js
0 → 100644
@@ -7,7 +7,7 @@ require.config({ | @@ -7,7 +7,7 @@ require.config({ | ||
7 | } | 7 | } |
8 | ], | 8 | ], |
9 | //在打包压缩时将会把include中的模块合并到主文件中 | 9 | //在打包压缩时将会把include中的模块合并到主文件中 |
10 | - include: ['css', 'layer', 'toastr', 'fast', 'backend', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs', 'selectpage'], | 10 | + include: ['css', 'layer', 'toastr', 'fast', 'backend', 'backend-init', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs', 'selectpage'], |
11 | paths: { | 11 | paths: { |
12 | 'lang': "empty:", | 12 | 'lang': "empty:", |
13 | 'form': 'require-form', | 13 | 'form': 'require-form', |
@@ -34,22 +34,20 @@ require.config({ | @@ -34,22 +34,20 @@ require.config({ | ||
34 | 'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile', | 34 | 'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile', |
35 | 'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN', | 35 | 'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN', |
36 | 'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min', | 36 | 'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min', |
37 | - 'dragsort': '../libs/dragsort/jquery.dragsort', | ||
38 | - 'qrcode': '../libs/jquery-qrcode/jquery.qrcode.min', | 37 | + 'dragsort': '../libs/fastadmin-dragsort/jquery.dragsort', |
39 | 'sortable': '../libs/Sortable/Sortable.min', | 38 | 'sortable': '../libs/Sortable/Sortable.min', |
40 | - 'addtabs': '../libs/jquery-addtabs/jquery.addtabs', | 39 | + 'addtabs': '../libs/fastadmin-addtabs/jquery.addtabs', |
41 | 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', | 40 | 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', |
42 | - 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min', | ||
43 | 'validator-core': '../libs/nice-validator/dist/jquery.validator', | 41 | 'validator-core': '../libs/nice-validator/dist/jquery.validator', |
44 | 'validator-lang': '../libs/nice-validator/dist/local/zh-CN', | 42 | 'validator-lang': '../libs/nice-validator/dist/local/zh-CN', |
45 | 'plupload': '../libs/plupload/js/plupload.min', | 43 | 'plupload': '../libs/plupload/js/plupload.min', |
46 | 'toastr': '../libs/toastr/toastr', | 44 | 'toastr': '../libs/toastr/toastr', |
47 | 'jstree': '../libs/jstree/dist/jstree.min', | 45 | 'jstree': '../libs/jstree/dist/jstree.min', |
48 | - 'layer': '../libs/layer/src/layer', | 46 | + 'layer': '../libs/layer/dist/layer', |
49 | 'cookie': '../libs/jquery.cookie/jquery.cookie', | 47 | 'cookie': '../libs/jquery.cookie/jquery.cookie', |
50 | - 'cxselect': '../libs/jquery-cxselect/js/jquery.cxselect', | 48 | + 'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect', |
51 | 'template': '../libs/art-template/dist/template-native', | 49 | 'template': '../libs/art-template/dist/template-native', |
52 | - 'selectpage': '../libs/selectpage/selectpage', | 50 | + 'selectpage': '../libs/fastadmin-selectpage/selectpage', |
53 | 'citypicker': '../libs/city-picker/dist/js/city-picker.min', | 51 | 'citypicker': '../libs/city-picker/dist/js/city-picker.min', |
54 | 'citypicker-data': '../libs/city-picker/dist/js/city-picker.data', | 52 | 'citypicker-data': '../libs/city-picker/dist/js/city-picker.data', |
55 | }, | 53 | }, |
@@ -106,7 +104,6 @@ require.config({ | @@ -106,7 +104,6 @@ require.config({ | ||
106 | ], | 104 | ], |
107 | 'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ], | 105 | 'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ], |
108 | 'bootstrap-select-lang': ['bootstrap-select'], | 106 | 'bootstrap-select-lang': ['bootstrap-select'], |
109 | - 'summernote': ['../libs/summernote/dist/summernote.min', 'css!../libs/summernote/dist/summernote.css'], | ||
110 | // 'toastr': ['css!../libs/toastr/toastr.min.css'], | 107 | // 'toastr': ['css!../libs/toastr/toastr.min.css'], |
111 | 'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ], | 108 | 'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ], |
112 | 'plupload': { | 109 | 'plupload': { |
@@ -116,7 +113,7 @@ require.config({ | @@ -116,7 +113,7 @@ require.config({ | ||
116 | // 'layer': ['css!../libs/layer/dist/theme/default/layer.css'], | 113 | // 'layer': ['css!../libs/layer/dist/theme/default/layer.css'], |
117 | // 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'], | 114 | // 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'], |
118 | 'validator-lang': ['validator-core'], | 115 | 'validator-lang': ['validator-core'], |
119 | -// 'selectpage': ['css!../libs/selectpage/selectpage.css'], | 116 | +// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'], |
120 | 'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css'] | 117 | 'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css'] |
121 | }, | 118 | }, |
122 | baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径 | 119 | baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径 |
@@ -144,7 +141,7 @@ require(['jquery', 'bootstrap'], function ($, undefined) { | @@ -144,7 +141,7 @@ require(['jquery', 'bootstrap'], function ($, undefined) { | ||
144 | // 初始化 | 141 | // 初始化 |
145 | $(function () { | 142 | $(function () { |
146 | require(['fast'], function (Fast) { | 143 | require(['fast'], function (Fast) { |
147 | - require(['backend', 'addons'], function (Backend, Addons) { | 144 | + require(['backend', 'backend-init', 'addons'], function (Backend, undefined, Addons) { |
148 | //加载相应模块 | 145 | //加载相应模块 |
149 | if (Config.jsname) { | 146 | if (Config.jsname) { |
150 | require([Config.jsname], function (Controller) { | 147 | require([Config.jsname], function (Controller) { |
此 diff 太大无法显示。
@@ -40,6 +40,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | @@ -40,6 +40,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | ||
40 | Form.api.submit($(ret), function (data, ret) { | 40 | Form.api.submit($(ret), function (data, ret) { |
41 | that.holdSubmit(false); | 41 | that.holdSubmit(false); |
42 | submitBtn.removeClass("disabled"); | 42 | submitBtn.removeClass("disabled"); |
43 | + if (false === $(this).triggerHandler("success.form", [data, ret])) { | ||
44 | + return false; | ||
45 | + } | ||
43 | if (typeof success === 'function') { | 46 | if (typeof success === 'function') { |
44 | if (false === success.call($(this), data, ret)) { | 47 | if (false === success.call($(this), data, ret)) { |
45 | return false; | 48 | return false; |
@@ -54,6 +57,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | @@ -54,6 +57,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | ||
54 | return false; | 57 | return false; |
55 | }, function (data, ret) { | 58 | }, function (data, ret) { |
56 | that.holdSubmit(false); | 59 | that.holdSubmit(false); |
60 | + if (false === $(this).triggerHandler("error.form", [data, ret])) { | ||
61 | + return false; | ||
62 | + } | ||
57 | submitBtn.removeClass("disabled"); | 63 | submitBtn.removeClass("disabled"); |
58 | if (typeof error === 'function') { | 64 | if (typeof error === 'function') { |
59 | if (false === error.call($(this), data, ret)) { | 65 | if (false === error.call($(this), data, ret)) { |
@@ -81,13 +87,25 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | @@ -81,13 +87,25 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | ||
81 | if ($(".selectpage", form).size() > 0) { | 87 | if ($(".selectpage", form).size() > 0) { |
82 | require(['selectpage'], function () { | 88 | require(['selectpage'], function () { |
83 | $('.selectpage', form).selectPage({ | 89 | $('.selectpage', form).selectPage({ |
84 | - source: 'ajax/selectpage', | 90 | + eAjaxSuccess: function (data) { |
91 | + data.list = typeof data.rows !== 'undefined' ? data.rows : (typeof data.list !== 'undefined' ? data.list : []); | ||
92 | + data.totalRow = typeof data.total !== 'undefined' ? data.total : (typeof data.totalRow !== 'undefined' ? data.totalRow : data.list.length); | ||
93 | + return data; | ||
94 | + } | ||
85 | }); | 95 | }); |
86 | }); | 96 | }); |
87 | //给隐藏的元素添加上validate验证触发事件 | 97 | //给隐藏的元素添加上validate验证触发事件 |
88 | - $(form).on("change", ".selectpage-input-hidden", function () { | 98 | + $(document).on("change", ".sp_hidden", function () { |
89 | $(this).trigger("validate"); | 99 | $(this).trigger("validate"); |
90 | }); | 100 | }); |
101 | + $(document).on("change", ".sp_input", function () { | ||
102 | + $(this).closest(".sp_container").find(".sp_hidden").trigger("change"); | ||
103 | + }); | ||
104 | + $(form).on("reset", function () { | ||
105 | + setTimeout(function () { | ||
106 | + $('.selectpage', form).selectPageClear(); | ||
107 | + }, 1); | ||
108 | + }); | ||
91 | } | 109 | } |
92 | }, | 110 | }, |
93 | cxselect: function (form) { | 111 | cxselect: function (form) { |
@@ -132,6 +150,48 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | @@ -132,6 +150,48 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | ||
132 | }); | 150 | }); |
133 | } | 151 | } |
134 | }, | 152 | }, |
153 | + daterangepicker: function (form) { | ||
154 | + //绑定日期时间元素事件 | ||
155 | + if ($(".datetimerange", form).size() > 0) { | ||
156 | + require(['bootstrap-daterangepicker'], function () { | ||
157 | + var ranges = {}; | ||
158 | + ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')]; | ||
159 | + ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')]; | ||
160 | + ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')]; | ||
161 | + ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')]; | ||
162 | + ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')]; | ||
163 | + ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')]; | ||
164 | + var options = { | ||
165 | + timePicker: false, | ||
166 | + autoUpdateInput: false, | ||
167 | + timePickerSeconds: true, | ||
168 | + timePicker24Hour: true, | ||
169 | + autoApply: true, | ||
170 | + locale: { | ||
171 | + format: 'YYYY-MM-DD HH:mm:ss', | ||
172 | + customRangeLabel: __("Custom Range"), | ||
173 | + applyLabel: __("Apply"), | ||
174 | + cancelLabel: __("Clear"), | ||
175 | + }, | ||
176 | + ranges: ranges, | ||
177 | + }; | ||
178 | + var origincallback = function (start, end) { | ||
179 | + $(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format)); | ||
180 | + $(this.element).trigger('blur'); | ||
181 | + }; | ||
182 | + $(".datetimerange", form).each(function () { | ||
183 | + var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback; | ||
184 | + $(this).on('apply.daterangepicker', function (ev, picker) { | ||
185 | + callback.call(picker, picker.startDate, picker.endDate); | ||
186 | + }); | ||
187 | + $(this).on('cancel.daterangepicker', function (ev, picker) { | ||
188 | + $(this).val('').trigger('blur'); | ||
189 | + }); | ||
190 | + $(this).daterangepicker($.extend({}, options, $(this).data()), callback); | ||
191 | + }); | ||
192 | + }); | ||
193 | + } | ||
194 | + }, | ||
135 | plupload: function (form) { | 195 | plupload: function (form) { |
136 | //绑定plupload上传元素事件 | 196 | //绑定plupload上传元素事件 |
137 | if ($(".plupload", form).size() > 0) { | 197 | if ($(".plupload", form).size() > 0) { |
@@ -287,6 +347,8 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | @@ -287,6 +347,8 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U | ||
287 | 347 | ||
288 | events.selectpicker(form); | 348 | events.selectpicker(form); |
289 | 349 | ||
350 | + events.daterangepicker(form); | ||
351 | + | ||
290 | events.selectpage(form); | 352 | events.selectpage(form); |
291 | 353 | ||
292 | events.cxselect(form); | 354 | events.cxselect(form); |
@@ -7,7 +7,7 @@ require.config({ | @@ -7,7 +7,7 @@ require.config({ | ||
7 | } | 7 | } |
8 | ], | 8 | ], |
9 | //在打包压缩时将会把include中的模块合并到主文件中 | 9 | //在打包压缩时将会把include中的模块合并到主文件中 |
10 | - include: ['css', 'layer', 'toastr', 'fast', 'frontend'], | 10 | + include: ['css', 'layer', 'toastr', 'fast', 'frontend', 'frontend-init'], |
11 | paths: { | 11 | paths: { |
12 | 'lang': "empty:", | 12 | 'lang': "empty:", |
13 | 'form': 'require-form', | 13 | 'form': 'require-form', |
@@ -34,22 +34,20 @@ require.config({ | @@ -34,22 +34,20 @@ require.config({ | ||
34 | 'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile', | 34 | 'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile', |
35 | 'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN', | 35 | 'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN', |
36 | 'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min', | 36 | 'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min', |
37 | - 'dragsort': '../libs/dragsort/jquery.dragsort', | ||
38 | - 'qrcode': '../libs/jquery-qrcode/jquery.qrcode.min', | 37 | + 'dragsort': '../libs/fastadmin-dragsort/jquery.dragsort', |
39 | 'sortable': '../libs/Sortable/Sortable.min', | 38 | 'sortable': '../libs/Sortable/Sortable.min', |
40 | - 'addtabs': '../libs/jquery-addtabs/jquery.addtabs', | 39 | + 'addtabs': '../libs/fastadmin-addtabs/jquery.addtabs', |
41 | 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', | 40 | 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', |
42 | - 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min', | ||
43 | 'validator-core': '../libs/nice-validator/dist/jquery.validator', | 41 | 'validator-core': '../libs/nice-validator/dist/jquery.validator', |
44 | 'validator-lang': '../libs/nice-validator/dist/local/zh-CN', | 42 | 'validator-lang': '../libs/nice-validator/dist/local/zh-CN', |
45 | 'plupload': '../libs/plupload/js/plupload.min', | 43 | 'plupload': '../libs/plupload/js/plupload.min', |
46 | 'toastr': '../libs/toastr/toastr', | 44 | 'toastr': '../libs/toastr/toastr', |
47 | 'jstree': '../libs/jstree/dist/jstree.min', | 45 | 'jstree': '../libs/jstree/dist/jstree.min', |
48 | - 'layer': '../libs/layer/src/layer', | 46 | + 'layer': '../libs/layer/dist/layer', |
49 | 'cookie': '../libs/jquery.cookie/jquery.cookie', | 47 | 'cookie': '../libs/jquery.cookie/jquery.cookie', |
50 | - 'cxselect': '../libs/jquery-cxselect/js/jquery.cxselect', | 48 | + 'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect', |
51 | 'template': '../libs/art-template/dist/template-native', | 49 | 'template': '../libs/art-template/dist/template-native', |
52 | - 'selectpage': '../libs/selectpage/selectpage', | 50 | + 'selectpage': '../libs/fastadmin-selectpage/selectpage', |
53 | 'citypicker': '../libs/city-picker/dist/js/city-picker.min', | 51 | 'citypicker': '../libs/city-picker/dist/js/city-picker.min', |
54 | 'citypicker-data': '../libs/city-picker/dist/js/city-picker.data', | 52 | 'citypicker-data': '../libs/city-picker/dist/js/city-picker.data', |
55 | }, | 53 | }, |
@@ -106,7 +104,6 @@ require.config({ | @@ -106,7 +104,6 @@ require.config({ | ||
106 | ], | 104 | ], |
107 | 'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ], | 105 | 'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ], |
108 | 'bootstrap-select-lang': ['bootstrap-select'], | 106 | 'bootstrap-select-lang': ['bootstrap-select'], |
109 | - 'summernote': ['../libs/summernote/dist/summernote.min', 'css!../libs/summernote/dist/summernote.css'], | ||
110 | // 'toastr': ['css!../libs/toastr/toastr.min.css'], | 107 | // 'toastr': ['css!../libs/toastr/toastr.min.css'], |
111 | 'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ], | 108 | 'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ], |
112 | 'plupload': { | 109 | 'plupload': { |
@@ -116,7 +113,7 @@ require.config({ | @@ -116,7 +113,7 @@ require.config({ | ||
116 | // 'layer': ['css!../libs/layer/dist/theme/default/layer.css'], | 113 | // 'layer': ['css!../libs/layer/dist/theme/default/layer.css'], |
117 | // 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'], | 114 | // 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'], |
118 | 'validator-lang': ['validator-core'], | 115 | 'validator-lang': ['validator-core'], |
119 | -// 'selectpage': ['css!../libs/selectpage/selectpage.css'], | 116 | +// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'], |
120 | 'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css'] | 117 | 'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css'] |
121 | }, | 118 | }, |
122 | baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径 | 119 | baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径 |
-
请 注册 或 登录 后发表评论