Compare commits

...

197 Commits

Author SHA1 Message Date
Karson 14dd8c7434 更新版本号 2026-06-02 17:16:58 +08:00
Karson b993aa7efb 优化Referer校验 2026-06-02 17:16:36 +08:00
Karson fc774889b5 优化退出跳转时间
打包JS
2026-06-02 16:30:35 +08:00
Karson 6ab37ef8b7 优化退出逻辑 2026-06-02 15:59:15 +08:00
Karson 308e86c345 优化退出表单元素 2026-06-02 15:36:01 +08:00
Karson dd1560d9bf 优化后台退出逻辑 2026-06-02 15:17:46 +08:00
Karson a88f91046c 完善语言包
优化退出逻辑
2026-06-02 10:56:33 +08:00
Karson c7582f7efe 优化API文档生成
优化公共接口输出
优化用户退出逻辑
优化头像保存
优化模板变量输出
2026-06-02 10:42:14 +08:00
Karson 542771bbf8 更新版本号 2026-05-22 11:39:35 +08:00
Karson 9fe1c1c7a6 修复SelectPage筛选问题 2026-05-22 11:06:40 +08:00
Karson 214ff67a55 修复异常时的提示 2026-05-20 17:59:30 +08:00
Karson 63426c0e72 更新版本号 2026-05-20 17:44:35 +08:00
Karson 127919050e 修复Selectpage自定义筛选安全问题 2026-05-20 17:36:21 +08:00
Karson dd32740c66 修复SelectPage排序安全问题 2026-03-23 22:33:21 +08:00
Karson 3b02c0fbeb 优化API模板资源地址 2026-03-23 22:31:25 +08:00
Karson 6361d9228f 更新版本号 2025-04-30 17:42:39 +08:00
Karson 9339314d19 优化cxselect组件依赖 2025-04-30 17:36:36 +08:00
Karson b13ed1da95 更新版本号 2025-03-31 17:24:14 +08:00
Karson 3637028f89 更新bootstrap仓库链接
修改bootstrap至fastadmin-bootstrap
2025-03-31 17:14:39 +08:00
Karson 4f8d7380a5
!490 简化代码
Merge pull request !490 from simon429/1.x
2025-03-30 04:33:36 +00:00
Karson 3f3800cbdc 更新mailer依赖组件,修复QQ邮箱兼容问题 2025-03-30 11:42:29 +08:00
Karson 87d4163a89 更新仓库链接 2025-03-29 22:47:24 +08:00
Karson 0099085bf2 优化包名 2025-03-29 22:40:27 +08:00
Karson 8c1a2f7274 优化站点路径 2025-03-29 22:39:45 +08:00
Karson 6f4bc063cd 修复系统配置分组标题未转义的问题 2025-03-29 22:38:24 +08:00
Karson 41d75cdbf8 新增限制上传以.开头的文件
优化上传文件配置提示
2025-03-29 22:34:46 +08:00
Karson 7fbb953497
!491 !481 修复本地时间参数无效、修复 __ 函数的参数传递错误
Merge pull request !491 from Karson/develop
2025-03-29 01:40:44 +00:00
Karson 4cb081f5c0 修复normal和flag格式化方法输出未转义的问题 2025-03-29 09:37:29 +08:00
Karson ca4c0ed076 优化Gruntfile配置 2025-03-29 09:22:29 +08:00
Simon 8162279430 简化代码 2025-03-29 01:41:35 +08:00
Karson af25765558 新增package包管理,移除bower包管理 2025-03-28 17:21:30 +08:00
Karson 49e8cc52e7 新增bower-cleanup.js用于移除bower.json中ignores参数配置的文件或文件夹
bower.json新增ignores配置
2025-03-12 15:41:11 +08:00
Karson 31c3d7b469 优化参数 2025-02-17 21:41:39 +08:00
Karson 017c7687c3 更新版本号 2025-02-17 14:55:09 +08:00
Karson 2bd2fd5684 修复菜单规则和会员规则列表转义 2025-02-17 14:47:58 +08:00
Karson 71d15964fd 修复日期渲染 2025-02-17 14:47:12 +08:00
Karson 7a81b078f3
!477 BUG后台自动跳转
Merge pull request !477 from 御宅男(YznCMS官方)/demo
2025-01-03 03:03:50 +00:00
Karson 9bdf43e808
!481 修复本地时间参数无效、修复 __ 函数的参数传递错误
Merge pull request !481 from 一半/develop
2025-01-03 03:02:38 +00:00
一半 8fe9f5954c
修复本地时间参数无效、修复 __ 函数的参数传递错误
Signed-off-by: 一半 <1094963513@qq.com>
2025-01-01 23:49:59 +00:00
Karson 516c18116a Merge branch 'develop' into 1.x
# Conflicts:
#	README.md
#	application/admin/view/index/index.html
#	application/api/controller/User.php
#	application/config.php
#	application/index/view/common/script.html
#	bower.json
#	composer.json
#	public/assets/js/require-backend.min.js
#	public/assets/js/require-frontend.min.js
#	public/assets/js/require-table.js
2024-11-28 18:23:42 +08:00
Karson 00c5561c49 优化日期区间选择组件事件 2024-11-28 18:09:42 +08:00
Karson 0882b94683 优化customField字段
优化占位符替换

# Conflicts:
#	public/assets/js/require-table.js
2024-11-28 18:09:26 +08:00
Karson 420b82f6fb 优化验证码发送和验证
# Conflicts:
#	application/index/view/common/script.html
#	public/assets/js/frontend.js
2024-11-28 18:05:14 +08:00
Karson 8e3582a392 优化登录失效判断 2024-11-28 18:03:33 +08:00
Karson b0a44db6d8 优化安装最低PHP版本限制
# Conflicts:
#	application/admin/command/Install.php
#	application/admin/command/Install/zh-cn.php
2024-11-28 18:03:02 +08:00
Karson 4efc5056a5 优化依赖版本号 2024-11-28 17:46:17 +08:00
Karson 4b9643e967 Merge branch '1.x' of gitee.com:karson/fastadmin into 1.x 2024-11-28 17:44:54 +08:00
Karson 8a50431006 优化通用搜索和表格searchList 2024-11-28 12:11:59 +08:00
Karson 1276d44e48 优化视图渲染 2024-11-28 12:10:22 +08:00
Karson d7c3bc90ea 优化代码 2024-11-28 11:53:18 +08:00
Karson 279d8d876f 优化API文档生成 2024-11-28 11:46:44 +08:00
Karson 17931decd5
!471 动态显示组件在进行判断时, 增加对已被附加禁用(disabled)组件的处理
Merge pull request !471 from AriFe.Liu/develop
2024-11-18 09:50:09 +00:00
Karson 4fd2558a8b
!442 update public/assets/js/require-table.js.
Merge pull request !442 from 御宅男(YznCMS官方)/N/A
2024-11-18 09:46:58 +00:00
Karson be3c601b72
!468 searchList 如果传入的是$.getJSON,则无法正确显示label
Merge pull request !468 from 还俗二师兄/develop
2024-11-18 09:46:12 +00:00
Karson a5a0a30d07
!452 模型已做清除缓存,去除多余代码
Merge pull request !452 from 御宅男(YznCMS官方)/N/A
2024-11-18 09:16:05 +00:00
Karson 426209a5d5
!479 CRUD生成admin表时,默认字段为nickname
Merge pull request !479 from simon429/develop
2024-11-18 09:14:36 +00:00
Karson 385a33344c
!472 重构初始化安装的数据库配置处理,使用 .env 文件
Merge pull request !472 from ox5a0b54/env-file-db-config
2024-11-18 09:01:55 +00:00
Karson 142ed14afa
!476 require.js 原型污染安全修复
Merge pull request !476 from 御宅男(YznCMS官方)/1.x
2024-11-18 08:04:58 +00:00
Karson cfd8a6a295
!475 会员登录次数无效,旧的冗余代码删除
Merge pull request !475 from 御宅男(YznCMS官方)/1.x
2024-11-18 08:03:49 +00:00
Karson 7763aefd61
!478 做了一些修改
Merge pull request !478 from 端木/develop
2024-11-18 08:00:59 +00:00
Simon 16ae2acb2c CRUD生成admin表时,默认字段为nickname 2024-11-10 18:42:35 +08:00
端木 63cdd2ad25 mod: add type comments 2024-11-10 11:09:48 +08:00
御宅男(YznCMS官方) 04af4aa1c0
Revert "update application/common/view/tpl/dispatch_jump.tpl."
Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-29 07:03:25 +00:00
御宅男(YznCMS官方) f4a14c6295
update application/common/view/tpl/dispatch_jump.tpl.
Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-29 05:42:43 +00:00
御宅男(YznCMS官方) d6635c1cd6
update application/common/view/tpl/dispatch_jump.tpl.
Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-29 05:37:27 +00:00
ken678 3e6ffdf276 优化 2024-10-10 10:14:40 +08:00
御宅男(YznCMS官方) 4e28f319b7
update application/admin/command/Min/r.js.
require.js 原型污染安全修复

Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-10 01:44:38 +00:00
御宅男(YznCMS官方) 73686e38c8
update public/assets/js/require.min.js.
require.js 原型污染安全修复

Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-09 09:17:39 +00:00
御宅男(YznCMS官方) 986cc85be3
update public/assets/js/require.js.
require.js 原型污染安全修复

Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-10-09 09:12:24 +00:00
御宅男(YznCMS官方) f01d11d02b
update application/admin/controller/auth/Adminlog.php.
删除残留的旧的冗余代码

Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-09-27 05:33:05 +00:00
Karson 77300998fc 优化SelectPage编码输出 2024-09-26 17:23:49 +08:00
御宅男(YznCMS官方) a5025fd1b1
update application/index/lang/zh-cn/user.php.
登录次数多语言

Signed-off-by: 御宅男(YznCMS官方) <530765310@qq.com>
2024-09-19 02:47:53 +00:00
御宅男(YznCMS官方) f57cf5ce80
update application/common/library/Auth.php.
此处没有用return false;
2024-09-19 02:42:28 +00:00
ox5a0b54 c12e304aec 重构初始化安装的数据库配置处理 2024-08-01 15:50:55 +08:00
ox5a0b54 0fb49c1a9a 重构初始化安装的数据库配置处理 2024-08-01 15:38:42 +08:00
gtlee d12f549396 Merge remote-tracking branch 'upstream/develop' into develop 2024-08-01 15:07:27 +08:00
AriFe.Liu 7c7780bc56
动态显示组件在进行判断时, 增加对已被附加禁用(disabled)组件的处理
原代码在进行校验时, 使用serializeArray方法在序列化表单元素时, 会默认将disabled的组件过滤掉, 此操作将会导致动态显示组件依赖的组件被设置为disabled时判断失效, 会隐藏掉使用了data-favisible的组件
本次修改在调用序列化之前, 先临时移除disabled属性, 取出完整的序列化参数后, 再将其恢复禁用, 从而使附加了disabled的组件也能使data-favisible组件正确获取到其当前值
使用情景: 添加表单时某个选项需要管理员手动选择, 在添加完成后, 编辑不能再次修改该选项, 但其下根据该元素需要显隐的组件应当正常展示

Signed-off-by: AriFe.Liu <88468560@qq.com>
2024-07-26 12:51:44 +00:00
Karson b0d295bd67 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2024-07-25 15:26:14 +08:00
Karson 3ee684875f 新增选择文件后回调
优化选择文件回调参数
2024-07-25 15:25:37 +08:00
Karson b6ae55ef1e 修复插件安装时发现冲突文件时无法提示的问题 2024-07-25 14:53:55 +08:00
Karson 38969376c9 优化冗余参数 2024-07-25 14:53:18 +08:00
Karson 1496698d46 优化API资源URL 2024-07-25 14:52:39 +08:00
Karson 25c0490285 优化安装脚本资源加载 2024-07-25 14:51:18 +08:00
Karson e8d65eb124
!470 修复sidebar左侧菜单因大小写问题导致的菜单列表不能正确显示问题
Merge pull request !470 from AriFe.Liu/develop
2024-07-25 02:50:15 +00:00
AriFe.Liu 271596ee2d
修复sidebar左侧菜单因大小写问题导致的菜单列表不能正确显示问题
当手动添加菜单规则时, 规则字段未提示和处理用户录入的字符
在application/admin/library/Auth.php -> getSidebar方法中, 会对当前用户所拥有的权限节点做校验移除不相关的权限
当判断当前菜单规则是否在$userRule中时, 原本的$v['name']为直接从数据库中取出未做处理, $userRule则是通过$this->getRuleList方法获取, 方法内已经对字符串做了转小写处理, 假如用户填写了大小写混合的规则, 则此处将会被错误的移除掉; 导致左侧菜单无法正常展示该菜单规则;

Signed-off-by: AriFe.Liu <88468560@qq.com>
2024-07-23 03:33:44 +00:00
还俗二师兄 6ab795e12f
update public/assets/js/require-table.js.
searchList 如果传入的是$.getJSON,则无法正确显示label

如果传入的是value直接是数组的话就无需切割成数组

Signed-off-by: 还俗二师兄 <505097558@qq.com>
2024-07-17 16:55:12 +00:00
Karson ac25e4b275 优化邮箱验证码发送参数验证 2024-07-04 15:27:26 +08:00
Karson 64c157f56a 新增删除按钮自定义提示语 2024-06-25 11:44:38 +08:00
Karson b72b5605e5 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2024-06-18 16:06:14 +08:00
Karson db8739670c 修复autocomplete选中后未触发验证的问题
修复Table.api.formatter.file无法渲染的问题
2024-06-18 16:05:57 +08:00
Karson e7c96a994b
!410 修复iframe打开窗口时链接内问号重复的问题以及附件选择组件在未添加ID时无法正常响应
Merge pull request !410 from AriFe.Liu/develop
2024-06-18 07:39:11 +00:00
Karson c4499a3266
!414 修复Crud.php删除时抛出table not found异常问题
Merge pull request !414 from 苏小马/develop
2024-06-18 07:34:54 +00:00
小和 372be26dd2 !465 修改字段错误问题
* 修复字段错误
2024-06-17 01:56:09 +00:00
gtlee ccf6bd9a98 修复头像URL在命令行初始化安装时无法获取域名问题 2024-06-14 22:38:07 +08:00
Karson feed46823f Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2024-05-16 11:04:04 +08:00
Karson cc4c0ab3ed 优化后台参数传递 2024-05-16 10:58:47 +08:00
Karson ddccd51105 优化表格加载 2024-05-16 10:54:32 +08:00
Karson 6d82e89ff6 优化插件打包 2024-05-16 10:52:23 +08:00
Karson 1a8f81cc35
!463 有权重字段时,模型添加数据后会自动用ID替换,导致添加时设置的权重值无法保存
Merge pull request !463 from simon429/develop
2024-04-26 03:46:50 +00:00
Karson de5c92e78a 优化上传参数处理 2024-04-03 09:29:19 +08:00
Karson d4c866cb55 优化格式化输出时文本编码 2024-04-02 17:50:19 +08:00
Karson 47c4115a53 优化日期区间选择组件事件 2024-04-02 17:41:29 +08:00
Karson 5a29c4eeed 优化customField字段
优化占位符替换
2024-04-02 17:16:51 +08:00
Karson 7898b811b2 优化验证码发送和验证 2024-04-02 16:18:31 +08:00
Karson 0de3858c90 优化登录失效判断 2024-04-02 15:07:04 +08:00
Karson 76024147aa 更新版本号 2024-04-02 10:24:25 +08:00
Karson 9cf5b91143 优化安装最低PHP版本限制 2024-04-02 10:23:21 +08:00
Karson 1b9c035daf 优化资源目录 2024-04-01 22:04:05 +08:00
Karson 8caeeb8a78 Merge branch '1.x' into develop
# Conflicts:
#	README.md
#	application/admin/command/Install/fastadmin.sql
#	application/admin/controller/Index.php
#	application/admin/controller/auth/Adminlog.php
#	application/common.php
#	application/common/controller/Backend.php
#	application/common/library/Email.php
#	application/config.php
#	application/index/controller/User.php
#	bower.json
#	composer.json
#	extend/fast/Http.php
#	public/assets/css/backend.min.css
#	public/assets/css/frontend.min.css
#	public/assets/js/backend/addon.js
#	public/assets/js/bootstrap-table-commonsearch.js
#	public/assets/js/fast.js
#	public/assets/js/frontend/user.js
#	public/assets/js/jquery.drag.min.js
#	public/assets/js/require-backend.js
#	public/assets/js/require-backend.min.js
#	public/assets/js/require-form.js
#	public/assets/js/require-frontend.min.js
#	public/assets/js/require-table.js
2024-04-01 15:22:15 +08:00
Karson 684e6704e8
!459 mail_smtp_pass 为密码类型
Merge pull request !459 from 高级CV工程师/N/A
2024-03-27 02:59:08 +00:00
Karson afa636ba15
!451 update public/assets/js/require-form.js.
Merge pull request !451 from SiGool/N/A
2024-03-15 03:48:38 +00:00
Simon e37103f8f3 修复添加时,权重传值不生效 2024-02-29 19:41:32 +08:00
F4nniu 1cc09a5a19 docs: 更新年份 2024-02-16 21:53:44 +08:00
Karson 80fdc19c8e 修复checkbox和radio组件生成
(cherry picked from commit 65068c9a29)
2024-02-16 11:41:40 +08:00
Karson 03a0e0dd4e 优化url检测
(cherry picked from commit dc466cb1c9)
2024-02-15 22:53:42 +08:00
Karson fb5b78e777 优化菜单规则管理
(cherry picked from commit 31a6a47dc3)
2024-02-15 22:52:59 +08:00
Karson 20dea7cb5b 优化CRUD生成
(cherry picked from commit a40420b8cd)
2024-02-15 22:52:29 +08:00
Karson 57c2f23106 增强后台安全限制
优化登录判断机制
移除冗余代码

(cherry picked from commit 7e6314a701)
2024-02-15 22:52:01 +08:00
Karson b44f3791b1 修复语言检测未匹配时的错误
优化分片上传

(cherry picked from commit ae57feebb6)
2024-02-15 22:42:49 +08:00
Karson 4f466551e2 新增自定义错误码模板配置
(cherry picked from commit 4845b08077)
2024-02-15 22:33:55 +08:00
Karson 1066b4108b 优化权限规则列表显示
(cherry picked from commit 2c66c67d71)
2024-02-15 22:28:29 +08:00
Karson 4badf65bd2 优化获取类名兼容性
(cherry picked from commit a9003ecce4)
2024-02-15 22:18:55 +08:00
liuan 5d8da63740 fix(Lang): 修复后台登录时用户名和密码只有英文提示的问题
(cherry picked from commit 879554d5a8)
2024-02-13 16:30:12 +08:00
F4nniu 198604c584 fix(common): getEncryptedToken 的 php8 兼容修复 2024-02-11 21:46:44 +08:00
高级CV工程师 e0f684a0c3
mail_smtp_pass 为密码类型
Signed-off-by: 高级CV工程师 <2535688890@qq.com>
2024-02-07 14:32:58 +00:00
F4nniu (FastAdmin开源框架) c8404c7096
!457 修复api上传文件时,最大上传文件报错,不显示语言包的提示语的bug
Merge pull request !457 from badou/develop
2024-01-19 04:31:25 +00:00
lande d5b07d49cb 修复api上传文件时,最大上传文件报错,不显示语言包的提示语的bug 2024-01-17 22:06:13 +08:00
Karson c846402a79 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2023-11-23 16:32:31 +08:00
Karson d7302f2602 新增autocontent
新增autocontent
优化Fast.api.open
2023-11-23 16:31:16 +08:00
F4nniu 6f35aff2eb
!455 [fix]公共函数字节转换bug修复
Merge pull request !455 from Bran/origin-develop
2023-08-29 09:10:11 +00:00
bran 6b4cdff2e0 [fix]公共函数字节转换bug修复 2023-08-28 08:55:53 +08:00
Karson 9bbd11e4bc 新增URL检测和清理函数
优化登录和注册链接跳转

(cherry picked from commit 3549e95ea1)
2023-08-26 21:30:03 +08:00
F4nniu 8947877915
!447 继续完善 php8 的兼容
Merge pull request !447 from F4nniu/php8_compatibily
2023-08-25 14:52:31 +00:00
御宅男 611d9d1a2e
模型已做清除缓存,去除多余代码
Signed-off-by: 御宅男 <530765310@qq.com>
2023-08-07 02:51:22 +00:00
SiGool db510531f4
update public/assets/js/require-form.js.
指向同一个options了,后面时间区间组件初始化用的配置受到前面的干扰了

Signed-off-by: SiGool <sigool@sina.com>
2023-08-04 03:07:40 +00:00
F4nniu 7fe625cf5b 修复 select 生成在 php8 环境中的报错 2023-07-25 18:27:20 +08:00
F4nniu dd63aa5948 让 IDE 提示友好 2023-07-22 23:52:07 +08:00
F4nniu 85271d1cf7 使用框架 get 自带的过滤参数 2023-07-22 23:40:58 +08:00
F4nniu a64cf1173f 优化 php8 兼容 2023-07-17 15:04:20 +08:00
F4nniu 927510f5ad captcha 为了兼容 php8 2023-07-17 11:09:58 +08:00
F4nniu c7da57a109 修复显示本地插件列表时的 null 值报错 2023-07-16 17:20:14 +08:00
F4nniu 35d6514381 api 生成兼容 php8 2023-07-16 15:27:20 +08:00
Karson 3831955b9b 移除QQ群 2023-06-16 11:00:03 +08:00
Karson 4dabb80044 优化验证码 2023-06-15 22:12:46 +08:00
Karson 96dd46d32d 优化插件管理
兼容旧版本jQuery的size方法
2023-06-15 21:40:15 +08:00
Karson 0e75d1d6cd 优化插件管理 2023-06-15 21:32:42 +08:00
Karson 3c575e2383 优化CRUD代码 2023-06-15 14:43:56 +08:00
Karson b50e6c9cf0 按钮配置属性extend支持function 2023-06-15 14:36:08 +08:00
Karson 25832b2a0e 优化会员编辑模板 2023-06-14 11:18:01 +08:00
Karson 89ab1dd690 新增think-queue配置 2023-06-14 10:44:54 +08:00
Karson 031cd59bcd Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2023-06-14 10:42:11 +08:00
Karson 09bdafd65c 优化附件上传预览 2023-06-14 10:41:58 +08:00
Karson 568fd9073b
!429 【优化】Table.api.replaceurl自动添加ids参数正则
Merge pull request !429 from Bran/develop
2023-06-09 07:14:12 +00:00
Karson c1236b17da
!445 修复插件生成模板config.stub中usernmae拼写错误
Merge pull request !445 from liuan/fixbug
2023-06-09 07:10:23 +00:00
Karson 3c32166b3b 优化fieldlist键名排序
优化上传预览
优化cdnurl
2023-06-09 15:06:54 +08:00
Karson 5e6c32e04c 优化代码 2023-06-09 14:53:12 +08:00
Karson 563596fddc Merge branch 'develop' of gitee.com:karson/fastadmin into develop
# Conflicts:
#	composer.json
2023-06-09 14:50:14 +08:00
Karson 900db646ee 优化依赖配置 2023-06-09 14:48:54 +08:00
Karson 11290c1724 新增会员相关参数配置
新增上传超时配置
2023-06-09 14:48:06 +08:00
Karson 9b0db19326 优化代码 2023-06-09 14:41:04 +08:00
Karson 67aa9df53a 优化CRUD生成的代码 2023-06-07 15:04:38 +08:00
Karson eb66ecb256 优化代码
优化样式
2023-06-07 14:54:33 +08:00
Karson fdaf86ce92 优化代码 2023-06-06 18:22:46 +08:00
liuan 5b9130a459 修复插件生成模板config.stub中usernmae拼写错误 2023-06-05 00:13:36 +08:00
F4nniu 1afdacbcd9
update .gitee/ISSUE_TEMPLATE.zh-CN.md. 2023-05-10 08:32:10 +00:00
F4nniu f49c0ae11b
更新 Issue 模板 2023-05-03 02:12:45 +00:00
F4nniu 1dfd1cc66b
更新 ISSUE 模板 2023-05-03 02:11:30 +00:00
F4nniu db487a52df
nelexa zip 组件以 fastadmin-addons 组件中的依赖为准 2023-05-02 12:21:05 +00:00
F4nniu d596d4b4a7
完善模板信息 2023-05-01 01:33:12 +00:00
F4nniu c4e726ff3a
添加 ISSUES 模板。 2023-04-30 14:19:56 +00:00
F4nniu 731f27e0d5
添加 ISSUES 模板。
Signed-off-by: F4nniu <sparkamax@gmail.com>
2023-04-30 14:18:05 +00:00
御宅男 fe9029beac
update public/assets/js/require-table.js.
修复例如角色组,菜单规则菜单已经关闭通用搜索,但是还是状态还是显示搜索tips的bug

Signed-off-by: 御宅男 <530765310@qq.com>
2023-04-27 05:42:42 +00:00
Karson ab7ebc3787 修复超级管理管理员无法显示部分日志的问题 2023-04-24 09:47:07 +08:00
Karson cb0fbe022c
!441 修复后台控制器关联查询参数设置无效
Merge pull request !441 from 王子涵/N/A
2023-04-20 02:00:31 +00:00
小和 c69ba1aea3 !435 修改密码类型默认手机号
* 修改密码类型默认手机号
2023-04-20 01:59:42 +00:00
Karson 2c09a10786
!439 CRUD生成字段默认值bug
Merge pull request !439 from Jon/develop
2023-04-20 01:58:54 +00:00
Karson 7cb8fec4ab
!437 解决fast/Date::unixtime() 报错非法日期BUG
Merge pull request !437 from bluehow/develop
2023-04-20 01:58:34 +00:00
Karson e4cb165c35 新增搜索数量提示
修复重置SelectPage不生效的问题
修改搜索文字
2023-04-17 12:06:25 +08:00
王子涵 52c83348bc
update application/common/controller/Backend.php.
修复后台控制器关联查询参数设置无效

Signed-off-by: 王子涵 <3125976329@qq.com>
2023-04-12 03:47:46 +00:00
Karson c9ef6b9780 优化iOS下后台样式 2023-04-07 15:44:52 +08:00
Karson 4865816388 优化Bootstrap-Select组件和Selectpicker组件 2023-04-07 10:54:37 +08:00
Jon cecf1ad1cd
crud自动生成字段默认值判断
Signed-off-by: Jon <363516862@qq.com>
2023-03-28 09:01:05 +00:00
Karson b281396aee 修复参数过滤错误
修复附件列表引入文件错误
2023-03-28 16:14:38 +08:00
Karson 22c2f66e3a 修复新版本Bootstrap-select兼容问题 2023-03-24 11:31:45 +08:00
Karson b685a32d63 移除默认的api文档
优化api文档生成文本框
2023-03-23 15:42:03 +08:00
lijian a6c3c77949 解决fast/Date::unixtime()bug
该bug会导致position为结束时且type为quarter时
如果以当前月份偏移offset单位的季度时出现跨越年份,会导致cal_days_in_month报错 非法日期。
2023-03-21 20:27:43 +08:00
Karson 0433dc4b30 移除注册页默认测试数据 2023-03-15 17:26:12 +08:00
Karson 6765368781 修改版本号 2023-03-15 16:39:10 +08:00
Karson a5fd9067c1 新增手机验证码登录 2023-03-15 16:37:34 +08:00
Karson 9c422d6285 新增简洁模式菜单 2023-03-15 16:34:38 +08:00
Karson ec84778d3d 优化路径加载
优化JS和CSS加载目录
2023-03-15 16:18:28 +08:00
Karson 6f1805ceb0 新增npm包管理
新增grunt进行JS和CSS打包
移除bower包管理
优化压缩打包
2023-03-15 16:15:06 +08:00
bran 9f1c1db03c 关联模型下时间无法搜索的BUG,仅在关联搜索条件下调用 2023-02-10 15:44:48 +08:00
jianglei 242d670b5a 优化Table.api.replaceurl自动添加ids参数正则 2023-01-19 11:41:28 +08:00
苏小马 fb5972dd2c
update application/admin/command/Crud.php.
问题:删除模式时不需要强制读取数据表,如果在删除前已手动删除数据表,将抛出异常“table not found”导致删除失败

修复:增加删除模式判断,如果是删除模式,无需读取数据表

Signed-off-by: 苏小马 <179906767@qq.com>
2022-09-09 03:23:40 +00:00
AriFe.Liu 34e4c6c1e5
修复iframe打开窗口时链接内问号重复的问题
如果在添加菜单时, 在规则或URL中追加了 ? , 则会导致在刷新这个标签页时, 请求链接中使用了两个问号导致参数取出错误, 此处原本追加的?addtabs=1未做判断.

Signed-off-by: AriFe.Liu <88468560@qq.com>
2022-08-13 03:46:36 +00:00
AriFe.Liu bf6c4590ee
修复附件选择组件因没有id导致无法响应事件的bug
该问题曾导致附件选择组件在没有添加ID时造成无法正常响应回调事件
官方文档: https://doc.fastadmin.net/doc/183.html 附件选择 中, 示例及文档均未提及添加了faselect的组件必须添加id
如非bug而有意为之, 请修改官方文档说明, 告知用户添加了faselect的标签必须同时添加ID才能正确处理回调.
2022-06-27 03:27:27 +00:00
86 changed files with 14859 additions and 8061 deletions

View File

@ -7,5 +7,8 @@
"jspdf", "jspdf",
"jspdf-autotable", "jspdf-autotable",
"pdfmake" "pdfmake"
] ],
"scripts":{
"postinstall": "node bower-cleanup.js"
}
} }

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
/public/assets/libs/ /public/assets/libs/
/public/assets/addons/* /public/assets/addons/*
/public/uploads/* /public/uploads/*
.DS_Store
.idea .idea
composer.lock composer.lock
*.log *.log

4
.npmrc 100644
View File

@ -0,0 +1,4 @@
# 使用自定义镜像源
registry=http://mirrors.tencent.com/npm/
#关闭SSL验证
strict-ssl=false

139
Gruntfile.js 100644
View File

@ -0,0 +1,139 @@
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
main: {
files: []
}
}
});
var build = function (module, type, callback) {
var config = {
compile: {
options: type === 'js' ? {
optimizeCss: "standard",
optimize: "uglify", //可使用uglify|closure|none
preserveLicenseComments: true,
removeCombined: false,
baseUrl: "./public/assets/js/", //JS文件所在的基础目录
name: "require-" + module, //来源文件,不包含后缀
out: "./public/assets/js/require-" + module + ".min.js" //目标文件
} : {
optimizeCss: "default",
optimize: "uglify", //可使用uglify|closure|none
cssIn: "./public/assets/css/" + module + ".css", //CSS文件所在的基础目录
out: "./public/assets/css/" + module + ".min.css" //目标文件
}
}
};
var content = grunt.file.read("./public/assets/js/require-" + module + ".js"),
pattern = /^require\.config\(\{[\r\n]?[\n]?(.*?)[\r\n]?[\n]?}\);/is;
var matches = content.match(pattern);
if (matches) {
if (type === 'js') {
var data = matches[1].replaceAll(/(urlArgs|baseUrl):(.*)\n/gi, '');
const parse = require('parse-config-file'), fs = require('fs');
require('jsonminify');
data = JSON.minify("{\n" + data + "\n}");
let options = parse(data);
options.paths.tableexport = "empty:";
Object.assign(config.compile.options, options);
}
let requirejs = require("./application/admin/command/Min/r");
try {
requirejs.optimize(config.compile.options, function (buildResponse) {
// var contents = require('fs').readFileSync(config.compile.options.out, 'utf8');
callback();
}, function (err) {
console.error(err);
callback();
});
} catch (err) {
console.error(err);
callback();
}
}
};
// 加载 "copy" 插件
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('frontend:js', 'build frontend js', function () {
var done = this.async();
build('frontend', 'js', done);
});
grunt.registerTask('backend:js', 'build backend js', function () {
var done = this.async();
build('backend', 'js', done);
});
grunt.registerTask('frontend:css', 'build frontend css', function () {
var done = this.async();
build('frontend', 'css', done);
});
grunt.registerTask('backend:css', 'build frontend css', function () {
var done = this.async();
build('backend', 'css', done);
});
// 注册部署JS和CSS任务
grunt.registerTask('deploy', 'deploy', function () {
const fs = require('fs');
const path = require("path")
const nodeModulesDir = path.resolve(__dirname, "./node_modules");
const getAllFiles = function (dirPath, arrayOfFiles) {
files = fs.readdirSync(dirPath)
arrayOfFiles = arrayOfFiles || []
files.forEach(function (file) {
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles)
} else {
arrayOfFiles.push(path.join(__dirname, dirPath, "/", file))
}
});
return arrayOfFiles
};
const mainPackage = grunt.config.get('pkg');
let dists = mainPackage.dists || [];
let files = [];
// 兼容旧版本bower使用的目录
let specialKey = {
'fastadmin-bootstraptable': 'bootstrap-table',
'sortablejs': 'Sortable',
'tableexport.jquery.plugin': 'tableExport.jquery.plugin',
};
Object.keys(dists).forEach(key => {
let src = ["**/*LICENSE*", "**/*license*"];
src = src.concat(Array.isArray(dists[key]) ? dists[key] : [dists[key]]);
files.push({expand: true, cwd: nodeModulesDir + "/" + key, src: src, dest: 'public/assets/libs/' + (specialKey[key] || key) + "/"});
});
// 兼容bower历史路径文件
files = [...files,
{src: nodeModulesDir + "/toastr/build/toastr.min.css", dest: "public/assets/libs/toastr/toastr.min.css"},
{src: nodeModulesDir + "/bootstrap-slider/dist/css/bootstrap-slider.css", dest: "public/assets/libs/bootstrap-slider/slider.css"},
{expand: true, cwd: nodeModulesDir + "/bootstrap-slider/dist", src: ["*.js"], dest: "public/assets/libs/bootstrap-slider/"}
]
grunt.config.set('copy.main.files', files);
grunt.task.run("copy:main");
});
// 注册默认任务
grunt.registerTask('default', ['deploy', 'frontend:js', 'backend:js', 'frontend:css', 'backend:css']);
};

View File

@ -55,9 +55,9 @@ https://demo.fastadmin.net
问答社区: https://ask.fastadmin.net 问答社区: https://ask.fastadmin.net
Github: https://github.com/karsonzhang/fastadmin Github: https://github.com/fastadminnet/fastadmin
Gitee: https://gitee.com/karson/fastadmin Gitee: https://gitee.com/fastadminnet/fastadmin
## 特别鸣谢 ## 特别鸣谢

View File

@ -201,16 +201,20 @@ class Addon extends Command
new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
); );
$addonDir = str_replace(DS, '/', $addonDir);
$excludeDirRegex = "/\/(\.git|\.svn|\.vscode|\.idea|unpackage)\//i";
foreach ($files as $name => $file) { foreach ($files as $name => $file) {
if (!$file->isDir()) { $filePath = str_replace(DS, '/', $file->getPathname());
$filePath = $file->getRealPath(); if ($file->isDir() || preg_match($excludeDirRegex, $filePath))
$relativePath = str_replace(DS, '/', substr($filePath, strlen($addonDir))); continue;
if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) { $relativePath = substr($filePath, strlen($addonDir));
$zip->addFile($filePath, $relativePath); if (!in_array($file->getFilename(), ['.DS_Store', 'Thumbs.db'])) {
} $zip->addFile($filePath, $relativePath);
} }
} }
$zip->close(); $zip->close();
$output->info("Package Resource Path:" . $addonFile);
$output->info("Package Successed!"); $output->info("Package Successed!");
break; break;
case 'move': case 'move':

View File

@ -18,8 +18,9 @@ class Api extends Command
$this $this
->setName('api') ->setName('api')
->addOption('url', 'u', Option::VALUE_OPTIONAL, 'default api url', '') ->addOption('url', 'u', Option::VALUE_OPTIONAL, 'default api url', '')
->addOption('module', 'm', Option::VALUE_OPTIONAL, 'module name(admin/index/api)', 'api') ->addOption('cdnurl', 'd', Option::VALUE_OPTIONAL, 'default cdn url', '')
->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html') ->addOption('module', 'm', Option::VALUE_OPTIONAL, 'module name(index/api)', 'api')
->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', '')
->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html') ->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html')
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override general file', false) ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override general file', false)
->addOption('title', 't', Option::VALUE_OPTIONAL, 'document title', $site['name'] ?? '') ->addOption('title', 't', Option::VALUE_OPTIONAL, 'document title', $site['name'] ?? '')
@ -36,27 +37,36 @@ class Api extends Command
$force = $input->getOption('force'); $force = $input->getOption('force');
$url = $input->getOption('url'); $url = $input->getOption('url');
$cdnurl = $input->getOption('cdnurl');
$language = $input->getOption('language'); $language = $input->getOption('language');
$template = $input->getOption('template'); $template = $input->getOption('template');
if (!preg_match("/^([a-z0-9]+)\.html\$/i", $template)) { if (!preg_match("/^([a-z0-9]+)\.html\$/i", $template)) {
throw new Exception('template file not correct'); throw new Exception('template file not correct');
} }
$language = $language ? $language : 'zh-cn'; $language = $language ?: 'zh-cn';
$langFile = $apiDir . 'lang' . DS . $language . '.php'; $langFile = $apiDir . 'lang' . DS . $language . '.php';
if (!is_file($langFile)) { if (!is_file($langFile)) {
throw new Exception('language file not found'); throw new Exception('language file not found');
} }
$lang = include_once $langFile; $lang = include_once $langFile;
// 目标目录 // 目标目录
$output_dir = ROOT_PATH . 'public' . DS; $outputDir = ROOT_PATH . 'runtime' . DS . 'docs' . DS;
$output_file = $output_dir . $input->getOption('output'); if (!is_dir($outputDir)) {
if (is_file($output_file) && !$force) { mkdir($outputDir, 0755, true);
}
$outputFilename = $input->getOption('output') ?: 'doc_' . date('Ymd_') . strtolower(\fast\Random::alnum(6)) . '.html';
if ($outputFilename === 'api.html') {
throw new Exception('api.html cannot be used as the output file name');
}
$outputFile = $outputDir . $outputFilename;
if (is_file($outputFile) && !$force) {
throw new Exception("api index file already exists!\nIf you need to rebuild again, use the parameter --force=true "); throw new Exception("api index file already exists!\nIf you need to rebuild again, use the parameter --force=true ");
} }
// 模板文件 // 模板文件
$template_dir = $apiDir . 'template' . DS; $templateDir = $apiDir . 'template' . DS;
$template_file = $template_dir . $template; $templateFile = $templateDir . $template;
if (!is_file($template_file)) { if (!is_file($templateFile)) {
throw new Exception('template file not found'); throw new Exception('template file not found');
} }
// 额外的类 // 额外的类
@ -68,7 +78,6 @@ class Api extends Command
// 插件 // 插件
$addon = $input->getOption('addon'); $addon = $input->getOption('addon');
$moduleDir = $addonDir = '';
if ($addon) { if ($addon) {
$addonInfo = get_addon_info($addon); $addonInfo = get_addon_info($addon);
if (!$addonInfo) { if (!$addonInfo) {
@ -81,9 +90,12 @@ class Api extends Command
if (!is_dir($moduleDir)) { if (!is_dir($moduleDir)) {
throw new Exception('module not found'); throw new Exception('module not found');
} }
if (in_array($module, ['admin', 'common'])) {
throw new Exception('module not allowed');
}
if (version_compare(PHP_VERSION, '7.0.0', '<')) { if (version_compare(PHP_VERSION, '7.4.0', '<')) {
throw new Exception("Requires PHP version 7.0 or newer"); throw new Exception("Requires PHP version 7.4 or newer");
} }
//控制器名 //控制器名
@ -98,34 +110,45 @@ class Api extends Command
foreach ($files as $name => $file) { foreach ($files as $name => $file) {
if (!$file->isDir() && $file->getExtension() == 'php') { if (!$file->isDir() && $file->getExtension() == 'php') {
$filePath = $file->getRealPath(); $filePath = $file->getRealPath();
$classes[] = $this->getClassFromFile($filePath); $className = $this->getClassFromFile($filePath);
if ($className) {
$classes[] = $className;
}
} }
} }
} else { } else {
foreach ($controller as $index => $item) { foreach ($controller as $index => $item) {
$filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php'; $filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php';
$classes[] = $this->getClassFromFile($filePath); $className = $this->getClassFromFile($filePath);
if ($className) {
$classes[] = $className;
}
} }
} }
$classes = array_unique(array_filter($classes)); $classes = array_unique(array_filter($classes));
$cdnurl = $cdnurl ?: Config::get('site.cdnurl');
$config = [ $config = [
'sitename' => config('site.name'), 'sitename' => config('site.name'),
'title' => $title, 'title' => $title,
'author' => config('site.name'), 'author' => config('site.name'),
'description' => '', 'description' => '',
'apiurl' => $url, 'apiurl' => $url,
'cdnurl' => $cdnurl,
'language' => $language, 'language' => $language,
]; ];
Config::set('view_replace_str.__CDN__', $cdnurl);
$builder = new Builder($classes); $builder = new Builder($classes);
$content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]); $content = $builder->render($templateFile, ['config' => $config, 'lang' => $lang]);
if (!file_put_contents($output_file, $content)) { if (!file_put_contents($outputFile, $content)) {
throw new Exception('Cannot save the content to ' . $output_file); throw new Exception('Cannot save the content to ' . $outputFile);
} }
$output->info("Build Successed!"); $output->info("Build Successed!");
$output->info("Docs Location:" . $outputFile);
} }
/** /**
@ -183,7 +206,7 @@ class Api extends Command
} }
} }
} }
$className = $namespace . '\\' . $class;
return $namespace . '\\' . $class; return preg_match('/([a-z0-9_\\]+)([a-z0-9_]+)$/i', $className) ? $className : '';
} }
} }

View File

@ -90,14 +90,15 @@ class Builder
$typeArr = [ $typeArr = [
'integer' => 'number', 'integer' => 'number',
'file' => 'file', 'file' => 'file',
]; ];
$paramslist = array(); $paramslist = array();
foreach ($docs['ApiParams'] as $params) { foreach ($docs['ApiParams'] as $params) {
$inputtype = $params['type'] && isset($typeArr[$params['type']]) ? $typeArr[$params['type']] : ($params['name'] == 'password' ? 'password' : 'text'); $type = strtolower($params['type'] ?? 'string');
$inputtype = $typeArr[$type] ?? ($params['name'] == 'password' ? 'password' : 'text');
$tr = array( $tr = array(
'name' => $params['name'], 'name' => $params['name'],
'type' => $params['type'] ?? 'string', 'type' => $type,
'inputtype' => $inputtype, 'inputtype' => $inputtype,
'sample' => $params['sample'] ?? '', 'sample' => $params['sample'] ?? '',
'required' => $params['required'] ?? true, 'required' => $params['required'] ?? true,
@ -162,7 +163,7 @@ class Builder
'OPTIONS' => 'label-info' 'OPTIONS' => 'label-info'
); );
return isset($labes[$method]) ? $labes[$method] : $labes['GET']; return $labes[$method] ?? $labes['GET'];
} }
public function parse() public function parse()
@ -230,7 +231,7 @@ class Builder
foreach ($docsList as $index => &$methods) { foreach ($docsList as $index => &$methods) {
$methodSectorArr = []; $methodSectorArr = [];
foreach ($methods as $name => $method) { foreach ($methods as $name => $method) {
$methodSectorArr[$name] = isset($method['weigh']) ? $method['weigh'] : 0; $methodSectorArr[$name] = $method['weigh'] ?? 0;
} }
arsort($methodSectorArr); arsort($methodSectorArr);
$methods = array_merge(array_flip(array_keys($methodSectorArr)), $methods); $methods = array_merge(array_flip(array_keys($methodSectorArr)), $methods);
@ -253,7 +254,6 @@ class Builder
public function render($template, $vars = []) public function render($template, $vars = [])
{ {
$docsList = $this->parse(); $docsList = $this->parse();
return $this->view->display(file_get_contents($template), array_merge($vars, ['docsList' => $docsList])); return $this->view->display(file_get_contents($template), array_merge($vars, ['docsList' => $docsList]));
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -920,6 +920,7 @@ class Crud extends Command
$replace = '\'{"custom[type]":"' . $table . '"}\''; $replace = '\'{"custom[type]":"' . $table . '"}\'';
} elseif ($selectpageController == 'admin') { } elseif ($selectpageController == 'admin') {
$attrArr['data-source'] = 'auth/admin/selectpage'; $attrArr['data-source'] = 'auth/admin/selectpage';
$attrArr['data-field'] = 'nickname';
} elseif ($selectpageController == 'user') { } elseif ($selectpageController == 'user') {
$attrArr['data-source'] = 'user/user/index'; $attrArr['data-source'] = 'user/user/index';
$attrArr['data-field'] = 'nickname'; $attrArr['data-field'] = 'nickname';

View File

@ -1,7 +1,7 @@
public function {%methodName%}($value, $data) public function {%methodName%}($value, $data)
{ {
$value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $value = $value ?: ($data['{%field%}'] ?? '');
$valueArr = explode(',', $value); $valueArr = explode(',', $value);
$list = $this->{%listMethodName%}(); $list = $this->{%listMethodName%}();
return implode(',', array_intersect_key($list, array_flip($valueArr))); return implode(',', array_intersect_key($list, array_flip($valueArr)));

View File

@ -1,6 +1,6 @@
public function {%methodName%}($value, $data) public function {%methodName%}($value, $data)
{ {
$value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $value = $value ?: ($data['{%field%}'] ?? '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
} }

View File

@ -1,7 +1,7 @@
public function {%methodName%}($value, $data) public function {%methodName%}($value, $data)
{ {
$value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $value = $value ?: ($data['{%field%}'] ?? '');
$list = $this->{%listMethodName%}(); $list = $this->{%listMethodName%}();
return isset($list[$value]) ? $list[$value] : ''; return $list[$value] ?? '';
} }

View File

@ -1,7 +1,7 @@
public function {%methodName%}($value, $data) public function {%methodName%}($value, $data)
{ {
$value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : ''); $value = $value ?: ($data['{%field%}'] ?? '');
$list = $this->{%listMethodName%}(); $list = $this->{%listMethodName%}();
return isset($list[$value]) ? $list[$value] : ''; return $list[$value] ?? '';
} }

View File

@ -17,6 +17,13 @@ use think\View;
class Install extends Command class Install extends Command
{ {
/**
* 最低PHP版本
* @var string
*/
protected $minPhpVersion = '7.4.0';
protected $model = null; protected $model = null;
/** /**
* @var \think\View 视图类实例 * @var \think\View 视图类实例
@ -70,7 +77,7 @@ class Install extends Command
$adminName = $this->installation($hostname, $hostport, $database, $username, $password, $prefix, $adminUsername, $adminPassword, $adminEmail, $siteName); $adminName = $this->installation($hostname, $hostport, $database, $username, $password, $prefix, $adminUsername, $adminPassword, $adminEmail, $siteName);
if ($adminName) { if ($adminName) {
$output->highlight("Admin url:http://www.example.com/{$adminName}"); $output->highlight("Admin url:https://www.example.com/{$adminName}");
} }
$output->highlight("Admin username:{$adminUsername}"); $output->highlight("Admin username:{$adminUsername}");
@ -207,22 +214,27 @@ class Install extends Command
$adminFile = ROOT_PATH . 'public' . DS . 'admin.php'; $adminFile = ROOT_PATH . 'public' . DS . 'admin.php';
// 数据库配置文件 // 数据库配置文件
$dbConfigFile = APP_PATH . 'database.php'; $envSampleFile = ROOT_PATH . '.env.sample';
$dbConfigText = @file_get_contents($dbConfigFile); $envFile = ROOT_PATH . '.env';
if (!file_exists($envFile)) {
if (!copy($envSampleFile, $envFile)) {
throw new Exception(__('Failed to copy %s to %s', '.env.sample', '.env'));
}
}
$envText = @file_get_contents($envFile);
$callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) { $callback = function ($matches) use ($mysqlHostname, $mysqlHostport, $mysqlUsername, $mysqlPassword, $mysqlDatabase, $mysqlPrefix) {
$field = "mysql" . ucfirst($matches[1]); $field = "mysql" . ucfirst($matches[1]);
$replace = $$field; $replace = $$field;
if ($matches[1] == 'hostport' && $mysqlHostport == 3306) { return "{$matches[1]} = {$replace}";
$replace = '';
}
return "'{$matches[1]}'{$matches[2]}=>{$matches[3]}Env::get('database.{$matches[1]}', '{$replace}'),";
}; };
$dbConfigText = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)Env::get\((.*)\)\,/", $callback, $dbConfigText); $envText = preg_replace_callback("/(hostname|database|username|password|hostport|prefix)\s*=\s*(.*)/", $callback, $envText);
// 检测能否成功写入数据库配置 // 检测能否成功写入数据库配置
$result = @file_put_contents($dbConfigFile, $dbConfigText); $result = @file_put_contents($envFile, $envText);
if (!$result) { if (!$result) {
throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/database.php')); throw new Exception(__('The current permissions are insufficient to write the file %s', '.env'));
} }
// 设置新的Token随机密钥key // 设置新的Token随机密钥key
@ -237,7 +249,7 @@ class Install extends Command
throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/config.php')); throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/config.php'));
} }
$avatar = request()->domain() . '/assets/img/avatar.png'; $avatar = '/assets/img/avatar.png';
// 变更默认管理员密码 // 变更默认管理员密码
$adminPassword = $adminPassword ? $adminPassword : Random::alnum(8); $adminPassword = $adminPassword ? $adminPassword : Random::alnum(8);
$adminEmail = $adminEmail ? $adminEmail : "admin@admin.com"; $adminEmail = $adminEmail ? $adminEmail : "admin@admin.com";
@ -309,8 +321,8 @@ class Install extends Command
//数据库配置文件 //数据库配置文件
$dbConfigFile = APP_PATH . 'database.php'; $dbConfigFile = APP_PATH . 'database.php';
if (version_compare(PHP_VERSION, '7.4.0', '<')) { if (version_compare(PHP_VERSION, $this->minPhpVersion, '<')) {
throw new Exception(__("The current version %s is too low, please use PHP 7.4 or higher", PHP_VERSION)); throw new Exception(__("The current PHP %s is too low, please use PHP %s or higher", PHP_VERSION, $this->minPhpVersion));
} }
if (!extension_loaded("PDO")) { if (!extension_loaded("PDO")) {
throw new Exception(__("PDO is not currently installed and cannot be installed")); throw new Exception(__("PDO is not currently installed and cannot be installed"));

View File

@ -27,7 +27,7 @@ return [
'Password is too weak' => '密码太简单,请重新输入', 'Password is too weak' => '密码太简单,请重新输入',
'The two passwords you entered did not match' => '两次输入的密码不一致', 'The two passwords you entered did not match' => '两次输入的密码不一致',
'Please input correct website' => '网站名称输入不正确', 'Please input correct website' => '网站名称输入不正确',
'The current version %s is too low, please use PHP 7.4 or higher' => '当前版本%s过低请使用PHP7.4及以上版本', 'The current PHP %s is too low, please use PHP %s or higher' => '当前版本PHP %s过低请使用PHP %s及以上版本',
'PDO is not currently installed and cannot be installed' => '当前未开启PDO无法进行安装', 'PDO is not currently installed and cannot be installed' => '当前未开启PDO无法进行安装',
'The current permissions are insufficient to write the file %s' => '当前权限不足,无法写入文件%s', 'The current permissions are insufficient to write the file %s' => '当前权限不足,无法写入文件%s',
'Please go to the official website to download the full package or resource package and try to install' => '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装', 'Please go to the official website to download the full package or resource package and try to install' => '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装',

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,6 @@ use think\Validate;
*/ */
class Ajax extends Backend class Ajax extends Backend
{ {
protected $noNeedLogin = ['lang']; protected $noNeedLogin = ['lang'];
protected $noNeedRight = ['*']; protected $noNeedRight = ['*'];
protected $layout = ''; protected $layout = '';
@ -175,18 +174,18 @@ class Ajax extends Backend
$weighdata[$v[$prikey]] = $v[$field]; $weighdata[$v[$prikey]] = $v[$field];
} }
$position = array_search($changeid, $ids); $position = array_search($changeid, $ids);
$desc_id = isset($sour[$position]) ? $sour[$position] : end($sour); //移动到目标的ID值,取出所处改变前位置的值 $desc_id = $sour[$position] ?? end($sour); //移动到目标的ID值,取出所处改变前位置的值
$sour_id = $changeid; $sour_id = $changeid;
$weighids = array(); $weighids = [];
$temp = array_values(array_diff_assoc($ids, $sour)); $temp = array_values(array_diff_assoc($ids, $sour));
foreach ($temp as $m => $n) { foreach ($temp as $m => $n) {
if ($n == $sour_id) { if ($n == $sour_id) {
$offset = $desc_id; $offset = $desc_id;
} else { } else {
if ($sour_id == $temp[0]) { if ($sour_id == $temp[0]) {
$offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id; $offset = $temp[$m + 1] ?? $sour_id;
} else { } else {
$offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id; $offset = $temp[$m - 1] ?? $sour_id;
} }
} }
if (!isset($weighdata[$offset])) { if (!isset($weighdata[$offset])) {
@ -207,7 +206,6 @@ class Ajax extends Backend
$type = $this->request->request("type"); $type = $this->request->request("type");
switch ($type) { switch ($type) {
case 'all': case 'all':
// no break
case 'content': case 'content':
//内容缓存 //内容缓存
rmdirs(CACHE_PATH, false); rmdirs(CACHE_PATH, false);
@ -215,18 +213,21 @@ class Ajax extends Backend
if ($type == 'content') { if ($type == 'content') {
break; break;
} }
// no break
case 'template': case 'template':
// 模板缓存 // 模板缓存
rmdirs(TEMP_PATH, false); rmdirs(TEMP_PATH, false);
if ($type == 'template') { if ($type == 'template') {
break; break;
} }
// no break
case 'addons': case 'addons':
// 插件缓存 // 插件缓存
Service::refresh(); Service::refresh();
if ($type == 'addons') { if ($type == 'addons') {
break; break;
} }
// no break
case 'browser': case 'browser':
// 浏览器缓存 // 浏览器缓存
// 只有生产环境下才修改 // 只有生产环境下才修改
@ -323,5 +324,4 @@ class Ajax extends Backend
$response = Response::create($data, '', 200, $header); $response = Response::create($data, '', 200, $header);
return $response; return $response;
} }
} }

View File

@ -127,15 +127,20 @@ class Index extends Backend
*/ */
public function logout() public function logout()
{ {
if ($this->request->isPost()) { if ($this->request->isPost()) {
// 加强校验referer是否来自服务器允许referer为空
$referer = $this->request->server('HTTP_REFERER');
if ($referer && strtolower(parse_url($referer, PHP_URL_HOST)) != strtolower($this->request->host())) {
$this->error(__('Invalid request'));
}
$this->token();
$this->auth->logout(); $this->auth->logout();
Hook::listen("admin_logout_after", $this->request); Hook::listen("admin_logout_after", $this->request);
$this->success(__('Logout successful'), 'index/login'); $this->success(__('Logout successful'), 'index/login');
} }
$html = "<form id='logout_submit' name='logout_submit' action='' method='post'>" . token() . "<input type='submit' value='ok' style='display:none;'></form>"; return $this->view->fetch();
$html .= "<script>document.forms['logout_submit'].submit();</script>";
return $html;
} }
} }

View File

@ -18,21 +18,13 @@ class Adminlog extends Backend
* @var \app\admin\model\AdminLog * @var \app\admin\model\AdminLog
*/ */
protected $model = null; protected $model = null;
protected $childrenGroupIds = [];
protected $childrenAdminIds = []; protected $childrenAdminIds = [];
public function _initialize() public function _initialize()
{ {
parent::_initialize(); parent::_initialize();
$this->model = model('AdminLog'); $this->model = model('AdminLog');
$this->childrenAdminIds = $this->auth->getChildrenAdminIds(true); $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
$this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
$groupName = AuthGroup::where('id', 'in', $this->childrenGroupIds)
->column('id,name');
$this->view->assign('groupdata', $groupName);
} }
/** /**

View File

@ -82,7 +82,6 @@ class Rule extends Backend
if ($result === false) { if ($result === false) {
$this->error($this->model->getError()); $this->error($this->model->getError());
} }
Cache::rm('__menu__');
$this->success(); $this->success();
} }
$this->error(); $this->error();
@ -124,7 +123,6 @@ class Rule extends Backend
if ($result === false) { if ($result === false) {
$this->error($row->getError()); $this->error($row->getError());
} }
Cache::rm('__menu__');
$this->success(); $this->success();
} }
$this->error(); $this->error();

View File

@ -7,6 +7,7 @@ return [
'Mobile' => '手机', 'Mobile' => '手机',
'Email' => '邮箱', 'Email' => '邮箱',
'Password' => '密码', 'Password' => '密码',
'Mobile' => '手机号',
'Sign up' => '注 册', 'Sign up' => '注 册',
'Sign in' => '登 录', 'Sign in' => '登 录',
'Sign out' => '退 出', 'Sign out' => '退 出',

View File

@ -30,12 +30,15 @@ return [
'You\'ve logged in, do not login again' => '你已经登录,无需重复登录', 'You\'ve logged in, do not login again' => '你已经登录,无需重复登录',
'Username or password can not be empty' => '用户名密码不能为空', 'Username or password can not be empty' => '用户名密码不能为空',
'Username or password is incorrect' => '用户名或密码不正确', 'Username or password is incorrect' => '用户名或密码不正确',
'Username must be 3 to 30 characters' => '用户名只能由3-30位数字、字母、下划线组合',
'Username is incorrect' => '用户名不正确', 'Username is incorrect' => '用户名不正确',
'Password is incorrect' => '密码不正确', 'Password is incorrect' => '密码不正确',
'Admin is forbidden' => '管理员已经被禁止登录', 'Admin is forbidden' => '管理员已经被禁止登录',
'Please try again after 1 day' => '请于1天后再尝试登录', 'Please try again after 1 day' => '请于1天后再尝试登录',
'Login successful' => '登录成功!', 'Login successful' => '登录成功!',
'Logout successful' => '退出成功!', 'Logout successful' => '退出成功!',
'Are you sure you want to sign out?' => '确定要退出后台管理吗?',
'Confirm sign out' => '确定退出',
'Verification code is incorrect' => '验证码不正确', 'Verification code is incorrect' => '验证码不正确',
'Wipe cache completed' => '清除缓存成功', 'Wipe cache completed' => '清除缓存成功',
'Wipe cache failed' => '清除缓存失败', 'Wipe cache failed' => '清除缓存失败',

View File

@ -327,10 +327,7 @@ class Auth extends \fast\Auth
{ {
//取出当前管理员所有的分组 //取出当前管理员所有的分组
$groups = $this->getGroups(); $groups = $this->getGroups();
$groupIds = []; $groupIds = array_column($groups, 'id');
foreach ($groups as $k => $v) {
$groupIds[] = $v['id'];
}
$originGroupIds = $groupIds; $originGroupIds = $groupIds;
foreach ($groups as $k => $v) { foreach ($groups as $k => $v) {
if (in_array($v['pid'], $originGroupIds)) { if (in_array($v['pid'], $originGroupIds)) {
@ -371,12 +368,8 @@ class Auth extends \fast\Auth
$childrenAdminIds = []; $childrenAdminIds = [];
if (!$this->isSuperAdmin()) { if (!$this->isSuperAdmin()) {
$groupIds = $this->getChildrenGroupIds(false); $groupIds = $this->getChildrenGroupIds(false);
$authGroupList = \app\admin\model\AuthGroupAccess::field('uid,group_id') $childrenAdminIds = \app\admin\model\AuthGroupAccess::where('group_id', 'in', $groupIds)
->where('group_id', 'in', $groupIds) ->column('uid');
->select();
foreach ($authGroupList as $k => $v) {
$childrenAdminIds[] = $v['uid'];
}
} else { } else {
//超级管理员拥有所有人的权限 //超级管理员拥有所有人的权限
$childrenAdminIds = Admin::column('id'); $childrenAdminIds = Admin::column('id');

View File

@ -2,9 +2,9 @@
{if $addon.tips && $addon.tips.value} {if $addon.tips && $addon.tips.value}
<div class="alert {$addon.tips.extend|default='alert-info-light'}" style="margin-bottom:10px;"> <div class="alert {$addon.tips.extend|default='alert-info-light'}" style="margin-bottom:10px;">
{if $addon.tips.title} {if $addon.tips.title}
<b>{$addon.tips.title}</b><br> <b>{$addon.tips.title|htmlentities}</b><br>
{/if} {/if}
{$addon.tips.value} {$addon.tips.value|htmlentities}
</div> </div>
{/if} {/if}
@ -14,7 +14,7 @@
<ul class="nav nav-tabs nav-group"> <ul class="nav nav-tabs nav-group">
<li class="active"><a href="#all" data-toggle="tab">全部</a></li> <li class="active"><a href="#all" data-toggle="tab">全部</a></li>
{foreach name="groupList" id="tab"} {foreach name="groupList" id="tab"}
<li><a href="#tab-{$key}" title="{$tab}" data-toggle="tab">{$tab}</a></li> <li><a href="#tab-{$key|htmlentities}" title="{$tab|htmlentities}" data-toggle="tab">{$tab|htmlentities}</a></li>
{/foreach} {/foreach}
</ul> </ul>
</div> </div>
@ -23,99 +23,99 @@
<div class="panel-body no-padding"> <div class="panel-body no-padding">
<div id="myTabContent" class="tab-content"> <div id="myTabContent" class="tab-content">
{foreach name="groupList" id="group" key="groupName"} {foreach name="groupList" id="group" key="groupName"}
<div class="tab-pane fade active in" id="tab-{$groupName}"> <div class="tab-pane fade active in" id="tab-{$groupName|htmlentities}">
<table class="table table-striped table-config mb-0"> <table class="table table-striped table-config mb-0">
<tbody> <tbody>
{foreach name="$addon.config" id="item"} {foreach name="$addon.config" id="item"}
{if ((!isset($item['group']) || $item['group']=='') && $groupName=='other') || (isset($item['group']) && $item['group']==$group)} {if ((!isset($item['group']) || $item['group']=='') && $groupName=='other') || (isset($item['group']) && $item['group']==$group)}
<tr data-favisible="{$item.visible|default=''|htmlentities}" data-name="{$item.name}" class="{if $item.visible??''}hidden{/if}"> <tr data-favisible="{$item.visible|default=''|htmlentities}" data-name="{$item.name|htmlentities}" class="{if $item.visible??''}hidden{/if}">
<td width="15%">{$item.title}</td> <td width="15%">{$item.title|htmlentities}</td>
<td> <td>
<div class="row"> <div class="row">
<div class="col-sm-8 col-xs-12"> <div class="col-sm-8 col-xs-12">
{switch $item.type} {switch $item.type}
{case string} {case string}
<input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}"/> <input {$item.extend} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule|htmlentities}" data-tip="{$item.tip|htmlentities}"/>
{/case} {/case}
{case password} {case password}
<input {$item.extend} type="password" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}"/> <input {$item.extend} type="password" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule|htmlentities}" data-tip="{$item.tip|htmlentities}"/>
{/case} {/case}
{case text} {case text}
<textarea {$item.extend} name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}">{$item.value|htmlentities}</textarea> <textarea {$item.extend} name="row[{$item.name|htmlentities}]" class="form-control" data-rule="{$item.rule|htmlentities}" rows="5" data-tip="{$item.tip|htmlentities}">{$item.value|htmlentities}</textarea>
{/case} {/case}
{case array} {case array}
<dl class="fieldlist" data-name="row[{$item.name}]"> <dl class="fieldlist" data-name="row[{$item.name|htmlentities}]">
<dd> <dd>
<ins>{:__('Array key')}</ins> <ins>{:__('Array key')}</ins>
<ins>{:__('Array value')}</ins> <ins>{:__('Array value')}</ins>
</dd> </dd>
<dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd> <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
<textarea name="row[{$item.name}]" cols="30" rows="5" class="hide">{$item.value|json_encode|htmlentities}</textarea> <textarea name="row[{$item.name|htmlentities}]" cols="30" rows="5" class="hide">{$item.value|json_encode|htmlentities}</textarea>
</dl> </dl>
{/case} {/case}
{case date} {case date}
<input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case time} {case time}
<input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="HH:mm:ss" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case datetime} {case datetime}
<input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case number} {case number}
<input {$item.extend} type="number" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend} type="number" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case checkbox} {case checkbox}
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}][]-{$key}"><input id="row[{$item.name}][]-{$key}" name="row[{$item.name}][]" type="checkbox" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name|htmlentities}][]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}][]-{$key|htmlentities}" name="row[{$item.name|htmlentities}][]" type="checkbox" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
<span class="msg-box n-right" for="row[{$item.name}]"></span> <span class="msg-box n-right" for="row[{$item.name|htmlentities}]"></span>
{/case} {/case}
{case radio} {case radio}
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}]-{$key}"><input id="row[{$item.name}]-{$key}" name="row[{$item.name}]" type="radio" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name|htmlentities}]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}]-{$key|htmlentities}" name="row[{$item.name|htmlentities}]" type="radio" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
<span class="msg-box n-right" for="row[{$item.name}]"></span> <span class="msg-box n-right" for="row[{$item.name|htmlentities}]"></span>
{/case} {/case}
{case value="select" break="0"}{/case} {case value="select" break="0"}{/case}
{case value="selects"} {case value="selects"}
<select {$item.extend} name="row[{$item.name}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip}" {$item.type=='selects'?'multiple':''}> <select {$item.extend} name="row[{$item.name|htmlentities}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip|htmlentities}" {$item.type=='selects'?'multiple':''}>
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<option value="{$key}" {in name="key" value="$item.value" }selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="$item.value" }selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
{/case} {/case}
{case value="image" break="0"}{/case} {case value="image" break="0"}{/case}
{case value="images"} {case value="images"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="28" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <input id="c-{$item.name|htmlentities}" class="form-control" size="28" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}">
<span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="plupload-{$item.name|htmlentities}" class="btn btn-danger plupload" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name|htmlentities}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul> <ul class="row list-inline plupload-preview" id="p-{$item.name|htmlentities}"></ul>
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
</div> </div>
{/case} {/case}
{case value="file" break="0"}{/case} {case value="file" break="0"}{/case}
{case value="files"} {case value="files"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="28" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <input id="c-{$item.name|htmlentities}" class="form-control" size="28" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}">
<span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="plupload-{$item.name|htmlentities}" class="btn btn-danger plupload" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
</div> </div>
{/case} {/case}
{case switch} {case switch}
<input id="c-{$item.name}" name="row[{$item.name}]" type="hidden" value="{:$item.value?1:0}"> <input id="c-{$item.name|htmlentities}" name="row[{$item.name|htmlentities}]" type="hidden" value="{:$item.value?1:0}">
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-{$item.name}" data-yes="1" data-no="0"> <a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-{$item.name|htmlentities}" data-yes="1" data-no="0">
<i class="fa fa-toggle-on text-success {if !$item.value}fa-flip-horizontal text-gray{/if} fa-2x"></i> <i class="fa fa-toggle-on text-success {if !$item.value}fa-flip-horizontal text-gray{/if} fa-2x"></i>
</a> </a>
{/case} {/case}
{case bool} {case bool}
<label for="row[{$item.name}]-yes"><input id="row[{$item.name}]-yes" name="row[{$item.name}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip}" /> {:__('Yes')}</label> <label for="row[{$item.name|htmlentities}]-yes"><input id="row[{$item.name|htmlentities}]-yes" name="row[{$item.name|htmlentities}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip|htmlentities}" /> {:__('Yes')}</label>
<label for="row[{$item.name}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label> <label for="row[{$item.name|htmlentities}]-no"><input id="row[{$item.name|htmlentities}]-no" name="row[{$item.name|htmlentities}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip|htmlentities}" /> {:__('No')}</label>
{/case} {/case}
{default /}{$item.value} {default /}{$item.value|htmlentities}
{/switch} {/switch}
</div> </div>
<div class="col-sm-4"></div> <div class="col-sm-4"></div>

View File

@ -136,7 +136,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label">{:__('Version')}</label> <label class="control-label">{:__('Version')}</label>
<input type="hidden" class="operate" data-name="faversion" value="="/> <input type="hidden" class="operate" data-name="faversion" value="="/>
<input class="form-control" name="faversion" type="text" value="{$Think.config.fastadmin.version}"> <input class="form-control" name="faversion" type="text" value="{$Think.config.fastadmin.version|htmlentities}">
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-3"> <div class="col-xs-12 col-sm-6 col-md-3">

View File

@ -10,7 +10,7 @@
<select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]"> <select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]">
{foreach name="typeList" item="vo"} {foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value=""}selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value=""}selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
@ -22,7 +22,7 @@
<select id="c-pid" data-rule="required" class="form-control selectpicker" name="row[pid]"> <select id="c-pid" data-rule="required" class="form-control selectpicker" name="row[pid]">
{foreach name="parentList" item="vo"} {foreach name="parentList" item="vo"}
<option data-type="{$vo.type}" value="{$key}" {in name="key" value=""}selected{/in}>{$vo.name}</option> <option data-type="{$vo.type|htmlentities}" value="{$key|htmlentities}" {in name="key" value=""}selected{/in}>{$vo.name|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
@ -46,7 +46,7 @@
<select id="c-flag" class="form-control selectpicker" multiple="" name="row[flag][]"> <select id="c-flag" class="form-control selectpicker" multiple="" name="row[flag][]">
{foreach name="flagList" item="vo"} {foreach name="flagList" item="vo"}
<option value="{$key}" {in name="key" value=""}selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value=""}selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>

View File

@ -6,7 +6,7 @@
<select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]"> <select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]">
{foreach name="typeList" item="vo"} {foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value="$row.type"}selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="$row.type"}selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
@ -18,7 +18,7 @@
<select id="c-pid" data-rule="required" class="form-control selectpicker" name="row[pid]"> <select id="c-pid" data-rule="required" class="form-control selectpicker" name="row[pid]">
{foreach name="parentList" item="vo"} {foreach name="parentList" item="vo"}
<option data-type="{$vo.type}" class="{:$vo.type==$row.type||$vo.type=='all'?'':'hide'}" value="{$key}" {in name="key" value="$row.pid"}selected{/in}>{$vo.name}</option> <option data-type="{$vo.type|htmlentities}" class="{:$vo.type==$row.type||$vo.type=='all'?'':'hide'}" value="{$key|htmlentities}" {in name="key" value="$row.pid"}selected{/in}>{$vo.name|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
@ -42,7 +42,7 @@
<select id="c-flag" class="form-control selectpicker" multiple="" name="row[flag][]"> <select id="c-flag" class="form-control selectpicker" multiple="" name="row[flag][]">
{foreach name="flagList" item="vo"} {foreach name="flagList" item="vo"}
<option value="{$key}" {in name="key" value="$row.flag"}selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="$row.flag"}selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>

View File

@ -4,7 +4,7 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#all" data-toggle="tab">{:__('All')}</a></li> <li class="active"><a href="#all" data-toggle="tab">{:__('All')}</a></li>
{foreach name="typeList" item="vo"} {foreach name="typeList" item="vo"}
<li><a href="#{$key}" data-toggle="tab">{$vo}</a></li> <li><a href="#{$key|htmlentities}" data-toggle="tab">{$vo|htmlentities}</a></li>
{/foreach} {/foreach}
</ul> </ul>

View File

@ -117,10 +117,10 @@
<div id="secondnav"> <div id="secondnav">
<ul class="nav nav-tabs nav-addtabs disable-top-badge" role="tablist"> <ul class="nav nav-tabs nav-addtabs disable-top-badge" role="tablist">
{if $fixedmenu} {if $fixedmenu}
<li role="presentation" id="tab_{$fixedmenu.id}" class="{:$referermenu?'':'active'}"><a href="#con_{$fixedmenu.id}" node-id="{$fixedmenu.id}" aria-controls="{$fixedmenu.id}" role="tab" data-toggle="tab"><i class="fa fa-dashboard fa-fw"></i> <span>{$fixedmenu.title}</span> <span class="pull-right-container"> </span></a></li> <li role="presentation" id="tab_{$fixedmenu.id|htmlentities}" class="{:$referermenu?'':'active'}"><a href="#con_{$fixedmenu.id|htmlentities}" node-id="{$fixedmenu.id|htmlentities}" aria-controls="{$fixedmenu.id|htmlentities}" role="tab" data-toggle="tab"><i class="fa fa-dashboard fa-fw"></i> <span>{$fixedmenu.title|htmlentities}</span> <span class="pull-right-container"> </span></a></li>
{/if} {/if}
{if $referermenu} {if $referermenu}
<li role="presentation" id="tab_{$referermenu.id}" class="active"><a href="#con_{$referermenu.id}" node-id="{$referermenu.id}" aria-controls="{$referermenu.id}" role="tab" data-toggle="tab"><i class="fa fa-list fa-fw"></i> <span>{$referermenu.title}</span> <span class="pull-right-container"> </span></a> <i class="close-tab fa fa-remove"></i></li> <li role="presentation" id="tab_{$referermenu.id|htmlentities}" class="active"><a href="#con_{$referermenu.id|htmlentities}" node-id="{$referermenu.id|htmlentities}" aria-controls="{$referermenu.id|htmlentities}" role="tab" data-toggle="tab"><i class="fa fa-list fa-fw"></i> <span>{$referermenu.title|htmlentities}</span> <span class="pull-right-container"> </span></a> <i class="close-tab fa fa-remove"></i></li>
{/if} {/if}
</ul> </ul>
</div> </div>

View File

@ -7,10 +7,10 @@
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" /> <link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<!-- Loading Bootstrap --> <!-- Loading Bootstrap -->
<link href="__CDN__/assets/css/backend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version}" rel="stylesheet"> <link href="__CDN__/assets/css/backend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version|htmlentities}" rel="stylesheet">
{if $Think.config.fastadmin.adminskin} {if $Think.config.fastadmin.adminskin}
<link href="__CDN__/assets/css/skins/{$Think.config.fastadmin.adminskin}.css?v={$Think.config.site.version}" rel="stylesheet"> <link href="__CDN__/assets/css/skins/{$Think.config.fastadmin.adminskin|htmlentities}.css?v={$Think.config.site.version|htmlentities}" rel="stylesheet">
{/if} {/if}
<!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. --> <!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. -->

View File

@ -1 +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|htmlentities}"></script> <script src="__CDN__/assets/js/require.min.js" data-main="__CDN__/assets/js/require-backend{$Think.config.app_debug?'':'.min'}.js?v={$site.version|htmlentities}"></script>

View File

@ -176,7 +176,7 @@
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-red"><i class="fa fa-users"></i></span> <span class="sm-st-icon st-red"><i class="fa fa-users"></i></span>
<div class="sm-st-info"> <div class="sm-st-info">
<span>{$totaluser}</span> <span>{$totaluser|htmlentities}</span>
{:__('Total user')} {:__('Total user')}
</div> </div>
</div> </div>
@ -185,7 +185,7 @@
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-violet"><i class="fa fa-magic"></i></span> <span class="sm-st-icon st-violet"><i class="fa fa-magic"></i></span>
<div class="sm-st-info"> <div class="sm-st-info">
<span>{$totaladdon}</span> <span>{$totaladdon|htmlentities}</span>
{:__('Total addon')} {:__('Total addon')}
</div> </div>
</div> </div>
@ -194,7 +194,7 @@
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-blue"><i class="fa fa-leaf"></i></span> <span class="sm-st-icon st-blue"><i class="fa fa-leaf"></i></span>
<div class="sm-st-info"> <div class="sm-st-info">
<span>{$attachmentnums}</span> <span>{$attachmentnums|htmlentities}</span>
{:__('Total attachment')} {:__('Total attachment')}
</div> </div>
</div> </div>
@ -203,7 +203,7 @@
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-green"><i class="fa fa-user"></i></span> <span class="sm-st-icon st-green"><i class="fa fa-user"></i></span>
<div class="sm-st-info"> <div class="sm-st-info">
<span>{$totaladmin}</span> <span>{$totaladmin|htmlentities}</span>
{:__('Total admin')} {:__('Total admin')}
</div> </div>
</div> </div>
@ -221,7 +221,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-rocket"></i></div> <div class="stat-icon"><i class="fa fa-rocket"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$todayusersignup}</div> <div class="value"> {$todayusersignup|htmlentities}</div>
<div class="name"> {:__('Today user signup')}</div> <div class="name"> {:__('Today user signup')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -231,7 +231,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-vcard"></i></div> <div class="stat-icon"><i class="fa fa-vcard"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$todayuserlogin}</div> <div class="value"> {$todayuserlogin|htmlentities}</div>
<div class="name"> {:__('Today user login')}</div> <div class="name"> {:__('Today user login')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -241,7 +241,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-calendar"></i></div> <div class="stat-icon"><i class="fa fa-calendar"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$threednu}</div> <div class="value"> {$threednu|htmlentities}</div>
<div class="name"> {:__('Three dnu')}</div> <div class="name"> {:__('Three dnu')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -251,7 +251,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-calendar-plus-o"></i></div> <div class="stat-icon"><i class="fa fa-calendar-plus-o"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$sevendnu}</div> <div class="value"> {$sevendnu|htmlentities}</div>
<div class="name"> {:__('Seven dnu')}</div> <div class="name"> {:__('Seven dnu')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -261,7 +261,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-user-circle"></i></div> <div class="stat-icon"><i class="fa fa-user-circle"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$sevendau}</div> <div class="value"> {$sevendau|htmlentities}</div>
<div class="name"> {:__('Seven dau')}</div> <div class="name"> {:__('Seven dau')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -271,7 +271,7 @@
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-user-circle-o"></i></div> <div class="stat-icon"><i class="fa fa-user-circle-o"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$thirtydau}</div> <div class="value"> {$thirtydau|htmlentities}</div>
<div class="name"> {:__('Thirty dau')}</div> <div class="name"> {:__('Thirty dau')}</div>
</div> </div>
<div class="progress"> <div class="progress">
@ -298,7 +298,7 @@
<div class="panel-content"> <div class="panel-content">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h1 class="no-margins">{$totalworkingaddon}</h1> <h1 class="no-margins">{$totalworkingaddon|htmlentities}</h1>
<div class="font-bold"><i class="fa fa-magic"></i> <div class="font-bold"><i class="fa fa-magic"></i>
<small>{:__('Working addon count tips')}</small> <small>{:__('Working addon count tips')}</small>
</div> </div>
@ -318,7 +318,7 @@
<div class="ibox-content"> <div class="ibox-content">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h1 class="no-margins">{$dbtablenums}</h1> <h1 class="no-margins">{$dbtablenums|htmlentities}</h1>
<div class="font-bold"><i class="fa fa-database"></i> <div class="font-bold"><i class="fa fa-database"></i>
<small>{:__('Database table nums')}</small> <small>{:__('Database table nums')}</small>
</div> </div>
@ -346,7 +346,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h1 class="no-margins">{$attachmentnums}</h1> <h1 class="no-margins">{$attachmentnums|htmlentities}</h1>
<div class="font-bold"><i class="fa fa-files-o"></i> <div class="font-bold"><i class="fa fa-files-o"></i>
<small>{:__('Attachment nums')}</small> <small>{:__('Attachment nums')}</small>
</div> </div>
@ -373,7 +373,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h1 class="no-margins">{$picturenums}</h1> <h1 class="no-margins">{$picturenums|htmlentities}</h1>
<div class="font-bold"><i class="fa fa-picture-o"></i> <div class="font-bold"><i class="fa fa-picture-o"></i>
<small>{:__('Picture nums')}</small> <small>{:__('Picture nums')}</small>
</div> </div>

View File

@ -15,7 +15,7 @@
<select name="category-third" id="category-third" class="form-control selectpicker"> <select name="category-third" id="category-third" class="form-control selectpicker">
<option value="">{:__('Please select category')}</option> <option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"} {foreach name="categoryList" id="item"}
<option value="{$key}">{$item}</option> <option value="{$key|htmlentities}">{$item|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>
@ -42,13 +42,13 @@
<select name="category-local" id="category-local" class="form-control selectpicker"> <select name="category-local" id="category-local" class="form-control selectpicker">
<option value="">{:__('Please select category')}</option> <option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"} {foreach name="categoryList" id="item"}
<option value="{$key}">{$item}</option> <option value="{$key|htmlentities}">{$item|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>
<button type="button" id="faupload-local" class="btn btn-primary faupload" data-input-id="c-local" data-multiple="true" data-preview-id="p-local" data-url="{:url('ajax/upload')}"><i class="fa fa-upload"></i> {:__("Upload to local")}</button> <button type="button" id="faupload-local" class="btn btn-primary faupload" data-input-id="c-local" data-multiple="true" data-preview-id="p-local" data-url="{:url('ajax/upload')}" data-cdnurl=""><i class="fa fa-upload"></i> {:__("Upload to local")}</button>
{if $config.upload.chunking} {if $config.upload.chunking}
<button type="button" id="faupload-local-chunking" class="btn btn-primary faupload" data-chunking="true" data-maxsize="1gb" data-input-id="c-local" data-multiple="true" data-preview-id="p-local" data-url="{:url('ajax/upload')}"><i class="fa fa-upload"></i> {:__("Upload to local by chunk")}</button> <button type="button" id="faupload-local-chunking" class="btn btn-primary faupload" data-chunking="true" data-maxsize="1gb" data-input-id="c-local" data-multiple="true" data-preview-id="p-local" data-url="{:url('ajax/upload')}" data-cdnurl=""><i class="fa fa-upload"></i> {:__("Upload to local by chunk")}</button>
{/if} {/if}
</div> </div>
</div> </div>

View File

@ -8,7 +8,7 @@
<select name="row[category]" class="form-control"> <select name="row[category]" class="form-control">
<option value="">{:__('Please select category')}</option> <option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"} {foreach name="categoryList" id="item"}
<option value="{$key}" {if $key==$row.category}selected{/if}>{$item}</option> <option value="{$key|htmlentities}" {if $key==$row.category}selected{/if}>{$item|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>

View File

@ -5,14 +5,14 @@
<ul class="nav nav-tabs" data-field="category"> <ul class="nav nav-tabs" data-field="category">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="categoryList" item="vo"} {foreach name="categoryList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> <li><a href="#t-{$key|htmlentities}" data-value="{$key|htmlentities}" data-toggle="tab">{$vo|htmlentities}</a></li>
{/foreach} {/foreach}
<li class="pull-right dropdown filter-type"> <li class="pull-right dropdown filter-type">
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-filter"></i> {:__('Filter Type')}</a> <a href="javascript:" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-filter"></i> {:__('Filter Type')}</a>
<ul class="dropdown-menu text-left" role="menu"> <ul class="dropdown-menu text-left" role="menu">
<li class="active"><a href="javascript:" data-value="">{:__('All')}</a></li> <li class="active"><a href="javascript:" data-value="">{:__('All')}</a></li>
{foreach name="mimetypeList" id="item"} {foreach name="mimetypeList" id="item"}
<li><a href="javascript:" data-value="{$key}">{$item}</a></li> <li><a href="javascript:" data-value="{$key|htmlentities}">{$item|htmlentities}</a></li>
{/foreach} {/foreach}
</ul> </ul>
</li> </li>
@ -45,7 +45,7 @@
<select name="category" class="form-control"> <select name="category" class="form-control">
<option value="">{:__('Please select category')}</option> <option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"} {foreach name="categoryList" id="item"}
<option value="{$key}">{$item}</option> <option value="{$key|htmlentities}">{$item|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>

View File

@ -9,7 +9,7 @@
<ul class="nav nav-tabs" data-field="category"> <ul class="nav nav-tabs" data-field="category">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> <li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="categoryList" item="vo"} {foreach name="categoryList" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> <li><a href="#t-{$key|htmlentities}" data-value="{$key|htmlentities}" data-toggle="tab">{$vo|htmlentities}</a></li>
{/foreach} {/foreach}
{if stripos(request()->get('mimetype'),'image/')===false} {if stripos(request()->get('mimetype'),'image/')===false}
<li class="pull-right dropdown filter-type"> <li class="pull-right dropdown filter-type">
@ -17,7 +17,7 @@
<ul class="dropdown-menu text-left" role="menu"> <ul class="dropdown-menu text-left" role="menu">
<li class="active"><a href="javascript:" data-value="">{:__('All')}</a></li> <li class="active"><a href="javascript:" data-value="">{:__('All')}</a></li>
{foreach name="mimetypeList" id="item"} {foreach name="mimetypeList" id="item"}
<li><a href="javascript:" data-value="{$key}">{$item}</a></li> <li><a href="javascript:" data-value="{$key|htmlentities}">{$item|htmlentities}</a></li>
{/foreach} {/foreach}
</ul> </ul>
</li> </li>

View File

@ -27,7 +27,7 @@
{:build_heading(null, false)} {:build_heading(null, false)}
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
{foreach $siteList as $index=>$vo} {foreach $siteList as $index=>$vo}
<li class="{$vo.active?'active':''}"><a href="#tab-{$vo.name}" data-toggle="tab">{:__($vo.title)}</a></li> <li class="{$vo.active?'active':''}"><a href="#tab-{$vo.name|htmlentities}" data-toggle="tab">{:__(htmlentities($vo.title))}</a></li>
{/foreach} {/foreach}
{if $Think.config.app_debug} {if $Think.config.app_debug}
<li data-toggle="tooltip" title="{:__('Add new config')}"> <li data-toggle="tooltip" title="{:__('Add new config')}">
@ -41,9 +41,9 @@
<div id="myTabContent" class="tab-content"> <div id="myTabContent" class="tab-content">
<!--@formatter:off--> <!--@formatter:off-->
{foreach $siteList as $index=>$vo} {foreach $siteList as $index=>$vo}
<div class="tab-pane fade {$vo.active ? 'active in' : ''}" id="tab-{$vo.name}"> <div class="tab-pane fade {$vo.active ? 'active in' : ''}" id="tab-{$vo.name|htmlentities}">
<div class="widget-body no-padding"> <div class="widget-body no-padding">
<form id="{$vo.name}-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="{:url('general.config/edit')}"> <form id="{$vo.name|htmlentities}-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="{:url('general.config/edit')}">
{:token()} {:token()}
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
@ -58,111 +58,111 @@
</thead> </thead>
<tbody> <tbody>
{foreach $vo.list as $item} {foreach $vo.list as $item}
<tr data-favisible="{$item.visible|default=''|htmlentities}" data-name="{$item.name}" class="{if $item.visible??''}hidden{/if}"> <tr data-favisible="{$item.visible|default=''|htmlentities}" data-name="{$item.name|htmlentities}" class="{if $item.visible??''}hidden{/if}">
<td>{$item.title}</td> <td>{$item.title|htmlentities}</td>
<td> <td>
<div class="row"> <div class="row">
<div class="col-sm-8 col-xs-12"> <div class="col-sm-8 col-xs-12">
{switch $item.type} {switch $item.type}
{case string} {case string}
<input {$item.extend_html} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}"/> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule|htmlentities}" data-tip="{$item.tip|htmlentities}"/>
{/case} {/case}
{case password} {case password}
<input {$item.extend_html} type="password" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}"/> <input {$item.extend_html|htmlentities} type="password" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule|htmlentities}" data-tip="{$item.tip|htmlentities}"/>
{/case} {/case}
{case text} {case text}
<textarea {$item.extend_html} name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}">{$item.value|htmlentities}</textarea> <textarea {$item.extend_html|htmlentities} name="row[{$item.name|htmlentities}]" class="form-control" data-rule="{$item.rule|htmlentities}" rows="5" data-tip="{$item.tip|htmlentities}">{$item.value|htmlentities}</textarea>
{/case} {/case}
{case editor} {case editor}
<textarea {$item.extend_html} name="row[{$item.name}]" id="editor-{$item.name}" class="form-control editor" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}">{$item.value|htmlentities}</textarea> <textarea {$item.extend_html|htmlentities} name="row[{$item.name|htmlentities}]" id="editor-{$item.name|htmlentities}" class="form-control editor" data-rule="{$item.rule|htmlentities}" rows="5" data-tip="{$item.tip|htmlentities}">{$item.value|htmlentities}</textarea>
{/case} {/case}
{case array} {case array}
<dl {$item.extend_html} class="fieldlist" data-name="row[{$item.name}]"> <dl {$item.extend_html|htmlentities} class="fieldlist" data-name="row[{$item.name|htmlentities}]">
<dd> <dd>
<ins>{:isset($item["setting"]["key"])&&$item["setting"]["key"]?$item["setting"]["key"]:__('Array key')}</ins> <ins>{:isset($item["setting"]["key"])&&$item["setting"]["key"]?$item["setting"]["key"]:__('Array key')}</ins>
<ins>{:isset($item["setting"]["value"])&&$item["setting"]["value"]?$item["setting"]["value"]:__('Array value')}</ins> <ins>{:isset($item["setting"]["value"])&&$item["setting"]["value"]?$item["setting"]["value"]:__('Array value')}</ins>
</dd> </dd>
<dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd> <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
<textarea name="row[{$item.name}]" class="form-control hide" cols="30" rows="5">{$item.value|htmlentities}</textarea> <textarea name="row[{$item.name|htmlentities}]" class="form-control hide" cols="30" rows="5">{$item.value|htmlentities}</textarea>
</dl> </dl>
{/case} {/case}
{case date} {case date}
<input {$item.extend_html} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case time} {case time}
<input {$item.extend_html} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="HH:mm:ss" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case datetime} {case datetime}
<input {$item.extend_html} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case datetimerange} {case datetimerange}
<input {$item.extend_html} type="text" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control datetimerange" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimerange" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case number} {case number}
<input {$item.extend_html} type="number" name="row[{$item.name}]" value="{$item.value|htmlentities}" class="form-control" data-tip="{$item.tip}" data-rule="{$item.rule}"/> <input {$item.extend_html|htmlentities} type="number" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
{/case} {/case}
{case checkbox} {case checkbox}
<div class="checkbox"> <div class="checkbox">
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}][]-{$key}"><input id="row[{$item.name}][]-{$key}" name="row[{$item.name}][]" type="checkbox" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name|htmlentities}][]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}][]-{$key|htmlentities}" name="row[{$item.name|htmlentities}][]" type="checkbox" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
</div> </div>
{/case} {/case}
{case radio} {case radio}
<div class="radio"> <div class="radio">
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}]-{$key}"><input id="row[{$item.name}]-{$key}" name="row[{$item.name}]" type="radio" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name|htmlentities}]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}]-{$key|htmlentities}" name="row[{$item.name|htmlentities}]" type="radio" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
</div> </div>
{/case} {/case}
{case value="select" break="0"}{/case} {case value="select" break="0"}{/case}
{case value="selects"} {case value="selects"}
<select {$item.extend_html} name="row[{$item.name}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip}" {$item.type=='selects'?'multiple':''}> <select {$item.extend_html|htmlentities} name="row[{$item.name|htmlentities}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip|htmlentities}" {$item.type=='selects'?'multiple':''}>
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<option value="{$key}" {in name="key" value="$item.value" }selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="$item.value" }selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
{/case} {/case}
{case value="image" break="0"}{/case} {case value="image" break="0"}{/case}
{case value="images"} {case value="images"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="50" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <input id="c-{$item.name|htmlentities}" class="form-control" size="50" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}">
<span><button type="button" id="faupload-{$item.name}" class="btn btn-danger faupload" data-input-id="c-{$item.name}" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-{$item.name|htmlentities}" class="btn btn-danger faupload" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name|htmlentities}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
<ul class="row list-inline faupload-preview" id="p-{$item.name}"></ul> <ul class="row list-inline faupload-preview" id="p-{$item.name|htmlentities}"></ul>
</div> </div>
{/case} {/case}
{case value="file" break="0"}{/case} {case value="file" break="0"}{/case}
{case value="files"} {case value="files"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="50" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <input id="c-{$item.name|htmlentities}" class="form-control" size="50" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}">
<span><button type="button" id="faupload-{$item.name}" class="btn btn-danger faupload" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-{$item.name|htmlentities}" class="btn btn-danger faupload" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
</div> </div>
{/case} {/case}
{case switch} {case switch}
<input id="c-{$item.name}" name="row[{$item.name}]" type="hidden" value="{:$item.value?1:0}"> <input id="c-{$item.name|htmlentities}" name="row[{$item.name|htmlentities}]" type="hidden" value="{:$item.value?1:0}">
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-{$item.name}" data-yes="1" data-no="0"> <a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-{$item.name|htmlentities}" data-yes="1" data-no="0">
<i class="fa fa-toggle-on text-success {if !$item.value}fa-flip-horizontal text-gray{/if} fa-2x"></i> <i class="fa fa-toggle-on text-success {if !$item.value}fa-flip-horizontal text-gray{/if} fa-2x"></i>
</a> </a>
{/case} {/case}
{case bool} {case bool}
<label for="row[{$item.name}]-yes"><input id="row[{$item.name}]-yes" name="row[{$item.name}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip}" /> {:__('Yes')}</label> <label for="row[{$item.name|htmlentities}]-yes"><input id="row[{$item.name|htmlentities}]-yes" name="row[{$item.name|htmlentities}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip|htmlentities}" /> {:__('Yes')}</label>
<label for="row[{$item.name}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label> <label for="row[{$item.name|htmlentities}]-no"><input id="row[{$item.name|htmlentities}]-no" name="row[{$item.name|htmlentities}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip|htmlentities}" /> {:__('No')}</label>
{/case} {/case}
{case city} {case city}
<div style="position:relative"> <div style="position:relative">
<input {$item.extend_html} type="text" name="row[{$item.name}]" id="c-{$item.name}" value="{$item.value|htmlentities}" class="form-control" data-toggle="city-picker" data-tip="{$item.tip}" data-rule="{$item.rule}" /> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" id="c-{$item.name|htmlentities}" value="{$item.value|htmlentities}" class="form-control" data-toggle="city-picker" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}" />
</div> </div>
{/case} {/case}
{case value="selectpage" break="0"}{/case} {case value="selectpage" break="0"}{/case}
{case value="selectpages"} {case value="selectpages"}
<input {$item.extend_html} type="text" name="row[{$item.name}]" id="c-{$item.name}" value="{$item.value|htmlentities}" class="form-control selectpage" data-source="{:url('general.config/selectpage')}?id={$item.id}" data-primary-key="{$item.setting.primarykey}" data-field="{$item.setting.field}" data-multiple="{$item.type=='selectpage'?'false':'true'}" data-tip="{$item.tip}" data-rule="{$item.rule}" /> <input {$item.extend_html|htmlentities} type="text" name="row[{$item.name|htmlentities}]" id="c-{$item.name|htmlentities}" value="{$item.value|htmlentities}" class="form-control selectpage" data-source="{:url('general.config/selectpage')}?id={$item.id|htmlentities}" data-primary-key="{$item.setting.primarykey|htmlentities}" data-field="{$item.setting.field|htmlentities}" data-multiple="{$item.type=='selectpage'?'false':'true'}" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}" />
{/case} {/case}
{case custom} {case custom}
{$item.extend_html} {$item.extend_html|htmlentities}
{/case} {/case}
{/switch} {/switch}
</div> </div>
@ -172,7 +172,7 @@
</td> </td>
{if $Think.config.app_debug} {if $Think.config.app_debug}
<td>{php}echo "{\$site.". $item['name'] . "}";{/php}</td> <td>{php}echo "{\$site.". $item['name'] . "}";{/php}</td>
<td>{if $item['id']>18}<a href="javascript:;" class="btn-delcfg text-muted" data-name="{$item.name}"><i class="fa fa-times"></i></a>{/if}</td> <td>{if $item['id']>18}<a href="javascript:;" class="btn-delcfg text-muted" data-name="{$item.name|htmlentities}"><i class="fa fa-times"></i></a>{/if}</td>
{/if} {/if}
</tr> </tr>
{/foreach} {/foreach}
@ -205,7 +205,7 @@
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<select name="row[group]" class="form-control selectpicker"> <select name="row[group]" class="form-control selectpicker">
{foreach name="groupList" item="vo"} {foreach name="groupList" item="vo"}
<option value="{$key}" {in name="key" value="basic" }selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="basic" }selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>
@ -215,7 +215,7 @@
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<select name="row[type]" id="c-type" class="form-control selectpicker"> <select name="row[type]" id="c-type" class="form-control selectpicker">
{foreach name="typeList" item="vo"} {foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value="string" }selected{/in}>{$vo}</option> <option value="{$key|htmlentities}" {in name="key" value="string" }selected{/in}>{$vo|htmlentities}</option>
{/foreach} {/foreach}
</select> </select>
</div> </div>
@ -306,7 +306,7 @@ value2|title2</textarea>
<button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" type="button">{:__('Choose')}</button> <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" type="button">{:__('Choose')}</button>
<ul class="dropdown-menu pull-right rulelist"> <ul class="dropdown-menu pull-right rulelist">
{volist name="ruleList" id="item"} {volist name="ruleList" id="item"}
<li><a href="javascript:;" data-value="{$key}">{$item}<span class="text-muted">({$key})</span></a></li> <li><a href="javascript:;" data-value="{$key|htmlentities}">{$item|htmlentities}<span class="text-muted">({$key|htmlentities})</span></a></li>
{/volist} {/volist}
</ul> </ul>
</span> </span>

View File

@ -27,13 +27,13 @@
<!-- 主体内容区域 --> <!-- 主体内容区域 -->
<div class="content-wrapper tab-content tab-addtabs"> <div class="content-wrapper tab-content tab-addtabs">
{if $fixedmenu} {if $fixedmenu}
<div role="tabpanel" class="tab-pane {:$referermenu?'':'active'}" id="con_{$fixedmenu.id}"> <div role="tabpanel" class="tab-pane {:$referermenu?'':'active'}" id="con_{$fixedmenu.id|htmlentities}">
<iframe src="{$fixedmenu.url}{:stripos($fixedmenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe> <iframe src="{$fixedmenu.url|htmlentities}{:stripos($fixedmenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe>
</div> </div>
{/if} {/if}
{if $referermenu} {if $referermenu}
<div role="tabpanel" class="tab-pane active" id="con_{$referermenu.id}"> <div role="tabpanel" class="tab-pane active" id="con_{$referermenu.id|htmlentities}">
<iframe src="{$referermenu.url}{:stripos($referermenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe> <iframe src="{$referermenu.url|htmlentities}{:stripos($referermenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe>
</div> </div>
{/if} {/if}
</div> </div>
@ -42,7 +42,7 @@
<footer class="main-footer hide"> <footer class="main-footer hide">
<div class="pull-right hidden-xs"> <div class="pull-right hidden-xs">
</div> </div>
<strong>Copyright &copy; 2017-{:date("Y")} <a href="__PUBLIC__">{$site.name}</a>.</strong> All rights reserved. <strong>Copyright &copy; 2017-{:date("Y")} <a href="__PUBLIC__">{$site.name|htmlentities}</a>.</strong> All rights reserved.
</footer> </footer>
<!-- 右侧控制栏 --> <!-- 右侧控制栏 -->

View File

@ -81,7 +81,7 @@
{if $background} {if $background}
<style type="text/css"> <style type="text/css">
body{ body{
background-image: url('{$background}'); background-image: url('{$background|htmlentities}');
} }
</style> </style>
{/if} {/if}
@ -116,7 +116,7 @@
{if $Think.config.fastadmin.login_captcha} {if $Think.config.fastadmin.login_captcha}
<div class="input-group"> <div class="input-group">
<div class="input-group-addon"><span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span></div> <div class="input-group-addon"><span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span></div>
<input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="{:__('Captcha')}:required;length({$Think.config.captcha.length})" autocomplete="off"/> <input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="{:__('Captcha')}:required;length({$Think.config.captcha.length|htmlentities})" autocomplete="off"/>
<span class="input-group-addon" style="padding:0;border:none;cursor:pointer;"> <span class="input-group-addon" style="padding:0;border:none;cursor:pointer;">
<img src="{:rtrim('__PUBLIC__', '/')}/index.php?s=/captcha" width="100" height="30" onclick="this.src = '{:rtrim('__PUBLIC__', '/')}/index.php?s=/captcha&r=' + Math.random();"/> <img src="{:rtrim('__PUBLIC__', '/')}/index.php?s=/captcha" width="100" height="30" onclick="this.src = '{:rtrim('__PUBLIC__', '/')}/index.php?s=/captcha&r=' + Math.random();"/>
</span> </span>

View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
{include file="common/meta" /}
<style type="text/css">
body {
color: #999;
background-color: #f1f4fd;
background-size: cover;
}
a {
color: #444;
}
.logout-main {
text-align: center;
max-width: 430px;
margin: 0 auto;
margin-top: 150px;
background-color: #fff;
padding: 40px 30px;
border-radius: 3px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="container">
<div class="logout-main text-center">
<div class="image">
<img src="__CDN__/assets/img/info.svg" alt="" width="100" />
</div>
<h3 class="my-4" style="font-size:16px;">{:__('Are you sure you want to sign out?')}</h3>
<form name="form" id="logout-form" class="form-vertical" method="POST" action="#">
{:token()}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Confirm sign out')}</button>
<button type="button" class="btn btn-default btn-lg btn-block mt-3" onclick="history.back()">{:__('Cancel')}</button>
</div>
</form>
</div>
</div>
{include file="common/script" /}
</body>
</html>

View File

@ -26,7 +26,7 @@
</ol> </ol>
<ol class="breadcrumb pull-right"> <ol class="breadcrumb pull-right">
{foreach $breadcrumb as $vo} {foreach $breadcrumb as $vo}
<li><a href="javascript:;" data-url="{$vo.url}">{$vo.title}</a></li> <li><a href="javascript:;" data-url="{$vo.url|htmlentities}">{$vo.title|htmlentities}</a></li>
{/foreach} {/foreach}
</ol> </ol>
</div> </div>

View File

@ -22,7 +22,7 @@
<div class="radio"> <div class="radio">
{foreach name="statusList" item="vo"} {foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="normal"}checked{/in} /> {$vo}</label> <label for="row[status]-{$key|htmlentities}"><input id="row[status]-{$key|htmlentities}" name="row[status]" type="radio" value="{$key|htmlentities}" {in name="key" value="normal"}checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
</div> </div>

View File

@ -22,7 +22,7 @@
<div class="radio"> <div class="radio">
{foreach name="statusList" item="vo"} {foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="$row.status"}checked{/in} /> {$vo}</label> <label for="row[status]-{$key|htmlentities}"><input id="row[status]-{$key|htmlentities}" name="row[status]" type="radio" value="{$key|htmlentities}" {in name="key" value="$row.status"}checked{/in} /> {$vo|htmlentities}</label>
{/foreach} {/foreach}
</div> </div>

View File

@ -39,37 +39,20 @@ class Common extends Api
* 加载初始化 * 加载初始化
* *
* @ApiParams (name="version", type="string", required=true, description="版本号") * @ApiParams (name="version", type="string", required=true, description="版本号")
* @ApiParams (name="lng", type="string", required=true, description="经度")
* @ApiParams (name="lat", type="string", required=true, description="纬度")
*/ */
public function init() public function init()
{ {
if ($version = $this->request->request('version')) { if ($version = $this->request->request('version')) {
$lng = $this->request->request('lng');
$lat = $this->request->request('lat');
//配置信息 //配置信息
$upload = Config::get('upload'); $upload = Config::get('upload');
//如果非服务端中转模式需要修改为中转
if ($upload['storage'] != 'local' && isset($upload['uploadmode']) && $upload['uploadmode'] != 'server') {
//临时修改上传模式为服务端中转
set_addon_config($upload['storage'], ["uploadmode" => "server"], false);
$upload = \app\common\model\Config::upload(); $uploaddata = [];
// 上传信息配置后 $uploaddata['cdnurl'] = $upload['cdnurl'] ?: cdnurl('', true);
Hook::listen("upload_config_init", $upload); $uploaddata['uploadurl'] = url('/api/common/upload', '', false, true);
$upload = Config::set('upload', array_merge(Config::get('upload'), $upload));
}
$upload['cdnurl'] = $upload['cdnurl'] ? $upload['cdnurl'] : cdnurl('', true);
$upload['uploadurl'] = preg_match("/^((?:[a-z]+:)?\/\/)(.*)/i", $upload['uploadurl']) ? $upload['uploadurl'] : url($upload['storage'] == 'local' ? '/api/common/upload' : $upload['uploadurl'], '', false, true);
$content = [ $content = [
'citydata' => Area::getCityFromLngLat($lng, $lat),
'versiondata' => Version::check($version), 'versiondata' => Version::check($version),
'uploaddata' => $upload, 'uploaddata' => $uploaddata,
'coverdata' => Config::get("cover"),
]; ];
$this->success('', $content); $this->success('', $content);
} else { } else {
@ -80,7 +63,7 @@ class Common extends Api
/** /**
* 上传文件 * 上传文件
* @ApiMethod (POST) * @ApiMethod (POST)
* @ApiParams (name="file", type="File", required=true, description="文件流") * @ApiParams (name="file", type="file", required=true, description="文件流")
*/ */
public function upload() public function upload()
{ {

View File

@ -179,8 +179,15 @@ class User extends Api
} }
$user->nickname = $nickname; $user->nickname = $nickname;
} }
if ($avatar) {
//判断是否匹配config('upload.cdnurl')开头以及当前$SERVER['HTTP_HOST']开头。
if (preg_match('/^' . preg_quote(config('upload.cdnurl') . '/', '/') . '/i', $avatar)
|| preg_match('/^' . preg_quote(substr(config('upload.savekey'), 0, strpos(config('upload.savekey'), '{')), '/') . '/i', $avatar)
|| preg_match('/^' . preg_quote($_SERVER['HTTP_HOST'] . '/', '/') . '/i', $avatar)) {
$user->avatar = $avatar;
}
}
$user->bio = $bio; $user->bio = $bio;
$user->avatar = $avatar;
$user->save(); $user->save();
$this->success(); $this->success();
} }

View File

@ -3,6 +3,7 @@
namespace app\common\controller; namespace app\common\controller;
use app\admin\library\Auth; use app\admin\library\Auth;
use app\common\library\SelectPage;
use think\Config; use think\Config;
use think\Controller; use think\Controller;
use think\Hook; use think\Hook;
@ -10,7 +11,6 @@ use think\Lang;
use think\Loader; use think\Loader;
use think\Model; use think\Model;
use think\Session; use think\Session;
use fast\Tree;
use think\Validate; use think\Validate;
/** /**
@ -459,140 +459,27 @@ class Backend extends Controller
/** /**
* Selectpage的实现方法 * Selectpage的实现方法
*
* 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可
* 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可
*
*/ */
protected function selectpage() protected function selectpage()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']); $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
//搜索关键词,客户端输入以空格分开,这里接收为数组 $selectPage = new SelectPage($this->model, $this->selectpageFields);
$word = (array)$this->request->request("q_word/a");
//当前页 // 数据限制
$page = $this->request->request("pageNumber"); $dataLimitIds = $this->getDataLimitAdminIds();
//分页大小 if (is_array($dataLimitIds)) {
$pagesize = $this->request->request("pageSize"); $selectPage->setDataLimit($this->dataLimit, $this->dataLimitField, $dataLimitIds);
//搜索条件
$andor = $this->request->request("andOr", "and", "strtoupper");
//排序方式
$orderby = (array)$this->request->request("orderBy/a");
//显示的字段
$field = $this->request->request("showField");
//主键
$primarykey = $this->request->request("keyField");
//主键值
$primaryvalue = $this->request->request("keyValue");
//搜索字段
$searchfield = (array)$this->request->request("searchField/a");
//自定义搜索条件
$custom = (array)$this->request->request("custom/a");
//是否返回树形结构
$istree = $this->request->request("isTree", 0);
$ishtml = $this->request->request("isHtml", 0);
if ($istree) {
$word = [];
$pagesize = 999999;
} }
$order = [];
foreach ($orderby as $k => $v) { try {
$order[$v[0]] = $v[1]; $result = $selectPage->execute($this->request->request());
} catch (\think\Exception $e) {
$this->error(__($e->getMessage()));
} }
$field = $field ? $field : 'name';
//如果有primaryvalue,说明当前是初始化传值 return json($result);
if ($primaryvalue !== null) {
$where = [$primarykey => ['in', $primaryvalue]];
$pagesize = 999999;
} else {
$where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
$logic = $andor == 'AND' ? '&' : '|';
$searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
$searchfield = str_replace(',', $logic, $searchfield);
$word = array_filter(array_unique($word));
if (count($word) == 1) {
$query->where($searchfield, "like", "%" . reset($word) . "%");
} else {
$query->where(function ($query) use ($word, $searchfield) {
foreach ($word as $index => $item) {
$query->whereOr(function ($query) use ($item, $searchfield) {
$query->where($searchfield, "like", "%{$item}%");
});
}
});
}
if ($custom && is_array($custom)) {
foreach ($custom as $k => $v) {
if (is_array($v) && 2 == count($v)) {
$query->where($k, trim($v[0]), $v[1]);
} else {
$query->where($k, '=', $v);
}
}
}
};
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = [];
$total = $this->model->where($where)->count();
if ($total > 0) {
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$fields = is_array($this->selectpageFields) ? $this->selectpageFields : ($this->selectpageFields && $this->selectpageFields != '*' ? explode(',', $this->selectpageFields) : []);
//如果有primaryvalue,说明当前是初始化传值,按照选择顺序排序
if ($primaryvalue !== null && preg_match("/^[a-z0-9_\-]+$/i", $primarykey)) {
$primaryvalue = array_unique(is_array($primaryvalue) ? $primaryvalue : explode(',', $primaryvalue));
//修复自定义data-primary-key为字符串内容时给排序字段添加上引号
$primaryvalue = array_map(function ($value) {
return '\'' . $value . '\'';
}, $primaryvalue);
$primaryvalue = implode(',', $primaryvalue);
$this->model->orderRaw("FIELD(`{$primarykey}`, {$primaryvalue})");
} else {
$this->model->order($order);
}
$datalist = $this->model->where($where)
->page($page, $pagesize)
->select();
foreach ($datalist as $index => $item) {
unset($item['password'], $item['salt']);
if ($this->selectpageFields == '*') {
$result = [
$primarykey => $item[$primarykey] ?? '',
$field => $item[$field] ?? '',
];
} else {
$result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields));
}
$result['pid'] = isset($item['pid']) ? $item['pid'] : (isset($item['parent_id']) ? $item['parent_id'] : 0);
$list[] = $result;
}
if ($istree && !$primaryvalue) {
$tree = Tree::instance();
$tree->init(collection($list)->toArray(), 'pid');
$list = $tree->getTreeList($tree->getTreeArray(0), $field);
if (!$ishtml) {
foreach ($list as &$item) {
$item = str_replace('&nbsp;', ' ', $item);
}
unset($item);
}
}
}
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]);
} }
/** /**

View File

@ -224,6 +224,7 @@ class Auth
if ($user->loginfailure >= 10 && time() - $user->loginfailuretime < 86400) { if ($user->loginfailure >= 10 && time() - $user->loginfailuretime < 86400) {
$this->setError('Please try again after 1 day'); $this->setError('Please try again after 1 day');
return false;
} }
if ($user->password != $this->getEncryptPassword($password, $user->salt)) { if ($user->password != $this->getEncryptPassword($password, $user->salt)) {

View File

@ -19,10 +19,8 @@ class Log extends AbstractLogger
* @param array $context * @param array $context
* *
* @return void * @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = [])
{ {
\think\Log::write($message); \think\Log::write($message);
} }

View File

@ -0,0 +1,447 @@
<?php
namespace app\common\library;
use fast\Tree;
use think\Db;
use think\Exception;
use think\Model;
/**
* SelectPage 查询构建器
*/
class SelectPage
{
/**
* 模型实例
* @var Model
*/
protected $model;
/**
* 允许显示的字段
* @var array|string
*/
protected $selectpageFields = '*';
/**
* 数据限制模式
* @var bool|string
*/
protected $dataLimit = false;
/**
* 数据限制字段
* @var string
*/
protected $dataLimitField = 'admin_id';
/**
* 允许的表字段列表
* @var array
*/
protected $allowedFields = [];
/**
* 允许的操作符ThinkPHP Builder::$exp 的键和值(不包含exp),去重后保留小写)
* @var array
*/
protected static $allowedOperators = [
'eq', 'neq', 'gt', 'egt', 'lt', 'elt',
'=', '<>', '>', '>=', '<', '<=',
'like', 'not like', 'notlike',
'in', 'not in', 'notin',
'between', 'not between', 'notbetween',
'null', 'not null', 'notnull',
'exists', 'not exists', 'notexists',
'> time', '< time', '>= time', '<= time',
'between time', 'not between time', 'notbetween time',
];
/**
* 允许排序的字段
* @var array
*/
protected $orderFields = [];
/**
* @param Model $model 模型实例
* @param string $fields SelectPage可显示的字段
*/
public function __construct(Model $model, $fields = '*')
{
$this->model = $model;
$this->selectpageFields = $fields;
$this->allowedFields = array_map('strtolower', $model->getTableFields());
$this->orderFields = $this->allowedFields;
}
/**
* 数据限制的ID集合
* @var array
*/
protected $dataLimitIds = [];
/**
* 设置数据限制
* @param bool|string $dataLimit auth/personal/false
* @param string $dataLimitField 限制字段
* @param array $dataLimitIds 允许的ID列表
* @return $this
*/
public function setDataLimit($dataLimit, $dataLimitField = 'admin_id', array $dataLimitIds = [])
{
$this->dataLimit = $dataLimit;
$this->dataLimitField = $dataLimitField;
$this->dataLimitIds = $dataLimitIds;
return $this;
}
/**
* 应用数据限制条件(每次构建新查询链前调用)
* ThinkPHP count()/select() 执行后会清空 model options
* 所以需要在每次查询前重新注入 dataLimit 条件。
* @return $this
*/
protected function applyDataLimit()
{
if ($this->dataLimit) {
$this->model->where($this->dataLimitField, 'in', $this->dataLimitIds);
}
return $this;
}
/**
* 执行查询
* @param array $params 请求参数
* @return array ['list' => [...], 'total' => int]
*/
public function execute(array $params)
{
$keywordWords = $this->getArrayParam($params, 'q_word');
$page = $params['pageNumber'] ?? 1;
$pageSize = $params['pageSize'] ?? 10;
$andor = strtoupper($params['andOr'] ?? 'AND');
$orderBy = $this->getArrayParam($params, 'orderBy');
$showField = $params['showField'] ?? 'name';
$keyField = $params['keyField'] ?? '';
$keyValue = $params['keyValue'] ?? null;
$searchField = $this->getArrayParam($params, 'searchField');
$custom = $this->getArrayParam($params, 'custom');
$isTree = (bool)($params['isTree'] ?? 0);
$isHtml = (bool)($params['isHtml'] ?? 0);
// 树形模式强制参数
if ($isTree) {
$keywordWords = [];
$pageSize = 999999;
}
// 验证字段
$this->validateField($showField);
$this->validateField($keyField);
// 验证搜索字段
foreach ($searchField as $f) {
$this->validateField($f);
}
// 验证自定义条件的字段和操作符
$this->validateCustomConditions($custom);
// 构建排序
$order = $this->buildOrder($orderBy);
// 构建查询条件
$where = $this->buildWhere(
$keywordWords,
$andor,
$showField,
$searchField,
$custom,
$keyField,
$keyValue
);
// 执行总数统计
$total = $this->applyDataLimit()
->model->where($where)
->count();
if ($total <= 0) {
return ['list' => [], 'total' => 0];
}
// 排序处理
if ($keyValue !== null && $keyField) {
$this->applyPrimaryKeyOrder($keyField, $keyValue);
} else {
$this->model->order($order);
}
// 执行查询count()会清空options需重新应用dataLimit
$dataList = $this->applyDataLimit()
->model->where($where)
->page($page, $pageSize)
->select();
// 构建结果集
$list = $this->buildResultList($dataList, $showField, $keyField);
// 树形结构处理
if ($isTree && !$keyValue) {
$list = $this->buildTreeList($list, $showField, $isHtml);
}
return ['list' => $list, 'total' => $total];
}
/**
* 标准化字段为数组(支持逗号分隔字符串)
*/
protected function normalizeField($field): array
{
if (is_array($field)) {
return $field;
}
if (is_string($field) && strpos($field, ',') !== false) {
return array_map('trim', explode(',', $field));
}
return $field !== '' ? [$field] : [];
}
/**
* 获取数组参数
*/
protected function getArrayParam(array $params, string $key): array
{
$value = $params[$key] ?? [];
if (is_array($value)) {
return $value;
}
if (is_string($value) && strpos($value, ',') !== false) {
return array_map('trim', explode(',', $value));
}
if ($value === '' || $value === null) {
return [];
}
return [$value];
}
/**
* 验证字段名是否在允许列表中
*/
protected function validateField(string $field)
{
$field = strtolower($field);
if (!in_array($field, $this->allowedFields, true)) {
throw new Exception('Invalid parameters');
}
}
/**
* 验证自定义搜索条件
*/
protected function validateCustomConditions(array $custom)
{
foreach ($custom as $k => $v) {
$field = strtolower($k);
if (!in_array($field, $this->allowedFields, true)) {
throw new Exception('Invalid parameters');
}
// 如果操作符是数组形式传入,校验操作符合法性
if (is_array($v) && count($v) >= 2) {
$operator = strtolower(trim($v[0]));
if (!in_array($operator, self::$allowedOperators, true)) {
throw new Exception('Invalid parameters');
}
}
}
}
/**
* 构建排序
*/
protected function buildOrder(array $orderBy): array
{
$order = [];
foreach ($orderBy as $v) {
if (!isset($v[0], $v[1])) {
continue;
}
$field = strtolower($v[0]);
$direction = strtoupper($v[1]) === 'ASC' ? 'ASC' : 'DESC';
if (in_array($field, $this->orderFields, true)) {
$order[$field] = $direction;
}
}
return $order;
}
/**
* 构建查询条件
*/
protected function buildWhere(
array $keywordWords,
string $andor,
string $showField,
array $searchField,
array $custom,
string $keyField,
$keyValue
)
{
// 如果有 keyValue按主键值精确查询
if ($keyValue !== null && $keyField) {
return [$keyField => ['in', is_array($keyValue) ? $keyValue : explode(',', (string)$keyValue)]];
}
return function ($query) use ($keywordWords, $andor, $showField, $searchField, $custom) {
// 关键词搜索
$searchFields = $this->resolveSearchFields($searchField, $showField, $andor);
$words = array_filter(array_unique($keywordWords));
if (!empty($words)) {
if (count($words) === 1) {
$query->where($searchFields, 'like', '%' . reset($words) . '%');
} else {
$query->where(function ($query) use ($words, $searchFields) {
foreach ($words as $word) {
$query->whereOr($searchFields, 'like', '%' . $word . '%');
}
});
}
}
// 自定义条件
foreach ($custom as $k => $v) {
if (is_array($v) && count($v) >= 2) {
$operator = strtolower(trim($v[0]));
$value = $v[1];
$query->where(strtolower($k), $operator, $value);
} else {
$query->where(strtolower($k), '=', $v);
}
}
};
}
/**
* 解析搜索字段
*/
protected function resolveSearchFields(array $searchField, string $showField, string $andor): string
{
// 过滤掉不在允许列表中的字段
$validFields = [];
$inputFields = array_filter(array_map('trim', $searchField));
foreach ($inputFields as $field) {
$lowerField = strtolower($field);
if (in_array($lowerField, $this->allowedFields, true)) {
$validFields[] = $lowerField;
}
}
if (empty($validFields)) {
$lowerShow = strtolower($showField);
if (in_array($lowerShow, $this->allowedFields, true)) {
return $lowerShow;
}
return 'id';
}
$logic = $andor === 'AND' ? '&' : '|';
return implode($logic, $validFields);
}
/**
* 应用主键排序
*/
protected function applyPrimaryKeyOrder(string $keyField, $keyValue)
{
$values = is_array($keyValue) ? $keyValue : explode(',', (string)$keyValue);
$values = array_unique(array_filter(array_map(function ($v) {
return trim((string)$v);
}, $values)));
if (empty($values)) {
return;
}
$quotedValues = implode(',', array_map(function ($v) {
return Db::quote($v);
}, $values));
$this->model->orderRaw("FIELD(`{$keyField}`, {$quotedValues})");
}
/**
* 构建结果列表
*/
protected function buildResultList($dataList, string $showField, string $keyField): array
{
$list = [];
$fields = $this->resolveSelectpageFields();
foreach ($dataList as $item) {
$row = $item instanceof Model ? $item->toArray() : (array)$item;
// 移除敏感字段
unset($row['password'], $row['salt']);
if ($this->selectpageFields === '*') {
$result = [
$keyField => $row[$keyField] ?? '',
$showField => $row[$showField] ?? '',
];
} else {
$result = array_intersect_key($row, array_flip($fields));
}
// 添加父级ID
$result['pid'] = $row['pid'] ?? ($row['parent_id'] ?? 0);
// HTML 转义
$result = array_map(function ($value) {
return $value === null ? '' : htmlentities((string)$value, ENT_QUOTES, 'UTF-8');
}, $result);
$list[] = $result;
}
return $list;
}
/**
* 构建树形列表
*/
protected function buildTreeList(array $list, string $showField, bool $isHtml): array
{
$tree = Tree::instance();
$tree->init($list, 'pid');
$result = $tree->getTreeList($tree->getTreeArray(0), $showField);
if (!$isHtml) {
foreach ($result as &$item) {
$item = str_replace('&nbsp;', ' ', $item);
}
unset($item);
}
return $result;
}
/**
* 解析 SelectPage 显示字段
*/
protected function resolveSelectpageFields(): array
{
if (is_array($this->selectpageFields)) {
return $this->selectpageFields;
}
if ($this->selectpageFields && $this->selectpageFields !== '*') {
return explode(',', $this->selectpageFields);
}
return [];
}
}

View File

@ -86,6 +86,11 @@ class Upload
*/ */
protected function checkExecutable() protected function checkExecutable()
{ {
//禁止上传以.开头的文件
if (substr($this->fileInfo['name'], 0, 1) === '.') {
throw new UploadException(__('Uploaded file format is limited'));
}
//禁止上传PHP和HTML文件 //禁止上传PHP和HTML文件
if (in_array($this->fileInfo['type'], ['text/x-php', 'text/html']) || in_array($this->fileInfo['suffix'], ['php', 'html', 'htm', 'phar', 'phtml']) || preg_match("/^php(.*)/i", $this->fileInfo['suffix'])) { if (in_array($this->fileInfo['type'], ['text/x-php', 'text/html']) || in_array($this->fileInfo['suffix'], ['php', 'html', 'htm', 'phar', 'phtml']) || preg_match("/^php(.*)/i", $this->fileInfo['suffix'])) {
throw new UploadException(__('Uploaded file format is limited')); throw new UploadException(__('Uploaded file format is limited'));
@ -107,8 +112,7 @@ class Upload
throw new UploadException(__('Uploaded file format is limited')); throw new UploadException(__('Uploaded file format is limited'));
} }
//验证文件后缀 //验证文件后缀
if ($this->config['mimetype'] === '*' if (in_array($this->fileInfo['suffix'], $mimetypeArr) || in_array('.' . $this->fileInfo['suffix'], $mimetypeArr)
|| in_array($this->fileInfo['suffix'], $mimetypeArr) || in_array('.' . $this->fileInfo['suffix'], $mimetypeArr)
|| in_array($typeArr[0] . "/*", $mimetypeArr) || (in_array($this->fileInfo['type'], $mimetypeArr) && stripos($this->fileInfo['type'], '/') !== false)) { || in_array($typeArr[0] . "/*", $mimetypeArr) || (in_array($this->fileInfo['type'], $mimetypeArr) && stripos($this->fileInfo['type'], '/') !== false)) {
return true; return true;
} }

View File

@ -219,7 +219,7 @@ class Config extends Model
} }
file_put_contents( file_put_contents(
CONF_PATH . 'extra' . DS . 'site.php', CONF_PATH . 'extra' . DS . 'site.php',
'<?php' . "\n\nreturn " . var_export_short($config) . ";\n" '<?php' . "\n\nreturn " . var_export($config, true) . ";\n"
); );
return true; return true;
} }

View File

@ -7,6 +7,10 @@ use think\Model;
/** /**
* 会员模型 * 会员模型
* @method static mixed getByUsername($str) 通过用户名查询用户
* @method static mixed getByNickname($str) 通过昵称查询用户
* @method static mixed getByMobile($str) 通过手机查询用户
* @method static mixed getByEmail($str) 通过邮箱查询用户
*/ */
class User extends Model class User extends Model
{ {

View File

@ -9,7 +9,7 @@
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased} *{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
body{padding:70px 50px;background:#f4f6f8;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333} body{padding:70px 50px;background:#f4f6f8;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer} a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
.system-message{margin:20px auto;padding:50px 0px;background:#fff;box-shadow:0 0 30px hsla(0,0%,39%,.06);text-align:center;width:100%;border-radius:2px;} .system-message{margin:20px auto;padding:80px 0px;background:#fff;box-shadow:0 0 30px hsla(0,0%,39%,.06);text-align:center;width:100%;border-radius:10px;}
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:30px} .system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:30px}
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400} .system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
.system-message .jump{font-size:14px} .system-message .jump{font-size:14px}
@ -32,7 +32,7 @@
<div class="image"> <div class="image">
<img src="__CDN__/assets/img/{$codeText}.svg" alt="" width="120" /> <img src="__CDN__/assets/img/{$codeText}.svg" alt="" width="120" />
</div> </div>
<h1>{$msg}</h1> <h1>{$msg|htmlentities}</h1>
{if $url} {if $url}
<p class="jump"> <p class="jump">
{:__('This page will be re-directed in %s seconds', '<span id="wait">' . $wait . '</span>')} {:__('This page will be re-directed in %s seconds', '<span id="wait">' . $wait . '</span>')}
@ -41,18 +41,19 @@
<p class="clearfix"> <p class="clearfix">
<a href="__PUBLIC__" class="btn btn-grey">{:__('Go back')}</a> <a href="__PUBLIC__" class="btn btn-grey">{:__('Go back')}</a>
{if $url} {if $url}
<a href="{$url|htmlentities}" class="btn btn-primary">{:__('Jump now')}</a> <a id="href" href="{$url|htmlentities}" class="btn btn-primary">{:__('Jump now')}</a>
{/if} {/if}
</p> </p>
</div> </div>
{if $url} {if $url}
<script type="text/javascript"> <script type="text/javascript">
(function () { (function () {
var wait = document.getElementById('wait'); var wait = document.getElementById('wait'),
href = document.getElementById('href').href;
var interval = setInterval(function () { var interval = setInterval(function () {
var time = --wait.innerHTML; var time = --wait.innerHTML;
if (time <= 0) { if (time <= 0) {
location.href = "{$url|htmlentities}"; location.href = href;
clearInterval(interval); clearInterval(interval);
} }
}, 1000); }, 1000);
@ -60,4 +61,4 @@
</script> </script>
{/if} {/if}
</body> </body>
</html> </html>

View File

@ -302,7 +302,7 @@ return [
//允许跨域的域名,多个以,分隔 //允许跨域的域名,多个以,分隔
'cors_request_domain' => 'localhost,127.0.0.1', 'cors_request_domain' => 'localhost,127.0.0.1',
//版本号 //版本号
'version' => '1.5.2.20240906', 'version' => '1.6.5.20260602',
//API接口地址 //API接口地址
'api_url' => 'https://api.fastadmin.net', 'api_url' => 'https://api.fastadmin.net',
], ],

View File

@ -20,12 +20,17 @@ return [
'maxsize' => '10mb', 'maxsize' => '10mb',
/** /**
* 可上传的文件类型 * 可上传的文件类型
* 如配置允许 pdf,ppt,docx,svg 等可能含有脚本的文件时,请先从服务器配置此类文件直接下载而不是预览
*/ */
'mimetype' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3,webm', 'mimetype' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3,webm',
/** /**
* 是否支持批量上传 * 是否支持批量上传
*/ */
'multiple' => false, 'multiple' => false,
/**
* 上传超时时长这里仅用于JS上传超时控制
*/
'timeout' => 60000,
/** /**
* 是否支持分片上传 * 是否支持分片上传
*/ */

View File

@ -195,16 +195,22 @@ class User extends Frontend
*/ */
public function logout() public function logout()
{ {
if ($this->request->isPost()) { if ($this->request->isPost()) {
// 加强校验referer是否来自服务器
$referer = $this->request->server('HTTP_REFERER');
if (!$referer || strtolower(parse_url($referer, PHP_URL_HOST)) != strtolower($this->request->host())) {
$this->error(__('Invalid request'));
}
$this->token(); $this->token();
//退出本站 //退出本站
$this->auth->logout(); $this->auth->logout();
$this->success(__('Logout successful'), url('user/index')); $this->success(__('Logout successful'), url('user/index'));
} }
$html = "<form id='logout_submit' name='logout_submit' action='' method='post'>" . token() . "<input type='submit' value='ok' style='display:none;'></form>";
$html .= "<script>document.forms['logout_submit'].submit();</script>";
return $html; $this->view->assign('title', __('Logout'));
return $this->view->fetch();
} }
/** /**

View File

@ -57,14 +57,17 @@ return [
'Change password successful' => '修改密码成功', 'Change password successful' => '修改密码成功',
'Password and confirm password don\'t match' => '两次输入的密码不一致', 'Password and confirm password don\'t match' => '两次输入的密码不一致',
'Captcha is incorrect' => '验证码不正确', 'Captcha is incorrect' => '验证码不正确',
'Please try again after 1 day' => '请于1天后再尝试登录',
'Logged in successful' => '登录成功', 'Logged in successful' => '登录成功',
'Logout successful' => '退出成功', 'Logout successful' => '退出成功',
'User center already closed' => '会员中心已经关闭', 'User center already closed' => '会员中心已经关闭',
'Don\'t have an account? Sign up' => '还没有账号?点击注册', 'Don\'t have an account? Sign up' => '还没有账号?点击注册',
'Already have an account? Sign in' => '已经有账号?点击登录', 'Already have an account? Sign in' => '已经有账号?点击登录',
'Operation failed' => '操作失败', 'Operation failed' => '操作失败',
'Invalid parameters' => '参数不正确', 'Invalid parameters' => '参数不正确',
'Change password failure' => '修改密码失败', 'Change password failure' => '修改密码失败',
'Are you sure you want to sign out?' => '确定要退出登录吗?',
'Confirm sign out' => '确定退出',
'All' => '全部', 'All' => '全部',
'Url' => '物理路径', 'Url' => '物理路径',
'Imagewidth' => '宽度', 'Imagewidth' => '宽度',

View File

@ -1 +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|htmlentities}"></script> <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|htmlentities}"></script>

View File

@ -0,0 +1,17 @@
<div id="content-container" class="container">
<div class="user-section login-section">
<div class="login-main text-center">
<div class="image">
<img src="__CDN__/assets/img/info.svg" alt="" width="100" />
</div>
<h3 class="my-4" style="font-size:16px;">{:__('Are you sure you want to sign out?')}</h3>
<form name="form" id="logout-form" class="form-vertical" method="POST" action="#">
{:token()}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Confirm sign out')}</button>
<button type="button" class="btn btn-default btn-lg btn-block mt-3" onclick="history.back()">{:__('Cancel')}</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -1,34 +0,0 @@
{
"name": "fastadmin",
"description": "the fastest admin framework",
"main": "",
"license": "Apache2.0",
"homepage": "https://www.fastadmin.net",
"private": true,
"dependencies": {
"jquery": "^3.7.0",
"bootstrap": "^3.3.7",
"font-awesome": "^4.6.1",
"bootstrap-table": "fastadmin-bootstraptable#~1.11.5",
"jstree": "~3.3.2",
"moment": "~2.29.0",
"toastr": "~2.1.3",
"eonasdan-bootstrap-datetimepicker": "~4.17.43",
"bootstrap-select": "~1.13.18",
"require-css": "~0.1.8",
"tableExport.jquery.plugin": "~1.10.3",
"jquery-slimscroll": "~1.3.8",
"jquery.cookie": "~1.4.1",
"Sortable": "~1.10.0",
"nice-validator": "karsonzhang/fastadmin-nicevalidator#~1.1.6",
"art-template": "~3.1.3",
"bootstrap-daterangepicker": "~2.1.25",
"fastadmin-citypicker": "~1.3.1",
"fastadmin-cxselect": "~1.4.0",
"fastadmin-dragsort": "~1.0.0",
"fastadmin-addtabs": "~1.0.8",
"fastadmin-selectpage": "~1.0.12",
"fastadmin-layer": "~3.5.1",
"bootstrap-slider": "*"
}
}

View File

@ -1,5 +1,5 @@
{ {
"name": "karsonzhang/fastadmin", "name": "fastadminnet/fastadmin",
"description": "the fastest admin framework", "description": "the fastest admin framework",
"type": "project", "type": "project",
"keywords": [ "keywords": [
@ -21,15 +21,15 @@
"topthink/think-installer": "^1.0.14", "topthink/think-installer": "^1.0.14",
"topthink/think-queue": "1.1.6", "topthink/think-queue": "1.1.6",
"topthink/think-helper": "^1.0.7", "topthink/think-helper": "^1.0.7",
"karsonzhang/fastadmin-addons": "~1.4.0", "fastadminnet/fastadmin-addons": "~1.4.0",
"fastadminnet/fastadmin-mailer": "^2.0.0",
"overtrue/pinyin": "^3.0", "overtrue/pinyin": "^3.0",
"phpoffice/phpspreadsheet": "^1.29.1", "phpoffice/phpspreadsheet": "^1.29.1",
"overtrue/wechat": "^4.6", "overtrue/wechat": "^4.6",
"ext-json": "*", "ext-json": "*",
"ext-curl": "*", "ext-curl": "*",
"ext-pdo": "*", "ext-pdo": "*",
"ext-bcmath": "*", "ext-bcmath": "*"
"txthinking/mailer": "^2.0"
}, },
"config": { "config": {
"preferred-install": "dist", "preferred-install": "dist",

View File

@ -124,7 +124,7 @@ class Date
*/ */
public static function human($remote, $local = null) public static function human($remote, $local = null)
{ {
$time_diff = (is_null($local) || $local ? time() : $local) - $remote; $time_diff = (is_null($local) ? time() : $local) - $remote;
$tense = $time_diff < 0 ? 'after' : 'ago'; $tense = $time_diff < 0 ? 'after' : 'ago';
$time_diff = abs($time_diff); $time_diff = abs($time_diff);
$chunks = [ $chunks = [
@ -146,7 +146,7 @@ class Date
break; break;
} }
} }
return __("%d $name%s $tense", $count, ($count > 1 ? 's' : '')); return __("%d $name%s $tense", [$count, ($count > 1 ? 's' : '')]);
} }
/** /**

View File

@ -14,7 +14,7 @@ class Random
* @param int $len 长度 * @param int $len 长度
* @return string * @return string
*/ */
public static function alnum($len = 6) public static function alnum(int $len = 6): string
{ {
return self::build('alnum', $len); return self::build('alnum', $len);
} }
@ -25,7 +25,7 @@ class Random
* @param int $len 长度 * @param int $len 长度
* @return string * @return string
*/ */
public static function alpha($len = 6) public static function alpha(int $len = 6): string
{ {
return self::build('alpha', $len); return self::build('alpha', $len);
} }
@ -36,7 +36,7 @@ class Random
* @param int $len 长度 * @param int $len 长度
* @return string * @return string
*/ */
public static function numeric($len = 4) public static function numeric(int $len = 4): string
{ {
return self::build('numeric', $len); return self::build('numeric', $len);
} }
@ -47,7 +47,7 @@ class Random
* @param int $len 长度 * @param int $len 长度
* @return string * @return string
*/ */
public static function nozero($len = 4) public static function nozero(int $len = 4): string
{ {
return self::build('nozero', $len); return self::build('nozero', $len);
} }
@ -58,7 +58,7 @@ class Random
* @param int $len 长度 * @param int $len 长度
* @return string * @return string
*/ */
public static function build($type = 'alnum', $len = 8) public static function build(string $type = 'alnum', int $len = 8): string
{ {
switch ($type) { switch ($type) {
case 'alpha': case 'alpha':
@ -93,7 +93,7 @@ class Random
* 获取全球唯一标识 * 获取全球唯一标识
* @return string * @return string
*/ */
public static function uuid() public static function uuid(): string
{ {
return sprintf( return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',

View File

@ -325,7 +325,7 @@ class Tree
'@url' => $childdata || !isset($value['@url']) ? "javascript:;" : $value['@url'], '@url' => $childdata || !isset($value['@url']) ? "javascript:;" : $value['@url'],
'@addtabs' => $childdata || !isset($value['@url']) ? "" : (stripos($value['@url'], "?") !== false ? "&" : "?") . "ref=addtabs", '@addtabs' => $childdata || !isset($value['@url']) ? "" : (stripos($value['@url'], "?") !== false ? "&" : "?") . "ref=addtabs",
'@caret' => ($childdata && (!isset($value['@badge']) || !$value['@badge']) ? '<i class="fa fa-angle-left"></i>' : ''), '@caret' => ($childdata && (!isset($value['@badge']) || !$value['@badge']) ? '<i class="fa fa-angle-left"></i>' : ''),
'@badge' => isset($value['@badge']) ? $value['@badge'] : '', '@badge' => $value['@badge'] ?? '',
'@class' => ($selected ? ' active' : '') . ($disabled ? ' disabled' : '') . ($childdata ? ' treeview' . (config('fastadmin.show_submenu') ? ' treeview-open' : '') : ''), '@class' => ($selected ? ' active' : '') . ($disabled ? ' disabled' : '') . ($childdata ? ' treeview' . (config('fastadmin.show_submenu') ? ' treeview-open' : '') : ''),
); );
$str .= strtr($nstr, $value); $str .= strtr($nstr, $value);
@ -422,7 +422,7 @@ class Tree
{ {
$arr = []; $arr = [];
foreach ($data as $k => $v) { foreach ($data as $k => $v) {
$childlist = isset($v['childlist']) ? $v['childlist'] : []; $childlist = $v['childlist'] ?? [];
unset($v['childlist']); unset($v['childlist']);
$v[$field] = $v['spacer'] . ' ' . $v[$field]; $v[$field] = $v['spacer'] . ' ' . $v[$field];
$v['haschild'] = $childlist ? 1 : 0; $v['haschild'] = $childlist ? 1 : 0;

3190
package-lock.json generated 100644

File diff suppressed because it is too large Load Diff

109
package.json 100644
View File

@ -0,0 +1,109 @@
{
"name": "fastadmin",
"version": "1.6.1",
"description": "FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。",
"scripts": {
"build": "grunt"
},
"repository": {
"type": "git",
"url": "git@gitee.com:karson/fastadmin.git"
},
"dependencies": {
"bootstrap": "npm:fastadmin-bootstrap@^3.4.1",
"bootstrap-daterangepicker": "~2.1.25",
"bootstrap-select": "^1.13.18",
"bootstrap-slider": "^11.0.2",
"eonasdan-bootstrap-datetimepicker": "^4.17.49",
"fastadmin-addtabs": "^1.0.8",
"fastadmin-arttemplate": "^3.1.4",
"fastadmin-bootstraptable": "^1.11.12",
"fastadmin-citypicker": "^1.3.6",
"fastadmin-cxselect": "^1.4.0",
"fastadmin-dragsort": "^1.0.5",
"fastadmin-layer": "^3.5.6",
"fastadmin-selectpage": "^1.1.1",
"fastadmin-nicevalidator": "^1.1.6",
"art-template": "npm:fastadmin-arttemplate@^3.1.4",
"bootstrap-table": "npm:fastadmin-bootstraptable@^1.11.12",
"nice-validator": "npm:fastadmin-nicevalidator@^1.1.6",
"font-awesome": "^4.6.1",
"jquery": "^3.7.1",
"jquery-slimscroll": "~1.3.8",
"jquery.cookie": "~1.4.1",
"jstree": "~3.3.2",
"moment": "^2.10",
"require-css": "~0.1.8",
"sortablejs": "^1.12.0",
"tableexport.jquery.plugin": "^1.20.0",
"toastr": "~2.1.3"
},
"author": "FastAdmin",
"license": "Apache-2.0",
"devDependencies": {
"grunt": "^1.5.3",
"grunt-contrib-clean": "^2.0.1",
"grunt-contrib-copy": "^1.0.0",
"jsonminify": "^0.4.2",
"parse-config-file": "^1.0.4"
},
"overrides": {
"canvg": {
"xmldom": "^0.7.0"
},
"tableexport.jquery.plugin": {
"xlsx": "npm:@e965/xlsx@^0.20.3"
},
"eonasdan-bootstrap-datetimepicker": {
"moment-timezone": "^0.5.35"
}
},
"dists": {
"art-template": "dist/**",
"bootstrap": "dist/**",
"bootstrap-daterangepicker": [
"daterangepicker.js",
"daterangepicker.css"
],
"bootstrap-select": "dist/**",
"bootstrap-slider": [
"dist/**",
"*.css",
"*.js"
],
"coloris": [
"dist/umd/**",
"dist/*.css"
],
"eonasdan-bootstrap-datetimepicker": "build/**",
"fastadmin-addtabs": "*.js",
"fastadmin-bootstraptable": "dist/**",
"fastadmin-citypicker": "dist/**",
"fastadmin-cxselect": "js/**",
"fastadmin-dragsort": "*.js",
"fastadmin-layer": "dist/**",
"fastadmin-selectpage": "*",
"font-awesome": [
"css/**",
"fonts/**"
],
"jquery": "dist/**",
"jquery-slimscroll": "*.js",
"jquery.cookie": "*.js",
"jstree": "dist/**",
"moment": [
"moment.js",
"locale/**"
],
"nice-validator": "dist/**",
"require-css": "*.js",
"sortablejs": "*.js",
"tableexport.jquery.plugin": "tableExport.min.js",
"toastr": [
"*.less",
"*.css",
"*.js",
"build/**"
]
}
}

View File

@ -3,7 +3,7 @@
@import url("../css/skins/skin-black-blue.css"); @import url("../css/skins/skin-black-blue.css");
@import url("../css/iconfont.css"); @import url("../css/iconfont.css");
@import url("../libs/font-awesome/css/font-awesome.min.css"); @import url("../libs/font-awesome/css/font-awesome.min.css");
@import url("../libs/toastr/toastr.min.css"); @import url("../libs/toastr/build/toastr.min.css");
@import url("../libs/fastadmin-layer/dist/theme/default/layer.css"); @import url("../libs/fastadmin-layer/dist/theme/default/layer.css");
@import url("../libs/bootstrap-table/dist/bootstrap-table.min.css"); @import url("../libs/bootstrap-table/dist/bootstrap-table.min.css");
@import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"); @import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css");
@ -11,7 +11,7 @@
@import url("../libs/nice-validator/dist/jquery.validator.css"); @import url("../libs/nice-validator/dist/jquery.validator.css");
@import url("../libs/bootstrap-select/dist/css/bootstrap-select.min.css"); @import url("../libs/bootstrap-select/dist/css/bootstrap-select.min.css");
@import url("../libs/fastadmin-selectpage/selectpage.css"); @import url("../libs/fastadmin-selectpage/selectpage.css");
@import url("../libs/bootstrap-slider/slider.css"); @import url("../libs/bootstrap-slider/dist/css/bootstrap-slider.css");
.m-0 { .m-0 {
margin-top: 0px !important; margin-top: 0px !important;
margin-right: 0px !important; margin-right: 0px !important;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -165,7 +165,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'cookie']
title: __('Operate'), title: __('Operate'),
table: table, table: table,
formatter: Controller.api.formatter.operate, formatter: Controller.api.formatter.operate,
align: 'right' align: 'right',
cellStyle: function (value, row, index) {
return {css: {'min-width': '158px'}};
}
}, },
] ]
], ],
@ -238,6 +241,27 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'cookie']
Layer.close(index); Layer.close(index);
}); });
return false; return false;
} else if (ret && ret.code === -3) {
//插件目录发现影响全局的文件
Layer.open({
content: Template("conflicttpl", ret.data),
shade: 0.8,
area: area,
title: __('Warning'),
btn: [__('Continue install'), __('Cancel')],
end: function () {
},
yes: function (index) {
up.removeFile(file);
file.force = true;
up.uploadFile(file);
Layer.close(index);
}
});
} else {
Layer.alert(ret.msg, {title: __('Warning'), icon: 0});
} }
}); });
@ -480,7 +504,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'cookie']
//如果登录已经超时,重新提醒登录 //如果登录已经超时,重新提醒登录
if (uid && uid != ret.data.uid) { if (uid && uid != ret.data.uid) {
Controller.api.userinfo.set(null); Controller.api.userinfo.set(null);
$(".operate[data-name='" + name + "'] .btn-install").trigger("click"); $(".operate[data-name='" + name + "'] .btn-install:first").trigger("click");
return; return;
} }
top.Fast.api.open(ret.data.payurl, __('Pay now'), { top.Fast.api.open(ret.data.payurl, __('Pay now'), {

View File

@ -20,7 +20,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
table.bootstrapTable({ table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
sortName: '', sortName: '',
escape: false, escape: true,
columns: [ columns: [
[ [
{field: 'state', checkbox: true,}, {field: 'state', checkbox: true,},
@ -180,7 +180,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
var iconfunc = function () { var iconfunc = function () {
Layer.open({ Layer.open({
type: 1, type: 1,
area: ['99%', '98%'], //宽高 area: ['80%', '80%'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist}) content: Template('chooseicontpl', {iconlist: iconlist})
}); });
}; };
@ -192,8 +192,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
}); });
$(document).on('click', ".btn-search-icon", function () { $(document).on('click', ".btn-search-icon", function () {
if (iconlist.length == 0) { if (iconlist.length == 0) {
$.get(Config.site.cdnurl + "/assets/libs/font-awesome/less/variables.less", function (ret) { $.get(Config.site.cdnurl + "/assets/libs/font-awesome/css/font-awesome.css", function (ret) {
var exp = /fa-var-(.*):/ig; var exp = /fa-(.*):before/ig;
var result; var result;
while ((result = exp.exec(ret)) != null) { while ((result = exp.exec(ret)) != null) {
iconlist.push(result[1]); iconlist.push(result[1]);

View File

@ -167,7 +167,7 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
{ {
field: 'operate', title: __('Operate'), width: 85, events: { field: 'operate', title: __('Operate'), width: 85, events: {
'click .btn-chooseone': function (e, value, row, index) { 'click .btn-chooseone': function (e, value, row, index) {
Fast.api.close({url: row.url, multiple: multiple}); Fast.api.close($.extend({multiple: multiple}, row));
}, },
}, formatter: function () { }, formatter: function () {
return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>'; return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>';

View File

@ -333,7 +333,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
// 切换菜单栏 // 切换菜单栏
$(document).on("click", ".sidebar-toggle", function () { $(document).on("click", ".sidebar-toggle", function () {
setTimeout(function(){ setTimeout(function () {
var value = $("body").hasClass("sidebar-collapse") ? 1 : 0; var value = $("body").hasClass("sidebar-collapse") ? 1 : 0;
setTimeout(function () { setTimeout(function () {
$(window).trigger("resize"); $(window).trigger("resize");
@ -381,6 +381,24 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
} }
}); });
$(document).on("click", "a[href*='index/logout']", function () {
var that = this;
$.ajax({
type: 'GET', dataType: 'html', url: $(that).attr("href"),
success: function (data, status, xhr) {
Fast.api.ajax({url: $(that).attr("href"), loading: false, data: {__token__: xhr.getResponseHeader('__token__')}}, function (data, ret) {
Layer.msg(ret.msg, {icon: 1, time: 1500}, function () {
location.reload();
});
return false;
});
}, error: function (xhr, type) {
Layer.msg(__('Network error'), {icon: 2});
}
});
return false;
});
$(window).resize(); $(window).resize();
}, },

View File

@ -21,7 +21,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id', pk: 'id',
sortName: 'weigh', sortName: 'weigh',
escape: false, escape: true,
columns: [ columns: [
[ [
{checkbox: true}, {checkbox: true},

View File

@ -21,6 +21,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id', pk: 'id',
sortName: 'user.id', sortName: 'user.id',
fixedColumns: true,
fixedRightNumber: 1,
columns: [ columns: [
[ [
{checkbox: true}, {checkbox: true},

View File

@ -157,7 +157,7 @@
} else { } else {
key = isArray ? value : key; key = isArray ? value : key;
} }
optionList.push(sprintf("<option value='" + key + "' %s>" + value + "</option>", key == vObjCol.defaultValue ? 'selected' : '')); optionList.push(sprintf("<option value='" + Fast.api.escape(key) + "' %s>" + Fast.api.escape(value) + "</option>", key == vObjCol.defaultValue ? 'selected' : ''));
}); });
return optionList; return optionList;
}; };
@ -208,7 +208,7 @@
} else { } else {
value = process ? process(obj.val()) : obj.val(); value = process ? process(obj.val()) : obj.val();
} }
if (removeempty && (value == '' || value == null || ($.isArray(value) && value.length == 0)) && !sym.match(/null/i)) { if (removeempty && (value === '' || value == null || ($.isArray(value) && value.length === 0)) && !sym.match(/null/i)) {
return true; return true;
} }
@ -268,7 +268,7 @@
return "Common search"; return "Common search";
}, },
formatCommonSubmitButton: function () { formatCommonSubmitButton: function () {
return "Submit"; return "Search";
}, },
formatCommonResetButton: function () { formatCommonResetButton: function () {
return "Reset"; return "Reset";

View File

@ -4,7 +4,7 @@
* @author: karson * @author: karson
* @version: v0.0.1 * @version: v0.0.1
* *
* @update 2017-06-24 <http://github.com/karsonzhang/fastadmin> * @update 2017-06-24 <http://github.com/fastadminnet/fastadmin>
*/ */
!function ($) { !function ($) {

View File

@ -100,6 +100,24 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
$(document).on("click", ".sidebar-toggle", function () { $(document).on("click", ".sidebar-toggle", function () {
$("body").toggleClass("sidebar-open"); $("body").toggleClass("sidebar-open");
}); });
$(document).on("click", "a[href*='user/logout']", function () {
var that = this;
$.ajax({
type: 'GET', dataType: 'html', url: $(that).attr("href"),
success: function (data, status, xhr) {
Fast.api.ajax({url: $(that).attr("href"), loading:false, data: {__token__: xhr.getResponseHeader('__token__')}}, function (data, ret) {
Layer.msg(ret.msg, {icon: 1, time: 1500}, function () {
location.reload();
});
return false;
});
}, error: function (xhr, type) {
Layer.msg(__('Network error'), {icon: 2});
}
});
return false;
});
} }
}; };
Frontend.api = $.extend(Fast.api, Frontend.api); Frontend.api = $.extend(Fast.api, Frontend.api);

File diff suppressed because one or more lines are too long

View File

@ -102,6 +102,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
//绑定select元素事件 //绑定select元素事件
if ($(".selectpicker", form).length > 0) { if ($(".selectpicker", form).length > 0) {
require(['bootstrap-select', 'bootstrap-select-lang'], function () { require(['bootstrap-select', 'bootstrap-select-lang'], function () {
$.fn.selectpicker.Constructor.BootstrapVersion = '3';
$('.selectpicker', form).selectpicker(); $('.selectpicker', form).selectpicker();
$(form).on("reset", function () { $(form).on("reset", function () {
setTimeout(function () { setTimeout(function () {
@ -218,7 +219,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
}; };
var origincallback = function (start, end) { var origincallback = function (start, end) {
$(this.element).val(start.format(this.locale.format) + " - " + end.format(this.locale.format)); $(this.element).val(start.format(this.locale.format) + " - " + end.format(this.locale.format));
$(this.element).trigger('change'); $(this.element).trigger('change').trigger('validate');
}; };
$(".datetimerange", form).each(function () { $(".datetimerange", form).each(function () {
var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback; var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback;
@ -226,7 +227,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
callback.call(picker, picker.startDate, picker.endDate); callback.call(picker, picker.startDate, picker.endDate);
}); });
$(this).on('cancel.daterangepicker', function (ev, picker) { $(this).on('cancel.daterangepicker', function (ev, picker) {
$(this).val('').trigger('change'); $(this).val('').trigger('change').trigger('validate');
}); });
$(this).daterangepicker($.extend(true, {}, options, $(this).data() || {}, $(this).data("daterangepicker-options") || {})); $(this).daterangepicker($.extend(true, {}, options, $(this).data() || {}, $(this).data("daterangepicker-options") || {}));
}); });
@ -294,6 +295,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
var url = Config.upload.fullmode ? Fast.api.cdnurl(data.url) : data.url; var url = Config.upload.fullmode ? Fast.api.cdnurl(data.url) : data.url;
$("#" + input_id).val(url).trigger("change").trigger("validate"); $("#" + input_id).val(url).trigger("change").trigger("validate");
} }
// 触发选择文件自定义事件
button.trigger("fa.event.selectedfile", data);
} }
}); });
return false; return false;
@ -567,7 +571,9 @@ define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], functio
} }
}; };
// @formatter:on // @formatter:on
var $disabledElements = form.find(':disabled').removeAttr('disabled');
var dataArr = form.serializeArray(), dataObj = {}, fieldName, fieldValue; var dataArr = form.serializeArray(), dataObj = {}, fieldName, fieldValue;
$disabledElements.attr('disabled', 'disabled');
$(dataArr).each(function (i, field) { $(dataArr).each(function (i, field) {
fieldName = field.name; fieldName = field.name;
fieldValue = field.value; fieldValue = field.value;

File diff suppressed because one or more lines are too long

View File

@ -131,7 +131,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
return __('Common search'); return __('Common search');
}, },
formatCommonSubmitButton: function () { formatCommonSubmitButton: function () {
return __('Submit'); return __('Search');
}, },
formatCommonResetButton: function () { formatCommonResetButton: function () {
return __('Reset'); return __('Reset');
@ -764,7 +764,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
suffix = /[\.]?([a-zA-Z0-9]+)$/.exec(value); suffix = /[\.]?([a-zA-Z0-9]+)$/.exec(value);
suffix = suffix ? suffix[1] : 'file'; suffix = suffix ? suffix[1] : 'file';
url = Fast.api.fixurl("ajax/icon?suffix=" + suffix); url = Fast.api.fixurl("ajax/icon?suffix=" + suffix);
html.push('<a href="' + value + '" target="_blank"><img src="' + url + '" class="' + classname + '"></a>'); html.push('<a href="' + value + '" target="_blank"><img src="' + url + '" class="' + classname + '" width="30" height="30"></a>');
}); });
return html.join(' '); return html.join(' ');
}, },
@ -788,6 +788,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
if (typeof this.custom !== 'undefined') { if (typeof this.custom !== 'undefined') {
custom = $.extend(custom, this.custom); custom = $.extend(custom, this.custom);
} }
value = row[this.field] || value;
value = value == null || value.length === 0 ? '' : value.toString(); value = value == null || value.length === 0 ? '' : value.toString();
var keys = typeof this.searchList === 'object' ? Object.keys(this.searchList) : []; var keys = typeof this.searchList === 'object' ? Object.keys(this.searchList) : [];
var index = keys.indexOf(value); var index = keys.indexOf(value);
@ -800,6 +801,8 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
if (!display) { if (!display) {
display = __(value.charAt(0).toUpperCase() + value.slice(1)); display = __(value.charAt(0).toUpperCase() + value.slice(1));
} }
value = Fast.api.escape(value);
display = Fast.api.escape(display);
var html = '<span class="text-' + color + '">' + (icon ? '<i class="' + icon + '"></i> ' : '') + display + '</span>'; var html = '<span class="text-' + color + '">' + (icon ? '<i class="' + icon + '"></i> ' : '') + display + '</span>';
if (this.operate != false) { if (this.operate != false) {
html = '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', display) + '" data-field="' + this.field + '" data-value="' + value + '">' + html + '</a>'; html = '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', display) + '" data-field="' + this.field + '" data-value="' + value + '">' + html + '</a>';
@ -866,6 +869,15 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
value = Fast.api.escape(customValue); value = Fast.api.escape(customValue);
field = this.customField; field = this.customField;
} }
if (typeof that.searchList === 'object' && typeof that.searchList.then === 'function') {
$.when(that.searchList).done(function (ret) {
if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
that.searchList = ret.data.searchlist;
} else if (ret.constructor === Array || ret.constructor === Object) {
that.searchList = ret;
}
})
}
if (typeof that.searchList === 'object' && typeof that.custom === 'undefined') { if (typeof that.searchList === 'object' && typeof that.custom === 'undefined') {
var i = 0; var i = 0;
var searchValues = Object.values(colorArr); var searchValues = Object.values(colorArr);
@ -879,14 +891,16 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
//渲染Flag //渲染Flag
var html = []; var html = [];
var arr = value != '' ? value.split(',') : []; var arr = $.isArray(value) ? value : value != '' ? value.split(',') : [];
var color, display, label; var color, display, label;
$.each(arr, function (i, value) { $.each(arr, function (i, value) {
value = value == null || value.length === 0 ? '' : value.toString(); value = value == null || value.length === 0 ? '' : value.toString();
if (value == '') if (value === '')
return true; return true;
color = value && typeof colorArr[value] !== 'undefined' ? colorArr[value] : 'primary'; color = value && typeof colorArr[value] !== 'undefined' ? colorArr[value] : 'primary';
display = typeof that.searchList !== 'undefined' && typeof that.searchList[value] !== 'undefined' ? that.searchList[value] : __(value.charAt(0).toUpperCase() + value.slice(1)); display = typeof that.searchList !== 'undefined' && typeof that.searchList[value] !== 'undefined' ? that.searchList[value] : __(value.charAt(0).toUpperCase() + value.slice(1));
value = Fast.api.escape(value);
display = Fast.api.escape(display);
label = '<span class="label label-' + color + '">' + display + '</span>'; label = '<span class="label label-' + color + '">' + display + '</span>';
if (that.operate) { if (that.operate) {
html.push('<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', display) + '" data-field="' + field + '" data-value="' + value + '">' + label + '</a>'); html.push('<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', display) + '" data-field="' + field + '" data-value="' + value + '">' + label + '</a>');

View File

@ -1,5 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4 /** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.3.2 Copyright jQuery Foundation and other contributors. * @license RequireJS 2.3.7 Copyright jQuery Foundation and other contributors.
* Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
*/ */
//Not using strict: uneven strict support in browsers, #392, and causes //Not using strict: uneven strict support in browsers, #392, and causes
@ -11,7 +11,7 @@ var requirejs, require, define;
(function (global, setTimeout) { (function (global, setTimeout) {
var req, s, head, baseElement, dataMain, src, var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath, interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.3.2', version = '2.3.7',
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg, commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/, jsSuffixRegExp = /\.js$/,
@ -33,7 +33,8 @@ var requirejs, require, define;
contexts = {}, contexts = {},
cfg = {}, cfg = {},
globalDefQueue = [], globalDefQueue = [],
useInteractive = false; useInteractive = false,
disallowedProps = ['__proto__', 'constructor'];
//Could match something like ')//comment', do not lose the prefix to comment. //Could match something like ')//comment', do not lose the prefix to comment.
function commentReplace(match, singlePrefix) { function commentReplace(match, singlePrefix) {
@ -94,7 +95,7 @@ var requirejs, require, define;
function eachProp(obj, func) { function eachProp(obj, func) {
var prop; var prop;
for (prop in obj) { for (prop in obj) {
if (hasProp(obj, prop)) { if (hasProp(obj, prop) && disallowedProps.indexOf(prop) == -1) {
if (func(obj[prop], prop)) { if (func(obj[prop], prop)) {
break; break;
} }
@ -165,7 +166,7 @@ var requirejs, require, define;
* @returns {Error} * @returns {Error}
*/ */
function makeError(id, msg, err, requireModules) { function makeError(id, msg, err, requireModules) {
var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); var e = new Error(msg + '\nhttps://requirejs.org/docs/errors.html#' + id);
e.requireType = id; e.requireType = id;
e.requireModules = requireModules; e.requireModules = requireModules;
if (err) { if (err) {
@ -440,7 +441,9 @@ var requirejs, require, define;
//Account for relative paths if there is a base name. //Account for relative paths if there is a base name.
if (name) { if (name) {
if (prefix) { if (prefix) {
if (pluginModule && pluginModule.normalize) { if (isNormalized) {
normalizedName = name;
} else if (pluginModule && pluginModule.normalize) {
//Plugin is loaded, use its normalize method. //Plugin is loaded, use its normalize method.
normalizedName = pluginModule.normalize(name, function (name) { normalizedName = pluginModule.normalize(name, function (name) {
return normalize(name, parentName, applyMap); return normalize(name, parentName, applyMap);
@ -972,7 +975,8 @@ var requirejs, require, define;
//prefix and name should already be normalized, no need //prefix and name should already be normalized, no need
//for applying map config again either. //for applying map config again either.
normalizedMap = makeModuleMap(map.prefix + '!' + name, normalizedMap = makeModuleMap(map.prefix + '!' + name,
this.map.parentMap); this.map.parentMap,
true);
on(normalizedMap, on(normalizedMap,
'defined', bind(this, function (value) { 'defined', bind(this, function (value) {
this.map.normalizedMap = normalizedMap; this.map.normalizedMap = normalizedMap;

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
@import url("../css/skins/skin-black-blue.css"); @import url("../css/skins/skin-black-blue.css");
@import url("../css/iconfont.css"); @import url("../css/iconfont.css");
@import url("../libs/font-awesome/css/font-awesome.min.css"); @import url("../libs/font-awesome/css/font-awesome.min.css");
@import url("../libs/toastr/toastr.min.css"); @import url("../libs/toastr/build/toastr.min.css");
@import url("../libs/fastadmin-layer/dist/theme/default/layer.css"); @import url("../libs/fastadmin-layer/dist/theme/default/layer.css");
@import url("../libs/bootstrap-table/dist/bootstrap-table.min.css"); @import url("../libs/bootstrap-table/dist/bootstrap-table.min.css");
@import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"); @import url("../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css");
@ -16,7 +16,7 @@
@import url("../libs/nice-validator/dist/jquery.validator.css"); @import url("../libs/nice-validator/dist/jquery.validator.css");
@import url("../libs/bootstrap-select/dist/css/bootstrap-select.min.css"); @import url("../libs/bootstrap-select/dist/css/bootstrap-select.min.css");
@import url("../libs/fastadmin-selectpage/selectpage.css"); @import url("../libs/fastadmin-selectpage/selectpage.css");
@import url("../libs/bootstrap-slider/slider.css"); @import url("../libs/bootstrap-slider/dist/css/bootstrap-slider.css");
@import "tinycss.less"; @import "tinycss.less";
@main-bg: #f1f4f6; @main-bg: #f1f4f6;