Compare commits

..

573 Commits

Author SHA1 Message Date
Karson c74b9dc24a 修复会员表结构字段
优化版本依赖
2024-09-06 11:05:48 +08:00
Karson 5188621e9c 优化语言包加载 2024-09-04 12:10:37 +08:00
Karson 7238632f14 更新版本号 2024-09-03 17:51:45 +08:00
Karson 4329b47c56 更新phpoffice/phpspreadsheet依赖版本 2024-09-03 17:48:46 +08:00
Karson 418d93f448 打包JS 2024-09-03 15:24:23 +08:00
Karson 8e88e1c9dc 优化格式化输出时文本编码
# Conflicts:
#	public/assets/js/require-table.js
2024-09-03 15:21:22 +08:00
Karson 592a42fcc5 优化后台参数传递 2024-09-03 15:17:29 +08:00
Simon a532001e7b 修复添加时,权重传值不生效 2024-09-03 15:15:44 +08:00
苏小马 9876dc22db update application/admin/command/Crud.php.
问题:删除模式时不需要强制读取数据表,如果在删除前已手动删除数据表,将抛出异常“table not found”导致删除失败

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

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

Signed-off-by: AriFe.Liu <88468560@qq.com>
2024-09-03 15:14:52 +08:00
AriFe.Liu 5c9c6ef89c 修复附件选择组件因没有id导致无法响应事件的bug
该问题曾导致附件选择组件在没有添加ID时造成无法正常响应回调事件
官方文档: https://doc.fastadmin.net/doc/183.html 附件选择 中, 示例及文档均未提及添加了faselect的组件必须添加id
如非bug而有意为之, 请修改官方文档说明, 告知用户添加了faselect的标签必须同时添加ID才能正确处理回调.
2024-09-03 15:14:52 +08:00
Karson 03ccce86f0 修复autocomplete选中后未触发验证的问题
修复Table.api.formatter.file无法渲染的问题
2024-09-03 15:10:11 +08:00
小和 18a661fb22 !465 修改字段错误问题
* 修复字段错误
2024-09-03 15:09:46 +08:00
AriFe.Liu c01628a914 修复sidebar左侧菜单因大小写问题导致的菜单列表不能正确显示问题
当手动添加菜单规则时, 规则字段未提示和处理用户录入的字符
在application/admin/library/Auth.php -> getSidebar方法中, 会对当前用户所拥有的权限节点做校验移除不相关的权限
当判断当前菜单规则是否在$userRule中时, 原本的$v['name']为直接从数据库中取出未做处理, $userRule则是通过$this->getRuleList方法获取, 方法内已经对字符串做了转小写处理, 假如用户填写了大小写混合的规则, 则此处将会被错误的移除掉; 导致左侧菜单无法正常展示该菜单规则;

Signed-off-by: AriFe.Liu <88468560@qq.com>
2024-09-03 15:08:20 +08:00
Karson 996fa27d62 优化数据表结构 2024-09-03 15:05:53 +08:00
Karson b13a1ca7b5 优化冗余参数 2024-09-03 10:53:19 +08:00
Karson c78b3aecc5 优化API资源URL 2024-09-03 10:53:19 +08:00
Karson 54d6e0904b 优化安装脚本资源加载 2024-09-03 10:53:19 +08:00
Karson 6d4aaf5ea8 优化邮箱验证码发送参数验证
# Conflicts:
#	application/api/controller/Ems.php
2024-09-03 10:50:29 +08:00
Karson 4a97bdaf19 Merge branch '1.x' of gitee.com:karson/fastadmin into 1.x 2024-09-03 10:28:37 +08:00
Karson 028a0b5f22 Fieldlist新增使用数组保存和保留空数据选项 2024-09-03 10:27:56 +08:00
Karson 7f54960449 优化PHP版本依赖 2024-09-03 10:27:24 +08:00
Karson e7c1922cf3 优化前台会员登录 2024-09-03 10:23:19 +08:00
Karson c5285b8fdd 优化多语言加载 2024-09-03 10:22:34 +08:00
Karson 5400c6ff2a 优化视图变量输出 2024-09-03 10:20:59 +08:00
建伟F4nniu 090381a1a2
!462 按照注释规则修改API模块下控制器方法的注解
Merge pull request !462 from Henry/fix_phpdoc
2024-07-03 08:03:46 +00:00
Karson 8f7a55928c 修复列表多个分组按钮显示优化 2024-04-01 15:08:03 +08:00
Karson e8a804afad 优化后台编辑默认加载模型 2024-03-28 12:03:14 +08:00
Karson 26a5ca4a2c 修改install.sql默认数据 2024-03-28 11:56:50 +08:00
Karson f932156c8e 修改默认配置 2024-03-28 11:55:34 +08:00
Karson 77c386ed47 打包新版本JS和CSS 2024-03-28 11:47:38 +08:00
Karson 57da65acd0 更新版本号 2024-03-28 11:25:20 +08:00
Karson 6dd941e168 表格导出新增提示文本 2024-03-28 11:16:38 +08:00
Karson b7eef593a3 优化插件配置分组
优化版本依赖
2024-03-28 09:58:30 +08:00
Karson 2b14bc4e2b 优化fa_test表测试数据 2024-03-28 09:42:20 +08:00
Karson 5e7d398b49 优化nice-validator依赖 2024-03-27 21:59:07 +08:00
Karson 58035763ea 优化本地安装点击事件判断 2024-03-27 20:17:41 +08:00
Karson 7c9841cee9 新增html转义函数
优化插件管理标题和描述
2024-03-27 17:40:08 +08:00
Karson a5e1fe9cb6 优化Http多维数组参数传递 2024-03-27 16:11:15 +08:00
Karson 1a31ac2dc9 新增无键名数组CRUD生成
优化注释判断
2024-03-27 15:09:05 +08:00
Karson 56b33f1514 移除冗余代码 2024-03-27 11:48:32 +08:00
Karson c5d26b7f3a 新增插件配置switch支持
优化默认SQL
2024-03-27 11:11:59 +08:00
Karson de002debd7 修改默认请求超时时长 2024-03-26 18:11:20 +08:00
Karson d1c240bd91 新增插件管理本地安装升级和版本检测
优化前台
优化fieldlist组件
优化上传组件传递参数
优化composer依赖
2024-03-26 17:51:30 +08:00
Karson e45b435b48 修复列表显示全部时选择卡切换问题 2024-03-26 09:48:43 +08:00
Karson aec4efe9e0 优化代码 2024-03-25 22:29:48 +08:00
Karson 0a5484b738 优化代码 2024-03-25 22:29:23 +08:00
Karson 9f2c08414a 优化后台管理日志记录 2024-03-25 22:28:43 +08:00
Karson 448eaad5f5 优化CRUD生成
优化代码
2024-03-25 15:26:58 +08:00
Karson 578044505a 移除JSONP加载 2024-03-25 14:58:39 +08:00
Karson 36bf77df6c 移除API基类自动判断JSONP的支持 2024-03-23 18:21:20 +08:00
Karson bac6606786 修复datetimerange组件自定义配置覆盖的问题 2024-03-14 20:11:31 +08:00
Karson 131ef803d1 修复后台修改个人资料导致退出的问题 2024-03-14 19:52:35 +08:00
Karson 17eb182063 修复超级管理员隐藏的组别不显示的问题 2024-03-14 19:44:35 +08:00
Karson f7e47d90f1 修复slider重复渲染时的问题 2024-03-14 18:56:17 +08:00
Karson a9a6065fde Merge branch '1.x' of gitee.com:karson/fastadmin into 1.x 2024-02-28 12:00:44 +08:00
Karson 6a94a07903 修复favisible中selectpage验证失效的问题
优化通用搜索
2024-02-28 12:00:37 +08:00
Karson 5bf63c557b 优化插件卸载 2024-02-28 12:00:04 +08:00
Karson 5d3d667143 修复分页选中all后刷新问题 2024-02-28 11:59:26 +08:00
Karson 8a0e8b1d3b 优化代码 2024-02-28 11:59:00 +08:00
Henry ee0be09841 style: 去掉多余的空格 2024-02-26 22:34:06 +08:00
Henry c8c1573c27 docs: 按照注释规则修改API模块下控制器方法的注解 2024-02-26 22:22:59 +08:00
F4nniu 76abb2dcd7 docs: 更新年份 2024-02-17 14:59:02 +08:00
F4nniu (FastAdmin开源框架) 787334972e
!460 fix: 优化 v1.x 对 php8 的兼容
Merge pull request !460 from F4nniu (FastAdmin开源框架)/php8_compatibily
2024-02-16 06:19:27 +00:00
F4nniu 1c7d0b710e nelexa zip 组件以 fastadmin-addons 组件中的依赖为准
(cherry picked from commit db487a52df)
2024-02-15 15:48:11 +08:00
F4nniu b0a3851d93 fix(common): getEncryptedToken 的 php8 兼容修复
(cherry picked from commit 198604c584)
2024-02-15 13:58:13 +08:00
F4nniu 2e4fe16f44 修复 select 生成在 php8 环境中的报错
(cherry picked from commit 7fe625cf5b)
2024-02-15 13:57:59 +08:00
F4nniu e3779a1f05 让 IDE 提示友好
(cherry picked from commit dd63aa5948)
2024-02-15 13:57:44 +08:00
F4nniu d8acbf8abe 使用框架 get 自带的过滤参数
(cherry picked from commit 85271d1cf7)
2024-02-15 13:57:36 +08:00
F4nniu e76eba0c21 优化 php8 兼容
(cherry picked from commit a64cf1173f)
2024-02-15 13:57:22 +08:00
F4nniu 7b66d0bf58 captcha 为了兼容 php8
(cherry picked from commit 927510f5ad)
2024-02-15 13:57:09 +08:00
F4nniu bb68eb4254 修复显示本地插件列表时的 null 值报错
(cherry picked from commit c7da57a109)
2024-02-15 13:56:58 +08:00
liuan 879554d5a8 fix(Lang): 修复后台登录时用户名和密码只有英文提示的问题 2024-02-13 16:27:59 +08:00
lande 403c6a2a7d 修复api上传文件时,最大上传文件报错,不显示语言包的提示语的bug
(cherry picked from commit d5b07d49cb)
2024-02-12 21:27:06 +08:00
Karson 42e91e10e6 优化菜单搜索结果点击 2024-01-26 16:34:13 +08:00
Karson 22628fca0e fieldlist组件一维数组支持 2023-12-27 14:38:17 +08:00
Karson 709424da7f 优化favisible适配textarea多行文本框 2023-12-14 18:04:13 +08:00
Karson ae57feebb6 修复语言检测未匹配时的错误
优化分片上传
2023-12-14 17:57:38 +08:00
Karson cdb41c5334 优化表格&表单 2023-10-26 17:08:14 +08:00
Karson 2fe68b4c27 Merge branch '1.x' of gitee.com:karson/fastadmin into 1.x 2023-08-30 16:57:37 +08:00
Karson 31b307a4a1 优化上传异常捕获 2023-08-30 16:56:33 +08:00
Karson 7fffba8963 优化表格列表图片显示 2023-08-30 16:27:03 +08:00
Karson 4aa2666c98 优化后台菜单切换 2023-08-30 16:24:11 +08:00
Karson 940e9a0814 新增IP发送频繁检测 2023-08-30 16:22:21 +08:00
Karson 901bea7d59 修复check_url_allowed判断不全的问题 2023-08-30 16:20:55 +08:00
bran faff9fc96f [fix]公共函数字节转换bug修复
(cherry picked from commit 6b4cdff2e0)
2023-08-30 08:35:33 +08:00
Karson cc9802877a 更新版本号1.4.0 2023-07-11 10:45:29 +08:00
Karson 681558500c 优化代码 2023-07-10 15:41:27 +08:00
Karson 033af96e1a 优化代码 2023-07-10 14:30:50 +08:00
Karson ad166f07eb 打包JS 2023-07-10 11:55:56 +08:00
Karson b76b99f3a0 优化跨域检测 2023-07-10 11:54:43 +08:00
Karson b4dc742fed 优化Sidebar 2023-07-09 11:52:57 +08:00
Karson 37e844181e 优化后台页面样式和Sidebar 2023-07-09 11:44:21 +08:00
Karson 1a660364af 优化通用搜索和表格Tabs联动 2023-07-07 16:39:42 +08:00
Karson 65068c9a29 修复checkbox和radio组件生成 2023-07-07 16:09:17 +08:00
Karson 4845b08077 新增自定义错误码模板配置 2023-07-07 15:45:53 +08:00
Karson b0387e668b 优化CRUD生成 2023-07-07 15:25:03 +08:00
Karson aca4e9221c 优化表单重置时组件渲染
移除CRUD默认的重置按钮
优化上传大小判断
优化插件管理
2023-07-07 14:56:30 +08:00
Karson 7a4d05bbd9 优化语言包
优化cdnurl计算
2023-07-06 18:19:21 +08:00
Karson a9003ecce4 优化获取类名兼容性 2023-07-06 17:31:21 +08:00
Karson 7f28eaa570 优化服务端cdnurl函数计算
优化代码
2023-07-05 15:03:30 +08:00
Karson 31528c8951 修复cdnurl处理
新增表格列表内容弹窗hover模式
2023-07-05 11:38:57 +08:00
Karson e4094e24e2 优化代码 2023-07-04 10:05:40 +08:00
Karson 80ad9e307a 优化事件绑定 2023-07-03 16:58:33 +08:00
Karson e6f2894af7 新增表格列表内容弹窗展示 2023-06-28 18:14:34 +08:00
Karson c170985264 优化表格拖拽移动时tooltip定位 2023-06-28 15:20:08 +08:00
Karson 9d9c8dcf52 优化拖拽选择复选框功能
移除drag和drop依赖
2023-06-27 11:47:45 +08:00
Karson 4eaae6ac4e 优化站内相对链接判断
优化后台链接跳转
2023-06-20 16:46:04 +08:00
Karson 7e6314a701 增强后台安全限制
优化登录判断机制
移除冗余代码
2023-06-20 11:51:59 +08:00
Karson a40420b8cd 优化CRUD生成 2023-06-20 10:10:55 +08:00
Karson 31a6a47dc3 优化菜单规则管理 2023-06-19 18:12:01 +08:00
Karson 2c66c67d71 优化权限规则列表显示 2023-06-16 23:05:05 +08:00
Karson 42fdea065a 优化前台验证提示位置 2023-06-16 21:13:21 +08:00
Karson 0fb7924420 优化前台弹窗宽高 2023-06-16 21:13:06 +08:00
Karson 7cd9281c74 优化前台模板 2023-06-16 21:12:49 +08:00
Karson dc466cb1c9 优化url检测 2023-06-16 17:45:07 +08:00
Karson d2c275e20a 优化检测的URL默认值 2023-06-16 17:37:34 +08:00
Karson 3549e95ea1 新增URL检测和清理函数
优化登录和注册链接跳转
2023-06-16 17:32:00 +08:00
Karson a34c5fbdb8 优化打包JS 2023-06-16 16:33:35 +08:00
Karson 9fe7a6f9a0 优化拖拽组件高版本jQuery兼容 2023-06-16 16:33:16 +08:00
Karson 94b61ab7dc 优化bower依赖 2023-06-16 14:39:34 +08:00
Karson 6ebde793bd 优化插件管理JS 2023-06-16 14:38:52 +08:00
Karson faca2e0be0 优化前后台JS和CSS 2023-06-16 14:38:39 +08:00
Karson 7c8d1a6683 优化验证码 2023-06-16 11:32:58 +08:00
Karson 76c48c00fd 优化插件管理
兼容旧版本jQuery的size方法
2023-06-16 11:32:58 +08:00
Karson bc6bcb84f9 优化插件管理
# Conflicts:
#	public/assets/js/backend/addon.js
2023-06-16 11:03:58 +08:00
Karson 5f35be92b5 优化CRUD代码 2023-06-16 11:03:14 +08:00
Karson 9cadda6c3f 优化插件管理前端JS代码 2023-06-15 15:30:33 +08:00
Karson 152ac2cdcb 优化插件管理前端代码 2023-06-15 15:29:43 +08:00
Karson cd5fafde38 移除默认的api文档
优化api文档生成文本框
2023-06-15 15:08:54 +08:00
Karson 3d4a02160c 优化jQuery兼容
优化插件管理功能
2023-06-15 15:02:09 +08:00
Karson 1004bdedad Merge branch 'develop' of gitee.com:karson/fastadmin into develop
# Conflicts:
#	composer.json
2023-06-15 14:53:08 +08:00
Karson 8ce9f1f884 优化会员编辑模板 2023-06-15 14:52:41 +08:00
Karson bfd3737b28 按钮配置属性extend支持function 2023-06-15 14:52:29 +08:00
Karson 4b4d4493aa Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2023-06-15 14:51:53 +08:00
Karson 164a4f6664 新增think-queue配置 2023-06-15 14:51:39 +08:00
Karson e59668c0f2 优化iOS下后台样式 2023-06-15 14:50:57 +08:00
Karson afe0fdce73 修复超级管理管理员无法显示部分日志的问题 2023-06-15 14:50:44 +08:00
Karson 03f46a637d !437 解决fast/Date::unixtime() 报错非法日期BUG
Merge pull request !437 from bluehow/develop
2023-06-15 14:50:15 +08:00
Karson 0a062a8d63 !439 CRUD生成字段默认值bug
Merge pull request !439 from Jon/develop
2023-06-15 14:49:52 +08:00
小和 db5574582e !435 修改密码类型默认手机号
* 修改密码类型默认手机号
2023-06-15 14:48:02 +08:00
王子涵 e4ef9f1db0 update application/common/controller/Backend.php.
修复后台控制器关联查询参数设置无效

Signed-off-by: 王子涵 <3125976329@qq.com>
2023-06-15 14:47:49 +08:00
Karson 2c02ed019b 优化本地上传cdnurl
修复移动端站点配置不可见的问题
优化代码和注释
2023-03-09 17:42:20 +08:00
F4nniu eee98aad11
!432 更新统一数据库字符集
Merge pull request !432 from F4nniu/fix-utf8mb4
2023-02-19 13:31:24 +00:00
F4nniu 6d8f98a554 更新统一数据库字符集 2023-02-19 21:28:29 +08:00
Karson 9e9d729c62 优化打包压缩CSS 2022-12-14 20:20:43 +08:00
Karson 91549dbfea 优化CRUD回收站生成
优化前台多语言
优化组件样式
2022-12-14 17:16:33 +08:00
Karson 85f0e4f041 修改默认允许上传的文件
更新版本号
优化上传归类
优化默认GIT忽略
2022-12-14 16:35:58 +08:00
Karson 17256db17a 优化前台默认首页 2022-12-14 16:34:33 +08:00
Karson 2b81652072 优化会员规则多语言 2022-12-14 16:33:49 +08:00
Karson e846244791 优化语言包获取 2022-12-14 16:33:10 +08:00
F4nniu f8292a8813
!421 调整正确的语言文字
Merge pull request !421 from 椒颜玉米粒/N/A
2022-11-07 08:42:00 +00:00
椒颜玉米粒 89ed50d790
调整正确的语言文字,用户名必须6-30个字符
Signed-off-by: 椒颜玉米粒 <1336749157@qq.com>
2022-11-03 04:59:14 +00:00
F4nniu 776a4fedb5
!417 修复插件配置页面显示问题
Merge pull request !417 from sixXing/develop
2022-10-25 15:23:22 +00:00
sixXing 6b190fe111
update application/admin/view/addon/config.html.
1.解决按钮换行问题,2.解决图片和文件组件有tip时重叠问题

Signed-off-by: sixXing <464401240@qq.com>
2022-10-13 11:45:28 +00:00
F4nniu d562f3d17c 更新 less 文件 2022-10-10 00:06:47 +08:00
F4nniu 445f0c94d8 调整 select padding-right
压缩 css
2022-09-30 20:49:02 +08:00
F4nniu 6e4321d5cf
!381 优化 select.form-control 样式遮盖选中项文字
Merge pull request !381 from 黑化肥挥发会发灰/N/A
2022-09-30 12:40:17 +00:00
F4nniu 6d4d564ae8 压缩 css js 2022-09-30 10:56:39 +08:00
F4nniu b1af836710 更新 QQ 群信息。 2022-09-28 16:40:37 +08:00
F4nniu 7f0e4eb25c 删除无用的 build.php 2022-09-28 16:23:58 +08:00
F4nniu eaa1832852 easywechat 升级 2022-09-04 00:17:13 +08:00
F4nniu aa9fa16451 升级 bootstrap-select
解决微软拼音下输入重复的文字问题
2022-08-04 22:58:50 +08:00
F4nniu f02121cfcc 更新 Layer 地址 2022-07-25 21:53:24 +08:00
F4nniu 4fb1379afa 修改在线安装 php 版本要求 2022-07-20 22:49:31 +08:00
Karson ae935d260c
!409 导入时枚举型字段型备注只截取冒号前面部分
Merge pull request !409 from simon429/develop
2022-07-06 01:55:14 +00:00
Karson 44887b8aec
!411 fix: 回收站无法清空
Merge pull request !411 from Henry/fix
2022-07-06 01:53:15 +00:00
Henry 1dbafec12f fix: 回收站无法清空 2022-07-06 09:48:08 +08:00
F4nniu 9a90cbe329 phpspreadsheet 升级到 1.19 2022-06-23 18:51:21 +08:00
F4nniu ae11381309 php 版本依赖修改为大于等于 7.2 2022-06-23 00:31:19 +08:00
F4nniu c3bdbbf779 忽略 .user.ini 2022-06-15 23:56:37 +08:00
simon 3ba1192555 导入时字段备注截取 2022-06-09 21:04:52 +08:00
Karson 80d928d872 修复联动调用选择空时的错误 2022-06-07 10:00:20 +08:00
Karson b9877c10ff 移除冗余代码 2022-05-30 14:51:49 +08:00
Karson a7983055fc 优化密码长度判断
新增个人资料手机号显示
2022-05-30 11:24:23 +08:00
Karson 3fd25c3de0 优化表格分页判断
优化语言包加载
2022-05-27 17:14:33 +08:00
Karson 85e0f4bacc 管理员表新增mobile字段 2022-05-27 16:21:36 +08:00
Karson b3c4692164 优化注释文字 2022-05-27 15:51:31 +08:00
Karson dfeff713bd 优化配置打包JS 2022-05-27 15:46:18 +08:00
Karson f639cecf73 Merge https://github.com/karsonzhang/fastadmin into develop
# Conflicts:
#	application/config.php
#	public/assets/js/require-backend.min.js
#	public/assets/js/require-frontend.min.js
2022-05-27 15:45:07 +08:00
Karson 466aa4233f 优化安装脚本
优化JS
2022-05-27 15:33:27 +08:00
Karson 378aad4409 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2022-05-27 15:30:18 +08:00
Karson 1a07280f79 优化语言获取和加载 2022-05-27 15:30:05 +08:00
Karson b3e172ddce 优化后台菜单生成
优化菜单写入字段
2022-05-27 15:03:00 +08:00
Karson 079f6df9dd 优化生成表格工具栏按钮权限判断 2022-05-27 15:01:40 +08:00
Karson 9400aa6e4e 优化size判断 2022-05-27 11:47:02 +08:00
Karson 0b4eceea54 移除头部语言配置 2022-05-27 11:43:42 +08:00
Karson ce811fa904 优化默认安装脚本 2022-05-27 11:43:01 +08:00
Karson 06ccca81c9 优化CRUD生成 2022-05-27 11:42:51 +08:00
F4nniu be2f342044
!398 解决在使用Table组件时,传递pageSize参数确被设置全局的问题,并开放全局页面显示数方法
Merge pull request !398 from Henry/page-size
2022-05-17 14:11:39 +00:00
Henry 1898e481e0 压缩打包 backend、frontend 文件 2022-05-09 09:26:29 +08:00
Henry e59d2df641 将插件页面表格的设置分页数方法修改为全局统一的方法 2022-05-09 09:26:04 +08:00
F4nniu f4795e90da 为适应现代编辑器 VSCODE 的提示修改注释 2022-05-08 09:50:15 +08:00
F4nniu 9eeb35a79b 修改 framework git 地址 2022-05-07 23:43:44 +08:00
F4nniu 12e7bbf5f2
!400 代码优化,处理destroy方法未判断$ids变量为空情况的问题
Merge pull request !400 from Henry/optimize
2022-05-07 05:16:43 +00:00
Henry 940d4f0410 代码优化 2022-05-04 11:49:25 +08:00
Henry 5022da9cea 解决在使用Table组件时,传递pageSize参数确被设置全局的问题,并开放全局页面显示数方法 2022-04-25 15:26:41 +08:00
F4nniu 8e48aa7edd
!396 语言文件说明不对
Merge pull request !396 from dublog/develop
2022-04-20 00:20:51 +00:00
qhyan 036c2dcc25 修复说明不对 2022-04-19 20:29:47 +08:00
F4nniu 9116b86a36
!385 基于PHP7.1版本使用Catch多个语句
Merge pull request !385 from Henry/optimiza-exception-handle
2022-04-02 09:13:44 +00:00
F4nniu a4617c7f28 修复验证码不支持 0 开头的错误 2022-04-01 09:58:43 +08:00
F4nniu a9a5696f58
!389 修改think框架引导文件为绝对路径
Merge pull request !389 from aa820t@126.com/master
2022-03-31 15:33:06 +00:00
F4nniu e67f9a20c5 修复手机验证码不支持 0 开头的错误 2022-03-31 23:28:16 +08:00
aa820t@126.com ff51380686
修改 think 框架引导文件 为绝对路径
在非本项目根目录下, 执行php think 命令行, 使用引用路径会导致后续代码无法执行.
2022-03-30 08:21:20 +00:00
Henry 2a97c21c0c 基于PHP7.1版本使用Catch多个语句 2022-02-17 14:54:57 +08:00
Karson 6470a8ed74 更新版本号&依赖
压缩打包JS文件
2022-01-21 16:00:42 +08:00
Karson d7ffc690c2 更新JS压缩文件 2022-01-21 15:31:52 +08:00
Karson 41682bd850 更新版本号和依赖 2022-01-21 15:29:59 +08:00
Karson 2401cd3ba1 优化插件配置分组 2022-01-21 11:36:57 +08:00
Karson 8b55020b3a 优化邮件发送插件检测 2022-01-21 09:33:29 +08:00
Karson 3dd4276ca1 优化插件插件列表
优化登录注册模板注释,便于插件整合。
2022-01-20 22:05:05 +08:00
Karson 02cc257faf 新增是否默认展示子菜单功能 2022-01-20 17:23:43 +08:00
Karson cd60f5f381 优化控制台统计 2022-01-20 16:46:02 +08:00
Karson d4531c7df0 优化计算月天数 2022-01-20 16:00:57 +08:00
Karson d2d6648d9c Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2022-01-20 15:48:43 +08:00
Karson f700dbcdc7 修复表格dropdown被遮挡的BUG
优化表格
优化动态显示组件
2022-01-20 15:48:36 +08:00
黑化肥挥发会发灰 9ed5fbd2e3
优化 select.form-control 样式遮盖选中项文字 2022-01-20 03:13:19 +00:00
Karson 6569dfbb3c
!377 修复当 $myid 为字符串类型时出现的无限递归的问题
Merge pull request !377 from T2cc/N/A
2022-01-20 02:47:14 +00:00
Karson c87a7f9f3c 优化插件配置分组
优化fieldlist触发事件
2022-01-20 10:43:23 +08:00
T2cc 077bba602d
修复当 $myid 为字符串类型时出现的无限递归的问题
由于 PHP 中 0 == 字符串永远等于 true 的特性,该处容易出现判断错误。
- 为什么不用 ===
因为很多情况可能会搞不清当前数据是 0 还是 '0' ,使用类型转换更加兼容。
2022-01-18 05:27:34 +00:00
Karson edec9f7fe1 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2022-01-16 19:05:04 +08:00
Karson 0c950a93cf 优化隐藏元素验证 2022-01-16 19:04:48 +08:00
F4nniu 96cb06f825 Copyright 2017-2022 2022-01-16 18:47:30 +08:00
Karson 65073c30b9 新增插件配置分组功能
新增插件配置分组功能
新增插件配置可见条件
新增常规管理系统配置可见条件功能
新增表单可见条件组件
2022-01-16 18:37:33 +08:00
Karson d785d321f7 优化移动端弹窗大小判断
优化上传文件名过滤
2022-01-13 14:41:43 +08:00
Karson ff85bb3b21 修复新版本密码长度导致无法添加管理员的BUG
优化错误提示
2022-01-13 09:38:44 +08:00
Karson c65e3b23e2 优化默认SQL 2022-01-12 01:37:47 +08:00
Karson c00584a5b5 优化插件管理&优化前台弹窗 2022-01-12 01:23:41 +08:00
Karson 017970a2e3 优化用户名密码长度检测
优化CRUD文件类型
移除cdnurl后台系统配置中配置
修复附件选择列表无法上传文件的BUG
2022-01-08 15:00:25 +08:00
Karson 5673ce72fd 优化插件管理请求接口 2022-01-01 01:59:32 +08:00
Karson 4fa13dca39 更新bower依赖 2022-01-01 00:19:32 +08:00
Karson 8366745875 优化打包压缩文件 2021-12-31 22:46:04 +08:00
Karson a176508bb9 优化依赖 2021-12-31 22:04:02 +08:00
Karson 5ea57836c8 优化CRUD 2021-12-31 21:51:16 +08:00
Karson 82ea7fcd15 优化依赖版本 2021-12-31 21:36:40 +08:00
Karson 03bfe24893 优化addtion
优化blockquote字体大小
2021-12-31 18:18:59 +08:00
Karson acca6a0584 优化后台首页Cookie限制path 2021-12-29 11:03:24 +08:00
Karson 12ea49d937 修复后台首页Cookie限制path 2021-12-29 10:46:54 +08:00
Karson 41fc1d1b3a 优化控制栏&时间区间回调 2021-12-28 16:43:28 +08:00
Karson b52df110ee 优化后台控制栏选项 2021-12-27 16:03:01 +08:00
Karson e3169bcaf4 新增验证码长度配置&优化后台管理菜单 2021-12-27 15:53:09 +08:00
Karson d1cdc51798 修复默认皮肤
改进内置服务器
优化伪静态
2021-12-17 16:01:59 +08:00
Karson cd9d2e6516 Merge branch 'develop' of gitee.com:karson/fastadmin into develop
# Conflicts:
#	application/admin/command/Crud.php
#	application/common/library/Upload.php
#	public/assets/js/require-form.js
2021-12-17 15:59:04 +08:00
Karson bc99cfddd8 优化附件选择 2021-12-17 15:30:49 +08:00
Karson a7317ec08c 新增一对多CRUD功能
新增一键生成tagsinput组件
新增autocomplete和tagsinput前端组件
新增配置全局启用上传时使用完整URL功能
新增附件列表上传归类
新增后台管理布局个性化配置
新增插件安装成功导入测试数据提示
新增后缀生成icon缓存
新增全局列表图片缩略图样式
优化插件安装后自动刷新JS缓存
优化后台管理左侧菜单展现方式
优化全局样式
优化fieldlist组件
优化上传组件归类功能
优化Bootstrap-table固定列高度
优化Layer弹窗焦点框
2021-12-16 10:47:18 +08:00
Karson 824f337481 优化复合组件检测 2021-12-02 09:41:45 +08:00
Karson fce5b8e374 新增自动生成标签&时间区间组件
新增自动生成固定列
新增弱密码检测
优化插件相关命令行命令
优化默认管理员和前台用户头像
2021-12-01 16:35:07 +08:00
Karson 093d60b719 !371 修复CRUD关联模型时,自定义控制器生成的被关联表模型namespace错误
Merge pull request !371 from simon429/develop
2021-11-18 01:54:50 +00:00
F4nniu a7b7b772fd 删除 public 目录下无用的 router.php。 2021-11-11 18:46:59 +08:00
simon429 48066342da 修复CRUD关联模型下,自定义控制器生成的被关联表模型namespace错误 2021-10-26 16:31:38 +08:00
F4nniu ecdaa81a8d !370 修正fa_area中城市层级说明
Merge pull request !370 from lscho/master
2021-10-26 06:21:27 +00:00
Karson a87cfefd50 !361 修复fieldlist在初始值为空时,不会绑定fa.event.refreshfieldlist事件
Merge pull request !361 from 诛心/fieldlist
2021-10-20 08:06:16 +00:00
Karson e7f8b75ecf !327 修复 User 模型附加字段不存在时导致接口报错的 BUG。
Merge pull request !327 from T2cc/N/A
2021-10-20 08:02:52 +00:00
Karson 9a239de4b1 !364 update application/common/library/Upload.php.
Merge pull request !364 from 御宅男/N/A
2021-10-20 07:55:25 +00:00
lscho db69a36d28 修正城市层级说明 2021-10-15 08:05:06 +00:00
Karson 70b9c8affe 更新版本号 2021-10-11 17:22:37 +08:00
Karson 9d1d1248e9 Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2021-10-11 17:17:21 +08:00
Karson 84eef812f3 修复上传文件的安全隐患 2021-10-11 17:16:48 +08:00
F4nniu 0266534d95 !365 前台关闭会员中心时,报错信息页链接跳转到首页
Merge pull request !365 from simon429/develop
2021-10-06 10:06:25 +00:00
simon429 e7ae8fb4d1 关闭会员中心时,报错信息页链接跳转到首页 2021-10-01 23:22:54 +08:00
御宅男 c12f9bca84 update application/common/library/Upload.php.
多余类属性
2021-09-26 02:02:26 +00:00
F4nniu 69ad41a3e9 !362 【轻量级 PR】:修复当文件名称为中文时截断导致的乱码报错问题。
Merge pull request !362 from T2cc/N/A
2021-09-12 14:02:29 +00:00
T2cc 3a0352e183 修复当文件名称为中文时截断导致的乱码报错问题。 2021-09-10 01:44:42 +00:00
诛心 ab53e00a75 修复fieldlist在初始值为空时,不会绑定fa.event.refreshfieldlist事件 2021-09-08 20:12:57 +08:00
Karson ac2b3ffbff !358 表格赛选为BETWEEN时 无法筛选0,0的数据
Merge pull request !358 from 码龍/editBuildParams
2021-08-27 15:06:40 +00:00
码龍 9cf930a932 修改表格BETWEEN查询 值为0时无法筛选问题 2021-08-24 06:48:39 +00:00
Karson 343ad6055d !348 解决huamn函数无法格式未来时的问题
Merge pull request !348 from Henry/prefect
2021-08-09 02:06:06 +00:00
Karson 2ab8d7fa81 !349 系统配置新增密码类型参数
Merge pull request !349 from Henry/prefect2
2021-08-09 02:04:49 +00:00
Karson f3b841c456 !350 插件配置新增密码类型参数
Merge pull request !350 from Henry/prefect3
2021-08-09 02:04:21 +00:00
Henry 683d837d20 插件配置新增密码类型参数 2021-08-05 16:45:49 +08:00
Henry 3f1cac43e4 系统配置新增密码类型参数 2021-08-05 16:23:57 +08:00
Henry 75141e192d 解决huamn函数无法格式未来时的问题 2021-08-05 16:03:24 +08:00
Karson 1d7c7d7ce6 更新新版本
移除冗余代码
2021-07-30 16:17:04 +08:00
Karson 6178a5c231 优化附件未归类功能 2021-07-28 09:59:58 +08:00
Karson 0c7a4850a2 优化报错页面 2021-07-23 17:29:44 +08:00
Karson a502a98df0 新增附件类型筛选
优化Layer样式
2021-07-23 17:13:25 +08:00
Karson 3d9805eea7 优化Layer弹窗
优化表格Loading
优化个人日志搜索
优化附件列表
2021-07-21 18:30:03 +08:00
Karson 8925cbc9f7 优化API生成提示
优化后台菜单刷新
2021-07-21 14:51:42 +08:00
Karson 80a25c9749 优化附件列表变量输出
优化前后台退出机制
2021-07-20 17:34:38 +08:00
Karson 70e215cdde !340 优化菜单规则的拼音转换
Merge pull request !340 from Henry/repair
2021-07-20 02:45:47 +00:00
Henry f501638884 优化菜单规则的拼音转换 2021-07-20 09:39:54 +08:00
Karson d1d3ea1dea 修复后台边框部分情况下无法滚动的BUG
优化后台刷新跳转效率
优化后台直接跳转登录
优化后台菜单搜索
优化前台变量输出
2021-07-19 21:49:20 +08:00
Karson b3b9a61723 !319 优化后台首页打开速度,避免后期菜单过多导致加载超时问题
Merge pull request !319 from Henry/develop_2
2021-07-19 09:49:40 +00:00
Karson 60902457bb 优化跨域提示 2021-07-19 15:44:14 +08:00
Karson 8b11a77294 !330 cors 检测的时候不直接使用 exit
Merge pull request !330 from T2cc/N/A
2021-07-19 07:28:56 +00:00
Karson dfd0ba0524 !302 点击表格删除按钮后 Layer弹出层 确定 取消 按钮 的 多语言 版本修改
Merge pull request !302 from Ylianjie/develop
2021-07-19 06:39:14 +00:00
Karson 5599170ce4 !337 解决api模块上传文件获取不到uid的问题
Merge pull request !337 from Henry/repair
2021-07-19 06:36:30 +00:00
Karson ca8238df06 !339 解决后台用户余额和积分修改时,因类型不同导致写入记录表无用记录的问题
Merge pull request !339 from Henry/repair_user_fund
2021-07-19 06:34:54 +00:00
Karson 2c4efe19f2 Merge remote-tracking branch 'origin/develop' into develop 2021-07-19 11:59:56 +08:00
Karson b3d32e2bf3 修复前台URL跳转输出 2021-07-19 11:59:03 +08:00
Henry 4275d769ea 解决后台用户余额和积分修改时,因类型不同导致写入记录表无用记录的问题 2021-07-13 11:43:17 +08:00
Henry 9b4d4c78dd 解决api模块上传文件获取不到uid的问题 2021-07-12 14:10:22 +08:00
Karson 88df7bd386 !336 解决Form类内部分方法的可选参在必选参前的问题
Merge pull request !336 from Henry/repair
2021-07-10 01:55:09 +00:00
Henry 503c67f9d8 解决Form类内部分方法的可选参在必选参前的问题 2021-07-09 13:34:32 +08:00
F4nniu e05a8584e2 !333 解决 Soft 单词拼写错误问题
Merge pull request !333 from Henry/naming
2021-07-07 04:50:08 +00:00
F4nniu 82748502ea !335 修复API模块用户中心关闭无效
Merge pull request !335 from F4nniu/fix-user-api
2021-07-07 04:47:18 +00:00
King超 33788fc93e 修复API模块用户中心关闭无效 2021-07-07 12:37:44 +08:00
Henry 49ed6cb808 解决 Soft 单词命名错误问题 2021-07-07 10:29:53 +08:00
Karson 4b1c3a3b4b Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2021-07-05 11:47:38 +08:00
Karson a5163732af 优化附件选择按钮事件 2021-07-05 11:28:16 +08:00
Karson 7adc36ae4f 优化一键生成API文档
优化接口请求方法
2021-07-05 11:27:38 +08:00
Karson 9a7e29a080 优化CRUD自定义删除字段
优化CRUD无符号字段
2021-07-05 11:23:13 +08:00
T2cc 3dfa4f7065 cors 检测的时候不直接使用 exit 2021-06-22 02:32:54 +00:00
T2cc bbf728b5e6 修复 User 模型附加字段不存在时导致接口报错的 BUG。 2021-06-18 14:51:08 +00:00
F4nniu 99c3fac317 !326 修复crud生成文件时未选中id主键时导致编辑功能错误问题
Merge pull request !326 from F4nniu/crud-pk
2021-06-17 07:03:44 +00:00
wanger 614384a2bb 修复crud生成文件时未选中id主键时导致编辑功能错误问题 2021-06-17 13:36:32 +08:00
F4nniu 44fd7d14ec !320 发送邮件时,邮件服务商返回的错误信息编码导致系统500错误
Merge pull request !320 from Henry/email_revision
2021-06-17 03:23:01 +00:00
F4nniu c615eda2dc !324 禁止系统表被 CRUD
Merge pull request !324 from F4nniu/prohibit-crud-system-tables
2021-06-15 15:34:10 +00:00
F4nniu e5235a4991 将用户相关表加入到受保护列表中。 2021-06-15 23:28:58 +08:00
wanger f05e5ae722 添加admin_log表 2021-06-15 23:00:08 +08:00
wanger 6edcaffa75 防止系统表文件生成被覆盖 2021-06-15 22:59:58 +08:00
F4nniu de1c8194f1 !322 修复顶部选项卡icon不显示问题
Merge pull request !322 from King超/master
2021-06-15 06:35:26 +00:00
King超 364d7be7ba 修复顶部菜单icon不显示问题 2021-06-10 11:00:46 +08:00
Henry e0b008097a 解决邮件发送时,腾讯企业邮箱返回的错误信息编码影响系统报错的问题 2021-06-09 14:08:50 +08:00
Henry 4f28da05fe 移除拼音转换,代码优化 2021-06-09 14:03:49 +08:00
Henry a5eb7ef3b7 模型定义拼音自动完成字段 2021-06-09 14:03:12 +08:00
Henry 119b0273d4 auth_rule表冗余拼音字段 2021-06-09 14:02:35 +08:00
Karson bba702bd18 优化分片上传 2021-06-04 15:21:28 +08:00
Karson 8130a49fab 优化通用搜索表单重置
优化标签渲染
2021-06-04 14:57:03 +08:00
Karson 4e657d1f25 优化权重排序
优化权限规则写入
2021-06-04 14:53:42 +08:00
Karson ed0da37370 优化附件归类文字和权限判断 2021-06-04 14:49:23 +08:00
Karson bf720c176e 新增附件分类功能
新增上传接口设定分类功能
优化分片上传进行百分比计算
优化系统配置字典文字显示
2021-06-04 14:33:44 +08:00
Karson 7045f0d02b Merge branch 'develop' of gitee.com:karson/fastadmin into develop 2021-05-19 17:54:04 +08:00
Karson cdebb284c3 优化菜单规则中的条件判断 2021-05-19 17:52:34 +08:00
F4nniu 9f725a062a !299 修复生成 api 文档报错的 bug
Merge pull request !299 from T2cc/N/A
2021-05-13 22:35:31 +08:00
F4NNIU d59ff78fd8 修改 framework type 为 git 2021-05-13 22:31:12 +08:00
unknown 289e9306bd 点击表格删除按钮后 LAYER 弹出层 确定取消 按钮的 多语言版本 修改 2021-04-13 13:11:54 +08:00
F4nniu dba3ca50fc !300 优化user的Validate验证
Merge pull request !300 from YouKnow/master
2021-04-12 14:10:35 +08:00
T2cc 6b9e5ba379 修复生成 api 文档报错的 bug 2021-04-11 22:36:53 +08:00
YouKnow 1c62049989 优化user验证 2021-04-09 15:56:03 +08:00
Karson ab083686a8 优化积分和余额并发 2021-04-06 12:03:25 +08:00
Karson 0236b39df0 修复控制台管理员统计 2021-04-02 11:07:29 +08:00
Karson 61cf9c2896 修复菜单规则缺少url字段 2021-04-02 11:05:41 +08:00
Karson 04e1f7f0ae 更新版本号
移除冗余图片
2021-04-01 22:26:14 +08:00
Karson 43d8570337 优化验证控制器变量名 2021-04-01 18:05:48 +08:00
Karson f1fb9cbb3b 优化插件目录和缓存目录缓存 2021-04-01 17:53:47 +08:00
Karson e1fe326597 优化Fieldlist组件
优化上传图片顺序
优化Composer依赖
2021-04-01 17:46:42 +08:00
Karson 454fdcded9 修复分片上传参数过滤不严的BUG 2021-04-01 17:36:22 +08:00
Karson a58a147143 优化后台离线上传 2021-04-01 17:35:42 +08:00
Karson 4db3a64b2c 前后台API添加IP屏蔽功能 2021-04-01 17:34:14 +08:00
Karson 0c494ee2b3 优化接口请求方式 2021-04-01 17:31:59 +08:00
Karson 132dc960b2 修复分片上传兼容性BUG
优化后台控制器分组统计
优化清除缓存提示
2021-03-29 23:42:39 +08:00
Karson 5ad3d5125a 新增清除浏览器缓存功能
调整优化下拉菜单的字体大小和间距
2021-03-29 16:44:00 +08:00
Karson dc691dbe84 新增菜单规则自定义URL功能
新增菜单规则弹窗&Ajax&外部链接功能
修复清除缓存事件重复绑定的BUG
2021-03-29 11:47:07 +08:00
Karson 120aa6b200 优化过期Token删除
优化控制台DAU计算
2021-03-28 16:04:50 +08:00
Karson cd37a9e7e4 优化后台右上角图标文字
优化权限规则菜单展示
2021-03-27 23:03:59 +08:00
Karson e2772b164b 优化控制台数据显示 2021-03-27 23:02:33 +08:00
Karson ab89d2d506 优化API文档模板参数格式校验 2021-03-26 16:46:52 +08:00
Karson 916722b139 修复插件配置规则图片和文件类型时不生效 2021-03-26 14:57:04 +08:00
Karson 65daf79d0a 优化备案链接 2021-03-26 11:04:52 +08:00
Karson e4b2066e0f 优化管理员增删改事务处理 2021-03-26 11:01:22 +08:00
Karson d610fe6141 Merge remote-tracking branch 'origin/develop' into develop 2021-03-26 10:58:35 +08:00
Karson 97a6b53cec 优化管理员增删改事务处理 2021-03-26 10:58:11 +08:00
F4NNIU 63d74029f0 关闭后台验证码的自动完成 2021-03-25 11:29:34 +08:00
Karson fb2b5aed30 Merge remote-tracking branch 'origin/develop' into develop 2021-03-24 11:18:33 +08:00
Karson c7126fe7bb 优化拼音转换 2021-03-24 11:18:12 +08:00
F4NNIU 2e74e2c119 更新 Composer 依赖 2021-03-18 15:33:18 +08:00
F4NNIU 2b5cab420a Merge branch 'master' into develop 2021-03-14 20:20:52 +08:00
Karson f815edab04 !212 补充Auth兼容调用user模型的属性
Merge pull request !212 from caiqy/master
2021-03-10 14:19:11 +08:00
Karson 0b752a3dfa !282 后台系统配置发送测试邮件时,多语言变量传入支持格式错误
Merge pull request !282 from Henry/revision
2021-03-10 11:02:29 +08:00
Karson 6bac3fca8a !286 解决自带Email类发送邮件收件人账号名是数组索引,移除未使用形参
Merge pull request !286 from Henry/email_bug_revision
2021-03-10 11:01:08 +08:00
Karson 025f37f1f1 !288 在线命令生成Api文档,控制器设置隐藏仍然会显示
Merge pull request !288 from Henry/api_revision
2021-03-10 10:40:23 +08:00
Karson 89e14e8f8b 安装脚本PHP版本检测 2021-03-10 10:28:32 +08:00
Karson 74a4aacb66 修复unixtime方法计算周偏移时的错误 2021-03-10 10:27:32 +08:00
Karson 6c0ea3a420 修复邮件发送错误 2021-03-10 10:26:54 +08:00
F4NNIU b909c0b27a 后台禁止搜索引擎收录和索引。 2021-03-09 15:58:19 +08:00
Henry 8127f56953 解决在线命令生成Api文档,控制器设置隐藏仍然会显示问题 2021-03-09 09:17:33 +08:00
F4nniu 351475ca06 !285 解决生成CURD时,指定需要使用富文本编辑器字段时的报错问题
Merge pull request !285 from Henry/revision3
2021-03-02 16:17:42 +08:00
Henry 5d7181fe1d 移除to方法从未使用的$name变量 2021-03-02 13:45:19 +08:00
Henry 5ab531e0ec 解决使用自带Email类发送邮件时,收件人账号名是数组索引的问题 2021-03-02 13:44:37 +08:00
Henry dc5a2e01dd 解决生成CURD时,指定需要使用富文本编辑器字段时的报错问题 2021-03-02 13:21:22 +08:00
Henry 5a9dbf0abf 解决后台系统配置发送测试邮件时,语言包变量未替换的问题 2021-03-02 13:08:35 +08:00
F4NNIU af241c7c21 Merge branch 'master' into develop 2021-02-23 09:08:24 +08:00
F4nniu 9174b6c306 !274 修复图片 value 问题
Merge pull request !274 from F4nniu/fix-image-value-split
2021-02-02 15:29:36 +08:00
F4NNIU 1fc50ed06d 修复图片分隔缺少 value 问题 2021-02-02 15:27:41 +08:00
F4nniu 504e50e65c !273 修复邮件发送报类找不到的问题
Merge pull request !273 from 一半/master
2021-01-30 17:21:40 +08:00
一半 76b31ced93 修复邮件发送时Log类找不到的致命错误 2021-01-27 04:36:37 +08:00
Karson 700184c8eb 修复安装脚本错误 2021-01-25 21:04:13 +08:00
Karson 35220f545c Merge branch 'master' of gitee.com:karson/fastadmin 2021-01-25 16:57:47 +08:00
Karson b82dbd7eee Merge branch 'develop'
# Conflicts:
#	application/admin/command/Api.php
#	application/admin/command/Install.php
#	application/config.php
2021-01-25 16:57:18 +08:00
Karson 6f17a39d90 更新版本号 2021-01-25 16:54:21 +08:00
Karson ce8c3a94d9 优化IP获取配置 2021-01-25 16:51:26 +08:00
Karson e097ae2429 优化上传图片后预览事件 2021-01-25 16:50:10 +08:00
Karson c2460a3241 修复权限管理员越权上级权限的BUG
修复管理员日志查看超级权限的BUG
优化权限管理分组列表
2021-01-24 22:10:53 +08:00
Karson c585fa1228 !266 修复cal_days_in_month的month参数错误,导致计算跨年时间戳报错
Merge pull request !266 from Chrisleung/master
2021-01-14 10:32:49 +08:00
Chrisleung 00bca5e0c8 修复cal_days_in_month的month参数错误,导致计算跨年时间戳报错 2021-01-08 11:39:24 +08:00
Karson 4a9ebb9c7d 优化安装脚本
优化cookie加密
修复系统配置关联字段链接错误BUG
修复addtion方法空数据错误的BUG
修复后台管理获取子级分组列表BUG
优化邮件发送方式
优化cdnurl判断
优化插件管理提示
优化会员附件列表搜索
优化会员登录注册跳转链接获取
2020-12-29 09:46:41 +08:00
Karson 7daf3601ed 修复上传异常时不提示的BUG 2020-12-25 10:26:29 +08:00
Karson 6609ac1470 修复fieldlist中textarea刷新不渲染的BUG 2020-12-25 10:25:52 +08:00
Karson 794f02c502 新增自动修复下拉列表功能
新增自定义弹窗标题功能
优化部分formatter格式化判断
2020-12-25 10:18:29 +08:00
Karson 39c6720cfc 新增自定义插件API文档生成
新增自定义插件API文档生成
新增登录和鉴权状态显示
新增自定义测试提交参数
2020-12-21 11:43:16 +08:00
Karson dd3d6f3172 优化安装脚本
添加随机token设置
2020-12-21 11:38:25 +08:00
Karson 12a62eaa05 !166 增加可选api生成文档(修改参数冲突)
Merge pull request !166 from kingang/master
2020-12-21 09:38:16 +08:00
Karson 662d211946 !260 修复selectpage自定义 data-primary-key 为非数值型内容导致自定义排序SQL报错BUG
Merge pull request !260 from 傲杰笔记/fix_bug
2020-12-19 12:01:27 +08:00
傲杰笔记 2a131ae573 修复自定义data-primary-key为字符串内容时排序报错BUG 2020-12-19 11:18:07 +08:00
Karson c4d676aa8c !263 修改 后台-》常规配置-》管理配置-》系统配置 的 初始化方法
Merge pull request !263 from 小鸡炖蘑菇/master
2020-12-19 10:51:10 +08:00
cf king 9c13b07f73 优化为 ConfigModel 2020-12-10 17:43:56 +08:00
Karson 8af7f5653a !258 update public/assets/js/frontend/user.js.
Merge pull request !258 from EZ/N/A
2020-12-03 20:57:12 +08:00
傲杰笔记 8d0384ee49 简单修复selectpage 自定义data-primary-key为非数值型内容时,自定义排序导致SQL报错BUG 2020-12-03 09:03:39 +08:00
I'am EZ fadcb5432a update public/assets/js/frontend/user.js. 2020-11-29 04:50:56 +08:00
Karson eca3ae7086 优化在非80端口下的跨域判断
优化安装脚本
2020-10-08 22:51:06 +08:00
Karson 346f6eab1a 更新版本号 2020-09-30 16:27:39 +08:00
Karson 08ee8d3362 开启未知来源验证 2020-09-30 16:24:17 +08:00
Karson 2a811716b9 优化API接口上传配置 2020-09-30 15:44:41 +08:00
Karson 0f3ee250ad 优化上传配置和API接口上传配置 2020-09-30 15:17:29 +08:00
Karson 06057850c1 优化上传配置
优化API接口配置
2020-09-30 13:32:22 +08:00
Karson d1bdd4982c 优化selectpage字段筛选 2020-09-30 08:43:57 +08:00
Karson 3e48396821 移除冗余依赖包
优化规则菜单操作逻辑
2020-09-30 00:27:25 +08:00
Karson bb97452fe1 优化切换按钮禁用状态
优化语言包判断
优化权限管理规则管理列表逻辑
2020-09-29 23:13:42 +08:00
Karson e8fa069fe9 优化安装脚本
优化SelectPage编辑时按顺序显示
优化分类、省市联动列表接口逻辑
2020-09-29 21:25:39 +08:00
Karson bcfbe92d51 !245 修复后台分类调用PID为0时无法调用顶级分类
Merge pull request !245 from simon429/master
2020-09-29 17:17:00 +08:00
simon429 908039c13d 修复调用PID为0时无法调用顶级分类 2020-09-29 15:46:49 +08:00
Karson 32f256f3fa !225 多选字段存储和编辑时按选择顺序存储及显示
Merge pull request !225 from HID丨emotion/adv_multi_order
2020-09-29 09:53:36 +08:00
Karson 750f5d7887 !243 修复前台菜单多语言
Merge pull request !243 from DonsonLau/master
2020-09-29 09:23:27 +08:00
Karson 7b0ce82bbb !242 优化 用户注册隐私问题,支持号段1[3-9]
Merge pull request !242 from 前海万联/N/A
2020-09-29 09:15:41 +08:00
Donson bcdbd82c5c 修复前台菜单多语言 2020-09-28 16:15:35 +08:00
万联科技 fffad26373 优化 用户注册隐私问题,支持号段1[3-9] 2020-09-28 11:09:23 +08:00
Karson ad69fbab5c 修复composer和bower依赖 2020-09-24 15:24:07 +08:00
Karson acb42e8eb8 新增日志过滤
新增安装未知来源插件开关
新增插件纯净模式
修复分片合并未创建文件夹BUG
优化插件管理逻辑
2020-09-24 15:15:24 +08:00
Karson 9d5ccb91b4 !240 修复管理员日志中的标题获取
Merge pull request !240 from DonsonLau/master
2020-09-21 17:38:29 +08:00
Donson 1473fd93cf 修复管理员日志中的标题获取 2020-09-21 11:45:50 +08:00
Karson aa5d413cc0 update application/index/controller/User.php.
移除空请求判断
2020-09-20 19:24:57 +08:00
Karson e550b327dd 优化会员列表显示
优化个人资料列表显示
优化基类模型
2020-09-18 17:17:13 +08:00
Karson 82fc4f971c 新增时间字段CRUD默认关闭autocomplete 2020-09-18 16:49:43 +08:00
Karson c8085a406e 新增列表搜索autocomplete配置
优化关联搜索
优化附件列表缩略图显示
2020-09-18 16:42:19 +08:00
Karson b4185e2da8 优化SelectPage多选删除样式 2020-09-17 22:13:44 +08:00
Karson dfd326a6e1 修复多选全部移除后输入框的宽度BUG
优化SelectPage初始化样式
2020-09-17 21:31:59 +08:00
Karson ebb5d34414 优化列表固定宽度功能 2020-09-17 17:12:20 +08:00
Karson b277d31c60 优化列表导出功能
修复导出全部BUG
优化移动端列表展示
优化iOS移动端展示
2020-09-17 15:01:16 +08:00
Karson d0f71f4f1d 优化上传返回错误时的提示文字 2020-09-14 21:35:34 +08:00
Karson 98b813aff1 更新Echarts
优化表格content格式化方法
2020-09-14 14:49:47 +08:00
Karson 15f6fb7553 优化选项卡关闭按钮颜色 2020-09-12 22:47:00 +08:00
Karson f70e1f3349 优化后台回收站列表逻辑 2020-09-12 16:41:04 +08:00
Karson 045b756272 修复关联主表时间字段无法搜索的BUG 2020-09-12 16:27:56 +08:00
Karson 788b1d57f6 优化后台列表空格显示 2020-09-12 11:31:59 +08:00
Karson 077eebec86 优化前台退出文字
修复分页搜索BUG
2020-09-11 22:52:08 +08:00
Karson 36d762fc81 优化跳转和错误页面样式 2020-09-11 17:59:48 +08:00
Karson 4f7b083e8d 修复登录页背景图错误 2020-09-11 17:23:16 +08:00
Karson 7150bea947 全新后台登录页面 2020-09-11 16:54:24 +08:00
Karson a2d99f4bdb 修复关联字段时间无法搜索的BUG
优化后台列表逻辑
2020-09-11 14:10:59 +08:00
Karson 8b772d30cd !235 update application/index/view/index/index.html.
Merge pull request !235 from 万联科技/N/A
2020-09-10 21:35:10 +08:00
Karson 5ea682edf4 优化移动端下Tabs滚动
优化移动端下系统配置页面展示
2020-09-10 21:05:00 +08:00
Karson 1cc0cadbdd 优化后台皮肤 2020-09-10 17:57:39 +08:00
Karson 29976027fc 优化后台皮肤 2020-09-10 17:46:40 +08:00
万联科技 e37ca7506a update application/index/view/index/index.html.
首页添加备案号,防止开发期间站点被恶意投诉 “无工信部备案号标识链接”
2020-09-10 04:05:38 +08:00
Karson b7964f7aa9 优化多级菜单在移动端的显示效果
优化附件选择列表
2020-09-09 23:11:41 +08:00
HID丨emotion c3eae7b1aa Merge branch 'master' of gitee.com:karson/fastadmin into adv_multi_order 2020-09-09 15:25:47 +08:00
Karson b194c91398 优化附件选择 2020-09-09 14:48:28 +08:00
Karson 30f1702b4c 优化前台首页资源为本地加载 2020-09-09 10:28:33 +08:00
F4NNIU e9755a31d7 !234 修正 Http 请求类注释
Merge pull request !234 from F4NNIU/fix-http-comment
2020-09-09 09:23:19 +08:00
F4NNIU df72ef06fd 修正 Http 请求类注释 2020-09-09 09:22:13 +08:00
Karson a685e48ada 优化后台皮肤样式 2020-09-08 23:35:19 +08:00
Karson a1a0d0f70c 新增多个后台皮肤
全新前台默认首页
优化后台菜单折叠
优化nice-validator加载
优化压缩打包后的JS文件
2020-09-08 22:17:42 +08:00
Karson 07679a3fe3 新增后台管理面包屑开关配置
优化插件卸载删除表
优化固定列初始化样式
2020-09-04 23:26:36 +08:00
Karson adb3cc080a 新增安全过滤类 2020-09-04 17:00:48 +08:00
Karson cdd53ac377 优化安装脚本检测 2020-09-04 14:22:13 +08:00
Karson bdb9b61f24 优化前台会员中心H5下展示
优化后台菜单栏切换
优化后台Logo展示
2020-09-03 21:18:19 +08:00
Karson 4a675d5689 新增附件管理分片模式上传按钮
优化系统配置显示
2020-09-02 22:41:12 +08:00
Karson 6f56a83422 优化后台会员列表头像显示
优化后台请求方法判断
2020-09-02 21:54:10 +08:00
Karson 9d2e7f1c95 优化前台默认引入的组件样式 2020-09-02 20:28:10 +08:00
Karson a3a5707cdd 优化searchList修改后刷新事件
优化标题过长时固定宽度不生效的BUG
2020-09-02 16:48:04 +08:00
Karson b9d55fca25 优化JS分片上传默认配置
优化菜单规则和分组JS安全配置
2020-09-02 15:48:15 +08:00
Karson 2fecaeae0b 新增开关切换确认提示功能
优化拖拽排序
2020-09-01 21:36:50 +08:00
Karson b44add7ad8 新增前台会员选择图片附件功能 2020-09-01 16:04:11 +08:00
Karson 8ddbd81d6d 新增表格列表固定列功能 2020-08-31 17:57:56 +08:00
Karson 46bd263186 新增API基类Token验证
优化后台选项卡判断
2020-08-31 14:28:57 +08:00
Karson 4493a69b80 Merge remote-tracking branch 'origin/master' 2020-08-28 14:58:52 +08:00
Karson 8058ba312b 修复注册成功后登录状态未变更的BUG
优化安装脚本跳转
2020-08-28 14:58:02 +08:00
Karson cd99b2d1f0 !232 修复附件管理模型中文件类型写死,导致语言切换无法正常读取语言包的问题
Merge pull request !232 from HID丨emotion/fix_attachment_i18n
2020-08-27 21:24:16 +08:00
HID丨emotion 2968a38abb 修复附件管理模型中文件类型写死,导致语言切换无法正常读取语言包的问题 2020-08-27 15:56:49 +08:00
Karson e31a546b48 新增记忆列表分页大小
优化插件管理列表加载
2020-08-26 22:26:18 +08:00
Karson 481256dff3 优化基类控制器Traits的方法 2020-08-23 21:12:42 +08:00
Karson 0a164777fe 新增搜索字段安全检测
修复find_in_set多值时无法查询的BUG
移除冗余查询代码
2020-08-23 12:30:26 +08:00
Karson dd83a6255e 修复分片上传在Windows下的兼容问题
优化分片上传合并失败时清除分片文件
2020-08-22 23:26:55 +08:00
Karson 260198e1cb 新增插件卸载时删除相关数据表功能 2020-08-22 20:55:13 +08:00
Karson 3d9cde96a1 新增系统配置关联字段、城市专区类型
新增自定义数组类型标题
新增多选项卡配置
新增自定义皮肤配置
2020-08-21 23:25:34 +08:00
Karson f36a3415d7 优化前台下拉列表样式 2020-08-20 15:51:49 +08:00
Karson 9ddcb1953f 新增会员中心边栏高亮检查方法
优化跨域检测方法
2020-08-19 22:23:48 +08:00
Karson da4402b44e Merge https://github.com/karsonzhang/fastadmin 2020-08-19 21:45:00 +08:00
Karson cb4c41e8bf
Merge pull request #69 from Jayin/patch-1
修复关闭路由错误
2020-08-19 21:43:51 +08:00
Karson 5ee9219627 Merge https://github.com/karsonzhang/fastadmin 2020-08-19 21:42:12 +08:00
Karson cdbcca0b0e
Merge pull request #71 from SunQifeng1988/patch-1
Update Crud.php
2020-08-19 21:40:51 +08:00
Karson 28a1321b4d !228 根据 get 参数判断活动页签
Merge pull request !228 from 开兴/edit-index-tabs
2020-08-19 21:35:13 +08:00
Karson 66e69dfd26 !227 文件、图片、权重等字段默认不加入搜索栏,字符串类型默认LIKE
Merge pull request !227 from 开兴/add-search-filter
2020-08-19 21:32:31 +08:00
Karson bae3079574 !224 修复管理入口文件名不能包含admin
Merge pull request !224 from youwo/dev
2020-08-19 21:28:12 +08:00
Karson 1c1f457e1d 新增跨域检测方法
修复本地上传后cdnurl获取不正确的BUG
2020-08-19 21:22:29 +08:00
zhuangkaixing 2012f7f9f2 根据 get 参数判断活动页签 2020-08-19 17:12:32 +08:00
zhuangkaixing 9f2aa5cd3a 文件、图片、权重等字段默认不加入搜索栏,字符串类型默认LIKE 2020-08-19 16:52:28 +08:00
HID丨emotion 1a673fc758 增加参数过滤,防止sql注入
多选字段选择多个时,再次编辑保持选择顺序不变
对参数增加过滤,防止sql注入
2020-08-18 13:35:33 +08:00
HID丨emotion 69d155b1d0 多选字段编辑时按选择顺序显示
多选字段选择多个时,再次编辑保持选择顺序不变
2020-08-18 12:37:08 +08:00
youwo 7f2ca19ef8 修复管理入口文件名不能包含admin 2020-08-17 22:44:06 +08:00
Karson 13da01a48c 新增跨页记忆已选中的行
新增多个扁平化样式按钮
优化表格高亮颜色
2020-08-16 22:36:22 +08:00
Karson 84a181be73 优化多选下拉列表初始化样式 2020-08-14 16:10:33 +08:00
Karson 3abfacb86e 优化多选下拉列表初始化样式 2020-08-14 10:13:25 +08:00
Karson 3f4e54d0dd 修复API接口错误提示
优化上传选择器优先逻辑
优化插件离线安装后续限制
优化后台头像无法保存的BUG
2020-08-14 09:46:16 +08:00
Karson ac97988661 优化文件名长度限制
优化上传文件mimetype限制
2020-08-13 23:12:47 +08:00
Karson 926e16bde6 优化分片上传配置开关和分片大小 2020-08-13 22:37:04 +08:00
Karson 1d37f23a5e 优化普通文件图片预览大小 2020-08-13 16:20:28 +08:00
Karson 285095f80f 修复上传类型配置mimetype无效的BUG 2020-08-13 16:11:13 +08:00
Karson 82966e07c3 附件上传新增分片上传按钮
修复附件列表按钮失效的BUG
修复上传单一文件无法再次上传的BUG
2020-08-13 15:13:09 +08:00
Karson 9f04fcdb66 修复分片上传未检测目录 2020-08-13 11:07:04 +08:00
Karson beccee0811 新增null或空字符串筛选过滤
新增表格列表字段renderDefault控制默认数据
2020-08-13 10:46:11 +08:00
Karson 614d88eb81 修复附件表初始化数据 2020-08-13 09:34:50 +08:00
Karson e0231e4051 !220 附件字段filename缺失
Merge pull request !220 from 放码过来/editInstallSql
2020-08-13 09:29:40 +08:00
放码过来 07234a16c8 修复上传提示没有字段filename 2020-08-12 22:57:58 +08:00
Karson ed20e5ac6f 新增菜单类upgrade方法
新增上传存储文件名功能
新增文件分片上传功能
优化上传组件及方法
优化系统配置中冗余的JS代码
优化下拉框显示样式
优化大数据列表时表格列表渲染速度
修复在PHP高版本下Token验证错误的BUG
修复在PHP高版本下会员登录页错误的BUG
修复Token::get默认值不生效的BUG
2020-08-12 21:49:44 +08:00
Karson e29a9e41fc Merge branch 'master' of https://gitee.com/karson/fastadmin 2020-08-12 21:16:55 +08:00
Karson 049e719d89 !219 随机类注释错误
Merge pull request !219 from 放码过来/editNotes
2020-08-12 21:16:36 +08:00
Karson d101bcd3e6 Merge branch 'master' of https://gitee.com/karson/fastadmin 2020-08-12 21:07:19 +08:00
放码过来 af3aa231f8 update extend/fast/Random.php. 2020-08-12 21:03:17 +08:00
Karson 541a182a7e !215 修复生成API文档相同分组方法名相同被覆盖问题
Merge pull request !215 from HID丨emotion/fix_api_same_method
2020-08-12 20:48:09 +08:00
Karson c5da47b16b !217 update application/admin/library/Auth.php.
Merge pull request !217 from sixXing/N/A
2020-08-12 20:39:36 +08:00
zq 6d34058826 '随机类字符错误' 2020-08-12 16:38:22 +08:00
sixXing dbf47c182a update application/admin/library/Auth.php.
解决同一时间只能在一个地方登录的时候token清空导致两边都挤掉的BUG
2020-08-10 16:04:47 +08:00
孙奇峰 1dfbc62783
Update Crud.php
There is a mistake when the amount of relationModel more than one
2020-08-06 22:19:46 +08:00
Karson 0d800cbbb0 Merge branch 'master' of https://gitee.com/karson/fastadmin 2020-08-06 21:55:20 +08:00
Karson df183a86e4 !214 解决Config系统配置自定义类型字段定界符被修改后保存到数据库导致编辑后无法正常替换定界符得问题
Merge pull request !214 from Twhmr/master
2020-08-06 21:47:23 +08:00
twhmr ac7f3f2690 update application/common/library/Token.php. 2020-08-03 14:48:55 +08:00
HID丨emotion 2786259135 修复生成API文档相同分组方法名相同被覆盖问题
修复如两个Controller使用同一个API分组,相同的方法名会产生覆盖的问题
2020-08-01 14:58:33 +08:00
twhmr b6aaaeaebe update application/admin/view/general/config/index.html.
修改自定义类型的显示字段名extend为extend_html
2020-07-31 10:47:58 +08:00
twhmr 5e908498bd update application/common/model/Config.php.
新增额外属性 extend_html,用来解决直接替换extend的预定义定界符被篡改并保存进数据库的问题的问题
2020-07-31 10:46:43 +08:00
Karson fc701cb901 恢复cookie的httponly默认设置 2020-07-20 16:05:57 +08:00
Caiqy 83ae127480 补充Auth兼容调用user模型的属性 2020-07-10 18:26:07 +08:00
Jayin Ton a6b4a1d355
修复关闭路由错误 2020-07-06 16:16:13 +08:00
Karson bcd1b7fb9c 恢复cookie的httponly默认设置 2020-06-14 21:28:44 +08:00
Karson 6657f92fe6 更新easywechat依赖 2020-06-13 09:32:54 +08:00
Karson d901af60e8 Merge https://github.com/karsonzhang/fastadmin 2020-06-12 18:02:20 +08:00
Karson 3cae744a00 新增会员分组、权限规则、会员编辑Token验证
新增分类编辑Token验证
新增后台禁用Referer携带
新增弹窗自定义关闭按钮事件
新增后台安全提示
新增插件伪静态优先级配置
新增插件卸载移除空目录
修复语言包更新后不生效的BUG
修复fa_area和fa_version表不存在的BUG
修复编辑会员日期错误的BUG
修复会员删除事件未触发的BUG
修复页面跳转BUG
修复后台左侧菜单指示未切换的BUG
修复Bootstrap-Table切换语言不生效的BUG
更新PHPMailer版本
移除EasyWechat和Qrcode依赖
优化本地插件加载速度
2020-06-12 17:59:05 +08:00
Karson 431ac47172
Merge pull request #66 from zhuangkaixing/fix-import
修复 crud 生成的 js 缺少导入连接,控制器缺少导入方法
2020-06-09 15:46:04 +08:00
Karson 1a5661f994 !202 修复多语言问题
Merge pull request !202 from 萤火虫/master
2020-06-09 15:41:09 +08:00
Karson 27d20e2fca !205 修复插件安装时不识别权重排序
Merge pull request !205 from lidongtony/master
2020-06-03 21:13:03 +08:00
lidongtony 3c17401985 fix the weigh of menu 2020-06-03 14:55:09 +08:00
萤火虫 8fb48352ed 修复Bug: 关闭Debug的情况下,切换语言时,请求语言包的url没有变化,使得浏览器使用了缓存,导致没能成功切换语言 2020-05-25 16:00:02 +08:00
Karson d3a1c3978e !189 Api模块lang目录下文件/控制器若定义为_分割,后台一键生成Api文档,无法忽略控制器和方法
Merge pull request !189 from twhmr/master
2020-05-24 09:17:41 +08:00
Karson ce706fde18 !199 后台无控制台权限用户 不显示内容窗口控制台按钮
Merge pull request !199 from HID丨emotion/fix_dashboard_auth
2020-05-24 09:14:03 +08:00
HID丨emotion 4d1b5db9f2 后台无控制台权限用户 不显示内容窗口控制台按钮 2020-05-22 09:01:40 +08:00
F4NNIU cf4949db77 !196 注册时防止昵称重复
Merge pull request !196 from F4NNIU/user_register_improvement
2020-05-16 10:35:22 +08:00
F4NNIU 36d062d612 注册时防止昵称重复 2020-05-15 17:35:51 +08:00
F4NNIU 8c99271e66 !195 改善前台用户设置
Merge pull request !195 from F4NNIU/user_profile_improvement
2020-05-15 08:21:50 +08:00
F4NNIU 6c7b53a9d7 !194 修复通用搜索为 BETWEEN 时 ID 重复的问题
Merge pull request !194 from F4NNIU/fix_common_search_between_id
2020-05-15 08:20:40 +08:00
F4NNIU 7065215109 !191 修正插件管理弹窗在手机中适应手机宽高
Merge pull request !191 from Young小杰/master
2020-05-14 14:21:57 +08:00
F4NNIU 489a29f15d !193 用户管理在编辑时加验证
Merge pull request !193 from F4NNIU/user_management_improvements
2020-05-14 14:05:52 +08:00
F4NNIU 568fd153ad 改善前台用户设置防止昵称重复 2020-05-13 08:57:04 +08:00
F4NNIU caf60d8c2b 修复通用搜索为 BETWEEN 时 ID 重复的问题 2020-05-12 23:12:36 +08:00
F4NNIU 3793266280 加入字段描述 2020-05-11 09:28:14 +08:00
F4NNIU 98c37f5e2b 给用户管理在编辑时加验证 2020-05-11 01:04:42 +08:00
Karson 7e3205fd38 更新版本号 2020-05-06 19:39:28 +08:00
zhuangkaixing 87aa1dcafe 修复 crud 生成的 js 缺少导入连接,控制器缺少导入方法 2020-05-05 10:56:56 +08:00
Karson b06d963a4a 新增Api和Index模块下指定URL前缀不匹配路由。
修复后台图片预览一处BUG
2020-05-01 23:02:32 +08:00
1170535111@qq.com 40eb4ed86c 修正插件管理弹窗在手机中自适应宽高的问题 2020-04-29 22:54:32 +08:00
F4NNIU 1a81c45317 !190 分组表使用 utf8mb4_unicode_ci
Merge pull request !190 from F4NNIU/fix-auth-group-utf8mb4-unicode
2020-04-27 16:02:38 +08:00
F4NNIU 4346b37ab8 分组表使用 utf8mb4_unicode_ci 2020-04-27 15:59:47 +08:00
F4NNIU a588fa629a !185 修复 checkboxs
Merge pull request !185 from F4NNIU/fix-form-checkboxs
2020-04-27 12:17:54 +08:00
Twhmr e9af5be8d6 Api模块生成文档时,使用@ApiInternal需隐藏的控制器没有被隐藏 2020-04-25 10:56:44 +08:00
Twhmr d0e42a27b7 修复Api模块语言包加载不到文件名以_分割的文件 2020-04-25 10:46:44 +08:00
F4NNIU b849191a1d !187 改数据库编码为 utf8mb4
Merge pull request !187 from F4NNIU/db-utf8mb4
2020-04-24 23:48:46 +08:00
F4NNIU 713f882552 改数据库编码为 utf8mb4 2020-04-24 13:22:04 +08:00
F4NNIU f8a1c3975f 修复 checkboxs 2020-04-24 11:28:18 +08:00
Karson a97d0c9a68 !179 修复字段类型为url时列表页JS格式化未对null做处理的问题
Merge pull request !179 from HID丨emotion/fix_url_formatter
2020-04-22 19:20:00 +08:00
Karson 1dc1f7388c !173 首页加上 favicon
Merge pull request !173 from F4NNIU/fix-favicon-ico
2020-04-22 19:18:41 +08:00
Karson 3aacc8421f !180 一键生成CRUD多选字段和多图字段支持text类型
Merge pull request !180 from HID丨emotion/adv_crud
2020-04-22 19:17:44 +08:00
Karson bfaddd1832 !182 update application/index/view/index/index.html.
Merge pull request !182 from jason-张百万/N/A
2020-04-22 19:12:54 +08:00
Karson 327f2a2707 !171 不打开新的窗口
Merge pull request !171 from F4NNIU/fix-home-href
2020-04-22 19:10:56 +08:00
途仕网络 37d77a6e37 update application/index/view/index/index.html.
增加个双引号 jason-张百万2020-4-18
2020-04-18 17:33:53 +08:00
HID丨emotion 8443d2e7c5 修复字段类型为url时列表页JS格式化未对null做处理的问题
修复字段类型为url时列表页JS格式化未对null做处理的问题
2020-03-24 12:20:43 +08:00
HID丨emotion 7e73e0b562 一键生成CRUD多选字段和多图字段支持text类型
解决当字段类型为多选项或多图片时varchar(255)不够存储的情况,数据库字段使用text符合多选字段名或多图片规则时依然生成多选菜单。
2020-03-24 12:18:37 +08:00
Karson 290bfc4f75 新增邮件抄送、附件方法
更新PHPMailer到6.0版本
2020-03-06 14:32:41 +08:00
Karson 30c695ff61 修复列表开关组件未兼容旧版本BUG 2020-03-01 15:52:56 +08:00
F4NNIU b3d8877ead 首页加上 favicon 2020-03-01 15:20:01 +08:00
F4NNIU 1b3c22ead2 不打开新的窗口 2020-02-29 00:01:06 +08:00
kingang fa088b1897 增加可选api生成文档 2020-01-02 22:59:57 +08:00
kingang efc92f71a9 增加可选api生成文档 2019-12-21 15:10:05 +08:00
kingang 63e0fb3fd5 增加可选api生成文档 2019-12-21 15:04:13 +08:00
305 changed files with 26322 additions and 31141 deletions

View File

@ -5,6 +5,7 @@
"file-saver", "file-saver",
"html2canvas", "html2canvas",
"jspdf", "jspdf",
"jspdf-autotable" "jspdf-autotable",
"pdfmake"
] ]
} }

View File

@ -0,0 +1,22 @@
### 类型
类型(问题/建议/其他):?
### 现象
现象(请详细描述一下复现过程):?
### 期望结果
期望结果(请详细描述一下你说期望的结果):?
### 环境
(请详细说明一下你的运行环境)
- 操作系统Linux/Windows/Other
- Web ServerNGINX/Apache/Other
- PHP 版本7.2/7.3/7.4/8.0/8.1/8.2/Other
- MySQL 版本(5.6/5.7/8.0/Other)
- 服务器面板BT/phpStudy/XAMPP/其他/无):?
- FastAdmin 版本:?
- 浏览器Chrome/IE/Edge/其他):?
- 报错信息:?

3
.gitignore vendored
View File

@ -3,7 +3,6 @@
/vendor/ /vendor/
/runtime/* /runtime/*
/addons/* /addons/*
/application/admin/command/Install/*.lock
/public/assets/libs/ /public/assets/libs/
/public/assets/addons/* /public/assets/addons/*
/public/uploads/* /public/uploads/*
@ -15,3 +14,5 @@ composer.lock
.env .env
.svn .svn
.vscode .vscode
node_modules
.user.ini

View File

@ -1,4 +1,4 @@
FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。 FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。
## 主要特性 ## 主要特性
@ -17,18 +17,17 @@ FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。
* 基于`Bootstrap`开发自适应手机、平板、PC * 基于`Bootstrap`开发自适应手机、平板、PC
* 基于`RequireJS`进行JS模块管理按需加载 * 基于`RequireJS`进行JS模块管理按需加载
* 基于`Less`进行样式开发 * 基于`Less`进行样式开发
* 基于`Bower`进行前端组件包管理
* 强大的插件扩展功能,在线安装卸载升级插件 * 强大的插件扩展功能,在线安装卸载升级插件
* 通用的会员模块和API模块 * 通用的会员模块和API模块
* 共用同一账号体系的Web端会员中心权限验证和API接口会员权限验证 * 共用同一账号体系的Web端会员中心权限验证和API接口会员权限验证
* 二级域名部署支持,同时域名支持绑定到插件 * 二级域名部署支持,同时域名支持绑定到应用插件
* 多语言支持,服务端及客户端支持 * 多语言支持,服务端及客户端支持
* 强大的第三方模块支持([CMS](https://www.fastadmin.net/store/cms.html)、[博客](https://www.fastadmin.net/store/blog.html)、[知识付费问答](https://www.fastadmin.net/store/ask.html)、[在线投票系统](https://www.fastadmin.net/store/vote.html)) * 支持大文件分片上传、剪切板粘贴上传、拖拽上传,进度条显示,图片上传前压缩
* 支持CMS、博客、知识付费问答无缝整合[Xunsearch全文搜索](https://www.fastadmin.net/store/xunsearch.html) * 支持表格固定列、固定表头、跨页选择、Excel导出、模板渲染等功能
* 第三方小程序支持([预订小程序](https://www.fastadmin.net/store/ball.html)、[问答小程序](https://www.fastadmin.net/store/questions.html)、[活动报名小程序](https://www.fastadmin.net/store/huodong.html)、[商城小程序](https://www.fastadmin.net/store/xshop.html)、[博客小程序](https://www.fastadmin.net/store/blog.html)) * 强大的第三方应用模块支持([CMS](https://www.fastadmin.net/store/cms.html)、[CRM](https://www.fastadmin.net/store/facrm.html)、[企业网站管理系统](https://www.fastadmin.net/store/ldcms.html)、[知识库文档系统](https://www.fastadmin.net/store/knowbase.html)、[在线投票系统](https://www.fastadmin.net/store/vote.html)、[B2C商城](https://www.fastadmin.net/store/shopro.html)、[B2B2C商城](https://www.fastadmin.net/store/wanlshop.html))
* 整合第三方短信接口(阿里云、腾讯云短信) * 整合第三方短信接口(阿里云、腾讯云短信)
* 无缝整合第三方云存储(七牛、阿里云OSS、又拍云)功能 * 无缝整合第三方云存储(七牛、阿里云OSS、腾讯云存储、又拍云)功能,支持云储存分片上传
* 第三方富文本编辑器支持(Summernote、Kindeditor、百度编辑器) * 第三方富文本编辑器支持(Summernote、百度编辑器)
* 第三方登录(QQ、微信、微博)整合 * 第三方登录(QQ、微信、微博)整合
* 第三方支付(微信、支付宝)无缝整合微信支持PC端扫码支付 * 第三方支付(微信、支付宝)无缝整合微信支持PC端扫码支付
* 丰富的插件应用市场 * 丰富的插件应用市场
@ -48,15 +47,13 @@ https://demo.fastadmin.net
提 示:演示站数据无法进行修改,请下载源码安装体验全部功能 提 示:演示站数据无法进行修改,请下载源码安装体验全部功能
## 界面截图 ## 界面截图
![控制台](https://gitee.com/uploads/images/2017/0411/113717_e99ff3e7_10933.png "控制台") ![控制台](https://images.gitee.com/uploads/images/2020/0929/202947_8db2d281_10933.gif "控制台")
## 问题反馈 ## 问题反馈
在使用中有任何问题,请使用以下联系方式联系我们 在使用中有任何问题,请使用以下联系方式联系我们
交流社区: https://ask.fastadmin.net 问答社区: https://ask.fastadmin.net
QQ群: [636393962](https://jq.qq.com/?_wv=1027&k=487PNBb)(满) [708784003](https://jq.qq.com/?_wv=1027&k=5ObjtwM)(满) [964776039](https://jq.qq.com/?_wv=1027&k=59qjU2P)(3群) [749803490](https://jq.qq.com/?_wv=1027&k=5tczi88)(满) [767103006](https://jq.qq.com/?_wv=1027&k=5Z1U751)(满) [675115483](https://jq.qq.com/?_wv=1027&k=54I6mts)(6群)
Github: https://github.com/karsonzhang/fastadmin Github: https://github.com/karsonzhang/fastadmin
@ -80,6 +77,10 @@ Nice-validator: https://validator.niceue.com
SelectPage: https://github.com/TerryZ/SelectPage SelectPage: https://github.com/TerryZ/SelectPage
Layer: https://layuion.com/layer/
DropzoneJS: https://www.dropzonejs.com
## 版权信息 ## 版权信息
@ -87,6 +88,6 @@ FastAdmin遵循Apache2开源协议发布并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。 本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2017-2020 by FastAdmin (https://www.fastadmin.net) 版权所有Copyright © 2017-2024 by FastAdmin (https://www.fastadmin.net)
All rights reserved。 All rights reserved。

1
addons/.htaccess 100755
View File

@ -0,0 +1 @@
deny from all

View File

@ -4,9 +4,10 @@ namespace app\admin\behavior;
class AdminLog class AdminLog
{ {
public function run(&$params) public function run(&$response)
{ {
if (request()->isPost()) { //只记录POST请求的日志
if (request()->isPost() && config('fastadmin.auto_record_log')) {
\app\admin\model\AdminLog::record(); \app\admin\model\AdminLog::record();
} }
} }

View File

@ -15,23 +15,24 @@ use think\exception\PDOException;
class Addon extends Command class Addon extends Command
{ {
protected function configure() protected function configure()
{ {
$this $this
->setName('addon') ->setName('addon')
->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null) ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package/move)', 'create') ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/uninstall/refresh/package/move)', 'create')
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null) ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null) ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null) ->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null) ->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
->addOption('domain', 'd', Option::VALUE_OPTIONAL, 'domain', null)
->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local package', null) ->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local package', null)
->setDescription('Addon manager'); ->setDescription('Addon manager');
} }
protected function execute(Input $input, Output $output) protected function execute(Input $input, Output $output)
{ {
\think\Config::load(dirname(dirname(__FILE__)) . DS . 'config.php');
$name = $input->getOption('name') ?: ''; $name = $input->getOption('name') ?: '';
$action = $input->getOption('action') ?: ''; $action = $input->getOption('action') ?: '';
if (stripos($name, 'addons' . DS) !== false) { if (stripos($name, 'addons' . DS) !== false) {
@ -48,7 +49,7 @@ class Addon extends Command
include dirname(__DIR__) . DS . 'common.php'; include dirname(__DIR__) . DS . 'common.php';
if (!$name) { if (!$name && !in_array($action, ['refresh'])) {
throw new Exception('Addon name could not be empty'); throw new Exception('Addon name could not be empty');
} }
if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package', 'move'])) { if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package', 'move'])) {
@ -81,14 +82,13 @@ class Addon extends Command
$createTableSql = $result[0]['Create Table']; $createTableSql = $result[0]['Create Table'];
} }
} catch (PDOException $e) { } catch (PDOException $e) {
} }
$data = [ $data = [
'name' => $name, 'name' => $name,
'addon' => $name, 'addon' => $name,
'addonClassName' => ucfirst($name), 'addonClassName' => ucfirst($name),
'addonInstallMenu' => $createMenu ? "\$menu = " . var_export_short($createMenu, "\t") . ";\n\tMenu::create(\$menu);" : '', 'addonInstallMenu' => $createMenu ? "\$menu = " . var_export_short($createMenu) . ";\n\tMenu::create(\$menu);" : '',
'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '', 'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '',
'addonEnableMenu' => $menuList ? 'Menu::enable("' . $name . '");' : '', 'addonEnableMenu' => $menuList ? 'Menu::enable("' . $name . '");' : '',
'addonDisableMenu' => $menuList ? 'Menu::disable("' . $name . '");' : '', 'addonDisableMenu' => $menuList ? 'Menu::disable("' . $name . '");' : '',
@ -132,42 +132,6 @@ class Addon extends Command
} }
$output->info(ucfirst($action) . " Successed!"); $output->info(ucfirst($action) . " Successed!");
break; break;
case 'install':
//非覆盖模式时如果存在则报错
if (is_dir($addonDir) && !$force) {
throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
}
//如果存在先移除
if (is_dir($addonDir)) {
rmdirs($addonDir);
}
// 获取本地路径
$local = $input->getOption('local');
try {
Service::install($name, 0, ['version' => $release], $local);
} catch (AddonException $e) {
if ($e->getCode() != -3) {
throw new Exception($e->getMessage());
}
if (!$force) {
//如果有冲突文件则提醒
$data = $e->getData();
foreach ($data['conflictlist'] as $k => $v) {
$output->warning($v);
}
$output->info("Are you sure you want to override all those files? Type 'yes' to continue: ");
$line = fgets(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'));
if (trim($line) != 'yes') {
throw new Exception("Operation is aborted!");
}
}
Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token], $local);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
$output->info("Install Successed!");
break;
case 'uninstall': case 'uninstall':
//非覆盖模式时如果存在则报错 //非覆盖模式时如果存在则报错
if (!$force) { if (!$force) {
@ -202,10 +166,6 @@ class Addon extends Command
Service::refresh(); Service::refresh();
$output->info("Refresh Successed!"); $output->info("Refresh Successed!");
break; break;
case 'upgrade':
Service::upgrade($name, ['version' => $release, 'uid' => $uid, 'token' => $token]);
$output->info("Upgrade Successed!");
break;
case 'package': case 'package':
$infoFile = $addonDir . 'info.ini'; $infoFile = $addonDir . 'info.ini';
if (!is_file($infoFile)) { if (!is_file($infoFile)) {
@ -216,12 +176,12 @@ class Addon extends Command
if (!$info) { if (!$info) {
throw new Exception(__('Addon info file data incorrect')); throw new Exception(__('Addon info file data incorrect'));
} }
$infoname = isset($info['name']) ? $info['name'] : ''; $infoname = $info['name'] ?? '';
if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) { if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) {
throw new Exception(__('Addon info name incorrect')); throw new Exception(__('Addon info name incorrect'));
} }
$infoversion = isset($info['version']) ? $info['version'] : ''; $infoversion = $info['version'] ?? '';
if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) { if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) {
throw new Exception(__('Addon info version incorrect')); throw new Exception(__('Addon info version incorrect'));
} }
@ -256,8 +216,8 @@ class Addon extends Command
case 'move': case 'move':
$movePath = [ $movePath = [
'adminOnlySelfDir' => ['admin/behavior', 'admin/controller', 'admin/library', 'admin/model', 'admin/validate', 'admin/view'], 'adminOnlySelfDir' => ['admin/behavior', 'admin/controller', 'admin/library', 'admin/model', 'admin/validate', 'admin/view'],
'adminAllSubDir' => ['admin/lang'], 'adminAllSubDir' => ['admin/lang'],
'publicDir' => ['public/assets/addons', 'public/assets/js/backend'] 'publicDir' => ['public/assets/addons', 'public/assets/js/backend']
]; ];
$paths = []; $paths = [];
$appPath = str_replace('/', DS, APP_PATH); $appPath = str_replace('/', DS, APP_PATH);
@ -350,7 +310,7 @@ class Addon extends Command
/** /**
* 写入到文件 * 写入到文件
* @param string $name * @param string $name
* @param array $data * @param array $data
* @param string $pathname * @param string $pathname
* @return mixed * @return mixed
*/ */
@ -379,5 +339,4 @@ class Addon extends Command
{ {
return __DIR__ . '/Addon/stubs/' . $name . '.stub'; return __DIR__ . '/Addon/stubs/' . $name . '.stub';
} }
} }

View File

@ -51,18 +51,4 @@ class {%addonClassName%} extends Addons
return true; return true;
} }
/**
* 实现钩子方法
* @return mixed
*/
public function testhook($param)
{
// 调用钩子时候的参数信息
print_r($param);
// 当前插件的配置信息配置信息存在当前目录的config.php文件中见下方
print_r($this->getConfig());
// 可以返回模板,模板文件默认读取的为插件目录中的文件。模板名不能为空!
//return $this->fetch('view/info');
}
} }

View File

@ -3,17 +3,21 @@
return [ return [
[ [
//配置唯一标识 //配置唯一标识
'name' => 'usernmae', 'name' => 'username',
//显示的标题 //显示的标题
'title' => '用户名', 'title' => '用户名',
//类型 //类型
'type' => 'string', 'type' => 'string',
//分组
'group' => '',
//动态显示
'visible' => '',
//数据字典 //数据字典
'content' => [ 'content' => [
], ],
//值 //值
'value' => '', 'value' => '',
//验证规则 //验证规则
'rule' => 'required', 'rule' => 'required',
//错误消息 //错误消息
'msg' => '', 'msg' => '',

View File

@ -1,7 +1,7 @@
name = {%name%} name = {%name%}
title = 插件名称{%name%} title = 插件名称{%name%}
intro = FastAdmin插件 intro = 插件介绍
author = yourname author = yourname
website = https://www.fastadmin.net website = https://www.fastadmin.net
version = 1.0.0 version = 1.0.0
state = 1 state = 1

View File

@ -22,10 +22,11 @@ class Api extends Command
->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html') ->addOption('output', 'o', Option::VALUE_OPTIONAL, 'output index file name', 'api.html')
->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'] ?? '')
->addOption('author', 'a', Option::VALUE_OPTIONAL, 'document author', $site['name'])
->addOption('class', 'c', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'extend class', null) ->addOption('class', 'c', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'extend class', null)
->addOption('language', 'l', Option::VALUE_OPTIONAL, 'language', 'zh-cn') ->addOption('language', 'l', Option::VALUE_OPTIONAL, 'language', 'zh-cn')
->addOption('addon', 'a', Option::VALUE_OPTIONAL, 'addon name', null)
->addOption('controller', 'r', Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, 'controller name', null)
->setDescription('Build Api document from controller'); ->setDescription('Build Api document from controller');
} }
@ -36,6 +37,10 @@ class Api extends Command
$force = $input->getOption('force'); $force = $input->getOption('force');
$url = $input->getOption('url'); $url = $input->getOption('url');
$language = $input->getOption('language'); $language = $input->getOption('language');
$template = $input->getOption('template');
if (!preg_match("/^([a-z0-9]+)\.html\$/i", $template)) {
throw new Exception('template file not correct');
}
$language = $language ? $language : 'zh-cn'; $language = $language ? $language : 'zh-cn';
$langFile = $apiDir . 'lang' . DS . $language . '.php'; $langFile = $apiDir . 'lang' . DS . $language . '.php';
if (!is_file($langFile)) { if (!is_file($langFile)) {
@ -50,7 +55,7 @@ class Api extends Command
} }
// 模板文件 // 模板文件
$template_dir = $apiDir . 'template' . DS; $template_dir = $apiDir . 'template' . DS;
$template_file = $template_dir . $input->getOption('template'); $template_file = $template_dir . $template;
if (!is_file($template_file)) { if (!is_file($template_file)) {
throw new Exception('template file not found'); throw new Exception('template file not found');
} }
@ -58,51 +63,62 @@ class Api extends Command
$classes = $input->getOption('class'); $classes = $input->getOption('class');
// 标题 // 标题
$title = $input->getOption('title'); $title = $input->getOption('title');
// 作者
$author = $input->getOption('author');
// 模块 // 模块
$module = $input->getOption('module'); $module = $input->getOption('module');
// 插件
$addon = $input->getOption('addon');
$moduleDir = APP_PATH . $module . DS; $moduleDir = $addonDir = '';
if ($addon) {
$addonInfo = get_addon_info($addon);
if (!$addonInfo) {
throw new Exception('addon not found');
}
$moduleDir = ADDON_PATH . $addon . DS;
} else {
$moduleDir = APP_PATH . $module . DS;
}
if (!is_dir($moduleDir)) { if (!is_dir($moduleDir)) {
throw new Exception('module not found'); throw new Exception('module not found');
} }
if (version_compare(PHP_VERSION, '7.0.0', '<')) { if (version_compare(PHP_VERSION, '7.0.0', '<')) {
if (extension_loaded('Zend OPcache')) { throw new Exception("Requires PHP version 7.0 or newer");
$configuration = opcache_get_configuration(); }
$directives = $configuration['directives'];
$configName = request()->isCli() ? 'opcache.enable_cli' : 'opcache.enable'; //控制器名
if (!$directives[$configName]) { $controller = $input->getOption('controller') ?: [];
throw new Exception("Please make sure {$configName} is turned on, Get help:https://forum.fastadmin.net/d/1321"); if (!$controller) {
$controllerDir = $moduleDir . Config::get('url_controller_layer') . DS;
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($controllerDir),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file) {
if (!$file->isDir() && $file->getExtension() == 'php') {
$filePath = $file->getRealPath();
$classes[] = $this->getClassFromFile($filePath);
} }
} else { }
throw new Exception("Please make sure opcache already enabled, Get help:https://forum.fastadmin.net/d/1321"); } else {
foreach ($controller as $index => $item) {
$filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php';
$classes[] = $this->getClassFromFile($filePath);
} }
} }
$controllerDir = $moduleDir . Config::get('url_controller_layer') . DS;
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($controllerDir),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file) {
if (!$file->isDir() && $file->getExtension() == 'php') {
$filePath = $file->getRealPath();
$classes[] = $this->get_class_from_file($filePath);
}
}
$classes = array_unique(array_filter($classes)); $classes = array_unique(array_filter($classes));
$config = [ $config = [
'sitename' => config('site.name'), 'sitename' => config('site.name'),
'title' => $title, 'title' => $title,
'author' => $author, 'author' => config('site.name'),
'description' => '', 'description' => '',
'apiurl' => $url, 'apiurl' => $url,
'language' => $language, 'language' => $language,
]; ];
$builder = new Builder($classes); $builder = new Builder($classes);
$content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]); $content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]);
@ -113,67 +129,61 @@ class Api extends Command
} }
/** /**
* get full qualified class name * 从文件获取命名空间和类名
* *
* @param string $path_to_file * @param string $filename
* @return string * @return string
* @author JBYRNE http://jarretbyrne.com/2015/06/197/
*/ */
protected function get_class_from_file($path_to_file) protected function getClassFromFile($filename)
{ {
//Grab the contents of the file $getNext = null;
$contents = file_get_contents($path_to_file); $isNamespace = false;
$skipNext = false;
//Start with a blank namespace and class $namespace = '';
$namespace = $class = ""; $class = '';
foreach (\PhpToken::tokenize(file_get_contents($filename)) as $token) {
//Set helper values to know that we have found the namespace/class token and need to collect the string values after them if (!$token->isIgnorable()) {
$getting_namespace = $getting_class = false; $name = $token->getTokenName();
switch ($name) {
//Go through each token and evaluate it as necessary case 'T_NAMESPACE':
foreach (token_get_all($contents) as $token) { $isNamespace = true;
break;
//If this token is the namespace declaring, then flag that the next tokens will be the namespace name case 'T_EXTENDS':
if (is_array($token) && $token[0] == T_NAMESPACE) { case 'T_USE':
$getting_namespace = true; case 'T_IMPLEMENTS':
} $skipNext = true;
break;
//If this token is the class declaring, then flag that the next tokens will be the class name case 'T_CLASS':
if (is_array($token) && $token[0] == T_CLASS) { if ($skipNext) {
$getting_class = true; $skipNext = false;
} } else {
$getNext = strtolower(substr($name, 2));
//While we're grabbing the namespace name... }
if ($getting_namespace === true) { break;
case 'T_NAME_QUALIFIED':
//If the token is a string or the namespace separator... case 'T_NS_SEPARATOR':
if (is_array($token) && in_array($token[0], [T_STRING, T_NS_SEPARATOR])) { case 'T_STRING':
case ';':
//Append the token's value to the name of the namespace if ($isNamespace) {
$namespace .= $token[1]; if ($name == ';') {
} elseif ($token === ';') { $isNamespace = false;
} else {
//If the token is the semicolon, then we're done with the namespace declaration $namespace .= $token->text;
$getting_namespace = false; }
} } elseif ($skipNext) {
} $skipNext = false;
} elseif ($getNext == 'class') {
//While we're grabbing the class name... $class = $token->text;
if ($getting_class === true) { $getNext = null;
break 2;
//If the token is a string, it's the name of the class }
if (is_array($token) && $token[0] == T_STRING) { break;
default:
//Store the token's value as the class name $getNext = null;
$class = $token[1];
//Got what we need, stope here
break;
} }
} }
} }
//Build the fully-qualified class name and return it return $namespace . '\\' . $class;
return $namespace ? $namespace . '\\' . $class : $class;
} }
} }

View File

@ -16,6 +16,9 @@ return [
'Tokentips' => 'Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中', 'Tokentips' => 'Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中',
'Apiurltips' => 'API接口URL', 'Apiurltips' => 'API接口URL',
'Savetips' => '点击保存后Token和Api url都将保存在本地Localstorage中', 'Savetips' => '点击保存后Token和Api url都将保存在本地Localstorage中',
'Authorization' => '权限',
'NeedLogin' => '登录',
'NeedRight' => '鉴权',
'ReturnHeaders' => '响应头', 'ReturnHeaders' => '响应头',
'ReturnParameters' => '返回参数', 'ReturnParameters' => '返回参数',
'Response' => '响应输出', 'Response' => '响应输出',

View File

@ -7,7 +7,7 @@ use think\Config;
/** /**
* @website https://github.com/calinrada/php-apidoc * @website https://github.com/calinrada/php-apidoc
* @author Calin Rada <rada.calin@gmail.com> * @author Calin Rada <rada.calin@gmail.com>
* @author Karson <karsonzhang@163.com> * @author Karson <karson@fastadmin.net>
*/ */
class Builder class Builder
{ {
@ -43,9 +43,11 @@ class Builder
continue; continue;
} }
Extractor::getClassMethodAnnotations($class); Extractor::getClassMethodAnnotations($class);
//Extractor::getClassPropertyValues($class);
} }
$allClassAnnotation = Extractor::getAllClassAnnotations(); $allClassAnnotation = Extractor::getAllClassAnnotations();
$allClassMethodAnnotation = Extractor::getAllClassMethodAnnotations(); $allClassMethodAnnotation = Extractor::getAllClassMethodAnnotations();
//$allClassPropertyValue = Extractor::getAllClassPropertyValues();
// foreach ($allClassMethodAnnotation as $className => &$methods) { // foreach ($allClassMethodAnnotation as $className => &$methods) {
// foreach ($methods as &$method) { // foreach ($methods as &$method) {
@ -68,11 +70,11 @@ class Builder
$headerslist = array(); $headerslist = array();
foreach ($docs['ApiHeaders'] as $params) { foreach ($docs['ApiHeaders'] as $params) {
$tr = array( $tr = array(
'name' => $params['name'], 'name' => $params['name'] ?? '',
'type' => $params['type'], 'type' => $params['type'] ?? 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '', 'sample' => $params['sample'] ?? '',
'required' => isset($params['required']) ? $params['required'] : false, 'required' => $params['required'] ?? false,
'description' => isset($params['description']) ? $params['description'] : '', 'description' => $params['description'] ?? '',
); );
$headerslist[] = $tr; $headerslist[] = $tr;
} }
@ -86,14 +88,20 @@ class Builder
return []; return [];
} }
$typeArr = [
'integer' => 'number',
'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');
$tr = array( $tr = array(
'name' => $params['name'], 'name' => $params['name'],
'type' => isset($params['type']) ? $params['type'] : 'string', 'type' => $params['type'] ?? 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '', 'inputtype' => $inputtype,
'required' => isset($params['required']) ? $params['required'] : true, 'sample' => $params['sample'] ?? '',
'description' => isset($params['description']) ? $params['description'] : '', 'required' => $params['required'] ?? true,
'description' => $params['description'] ?? '',
); );
$paramslist[] = $tr; $paramslist[] = $tr;
} }
@ -110,11 +118,11 @@ class Builder
$headerslist = array(); $headerslist = array();
foreach ($docs['ApiReturnHeaders'] as $params) { foreach ($docs['ApiReturnHeaders'] as $params) {
$tr = array( $tr = array(
'name' => $params['name'], 'name' => $params['name'] ?? '',
'type' => 'string', 'type' => 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '', 'sample' => $params['sample'] ?? '',
'required' => isset($params['required']) && $params['required'] ? 'Yes' : 'No', 'required' => isset($params['required']) && $params['required'] ? 'Yes' : 'No',
'description' => isset($params['description']) ? $params['description'] : '', 'description' => $params['description'] ?? '',
); );
$headerslist[] = $tr; $headerslist[] = $tr;
} }
@ -131,10 +139,10 @@ class Builder
$paramslist = array(); $paramslist = array();
foreach ($st_params['ApiReturnParams'] as $params) { foreach ($st_params['ApiReturnParams'] as $params) {
$tr = array( $tr = array(
'name' => $params['name'], 'name' => $params['name'] ?? '',
'type' => isset($params['type']) ? $params['type'] : 'string', 'type' => $params['type'] ?? 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '', 'sample' => $params['sample'] ?? '',
'description' => isset($params['description']) ? $params['description'] : '', 'description' => $params['description'] ?? '',
); );
$paramslist[] = $tr; $paramslist[] = $tr;
} }
@ -162,10 +170,16 @@ class Builder
list($allClassAnnotations, $allClassMethodAnnotations) = $this->extractAnnotations(); list($allClassAnnotations, $allClassMethodAnnotations) = $this->extractAnnotations();
$sectorArr = []; $sectorArr = [];
foreach ($allClassAnnotations as $index => $allClassAnnotation) { foreach ($allClassAnnotations as $index => &$allClassAnnotation) {
// 如果设置隐藏,则不显示在文档
if (isset($allClassAnnotation['ApiInternal'])) {
continue;
}
$sector = isset($allClassAnnotation['ApiSector']) ? $allClassAnnotation['ApiSector'][0] : $allClassAnnotation['ApiTitle'][0]; $sector = isset($allClassAnnotation['ApiSector']) ? $allClassAnnotation['ApiSector'][0] : $allClassAnnotation['ApiTitle'][0];
$sectorArr[$sector] = isset($allClassAnnotation['ApiWeigh']) ? $allClassAnnotation['ApiWeigh'][0] : 0; $sectorArr[$sector] = isset($allClassAnnotation['ApiWeigh']) ? $allClassAnnotation['ApiWeigh'][0] : 0;
} }
unset($allClassAnnotation);
arsort($sectorArr); arsort($sectorArr);
$routes = include_once CONF_PATH . 'route.php'; $routes = include_once CONF_PATH . 'route.php';
$subdomain = false; $subdomain = false;
@ -175,7 +189,7 @@ class Builder
$counter = 0; $counter = 0;
$section = null; $section = null;
$weigh = 0; $weigh = 0;
$docslist = []; $docsList = [];
foreach ($allClassMethodAnnotations as $class => $methods) { foreach ($allClassMethodAnnotations as $class => $methods) {
foreach ($methods as $name => $docs) { foreach ($methods as $name => $docs) {
if (isset($docs['ApiSector'][0])) { if (isset($docs['ApiSector'][0])) {
@ -190,28 +204,30 @@ class Builder
if ($subdomain) { if ($subdomain) {
$route = substr($route, 4); $route = substr($route, 4);
} }
$docslist[$section][$name] = [ $docsList[$section][$name] = [
'id' => $counter, 'id' => $counter,
'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0], 'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0],
'method_label' => $this->generateBadgeForMethod($docs), 'methodLabel' => $this->generateBadgeForMethod($docs),
'section' => $section, 'section' => $section,
'route' => $route, 'route' => $route,
'title' => is_array($docs['ApiTitle'][0]) ? $docs['ApiTitle'][0]['data'] : $docs['ApiTitle'][0], 'title' => is_array($docs['ApiTitle'][0]) ? $docs['ApiTitle'][0]['data'] : $docs['ApiTitle'][0],
'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0], 'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0],
'body' => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '', 'body' => isset($docs['ApiBody'][0]) ? (is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0]) : '',
'headerslist' => $this->generateHeadersTemplate($docs), 'headersList' => $this->generateHeadersTemplate($docs),
'paramslist' => $this->generateParamsTemplate($docs), 'paramsList' => $this->generateParamsTemplate($docs),
'returnheaderslist' => $this->generateReturnHeadersTemplate($docs), 'returnHeadersList' => $this->generateReturnHeadersTemplate($docs),
'returnparamslist' => $this->generateReturnParamsTemplate($docs), 'returnParamsList' => $this->generateReturnParamsTemplate($docs),
'weigh' => is_array($docs['ApiWeigh'][0]) ? $docs['ApiWeigh'][0]['data'] : $docs['ApiWeigh'][0], 'weigh' => is_array($docs['ApiWeigh'][0]) ? $docs['ApiWeigh'][0]['data'] : $docs['ApiWeigh'][0],
'return' => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '', 'return' => isset($docs['ApiReturn']) ? (is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0]) : '',
'needLogin' => $docs['ApiPermissionLogin'][0],
'needRight' => $docs['ApiPermissionRight'][0],
]; ];
$counter++; $counter++;
} }
} }
//重建排序 //重建排序
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] = isset($method['weigh']) ? $method['weigh'] : 0;
@ -219,9 +235,8 @@ class Builder
arsort($methodSectorArr); arsort($methodSectorArr);
$methods = array_merge(array_flip(array_keys($methodSectorArr)), $methods); $methods = array_merge(array_flip(array_keys($methodSectorArr)), $methods);
} }
$docslist = array_merge(array_flip(array_keys($sectorArr)), $docslist); $docsList = array_merge(array_flip(array_keys($sectorArr)), $docsList);
return $docsList;
return $docslist;
} }
public function getView() public function getView()
@ -237,8 +252,8 @@ 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]));
} }
} }

View File

@ -24,6 +24,8 @@ class Extractor
private static $classMethodAnnotationCache; private static $classMethodAnnotationCache;
private static $classPropertyValueCache;
/** /**
* Indicates that annotations should has strict behavior, 'false' by default * Indicates that annotations should has strict behavior, 'false' by default
* @var boolean * @var boolean
@ -66,14 +68,16 @@ class Extractor
/** /**
* Gets all anotations with pattern @SomeAnnotation() from a given class * Gets all anotations with pattern @SomeAnnotation() from a given class
* *
* @param string $className class name to get annotations * @param string $className class name to get annotations
* @return array self::$classAnnotationCache all annotated elements * @return array self::$classAnnotationCache all annotated elements
*/ */
public static function getClassAnnotations($className) public static function getClassAnnotations($className)
{ {
if (!isset(self::$classAnnotationCache[$className])) { if (!isset(self::$classAnnotationCache[$className])) {
$class = new \ReflectionClass($className); $class = new \ReflectionClass($className);
self::$classAnnotationCache[$className] = self::parseAnnotations($class->getDocComment()); $annotationArr = self::parseAnnotations($class->getDocComment());
$annotationArr['ApiTitle'] = !isset($annotationArr['ApiTitle'][0]) || !trim($annotationArr['ApiTitle'][0]) ? [$class->getShortName()] : $annotationArr['ApiTitle'];
self::$classAnnotationCache[$className] = $annotationArr;
} }
return self::$classAnnotationCache[$className]; return self::$classAnnotationCache[$className];
@ -96,6 +100,17 @@ class Extractor
return self::$classMethodAnnotationCache[$className]; return self::$classMethodAnnotationCache[$className];
} }
public static function getClassPropertyValues($className)
{
$class = new \ReflectionClass($className);
foreach ($class->getProperties() as $object) {
self::$classPropertyValueCache[$className][$object->name] = self::getClassPropertyValue($className, $object->name);
}
return self::$classMethodAnnotationCache[$className];
}
public static function getAllClassAnnotations() public static function getAllClassAnnotations()
{ {
return self::$classAnnotationCache; return self::$classAnnotationCache;
@ -106,11 +121,25 @@ class Extractor
return self::$classMethodAnnotationCache; return self::$classMethodAnnotationCache;
} }
public static function getAllClassPropertyValues()
{
return self::$classPropertyValueCache;
}
public static function getClassPropertyValue($className, $property)
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$reflectionClass = new \ReflectionClass($className);
$reflectionProperty = $reflectionClass->getProperty($property);
$reflectionProperty->setAccessible(true);
return $reflectionProperty->getValue($reflectionClass->newInstanceWithoutConstructor());
}
/** /**
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
* *
* @param string $className class name * @param string $className class name
* @param string $methodName method name to get annotations * @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated elements of a method given * @return array self::$annotationCache all annotated elements of a method given
*/ */
public static function getMethodAnnotations($className, $methodName) public static function getMethodAnnotations($className, $methodName)
@ -138,8 +167,8 @@ class Extractor
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class * Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
* and instance its abcAnnotation class * and instance its abcAnnotation class
* *
* @param string $className class name * @param string $className class name
* @param string $methodName method name to get annotations * @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated objects of a method given * @return array self::$annotationCache all annotated objects of a method given
*/ */
public function getMethodAnnotationsObjects($className, $methodName) public function getMethodAnnotationsObjects($className, $methodName)
@ -189,14 +218,18 @@ class Extractor
$methodName = $method->getName(); $methodName = $method->getName();
$methodAnnotations = self::parseAnnotations($docblockMethod); $methodAnnotations = self::parseAnnotations($docblockMethod);
$methodAnnotations['ApiTitle'] = !isset($methodAnnotations['ApiTitle'][0]) || !trim($methodAnnotations['ApiTitle'][0]) ? [$method->getName()] : $methodAnnotations['ApiTitle'];
$classAnnotations = self::parseAnnotations($dockblockClass); $classAnnotations = self::parseAnnotations($dockblockClass);
$classAnnotations['ApiTitle'] = !isset($classAnnotations['ApiTitle'][0]) || !trim($classAnnotations['ApiTitle'][0]) ? [$class->getShortName()] : $classAnnotations['ApiTitle'];
if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') { if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') {
return []; return [];
} }
$properties = $class->getDefaultProperties(); $properties = $class->getDefaultProperties();
$noNeedLogin = isset($properties['noNeedLogin']) ? is_array($properties['noNeedLogin']) ? $properties['noNeedLogin'] : [$properties['noNeedLogin']] : []; $noNeedLogin = isset($properties['noNeedLogin']) ? (is_array($properties['noNeedLogin']) ? $properties['noNeedLogin'] : [$properties['noNeedLogin']]) : [];
$noNeedRight = isset($properties['noNeedRight']) ? is_array($properties['noNeedRight']) ? $properties['noNeedRight'] : [$properties['noNeedRight']] : []; $noNeedRight = isset($properties['noNeedRight']) ? (is_array($properties['noNeedRight']) ? $properties['noNeedRight'] : [$properties['noNeedRight']]) : [];
preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $docblockMethod), $methodArr); preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $docblockMethod), $methodArr);
preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $dockblockClass), $classArr); preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $dockblockClass), $classArr);
@ -264,15 +297,15 @@ class Extractor
} }
} }
$methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)]; $methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)];
$methodAnnotations['ApiPermissionRight'] = [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)]; $methodAnnotations['ApiPermissionRight'] = !$methodAnnotations['ApiPermissionLogin'][0] ? [false] : [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)];
return $methodAnnotations; return $methodAnnotations;
} }
/** /**
* Parse annotations * Parse annotations
* *
* @param string $docblock * @param string $docblock
* @param string $name * @param string $name
* @return array parsed annotations params * @return array parsed annotations params
*/ */
private static function parseCustomAnnotations($docblock, $name = 'param') private static function parseCustomAnnotations($docblock, $name = 'param')
@ -291,7 +324,7 @@ class Extractor
/** /**
* Parse annotations * Parse annotations
* *
* @param string $docblock * @param string $docblock
* @return array parsed annotations params * @return array parsed annotations params
*/ */
private static function parseAnnotations($docblock) private static function parseAnnotations($docblock)
@ -337,7 +370,7 @@ class Extractor
/** /**
* Parse individual annotation arguments * Parse individual annotation arguments
* *
* @param string $content arguments string * @param string $content arguments string
* @return array annotated arguments * @return array annotated arguments
*/ */
private static function parseArgs($content) private static function parseArgs($content)
@ -480,8 +513,8 @@ class Extractor
/** /**
* Try determinate the original type variable of a string * Try determinate the original type variable of a string
* *
* @param string $val string containing possibles variables that can be cast to bool or int * @param string $val string containing possibles variables that can be cast to bool or int
* @param boolean $trim indicate if the value passed should be trimmed after to try cast * @param boolean $trim indicate if the value passed should be trimmed after to try cast
* @return mixed returns the value converted to original type if was possible * @return mixed returns the value converted to original type if was possible
*/ */
private static function castValue($val, $trim = false) private static function castValue($val, $trim = false)

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{$config.language}"> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -8,15 +8,15 @@
<title>{$config.title}</title> <title>{$config.title}</title>
<!-- Bootstrap Core CSS --> <!-- Bootstrap Core CSS -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<!-- Plugin CSS --> <!-- Plugin CSS -->
<link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/respond.js/1.4.2/respond.min.js"></script>
<![endif]--> <![endif]-->
<style type="text/css"> <style type="text/css">
@ -27,12 +27,12 @@
font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-weight: 400; font-weight: 400;
} }
h2 { font-size: 1.6em; } h2 { font-size: 1.2em; }
hr { margin-top: 10px; } hr { margin-top: 10px; }
.tab-pane { padding-top: 10px; } .tab-pane { padding-top: 10px; }
.mt0 { margin-top: 0px; } .mt0 { margin-top: 0px; }
.footer { font-size: 12px; color: #666; } .footer { font-size: 12px; color: #666; }
.label { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; } .docs-list .label { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; }
.string { color: green; } .string { color: green; }
.number { color: darkorange; } .number { color: darkorange; }
.boolean { color: blue; } .boolean { color: blue; }
@ -65,12 +65,24 @@
#sidebar > .list-group > a{ #sidebar > .list-group > a{
text-indent:0; text-indent:0;
} }
#sidebar .child > a .tag{
position: absolute;
right: 10px;
top: 11px;
}
#sidebar .child > a .pull-right{
margin-left:3px;
}
#sidebar .child { #sidebar .child {
border:1px solid #ddd; border:1px solid #ddd;
border-bottom:none; border-bottom:none;
} }
#sidebar .child:last-child {
border-bottom:1px solid #ddd;
}
#sidebar .child > a { #sidebar .child > a {
border:0; border:0;
min-height: 40px;
} }
#sidebar .list-group a.current { #sidebar .list-group a.current {
background:#f5f5f5; background:#f5f5f5;
@ -94,6 +106,9 @@
.label-primary { .label-primary {
background-color: #248aff; background-color: #248aff;
} }
.docs-list .panel .panel-body .table {
margin-bottom: 0;
}
</style> </style>
</head> </head>
@ -122,7 +137,7 @@
Apiurl: Apiurl:
</div> </div>
<div class="form-group"> <div class="form-group">
<input id="apiUrl" type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Apiurltips}" placeholder="https://api.mydomain.com" value="{$config.apiurl}" /> <input id="apiUrl" type="text" class="form-control input-sm" data-toggle="tooltip" title="{$lang.Apiurltips}" placeholder="https://api.example.com" value="{$config.apiurl}" />
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="button" class="btn btn-success btn-sm" data-toggle="tooltip" title="{$lang.Savetips}" id="save_data"> <button type="button" class="btn btn-success btn-sm" data-toggle="tooltip" title="{$lang.Savetips}" id="save_data">
@ -138,25 +153,34 @@
<!-- menu --> <!-- menu -->
<div id="sidebar"> <div id="sidebar">
<div class="list-group panel"> <div class="list-group panel">
{foreach name="docslist" id="docs"} {foreach name="docsList" id="docs"}
<a href="#{$key}" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">{$key} <i class="fa fa-caret-down"></i></a> <a href="#{$key}" class="list-group-item" data-toggle="collapse" data-parent="#sidebar">{$key} <i class="fa fa-caret-down"></i></a>
<div class="child collapse" id="{$key}"> <div class="child collapse" id="{$key}">
{foreach name="docs" id="api" } {foreach name="docs" id="api" }
<a href="javascript:;" data-id="{$api.id}" class="list-group-item">{$api.title}</a> <a href="javascript:;" data-id="{$api.id}" class="list-group-item">{$api.title}
<span class="tag">
{if $api.needRight}
<span class="label label-danger pull-right"></span>
{/if}
{if $api.needLogin}
<span class="label label-success pull-right noneedlogin"></span>
{/if}
</span>
</a>
{/foreach} {/foreach}
</div> </div>
{/foreach} {/foreach}
</div> </div>
</div> </div>
<div class="panel-group" id="accordion"> <div class="panel-group docs-list" id="accordion">
{foreach name="docslist" id="docs"} {foreach name="docsList" id="docs"}
<h2>{$key}</h2> <h2>{$key}</h2>
<hr> <hr>
{foreach name="docs" id="api" } {foreach name="docs" id="api" }
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" id="heading-{$api.id}"> <div class="panel-heading" id="heading-{$api.id}">
<h4 class="panel-title"> <h4 class="panel-title">
<span class="label {$api.method_label}">{$api.method|strtoupper}</span> <span class="label {$api.methodLabel}">{$api.method|strtoupper}</span>
<a data-toggle="collapse" data-parent="#accordion{$api.id}" href="#collapseOne{$api.id}"> {$api.title} <span class="text-muted">{$api.route}</span></a> <a data-toggle="collapse" data-parent="#accordion{$api.id}" href="#collapseOne{$api.id}"> {$api.title} <span class="text-muted">{$api.route}</span></a>
</h4> </h4>
</div> </div>
@ -177,10 +201,27 @@
<div class="well"> <div class="well">
{$api.summary} {$api.summary}
</div> </div>
<div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.Authorization}</strong></div>
<div class="panel-body">
<table class="table table-hover">
<tbody>
<tr>
<td>{$lang.NeedLogin}</td>
<td>{$api.needLogin?'是':'否'}</td>
</tr>
<tr>
<td>{$lang.NeedRight}</td>
<td>{$api.needRight?'是':'否'}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.Headers}</strong></div> <div class="panel-heading"><strong>{$lang.Headers}</strong></div>
<div class="panel-body"> <div class="panel-body">
{if $api.headerslist} {if $api.headersList}
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
@ -191,7 +232,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach name="api['headerslist']" id="header"} {foreach name="api['headersList']" id="header"}
<tr> <tr>
<td>{$header.name}</td> <td>{$header.name}</td>
<td>{$header.type}</td> <td>{$header.type}</td>
@ -209,7 +250,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.Parameters}</strong></div> <div class="panel-heading"><strong>{$lang.Parameters}</strong></div>
<div class="panel-body"> <div class="panel-body">
{if $api.paramslist} {if $api.paramsList}
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
@ -220,7 +261,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach name="api['paramslist']" id="param"} {foreach name="api['paramsList']" id="param"}
<tr> <tr>
<td>{$param.name}</td> <td>{$param.name}</td>
<td>{$param.type}</td> <td>{$param.type}</td>
@ -246,15 +287,15 @@
<div class="tab-pane" id="sandbox{$api.id}"> <div class="tab-pane" id="sandbox{$api.id}">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{if $api.headerslist} {if $api.headersList}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.Headers}</strong></div> <div class="panel-heading"><strong>{$lang.Headers}</strong></div>
<div class="panel-body"> <div class="panel-body">
<div class="headers"> <div class="headers">
{foreach name="api['headerslist']" id="param"} {foreach name="api['headersList']" id="param"}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="{$param.name}">{$param.name}</label> <label class="control-label" for="{$param.name}">{$param.name}</label>
<input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description} - Ex: {$param.sample}" name="{$param.name}"> <input type="{$param.inputtype|default='text'}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description} - Ex: {$param.sample}" name="{$param.name}">
</div> </div>
{/foreach} {/foreach}
</div> </div>
@ -262,14 +303,18 @@
</div> </div>
{/if} {/if}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.Parameters}</strong></div> <div class="panel-heading"><strong>{$lang.Parameters}</strong>
<div class="pull-right">
<a href="javascript:" class="btn btn-xs btn-info btn-append">追加</a>
</div>
</div>
<div class="panel-body"> <div class="panel-body">
<form enctype="application/x-www-form-urlencoded" role="form" action="{$api.route}" method="{$api.method}" name="form{$api.id}" id="form{$api.id}"> <form enctype="application/x-www-form-urlencoded" role="form" action="{$api.route}" method="{$api.method}" name="form{$api.id}" id="form{$api.id}">
{if $api.paramslist} {if $api.paramsList}
{foreach name="api['paramslist']" id="param"} {foreach name="api['paramsList']" id="param"}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="{$param.name}">{$param.name}</label> <label class="control-label" for="{$param.name}">{$param.name}</label>
<input type="{$param.type}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description}{if $param.sample} - 例: {$param.sample}{/if}" name="{$param.name}"> <input type="{$param.inputtype|default='text'}" class="form-control input-sm" id="{$param.name}" {if $param.required}required{/if} placeholder="{$param.description}{if $param.sample} - 例: {$param.sample}{/if}" name="{$param.name}">
</div> </div>
{/foreach} {/foreach}
{else /} {else /}
@ -277,7 +322,7 @@
</div> </div>
{/if} {/if}
<div class="form-group"> <div class="form-group form-group-submit">
<button type="submit" class="btn btn-success send" rel="{$api.id}">{$lang.Send}</button> <button type="submit" class="btn btn-success send" rel="{$api.id}">{$lang.Send}</button>
<button type="reset" class="btn btn-info" rel="{$api.id}">{$lang.Reset}</button> <button type="reset" class="btn btn-info" rel="{$api.id}">{$lang.Reset}</button>
</div> </div>
@ -298,7 +343,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>{$lang.ReturnParameters}</strong></div> <div class="panel-heading"><strong>{$lang.ReturnParameters}</strong></div>
<div class="panel-body"> <div class="panel-body">
{if $api.returnparamslist} {if $api.returnParamsList}
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
@ -308,7 +353,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach name="api['returnparamslist']" id="param"} {foreach name="api['returnParamsList']" id="param"}
<tr> <tr>
<td>{$param.name}</td> <td>{$param.name}</td>
<td>{$param.type}</td> <td>{$param.type}</td>
@ -346,20 +391,20 @@
<div class="row mt0 footer"> <div class="row mt0 footer">
<div class="col-md-6" align="left"> <div class="col-md-6" align="left">
Generated on {:date('Y-m-d H:i:s')}
</div> </div>
<div class="col-md-6" align="right"> <div class="col-md-6" align="right">
<a href="./" target="_blank">{$config.sitename}</a> Generated on {:date('Y-m-d H:i:s')} <a href="./" target="_blank">{$config.sitename}</a>
</div> </div>
</div> </div>
</div> <!-- /container --> </div> <!-- /container -->
<!-- jQuery --> <!-- jQuery -->
<script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js"></script>
<!-- Bootstrap Core JavaScript --> <!-- Bootstrap Core JavaScript -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
function syntaxHighlight(json) { function syntaxHighlight(json) {
@ -475,7 +520,7 @@
$sample.html('<pre>' + str + '</pre>'); $sample.html('<pre>' + str + '</pre>');
}); });
$('body').on('click', '#save_data', function (e) { $(document).on('click', '#save_data', function (e) {
if (storage) { if (storage) {
storage.setItem('token', $('#token').val()); storage.setItem('token', $('#token').val());
storage.setItem('apiUrl', $('#apiUrl').val()); storage.setItem('apiUrl', $('#apiUrl').val());
@ -483,8 +528,20 @@
alert('Your browser does not support local storage'); alert('Your browser does not support local storage');
} }
}); });
$(document).on('click', '.btn-append', function (e) {
$($("#appendtpl").html()).insertBefore($(this).closest(".panel").find(".form-group-submit"));
return false;
});
$(document).on('click', '.btn-remove', function (e) {
$(this).closest(".form-group").remove();
return false;
});
$(document).on('keyup', '.input-custom-name', function (e) {
$(this).closest(".row").find(".input-custom-value").attr("name", $(this).val());
return false;
});
$('body').on('click', '.send', function (e) { $(document).on('click', '.send', function (e) {
e.preventDefault(); e.preventDefault();
var form = $(this).closest('form'); var form = $(this).closest('form');
//added /g to get all the matched params instead of only first //added /g to get all the matched params instead of only first
@ -577,5 +634,21 @@
}); });
}); });
</script> </script>
<script type="text/html" id="appendtpl">
<div class="form-group">
<label class="control-label">自定义</label>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control input-sm input-custom-name" placeholder="名称">
</div>
<div class="col-xs-6">
<input type="text" class="form-control input-sm input-custom-value" placeholder="值">
</div>
<div class="col-xs-2 text-center">
<a href="javascript:" class="btn btn-sm btn-danger btn-remove">删除</a>
</div>
</div>
</div>
</script>
</body> </body>
</html> </html>

View File

@ -11,6 +11,7 @@ use think\console\Output;
use think\Db; use think\Db;
use think\Exception; use think\Exception;
use think\exception\ErrorException; use think\exception\ErrorException;
use think\exception\PDOException;
use think\Lang; use think\Lang;
use think\Loader; use think\Loader;
@ -19,8 +20,93 @@ class Crud extends Command
protected $stubList = []; protected $stubList = [];
protected $internalKeywords = [ protected $internalKeywords = [
'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor' 'abstract',
'and',
'array',
'as',
'break',
'callable',
'case',
'catch',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exit',
'extends',
'final',
'for',
'foreach',
'function',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'isset',
'list',
'namespace',
'new',
'or',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'switch',
'throw',
'trait',
'try',
'unset',
'use',
'var',
'while',
'xor'
]; ];
/**
* 受保护的系统表, crud不会生效
*/
protected $systemTables = [
'admin',
'admin_log',
'auth_group',
'auth_group_access',
'auth_rule',
'attachment',
'config',
'category',
'ems',
'sms',
'user',
'user_group',
'user_rule',
'user_score_log',
'user_token',
];
/** /**
* Selectpage搜索字段关联 * Selectpage搜索字段关联
*/ */
@ -58,10 +144,20 @@ class Crud extends Command
*/ */
protected $citySuffix = ['city']; protected $citySuffix = ['city'];
/**
* 时间区间后缀
*/
protected $rangeSuffix = ['range'];
/** /**
* JSON后缀 * JSON后缀
*/ */
protected $jsonSuffix = ['json']; protected $jsonSuffix = ['json', 'array'];
/**
* 标签后缀
*/
protected $tagSuffix = ['tag', 'tags'];
/** /**
* Selectpage对应的后缀 * Selectpage对应的后缀
@ -83,9 +179,13 @@ class Crud extends Command
'url' => 'url', 'url' => 'url',
'image' => 'image', 'image' => 'image',
'images' => 'images', 'images' => 'images',
'file' => 'file',
'files' => 'files',
'avatar' => 'image', 'avatar' => 'image',
'switch' => 'toggle', 'switch' => 'toggle',
'time' => ['type' => ['int', 'timestamp'], 'name' => 'datetime'] 'tag' => 'flag',
'tags' => 'flag',
'time' => ['type' => ['int', 'bigint', 'timestamp'], 'name' => 'datetime'],
]; ];
/** /**
@ -157,12 +257,14 @@ class Crud extends Command
->addOption('fields', 'i', Option::VALUE_OPTIONAL, 'model visible fields', null) ->addOption('fields', 'i', Option::VALUE_OPTIONAL, 'model visible fields', null)
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override or force delete,without tips', null) ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override or force delete,without tips', null)
->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local model', 1) ->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local model', 1)
->addOption('import', 'a', Option::VALUE_OPTIONAL, 'enable import function', 0)
->addOption('relation', 'r', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table name without prefix', null) ->addOption('relation', 'r', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table name without prefix', null)
->addOption('relationmodel', 'e', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation model name', null) ->addOption('relationmodel', 'e', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation model name', null)
->addOption('relationforeignkey', 'k', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation foreign key', null) ->addOption('relationforeignkey', 'k', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation foreign key', null)
->addOption('relationprimarykey', 'p', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation primary key', null) ->addOption('relationprimarykey', 'p', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation primary key', null)
->addOption('relationfields', 's', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table fields', null) ->addOption('relationfields', 's', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table fields', null)
->addOption('relationmode', 'o', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table mode,hasone or belongsto', null) ->addOption('relationmode', 'o', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table mode,hasone/belongsto/hasmany', null)
->addOption('relationcontroller', 'w', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'relation table controller,only work at hasmany mode', null)
->addOption('delete', 'd', Option::VALUE_OPTIONAL, 'delete all files generated by CRUD', null) ->addOption('delete', 'd', Option::VALUE_OPTIONAL, 'delete all files generated by CRUD', null)
->addOption('menu', 'u', Option::VALUE_OPTIONAL, 'create menu when CRUD completed', null) ->addOption('menu', 'u', Option::VALUE_OPTIONAL, 'create menu when CRUD completed', null)
->addOption('setcheckboxsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate checkbox component with suffix', null) ->addOption('setcheckboxsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate checkbox component with suffix', null)
@ -173,11 +275,14 @@ class Crud extends Command
->addOption('switchsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate switch component with suffix', null) ->addOption('switchsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate switch component with suffix', null)
->addOption('citysuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate citypicker component with suffix', null) ->addOption('citysuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate citypicker component with suffix', null)
->addOption('jsonsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate fieldlist component with suffix', null) ->addOption('jsonsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate fieldlist component with suffix', null)
->addOption('tagsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate tag component with suffix', null)
->addOption('editorsuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate editor component with suffix', null)
->addOption('selectpagesuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate selectpage component with suffix', null) ->addOption('selectpagesuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate selectpage component with suffix', null)
->addOption('selectpagessuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate multiple selectpage component with suffix', null) ->addOption('selectpagessuffix', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'automatically generate multiple selectpage component with suffix', null)
->addOption('ignorefields', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'ignore fields', null) ->addOption('ignorefields', null, Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'ignore fields', null)
->addOption('sortfield', null, Option::VALUE_OPTIONAL, 'sort field', null) ->addOption('sortfield', null, Option::VALUE_OPTIONAL, 'sort field', null)
->addOption('headingfilterfield', null, Option::VALUE_OPTIONAL, 'heading filter field', null) ->addOption('headingfilterfield', null, Option::VALUE_OPTIONAL, 'heading filter field', null)
->addOption('fixedcolumns', null, Option::VALUE_OPTIONAL, 'fixed columns', null)
->addOption('editorclass', null, Option::VALUE_OPTIONAL, 'automatically generate editor class', null) ->addOption('editorclass', null, Option::VALUE_OPTIONAL, 'automatically generate editor class', null)
->addOption('db', null, Option::VALUE_OPTIONAL, 'database config name', 'database') ->addOption('db', null, Option::VALUE_OPTIONAL, 'database config name', 'database')
->setDescription('Build CRUD controller and model from table'); ->setDescription('Build CRUD controller and model from table');
@ -203,15 +308,20 @@ class Crud extends Command
$force = $input->getOption('force'); $force = $input->getOption('force');
//是否为本地model,为0时表示为全局model将会把model放在app/common/model中 //是否为本地model,为0时表示为全局model将会把model放在app/common/model中
$local = $input->getOption('local'); $local = $input->getOption('local');
//是否启用导入功能
$import = $input->getOption('import');
if (!$table) { if (!$table) {
throw new Exception('table name can\'t empty'); throw new Exception('table name can\'t empty');
} }
//是否生成菜单 //是否生成菜单
$menu = $input->getOption("menu"); $menu = $input->getOption("menu");
//关联表 //关联表
$relation = $input->getOption('relation'); $relation = $input->getOption('relation');
//自定义关联表模型 //自定义关联表模型
$relationModel = $input->getOption('relationmodel'); $relationModels = $input->getOption('relationmodel');
//模式 //模式
$relationMode = $mode = $input->getOption('relationmode'); $relationMode = $mode = $input->getOption('relationmode');
//外键 //外键
@ -220,6 +330,8 @@ class Crud extends Command
$relationPrimaryKey = $input->getOption('relationprimarykey'); $relationPrimaryKey = $input->getOption('relationprimarykey');
//关联表显示字段 //关联表显示字段
$relationFields = $input->getOption('relationfields'); $relationFields = $input->getOption('relationfields');
//关联表显示字段
$relationController = $input->getOption('relationcontroller');
//复选框后缀 //复选框后缀
$setcheckboxsuffix = $input->getOption('setcheckboxsuffix'); $setcheckboxsuffix = $input->getOption('setcheckboxsuffix');
//单选框后缀 //单选框后缀
@ -228,10 +340,14 @@ class Crud extends Command
$imagefield = $input->getOption('imagefield'); $imagefield = $input->getOption('imagefield');
//文件后缀 //文件后缀
$filefield = $input->getOption('filefield'); $filefield = $input->getOption('filefield');
//标签后缀
$tagsuffix = $input->getOption('tagsuffix');
//日期后缀 //日期后缀
$intdatesuffix = $input->getOption('intdatesuffix'); $intdatesuffix = $input->getOption('intdatesuffix');
//开关后缀 //开关后缀
$switchsuffix = $input->getOption('switchsuffix'); $switchsuffix = $input->getOption('switchsuffix');
//富文本编辑器
$editorsuffix = $input->getOption('editorsuffix');
//城市后缀 //城市后缀
$citysuffix = $input->getOption('citysuffix'); $citysuffix = $input->getOption('citysuffix');
//JSON配置后缀 //JSON配置后缀
@ -246,6 +362,8 @@ class Crud extends Command
$sortfield = $input->getOption('sortfield'); $sortfield = $input->getOption('sortfield');
//顶部筛选过滤字段 //顶部筛选过滤字段
$headingfilterfield = $input->getOption('headingfilterfield'); $headingfilterfield = $input->getOption('headingfilterfield');
//固定列数量
$fixedcolumns = $input->getOption('fixedcolumns');
//编辑器Class //编辑器Class
$editorclass = $input->getOption('editorclass'); $editorclass = $input->getOption('editorclass');
if ($setcheckboxsuffix) { if ($setcheckboxsuffix) {
@ -260,12 +378,18 @@ class Crud extends Command
if ($filefield) { if ($filefield) {
$this->fileField = $filefield; $this->fileField = $filefield;
} }
if ($tagsuffix) {
$this->tagSuffix = $tagsuffix;
}
if ($intdatesuffix) { if ($intdatesuffix) {
$this->intDateSuffix = $intdatesuffix; $this->intDateSuffix = $intdatesuffix;
} }
if ($switchsuffix) { if ($switchsuffix) {
$this->switchSuffix = $switchsuffix; $this->switchSuffix = $switchsuffix;
} }
if ($editorsuffix) {
$this->editorSuffix = $editorsuffix;
}
if ($citysuffix) { if ($citysuffix) {
$this->citySuffix = $citysuffix; $this->citySuffix = $citysuffix;
} }
@ -297,6 +421,11 @@ class Crud extends Command
$dbname = Config::get($db . '.database'); $dbname = Config::get($db . '.database');
$prefix = Config::get($db . '.prefix'); $prefix = Config::get($db . '.prefix');
//系统表无法生成,防止后台错乱
if (in_array(str_replace($prefix, "", $table), $this->systemTables)) {
throw new Exception('system table can\'t be crud');
}
//模块 //模块
$moduleName = 'admin'; $moduleName = 'admin';
$modelModuleName = $local ? $moduleName : 'common'; $modelModuleName = $local ? $moduleName : 'common';
@ -306,16 +435,19 @@ class Crud extends Command
$modelName = $table = stripos($table, $prefix) === 0 ? substr($table, strlen($prefix)) : $table; $modelName = $table = stripos($table, $prefix) === 0 ? substr($table, strlen($prefix)) : $table;
$modelTableType = 'table'; $modelTableType = 'table';
$modelTableTypeName = $modelTableName = $modelName; $modelTableTypeName = $modelTableName = $modelName;
$modelTableInfo = $dbconnect->query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], true); $modelTableInfo = null;
if (!$modelTableInfo) { if (!$input->getOption('delete')) {
$modelTableType = 'name';
$modelTableName = $prefix . $modelName;
$modelTableInfo = $dbconnect->query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], true); $modelTableInfo = $dbconnect->query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], true);
if (!$modelTableInfo) { if (!$modelTableInfo) {
throw new Exception("table not found"); $modelTableType = 'name';
$modelTableName = $prefix . $modelName;
$modelTableInfo = $dbconnect->query("SHOW TABLE STATUS LIKE '{$modelTableName}'", [], true);
if (!$modelTableInfo) {
throw new Exception("table not found");
}
} }
$modelTableInfo = $modelTableInfo[0];
} }
$modelTableInfo = $modelTableInfo[0];
$relations = []; $relations = [];
//检查关联表 //检查关联表
@ -337,7 +469,7 @@ class Crud extends Command
} }
} }
$relationTableInfo = $relationTableInfo[0]; $relationTableInfo = $relationTableInfo[0];
$relationModel = isset($relationModel[$index]) ? $relationModel[$index] : ''; $relationModel = $relationModels[$index] ?? '';
list($relationNamespace, $relationName, $relationFile) = $this->getModelData($modelModuleName, $relationModel, $relationName); list($relationNamespace, $relationName, $relationFile) = $this->getModelData($modelModuleName, $relationModel, $relationName);
@ -362,8 +494,10 @@ class Crud extends Command
'relationFields' => isset($relationFields[$index]) ? explode(',', $relationFields[$index]) : [], 'relationFields' => isset($relationFields[$index]) ? explode(',', $relationFields[$index]) : [],
//关联模式 //关联模式
'relationMode' => isset($relationMode[$index]) ? $relationMode[$index] : 'belongsto', 'relationMode' => isset($relationMode[$index]) ? $relationMode[$index] : 'belongsto',
//关联模型控制器
'relationController' => isset($relationController[$index]) ? $relationController[$index] : '',
//关联表外键 //关联表外键
'relationForeignKey' => isset($relationForeignKey[$index]) ? $relationForeignKey[$index] : Loader::parseName($relationName) . '_id', 'relationForeignKey' => isset($relationForeignKey[$index]) ? $relationForeignKey[$index] : '',
//关联表主键 //关联表主键
'relationPrimaryKey' => isset($relationPrimaryKey[$index]) ? $relationPrimaryKey[$index] : '', 'relationPrimaryKey' => isset($relationPrimaryKey[$index]) ? $relationPrimaryKey[$index] : '',
]; ];
@ -386,7 +520,8 @@ class Crud extends Command
$baseFileName = Loader::parseName(array_pop($baseNameArr), 0); $baseFileName = Loader::parseName(array_pop($baseNameArr), 0);
array_push($baseNameArr, $baseFileName); array_push($baseNameArr, $baseFileName);
$controllerBaseName = strtolower(implode(DS, $baseNameArr)); $controllerBaseName = strtolower(implode(DS, $baseNameArr));
$controllerUrl = strtolower(implode('/', $baseNameArr)); //$controllerUrl = strtolower(implode('/', $baseNameArr));
$controllerUrl = $this->getControllerUrl($moduleName, $baseNameArr);
//视图文件 //视图文件
$viewArr = $controllerArr; $viewArr = $controllerArr;
@ -510,28 +645,32 @@ class Crud extends Command
$editList = []; $editList = [];
$javascriptList = []; $javascriptList = [];
$langList = []; $langList = [];
$operateButtonList = [];
$field = 'id'; $field = 'id';
$order = 'id'; $order = 'id';
$priDefined = false; $priDefined = false;
$priKey = ''; $priKeyArr = [];
$relationPrimaryKey = ''; $relationPrimaryKey = '';
foreach ($columnList as $k => $v) { foreach ($columnList as $k => $v) {
if ($v['COLUMN_KEY'] == 'PRI') { if ($v['COLUMN_KEY'] == 'PRI') {
$priKey = $v['COLUMN_NAME']; $priKeyArr[] = $v['COLUMN_NAME'];
break;
} }
} }
if (!$priKey) { if (!$priKeyArr) {
throw new Exception('Primary key not found!'); throw new Exception('Primary key not found!');
} }
if (count($priKeyArr) > 1) {
throw new Exception('Multiple primary key not support!');
}
$priKey = reset($priKeyArr);
$order = $priKey; $order = $priKey;
//如果是关联模型 //如果是关联模型
foreach ($relations as $index => &$relation) { foreach ($relations as $index => &$relation) {
if ($relation['relationMode'] == 'hasone') { if ($relation['relationMode'] == 'hasone') {
$relationForeignKey = $relation['relationForeignKey'] ? $relation['relationForeignKey'] : $table . "_id"; $relationForeignKey = $relation['relationForeignKey'] ?: $table . "_id";
$relationPrimaryKey = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $priKey; $relationPrimaryKey = $relation['relationPrimaryKey'] ?: $priKey;
if (!in_array($relationForeignKey, $relation['relationFieldList'])) { if (!in_array($relationForeignKey, $relation['relationFieldList'])) {
throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationForeignKey . ']'); throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationForeignKey . ']');
@ -539,15 +678,26 @@ class Crud extends Command
if (!in_array($relationPrimaryKey, $fieldArr)) { if (!in_array($relationPrimaryKey, $fieldArr)) {
throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']'); throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']');
} }
} else { } elseif ($relation['relationMode'] == 'belongsto') {
$relationForeignKey = $relation['relationForeignKey'] ? $relation['relationForeignKey'] : Loader::parseName($relation['relationName']) . "_id"; $relationForeignKey = $relation['relationForeignKey'] ?: Loader::parseName($relation['relationName']) . "_id";
$relationPrimaryKey = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $relation['relationPriKey']; $relationPrimaryKey = $relation['relationPrimaryKey'] ?: $relation['relationPriKey'];
if (!in_array($relationForeignKey, $fieldArr)) { if (!in_array($relationForeignKey, $fieldArr)) {
throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationForeignKey . ']'); throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationForeignKey . ']');
} }
if (!in_array($relationPrimaryKey, $relation['relationFieldList'])) { if (!in_array($relationPrimaryKey, $relation['relationFieldList'])) {
throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationPrimaryKey . ']'); throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationPrimaryKey . ']');
} }
} elseif ($relation['relationMode'] == 'hasmany') {
$relationForeignKey = $relation['relationForeignKey'] ?: $table . "_id";
$relationPrimaryKey = $relation['relationPrimaryKey'] ?: $priKey;
if (!in_array($relationForeignKey, $relation['relationFieldList'])) {
throw new Exception('relation table [' . $relation['relationTableName'] . '] must be contain field [' . $relationForeignKey . ']');
}
if (!in_array($relationPrimaryKey, $fieldArr)) {
throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']');
}
$relation['relationColumnList'] = [];
$relation['relationFieldList'] = [];
} }
$relation['relationForeignKey'] = $relationForeignKey; $relation['relationForeignKey'] = $relationForeignKey;
$relation['relationPrimaryKey'] = $relationPrimaryKey; $relation['relationPrimaryKey'] = $relationPrimaryKey;
@ -563,21 +713,29 @@ class Crud extends Command
$appendAttrList = []; $appendAttrList = [];
$controllerAssignList = []; $controllerAssignList = [];
$headingHtml = '{:build_heading()}'; $headingHtml = '{:build_heading()}';
$controllerImport = '';
$importHtml = '';
$multipleHtml = '';
$recyclebinHtml = ''; $recyclebinHtml = '';
if ($import) {
$controllerImport = $this->getReplacedStub('mixins/import', []);
$importHtml = '<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check(\'' . $controllerUrl . '/import\')?\'\':\'hide\'}" title="{:__(\'Import\')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__(\'Import\')}</a>';
}
//循环所有字段,开始构造视图的HTML和JS信息 //循环所有字段,开始构造视图的HTML和JS信息
foreach ($columnList as $k => $v) { foreach ($columnList as $k => $v) {
$field = $v['COLUMN_NAME']; $field = $v['COLUMN_NAME'];
$itemArr = []; $itemArr = [];
// 这里构建Enum和Set类型的列表数据 // 这里构建Enum和Set类型的列表数据
if (in_array($v['DATA_TYPE'], ['enum', 'set', 'tinyint'])) { if (in_array($v['DATA_TYPE'], ['enum', 'set', 'tinyint']) || $this->headingFilterField == $field) {
if ($v['DATA_TYPE'] !== 'tinyint') { if ($v['DATA_TYPE'] !== 'tinyint') {
$itemArr = substr($v['COLUMN_TYPE'], strlen($v['DATA_TYPE']) + 1, -1); $itemArr = substr($v['COLUMN_TYPE'], strlen($v['DATA_TYPE']) + 1, -1);
$itemArr = explode(',', str_replace("'", '', $itemArr)); $itemArr = explode(',', str_replace("'", '', $itemArr));
} }
$itemArr = $this->getItemArray($itemArr, $field, $v['COLUMN_COMMENT']); $itemArr = $this->getItemArray($itemArr, $field, $v['COLUMN_COMMENT']);
//如果类型为tinyint且有使用备注数据 //如果类型为tinyint且有使用备注数据
if ($itemArr && $v['DATA_TYPE'] == 'tinyint') { if ($itemArr && !in_array($v['DATA_TYPE'], ['enum', 'set'])) {
$v['DATA_TYPE'] = 'enum'; $v['DATA_TYPE'] = 'enum';
} }
} }
@ -603,6 +761,11 @@ class Crud extends Command
$attrArr['data-rule'] = 'required'; $attrArr['data-rule'] = 'required';
} }
//如果字段类型为无符号型,则设置<input min=0>
if (stripos($v['COLUMN_TYPE'], 'unsigned') !== false) {
$attrArr['min'] = 0;
}
if ($inputType == 'select') { if ($inputType == 'select') {
$cssClassArr[] = 'selectpicker'; $cssClassArr[] = 'selectpicker';
$attrArr['class'] = implode(' ', $cssClassArr); $attrArr['class'] = implode(' ', $cssClassArr);
@ -661,6 +824,14 @@ class Crud extends Command
$attrArr['data-use-current'] = "true"; $attrArr['data-use-current'] = "true";
$formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr); $formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr);
$formEditElement = Form::text($fieldName, ($fieldFunc ? "{:\$row.{$field}?{$fieldFunc}(\$row.{$field}):''}" : "{\$row.{$field}{$fieldFunc}}"), $attrArr); $formEditElement = Form::text($fieldName, ($fieldFunc ? "{:\$row.{$field}?{$fieldFunc}(\$row.{$field}):''}" : "{\$row.{$field}{$fieldFunc}}"), $attrArr);
} elseif ($inputType == 'datetimerange') {
$cssClassArr[] = 'datetimerange';
$attrArr['class'] = implode(' ', $cssClassArr);
$attrArr['data-locale'] = '{"format":"YYYY-MM-DD HH:mm:ss"}';
$fieldFunc = '';
$defaultDateTime = "";
$formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr);
$formEditElement = Form::text($fieldName, $editValue, $attrArr);
} elseif ($inputType == 'checkbox' || $inputType == 'radio') { } elseif ($inputType == 'checkbox' || $inputType == 'radio') {
unset($attrArr['data-rule']); unset($attrArr['data-rule']);
$fieldName = $inputType == 'checkbox' ? $fieldName .= "[]" : $fieldName; $fieldName = $inputType == 'checkbox' ? $fieldName .= "[]" : $fieldName;
@ -678,7 +849,7 @@ class Crud extends Command
$formAddElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => $defaultValue]); $formAddElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => $defaultValue]);
$formEditElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => "\$row.{$field}"]); $formEditElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'fieldList' => $this->getFieldListName($field), 'attrStr' => Form::attributes($attrArr), 'selectedValue' => "\$row.{$field}"]);
} elseif ($inputType == 'textarea') { } elseif ($inputType == 'textarea' && !$this->isMatchSuffix($field, $this->selectpagesSuffix) && !$this->isMatchSuffix($field, $this->imageField)) {
$cssClassArr[] = $this->isMatchSuffix($field, $this->editorSuffix) ? $this->editorClass : ''; $cssClassArr[] = $this->isMatchSuffix($field, $this->editorSuffix) ? $this->editorClass : '';
$attrArr['class'] = implode(' ', $cssClassArr); $attrArr['class'] = implode(' ', $cssClassArr);
$attrArr['rows'] = 5; $attrArr['rows'] = 5;
@ -704,12 +875,25 @@ class Crud extends Command
$attrArr['data-toggle'] = "city-picker"; $attrArr['data-toggle'] = "city-picker";
$formAddElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $defaultValue, $attrArr)); $formAddElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $defaultValue, $attrArr));
$formEditElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $editValue, $attrArr)); $formEditElement = sprintf("<div class='control-relative'>%s</div>", Form::input('text', $fieldName, $editValue, $attrArr));
} elseif ($inputType == 'tagsinput') {
$attrArr['class'] = implode(' ', $cssClassArr);
$attrArr['data-role'] = "tagsinput";
$formAddElement = Form::input('text', $fieldName, $defaultValue, $attrArr);
$formEditElement = Form::input('text', $fieldName, $editValue, $attrArr);
} elseif ($inputType == 'fieldlist') { } elseif ($inputType == 'fieldlist') {
$itemArr = $this->getItemArray($itemArr, $field, $v['COLUMN_COMMENT']); $itemArr = $this->getItemArray($itemArr, $field, $v['COLUMN_COMMENT']);
$templateName = !isset($itemArr['key']) && count($itemArr) > 0 ? (isset($itemArr['value']) && count($itemArr) === 1 ? 'fieldlist-array' : 'fieldlist-template') : 'fieldlist';
$itemKey = isset($itemArr['key']) ? ucfirst($itemArr['key']) : 'Key'; $itemKey = isset($itemArr['key']) ? ucfirst($itemArr['key']) : 'Key';
$itemValue = isset($itemArr['value']) ? ucfirst($itemArr['value']) : 'Value'; $itemValue = isset($itemArr['value']) ? ucfirst($itemArr['value']) : 'Value';
$formAddElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'itemKey' => $itemKey, 'itemValue' => $itemValue, 'fieldValue' => $defaultValue]); $theadListArr = $tbodyListArr = [];
$formEditElement = $this->getReplacedStub('html/' . $inputType, ['field' => $field, 'fieldName' => $fieldName, 'itemKey' => $itemKey, 'itemValue' => $itemValue, 'fieldValue' => $editValue]); foreach ($itemArr as $index => $item) {
$theadListArr[] = "<td>{:__('" . $item . "')}</td>";
$tbodyListArr[] = '<td><input type="text" name="<%=name%>[<%=index%>][' . $index . ']" class="form-control" value="<%=row.' . $index . '%>"/></td>';
}
$colspan = count($theadListArr) + 1;
$commonFields = ['field' => $field, 'fieldName' => $fieldName, 'itemKey' => $itemKey, 'itemValue' => $itemValue, 'theadList' => implode("\n", $theadListArr), 'tbodyList' => implode("\n", $tbodyListArr), 'colspan' => $colspan];
$formAddElement = $this->getReplacedStub('html/' . $templateName, array_merge($commonFields, ['fieldValue' => $defaultValue]));
$formEditElement = $this->getReplacedStub('html/' . $templateName, array_merge($commonFields, ['fieldValue' => $editValue]));
} else { } else {
$search = $replace = ''; $search = $replace = '';
//特殊字段为关联搜索 //特殊字段为关联搜索
@ -718,7 +902,15 @@ class Crud extends Command
$defaultValue = ''; $defaultValue = '';
$attrArr['data-rule'] = 'required'; $attrArr['data-rule'] = 'required';
$cssClassArr[] = 'selectpage'; $cssClassArr[] = 'selectpage';
$selectpageController = str_replace('_', '/', substr($field, 0, strripos($field, '_'))); $selectpageTable = substr($field, 0, strripos($field, '_'));
$selectpageField = '';
foreach ($relations as $index => $relation) {
if ($relation['relationForeignKey'] === $field) {
$selectpageTable = substr($relation['relationTableName'], strlen($prefix));
break;
}
}
$selectpageController = str_replace('_', '/', $selectpageTable);
$attrArr['data-source'] = $selectpageController . "/index"; $attrArr['data-source'] = $selectpageController . "/index";
//如果是类型表需要特殊处理下 //如果是类型表需要特殊处理下
if ($selectpageController == 'category') { if ($selectpageController == 'category') {
@ -730,14 +922,31 @@ class Crud extends Command
$attrArr['data-source'] = 'auth/admin/selectpage'; $attrArr['data-source'] = 'auth/admin/selectpage';
} elseif ($selectpageController == 'user') { } elseif ($selectpageController == 'user') {
$attrArr['data-source'] = 'user/user/index'; $attrArr['data-source'] = 'user/user/index';
$attrArr['data-field'] = 'nickname';
} }
if ($this->isMatchSuffix($field, $this->selectpagesSuffix)) { if ($this->isMatchSuffix($field, $this->selectpagesSuffix)) {
$attrArr['data-multiple'] = 'true'; $attrArr['data-multiple'] = 'true';
} }
foreach ($this->fieldSelectpageMap as $m => $n) {
if (in_array($field, $n)) { $tableInfo = null;
$attrArr['data-field'] = $m; try {
break; $tableInfo = \think\Db::name($selectpageTable)->getTableInfo();
if (isset($tableInfo['fields'])) {
foreach ($tableInfo['fields'] as $m => $n) {
if (in_array($n, ['nickname', 'title', 'name'])) {
$selectpageField = $n;
break;
}
}
}
} catch (\Exception $e) {
}
if (!$selectpageField) {
foreach ($this->fieldSelectpageMap as $m => $n) {
if (in_array($field, $n)) {
$attrArr['data-field'] = $m;
break;
}
} }
} }
} }
@ -757,6 +966,11 @@ class Crud extends Command
$attrArr['size'] = 50; $attrArr['size'] = 50;
} }
//字段默认值判断
if ('NULL' == $defaultValue || "''" == $defaultValue) {
$defaultValue = '';
}
$formAddElement = Form::input($inputType, $fieldName, $defaultValue, $attrArr); $formAddElement = Form::input($inputType, $fieldName, $defaultValue, $attrArr);
$formEditElement = Form::input($inputType, $fieldName, $editValue, $attrArr); $formEditElement = Form::input($inputType, $fieldName, $editValue, $attrArr);
if ($search && $replace) { if ($search && $replace) {
@ -787,10 +1001,11 @@ class Crud extends Command
} }
if (!$fields || in_array($field, explode(',', $fields))) { if (!$fields || in_array($field, explode(',', $fields))) {
//构造JS列信息 //构造JS列信息
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr); $javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr, $v);
} }
if ($this->headingFilterField && $this->headingFilterField == $field && $itemArr) { if ($this->headingFilterField && $this->headingFilterField == $field && $itemArr) {
$headingHtml = $this->getReplacedStub('html/heading-html', ['field' => $field, 'fieldName' => Loader::parseName($field, 1, false)]); $headingHtml = $this->getReplacedStub('html/heading-html', ['field' => $field, 'fieldName' => Loader::parseName($field, 1, false)]);
$multipleHtml = $this->getReplacedStub('html/multiple-html', ['field' => $field, 'fieldName' => Loader::parseName($field, 1, false), 'controllerUrl' => $controllerUrl]);
} }
//排序方式,如果有指定排序字段,否则按主键排序 //排序方式,如果有指定排序字段,否则按主键排序
$order = $field == $this->sortField ? $this->sortField : $order; $order = $field == $this->sortField ? $this->sortField : $order;
@ -799,6 +1014,33 @@ class Crud extends Command
//循环关联表,追加语言包和JS列 //循环关联表,追加语言包和JS列
foreach ($relations as $index => $relation) { foreach ($relations as $index => $relation) {
if ($relation['relationMode'] == 'hasmany') {
$relationFieldText = ucfirst(strtolower($relation['relationName'])) . ' List';
// 语言列表
if ($relation['relationTableInfo']['Comment']) {
$langList[] = $this->getLangItem($relationFieldText, rtrim($relation['relationTableInfo']['Comment'], "") . "列表");
}
$relationTableName = $relation['relationTableName'];
$relationTableName = stripos($relationTableName, $prefix) === 0 ? substr($relationTableName, strlen($prefix)) : $relationTableName;
list($realtionControllerNamespace, $realtionControllerName, $realtionControllerFile, $realtionControllerArr) = $this->getControllerData($moduleName, $relation['relationController'], $relationTableName);
$realtionControllerArr = array_map("strtolower", $realtionControllerArr);
if (count($realtionControllerArr) > 1) {
$realtionControllerArr = [implode('.', $realtionControllerArr)];
}
$realtionControllerArr[] = 'index';
$realtionControllerArr[] = $relation['relationForeignKey'] . '/{ids}';
$relationControllerUrl = implode('/', $realtionControllerArr);
//构造JS列信息
$operateButtonList[] = "{name: 'addtabs',title: __('{$relationFieldText}'),text: __('{$relationFieldText}'),classname: 'btn btn-xs btn-info btn-dialog',icon: 'fa fa-list',url: '" . $relationControllerUrl . "'}";
//echo "php think crud -t {$relation['relationTableName']} -c {$relation['relationController']} -m {$relation['relationModel']} -i " . implode(',', $relation['relationFields']);
//不存在关联表控制器的情况下才进行生成
if (!is_file($realtionControllerFile)) {
exec("php think crud -t {$relation['relationTableName']} -c {$relation['relationController']} -m {$relation['relationModel']} -i " . implode(',', $relation['relationFields']));
}
}
foreach ($relation['relationColumnList'] as $k => $v) { foreach ($relation['relationColumnList'] as $k => $v) {
// 不显示的字段直接过滤掉 // 不显示的字段直接过滤掉
if ($relation['relationFields'] && !in_array($v['COLUMN_NAME'], $relation['relationFields'])) { if ($relation['relationFields'] && !in_array($v['COLUMN_NAME'], $relation['relationFields'])) {
@ -814,13 +1056,13 @@ class Crud extends Command
//过滤text类型字段 //过滤text类型字段
if ($v['DATA_TYPE'] != 'text') { if ($v['DATA_TYPE'] != 'text') {
//构造JS列信息 //构造JS列信息
$javascriptList[] = $this->getJsColumn($relationField, $v['DATA_TYPE']); $javascriptList[] = $this->getJsColumn($relationField, $v['DATA_TYPE'], '', [], $v);
} }
} }
} }
//JS最后一列加上操作列 //JS最后一列加上操作列
$javascriptList[] = str_repeat(" ", 24) . "{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}"; $javascriptList[] = str_repeat(" ", 24) . "{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, " . ($operateButtonList ? "buttons: [" . implode(',', $operateButtonList) . "], " : "") . "formatter: Table.api.formatter.operate}";
$addList = implode("\n", array_filter($addList)); $addList = implode("\n", array_filter($addList));
$editList = implode("\n", array_filter($editList)); $editList = implode("\n", array_filter($editList));
$javascriptList = implode(",\n", array_filter($javascriptList)); $javascriptList = implode(",\n", array_filter($javascriptList));
@ -834,9 +1076,15 @@ class Crud extends Command
} }
unset($line); unset($line);
$langList = implode(",\n", array_filter($langList)); $langList = implode(",\n", array_filter($langList));
$fixedcolumns = count($columnList) >= 10 ? 1 : $fixedcolumns;
$fixedColumnsJs = '';
if (is_numeric($fixedcolumns) && $fixedcolumns) {
$fixedColumnsJs = "\n" . str_repeat(" ", 16) . "fixedColumns: true,\n" . str_repeat(" ", 16) . ($fixedcolumns < 0 ? "fixedNumber" : "fixedRightNumber") . ": " . $fixedcolumns . ",";
}
//表注释 //表注释
$tableComment = $modelTableInfo['Comment']; $tableComment = $modelTableInfo ? $modelTableInfo['Comment'] : '';
$tableComment = mb_substr($tableComment, -1) == '表' ? mb_substr($tableComment, 0, -1) . '管理' : $tableComment; $tableComment = mb_substr($tableComment, -1) == '表' ? mb_substr($tableComment, 0, -1) . '管理' : $tableComment;
$modelInit = ''; $modelInit = '';
@ -861,26 +1109,30 @@ class Crud extends Command
'iconName' => $iconName, 'iconName' => $iconName,
'pk' => $priKey, 'pk' => $priKey,
'order' => $order, 'order' => $order,
'fixedColumnsJs' => $fixedColumnsJs,
'table' => $table, 'table' => $table,
'tableName' => $modelTableName, 'tableName' => $modelTableName,
'addList' => $addList, 'addList' => $addList,
'editList' => $editList, 'editList' => $editList,
'javascriptList' => $javascriptList, 'javascriptList' => $javascriptList,
'langList' => $langList, 'langList' => $langList,
'sofeDeleteClassPath' => in_array($this->deleteTimeField, $fieldArr) ? "use traits\model\SoftDelete;" : '', 'softDeleteClassPath' => in_array($this->deleteTimeField, $fieldArr) ? "use traits\model\SoftDelete;" : '',
'softDelete' => in_array($this->deleteTimeField, $fieldArr) ? "use SoftDelete;" : '', 'softDelete' => in_array($this->deleteTimeField, $fieldArr) ? "use SoftDelete;" : '',
'modelAutoWriteTimestamp' => in_array($this->createTimeField, $fieldArr) || in_array($this->updateTimeField, $fieldArr) ? "'int'" : 'false', 'modelAutoWriteTimestamp' => in_array($this->createTimeField, $fieldArr) || in_array($this->updateTimeField, $fieldArr) ? "'integer'" : 'false',
'createTime' => in_array($this->createTimeField, $fieldArr) ? "'{$this->createTimeField}'" : 'false', 'createTime' => in_array($this->createTimeField, $fieldArr) ? "'{$this->createTimeField}'" : 'false',
'updateTime' => in_array($this->updateTimeField, $fieldArr) ? "'{$this->updateTimeField}'" : 'false', 'updateTime' => in_array($this->updateTimeField, $fieldArr) ? "'{$this->updateTimeField}'" : 'false',
'deleteTime' => in_array($this->deleteTimeField, $fieldArr) ? "'{$this->deleteTimeField}'" : 'false', 'deleteTime' => in_array($this->deleteTimeField, $fieldArr) ? "'{$this->deleteTimeField}'" : 'false',
'relationSearch' => $relations ? 'true' : 'false', 'relationSearch' => $relations ? 'true' : 'false',
'relationWithList' => '', 'relationWithList' => '',
'relationMethodList' => '', 'relationMethodList' => '',
'controllerImport' => $controllerImport,
'controllerIndex' => '', 'controllerIndex' => '',
'recyclebinJs' => '', 'recyclebinJs' => '',
'headingHtml' => $headingHtml, 'headingHtml' => $headingHtml,
'multipleHtml' => $multipleHtml,
'importHtml' => $importHtml,
'recyclebinHtml' => $recyclebinHtml, 'recyclebinHtml' => $recyclebinHtml,
'visibleFieldList' => $fields ? "\$row->visible(['" . implode("','", array_filter(explode(',', $fields))) . "']);" : '', 'visibleFieldList' => $fields ? "\$row->visible(['" . implode("','", array_filter(in_array($priKey, explode(',', $fields)) ? explode(',', $fields) : explode(',', $priKey . ',' . $fields))) . "']);" : '',
'appendAttrList' => implode(",\n", $appendAttrList), 'appendAttrList' => implode(",\n", $appendAttrList),
'getEnumList' => implode("\n\n", $getEnumArr), 'getEnumList' => implode("\n\n", $getEnumArr),
'getAttrList' => implode("\n\n", $getAttrArr), 'getAttrList' => implode("\n\n", $getAttrArr),
@ -891,24 +1143,30 @@ class Crud extends Command
//如果使用关联模型 //如果使用关联模型
if ($relations) { if ($relations) {
$relationWithList = $relationMethodList = $relationVisibleFieldList = []; $relationWithList = $relationMethodList = $relationVisibleFieldList = [];
$relationKeyArr = ['hasone' => 'hasOne', 'belongsto' => 'belongsTo', 'hasmany' => 'hasMany'];
foreach ($relations as $index => $relation) { foreach ($relations as $index => $relation) {
//需要构造关联的方法 //需要构造关联的方法
$relation['relationMethod'] = strtolower($relation['relationName']); $relation['relationMethod'] = strtolower($relation['relationName']);
//关联的模式 //关联的模式
$relation['relationMode'] = $relation['relationMode'] == 'hasone' ? 'hasOne' : 'belongsTo'; $relation['relationMode'] = strtolower($relation['relationMode']);
$relation['relationMode'] = array_key_exists($relation['relationMode'], $relationKeyArr) ? $relationKeyArr[$relation['relationMode']] : '';
//关联字段 //关联字段
$relation['relationPrimaryKey'] = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $priKey; $relation['relationPrimaryKey'] = $relation['relationPrimaryKey'] ? $relation['relationPrimaryKey'] : $priKey;
//构造关联模型的方法
$relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod' . ($relation['relationMode'] == 'hasMany' ? '-hasmany' : ''), $relation);
if ($relation['relationMode'] == 'hasMany') {
continue;
}
//预载入的方法 //预载入的方法
$relationWithList[] = $relation['relationMethod']; $relationWithList[] = $relation['relationMethod'];
unset($relation['relationColumnList'], $relation['relationFieldList'], $relation['relationTableInfo']); unset($relation['relationColumnList'], $relation['relationFieldList'], $relation['relationTableInfo']);
//构造关联模型的方法
$relationMethodList[] = $this->getReplacedStub('mixins' . DS . 'modelrelationmethod', $relation);
//如果设置了显示主表字段,则必须显式将关联表字段显示 //如果设置了显示主表字段,则必须显式将关联表字段显示
if ($fields) { if ($fields) {
$relationVisibleFieldList[] = "\$row->visible(['{$relation['relationMethod']}']);"; $relationVisibleFieldList[] = "\$row->visible(['{$relation['relationMethod']}']);";
@ -924,8 +1182,10 @@ class Crud extends Command
$data['relationMethodList'] = implode("\n\n", $relationMethodList); $data['relationMethodList'] = implode("\n\n", $relationMethodList);
$data['relationVisibleFieldList'] = implode("\n\t\t\t\t", $relationVisibleFieldList); $data['relationVisibleFieldList'] = implode("\n\t\t\t\t", $relationVisibleFieldList);
//需要重写index方法 if ($relationWithList) {
$data['controllerIndex'] = $this->getReplacedStub('controllerindex', $data); //需要重写index方法
$data['controllerIndex'] = $this->getReplacedStub('controllerindex', $data);
}
} elseif ($fields) { } elseif ($fields) {
$data = array_merge($data, ['relationWithList' => '', 'relationMethodList' => '', 'relationVisibleFieldList' => '']); $data = array_merge($data, ['relationWithList' => '', 'relationMethodList' => '', 'relationVisibleFieldList' => '']);
//需要重写index方法 //需要重写index方法
@ -939,7 +1199,7 @@ class Crud extends Command
if ($relations) { if ($relations) {
foreach ($relations as $i => $relation) { foreach ($relations as $i => $relation) {
$relation['modelNamespace'] = $data['modelNamespace']; $relation['modelNamespace'] = $relation['relationNamespace'];
if (!is_file($relation['relationFile'])) { if (!is_file($relation['relationFile'])) {
// 生成关联模型文件 // 生成关联模型文件
$this->writeToFile('relationmodel', $relation, $relation['relationFile']); $this->writeToFile('relationmodel', $relation, $relation['relationFile']);
@ -956,7 +1216,7 @@ class Crud extends Command
$this->writeToFile('recyclebin', $data, $recyclebinFile); $this->writeToFile('recyclebin', $data, $recyclebinFile);
$recyclebinTitle = in_array('title', $fieldArr) ? 'title' : (in_array('name', $fieldArr) ? 'name' : ''); $recyclebinTitle = in_array('title', $fieldArr) ? 'title' : (in_array('name', $fieldArr) ? 'name' : '');
$recyclebinTitleJs = $recyclebinTitle ? "\n {field: '{$recyclebinTitle}', title: __('" . (ucfirst($recyclebinTitle)) . "'), align: 'left'}," : ''; $recyclebinTitleJs = $recyclebinTitle ? "\n {field: '{$recyclebinTitle}', title: __('" . (ucfirst($recyclebinTitle)) . "'), align: 'left'}," : '';
$data['recyclebinJs'] = $this->getReplacedStub('mixins/recyclebinjs', ['recyclebinTitleJs' => $recyclebinTitleJs, 'controllerUrl' => $controllerUrl]); $data['recyclebinJs'] = $this->getReplacedStub('mixins/recyclebinjs', ['deleteTimeField' => $this->deleteTimeField, 'recyclebinTitleJs' => $recyclebinTitleJs, 'controllerUrl' => $controllerUrl]);
} }
// 生成JS文件 // 生成JS文件
$this->writeToFile('javascript', $data, $javascriptFile); $this->writeToFile('javascript', $data, $javascriptFile);
@ -1064,6 +1324,28 @@ EOD;
return true; return true;
} }
/**
* 获取控制器URL
* @param string $moduleName
* @param array $baseNameArr
* @return string
*/
protected function getControllerUrl($moduleName, $baseNameArr)
{
for ($i = 0; $i < count($baseNameArr) - 1; $i++) {
$temp = array_slice($baseNameArr, 0, $i + 1);
$temp[$i] = ucfirst($temp[$i]);
$controllerFile = APP_PATH . $moduleName . DS . 'controller' . DS . implode(DS, $temp) . '.php';
//检测父级目录同名控制器是否存在存在则变更URL格式
if (is_file($controllerFile)) {
$baseNameArr = [implode('.', $baseNameArr)];
break;
}
}
$controllerUrl = strtolower(implode('/', $baseNameArr));
return $controllerUrl;
}
/** /**
* 获取控制器相关信息 * 获取控制器相关信息
* @param $module * @param $module
@ -1113,14 +1395,14 @@ EOD;
$arr = []; $arr = [];
if (!$name) { if (!$name) {
$parseName = Loader::parseName($table, 1); $parseName = Loader::parseName($table, 1);
$parseArr = [$table]; $name = str_replace('_', '/', $table);
} else {
$name = str_replace(['.', '/', '\\'], '/', $name);
$arr = explode('/', $name);
$parseName = ucfirst(array_pop($arr));
$parseArr = $arr;
array_push($parseArr, $parseName);
} }
$name = str_replace(['.', '/', '\\'], '/', $name);
$arr = explode('/', $name);
$parseName = ucfirst(array_pop($arr));
$parseArr = $arr;
array_push($parseArr, $parseName);
//类名不能为内部关键字 //类名不能为内部关键字
if (in_array(strtolower($parseName), $this->internalKeywords)) { if (in_array(strtolower($parseName), $this->internalKeywords)) {
throw new Exception('Unable to use internal variable:' . $parseName); throw new Exception('Unable to use internal variable:' . $parseName);
@ -1195,7 +1477,7 @@ EOD;
if ($content || !Lang::has($field)) { if ($content || !Lang::has($field)) {
$this->fieldMaxLen = strlen($field) > $this->fieldMaxLen ? strlen($field) : $this->fieldMaxLen; $this->fieldMaxLen = strlen($field) > $this->fieldMaxLen ? strlen($field) : $this->fieldMaxLen;
$content = str_replace('', ',', $content); $content = str_replace('', ',', $content);
if (stripos($content, ':') !== false && stripos($content, ',') && stripos($content, '=') !== false) { if (stripos($content, ':') !== false && stripos($content, '=') !== false) {
list($fieldLang, $item) = explode(':', $content); list($fieldLang, $item) = explode(':', $content);
$itemArr = [$field => $fieldLang]; $itemArr = [$field => $fieldLang];
foreach (explode(',', $item) as $k => $v) { foreach (explode(',', $item) as $k => $v) {
@ -1203,6 +1485,9 @@ EOD;
if (count($valArr) == 2) { if (count($valArr) == 2) {
list($key, $value) = $valArr; list($key, $value) = $valArr;
$itemArr[$field . ' ' . $key] = $value; $itemArr[$field . ' ' . $key] = $value;
if ($this->headingFilterField == $field) {
$itemArr['Set ' . $field . ' to ' . $key] = '设为' . $value;
}
$this->fieldMaxLen = strlen($field . ' ' . $key) > $this->fieldMaxLen ? strlen($field . ' ' . $key) : $this->fieldMaxLen; $this->fieldMaxLen = strlen($field . ' ' . $key) > $this->fieldMaxLen ? strlen($field . ' ' . $key) : $this->fieldMaxLen;
} }
} }
@ -1260,7 +1545,7 @@ EOD;
{ {
$itemArr = []; $itemArr = [];
$comment = str_replace('', ',', $comment); $comment = str_replace('', ',', $comment);
if (stripos($comment, ':') !== false && stripos($comment, ',') && stripos($comment, '=') !== false) { if (stripos($comment, ':') !== false && stripos($comment, '=') !== false) {
list($fieldLang, $item) = explode(':', $comment); list($fieldLang, $item) = explode(':', $comment);
$itemArr = []; $itemArr = [];
foreach (explode(',', $item) as $k => $v) { foreach (explode(',', $item) as $k => $v) {
@ -1278,7 +1563,7 @@ EOD;
return $itemArr; return $itemArr;
} }
protected function getFieldType(& $v) protected function getFieldType(&$v)
{ {
$inputType = 'text'; $inputType = 'text';
switch ($v['DATA_TYPE']) { switch ($v['DATA_TYPE']) {
@ -1336,10 +1621,18 @@ EOD;
if ($this->isMatchSuffix($fieldsName, $this->citySuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'char')) { if ($this->isMatchSuffix($fieldsName, $this->citySuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'char')) {
$inputType = "citypicker"; $inputType = "citypicker";
} }
// 指定后缀结尾城市选择框
if ($this->isMatchSuffix($fieldsName, $this->rangeSuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'char')) {
$inputType = "datetimerange";
}
// 指定后缀结尾JSON配置 // 指定后缀结尾JSON配置
if ($this->isMatchSuffix($fieldsName, $this->jsonSuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'text')) { if ($this->isMatchSuffix($fieldsName, $this->jsonSuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'text')) {
$inputType = "fieldlist"; $inputType = "fieldlist";
} }
// 指定后缀结尾标签配置
if ($this->isMatchSuffix($fieldsName, $this->tagSuffix) && ($v['DATA_TYPE'] == 'varchar' || $v['DATA_TYPE'] == 'text')) {
$inputType = "tagsinput";
}
return $inputType; return $inputType;
} }
@ -1389,17 +1682,17 @@ EOD;
{ {
$uploadfilter = $selectfilter = ''; $uploadfilter = $selectfilter = '';
if ($this->isMatchSuffix($field, $this->imageField)) { if ($this->isMatchSuffix($field, $this->imageField)) {
$uploadfilter = ' data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp"'; $uploadfilter = ' data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp"';
$selectfilter = ' data-mimetype="image/*"'; $selectfilter = ' data-mimetype="image/*"';
} }
$multiple = substr($field, -1) == 's' ? ' data-multiple="true"' : ' data-multiple="false"'; $multiple = substr($field, -1) == 's' ? ' data-multiple="true"' : ' data-multiple="false"';
$preview = ' data-preview-id="p-' . $field . '"'; $preview = ' data-preview-id="p-' . $field . '"';
$previewcontainer = $preview ? '<ul class="row list-inline plupload-preview" id="p-' . $field . '"></ul>' : ''; $previewcontainer = $preview ? '<ul class="row list-inline faupload-preview" id="p-' . $field . '"></ul>' : '';
return <<<EOD return <<<EOD
<div class="input-group"> <div class="input-group">
{$content} {$content}
<div class="input-group-addon no-border no-padding"> <div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-{$field}" class="btn btn-danger plupload" data-input-id="c-{$field}"{$uploadfilter}{$multiple}{$preview}><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-{$field}" class="btn btn-danger faupload" data-input-id="c-{$field}"{$uploadfilter}{$multiple}{$preview}><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-{$field}" class="btn btn-primary fachoose" data-input-id="c-{$field}"{$selectfilter}{$multiple}><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-{$field}" class="btn btn-primary fachoose" data-input-id="c-{$field}"{$selectfilter}{$multiple}><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div> </div>
<span class="msg-box n-right" for="c-{$field}"></span> <span class="msg-box n-right" for="c-{$field}"></span>
@ -1414,9 +1707,10 @@ EOD;
* @param string $datatype * @param string $datatype
* @param string $extend * @param string $extend
* @param array $itemArr * @param array $itemArr
* @param array $fieldConfig
* @return string * @return string
*/ */
protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = []) protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = [], $fieldConfig = [])
{ {
$lang = mb_ucfirst($field); $lang = mb_ucfirst($field);
$formatter = ''; $formatter = '';
@ -1449,14 +1743,27 @@ EOD;
if ($itemArr) { if ($itemArr) {
$html .= ", searchList: " . $searchList; $html .= ", searchList: " . $searchList;
} }
// 文件、图片、权重等字段默认不加入搜索栏字符串类型默认LIKE
$noSearchFiles = ['file$', 'files$', 'image$', 'images$', '^weigh$'];
if (preg_match("/" . implode('|', $noSearchFiles) . "/i", $field)) {
$html .= ", operate: false";
} elseif (in_array($datatype, ['varchar'])) {
$html .= ", operate: 'LIKE'";
}
if (in_array($datatype, ['date', 'datetime']) || $formatter === 'datetime') { if (in_array($datatype, ['date', 'datetime']) || $formatter === 'datetime') {
$html .= ", operate:'RANGE', addclass:'datetimerange'"; $html .= ", operate:'RANGE', addclass:'datetimerange', autocomplete:false";
} elseif (in_array($datatype, ['float', 'double', 'decimal'])) { } elseif (in_array($datatype, ['float', 'double', 'decimal'])) {
$html .= ", operate:'BETWEEN'"; $html .= ", operate:'BETWEEN'";
} }
if (in_array($datatype, ['set'])) { if (in_array($datatype, ['set'])) {
$html .= ", operate:'FIND_IN_SET'"; $html .= ", operate:'FIND_IN_SET'";
} }
if (isset($fieldConfig['CHARACTER_MAXIMUM_LENGTH']) && $fieldConfig['CHARACTER_MAXIMUM_LENGTH'] >= 255 && in_array($datatype, ['varchar']) && !$formatter) {
$formatter = 'content';
$html .= ", table: table, class: 'autocontent'";
}
if (in_array($formatter, ['image', 'images'])) { if (in_array($formatter, ['image', 'images'])) {
$html .= ", events: Table.api.events.image"; $html .= ", events: Table.api.events.image";
} }

View File

@ -4,8 +4,7 @@
<div class="form-group layer-footer"> <div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -11,7 +11,7 @@ use app\common\controller\Backend;
*/ */
class {%controllerName%} extends Backend class {%controllerName%} extends Backend
{ {
/** /**
* {%modelName%}模型对象 * {%modelName%}模型对象
* @var \{%modelNamespace%}\{%modelName%} * @var \{%modelNamespace%}\{%modelName%}
@ -24,12 +24,14 @@ class {%controllerName%} extends Backend
$this->model = new \{%modelNamespace%}\{%modelName%}; $this->model = new \{%modelNamespace%}\{%modelName%};
{%controllerAssignList%} {%controllerAssignList%}
} }
{%controllerImport%}
/** /**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/ */
{%controllerIndex%} {%controllerIndex%}
} }

View File

@ -8,35 +8,27 @@
$this->relationSearch = {%relationSearch%}; $this->relationSearch = {%relationSearch%};
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags', 'trim']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) if ($this->request->isAjax()) {
{
//如果发送的来源是Selectpage则转发到Selectpage //如果发送的来源是Selectpage则转发到Selectpage
if ($this->request->request('keyField')) if ($this->request->request('keyField')) {
{
return $this->selectpage(); return $this->selectpage();
} }
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
{%relationWithList%}
->where($where)
->order($sort, $order)
->count();
$list = $this->model $list = $this->model
{%relationWithList%} {%relationWithList%}
->where($where) ->where($where)
->order($sort, $order) ->order($sort, $order)
->limit($offset, $limit) ->paginate($limit);
->select();
foreach ($list as $row) { foreach ($list as $row) {
{%visibleFieldList%} {%visibleFieldList%}
{%relationVisibleFieldList%} {%relationVisibleFieldList%}
} }
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list); $result = array("total" => $list->total(), "rows" => $list->items());
return json($result); return json($result);
} }
return $this->view->fetch(); return $this->view->fetch();
} }

View File

@ -4,8 +4,7 @@
<div class="form-group layer-footer"> <div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -0,0 +1,21 @@
<dl class="list-unstyled fieldlist" data-name="{%fieldName%}" data-template="{%fieldName%}tpl">
<dd>
<ins>{:__('{%itemValue%}')}</ins>
</dd>
<dd>
<ins><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></ins>
</dd>
</dl>
<textarea name="{%fieldName%}" class="form-control hide" cols="30" rows="5">{%fieldValue%}</textarea>
<script id="{%fieldName%}tpl" type="text/html">
<dd class="form-inline">
<ins><input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" size="15" value="<%=row%>"/></ins>
<ins>
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</ins>
</dd>
</script>

View File

@ -0,0 +1,20 @@
<table class="table fieldlist" data-name="{%fieldName%}" data-template="{%fieldName%}tpl">
<tr>
{%theadList%}
<td width="90">{:__('Operate')}</td>
</tr>
<tr><td colspan="{%colspan%}">
<a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a>
<textarea name="{%fieldName%}" class="form-control hide" cols="30" rows="5">{%fieldValue%}</textarea>
</td></tr>
</table>
<script type="text/html" id="{%fieldName%}tpl">
<tr>
{%tbodyList%}
<td width="90">
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
</td>
</tr>
</script>

View File

@ -2,9 +2,9 @@
<div class="panel-heading"> <div class="panel-heading">
{:build_heading(null,FALSE)} {:build_heading(null,FALSE)}
<ul class="nav nav-tabs" data-field="{%field%}"> <ul class="nav nav-tabs" data-field="{%field%}">
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li> <li class="{:$Think.get.{%field%} === null ? 'active' : ''}"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
{foreach name="{%fieldName%}List" item="vo"} {foreach name="{%fieldName%}List" item="vo"}
<li><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li> <li class="{:$Think.get.{%field%} === (string)$key ? 'active' : ''}"><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
{/foreach} {/foreach}
</ul> </ul>
</div> </div>

View File

@ -0,0 +1,8 @@
<div class="dropdown btn-group {:$auth->check('{%controllerUrl%}/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
{foreach name="{%fieldName%}List" item="vo"}
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:" data-params="{%field%}={$key}">{:__('Set {%field%} to ' . $key)}</a></li>
{/foreach}
</ul>
</div>

View File

@ -10,21 +10,15 @@
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('{%controllerUrl%}/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('{%controllerUrl%}/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('{%controllerUrl%}/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('{%controllerUrl%}/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('{%controllerUrl%}/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('{%controllerUrl%}/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('{%controllerUrl%}/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a> {%importHtml%}
<div class="dropdown btn-group {:$auth->check('{%controllerUrl%}/multi')?'':'hide'}"> {%multipleHtml%}
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
{%recyclebinHtml%} {%recyclebinHtml%}
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap" <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('{%controllerUrl%}/edit')}" data-operate-edit="{:$auth->check('{%controllerUrl%}/edit')}"
data-operate-del="{:$auth->check('{%controllerUrl%}/del')}" data-operate-del="{:$auth->check('{%controllerUrl%}/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>

View File

@ -10,6 +10,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
edit_url: '{%controllerUrl%}/edit', edit_url: '{%controllerUrl%}/edit',
del_url: '{%controllerUrl%}/del', del_url: '{%controllerUrl%}/del',
multi_url: '{%controllerUrl%}/multi', multi_url: '{%controllerUrl%}/multi',
import_url: '{%controllerUrl%}/import',
table: '{%table%}', table: '{%table%}',
} }
}); });
@ -20,7 +21,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
table.bootstrapTable({ table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: '{%pk%}', pk: '{%pk%}',
sortName: '{%order%}', sortName: '{%order%}',{%fixedColumnsJs%}
columns: [ columns: [
[ [
{%javascriptList%} {%javascriptList%}
@ -44,4 +45,4 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
} }
}; };
return Controller; return Controller;
}); });

View File

@ -0,0 +1,4 @@
public function import()
{
parent::import();
}

View File

@ -2,7 +2,9 @@
protected static function init() protected static function init()
{ {
self::afterInsert(function ($row) { self::afterInsert(function ($row) {
$pk = $row->getPk(); if (!$row['{%order%}']) {
$row->getQuery()->where($pk, $row[$pk])->update(['{%order%}' => $row[$pk]]); $pk = $row->getPk();
$row->getQuery()->where($pk, $row[$pk])->update(['{%order%}' => $row[$pk]]);
}
}); });
} }

View File

@ -0,0 +1,5 @@
public function {%relationMethod%}s()
{
return $this->{%relationMode%}('{%relationClassName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}');
}

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

@ -19,7 +19,7 @@
{checkbox: true}, {checkbox: true},
{field: 'id', title: __('Id')},{%recyclebinTitleJs%} {field: 'id', title: __('Id')},{%recyclebinTitleJs%}
{ {
field: 'deletetime', field: '{%deleteTimeField%}',
title: __('Deletetime'), title: __('Deletetime'),
operate: 'RANGE', operate: 'RANGE',
addclass: 'datetimerange', addclass: 'datetimerange',
@ -27,7 +27,7 @@
}, },
{ {
field: 'operate', field: 'operate',
width: '130px', width: '140px',
title: __('Operate'), title: __('Operate'),
table: table, table: table,
events: Table.api.events.operate, events: Table.api.events.operate,
@ -57,4 +57,4 @@
// 为表格绑定事件 // 为表格绑定事件
Table.api.bindevent(table); Table.api.bindevent(table);
}, },

View File

@ -3,7 +3,7 @@
namespace {%modelNamespace%}; namespace {%modelNamespace%};
use think\Model; use think\Model;
{%sofeDeleteClassPath%} {%softDeleteClassPath%}
class {%modelName%} extends Model class {%modelName%} extends Model
{ {

View File

@ -70,7 +70,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.yoursite.com/{$adminName}"); $output->highlight("Admin url:http://www.example.com/{$adminName}");
} }
$output->highlight("Admin username:{$adminUsername}"); $output->highlight("Admin username:{$adminUsername}");
@ -86,11 +86,17 @@ class Install extends Command
*/ */
public function index() public function index()
{ {
$this->view = View::instance(Config::get('template'), Config::get('view_replace_str')); $this->view = View::instance(array_merge(Config::get('template'), ['tpl_cache' => false]));
$this->request = Request::instance(); $this->request = Request::instance();
define('INSTALL_PATH', APP_PATH . 'admin' . DS . 'command' . DS . 'Install' . DS); define('INSTALL_PATH', APP_PATH . 'admin' . DS . 'command' . DS . 'Install' . DS);
Lang::load(INSTALL_PATH . $this->request->langset() . '.php');
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
if (!$lang || in_array($lang, ['zh-cn', 'zh-hans-cn'])) {
Lang::load(INSTALL_PATH . 'zh-cn.php');
}
$installLockFile = INSTALL_PATH . "install.lock"; $installLockFile = INSTALL_PATH . "install.lock";
@ -159,6 +165,10 @@ class Install extends Command
if (!preg_match("/^[\S]{6,16}$/", $adminPassword)) { if (!preg_match("/^[\S]{6,16}$/", $adminPassword)) {
throw new Exception(__('Please input correct password')); throw new Exception(__('Please input correct password'));
} }
$weakPasswordArr = ['123456', '12345678', '123456789', '654321', '111111', '000000', 'password', 'qwerty', 'abc123', '1qaz2wsx'];
if (in_array($adminPassword, $weakPasswordArr)) {
throw new Exception(__('Password is too weak'));
}
if ($siteName == '' || preg_match("/fast" . "admin/i", $siteName)) { if ($siteName == '' || preg_match("/fast" . "admin/i", $siteName)) {
throw new Exception(__('Please input correct website')); throw new Exception(__('Please input correct website'));
} }
@ -172,7 +182,7 @@ class Install extends Command
try { try {
$pdo = new PDO("{$config['type']}:host={$mysqlHostname}" . ($mysqlHostport ? ";port={$mysqlHostport}" : ''), $mysqlUsername, $mysqlPassword); $pdo = new PDO("{$config['type']}:host={$mysqlHostname}" . ($mysqlHostport ? ";port={$mysqlHostport}" : ''), $mysqlUsername, $mysqlPassword);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8 COLLATE utf8_general_ci;"); $pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;");
// 连接install命令中指定的数据库 // 连接install命令中指定的数据库
$instance = Db::connect([ $instance = Db::connect([
@ -198,7 +208,7 @@ class Install extends Command
// 数据库配置文件 // 数据库配置文件
$dbConfigFile = APP_PATH . 'database.php'; $dbConfigFile = APP_PATH . 'database.php';
$config = @file_get_contents($dbConfigFile); $dbConfigText = @file_get_contents($dbConfigFile);
$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;
@ -207,21 +217,40 @@ class Install extends Command
} }
return "'{$matches[1]}'{$matches[2]}=>{$matches[3]}Env::get('database.{$matches[1]}', '{$replace}'),"; return "'{$matches[1]}'{$matches[2]}=>{$matches[3]}Env::get('database.{$matches[1]}', '{$replace}'),";
}; };
$config = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)Env::get\((.*)\)\,/", $callback, $config); $dbConfigText = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)Env::get\((.*)\)\,/", $callback, $dbConfigText);
// 检测能否成功写入数据库配置 // 检测能否成功写入数据库配置
$result = @file_put_contents($dbConfigFile, $config); $result = @file_put_contents($dbConfigFile, $dbConfigText);
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', 'application/database.php'));
} }
// 设置新的Token随机密钥key
$oldTokenKey = config('token.key');
$newTokenKey = \fast\Random::alnum(32);
$coreConfigFile = CONF_PATH . 'config.php';
$coreConfigText = @file_get_contents($coreConfigFile);
$coreConfigText = preg_replace("/'key'(\s+)=>(\s+)'{$oldTokenKey}'/", "'key'\$1=>\$2'{$newTokenKey}'", $coreConfigText);
$result = @file_put_contents($coreConfigFile, $coreConfigText);
if (!$result) {
throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/config.php'));
}
$avatar = request()->domain() . '/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";
$newSalt = substr(md5(uniqid(true)), 0, 6); $newSalt = substr(md5(uniqid(true)), 0, 6);
$newPassword = md5(md5($adminPassword) . $newSalt); $newPassword = md5(md5($adminPassword) . $newSalt);
$data = ['username' => $adminUsername, 'email' => $adminEmail, 'password' => $newPassword, 'salt' => $newSalt]; $data = ['username' => $adminUsername, 'email' => $adminEmail, 'avatar' => $avatar, 'password' => $newPassword, 'salt' => $newSalt];
$instance->name('admin')->where('username', 'admin')->update($data); $instance->name('admin')->where('username', 'admin')->update($data);
// 变更前台默认用户的密码,随机生成
$newSalt = substr(md5(uniqid(true)), 0, 6);
$newPassword = md5(md5(Random::alnum(8)) . $newSalt);
$instance->name('user')->where('username', 'admin')->update(['avatar' => $avatar, 'password' => $newPassword, 'salt' => $newSalt]);
// 修改后台入口 // 修改后台入口
$adminName = ''; $adminName = '';
if (is_file($adminFile)) { if (is_file($adminFile)) {
@ -230,22 +259,22 @@ class Install extends Command
} }
//修改站点名称 //修改站点名称
if ($siteName != __('My Website')) { if ($siteName != config('site.name')) {
$instance->name('config')->where('name', 'name')->update(['value' => $siteName]); $instance->name('config')->where('name', 'name')->update(['value' => $siteName]);
$configFile = APP_PATH . 'extra' . DS . 'site.php'; $siteConfigFile = CONF_PATH . 'extra' . DS . 'site.php';
$config = include $configFile; $siteConfig = include $siteConfigFile;
$configList = $instance->name("config")->select(); $configList = $instance->name("config")->select();
foreach ($configList as $k => $value) { foreach ($configList as $k => $value) {
if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'])) { if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'])) {
$value['value'] = explode(',', $value['value']); $value['value'] = is_array($value['value']) ? $value['value'] : explode(',', $value['value']);
} }
if ($value['type'] == 'array') { if ($value['type'] == 'array') {
$value['value'] = (array)json_decode($value['value'], true); $value['value'] = (array)json_decode($value['value'], true);
} }
$config[$value['name']] = $value['value']; $siteConfig[$value['name']] = $value['value'];
} }
$config['name'] = $siteName; $siteConfig['name'] = $siteName;
file_put_contents($configFile, '<?php' . "\n\nreturn " . var_export($config, true) . ";"); file_put_contents($siteConfigFile, '<?php' . "\n\nreturn " . var_export_short($siteConfig) . ";\n");
} }
$installLockFile = INSTALL_PATH . "install.lock"; $installLockFile = INSTALL_PATH . "install.lock";
@ -255,6 +284,13 @@ class Install extends Command
throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/admin/command/Install/install.lock')); throw new Exception(__('The current permissions are insufficient to write the file %s', 'application/admin/command/Install/install.lock'));
} }
try {
//删除安装脚本
@unlink(ROOT_PATH . 'public' . DS . 'install.php');
} catch (\Exception $e) {
}
return $adminName; return $adminName;
} }
@ -273,8 +309,8 @@ class Install extends Command
//数据库配置文件 //数据库配置文件
$dbConfigFile = APP_PATH . 'database.php'; $dbConfigFile = APP_PATH . 'database.php';
if (version_compare(PHP_VERSION, '5.5.0', '<')) { if (version_compare(PHP_VERSION, '7.4.0', '<')) {
throw new Exception(__("The current version %s is too low, please use PHP 5.5 or higher", PHP_VERSION)); throw new Exception(__("The current version %s is too low, please use PHP 7.4 or higher", PHP_VERSION));
} }
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

@ -1,6 +1,6 @@
/* /*
FastAdmin Install SQL FastAdmin Install SQL
Date: 20180526 Date: 2024-09-03 15:05:25
*/ */
SET FOREIGN_KEY_CHECKS = 0; SET FOREIGN_KEY_CHECKS = 0;
@ -8,119 +8,137 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_admin -- Table structure for fa_admin
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_admin`;
CREATE TABLE `fa_admin` ( CREATE TABLE `fa_admin` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名', `username` varchar(20) DEFAULT '' COMMENT '用户名',
`nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称', `nickname` varchar(50) DEFAULT '' COMMENT '昵称',
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '密码', `password` varchar(32) DEFAULT '' COMMENT '密码',
`salt` varchar(30) NOT NULL DEFAULT '' COMMENT '密码盐', `salt` varchar(30) DEFAULT '' COMMENT '密码盐',
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像', `avatar` varchar(255) DEFAULT '' COMMENT '头像',
`email` varchar(100) NOT NULL DEFAULT '' COMMENT '电子邮箱', `email` varchar(100) DEFAULT '' COMMENT '电子邮箱',
`mobile` varchar(11) DEFAULT '' COMMENT '手机号码',
`loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数', `loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数',
`logintime` int(10) DEFAULT NULL COMMENT '登录时间', `logintime` bigint(16) DEFAULT NULL COMMENT '登录时间',
`loginip` varchar(50) DEFAULT NULL COMMENT '登录IP', `loginip` varchar(50) DEFAULT NULL COMMENT '登录IP',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`token` varchar(59) NOT NULL DEFAULT '' COMMENT 'Session标识', `token` varchar(59) DEFAULT '' COMMENT 'Session标识',
`status` varchar(30) NOT NULL DEFAULT 'normal' COMMENT '状态', `status` varchar(30) NOT NULL DEFAULT 'normal' COMMENT '状态',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='管理员表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='管理员表';
-- ---------------------------- -- ----------------------------
-- Records of fa_admin -- Records of fa_admin
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_admin` VALUES (1, 'admin', 'Admin', '075eaec83636846f51c152f29b98a2fd', 's4f3', '/assets/img/avatar.png', 'admin@admin.com', 0, 1502029281, '127.0.0.1',1492186163, 1502029281, 'd3992c3b-5ecc-4ecb-9dc2-8997780fcadc', 'normal'); INSERT INTO `fa_admin` VALUES (1, 'admin', 'Admin', '', '', '/assets/img/avatar.png', 'admin@example.com', '', 0, 1491635035, '127.0.0.1',1491635035, 1491635035, '', 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_admin_log -- Table structure for fa_admin_log
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_admin_log`;
CREATE TABLE `fa_admin_log` ( CREATE TABLE `fa_admin_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID', `admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
`username` varchar(30) NOT NULL DEFAULT '' COMMENT '管理员名字', `username` varchar(30) DEFAULT '' COMMENT '管理员名字',
`url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面', `url` varchar(1500) DEFAULT '' COMMENT '操作页面',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '日志标题', `title` varchar(100) DEFAULT '' COMMENT '日志标题',
`content` text NOT NULL COMMENT '内容', `content` longtext NOT NULL COMMENT '内容',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP', `ip` varchar(50) DEFAULT '' COMMENT 'IP',
`useragent` varchar(255) NOT NULL DEFAULT '' COMMENT 'User-Agent', `useragent` varchar(255) DEFAULT '' COMMENT 'User-Agent',
`createtime` int(10) DEFAULT NULL COMMENT '操作时间', `createtime` bigint(16) DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `name` (`username`) KEY `name` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='管理员日志表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='管理员日志表';
-- ----------------------------
-- Table structure for fa_area
-- ----------------------------
CREATE TABLE `fa_area` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`pid` int(10) DEFAULT NULL COMMENT '父id',
`shortname` varchar(100) DEFAULT NULL COMMENT '简称',
`name` varchar(100) DEFAULT NULL COMMENT '名称',
`mergename` varchar(255) DEFAULT NULL COMMENT '全称',
`level` tinyint(4) DEFAULT NULL COMMENT '层级:1=省,2=市,3=区/县',
`pinyin` varchar(100) DEFAULT NULL COMMENT '拼音',
`code` varchar(100) DEFAULT NULL COMMENT '长途区号',
`zip` varchar(100) DEFAULT NULL COMMENT '邮编',
`first` varchar(50) DEFAULT NULL COMMENT '首字母',
`lng` varchar(100) DEFAULT NULL COMMENT '经度',
`lat` varchar(100) DEFAULT NULL COMMENT '纬度',
PRIMARY KEY (`id`),
KEY `pid` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='地区表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_attachment -- Table structure for fa_attachment
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_attachment`;
CREATE TABLE `fa_attachment` ( CREATE TABLE `fa_attachment` (
`id` int(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`category` varchar(50) DEFAULT '' COMMENT '类别',
`admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID', `admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID', `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '物理路径', `url` varchar(255) DEFAULT '' COMMENT '物理路径',
`imagewidth` varchar(30) NOT NULL DEFAULT '' COMMENT '宽度', `imagewidth` int(10) unsigned DEFAULT 0 COMMENT '宽度',
`imageheight` varchar(30) NOT NULL DEFAULT '' COMMENT '高度', `imageheight` int(10) unsigned DEFAULT 0 COMMENT '高度',
`imagetype` varchar(30) NOT NULL DEFAULT '' COMMENT '图片类型', `imagetype` varchar(30) DEFAULT '' COMMENT '图片类型',
`imageframes` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '图片帧数', `imageframes` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '图片帧数',
`filename` varchar(100) DEFAULT '' COMMENT '文件名称',
`filesize` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文件大小', `filesize` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文件大小',
`mimetype` varchar(100) NOT NULL DEFAULT '' COMMENT 'mime类型', `mimetype` varchar(100) DEFAULT '' COMMENT 'mime类型',
`extparam` varchar(255) NOT NULL DEFAULT '' COMMENT '透传数据', `extparam` varchar(255) DEFAULT '' COMMENT '透传数据',
`createtime` int(10) DEFAULT NULL COMMENT '创建日期', `createtime` bigint(16) DEFAULT NULL COMMENT '创建日期',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`uploadtime` int(10) DEFAULT NULL COMMENT '上传时间', `uploadtime` bigint(16) DEFAULT NULL COMMENT '上传时间',
`storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置', `storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置',
`sha1` varchar(40) NOT NULL DEFAULT '' COMMENT '文件 sha1编码', `sha1` varchar(40) DEFAULT '' COMMENT '文件 sha1编码',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='附件表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='附件表';
-- ---------------------------- -- ----------------------------
-- Records of fa_attachment -- Records of fa_attachment
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_attachment` VALUES (1, 1, 0, '/assets/img/qrcode.png', '150', '150', 'png', 0, 21859, 'image/png', '', 1499681848, 1499681848, 1499681848, 'local', '17163603d0263e4838b9387ff2cd4877e8b018f6'); INSERT INTO `fa_attachment` VALUES (1, '', 1, 0, '/assets/img/qrcode.png', '150', '150', 'png', 0, 'qrcode.png', 21859, 'image/png', '', 1491635035, 1491635035, 1491635035, 'local', '17163603d0263e4838b9387ff2cd4877e8b018f6');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_auth_group -- Table structure for fa_auth_group
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_auth_group`;
CREATE TABLE `fa_auth_group` ( CREATE TABLE `fa_auth_group` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父组别', `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父组别',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '组名', `name` varchar(100) DEFAULT '' COMMENT '组名',
`rules` text NOT NULL COMMENT '规则ID', `rules` text NOT NULL COMMENT '规则ID',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态', `status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='分组表'; ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='分组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_group -- Records of fa_auth_group
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_auth_group` VALUES (1, 0, 'Admin group', '*', 1490883540, 149088354, 'normal'); INSERT INTO `fa_auth_group` VALUES (1, 0, 'Admin group', '*', 1491635035, 1491635035, 'normal');
INSERT INTO `fa_auth_group` VALUES (2, 1, 'Second group', '13,14,16,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,1,9,10,11,7,6,8,2,4,5', 1490883540, 1505465692, 'normal'); INSERT INTO `fa_auth_group` VALUES (2, 1, 'Second group', '13,14,16,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,1,9,10,11,7,6,8,2,4,5', 1491635035, 1491635035, 'normal');
INSERT INTO `fa_auth_group` VALUES (3, 2, 'Third group', '1,4,9,10,11,13,14,15,16,17,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,5', 1490883540, 1502205322, 'normal'); INSERT INTO `fa_auth_group` VALUES (3, 2, 'Third group', '1,4,9,10,11,13,14,15,16,17,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,64,65,5', 1491635035, 1491635035, 'normal');
INSERT INTO `fa_auth_group` VALUES (4, 1, 'Second group 2', '1,4,13,14,15,16,17,55,56,57,58,59,60,61,62,63,64,65', 1490883540, 1502205350, 'normal'); INSERT INTO `fa_auth_group` VALUES (4, 1, 'Second group 2', '1,4,13,14,15,16,17,55,56,57,58,59,60,61,62,63,64,65', 1491635035, 1491635035, 'normal');
INSERT INTO `fa_auth_group` VALUES (5, 2, 'Third group 2', '1,2,6,7,8,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34', 1490883540, 1502205344, 'normal'); INSERT INTO `fa_auth_group` VALUES (5, 2, 'Third group 2', '1,2,6,7,8,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34', 1491635035, 1491635035, 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_auth_group_access -- Table structure for fa_auth_group_access
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_auth_group_access`;
CREATE TABLE `fa_auth_group_access` ( CREATE TABLE `fa_auth_group_access` (
`uid` int(10) unsigned NOT NULL COMMENT '会员ID', `uid` int(10) unsigned NOT NULL COMMENT '会员ID',
`group_id` int(10) unsigned NOT NULL COMMENT '级别ID', `group_id` int(10) unsigned NOT NULL COMMENT '级别ID',
UNIQUE KEY `uid_group_id` (`uid`,`group_id`), UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
KEY `uid` (`uid`), KEY `uid` (`uid`),
KEY `group_id` (`group_id`) KEY `group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限分组表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='权限分组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_group_access -- Records of fa_auth_group_access
@ -132,362 +150,366 @@ COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_auth_rule -- Table structure for fa_auth_rule
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_auth_rule`;
CREATE TABLE `fa_auth_rule` ( CREATE TABLE `fa_auth_rule` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` enum('menu','file') NOT NULL DEFAULT 'file' COMMENT 'menu为菜单,file为权限节点', `type` enum('menu','file') NOT NULL DEFAULT 'file' COMMENT 'menu为菜单,file为权限节点',
`pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID', `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则名称', `name` varchar(100) DEFAULT '' COMMENT '规则名称',
`title` varchar(50) NOT NULL DEFAULT '' COMMENT '规则名称', `title` varchar(50) DEFAULT '' COMMENT '规则名称',
`icon` varchar(50) NOT NULL DEFAULT '' COMMENT '图标', `icon` varchar(50) DEFAULT '' COMMENT '图标',
`condition` varchar(255) NOT NULL DEFAULT '' COMMENT '条件', `url` varchar(255) DEFAULT '' COMMENT '规则URL',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `condition` varchar(255) DEFAULT '' COMMENT '条件',
`remark` varchar(255) DEFAULT '' COMMENT '备注',
`ismenu` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否为菜单', `ismenu` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否为菜单',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `menutype` enum('addtabs','blank','dialog','ajax') DEFAULT NULL COMMENT '菜单类型',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `extend` varchar(255) DEFAULT '' COMMENT '扩展属性',
`py` varchar(30) DEFAULT '' COMMENT '拼音首字母',
`pinyin` varchar(100) DEFAULT '' COMMENT '拼音',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
`status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态', `status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`) USING BTREE, UNIQUE KEY `name` (`name`) USING BTREE,
KEY `pid` (`pid`), KEY `pid` (`pid`),
KEY `weigh` (`weigh`) KEY `weigh` (`weigh`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8 COMMENT='节点表'; ) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='节点表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_rule -- Records of fa_auth_rule
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_auth_rule` VALUES (1, 'file', 0, 'dashboard', 'Dashboard', 'fa fa-dashboard', '', 'Dashboard tips', 1, 1497429920, 1497429920, 143, 'normal'); INSERT INTO `fa_auth_rule` VALUES (1, 'file', 0, 'dashboard', 'Dashboard', 'fa fa-dashboard', '', '', 'Dashboard tips', 1, NULL, '', 'kzt', 'kongzhitai', 1491635035, 1491635035, 143, 'normal');
INSERT INTO `fa_auth_rule` VALUES (2, 'file', 0, 'general', 'General', 'fa fa-cogs', '', '', 1, 1497429920, 1497430169, 137, 'normal'); INSERT INTO `fa_auth_rule` VALUES (2, 'file', 0, 'general', 'General', 'fa fa-cogs', '', '', '', 1, NULL, '', 'cggl', 'changguiguanli', 1491635035, 1491635035, 137, 'normal');
INSERT INTO `fa_auth_rule` VALUES (3, 'file', 0, 'category', 'Category', 'fa fa-leaf', '', 'Category tips', 1, 1497429920, 1497429920, 119, 'normal'); INSERT INTO `fa_auth_rule` VALUES (3, 'file', 0, 'category', 'Category', 'fa fa-leaf', '', '', 'Category tips', 0, NULL, '', 'flgl', 'fenleiguanli', 1491635035, 1491635035, 119, 'normal');
INSERT INTO `fa_auth_rule` VALUES (4, 'file', 0, 'addon', 'Addon', 'fa fa-rocket', '', 'Addon tips', 1, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (4, 'file', 0, 'addon', 'Addon', 'fa fa-rocket', '', '', 'Addon tips', 1, NULL, '', 'cjgl', 'chajianguanli', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (5, 'file', 0, 'auth', 'Auth', 'fa fa-group', '', '', 1, 1497429920, 1497430092, 99, 'normal'); INSERT INTO `fa_auth_rule` VALUES (5, 'file', 0, 'auth', 'Auth', 'fa fa-group', '', '', '', 1, NULL, '', 'qxgl', 'quanxianguanli', 1491635035, 1491635035, 99, 'normal');
INSERT INTO `fa_auth_rule` VALUES (6, 'file', 2, 'general/config', 'Config', 'fa fa-cog', '', 'Config tips', 1, 1497429920, 1497430683, 60, 'normal'); INSERT INTO `fa_auth_rule` VALUES (6, 'file', 2, 'general/config', 'Config', 'fa fa-cog', '', '', 'Config tips', 1, NULL, '', 'xtpz', 'xitongpeizhi', 1491635035, 1491635035, 60, 'normal');
INSERT INTO `fa_auth_rule` VALUES (7, 'file', 2, 'general/attachment', 'Attachment', 'fa fa-file-image-o', '', 'Attachment tips', 1, 1497429920, 1497430699, 53, 'normal'); INSERT INTO `fa_auth_rule` VALUES (7, 'file', 2, 'general/attachment', 'Attachment', 'fa fa-file-image-o', '', '', 'Attachment tips', 1, NULL, '', 'fjgl', 'fujianguanli', 1491635035, 1491635035, 53, 'normal');
INSERT INTO `fa_auth_rule` VALUES (8, 'file', 2, 'general/profile', 'Profile', 'fa fa-user', '', '', 1, 1497429920, 1497429920, 34, 'normal'); INSERT INTO `fa_auth_rule` VALUES (8, 'file', 2, 'general/profile', 'Profile', 'fa fa-user', '', '', '', 1, NULL, '', 'grzl', 'gerenziliao', 1491635035, 1491635035, 34, 'normal');
INSERT INTO `fa_auth_rule` VALUES (9, 'file', 5, 'auth/admin', 'Admin', 'fa fa-user', '', 'Admin tips', 1, 1497429920, 1497430320, 118, 'normal'); INSERT INTO `fa_auth_rule` VALUES (9, 'file', 5, 'auth/admin', 'Admin', 'fa fa-user', '', '', 'Admin tips', 1, NULL, '', 'glygl', 'guanliyuanguanli', 1491635035, 1491635035, 118, 'normal');
INSERT INTO `fa_auth_rule` VALUES (10, 'file', 5, 'auth/adminlog', 'Admin log', 'fa fa-list-alt', '', 'Admin log tips', 1, 1497429920, 1497430307, 113, 'normal'); INSERT INTO `fa_auth_rule` VALUES (10, 'file', 5, 'auth/adminlog', 'Admin log', 'fa fa-list-alt', '', '', 'Admin log tips', 1, NULL, '', 'glyrz', 'guanliyuanrizhi', 1491635035, 1491635035, 113, 'normal');
INSERT INTO `fa_auth_rule` VALUES (11, 'file', 5, 'auth/group', 'Group', 'fa fa-group', '', 'Group tips', 1, 1497429920, 1497429920, 109, 'normal'); INSERT INTO `fa_auth_rule` VALUES (11, 'file', 5, 'auth/group', 'Group', 'fa fa-group', '', '', 'Group tips', 1, NULL, '', 'jsz', 'juesezu', 1491635035, 1491635035, 109, 'normal');
INSERT INTO `fa_auth_rule` VALUES (12, 'file', 5, 'auth/rule', 'Rule', 'fa fa-bars', '', 'Rule tips', 1, 1497429920, 1497430581, 104, 'normal'); INSERT INTO `fa_auth_rule` VALUES (12, 'file', 5, 'auth/rule', 'Rule', 'fa fa-bars', '', '', 'Rule tips', 1, NULL, '', 'cdgz', 'caidanguize', 1491635035, 1491635035, 104, 'normal');
INSERT INTO `fa_auth_rule` VALUES (13, 'file', 1, 'dashboard/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 136, 'normal'); INSERT INTO `fa_auth_rule` VALUES (13, 'file', 1, 'dashboard/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 136, 'normal');
INSERT INTO `fa_auth_rule` VALUES (14, 'file', 1, 'dashboard/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 135, 'normal'); INSERT INTO `fa_auth_rule` VALUES (14, 'file', 1, 'dashboard/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 135, 'normal');
INSERT INTO `fa_auth_rule` VALUES (15, 'file', 1, 'dashboard/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 133, 'normal'); INSERT INTO `fa_auth_rule` VALUES (15, 'file', 1, 'dashboard/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 133, 'normal');
INSERT INTO `fa_auth_rule` VALUES (16, 'file', 1, 'dashboard/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 134, 'normal'); INSERT INTO `fa_auth_rule` VALUES (16, 'file', 1, 'dashboard/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 134, 'normal');
INSERT INTO `fa_auth_rule` VALUES (17, 'file', 1, 'dashboard/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 132, 'normal'); INSERT INTO `fa_auth_rule` VALUES (17, 'file', 1, 'dashboard/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 132, 'normal');
INSERT INTO `fa_auth_rule` VALUES (18, 'file', 6, 'general/config/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 52, 'normal'); INSERT INTO `fa_auth_rule` VALUES (18, 'file', 6, 'general/config/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 52, 'normal');
INSERT INTO `fa_auth_rule` VALUES (19, 'file', 6, 'general/config/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 51, 'normal'); INSERT INTO `fa_auth_rule` VALUES (19, 'file', 6, 'general/config/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 51, 'normal');
INSERT INTO `fa_auth_rule` VALUES (20, 'file', 6, 'general/config/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 50, 'normal'); INSERT INTO `fa_auth_rule` VALUES (20, 'file', 6, 'general/config/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 50, 'normal');
INSERT INTO `fa_auth_rule` VALUES (21, 'file', 6, 'general/config/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 49, 'normal'); INSERT INTO `fa_auth_rule` VALUES (21, 'file', 6, 'general/config/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 49, 'normal');
INSERT INTO `fa_auth_rule` VALUES (22, 'file', 6, 'general/config/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 48, 'normal'); INSERT INTO `fa_auth_rule` VALUES (22, 'file', 6, 'general/config/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 48, 'normal');
INSERT INTO `fa_auth_rule` VALUES (23, 'file', 7, 'general/attachment/index', 'View', 'fa fa-circle-o', '', 'Attachment tips', 0, 1497429920, 1497429920, 59, 'normal'); INSERT INTO `fa_auth_rule` VALUES (23, 'file', 7, 'general/attachment/index', 'View', 'fa fa-circle-o', '', '', 'Attachment tips', 0, NULL, '', '', '', 1491635035, 1491635035, 59, 'normal');
INSERT INTO `fa_auth_rule` VALUES (24, 'file', 7, 'general/attachment/select', 'Select attachment', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 58, 'normal'); INSERT INTO `fa_auth_rule` VALUES (24, 'file', 7, 'general/attachment/select', 'Select attachment', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 58, 'normal');
INSERT INTO `fa_auth_rule` VALUES (25, 'file', 7, 'general/attachment/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 57, 'normal'); INSERT INTO `fa_auth_rule` VALUES (25, 'file', 7, 'general/attachment/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 57, 'normal');
INSERT INTO `fa_auth_rule` VALUES (26, 'file', 7, 'general/attachment/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 56, 'normal'); INSERT INTO `fa_auth_rule` VALUES (26, 'file', 7, 'general/attachment/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 56, 'normal');
INSERT INTO `fa_auth_rule` VALUES (27, 'file', 7, 'general/attachment/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 55, 'normal'); INSERT INTO `fa_auth_rule` VALUES (27, 'file', 7, 'general/attachment/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 55, 'normal');
INSERT INTO `fa_auth_rule` VALUES (28, 'file', 7, 'general/attachment/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 54, 'normal'); INSERT INTO `fa_auth_rule` VALUES (28, 'file', 7, 'general/attachment/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 54, 'normal');
INSERT INTO `fa_auth_rule` VALUES (29, 'file', 8, 'general/profile/index', 'View', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 33, 'normal'); INSERT INTO `fa_auth_rule` VALUES (29, 'file', 8, 'general/profile/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 33, 'normal');
INSERT INTO `fa_auth_rule` VALUES (30, 'file', 8, 'general/profile/update', 'Update profile', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 32, 'normal'); INSERT INTO `fa_auth_rule` VALUES (30, 'file', 8, 'general/profile/update', 'Update profile', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 32, 'normal');
INSERT INTO `fa_auth_rule` VALUES (31, 'file', 8, 'general/profile/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 31, 'normal'); INSERT INTO `fa_auth_rule` VALUES (31, 'file', 8, 'general/profile/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 31, 'normal');
INSERT INTO `fa_auth_rule` VALUES (32, 'file', 8, 'general/profile/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 30, 'normal'); INSERT INTO `fa_auth_rule` VALUES (32, 'file', 8, 'general/profile/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 30, 'normal');
INSERT INTO `fa_auth_rule` VALUES (33, 'file', 8, 'general/profile/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 29, 'normal'); INSERT INTO `fa_auth_rule` VALUES (33, 'file', 8, 'general/profile/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 29, 'normal');
INSERT INTO `fa_auth_rule` VALUES (34, 'file', 8, 'general/profile/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 28, 'normal'); INSERT INTO `fa_auth_rule` VALUES (34, 'file', 8, 'general/profile/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 28, 'normal');
INSERT INTO `fa_auth_rule` VALUES (35, 'file', 3, 'category/index', 'View', 'fa fa-circle-o', '', 'Category tips', 0, 1497429920, 1497429920, 142, 'normal'); INSERT INTO `fa_auth_rule` VALUES (35, 'file', 3, 'category/index', 'View', 'fa fa-circle-o', '', '', 'Category tips', 0, NULL, '', '', '', 1491635035, 1491635035, 142, 'normal');
INSERT INTO `fa_auth_rule` VALUES (36, 'file', 3, 'category/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 141, 'normal'); INSERT INTO `fa_auth_rule` VALUES (36, 'file', 3, 'category/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 141, 'normal');
INSERT INTO `fa_auth_rule` VALUES (37, 'file', 3, 'category/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 140, 'normal'); INSERT INTO `fa_auth_rule` VALUES (37, 'file', 3, 'category/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 140, 'normal');
INSERT INTO `fa_auth_rule` VALUES (38, 'file', 3, 'category/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 139, 'normal'); INSERT INTO `fa_auth_rule` VALUES (38, 'file', 3, 'category/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 139, 'normal');
INSERT INTO `fa_auth_rule` VALUES (39, 'file', 3, 'category/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 138, 'normal'); INSERT INTO `fa_auth_rule` VALUES (39, 'file', 3, 'category/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 138, 'normal');
INSERT INTO `fa_auth_rule` VALUES (40, 'file', 9, 'auth/admin/index', 'View', 'fa fa-circle-o', '', 'Admin tips', 0, 1497429920, 1497429920, 117, 'normal'); INSERT INTO `fa_auth_rule` VALUES (40, 'file', 9, 'auth/admin/index', 'View', 'fa fa-circle-o', '', '', 'Admin tips', 0, NULL, '', '', '', 1491635035, 1491635035, 117, 'normal');
INSERT INTO `fa_auth_rule` VALUES (41, 'file', 9, 'auth/admin/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 116, 'normal'); INSERT INTO `fa_auth_rule` VALUES (41, 'file', 9, 'auth/admin/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 116, 'normal');
INSERT INTO `fa_auth_rule` VALUES (42, 'file', 9, 'auth/admin/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 115, 'normal'); INSERT INTO `fa_auth_rule` VALUES (42, 'file', 9, 'auth/admin/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 115, 'normal');
INSERT INTO `fa_auth_rule` VALUES (43, 'file', 9, 'auth/admin/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 114, 'normal'); INSERT INTO `fa_auth_rule` VALUES (43, 'file', 9, 'auth/admin/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 114, 'normal');
INSERT INTO `fa_auth_rule` VALUES (44, 'file', 10, 'auth/adminlog/index', 'View', 'fa fa-circle-o', '', 'Admin log tips', 0, 1497429920, 1497429920, 112, 'normal'); INSERT INTO `fa_auth_rule` VALUES (44, 'file', 10, 'auth/adminlog/index', 'View', 'fa fa-circle-o', '', '', 'Admin log tips', 0, NULL, '', '', '', 1491635035, 1491635035, 112, 'normal');
INSERT INTO `fa_auth_rule` VALUES (45, 'file', 10, 'auth/adminlog/detail', 'Detail', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 111, 'normal'); INSERT INTO `fa_auth_rule` VALUES (45, 'file', 10, 'auth/adminlog/detail', 'Detail', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 111, 'normal');
INSERT INTO `fa_auth_rule` VALUES (46, 'file', 10, 'auth/adminlog/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 110, 'normal'); INSERT INTO `fa_auth_rule` VALUES (46, 'file', 10, 'auth/adminlog/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 110, 'normal');
INSERT INTO `fa_auth_rule` VALUES (47, 'file', 11, 'auth/group/index', 'View', 'fa fa-circle-o', '', 'Group tips', 0, 1497429920, 1497429920, 108, 'normal'); INSERT INTO `fa_auth_rule` VALUES (47, 'file', 11, 'auth/group/index', 'View', 'fa fa-circle-o', '', '', 'Group tips', 0, NULL, '', '', '', 1491635035, 1491635035, 108, 'normal');
INSERT INTO `fa_auth_rule` VALUES (48, 'file', 11, 'auth/group/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 107, 'normal'); INSERT INTO `fa_auth_rule` VALUES (48, 'file', 11, 'auth/group/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 107, 'normal');
INSERT INTO `fa_auth_rule` VALUES (49, 'file', 11, 'auth/group/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 106, 'normal'); INSERT INTO `fa_auth_rule` VALUES (49, 'file', 11, 'auth/group/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 106, 'normal');
INSERT INTO `fa_auth_rule` VALUES (50, 'file', 11, 'auth/group/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 105, 'normal'); INSERT INTO `fa_auth_rule` VALUES (50, 'file', 11, 'auth/group/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 105, 'normal');
INSERT INTO `fa_auth_rule` VALUES (51, 'file', 12, 'auth/rule/index', 'View', 'fa fa-circle-o', '', 'Rule tips', 0, 1497429920, 1497429920, 103, 'normal'); INSERT INTO `fa_auth_rule` VALUES (51, 'file', 12, 'auth/rule/index', 'View', 'fa fa-circle-o', '', '', 'Rule tips', 0, NULL, '', '', '', 1491635035, 1491635035, 103, 'normal');
INSERT INTO `fa_auth_rule` VALUES (52, 'file', 12, 'auth/rule/add', 'Add', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 102, 'normal'); INSERT INTO `fa_auth_rule` VALUES (52, 'file', 12, 'auth/rule/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 102, 'normal');
INSERT INTO `fa_auth_rule` VALUES (53, 'file', 12, 'auth/rule/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 101, 'normal'); INSERT INTO `fa_auth_rule` VALUES (53, 'file', 12, 'auth/rule/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 101, 'normal');
INSERT INTO `fa_auth_rule` VALUES (54, 'file', 12, 'auth/rule/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1497429920, 1497429920, 100, 'normal'); INSERT INTO `fa_auth_rule` VALUES (54, 'file', 12, 'auth/rule/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 100, 'normal');
INSERT INTO `fa_auth_rule` VALUES (55, 'file', 4, 'addon/index', 'View', 'fa fa-circle-o', '', 'Addon tips', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (55, 'file', 4, 'addon/index', 'View', 'fa fa-circle-o', '', '', 'Addon tips', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (56, 'file', 4, 'addon/add', 'Add', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (56, 'file', 4, 'addon/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (57, 'file', 4, 'addon/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (57, 'file', 4, 'addon/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (58, 'file', 4, 'addon/del', 'Delete', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (58, 'file', 4, 'addon/del', 'Delete', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (59, 'file', 4, 'addon/downloaded', 'Local addon', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (59, 'file', 4, 'addon/downloaded', 'Local addon', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (60, 'file', 4, 'addon/state', 'Update state', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (60, 'file', 4, 'addon/state', 'Update state', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (63, 'file', 4, 'addon/config', 'Setting', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (63, 'file', 4, 'addon/config', 'Setting', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (64, 'file', 4, 'addon/refresh', 'Refresh', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (64, 'file', 4, 'addon/refresh', 'Refresh', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (65, 'file', 4, 'addon/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (65, 'file', 4, 'addon/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (66, 'file', 0, 'user', 'User', 'fa fa-list', '', '', 1, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (66, 'file', 0, 'user', 'User', 'fa fa-user-circle', '', '', '', 1, NULL, '', 'hygl', 'huiyuanguanli', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (67, 'file', 66, 'user/user', 'User', 'fa fa-user', '', '', 1, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (67, 'file', 66, 'user/user', 'User', 'fa fa-user', '', '', '', 1, NULL, '', 'hygl', 'huiyuanguanli', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (68, 'file', 67, 'user/user/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (68, 'file', 67, 'user/user/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (69, 'file', 67, 'user/user/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (69, 'file', 67, 'user/user/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (70, 'file', 67, 'user/user/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (70, 'file', 67, 'user/user/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (71, 'file', 67, 'user/user/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (71, 'file', 67, 'user/user/del', 'Del', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (72, 'file', 67, 'user/user/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (72, 'file', 67, 'user/user/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (73, 'file', 66, 'user/group', 'User group', 'fa fa-users', '', '', 1, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (73, 'file', 66, 'user/group', 'User group', 'fa fa-users', '', '', '', 1, NULL, '', 'hyfz', 'huiyuanfenzu', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (74, 'file', 73, 'user/group/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (74, 'file', 73, 'user/group/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (75, 'file', 73, 'user/group/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (75, 'file', 73, 'user/group/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (76, 'file', 73, 'user/group/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (76, 'file', 73, 'user/group/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (77, 'file', 73, 'user/group/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (77, 'file', 73, 'user/group/del', 'Del', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (78, 'file', 73, 'user/group/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (78, 'file', 73, 'user/group/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (79, 'file', 66, 'user/rule', 'User rule', 'fa fa-circle-o', '', '', 1, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (79, 'file', 66, 'user/rule', 'User rule', 'fa fa-circle-o', '', '', '', 1, NULL, '', 'hygz', 'huiyuanguize', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (80, 'file', 79, 'user/rule/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (80, 'file', 79, 'user/rule/index', 'View', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (81, 'file', 79, 'user/rule/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (81, 'file', 79, 'user/rule/del', 'Del', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (82, 'file', 79, 'user/rule/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (82, 'file', 79, 'user/rule/add', 'Add', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (83, 'file', 79, 'user/rule/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (83, 'file', 79, 'user/rule/edit', 'Edit', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (84, 'file', 79, 'user/rule/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal'); INSERT INTO `fa_auth_rule` VALUES (84, 'file', 79, 'user/rule/multi', 'Multi', 'fa fa-circle-o', '', '', '', 0, NULL, '', '', '', 1491635035, 1491635035, 0, 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_category -- Table structure for fa_category
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_category`;
CREATE TABLE `fa_category` ( CREATE TABLE `fa_category` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID', `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
`type` varchar(30) NOT NULL DEFAULT '' COMMENT '栏目类型', `type` varchar(30) DEFAULT '' COMMENT '栏目类型',
`name` varchar(30) NOT NULL DEFAULT '', `name` varchar(30) DEFAULT '',
`nickname` varchar(50) NOT NULL DEFAULT '', `nickname` varchar(50) DEFAULT '',
`flag` set('hot','index','recommend') NOT NULL DEFAULT '', `flag` set('hot','index','recommend') DEFAULT '',
`image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片', `image` varchar(100) DEFAULT '' COMMENT '图片',
`keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字', `keywords` varchar(255) DEFAULT '' COMMENT '关键字',
`description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述', `description` varchar(255) DEFAULT '' COMMENT '描述',
`diyname` varchar(30) NOT NULL DEFAULT '' COMMENT '自定义名称', `diyname` varchar(30) DEFAULT '' COMMENT '自定义名称',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
`status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态', `status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `weigh` (`weigh`,`id`), KEY `weigh` (`weigh`,`id`),
KEY `pid` (`pid`) KEY `pid` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='分类表'; ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='分类表';
-- ---------------------------- -- ----------------------------
-- Records of fa_category -- Records of fa_category
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_category` VALUES (1, 0, 'page', '官方新闻', 'news', 'recommend', '/assets/img/qrcode.png', '', '', 'news', 1495262190, 1495262190, 1, 'normal'); INSERT INTO `fa_category` VALUES (1, 0, 'page', '官方新闻', 'news', 'recommend', '/assets/img/qrcode.png', '', '', 'news', 1491635035, 1491635035, 1, 'normal');
INSERT INTO `fa_category` VALUES (2, 0, 'page', '移动应用', 'mobileapp', 'hot', '/assets/img/qrcode.png', '', '', 'mobileapp', 1495262244, 1495262244, 2, 'normal'); INSERT INTO `fa_category` VALUES (2, 0, 'page', '移动应用', 'mobileapp', 'hot', '/assets/img/qrcode.png', '', '', 'mobileapp', 1491635035, 1491635035, 2, 'normal');
INSERT INTO `fa_category` VALUES (3, 2, 'page', '微信公众号', 'wechatpublic', 'index', '/assets/img/qrcode.png', '', '', 'wechatpublic', 1495262288, 1495262288, 3, 'normal'); INSERT INTO `fa_category` VALUES (3, 2, 'page', '微信公众号', 'wechatpublic', 'index', '/assets/img/qrcode.png', '', '', 'wechatpublic', 1491635035, 1491635035, 3, 'normal');
INSERT INTO `fa_category` VALUES (4, 2, 'page', 'Android开发', 'android', 'recommend', '/assets/img/qrcode.png', '', '', 'android', 1495262317, 1495262317, 4, 'normal'); INSERT INTO `fa_category` VALUES (4, 2, 'page', 'Android开发', 'android', 'recommend', '/assets/img/qrcode.png', '', '', 'android', 1491635035, 1491635035, 4, 'normal');
INSERT INTO `fa_category` VALUES (5, 0, 'page', '软件产品', 'software', 'recommend', '/assets/img/qrcode.png', '', '', 'software', 1495262336, 1499681850, 5, 'normal'); INSERT INTO `fa_category` VALUES (5, 0, 'page', '软件产品', 'software', 'recommend', '/assets/img/qrcode.png', '', '', 'software', 1491635035, 1491635035, 5, 'normal');
INSERT INTO `fa_category` VALUES (6, 5, 'page', '网站建站', 'website', 'recommend', '/assets/img/qrcode.png', '', '', 'website', 1495262357, 1495262357, 6, 'normal'); INSERT INTO `fa_category` VALUES (6, 5, 'page', '网站建站', 'website', 'recommend', '/assets/img/qrcode.png', '', '', 'website', 1491635035, 1491635035, 6, 'normal');
INSERT INTO `fa_category` VALUES (7, 5, 'page', '企业管理软件', 'company', 'index', '/assets/img/qrcode.png', '', '', 'company', 1495262391, 1495262391, 7, 'normal'); INSERT INTO `fa_category` VALUES (7, 5, 'page', '企业管理软件', 'company', 'index', '/assets/img/qrcode.png', '', '', 'company', 1491635035, 1491635035, 7, 'normal');
INSERT INTO `fa_category` VALUES (8, 6, 'page', 'PC端', 'website-pc', 'recommend', '/assets/img/qrcode.png', '', '', 'website-pc', 1495262424, 1495262424, 8, 'normal'); INSERT INTO `fa_category` VALUES (8, 6, 'page', 'PC端', 'website-pc', 'recommend', '/assets/img/qrcode.png', '', '', 'website-pc', 1491635035, 1491635035, 8, 'normal');
INSERT INTO `fa_category` VALUES (9, 6, 'page', '移动端', 'website-mobile', 'recommend', '/assets/img/qrcode.png', '', '', 'website-mobile', 1495262456, 1495262456, 9, 'normal'); INSERT INTO `fa_category` VALUES (9, 6, 'page', '移动端', 'website-mobile', 'recommend', '/assets/img/qrcode.png', '', '', 'website-mobile', 1491635035, 1491635035, 9, 'normal');
INSERT INTO `fa_category` VALUES (10, 7, 'page', 'CRM系统 ', 'company-crm', 'recommend', '/assets/img/qrcode.png', '', '', 'company-crm', 1495262487, 1495262487, 10, 'normal'); INSERT INTO `fa_category` VALUES (10, 7, 'page', 'CRM系统 ', 'company-crm', 'recommend', '/assets/img/qrcode.png', '', '', 'company-crm', 1491635035, 1491635035, 10, 'normal');
INSERT INTO `fa_category` VALUES (11, 7, 'page', 'SASS平台软件', 'company-sass', 'recommend', '/assets/img/qrcode.png', '', '', 'company-sass', 1495262515, 1495262515, 11, 'normal'); INSERT INTO `fa_category` VALUES (11, 7, 'page', 'SASS平台软件', 'company-sass', 'recommend', '/assets/img/qrcode.png', '', '', 'company-sass', 1491635035, 1491635035, 11, 'normal');
INSERT INTO `fa_category` VALUES (12, 0, 'test', '测试1', 'test1', 'recommend', '/assets/img/qrcode.png', '', '', 'test1', 1497015727, 1497015727, 12, 'normal'); INSERT INTO `fa_category` VALUES (12, 0, 'test', '测试1', 'test1', 'recommend', '/assets/img/qrcode.png', '', '', 'test1', 1491635035, 1491635035, 12, 'normal');
INSERT INTO `fa_category` VALUES (13, 0, 'test', '测试2', 'test2', 'recommend', '/assets/img/qrcode.png', '', '', 'test2', 1497015738, 1497015738, 13, 'normal'); INSERT INTO `fa_category` VALUES (13, 0, 'test', '测试2', 'test2', 'recommend', '/assets/img/qrcode.png', '', '', 'test2', 1491635035, 1491635035, 13, 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_config -- Table structure for fa_config
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_config`;
CREATE TABLE `fa_config` ( CREATE TABLE `fa_config` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '' COMMENT '变量名', `name` varchar(30) DEFAULT '' COMMENT '变量名',
`group` varchar(30) NOT NULL DEFAULT '' COMMENT '分组', `group` varchar(30) DEFAULT '' COMMENT '分组',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '变量标题', `title` varchar(100) DEFAULT '' COMMENT '变量标题',
`tip` varchar(100) NOT NULL DEFAULT '' COMMENT '变量描述', `tip` varchar(100) DEFAULT '' COMMENT '变量描述',
`type` varchar(30) NOT NULL DEFAULT '' COMMENT '类型:string,text,int,bool,array,datetime,date,file', `type` varchar(30) DEFAULT '' COMMENT '类型:string,text,int,bool,array,datetime,date,file',
`value` text NOT NULL COMMENT '变量值', `visible` varchar(255) DEFAULT '' COMMENT '可见条件',
`content` text NOT NULL COMMENT '变量字典数据', `value` text COMMENT '变量值',
`rule` varchar(100) NOT NULL DEFAULT '' COMMENT '验证规则', `content` text COMMENT '变量字典数据',
`extend` varchar(255) NOT NULL DEFAULT '' COMMENT '扩展属性', `rule` varchar(100) DEFAULT '' COMMENT '验证规则',
`extend` varchar(255) DEFAULT '' COMMENT '扩展属性',
`setting` varchar(255) DEFAULT '' COMMENT '配置',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`) UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COMMENT='系统配置'; ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='系统配置';
-- ---------------------------- -- ----------------------------
-- Records of fa_config -- Records of fa_config
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_config` VALUES (1, 'name', 'basic', 'Site name', '请填写站点名称', 'string', '我的网站', '', 'required', ''); INSERT INTO `fa_config` VALUES (1, 'name', 'basic', 'Site name', '请填写站点名称', 'string', '', '我的网站', '', 'required', '', '');
INSERT INTO `fa_config` VALUES (2, 'beian', 'basic', 'Beian', '粤ICP备15000000号-1', 'string', '', '', '', ''); INSERT INTO `fa_config` VALUES (2, 'beian', 'basic', 'Beian', '粤ICP备15000000号-1', 'string', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (3, 'cdnurl', 'basic', 'Cdn url', '如果静态资源使用第三方云储存请配置该值', 'string', '', '', '', ''); INSERT INTO `fa_config` VALUES (3, 'cdnurl', 'basic', 'Cdn url', '如果全站静态资源使用第三方云储存请配置该值', 'string', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (4, 'version', 'basic', 'Version', '如果静态资源有变动请重新配置该值', 'string', '1.0.1', '', 'required', ''); INSERT INTO `fa_config` VALUES (4, 'version', 'basic', 'Version', '如果静态资源有变动请重新配置该值', 'string', '', '1.0.1', '', 'required', '', '');
INSERT INTO `fa_config` VALUES (5, 'timezone', 'basic', 'Timezone', '', 'string', 'Asia/Shanghai', '', 'required', ''); INSERT INTO `fa_config` VALUES (5, 'timezone', 'basic', 'Timezone', '', 'string', '', 'Asia/Shanghai', '', 'required', '', '');
INSERT INTO `fa_config` VALUES (6, 'forbiddenip', 'basic', 'Forbidden ip', '一行一条记录', 'text', '', '', '', ''); INSERT INTO `fa_config` VALUES (6, 'forbiddenip', 'basic', 'Forbidden ip', '一行一条记录', 'text', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (7, 'languages', 'basic', 'Languages', '', 'array', '{\"backend\":\"zh-cn\",\"frontend\":\"zh-cn\"}', '', 'required', ''); INSERT INTO `fa_config` VALUES (7, 'languages', 'basic', 'Languages', '', 'array', '', '{\"backend\":\"zh-cn\",\"frontend\":\"zh-cn\"}', '', 'required', '', '');
INSERT INTO `fa_config` VALUES (8, 'fixedpage', 'basic', 'Fixed page', '请尽量输入左侧菜单栏存在的链接', 'string', 'dashboard', '', 'required', ''); INSERT INTO `fa_config` VALUES (8, 'fixedpage', 'basic', 'Fixed page', '请输入左侧菜单栏存在的链接', 'string', '', 'dashboard', '', 'required', '', '');
INSERT INTO `fa_config` VALUES (9, 'categorytype', 'dictionary', 'Category type', '', 'array', '{\"default\":\"Default\",\"page\":\"Page\",\"article\":\"Article\",\"test\":\"Test\"}', '', '', ''); INSERT INTO `fa_config` VALUES (9, 'categorytype', 'dictionary', 'Category type', '', 'array', '', '{\"default\":\"Default\",\"page\":\"Page\",\"article\":\"Article\",\"test\":\"Test\"}', '', '', '', '');
INSERT INTO `fa_config` VALUES (10, 'configgroup', 'dictionary', 'Config group', '', 'array', '{\"basic\":\"Basic\",\"email\":\"Email\",\"dictionary\":\"Dictionary\",\"user\":\"User\",\"example\":\"Example\"}', '', '', ''); INSERT INTO `fa_config` VALUES (10, 'configgroup', 'dictionary', 'Config group', '', 'array', '', '{\"basic\":\"Basic\",\"email\":\"Email\",\"dictionary\":\"Dictionary\",\"user\":\"User\",\"example\":\"Example\"}', '', '', '', '');
INSERT INTO `fa_config` VALUES (11, 'mail_type', 'email', 'Mail type', '选择邮件发送方式', 'select', '1', '[\"Please select\",\"SMTP\",\"Mail\"]', '', ''); INSERT INTO `fa_config` VALUES (11, 'mail_type', 'email', 'Mail type', '选择邮件发送方式', 'select', '', '1', '[\"请选择\",\"SMTP\"]', '', '', '');
INSERT INTO `fa_config` VALUES (12, 'mail_smtp_host', 'email', 'Mail smtp host', '错误的配置发送邮件会导致服务器超时', 'string', 'smtp.qq.com', '', '', ''); INSERT INTO `fa_config` VALUES (12, 'mail_smtp_host', 'email', 'Mail smtp host', '错误的配置发送邮件会导致服务器超时', 'string', '', 'smtp.qq.com', '', '', '', '');
INSERT INTO `fa_config` VALUES (13, 'mail_smtp_port', 'email', 'Mail smtp port', '(不加密默认25,SSL默认465,TLS默认587)', 'string', '465', '', '', ''); INSERT INTO `fa_config` VALUES (13, 'mail_smtp_port', 'email', 'Mail smtp port', '(不加密默认25,SSL默认465,TLS默认587)', 'string', '', '465', '', '', '', '');
INSERT INTO `fa_config` VALUES (14, 'mail_smtp_user', 'email', 'Mail smtp user', '(填写完整用户名)', 'string', '10000', '', '', ''); INSERT INTO `fa_config` VALUES (14, 'mail_smtp_user', 'email', 'Mail smtp user', '(填写完整用户名)', 'string', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (15, 'mail_smtp_pass', 'email', 'Mail smtp password', '(填写您的密码)', 'string', 'password', '', '', ''); INSERT INTO `fa_config` VALUES (15, 'mail_smtp_pass', 'email', 'Mail smtp password', '(填写您的密码或授权码)', 'password', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (16, 'mail_verify_type', 'email', 'Mail vertify type', 'SMTP验证方式[推荐SSL]', 'select', '2', '[\"None\",\"TLS\",\"SSL\"]', '', ''); INSERT INTO `fa_config` VALUES (16, 'mail_verify_type', 'email', 'Mail vertify type', 'SMTP验证方式[推荐SSL]', 'select', '', '2', '[\"无\",\"TLS\",\"SSL\"]', '', '', '');
INSERT INTO `fa_config` VALUES (17, 'mail_from', 'email', 'Mail from', '', 'string', '10000@qq.com', '', '', ''); INSERT INTO `fa_config` VALUES (17, 'mail_from', 'email', 'Mail from', '', 'string', '', '', '', '', '', '');
INSERT INTO `fa_config` VALUES (18, 'attachmentcategory', 'dictionary', 'Attachment category', '', 'array', '', '{\"category1\":\"Category1\",\"category2\":\"Category2\",\"custom\":\"Custom\"}', '', '', '', '');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_ems -- Table structure for fa_ems
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_ems`;
CREATE TABLE `fa_ems` ( CREATE TABLE `fa_ems` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`event` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '事件', `event` varchar(30) DEFAULT '' COMMENT '事件',
`email` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '邮箱', `email` varchar(100) DEFAULT '' COMMENT '邮箱',
`code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '验证码', `code` varchar(10) DEFAULT '' COMMENT '验证码',
`times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数', `times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数',
`ip` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP', `ip` varchar(30) DEFAULT '' COMMENT 'IP',
`createtime` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='邮箱验证码表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='邮箱验证码表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_sms -- Table structure for fa_sms
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_sms`;
CREATE TABLE `fa_sms` ( CREATE TABLE `fa_sms` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`event` varchar(30) NOT NULL DEFAULT '' COMMENT '事件', `event` varchar(30) DEFAULT '' COMMENT '事件',
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号', `mobile` varchar(20) DEFAULT '' COMMENT '手机号',
`code` varchar(10) NOT NULL DEFAULT '' COMMENT '验证码', `code` varchar(10) DEFAULT '' COMMENT '验证码',
`times` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '验证次数', `times` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '验证次数',
`ip` varchar(30) NOT NULL DEFAULT '' COMMENT 'IP', `ip` varchar(30) DEFAULT '' COMMENT 'IP',
`createtime` int(10) unsigned DEFAULT '0' COMMENT '创建时间', `createtime` bigint(16) unsigned DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='短信验证码表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='短信验证码表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_test -- Table structure for fa_test
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_test`;
CREATE TABLE `fa_test` ( CREATE TABLE `fa_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) NOT NULL DEFAULT '0' COMMENT '管理员ID', `user_id` int(10) DEFAULT '0' COMMENT '会员ID',
`category_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分类ID(单选)', `admin_id` int(10) DEFAULT '0' COMMENT '管理员ID',
`category_ids` varchar(100) NOT NULL COMMENT '分类ID(多选)', `category_id` int(10) unsigned DEFAULT '0' COMMENT '分类ID(单选)',
`week` enum('monday','tuesday','wednesday') NOT NULL COMMENT '星期(单选):monday=星期一,tuesday=星期二,wednesday=星期三', `category_ids` varchar(100) COMMENT '分类ID(多选)',
`flag` set('hot','index','recommend') NOT NULL DEFAULT '' COMMENT '标志(多选):hot=热门,index=首页,recommend=推荐', `tags` varchar(255) DEFAULT '' COMMENT '标签',
`genderdata` enum('male','female') NOT NULL DEFAULT 'male' COMMENT '性别(单选):male=男,female=女', `week` enum('monday','tuesday','wednesday') COMMENT '星期(单选):monday=星期一,tuesday=星期二,wednesday=星期三',
`hobbydata` set('music','reading','swimming') NOT NULL COMMENT '爱好(多选):music=音乐,reading=读书,swimming=游泳', `flag` set('hot','index','recommend') DEFAULT '' COMMENT '标志(多选):hot=热门,index=首页,recommend=推荐',
`title` varchar(50) NOT NULL DEFAULT '' COMMENT '标题', `genderdata` enum('male','female') DEFAULT 'male' COMMENT '性别(单选):male=男,female=女',
`content` text NOT NULL COMMENT '内容', `hobbydata` set('music','reading','swimming') COMMENT '爱好(多选):music=音乐,reading=读书,swimming=游泳',
`image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片', `title` varchar(100) DEFAULT '' COMMENT '标题',
`images` varchar(1500) NOT NULL DEFAULT '' COMMENT '图片组', `content` text COMMENT '内容',
`attachfile` varchar(100) NOT NULL DEFAULT '' COMMENT '附件', `image` varchar(100) DEFAULT '' COMMENT '图片',
`keywords` varchar(100) NOT NULL DEFAULT '' COMMENT '关键字', `images` varchar(1500) DEFAULT '' COMMENT '图片组',
`description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述', `attachfile` varchar(100) DEFAULT '' COMMENT '附件',
`city` varchar(100) NOT NULL DEFAULT '' COMMENT '省市', `keywords` varchar(255) DEFAULT '' COMMENT '关键字',
`json` varchar(255) DEFAULT NULL COMMENT '配置:key=名称,value=值', `description` varchar(255) DEFAULT '' COMMENT '描述',
`price` float(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '价格', `city` varchar(100) DEFAULT '' COMMENT '省市',
`views` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '点击', `array` varchar(255) DEFAULT '' COMMENT '数组:value=值',
`json` varchar(255) DEFAULT '' COMMENT '配置:key=名称,value=值',
`multiplejson` varchar(1500) DEFAULT '' COMMENT '二维数组:title=标题,intro=介绍,author=作者,age=年龄',
`price` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '价格',
`views` int(10) unsigned DEFAULT '0' COMMENT '点击',
`workrange` varchar(100) DEFAULT '' COMMENT '时间区间',
`startdate` date DEFAULT NULL COMMENT '开始日期', `startdate` date DEFAULT NULL COMMENT '开始日期',
`activitytime` datetime DEFAULT NULL COMMENT '活动时间(datetime)', `activitytime` datetime DEFAULT NULL COMMENT '活动时间(datetime)',
`year` year(4) DEFAULT NULL COMMENT '', `year` year(4) DEFAULT NULL COMMENT '',
`times` time DEFAULT NULL COMMENT '时间', `times` time DEFAULT NULL COMMENT '时间',
`refreshtime` int(10) DEFAULT NULL COMMENT '刷新时间(int)', `refreshtime` bigint(16) DEFAULT NULL COMMENT '刷新时间',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`deletetime` int(10) DEFAULT NULL COMMENT '删除时间', `deletetime` bigint(16) DEFAULT NULL COMMENT '删除时间',
`weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', `weigh` int(10) DEFAULT '0' COMMENT '权重',
`switch` tinyint(1) NOT NULL DEFAULT '0' COMMENT '开关', `switch` tinyint(1) DEFAULT '0' COMMENT '开关',
`status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态', `status` enum('normal','hidden') DEFAULT 'normal' COMMENT '状态',
`state` enum('0','1','2') NOT NULL DEFAULT '1' COMMENT '状态值:0=禁用,1=正常,2=推荐', `state` enum('0','1','2') DEFAULT '1' COMMENT '状态值:0=禁用,1=正常,2=推荐',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='测试表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='测试表';
-- ---------------------------- -- ----------------------------
-- Records of fa_test -- Records of fa_test
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_test` VALUES (1, 0, 12, '12,13', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '描述', '广西壮族自治区/百色市/平果县', '{\"a\":\"1\",\"b\":\"2\"}', 0.00, 0, '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1499682285, 1499682526, 1499682526, NULL, 0, 1, 'normal', '1'); INSERT INTO `fa_test` VALUES (1, 1, 1, 12, '12,13', '互联网,计算机', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '我是一篇测试文章描述,内容过多时将自动隐藏', '广西壮族自治区/百色市/平果县', '[\"a\",\"b\"]', '{\"a\":\"1\",\"b\":\"2\"}', '[{\"title\":\"标题一\",\"intro\":\"介绍一\",\"author\":\"小明\",\"age\":\"21\"}]', 0.00, 0, '2020-10-01 00:00:00 - 2021-10-31 23:59:59', '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1491635035, 1491635035, 1491635035, NULL, 0, 1, 'normal', '1');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user -- Table structure for fa_user
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user`;
CREATE TABLE `fa_user` ( CREATE TABLE `fa_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '组别ID', `group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '组别ID',
`username` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名', `username` varchar(32) DEFAULT '' COMMENT '用户名',
`nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称', `nickname` varchar(50) DEFAULT '' COMMENT '昵称',
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '密码', `password` varchar(32) DEFAULT '' COMMENT '密码',
`salt` varchar(30) NOT NULL DEFAULT '' COMMENT '密码盐', `salt` varchar(30) DEFAULT '' COMMENT '密码盐',
`email` varchar(100) NOT NULL DEFAULT '' COMMENT '电子邮箱', `email` varchar(100) DEFAULT '' COMMENT '电子邮箱',
`mobile` varchar(11) NOT NULL DEFAULT '' COMMENT '手机号', `mobile` varchar(11) DEFAULT '' COMMENT '手机号',
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像', `avatar` varchar(255) DEFAULT '' COMMENT '头像',
`level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '等级', `level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '等级',
`gender` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别', `gender` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
`birthday` date COMMENT '生日', `birthday` date DEFAULT NULL COMMENT '生日',
`bio` varchar(100) NOT NULL DEFAULT '' COMMENT '格言', `bio` varchar(100) DEFAULT '' COMMENT '格言',
`money` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '余额', `money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '余额',
`score` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '积分', `score` int(10) NOT NULL DEFAULT '0' COMMENT '积分',
`successions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '连续登录天数', `successions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '连续登录天数',
`maxsuccessions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '最大连续登录天数', `maxsuccessions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '最大连续登录天数',
`prevtime` int(10) DEFAULT NULL COMMENT '上次登录时间', `prevtime` bigint(16) DEFAULT NULL COMMENT '上次登录时间',
`logintime` int(10) DEFAULT NULL COMMENT '登录时间', `logintime` bigint(16) DEFAULT NULL COMMENT '登录时间',
`loginip` varchar(50) NOT NULL DEFAULT '' COMMENT '登录IP', `loginip` varchar(50) DEFAULT '' COMMENT '登录IP',
`loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数', `loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数',
`joinip` varchar(50) NOT NULL DEFAULT '' COMMENT '加入IP', `loginfailuretime` bigint(16) DEFAULT NULL COMMENT '最后登录失败时间',
`jointime` int(10) DEFAULT NULL COMMENT '加入时间', `joinip` varchar(50) DEFAULT '' COMMENT '加入IP',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `jointime` bigint(16) DEFAULT NULL COMMENT '加入时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`token` varchar(50) NOT NULL DEFAULT '' COMMENT 'Token', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态', `token` varchar(50) DEFAULT '' COMMENT 'Token',
`verification` varchar(255) NOT NULL DEFAULT '' COMMENT '验证', `status` varchar(30) DEFAULT '' COMMENT '状态',
`verification` varchar(255) DEFAULT '' COMMENT '验证',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `username` (`username`), KEY `username` (`username`),
KEY `email` (`email`), KEY `email` (`email`),
KEY `mobile` (`mobile`) KEY `mobile` (`mobile`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='会员表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员表';
-- ---------------------------- -- ----------------------------
-- Records of fa_user -- Records of fa_user
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', 'c13f62012fd6a8fdf06b3452a94430e5', 'rpR6Bv', 'admin@163.com', '13888888888', '', 0, 0, '2017-04-15', '', 0, 0, 1, 1, 1516170492, 1516171614, '127.0.0.1', 0, '127.0.0.1', 1491461418, 0, 1516171614, '', 'normal',''); INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', '', '', 'admin@163.com', '13000000000', '', 0, 0, '2017-04-08', '', 0, 0, 1, 1, 1491635035, 1491635035, '127.0.0.1', 0, 1491635035,'127.0.0.1', 1491635035, 0, 1491635035, '', 'normal','');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user_group -- Table structure for fa_user_group
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user_group`;
CREATE TABLE `fa_user_group` ( CREATE TABLE `fa_user_group` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '组名', `name` varchar(50) DEFAULT '' COMMENT '组名',
`rules` text COMMENT '权限节点', `rules` text COMMENT '权限节点',
`createtime` int(10) DEFAULT NULL COMMENT '添加时间', `createtime` bigint(16) DEFAULT NULL COMMENT '添加时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`status` enum('normal','hidden') DEFAULT NULL COMMENT '状态', `status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='会员组表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_user_group -- Records of fa_user_group
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1515386468, 1516168298, 'normal'); INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1491635035, 1491635035, 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user_money_log -- Table structure for fa_user_money_log
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user_money_log`;
CREATE TABLE `fa_user_money_log` ( CREATE TABLE `fa_user_money_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID', `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更余额', `money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更余额',
`before` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更前余额', `before` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更前余额',
`after` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更后余额', `after` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更后余额',
`memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `memo` varchar(255) DEFAULT '' COMMENT '备注',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='会员余额变动表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员余额变动表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user_rule -- Table structure for fa_user_rule
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user_rule`;
CREATE TABLE `fa_user_rule` ( CREATE TABLE `fa_user_rule` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pid` int(10) DEFAULT NULL COMMENT '父ID', `pid` int(10) DEFAULT NULL COMMENT '父ID',
@ -495,55 +517,72 @@ CREATE TABLE `fa_user_rule` (
`title` varchar(50) DEFAULT '' COMMENT '标题', `title` varchar(50) DEFAULT '' COMMENT '标题',
`remark` varchar(100) DEFAULT NULL COMMENT '备注', `remark` varchar(100) DEFAULT NULL COMMENT '备注',
`ismenu` tinyint(1) DEFAULT NULL COMMENT '是否菜单', `ismenu` tinyint(1) DEFAULT NULL COMMENT '是否菜单',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`weigh` int(10) DEFAULT '0' COMMENT '权重', `weigh` int(10) DEFAULT '0' COMMENT '权重',
`status` enum('normal','hidden') DEFAULT NULL COMMENT '状态', `status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='会员规则表'; ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员规则表';
-- ---------------------------- -- ----------------------------
-- Records of fa_user_rule -- Records of fa_user_rule
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', '前台', '', 1, 1516168079, 1516168079, 1, 'normal'); INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', 'Frontend', '', 1, 1491635035, 1491635035, 1, 'normal');
INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API接口', '', 1, 1516168062, 1516168062, 2, 'normal'); INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API Interface', '', 1, 1491635035, 1491635035, 2, 'normal');
INSERT INTO `fa_user_rule` VALUES (3, 1, 'user', '会员模块', '', 1, 1515386221, 1516168103, 12, 'normal'); INSERT INTO `fa_user_rule` VALUES (3, 1, 'user', 'User Module', '', 1, 1491635035, 1491635035, 12, 'normal');
INSERT INTO `fa_user_rule` VALUES (4, 2, 'user', '会员模块', '', 1, 1515386221, 1516168092, 11, 'normal'); INSERT INTO `fa_user_rule` VALUES (4, 2, 'user', 'User Module', '', 1, 1491635035, 1491635035, 11, 'normal');
INSERT INTO `fa_user_rule` VALUES (5, 3, 'index/user/login', '登录', '', 0, 1515386247, 1515386247, 5, 'normal'); INSERT INTO `fa_user_rule` VALUES (5, 3, 'index/user/login', 'Login', '', 0, 1491635035, 1491635035, 5, 'normal');
INSERT INTO `fa_user_rule` VALUES (6, 3, 'index/user/register', '注册', '', 0, 1515386262, 1516015236, 7, 'normal'); INSERT INTO `fa_user_rule` VALUES (6, 3, 'index/user/register', 'Register', '', 0, 1491635035, 1491635035, 7, 'normal');
INSERT INTO `fa_user_rule` VALUES (7, 3, 'index/user/index', '会员中心', '', 0, 1516015012, 1516015012, 9, 'normal'); INSERT INTO `fa_user_rule` VALUES (7, 3, 'index/user/index', 'User Center', '', 0, 1491635035, 1491635035, 9, 'normal');
INSERT INTO `fa_user_rule` VALUES (8, 3, 'index/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 4, 'normal'); INSERT INTO `fa_user_rule` VALUES (8, 3, 'index/user/profile', 'Profile', '', 0, 1491635035, 1491635035, 4, 'normal');
INSERT INTO `fa_user_rule` VALUES (9, 4, 'api/user/login', '登录', '', 0, 1515386247, 1515386247, 6, 'normal'); INSERT INTO `fa_user_rule` VALUES (9, 4, 'api/user/login', 'Login', '', 0, 1491635035, 1491635035, 6, 'normal');
INSERT INTO `fa_user_rule` VALUES (10, 4, 'api/user/register', '注册', '', 0, 1515386262, 1516015236, 8, 'normal'); INSERT INTO `fa_user_rule` VALUES (10, 4, 'api/user/register', 'Register', '', 0, 1491635035, 1491635035, 8, 'normal');
INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', '会员中心', '', 0, 1516015012, 1516015012, 10, 'normal'); INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', 'User Center', '', 0, 1491635035, 1491635035, 10, 'normal');
INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 3, 'normal'); INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', 'Profile', '', 0, 1491635035, 1491635035, 3, 'normal');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user_score_log -- Table structure for fa_user_score_log
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user_score_log`;
CREATE TABLE `fa_user_score_log` ( CREATE TABLE `fa_user_score_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID', `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`score` int(10) NOT NULL DEFAULT '0' COMMENT '变更积分', `score` int(10) NOT NULL DEFAULT '0' COMMENT '变更积分',
`before` int(10) NOT NULL DEFAULT '0' COMMENT '变更前积分', `before` int(10) NOT NULL DEFAULT '0' COMMENT '变更前积分',
`after` int(10) NOT NULL DEFAULT '0' COMMENT '变更后积分', `after` int(10) NOT NULL DEFAULT '0' COMMENT '变更后积分',
`memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `memo` varchar(255) DEFAULT '' COMMENT '备注',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='会员积分变动表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员积分变动表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_user_token -- Table structure for fa_user_token
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_user_token`;
CREATE TABLE `fa_user_token` ( CREATE TABLE `fa_user_token` (
`token` varchar(50) NOT NULL COMMENT 'Token', `token` varchar(50) NOT NULL COMMENT 'Token',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID', `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`expiretime` int(10) DEFAULT NULL COMMENT '过期时间', `expiretime` bigint(16) DEFAULT NULL COMMENT '过期时间',
PRIMARY KEY (`token`) PRIMARY KEY (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员Token表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员Token表';
-- ----------------------------
-- Table structure for fa_version
-- ----------------------------
CREATE TABLE `fa_version` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`oldversion` varchar(30) DEFAULT '' COMMENT '旧版本号',
`newversion` varchar(30) DEFAULT '' COMMENT '新版本号',
`packagesize` varchar(30) DEFAULT '' COMMENT '包大小',
`content` varchar(500) DEFAULT '' COMMENT '升级内容',
`downloadurl` varchar(255) DEFAULT '' COMMENT '下载地址',
`enforce` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '强制更新',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重',
`status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='版本表';
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;

View File

@ -9,7 +9,7 @@
<style> <style>
body { body {
background: #fff; background: #f1f6fd;
margin: 0; margin: 0;
padding: 0; padding: 0;
line-height: 1.5; line-height: 1.5;
@ -31,7 +31,7 @@
} }
a { a {
color: #18bc9c; color: #4e73df;
text-decoration: none; text-decoration: none;
} }
@ -71,8 +71,8 @@
} }
.form-field input { .form-field input {
background: #EDF2F7; background: #fff;
margin: 0 0 1px; margin: 0 0 2px;
border: 2px solid transparent; border: 2px solid transparent;
transition: background 0.2s, border-color 0.2s, color 0.2s; transition: background 0.2s, border-color 0.2s, color 0.2s;
width: 100%; width: 100%;
@ -81,7 +81,7 @@
} }
.form-field input:focus { .form-field input:focus {
border-color: #18bc9c; border-color: #4e73df;
background: #fff; background: #fff;
color: #444; color: #444;
outline: none; outline: none;
@ -165,7 +165,7 @@
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M64.433651,605.899968 C20.067302,536.265612 0,469.698785 0,389.731348 C0,174.488668 171.922656,0 384,0 C596.077344,0 768,174.488668 768,389.731348 C768,469.698785 747.932698,536.265612 703.566349,605.899968 C614.4,753.480595 441.6,870.4 384,870.4 C326.4,870.4 153.6,753.480595 64.433651,605.899968 L64.433651,605.899968 Z" <path d="M64.433651,605.899968 C20.067302,536.265612 0,469.698785 0,389.731348 C0,174.488668 171.922656,0 384,0 C596.077344,0 768,174.488668 768,389.731348 C768,469.698785 747.932698,536.265612 703.566349,605.899968 C614.4,753.480595 441.6,870.4 384,870.4 C326.4,870.4 153.6,753.480595 64.433651,605.899968 L64.433651,605.899968 Z"
id="body" fill="#18BC9C"></path> id="body" fill="#4e73df"></path>
<path d="M429.648991,190.816 L430.160991,190.816 L429.648991,190.816 L429.648991,190.816 Z M429.648991,156 L427.088991,156 C419.408991,157.024 411.728991,160.608 404.560991,168.8 L403.024991,170.848 L206.928991,429.92 C198.736991,441.184 197.712991,453.984 204.368991,466.784 C210.512991,478.048 222.288991,485.728 235.600991,485.728 L336.464991,486.24 L304.208991,673.632 C301.648991,689.504 310.352991,705.376 325.200991,712.032 C329.808991,714.08 334.416991,714.592 339.536991,714.592 C349.776991,714.592 358.992991,709.472 366.160991,700.256 L561.744991,419.168 C569.936991,407.904 570.960991,395.104 564.304991,382.304 C557.648991,369.504 547.408991,363.36 533.072991,363.36 L432.208991,363.36 L463.952991,199.008 C464.464991,196.448 464.976991,193.376 464.976991,190.816 C464.976991,171.872 449.104991,156 431.184991,156 L429.648991,156 L429.648991,156 Z" <path d="M429.648991,190.816 L430.160991,190.816 L429.648991,190.816 L429.648991,190.816 Z M429.648991,156 L427.088991,156 C419.408991,157.024 411.728991,160.608 404.560991,168.8 L403.024991,170.848 L206.928991,429.92 C198.736991,441.184 197.712991,453.984 204.368991,466.784 C210.512991,478.048 222.288991,485.728 235.600991,485.728 L336.464991,486.24 L304.208991,673.632 C301.648991,689.504 310.352991,705.376 325.200991,712.032 C329.808991,714.08 334.416991,714.592 339.536991,714.592 C349.776991,714.592 358.992991,709.472 366.160991,700.256 L561.744991,419.168 C569.936991,407.904 570.960991,395.104 564.304991,382.304 C557.648991,369.504 547.408991,363.36 533.072991,363.36 L432.208991,363.36 L463.952991,199.008 C464.464991,196.448 464.976991,193.376 464.976991,190.816 C464.976991,171.872 449.104991,156 431.184991,156 L429.648991,156 L429.648991,156 Z"
id="flash" fill="#FFFFFF"></path> id="flash" fill="#FFFFFF"></path>
</g> </g>
@ -254,7 +254,7 @@
</form> </form>
<!-- jQuery --> <!-- jQuery -->
<script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script> <script src="__ROOT__/assets/libs/jquery/dist/jquery.min.js"></script>
<script> <script>
$(function () { $(function () {
@ -287,7 +287,7 @@
if (typeof data.adminName !== 'undefined') { if (typeof data.adminName !== 'undefined') {
var url = location.href.replace(/install\.php/, data.adminName); var url = location.href.replace(/install\.php/, data.adminName);
$("#warmtips").html("{:__('Security tips')}" + '<a href="' + url + '">' + url + '</a>').show(); $("#warmtips").html("{:__('Security tips')}" + '<a href="' + url + '">' + url + '</a>').show();
$('<a class="btn" href="' + url + '" id="btn-admin" style="background:#18bc9c">' + "{:__('Dashboard')}" + '</a>').appendTo($buttons); $('<a class="btn" href="' + url + '" id="btn-admin" style="background:#4e73df">' + "{:__('Dashboard')}" + '</a>').appendTo($buttons);
} }
localStorage.setItem("fastep", "installed"); localStorage.setItem("fastep", "installed");
} else { } else {
@ -313,4 +313,4 @@
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -8,10 +8,10 @@ return [
'Mysql Password' => 'MySQL 密码', 'Mysql Password' => 'MySQL 密码',
'Mysql Prefix' => 'MySQL 数据表前缀', 'Mysql Prefix' => 'MySQL 数据表前缀',
'Mysql Hostport' => 'MySQL 端口号', 'Mysql Hostport' => 'MySQL 端口号',
'Admin Username' => '管理用户名', 'Admin Username' => '管理用户名',
'Admin Email' => '管理Email', 'Admin Email' => '管理Email',
'Admin Password' => '管理密码', 'Admin Password' => '管理密码',
'Repeat Password' => '重复密码', 'Repeat Password' => '重复管理员密码',
'Website' => '网站名称', 'Website' => '网站名称',
'My Website' => '我的网站', 'My Website' => '我的网站',
'Install now' => '点击安装', 'Install now' => '点击安装',
@ -20,15 +20,16 @@ return [
'Dashboard' => '进入后台', 'Dashboard' => '进入后台',
'Go back' => '返回上一页', 'Go back' => '返回上一页',
'Install Successed' => '安装成功!', 'Install Successed' => '安装成功!',
'Security tips' => '温馨提示:请将以下后台登录入口添加到你的收藏夹,为了你的安全,不要泄漏或发送给他人!如有泄漏请及时修改!', 'Security tips' => '温馨提示:请将以下后台登录入口添加到你的收藏夹,为了你的站点安全,不要泄漏或发送给他人!如有泄漏请及时修改!',
'Please input correct database' => '请输入正确的数据库名', 'Please input correct database' => '请输入正确的数据库名',
'Please input correct username' => '用户名只能由3-12位数字、字母、下划线组合', 'Please input correct username' => '用户名只能由3-30位数字、字母、下划线组合',
'Please input correct password' => '密码长度必须在6-16位之间不能包含空格', 'Please input correct password' => '密码长度必须在6-30位之间不能包含空格',
'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 5.5 or higher' => '当前版本%s过低请使用PHP5.5以上版本', 'The current version %s is too low, please use PHP 7.4 or higher' => '当前版本%s过低请使用PHP7.4及以上版本',
'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' => '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装',
'The system has been installed. If you need to reinstall, please remove %s first' => '当前已经安装成功,如果需要重新安装,请手动移除%s文件', 'The system has been installed. If you need to reinstall, please remove %s first' => '当前已经安装成功,如果需要重新安装,请手动移除%s文件',
]; ];

View File

@ -104,6 +104,7 @@ class Min extends Command
continue; continue;
} }
$config = preg_replace("/(urlArgs|baseUrl):(.*)\n/", '', $matches[1]); $config = preg_replace("/(urlArgs|baseUrl):(.*)\n/", '', $matches[1]);
$config = preg_replace("/('tableexport'):(.*)\,\n/", "'tableexport': 'empty:',\n", $config);
$data['config'] = $config; $data['config'] = $config;
} }
// 生成压缩文件 // 生成压缩文件

View File

@ -4,6 +4,7 @@ use app\common\model\Category;
use fast\Form; use fast\Form;
use fast\Tree; use fast\Tree;
use think\Db; use think\Db;
use think\Loader;
if (!function_exists('build_select')) { if (!function_exists('build_select')) {
@ -17,8 +18,8 @@ if (!function_exists('build_select')) {
*/ */
function build_select($name, $options, $selected = [], $attr = []) function build_select($name, $options, $selected = [], $attr = [])
{ {
$options = is_array($options) ? $options : explode(',', $options); $options = is_array($options) ? $options : explode(',', $options ?? '');
$selected = is_array($selected) ? $selected : explode(',', $selected); $selected = is_array($selected) ? $selected : explode(',', $selected ?? '');
return Form::select($name, $options, $selected, $attr); return Form::select($name, $options, $selected, $attr);
} }
} }
@ -38,7 +39,7 @@ if (!function_exists('build_radios')) {
$selected = is_null($selected) ? key($list) : $selected; $selected = is_null($selected) ? key($list) : $selected;
$selected = is_array($selected) ? $selected : explode(',', $selected); $selected = is_array($selected) ? $selected : explode(',', $selected);
foreach ($list as $k => $v) { foreach ($list as $k => $v) {
$html[] = sprintf(Form::label("{$name}-{$k}", "%s {$v}"), Form::radio($name, $k, in_array($k, $selected), ['id' => "{$name}-{$k}"])); $html[] = sprintf(Form::label("{$name}-{$k}", "%s " . str_replace('%', '%%', $v)), Form::radio($name, $k, in_array($k, $selected), ['id' => "{$name}-{$k}"]));
} }
return '<div class="radio">' . implode(' ', $html) . '</div>'; return '<div class="radio">' . implode(' ', $html) . '</div>';
} }
@ -59,7 +60,7 @@ if (!function_exists('build_checkboxs')) {
$selected = is_null($selected) ? [] : $selected; $selected = is_null($selected) ? [] : $selected;
$selected = is_array($selected) ? $selected : explode(',', $selected); $selected = is_array($selected) ? $selected : explode(',', $selected);
foreach ($list as $k => $v) { foreach ($list as $k => $v) {
$html[] = sprintf(Form::label("{$name}-{$k}", "%s {$v}"), Form::checkbox($name, $k, in_array($k, $selected), ['id' => "{$name}-{$k}"])); $html[] = sprintf(Form::label("{$name}-{$k}", "%s " . str_replace('%', '%%', $v)), Form::checkbox($name, $k, in_array($k, $selected), ['id' => "{$name}-{$k}"]));
} }
return '<div class="checkbox">' . implode(' ', $html) . '</div>'; return '<div class="checkbox">' . implode(' ', $html) . '</div>';
} }
@ -102,7 +103,7 @@ if (!function_exists('build_toolbar')) {
function build_toolbar($btns = null, $attr = []) function build_toolbar($btns = null, $attr = [])
{ {
$auth = \app\admin\library\Auth::instance(); $auth = \app\admin\library\Auth::instance();
$controller = str_replace('.', '/', strtolower(think\Request::instance()->controller())); $controller = str_replace('.', '/', Loader::parseName(request()->controller()));
$btns = $btns ? $btns : ['refresh', 'add', 'edit', 'del', 'import']; $btns = $btns ? $btns : ['refresh', 'add', 'edit', 'del', 'import'];
$btns = is_array($btns) ? $btns : explode(',', $btns); $btns = is_array($btns) ? $btns : explode(',', $btns);
$index = array_search('delete', $btns); $index = array_search('delete', $btns);
@ -120,7 +121,7 @@ if (!function_exists('build_toolbar')) {
$html = []; $html = [];
foreach ($btns as $k => $v) { foreach ($btns as $k => $v) {
//如果未定义或没有权限 //如果未定义或没有权限
if (!isset($btnAttr[$v]) || ($v !== 'refresh' && !$auth->check("{$controller}/{$v}"))) { if (!isset($btnAttr[$v]) || ($v !== 'refresh' && !$auth->check("{$controller}/{$v}", $auth->id))) {
continue; continue;
} }
list($href, $class, $icon, $text, $title) = $btnAttr[$v]; list($href, $class, $icon, $text, $title) = $btnAttr[$v];
@ -175,7 +176,7 @@ if (!function_exists('build_heading')) {
$title = $content = ''; $title = $content = '';
if (is_null($path)) { if (is_null($path)) {
$action = request()->action(); $action = request()->action();
$controller = str_replace('.', '/', request()->controller()); $controller = str_replace('.', '/', Loader::parseName(request()->controller()));
$path = strtolower($controller . ($action && $action != 'index' ? '/' . $action : '')); $path = strtolower($controller . ($action && $action != 'index' ? '/' . $action : ''));
} }
// 根据当前的URI自动匹配父节点的标题和备注 // 根据当前的URI自动匹配父节点的标题和备注
@ -194,33 +195,3 @@ if (!function_exists('build_heading')) {
return $result; return $result;
} }
} }
if (!function_exists('build_suffix_image')) {
/**
* 生成文件后缀图片
* @param string $suffix 后缀
* @param null $background
* @return string
*/
function build_suffix_image($suffix, $background = null)
{
$suffix = mb_substr(strtoupper($suffix), 0, 4);
$total = unpack('L', hash('adler32', $suffix, true))[1];
$hue = $total % 360;
list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);
$background = $background ? $background : "rgb({$r},{$g},{$b})";
$icon = <<<EOT
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
</svg>
EOT;
return $icon;
}
}

View File

@ -8,28 +8,30 @@ use think\addons\AddonException;
use think\addons\Service; use think\addons\Service;
use think\Cache; use think\Cache;
use think\Config; use think\Config;
use think\Db;
use think\Exception; use think\Exception;
/** /**
* 插件管理 * 插件管理
* *
* @icon fa fa-cube * @icon fa fa-cube
* @remark 可在线安装、卸载、禁用、启用插件,同时支持添加本地插件。FastAdmin已上线插件商店 ,你可以发布你的免费或付费插件:<a href="https://www.fastadmin.net/store.html" target="_blank">https://www.fastadmin.net/store.html</a> * @remark 可在线安装、卸载、禁用、启用、配置、升级插件,插件升级前请做好备份
*/ */
class Addon extends Backend class Addon extends Backend
{ {
protected $model = null; protected $model = null;
protected $noNeedRight = ['get_table_list'];
public function _initialize() public function _initialize()
{ {
parent::_initialize(); parent::_initialize();
if (!$this->auth->isSuperAdmin() && in_array($this->request->action(), ['install', 'uninstall', 'local', 'upgrade'])) { if (!$this->auth->isSuperAdmin() && in_array($this->request->action(), ['install', 'uninstall', 'local', 'upgrade', 'authorization', 'testdata'])) {
$this->error(__('Access is allowed only to the super management group')); $this->error(__('Access is allowed only to the super management group'));
} }
} }
/** /**
* 查看 * 插件列表
*/ */
public function index() public function index()
{ {
@ -39,7 +41,7 @@ class Addon extends Backend
$v['config'] = $config ? 1 : 0; $v['config'] = $config ? 1 : 0;
$v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']); $v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']);
} }
$this->assignconfig(['addons' => $addons, 'api_url' => config('fastadmin.api_url'), 'faversion' => config('fastadmin.version')]); $this->assignconfig(['addons' => $addons, 'api_url' => config('fastadmin.api_url'), 'faversion' => config('fastadmin.version'), 'domain' => request()->host(true)]);
return $this->view->fetch(); return $this->view->fetch();
} }
@ -55,13 +57,10 @@ class Addon extends Backend
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect')); $this->error(__('Addon name incorrect'));
} }
if (!is_dir(ADDON_PATH . $name)) {
$this->error(__('Directory not found'));
}
$info = get_addon_info($name); $info = get_addon_info($name);
$config = get_addon_fullconfig($name); $config = get_addon_fullconfig($name);
if (!$info) { if (!$info) {
$this->error(__('No Results were found')); $this->error(__('Addon not exists'));
} }
if ($this->request->isPost()) { if ($this->request->isPost()) {
$params = $this->request->post("row/a", [], 'trim'); $params = $this->request->post("row/a", [], 'trim');
@ -78,23 +77,43 @@ class Addon extends Backend
} }
} }
try { try {
//更新配置文件 $addon = get_addon_instance($name);
set_addon_fullconfig($name, $config); //插件自定义配置实现逻辑
Service::refresh(); if (method_exists($addon, 'config')) {
$this->success(); $addon->config($name, $config);
} else {
//更新配置文件
set_addon_fullconfig($name, $config);
Service::refresh();
}
} catch (Exception $e) { } catch (Exception $e) {
$this->error(__($e->getMessage())); $this->error(__($e->getMessage()));
} }
$this->success();
} }
$this->error(__('Parameter %s can not be empty', '')); $this->error(__('Parameter %s can not be empty', ''));
} }
$tips = []; $tips = [];
$groupList = [];
$ungroupList = [];
foreach ($config as $index => &$item) { foreach ($config as $index => &$item) {
//如果有设置分组
if (isset($item['group']) && $item['group']) {
if (!in_array($item['group'], $groupList)) {
$groupList["custom" . (count($groupList) + 1)] = $item['group'];
}
} elseif ($item['name'] != '__tips__') {
$ungroupList[] = $item['name'];
}
if ($item['name'] == '__tips__') { if ($item['name'] == '__tips__') {
$tips = $item; $tips = $item;
unset($config[$index]); unset($config[$index]);
} }
} }
if ($ungroupList) {
$groupList['other'] = '其它';
}
$this->view->assign("groupList", $groupList);
$this->view->assign("addon", ['info' => $info, 'config' => $config, 'tips' => $tips]); $this->view->assign("addon", ['info' => $info, 'config' => $config, 'tips' => $tips]);
$configFile = ADDON_PATH . $name . DS . 'config.html'; $configFile = ADDON_PATH . $name . DS . 'config.html';
$viewFile = is_file($configFile) ? $configFile : ''; $viewFile = is_file($configFile) ? $configFile : '';
@ -114,6 +133,8 @@ class Addon extends Backend
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect')); $this->error(__('Addon name incorrect'));
} }
$info = [];
try { try {
$uid = $this->request->post("uid"); $uid = $this->request->post("uid");
$token = $this->request->post("token"); $token = $this->request->post("token");
@ -125,16 +146,13 @@ class Addon extends Backend
'version' => $version, 'version' => $version,
'faversion' => $faversion 'faversion' => $faversion
]; ];
Service::install($name, $force, $extend); $info = Service::install($name, $force, $extend);
$info = get_addon_info($name);
$info['config'] = get_addon_config($name) ? 1 : 0;
$info['state'] = 1;
$this->success(__('Install successful'), null, ['addon' => $info]);
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage())); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error(__($e->getMessage()), $e->getCode()); $this->error(__($e->getMessage()), $e->getCode());
} }
$this->success(__('Install successful'), '', ['addon' => $info]);
} }
/** /**
@ -144,20 +162,37 @@ class Addon extends Backend
{ {
$name = $this->request->post("name"); $name = $this->request->post("name");
$force = (int)$this->request->post("force"); $force = (int)$this->request->post("force");
$droptables = (int)$this->request->post("droptables");
if (!$name) { if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name')); $this->error(__('Parameter %s can not be empty', 'name'));
} }
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) { if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect')); $this->error(__('Addon name incorrect'));
} }
//只有开启调试且为超级管理员才允许删除相关数据库
$tables = [];
if ($droptables && Config::get("app_debug") && $this->auth->isSuperAdmin()) {
$tables = get_addon_tables($name);
}
try { try {
Service::uninstall($name, $force); Service::uninstall($name, $force);
$this->success(__('Uninstall successful')); if ($tables) {
$prefix = Config::get('database.prefix');
//删除插件关联表
foreach ($tables as $index => $table) {
//忽略非插件标识的表名
if (!preg_match("/^{$prefix}{$name}/", $table)) {
continue;
}
Db::execute("DROP TABLE IF EXISTS `{$table}`");
}
}
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage())); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error(__($e->getMessage())); $this->error(__($e->getMessage()));
} }
$this->success(__('Uninstall successful'));
} }
/** /**
@ -179,12 +214,12 @@ class Addon extends Backend
//调用启用、禁用的方法 //调用启用、禁用的方法
Service::$action($name, $force); Service::$action($name, $force);
Cache::rm('__menu__'); Cache::rm('__menu__');
$this->success(__('Operate successful'));
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage())); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error(__($e->getMessage())); $this->error(__($e->getMessage()));
} }
$this->success(__('Operate successful'));
} }
/** /**
@ -194,75 +229,28 @@ class Addon extends Backend
{ {
Config::set('default_return_type', 'json'); Config::set('default_return_type', 'json');
$info = [];
$file = $this->request->file('file'); $file = $this->request->file('file');
$addonTmpDir = RUNTIME_PATH . 'addons' . DS; try {
if (!is_dir($addonTmpDir)) { $uid = $this->request->post("uid");
@mkdir($addonTmpDir, 0755, true); $token = $this->request->post("token");
} $faversion = $this->request->post("faversion");
$info = $file->rule('uniqid')->validate(['size' => 10240000, 'ext' => 'zip'])->move($addonTmpDir); $force = $this->request->post("force");
if ($info) { if (!$uid || !$token) {
$tmpName = substr($info->getFilename(), 0, stripos($info->getFilename(), '.')); throw new Exception(__('Please login and try to install'));
$tmpAddonDir = ADDON_PATH . $tmpName . DS;
$tmpFile = $addonTmpDir . $info->getSaveName();
try {
Service::unzip($tmpName);
unset($info);
@unlink($tmpFile);
$infoFile = $tmpAddonDir . 'info.ini';
if (!is_file($infoFile)) {
throw new Exception(__('Addon info file was not found'));
}
$config = Config::parse($infoFile, '', $tmpName);
$name = isset($config['name']) ? $config['name'] : '';
if (!$name) {
throw new Exception(__('Addon info file data incorrect'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
throw new Exception(__('Addon name incorrect'));
}
$newAddonDir = ADDON_PATH . $name . DS;
if (is_dir($newAddonDir)) {
throw new Exception(__('Addon already exists'));
}
//重命名插件文件夹
rename($tmpAddonDir, $newAddonDir);
try {
//默认禁用该插件
$info = get_addon_info($name);
if ($info['state']) {
$info['state'] = 0;
set_addon_info($name, $info);
}
//执行插件的安装方法
$class = get_addon_class($name);
if (class_exists($class)) {
$addon = new $class();
$addon->install();
}
//导入SQL
Service::importsql($name);
$info['config'] = get_addon_config($name) ? 1 : 0;
$this->success(__('Offline installed tips'), null, ['addon' => $info]);
} catch (Exception $e) {
@rmdirs($newAddonDir);
throw new Exception(__($e->getMessage()));
}
} catch (Exception $e) {
unset($info);
@unlink($tmpFile);
@rmdirs($tmpAddonDir);
$this->error(__($e->getMessage()));
} }
} else { $extend = [
// 上传失败获取错误信息 'uid' => $uid,
$this->error(__($file->getError())); 'token' => $token,
'faversion' => $faversion
];
$info = Service::local($file, $extend, $force);
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()));
} }
$this->success(__('Offline installed tips'), '', ['addon' => $info]);
} }
/** /**
@ -281,26 +269,53 @@ class Addon extends Backend
if (!is_dir($addonTmpDir)) { if (!is_dir($addonTmpDir)) {
@mkdir($addonTmpDir, 0755, true); @mkdir($addonTmpDir, 0755, true);
} }
$info = [];
try { try {
$info = get_addon_info($name);
$uid = $this->request->post("uid"); $uid = $this->request->post("uid");
$token = $this->request->post("token"); $token = $this->request->post("token");
$version = $this->request->post("version"); $version = $this->request->post("version");
$faversion = $this->request->post("faversion"); $faversion = $this->request->post("faversion");
$extend = [ $extend = [
'uid' => $uid, 'uid' => $uid,
'token' => $token, 'token' => $token,
'version' => $version, 'version' => $version,
'faversion' => $faversion 'oldversion' => $info['version'] ?? '',
'faversion' => $faversion
]; ];
//调用更新的方法 //调用更新的方法
Service::upgrade($name, $extend); $info = Service::upgrade($name, $extend);
Cache::rm('__menu__'); Cache::rm('__menu__');
$this->success(__('Operate successful'));
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage())); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error(__($e->getMessage())); $this->error(__($e->getMessage()));
} }
$this->success(__('Operate successful'), '', ['addon' => $info]);
}
/**
* 测试数据
*/
public function testdata()
{
$name = $this->request->post("name");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
try {
Service::importsql($name, 'testdata.sql');
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()), $e->getCode());
}
$this->success(__('Import successful'), '');
} }
/** /**
@ -310,45 +325,32 @@ class Addon extends Backend
{ {
$offset = (int)$this->request->get("offset"); $offset = (int)$this->request->get("offset");
$limit = (int)$this->request->get("limit"); $limit = (int)$this->request->get("limit");
$filter = $this->request->get("filter"); $filter = $this->request->get("filter", '');
$search = $this->request->get("search"); $search = $this->request->get("search", '', 'strip_tags,htmlspecialchars');
$search = htmlspecialchars(strip_tags($search)); $onlineaddons = $this->getAddonList();
$onlineaddons = Cache::get("onlineaddons");
if (!is_array($onlineaddons)) {
$onlineaddons = [];
$result = Http::sendRequest(config('fastadmin.api_url') . '/addon/index');
if ($result['ret']) {
$json = (array)json_decode($result['msg'], true);
$rows = isset($json['rows']) ? $json['rows'] : [];
foreach ($rows as $index => $row) {
$onlineaddons[$row['name']] = $row;
}
}
Cache::set("onlineaddons", $onlineaddons, 600);
}
$filter = (array)json_decode($filter, true); $filter = (array)json_decode($filter, true);
$addons = get_addon_list(); $addons = get_addon_list();
$list = []; $list = [];
foreach ($addons as $k => $v) { foreach ($addons as $k => $v) {
if ($search && stripos($v['name'], $search) === false && stripos($v['intro'], $search) === false) { if ($search && stripos($v['name'], $search) === false && stripos($v['title'], $search) === false && stripos($v['intro'], $search) === false) {
continue; continue;
} }
if (isset($onlineaddons[$v['name']])) { if (isset($onlineaddons[$v['name']])) {
$v = array_merge($v, $onlineaddons[$v['name']]); $v = array_merge($v, $onlineaddons[$v['name']]);
$v['price'] = '-';
} else { } else {
$v['category_id'] = 0; $v['category_id'] = 0;
$v['flag'] = ''; $v['flag'] = '';
$v['banner'] = ''; $v['banner'] = '';
$v['image'] = ''; $v['image'] = '';
$v['donateimage'] = '';
$v['demourl'] = ''; $v['demourl'] = '';
$v['price'] = __('None'); $v['price'] = __('None');
$v['screenshots'] = []; $v['screenshots'] = [];
$v['releaselist'] = []; $v['releaselist'] = [];
$v['url'] = addon_url($v['name']);
$v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']);
} }
$v['url'] = addon_url($v['name']);
$v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']);
$v['createtime'] = filemtime(ADDON_PATH . $v['name']); $v['createtime'] = filemtime(ADDON_PATH . $v['name']);
if ($filter && isset($filter['category_id']) && is_numeric($filter['category_id']) && $filter['category_id'] != $v['category_id']) { if ($filter && isset($filter['category_id']) && is_numeric($filter['category_id']) && $filter['category_id'] != $v['category_id']) {
continue; continue;
@ -364,4 +366,97 @@ class Addon extends Backend
$callback = $this->request->get('callback') ? "jsonp" : "json"; $callback = $this->request->get('callback') ? "jsonp" : "json";
return $callback($result); return $callback($result);
} }
/**
* 检测
*/
public function isbuy()
{
$name = $this->request->post("name");
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
$faversion = $this->request->post("faversion");
$extend = [
'uid' => $uid,
'token' => $token,
'version' => $version,
'faversion' => $faversion
];
try {
$result = Service::isBuy($name, $extend);
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
return json($result);
}
/**
* 刷新授权
*/
public function authorization()
{
$params = [
'uid' => $this->request->post('uid'),
'token' => $this->request->post('token'),
'faversion' => $this->request->post('faversion'),
];
try {
Service::authorization($params);
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Operate successful'));
}
/**
* 获取插件相关表
*/
public function get_table_list()
{
$name = $this->request->post("name");
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
$tables = get_addon_tables($name);
$prefix = Config::get('database.prefix');
foreach ($tables as $index => $table) {
//忽略非插件标识的表名
if (!preg_match("/^{$prefix}{$name}/", $table)) {
unset($tables[$index]);
}
}
$tables = array_values($tables);
$this->success('', null, ['tables' => $tables]);
}
protected function getAddonList()
{
$onlineaddons = Cache::get("onlineaddons");
if (!is_array($onlineaddons) && config('fastadmin.api_url')) {
$onlineaddons = [];
$params = [
'uid' => $this->request->post('uid'),
'token' => $this->request->post('token'),
'version' => config('fastadmin.version'),
'faversion' => config('fastadmin.version'),
];
$json = [];
try {
$json = Service::addons($params);
} catch (\Exception $e) {
}
$rows = $json['rows'] ?? [];
foreach ($rows as $index => $row) {
if (!isset($row['name'])) {
continue;
}
$onlineaddons[$row['name']] = $row;
}
Cache::set("onlineaddons", $onlineaddons, 600);
}
return $onlineaddons;
}
} }

View File

@ -3,12 +3,16 @@
namespace app\admin\controller; namespace app\admin\controller;
use app\common\controller\Backend; use app\common\controller\Backend;
use app\common\exception\UploadException;
use app\common\library\Upload;
use fast\Random; use fast\Random;
use think\addons\Service; use think\addons\Service;
use think\Cache; use think\Cache;
use think\Config; use think\Config;
use think\Db; use think\Db;
use think\Lang; use think\Lang;
use think\Loader;
use think\Response;
use think\Validate; use think\Validate;
/** /**
@ -27,7 +31,7 @@ class Ajax extends Backend
parent::_initialize(); parent::_initialize();
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags', 'htmlspecialchars']); $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
} }
/** /**
@ -35,17 +39,30 @@ class Ajax extends Backend
*/ */
public function lang() public function lang()
{ {
header('Content-Type: application/javascript'); $this->request->get(['callback' => 'define']);
header("Cache-Control: public"); $header = ['Content-Type' => 'application/javascript'];
header("Pragma: cache"); if (!config('app_debug')) {
$offset = 30 * 60 * 60 * 24; // 缓存一个月
$header['Cache-Control'] = 'public';
$header['Pragma'] = 'cache';
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
}
$offset = 30 * 60 * 60 * 24; // 缓存一个月 $controllername = $this->request->get('controllername');
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"); $lang = $this->request->get('lang');
if (!$lang || !in_array($lang, config('allow_lang_list')) || !$controllername || !preg_match("/^[a-z0-9_\.]+$/i", $controllername)) {
return jsonp(['errmsg' => '参数错误'], 200, [], ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
}
$controllername = input("controllername"); $controllername = input("controllername");
//默认只加载了控制器对应的语言名,你还根据控制器名来加载额外的语言包 $className = Loader::parseClass($this->request->module(), 'controller', $controllername, false);
$this->loadlang($controllername);
return jsonp(Lang::get(), 200, [], ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]); //存在对应的类才加载
if (class_exists($className)) {
$this->loadlang($controllername);
}
return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
} }
/** /**
@ -54,98 +71,63 @@ class Ajax extends Backend
public function upload() public function upload()
{ {
Config::set('default_return_type', 'json'); Config::set('default_return_type', 'json');
$file = $this->request->file('file');
if (empty($file)) {
$this->error(__('No file upload or server upload limit exceeded'));
}
//判断是否已经存在附件 //必须还原upload配置,否则分片及cdnurl函数计算错误
$sha1 = $file->hash(); Config::load(APP_PATH . 'extra/upload.php', 'upload');
$extparam = $this->request->post();
$upload = Config::get('upload'); $chunkid = $this->request->post("chunkid");
if ($chunkid) {
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches); if (!Config::get('upload.chunking')) {
$type = strtolower($matches[2]); $this->error(__('Chunk file disabled'));
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; }
$size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); $action = $this->request->post("action");
$fileInfo = $file->getInfo(); $chunkindex = $this->request->post("chunkindex/d");
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); $chunkcount = $this->request->post("chunkcount/d");
$suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; $filename = $this->request->post("filename");
$method = $this->request->method(true);
$mimetypeArr = explode(',', strtolower($upload['mimetype'])); if ($action == 'merge') {
$typeArr = explode('/', $fileInfo['type']); $attachment = null;
//合并分片文件
//禁止上传PHP和HTML文件 try {
if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) { $upload = new Upload();
$this->error(__('Uploaded file format is limited')); $attachment = $upload->merge($chunkid, $chunkcount, $filename);
} } catch (UploadException $e) {
//验证文件后缀 $this->error($e->getMessage());
if ($upload['mimetype'] !== '*' && }
( $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
!in_array($suffix, $mimetypeArr) } elseif ($method == 'clean') {
|| (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))) //删除冗余的分片文件
) try {
) { $upload = new Upload();
$this->error(__('Uploaded file format is limited')); $upload->clean($chunkid);
} } catch (UploadException $e) {
//验证是否为图片文件 $this->error($e->getMessage());
$imagewidth = $imageheight = 0; }
if (in_array($fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) { $this->success();
$imgInfo = getimagesize($fileInfo['tmp_name']); } else {
if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { //上传分片文件
$this->error(__('Uploaded file is not a valid image')); //默认普通上传文件
$file = $this->request->file('file');
try {
$upload = new Upload($file);
$upload->chunk($chunkid, $chunkindex, $chunkcount);
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success();
} }
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$replaceArr = [
'{year}' => date("Y"),
'{mon}' => date("m"),
'{day}' => date("d"),
'{hour}' => date("H"),
'{min}' => date("i"),
'{sec}' => date("s"),
'{random}' => Random::alnum(16),
'{random32}' => Random::alnum(32),
'{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
'{suffix}' => $suffix,
'{.suffix}' => $suffix ? '.' . $suffix : '',
'{filemd5}' => md5_file($fileInfo['tmp_name']),
];
$savekey = $upload['savekey'];
$savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
$uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo) {
$params = array(
'admin_id' => (int)$this->auth->id,
'user_id' => 0,
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
'imagetype' => $suffix,
'imageframes' => 0,
'mimetype' => $fileInfo['type'],
'url' => $uploadDir . $splInfo->getSaveName(),
'uploadtime' => time(),
'storage' => 'local',
'sha1' => $sha1,
'extparam' => json_encode($extparam),
);
$attachment = model("attachment");
$attachment->data(array_filter($params));
$attachment->save();
\think\Hook::listen("upload_after", $attachment);
$this->success(__('Upload successful'), null, [
'url' => $uploadDir . $splInfo->getSaveName()
]);
} else { } else {
// 上传失败获取错误信息 $attachment = null;
$this->error($file->getError()); //默认普通上传文件
$file = $this->request->file('file');
try {
$upload = new Upload($file);
$attachment = $upload->upload();
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
} }
} }
@ -172,8 +154,8 @@ class Ajax extends Backend
$orderway = $orderway == 'asc' ? 'ASC' : 'DESC'; $orderway = $orderway == 'asc' ? 'ASC' : 'DESC';
$sour = $weighdata = []; $sour = $weighdata = [];
$ids = explode(',', $ids); $ids = explode(',', $ids);
$prikey = $pk ? $pk : (Db::name($table)->getPk() ?: 'id'); $prikey = $pk && preg_match("/^[a-z0-9\-_]+$/i", $pk) ? $pk : (Db::name($table)->getPk() ?: 'id');
$pid = $this->request->post("pid"); $pid = $this->request->post("pid", "");
//限制更新的字段 //限制更新的字段
$field = in_array($field, ['weigh']) ? $field : 'weigh'; $field = in_array($field, ['weigh']) ? $field : 'weigh';
@ -193,7 +175,7 @@ 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 = $sour[$position]; //移动到目标的ID值,取出所处改变前位置的值 $desc_id = isset($sour[$position]) ? $sour[$position] : end($sour); //移动到目标的ID值,取出所处改变前位置的值
$sour_id = $changeid; $sour_id = $changeid;
$weighids = array(); $weighids = array();
$temp = array_values(array_diff_assoc($ids, $sour)); $temp = array_values(array_diff_assoc($ids, $sour));
@ -207,6 +189,9 @@ class Ajax extends Backend
$offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id; $offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id;
} }
} }
if (!isset($weighdata[$offset])) {
continue;
}
$weighids[$n] = $weighdata[$offset]; $weighids[$n] = $weighdata[$offset];
Db::name($table)->where($prikey, $n)->update([$field => $weighdata[$offset]]); Db::name($table)->where($prikey, $n)->update([$field => $weighdata[$offset]]);
} }
@ -218,25 +203,56 @@ class Ajax extends Backend
*/ */
public function wipecache() public function wipecache()
{ {
$type = $this->request->request("type"); try {
switch ($type) { $type = $this->request->request("type");
case 'all': switch ($type) {
case 'content': case 'all':
rmdirs(CACHE_PATH, false); // no break
Cache::clear(); case 'content':
if ($type == 'content') { //内容缓存
break; rmdirs(CACHE_PATH, false);
} Cache::clear();
case 'template': if ($type == 'content') {
rmdirs(TEMP_PATH, false); break;
if ($type == 'template') { }
break; case 'template':
} // 模板缓存
case 'addons': rmdirs(TEMP_PATH, false);
Service::refresh(); if ($type == 'template') {
if ($type == 'addons') { break;
break; }
} case 'addons':
// 插件缓存
Service::refresh();
if ($type == 'addons') {
break;
}
case 'browser':
// 浏览器缓存
// 只有生产环境下才修改
if (!config('app_debug')) {
$version = config('site.version');
$newversion = preg_replace_callback("/(.*)\.([0-9]+)\$/", function ($match) {
return $match[1] . '.' . ($match[2] + 1);
}, $version);
if ($newversion && $newversion != $version) {
Db::startTrans();
try {
\app\common\model\Config::where('name', 'version')->update(['value' => $newversion]);
\app\common\model\Config::refreshFile();
Db::commit();
} catch (\Exception $e) {
Db::rollback();
exception($e->getMessage());
}
}
}
if ($type == 'browser') {
break;
}
}
} catch (\Exception $e) {
$this->error($e->getMessage());
} }
\think\Hook::listen("wipecache_after"); \think\Hook::listen("wipecache_after");
@ -248,21 +264,20 @@ class Ajax extends Backend
*/ */
public function category() public function category()
{ {
$type = $this->request->get('type'); $type = $this->request->get('type', '');
$pid = $this->request->get('pid'); $pid = $this->request->get('pid', '');
$where = ['status' => 'normal']; $where = ['status' => 'normal'];
$categorylist = null; $categorylist = null;
if ($pid !== '') { if ($pid || $pid === '0') {
if ($type) { $where['pid'] = $pid;
$where['type'] = $type;
}
if ($pid) {
$where['pid'] = $pid;
}
$categorylist = Db::name('category')->where($where)->field('id as value,name')->order('weigh desc,id desc')->select();
} }
$this->success('', null, $categorylist); if ($type) {
$where['type'] = $type;
}
$categorylist = Db::name('category')->where($where)->field('id as value,name')->order('weigh desc,id desc')->select();
$this->success('', '', $categorylist);
} }
/** /**
@ -272,7 +287,7 @@ class Ajax extends Backend
{ {
$params = $this->request->get("row/a"); $params = $this->request->get("row/a");
if (!empty($params)) { if (!empty($params)) {
$province = isset($params['province']) ? $params['province'] : ''; $province = isset($params['province']) ? $params['province'] : null;
$city = isset($params['city']) ? $params['city'] : null; $city = isset($params['city']) ? $params['city'] : null;
} else { } else {
$province = $this->request->get('province'); $province = $this->request->get('province');
@ -280,20 +295,16 @@ class Ajax extends Backend
} }
$where = ['pid' => 0, 'level' => 1]; $where = ['pid' => 0, 'level' => 1];
$provincelist = null; $provincelist = null;
if ($province !== '') { if ($province !== null) {
if ($province) { $where['pid'] = $province;
$where['pid'] = $province; $where['level'] = 2;
$where['level'] = 2; if ($city !== null) {
} $where['pid'] = $city;
if ($city !== '') { $where['level'] = 3;
if ($city) {
$where['pid'] = $city;
$where['level'] = 3;
}
$provincelist = Db::name('area')->where($where)->field('id as value,name')->select();
} }
} }
$this->success('', null, $provincelist); $provincelist = Db::name('area')->where($where)->field('id as value,name')->select();
$this->success('', '', $provincelist);
} }
/** /**
@ -302,10 +313,15 @@ class Ajax extends Backend
public function icon() public function icon()
{ {
$suffix = $this->request->request("suffix"); $suffix = $this->request->request("suffix");
header('Content-type: image/svg+xml');
$suffix = $suffix ? $suffix : "FILE"; $suffix = $suffix ? $suffix : "FILE";
echo build_suffix_image($suffix); $data = build_suffix_image($suffix);
exit; $header = ['Content-Type' => 'image/svg+xml'];
$offset = 30 * 60 * 60 * 24; // 缓存一个月
$header['Cache-Control'] = 'public';
$header['Pragma'] = 'cache';
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
$response = Response::create($data, '', 200, $header);
return $response;
} }
} }

View File

@ -10,7 +10,7 @@ use fast\Tree;
* 分类管理 * 分类管理
* *
* @icon fa fa-list * @icon fa fa-list
* @remark 用于统一管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加 * @remark 用于管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加
*/ */
class Category extends Backend class Category extends Backend
{ {
@ -81,6 +81,17 @@ class Category extends Backend
return $this->view->fetch(); return $this->view->fetch();
} }
/**
* 添加
*/
public function add()
{
if ($this->request->isPost()) {
$this->token();
}
return parent::add();
}
/** /**
* 编辑 * 编辑
*/ */
@ -97,6 +108,7 @@ class Category extends Backend
} }
} }
if ($this->request->isPost()) { if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a"); $params = $this->request->post("row/a");
if ($params) { if ($params) {
$params = $this->preExcludeFields($params); $params = $this->preExcludeFields($params);

View File

@ -2,13 +2,17 @@
namespace app\admin\controller; namespace app\admin\controller;
use app\admin\model\Admin;
use app\admin\model\User;
use app\common\controller\Backend; use app\common\controller\Backend;
use think\Config; use app\common\model\Attachment;
use fast\Date;
use think\Db;
/** /**
* 控制台 * 控制台
* *
* @icon fa fa-dashboard * @icon fa fa-dashboard
* @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据 * @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据
*/ */
class Dashboard extends Backend class Dashboard extends Backend
@ -19,37 +23,61 @@ class Dashboard extends Backend
*/ */
public function index() public function index()
{ {
$seventtime = \fast\Date::unixtime('day', -7); try {
$paylist = $createlist = []; \think\Db::execute("SET @@sql_mode='';");
for ($i = 0; $i < 7; $i++) } catch (\Exception $e) {
{
$day = date("Y-m-d", $seventtime + ($i * 86400)); }
$createlist[$day] = mt_rand(20, 200); $column = [];
$paylist[$day] = mt_rand(1, mt_rand(1, $createlist[$day])); $starttime = Date::unixtime('day', -6);
$endtime = Date::unixtime('day', 0, 'end');
$joinlist = Db("user")->where('jointime', 'between time', [$starttime, $endtime])
->field('jointime, status, COUNT(*) AS nums, DATE_FORMAT(FROM_UNIXTIME(jointime), "%Y-%m-%d") AS join_date')
->group('join_date')
->select();
for ($time = $starttime; $time <= $endtime;) {
$column[] = date("Y-m-d", $time);
$time += 86400;
}
$userlist = array_fill_keys($column, 0);
foreach ($joinlist as $k => $v) {
$userlist[$v['join_date']] = $v['nums'];
}
$dbTableList = Db::query("SHOW TABLE STATUS");
$addonList = get_addon_list();
$totalworkingaddon = 0;
$totaladdon = count($addonList);
foreach ($addonList as $index => $item) {
if ($item['state']) {
$totalworkingaddon += 1;
}
} }
$hooks = config('addons.hooks');
$uploadmode = isset($hooks['upload_config_init']) && $hooks['upload_config_init'] ? implode(',', $hooks['upload_config_init']) : 'local';
$addonComposerCfg = ROOT_PATH . '/vendor/karsonzhang/fastadmin-addons/composer.json';
Config::parse($addonComposerCfg, "json", "composer");
$config = Config::get("composer");
$addonVersion = isset($config['version']) ? $config['version'] : __('Unknown');
$this->view->assign([ $this->view->assign([
'totaluser' => 35200, 'totaluser' => User::count(),
'totalviews' => 219390, 'totaladdon' => $totaladdon,
'totalorder' => 32143, 'totaladmin' => Admin::count(),
'totalorderamount' => 174800, 'totalcategory' => \app\common\model\Category::count(),
'todayuserlogin' => 321, 'todayusersignup' => User::whereTime('jointime', 'today')->count(),
'todayusersignup' => 430, 'todayuserlogin' => User::whereTime('logintime', 'today')->count(),
'todayorder' => 2324, 'sevendau' => User::whereTime('jointime|logintime|prevtime', '-7 days')->count(),
'unsettleorder' => 132, 'thirtydau' => User::whereTime('jointime|logintime|prevtime', '-30 days')->count(),
'sevendnu' => '80%', 'threednu' => User::whereTime('jointime', '-3 days')->count(),
'sevendau' => '32%', 'sevendnu' => User::whereTime('jointime', '-7 days')->count(),
'paylist' => $paylist, 'dbtablenums' => count($dbTableList),
'createlist' => $createlist, 'dbsize' => array_sum(array_map(function ($item) {
'addonversion' => $addonVersion, return $item['Data_length'] + $item['Index_length'];
'uploadmode' => $uploadmode }, $dbTableList)),
'totalworkingaddon' => $totalworkingaddon,
'attachmentnums' => Attachment::count(),
'attachmentsize' => Attachment::sum('filesize'),
'picturenums' => Attachment::where('mimetype', 'like', 'image/%')->count(),
'picturesize' => Attachment::where('mimetype', 'like', 'image/%')->sum('filesize'),
]); ]);
$this->assignconfig('column', array_keys($userlist));
$this->assignconfig('userdata', array_values($userlist));
return $this->view->fetch(); return $this->view->fetch();
} }

View File

@ -6,6 +6,7 @@ use app\admin\model\AdminLog;
use app\common\controller\Backend; use app\common\controller\Backend;
use think\Config; use think\Config;
use think\Hook; use think\Hook;
use think\Session;
use think\Validate; use think\Validate;
/** /**
@ -31,12 +32,18 @@ class Index extends Backend
*/ */
public function index() public function index()
{ {
$cookieArr = ['adminskin' => "/^skin\-([a-z\-]+)\$/i", 'multiplenav' => "/^(0|1)\$/", 'multipletab' => "/^(0|1)\$/", 'show_submenu' => "/^(0|1)\$/"];
foreach ($cookieArr as $key => $regex) {
$cookieValue = $this->request->cookie($key);
if (!is_null($cookieValue) && preg_match($regex, $cookieValue)) {
config('fastadmin.' . $key, $cookieValue);
}
}
//左侧菜单 //左侧菜单
list($menulist, $navlist, $fixedmenu, $referermenu) = $this->auth->getSidebar([ list($menulist, $navlist, $fixedmenu, $referermenu) = $this->auth->getSidebar([
'dashboard' => 'hot', 'dashboard' => 'hot',
'addon' => ['new', 'red', 'badge'], 'addon' => ['new', 'red', 'badge'],
'auth/rule' => __('Menu'), 'auth/rule' => __('Menu'),
'general' => ['new', 'purple'],
], $this->view->site['fixedpage']); ], $this->view->site['fixedpage']);
$action = $this->request->request('action'); $action = $this->request->request('action');
if ($this->request->isPost()) { if ($this->request->isPost()) {
@ -44,6 +51,7 @@ class Index extends Backend
$this->success('', null, ['menulist' => $menulist, 'navlist' => $navlist]); $this->success('', null, ['menulist' => $menulist, 'navlist' => $navlist]);
} }
} }
$this->assignconfig('cookie', ['prefix' => config('cookie.prefix')]);
$this->view->assign('menulist', $menulist); $this->view->assign('menulist', $menulist);
$this->view->assign('navlist', $navlist); $this->view->assign('navlist', $navlist);
$this->view->assign('fixedmenu', $fixedmenu); $this->view->assign('fixedmenu', $fixedmenu);
@ -57,13 +65,16 @@ class Index extends Backend
*/ */
public function login() public function login()
{ {
$url = $this->request->get('url', 'index/index'); $url = $this->request->get('url', '', 'url_clean');
$url = $url ?: 'index/index';
if ($this->auth->isLogin()) { if ($this->auth->isLogin()) {
$this->success(__("You've logged in, do not login again"), $url); $this->success(__("You've logged in, do not login again"), $url);
} }
//保持会话有效时长,单位:小时
$keeyloginhours = 24;
if ($this->request->isPost()) { if ($this->request->isPost()) {
$username = $this->request->post('username'); $username = $this->request->post('username');
$password = $this->request->post('password'); $password = $this->request->post('password', '', null);
$keeplogin = $this->request->post('keeplogin'); $keeplogin = $this->request->post('keeplogin');
$token = $this->request->post('__token__'); $token = $this->request->post('__token__');
$rule = [ $rule = [
@ -86,7 +97,7 @@ class Index extends Backend
$this->error($validate->getError(), $url, ['token' => $this->request->token()]); $this->error($validate->getError(), $url, ['token' => $this->request->token()]);
} }
AdminLog::setTitle(__('Login')); AdminLog::setTitle(__('Login'));
$result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0); $result = $this->auth->login($username, $password, $keeplogin ? $keeyloginhours * 3600 : 0);
if ($result === true) { if ($result === true) {
Hook::listen("admin_login_after", $this->request); Hook::listen("admin_login_after", $this->request);
$this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $username, 'avatar' => $this->auth->avatar]); $this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $username, 'avatar' => $this->auth->avatar]);
@ -99,10 +110,12 @@ class Index extends Backend
// 根据客户端的cookie,判断是否可以自动登录 // 根据客户端的cookie,判断是否可以自动登录
if ($this->auth->autologin()) { if ($this->auth->autologin()) {
Session::delete("referer");
$this->redirect($url); $this->redirect($url);
} }
$background = Config::get('fastadmin.login_background'); $background = Config::get('fastadmin.login_background');
$background = stripos($background, 'http') === 0 ? $background : config('site.cdnurl') . $background; $background = $background ? (stripos($background, 'http') === 0 ? $background : config('site.cdnurl') . $background) : '';
$this->view->assign('keeyloginhours', $keeyloginhours);
$this->view->assign('background', $background); $this->view->assign('background', $background);
$this->view->assign('title', __('Login')); $this->view->assign('title', __('Login'));
Hook::listen("admin_login_init", $this->request); Hook::listen("admin_login_init", $this->request);
@ -110,13 +123,19 @@ class Index extends Backend
} }
/** /**
* 注销登录 * 退出登录
*/ */
public function logout() public function logout()
{ {
$this->auth->logout(); if ($this->request->isPost()) {
Hook::listen("admin_logout_after", $this->request); $this->auth->logout();
$this->success(__('Logout successful'), 'index/login'); Hook::listen("admin_logout_after", $this->request);
$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>";
$html .= "<script>document.forms['logout_submit'].submit();</script>";
return $html;
} }
} }

View File

@ -7,12 +7,13 @@ use app\admin\model\AuthGroupAccess;
use app\common\controller\Backend; use app\common\controller\Backend;
use fast\Random; use fast\Random;
use fast\Tree; use fast\Tree;
use think\Db;
use think\Validate; use think\Validate;
/** /**
* 管理员管理 * 管理员管理
* *
* @icon fa fa-users * @icon fa fa-users
* @remark 一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成 * @remark 一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成
*/ */
class Admin extends Backend class Admin extends Backend
@ -22,6 +23,8 @@ class Admin extends Backend
* @var \app\admin\model\Admin * @var \app\admin\model\Admin
*/ */
protected $model = null; protected $model = null;
protected $selectpageFields = 'id,username,nickname,avatar';
protected $searchFields = 'id,username,nickname';
protected $childrenGroupIds = []; protected $childrenGroupIds = [];
protected $childrenAdminIds = []; protected $childrenAdminIds = [];
@ -30,8 +33,8 @@ class Admin extends Backend
parent::_initialize(); parent::_initialize();
$this->model = model('Admin'); $this->model = model('Admin');
$this->childrenAdminIds = $this->auth->getChildrenAdminIds(true); $this->childrenAdminIds = $this->auth->getChildrenAdminIds($this->auth->isSuperAdmin());
$this->childrenGroupIds = $this->auth->getChildrenGroupIds(true); $this->childrenGroupIds = $this->auth->getChildrenGroupIds($this->auth->isSuperAdmin());
$groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray(); $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
@ -65,6 +68,8 @@ class Admin extends Backend
*/ */
public function index() public function index()
{ {
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
//如果发送的来源是Selectpage则转发到Selectpage //如果发送的来源是Selectpage则转发到Selectpage
if ($this->request->request('keyField')) { if ($this->request->request('keyField')) {
@ -88,26 +93,21 @@ class Admin extends Backend
$adminGroupName[$this->auth->id][$n['id']] = $n['name']; $adminGroupName[$this->auth->id][$n['id']] = $n['name'];
} }
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->where('id', 'in', $this->childrenAdminIds)
->order($sort, $order)
->count();
$list = $this->model $list = $this->model
->where($where) ->where($where)
->where('id', 'in', $this->childrenAdminIds) ->where('id', 'in', $this->childrenAdminIds)
->field(['password', 'salt', 'token'], true) ->field(['password', 'salt', 'token'], true)
->order($sort, $order) ->order($sort, $order)
->limit($offset, $limit) ->paginate($limit);
->select();
foreach ($list as $k => &$v) { foreach ($list as $k => &$v) {
$groups = isset($adminGroupName[$v['id']]) ? $adminGroupName[$v['id']] : []; $groups = isset($adminGroupName[$v['id']]) ? $adminGroupName[$v['id']] : [];
$v['groups'] = implode(',', array_keys($groups)); $v['groups'] = implode(',', array_keys($groups));
$v['groups_text'] = implode(',', array_values($groups)); $v['groups_text'] = implode(',', array_values($groups));
} }
unset($v); unset($v);
$result = array("total" => $total, "rows" => $list); $result = array("total" => $list->total(), "rows" => $list->items());
return json($result); return json($result);
} }
@ -123,28 +123,39 @@ class Admin extends Backend
$this->token(); $this->token();
$params = $this->request->post("row/a"); $params = $this->request->post("row/a");
if ($params) { if ($params) {
if (!Validate::is($params['password'], '\S{6,16}')) { Db::startTrans();
$this->error(__("Please input correct password")); try {
} if (!Validate::is($params['password'], '\S{6,30}')) {
$params['salt'] = Random::alnum(); exception(__("Please input correct password"));
$params['password'] = md5(md5($params['password']) . $params['salt']); }
$params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。 $params['salt'] = Random::alnum();
$result = $this->model->validate('Admin.add')->save($params); $params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
if ($result === false) { $params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。
$this->error($this->model->getError()); $result = $this->model->validate('Admin.add')->save($params);
} if ($result === false) {
$group = $this->request->post("group/a"); exception($this->model->getError());
}
$group = $this->request->post("group/a");
//过滤不允许的组别,避免越权 //过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group); $group = array_intersect($this->childrenGroupIds, $group);
$dataset = []; if (!$group) {
foreach ($group as $value) { exception(__('The parent group exceeds permission limit'));
$dataset[] = ['uid' => $this->model->id, 'group_id' => $value]; }
$dataset = [];
foreach ($group as $value) {
$dataset[] = ['uid' => $this->model->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} }
model('AuthGroupAccess')->saveAll($dataset);
$this->success(); $this->success();
} }
$this->error(); $this->error(__('Parameter %s can not be empty', ''));
} }
return $this->view->fetch(); return $this->view->fetch();
} }
@ -165,43 +176,54 @@ class Admin extends Backend
$this->token(); $this->token();
$params = $this->request->post("row/a"); $params = $this->request->post("row/a");
if ($params) { if ($params) {
if ($params['password']) { Db::startTrans();
if (!Validate::is($params['password'], '\S{6,16}')) { try {
$this->error(__("Please input correct password")); if ($params['password']) {
if (!Validate::is($params['password'], '\S{6,30}')) {
exception(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
} else {
unset($params['password'], $params['salt']);
} }
$params['salt'] = Random::alnum(); //这里需要针对username和email做唯一验证
$params['password'] = md5(md5($params['password']) . $params['salt']); $adminValidate = \think\Loader::validate('Admin');
} else { $adminValidate->rule([
unset($params['password'], $params['salt']); 'username' => 'require|regex:\w{3,30}|unique:admin,username,' . $row->id,
'email' => 'require|email|unique:admin,email,' . $row->id,
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id,
'password' => 'regex:\S{32}',
]);
$result = $row->validate('Admin.edit')->save($params);
if ($result === false) {
exception($row->getError());
}
// 先移除所有权限
model('AuthGroupAccess')->where('uid', $row->id)->delete();
$group = $this->request->post("group/a");
// 过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group);
if (!$group) {
exception(__('The parent group exceeds permission limit'));
}
$dataset = [];
foreach ($group as $value) {
$dataset[] = ['uid' => $row->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} }
//这里需要针对username和email做唯一验证
$adminValidate = \think\Loader::validate('Admin');
$adminValidate->rule([
'username' => 'require|regex:\w{3,12}|unique:admin,username,' . $row->id,
'email' => 'require|email|unique:admin,email,' . $row->id,
'password' => 'regex:\S{32}',
]);
$result = $row->validate('Admin.edit')->save($params);
if ($result === false) {
$this->error($row->getError());
}
// 先移除所有权限
model('AuthGroupAccess')->where('uid', $row->id)->delete();
$group = $this->request->post("group/a");
// 过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group);
$dataset = [];
foreach ($group as $value) {
$dataset[] = ['uid' => $row->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
$this->success(); $this->success();
} }
$this->error(); $this->error(__('Parameter %s can not be empty', ''));
} }
$grouplist = $this->auth->getGroups($row['id']); $grouplist = $this->auth->getGroups($row['id']);
$groupids = []; $groupids = [];
@ -218,6 +240,10 @@ class Admin extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) { if ($ids) {
$ids = array_intersect($this->childrenAdminIds, array_filter(explode(',', $ids))); $ids = array_intersect($this->childrenAdminIds, array_filter(explode(',', $ids)));
// 避免越权删除管理员 // 避免越权删除管理员
@ -232,10 +258,18 @@ class Admin extends Backend
} }
$deleteIds = array_values(array_diff($deleteIds, [$this->auth->id])); $deleteIds = array_values(array_diff($deleteIds, [$this->auth->id]));
if ($deleteIds) { if ($deleteIds) {
$this->model->destroy($deleteIds); Db::startTrans();
model('AuthGroupAccess')->where('uid', 'in', $deleteIds)->delete(); try {
$this->model->destroy($deleteIds);
model('AuthGroupAccess')->where('uid', 'in', $deleteIds)->delete();
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success(); $this->success();
} }
$this->error(__('No rows were deleted'));
} }
} }
$this->error(__('You have no permission')); $this->error(__('You have no permission'));

View File

@ -8,7 +8,7 @@ use app\common\controller\Backend;
/** /**
* 管理员日志 * 管理员日志
* *
* @icon fa fa-users * @icon fa fa-users
* @remark 管理员可以查看自己所拥有的权限的管理员日志 * @remark 管理员可以查看自己所拥有的权限的管理员日志
*/ */
class Adminlog extends Backend class Adminlog extends Backend
@ -27,10 +27,10 @@ class Adminlog extends Backend
$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($this->auth->isSuperAdmin() ? true : false); $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
$groupName = AuthGroup::where('id', 'in', $this->childrenGroupIds) $groupName = AuthGroup::where('id', 'in', $this->childrenGroupIds)
->column('id,name'); ->column('id,name');
$this->view->assign('groupdata', $groupName); $this->view->assign('groupdata', $groupName);
} }
@ -40,22 +40,24 @@ class Adminlog extends Backend
*/ */
public function index() public function index()
{ {
if ($this->request->isAjax()) //设置过滤方法
{ $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model $isSuperAdmin = $this->auth->isSuperAdmin();
->where($where) $childrenAdminIds = $this->childrenAdminIds;
->where('admin_id', 'in', $this->childrenAdminIds)
->order($sort, $order)
->count();
$list = $this->model $list = $this->model
->where($where) ->where($where)
->where('admin_id', 'in', $this->childrenAdminIds) ->where(function ($query) use ($isSuperAdmin, $childrenAdminIds) {
->order($sort, $order) if (!$isSuperAdmin) {
->limit($offset, $limit) $query->where('admin_id', 'in', $childrenAdminIds);
->select(); }
$result = array("total" => $total, "rows" => $list); })
->field('content,useragent', true)
->order($sort, $order)
->paginate($limit);
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result); return json($result);
} }
@ -68,8 +70,14 @@ class Adminlog extends Backend
public function detail($ids) public function detail($ids)
{ {
$row = $this->model->get(['id' => $ids]); $row = $this->model->get(['id' => $ids]);
if (!$row) if (!$row) {
$this->error(__('No Results were found')); $this->error(__('No Results were found'));
}
if (!$this->auth->isSuperAdmin()) {
if (!$row['admin_id'] || !in_array($row['admin_id'], $this->childrenAdminIds)) {
$this->error(__('You have no permission'));
}
}
$this->view->assign("row", $row->toArray()); $this->view->assign("row", $row->toArray());
return $this->view->fetch(); return $this->view->fetch();
} }
@ -87,7 +95,7 @@ class Adminlog extends Backend
* 编辑 * 编辑
* @internal * @internal
*/ */
public function edit($ids = NULL) public function edit($ids = null)
{ {
$this->error(); $this->error();
} }
@ -97,21 +105,26 @@ class Adminlog extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if ($ids) if (!$this->request->isPost()) {
{ $this->error(__("Invalid parameters"));
$childrenGroupIds = $this->childrenGroupIds; }
$adminList = $this->model->where('id', 'in', $ids)->where('admin_id', 'in', function($query) use($childrenGroupIds) { $ids = $ids ? $ids : $this->request->post("ids");
$query->name('auth_group_access')->field('uid'); if ($ids) {
})->select(); $isSuperAdmin = $this->auth->isSuperAdmin();
if ($adminList) $childrenAdminIds = $this->childrenAdminIds;
{ $adminList = $this->model->where('id', 'in', $ids)
->where(function ($query) use ($isSuperAdmin, $childrenAdminIds) {
if (!$isSuperAdmin) {
$query->where('admin_id', 'in', $childrenAdminIds);
}
})
->select();
if ($adminList) {
$deleteIds = []; $deleteIds = [];
foreach ($adminList as $k => $v) foreach ($adminList as $k => $v) {
{
$deleteIds[] = $v->id; $deleteIds[] = $v->id;
} }
if ($deleteIds) if ($deleteIds) {
{
$this->model->destroy($deleteIds); $this->model->destroy($deleteIds);
$this->success(); $this->success();
} }
@ -129,10 +142,5 @@ class Adminlog extends Backend
// 管理员禁止批量操作 // 管理员禁止批量操作
$this->error(); $this->error();
} }
public function selectpage()
{
return parent::selectpage();
}
} }

View File

@ -11,7 +11,7 @@ use think\Exception;
/** /**
* 角色组 * 角色组
* *
* @icon fa fa-group * @icon fa fa-group
* @remark 角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别下级的角色组或管理员 * @remark 角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别下级的角色组或管理员
*/ */
class Group extends Backend class Group extends Backend
@ -24,6 +24,7 @@ class Group extends Backend
//当前登录管理员所有子组别 //当前登录管理员所有子组别
protected $childrenGroupIds = []; protected $childrenGroupIds = [];
//当前组别列表数据 //当前组别列表数据
protected $grouplist = [];
protected $groupdata = []; protected $groupdata = [];
//无需要权限判断的方法 //无需要权限判断的方法
protected $noNeedRight = ['roletree']; protected $noNeedRight = ['roletree'];
@ -38,20 +39,28 @@ class Group extends Backend
$groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray(); $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
Tree::instance()->init($groupList); Tree::instance()->init($groupList);
$result = []; $groupList = [];
if ($this->auth->isSuperAdmin()) { if ($this->auth->isSuperAdmin()) {
$result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0)); $groupList = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0));
} else { } else {
$groups = $this->auth->getGroups(); $groups = $this->auth->getGroups();
$groupIds = [];
foreach ($groups as $m => $n) { foreach ($groups as $m => $n) {
$result = array_merge($result, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid']))); if (in_array($n['id'], $groupIds) || in_array($n['pid'], $groupIds)) {
continue;
}
$groupList = array_merge($groupList, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid'])));
foreach ($groupList as $index => $item) {
$groupIds[] = $item['id'];
}
} }
} }
$groupName = []; $groupName = [];
foreach ($result as $k => $v) { foreach ($groupList as $k => $v) {
$groupName[$v['id']] = $v['name']; $groupName[$v['id']] = $v['name'];
} }
$this->grouplist = $groupList;
$this->groupdata = $groupName; $this->groupdata = $groupName;
$this->assignconfig("admin", ['id' => $this->auth->id, 'group_ids' => $this->auth->getGroupIds()]); $this->assignconfig("admin", ['id' => $this->auth->id, 'group_ids' => $this->auth->getGroupIds()]);
@ -64,19 +73,7 @@ class Group extends Backend
public function index() public function index()
{ {
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$list = AuthGroup::all(array_keys($this->groupdata)); $list = $this->grouplist;
$list = collection($list)->toArray();
$groupList = [];
foreach ($list as $k => $v) {
$groupList[$v['id']] = $v;
}
$list = [];
foreach ($this->groupdata as $k => $v) {
if (isset($groupList[$k])) {
$groupList[$k]['name'] = $v;
$list[] = $groupList[$k];
}
}
$total = count($list); $total = count($list);
$result = array("total" => $total, "rows" => $list); $result = array("total" => $total, "rows" => $list);
@ -140,7 +137,7 @@ class Group extends Backend
$this->error(__('The parent group exceeds permission limit')); $this->error(__('The parent group exceeds permission limit'));
} }
// 父节点不能是它自身的子节点或自己本身 // 父节点不能是它自身的子节点或自己本身
if (in_array($params['pid'], Tree::instance()->getChildrenIds($row->id,true))){ if (in_array($params['pid'], Tree::instance()->getChildrenIds($row->id, true))) {
$this->error(__('The parent group can not be its own child or itself')); $this->error(__('The parent group can not be its own child or itself'));
} }
$params['rules'] = explode(',', $params['rules']); $params['rules'] = explode(',', $params['rules']);
@ -163,16 +160,16 @@ class Group extends Backend
Db::startTrans(); Db::startTrans();
try { try {
$row->save($params); $row->save($params);
$children_auth_groups = model("AuthGroup")->all(['id'=>['in',implode(',',(Tree::instance()->getChildrenIds($row->id)))]]); $children_auth_groups = model("AuthGroup")->all(['id' => ['in', implode(',', (Tree::instance()->getChildrenIds($row->id)))]]);
$childparams = []; $childparams = [];
foreach ($children_auth_groups as $key=>$children_auth_group) { foreach ($children_auth_groups as $key => $children_auth_group) {
$childparams[$key]['id'] = $children_auth_group->id; $childparams[$key]['id'] = $children_auth_group->id;
$childparams[$key]['rules'] = implode(',', array_intersect(explode(',', $children_auth_group->rules), $rules)); $childparams[$key]['rules'] = implode(',', array_intersect(explode(',', $children_auth_group->rules), $rules));
} }
model("AuthGroup")->saveAll($childparams); model("AuthGroup")->saveAll($childparams);
Db::commit(); Db::commit();
$this->success(); $this->success();
}catch (Exception $e){ } catch (Exception $e) {
Db::rollback(); Db::rollback();
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
@ -189,6 +186,10 @@ class Group extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) { if ($ids) {
$ids = explode(',', $ids); $ids = explode(',', $ids);
$grouplist = $this->auth->getGroups(); $grouplist = $this->auth->getGroups();

View File

@ -31,12 +31,12 @@ class Rule extends Backend
} }
$this->model = model('AuthRule'); $this->model = model('AuthRule');
// 必须将结果集转换为数组 // 必须将结果集转换为数组
$ruleList = collection($this->model->field('condition,remark,createtime,updatetime', true)->order('weigh DESC,id ASC')->select())->toArray(); $ruleList = \think\Db::name("auth_rule")->field('type,condition,remark,createtime,updatetime', true)->order('weigh DESC,id ASC')->select();
foreach ($ruleList as $k => &$v) { foreach ($ruleList as $k => &$v) {
$v['title'] = __($v['title']); $v['title'] = __($v['title']);
} }
unset($v); unset($v);
Tree::instance()->init($ruleList); Tree::instance()->init($ruleList)->icon = ['&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;'];
$this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title'); $this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
$ruledata = [0 => __('None')]; $ruledata = [0 => __('None')];
foreach ($this->rulelist as $k => &$v) { foreach ($this->rulelist as $k => &$v) {
@ -44,9 +44,11 @@ class Rule extends Backend
continue; continue;
} }
$ruledata[$v['id']] = $v['title']; $ruledata[$v['id']] = $v['title'];
unset($v['spacer']);
} }
unset($v); unset($v);
$this->view->assign('ruledata', $ruledata); $this->view->assign('ruledata', $ruledata);
$this->view->assign("menutypeList", $this->model->getMenutypeList());
} }
/** /**
@ -57,7 +59,6 @@ class Rule extends Backend
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$list = $this->rulelist; $list = $this->rulelist;
$total = count($this->rulelist); $total = count($this->rulelist);
$result = array("total" => $total, "rows" => $list); $result = array("total" => $total, "rows" => $list);
return json($result); return json($result);
@ -105,6 +106,9 @@ class Rule extends Backend
if (!$params['ismenu'] && !$params['pid']) { if (!$params['ismenu'] && !$params['pid']) {
$this->error(__('The non-menu rule must have parent')); $this->error(__('The non-menu rule must have parent'));
} }
if ($params['pid'] == $row['id']) {
$this->error(__('Can not change the parent to self'));
}
if ($params['pid'] != $row['pid']) { if ($params['pid'] != $row['pid']) {
$childrenIds = Tree::instance()->init(collection(AuthRule::select())->toArray())->getChildrenIds($row['id']); $childrenIds = Tree::instance()->init(collection(AuthRule::select())->toArray())->getChildrenIds($row['id']);
if (in_array($params['pid'], $childrenIds)) { if (in_array($params['pid'], $childrenIds)) {
@ -114,7 +118,7 @@ class Rule extends Backend
//这里需要针对name做唯一验证 //这里需要针对name做唯一验证
$ruleValidate = \think\Loader::validate('AuthRule'); $ruleValidate = \think\Loader::validate('AuthRule');
$ruleValidate->rule([ $ruleValidate->rule([
'name' => 'require|format|unique:AuthRule,name,' . $row->id, 'name' => 'require|unique:AuthRule,name,' . $row->id,
]); ]);
$result = $row->validate()->save($params); $result = $row->validate()->save($params);
if ($result === false) { if ($result === false) {
@ -134,6 +138,10 @@ class Rule extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) { if ($ids) {
$delIds = []; $delIds = [];
foreach (explode(',', $ids) as $k => $v) { foreach (explode(',', $ids) as $k => $v) {

View File

@ -8,7 +8,7 @@ use app\common\controller\Backend;
* 附件管理 * 附件管理
* *
* @icon fa fa-circle-o * @icon fa fa-circle-o
* @remark 主要用于管理上传到又拍云的数据或上传至本服务的上传数据 * @remark 主要用于管理上传到服务器或第三方存储的数据
*/ */
class Attachment extends Backend class Attachment extends Backend
{ {
@ -18,11 +18,16 @@ class Attachment extends Backend
*/ */
protected $model = null; protected $model = null;
protected $searchFields = 'id,filename,url';
protected $noNeedRight = ['classify'];
public function _initialize() public function _initialize()
{ {
parent::_initialize(); parent::_initialize();
$this->model = model('Attachment'); $this->model = model('Attachment');
$this->view->assign("mimetypeList", \app\common\model\Attachment::getMimetypeList()); $this->view->assign("mimetypeList", \app\common\model\Attachment::getMimetypeList());
$this->view->assign("categoryList", \app\common\model\Attachment::getCategoryList());
$this->assignconfig("categoryList", \app\common\model\Attachment::getCategoryList());
} }
/** /**
@ -31,44 +36,41 @@ class Attachment extends Backend
public function index() public function index()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$mimetypeQuery = []; $mimetypeQuery = [];
$filter = $this->request->request('filter'); $filter = $this->request->request('filter');
$filterArr = (array)json_decode($filter, true); $filterArr = (array)json_decode($filter, true);
if (isset($filterArr['mimetype']) && preg_match("/[]\,|\*]/", $filterArr['mimetype'])) { if (isset($filterArr['category']) && $filterArr['category'] == 'unclassed') {
$this->request->get(['filter' => json_encode(array_diff_key($filterArr, ['mimetype' => '']))]); $filterArr['category'] = ',unclassed';
$mimetypeQuery = function ($query) use ($filterArr) { $this->request->get(['filter' => json_encode(array_diff_key($filterArr, ['category' => '']))]);
$mimetypeArr = explode(',', $filterArr['mimetype']); }
if (isset($filterArr['mimetype']) && preg_match("/(\/|\,|\*)/", $filterArr['mimetype'])) {
$mimetype = $filterArr['mimetype'];
$filterArr = array_diff_key($filterArr, ['mimetype' => '']);
$mimetypeQuery = function ($query) use ($mimetype) {
$mimetypeArr = array_filter(explode(',', $mimetype));
foreach ($mimetypeArr as $index => $item) { foreach ($mimetypeArr as $index => $item) {
if (stripos($item, "/*") !== false) { $query->whereOr('mimetype', 'like', '%' . str_replace("/*", "/", $item) . '%');
$query->whereOr('mimetype', 'like', str_replace("/*", "/", $item) . '%');
} else {
$query->whereOr('mimetype', 'like', '%' . $item . '%');
}
} }
}; };
} }
$this->request->get(['filter' => json_encode($filterArr)]);
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($mimetypeQuery)
->where($where)
->order($sort, $order)
->count();
$list = $this->model $list = $this->model
->where($mimetypeQuery) ->where($mimetypeQuery)
->where($where) ->where($where)
->order($sort, $order) ->order($sort, $order)
->limit($offset, $limit) ->paginate($limit);
->select();
$cdnurl = preg_replace("/\/(\w+)\.php$/i", '', $this->request->root()); $cdnurl = preg_replace("/\/(\w+)\.php$/i", '', $this->request->root());
foreach ($list as $k => &$v) { foreach ($list as $k => &$v) {
$v['fullurl'] = ($v['storage'] == 'local' ? $cdnurl : $this->view->config['upload']['cdnurl']) . $v['url']; $v['fullurl'] = ($v['storage'] == 'local' ? $cdnurl : $this->view->config['upload']['cdnurl']) . $v['url'];
} }
unset($v); unset($v);
$result = array("total" => $total, "rows" => $list); $result = array("total" => $list->total(), "rows" => $list->items());
return json($result); return json($result);
} }
@ -83,6 +85,9 @@ class Attachment extends Backend
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
return $this->index(); return $this->index();
} }
$mimetype = $this->request->get('mimetype', '');
$mimetype = substr($mimetype, -1) === '/' ? $mimetype . '*' : $mimetype;
$this->view->assign('mimetype', $mimetype);
return $this->view->fetch(); return $this->view->fetch();
} }
@ -103,11 +108,17 @@ class Attachment extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) { if ($ids) {
\think\Hook::add('upload_delete', function ($params) { \think\Hook::add('upload_delete', function ($params) {
$attachmentFile = ROOT_PATH . '/public' . $params['url']; if ($params['storage'] == 'local') {
if (is_file($attachmentFile)) { $attachmentFile = ROOT_PATH . '/public' . $params['url'];
@unlink($attachmentFile); if (is_file($attachmentFile)) {
@unlink($attachmentFile);
}
} }
}); });
$attachmentlist = $this->model->where('id', 'in', $ids)->select(); $attachmentlist = $this->model->where('id', 'in', $ids)->select();
@ -120,4 +131,30 @@ class Attachment extends Backend
$this->error(__('Parameter %s can not be empty', 'ids')); $this->error(__('Parameter %s can not be empty', 'ids'));
} }
/**
* 归类
*/
public function classify()
{
if (!$this->auth->check('general/attachment/edit')) {
\think\Hook::listen('admin_nopermission', $this);
$this->error(__('You have no permission'), '');
}
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$category = $this->request->post('category', '');
$ids = $this->request->post('ids');
if (!$ids) {
$this->error(__('Parameter %s can not be empty', 'ids'));
}
$categoryList = \app\common\model\Attachment::getCategoryList();
if ($category && !isset($categoryList[$category])) {
$this->error(__('Category not found'));
}
$category = $category == 'unclassed' ? '' : $category;
\app\common\model\Attachment::where('id', 'in', $ids)->update(['category' => $category]);
$this->success();
}
} }

View File

@ -5,6 +5,8 @@ namespace app\admin\controller\general;
use app\common\controller\Backend; use app\common\controller\Backend;
use app\common\library\Email; use app\common\library\Email;
use app\common\model\Config as ConfigModel; use app\common\model\Config as ConfigModel;
use think\Cache;
use think\Db;
use think\Exception; use think\Exception;
use think\Validate; use think\Validate;
@ -21,12 +23,13 @@ class Config extends Backend
* @var \app\common\model\Config * @var \app\common\model\Config
*/ */
protected $model = null; protected $model = null;
protected $noNeedRight = ['check', 'rulelist']; protected $noNeedRight = ['check', 'rulelist', 'selectpage', 'get_fields_list'];
public function _initialize() public function _initialize()
{ {
parent::_initialize(); parent::_initialize();
$this->model = model('Config'); // $this->model = model('Config');
$this->model = new ConfigModel;
ConfigModel::event('before_write', function ($row) { ConfigModel::event('before_write', function ($row) {
if (isset($row['name']) && $row['name'] == 'name' && preg_match("/fast" . "admin/i", $row['value'])) { if (isset($row['name']) && $row['name'] == 'name' && preg_match("/fast" . "admin/i", $row['value'])) {
throw new Exception(__("Site name incorrect")); throw new Exception(__("Site name incorrect"));
@ -57,7 +60,19 @@ class Config extends Backend
$value['value'] = explode(',', $value['value']); $value['value'] = explode(',', $value['value']);
} }
$value['content'] = json_decode($value['content'], true); $value['content'] = json_decode($value['content'], true);
if (in_array($value['name'], ['categorytype', 'configgroup', 'attachmentcategory'])) {
$dictValue = (array)json_decode($value['value'], true);
foreach ($dictValue as $index => &$item) {
$item = __($item);
}
unset($item);
$value['value'] = json_encode($dictValue, JSON_UNESCAPED_UNICODE);
}
$value['tip'] = htmlspecialchars($value['tip']); $value['tip'] = htmlspecialchars($value['tip']);
if ($value['name'] == 'cdnurl') {
//cdnurl不支持在线修改
continue;
}
$siteList[$v['group']]['list'][] = $value; $siteList[$v['group']]['list'][] = $value;
} }
$index = 0; $index = 0;
@ -77,12 +92,15 @@ class Config extends Backend
*/ */
public function add() public function add()
{ {
if (!config('app_debug')) {
$this->error(__('Only work at development environment'));
}
if ($this->request->isPost()) { if ($this->request->isPost()) {
$this->token(); $this->token();
$params = $this->request->post("row/a", [], 'trim'); $params = $this->request->post("row/a", [], 'trim');
if ($params) { if ($params) {
foreach ($params as $k => &$v) { foreach ($params as $k => &$v) {
$v = is_array($v) ? implode(',', $v) : $v; $v = is_array($v) && $k !== 'setting' ? implode(',', $v) : $v;
} }
if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array'])) { if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array'])) {
$params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE); $params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE);
@ -96,7 +114,7 @@ class Config extends Backend
} }
if ($result !== false) { if ($result !== false) {
try { try {
$this->refreshFile(); ConfigModel::refreshFile();
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
@ -139,7 +157,7 @@ class Config extends Backend
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
try { try {
$this->refreshFile(); ConfigModel::refreshFile();
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
@ -155,12 +173,15 @@ class Config extends Backend
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if (!config('app_debug')) {
$this->error(__('Only work at development environment'));
}
$name = $this->request->post('name'); $name = $this->request->post('name');
$config = ConfigModel::getByName($name); $config = ConfigModel::getByName($name);
if ($name && $config) { if ($name && $config) {
try { try {
$config->delete(); $config->delete();
$this->refreshFile(); ConfigModel::refreshFile();
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
@ -170,28 +191,6 @@ class Config extends Backend
} }
} }
/**
* 刷新配置文件
*/
protected function refreshFile()
{
$config = [];
foreach ($this->model->all() as $k => $v) {
$value = $v->toArray();
if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'])) {
$value['value'] = explode(',', $value['value']);
}
if ($value['type'] == 'array') {
$value['value'] = (array)json_decode($value['value'], true);
}
$config[$value['name']] = $value['value'];
}
file_put_contents(
APP_PATH . 'extra' . DS . 'site.php',
'<?php' . "\n\nreturn " . var_export($config, true) . ";"
);
}
/** /**
* 检测配置项是否存在 * 检测配置项是否存在
* @internal * @internal
@ -202,12 +201,12 @@ class Config extends Backend
if ($params) { if ($params) {
$config = $this->model->get($params); $config = $this->model->get($params);
if (!$config) { if (!$config) {
return $this->success(); $this->success();
} else { } else {
return $this->error(__('Name already exist')); $this->error(__('Name already exist'));
} }
} else { } else {
return $this->error(__('Invalid parameters')); $this->error(__('Invalid parameters'));
} }
} }
@ -253,8 +252,8 @@ class Config extends Backend
$email = new Email; $email = new Email;
$result = $email $result = $email
->to($receiver) ->to($receiver)
->subject(__("This is a test mail")) ->subject(__("This is a test mail", config('site.name')))
->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content') . '</div>') ->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content', config('site.name')) . '</div>')
->send(); ->send();
if ($result) { if ($result) {
$this->success(); $this->success();
@ -262,7 +261,51 @@ class Config extends Backend
$this->error($email->getError()); $this->error($email->getError());
} }
} else { } else {
return $this->error(__('Invalid parameters')); $this->error(__('Invalid parameters'));
} }
} }
public function selectpage()
{
$id = $this->request->get("id/d");
$config = \app\common\model\Config::get($id);
if (!$config) {
$this->error(__('Invalid parameters'));
}
$setting = $config['setting'];
//自定义条件
$custom = isset($setting['conditions']) ? (array)json_decode($setting['conditions'], true) : [];
$custom = array_filter($custom);
$this->request->request(['showField' => $setting['field'], 'keyField' => $setting['primarykey'], 'custom' => $custom, 'searchField' => [$setting['field'], $setting['primarykey']]]);
$this->model = \think\Db::connect()->setTable($setting['table']);
return parent::selectpage();
}
/**
* 获取表列表
* @internal
*/
public function get_table_list()
{
$tableList = [];
$dbname = \think\Config::get('database.database');
$tableList = \think\Db::query("SELECT `TABLE_NAME` AS `name`,`TABLE_COMMENT` AS `title` FROM `information_schema`.`TABLES` where `TABLE_SCHEMA` = '{$dbname}';");
$this->success('', null, ['tableList' => $tableList]);
}
/**
* 获取表字段列表
* @internal
*/
public function get_fields_list()
{
$table = $this->request->request('table');
$dbname = \think\Config::get('database.database');
//从数据库中获取表字段信息
$sql = "SELECT `COLUMN_NAME` AS `name`,`COLUMN_COMMENT` AS `title`,`DATA_TYPE` AS `type` FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION";
//加载主表的列
$fieldList = Db::query($sql, [$dbname, $table]);
$this->success("", null, ['fieldList' => $fieldList]);
}
} }

View File

@ -16,31 +16,26 @@ use think\Validate;
class Profile extends Backend class Profile extends Backend
{ {
protected $searchFields = 'id,title';
/** /**
* 查看 * 查看
*/ */
public function index() public function index()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$model = model('AdminLog'); $this->model = model('AdminLog');
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $model $list = $this->model
->where($where) ->where($where)
->where('admin_id', $this->auth->id) ->where('admin_id', $this->auth->id)
->order($sort, $order) ->order($sort, $order)
->count(); ->paginate($limit);
$list = $model $result = array("total" => $list->total(), "rows" => $list->items());
->where($where)
->where('admin_id', $this->auth->id)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result); return json($result);
} }
@ -64,7 +59,7 @@ class Profile extends Backend
$this->error(__("Please input correct email")); $this->error(__("Please input correct email"));
} }
if (isset($params['password'])) { if (isset($params['password'])) {
if (!Validate::is($params['password'], "/^[\S]{6,16}$/")) { if (!Validate::is($params['password'], "/^[\S]{6,30}$/")) {
$this->error(__("Please input correct password")); $this->error(__("Please input correct password"));
} }
$params['salt'] = Random::alnum(); $params['salt'] = Random::alnum();
@ -79,6 +74,7 @@ class Profile extends Backend
$admin->save($params); $admin->save($params);
//因为个人资料面板读取的Session显示修改自己资料后同时更新Session //因为个人资料面板读取的Session显示修改自己资料后同时更新Session
Session::set("admin", $admin->toArray()); Session::set("admin", $admin->toArray());
Session::set("admin.safecode", $this->auth->getEncryptSafecode($admin));
$this->success(); $this->success();
} }
$this->error(); $this->error();

View File

@ -26,16 +26,23 @@ class Group extends Backend
public function add() public function add()
{ {
if ($this->request->isPost()) {
$this->token();
}
$nodeList = \app\admin\model\UserRule::getTreeList(); $nodeList = \app\admin\model\UserRule::getTreeList();
$this->assign("nodeList", $nodeList); $this->assign("nodeList", $nodeList);
return parent::add(); return parent::add();
} }
public function edit($ids = NULL) public function edit($ids = null)
{ {
if ($this->request->isPost()) {
$this->token();
}
$row = $this->model->get($ids); $row = $this->model->get($ids);
if (!$row) if (!$row) {
$this->error(__('No Results were found')); $this->error(__('No Results were found'));
}
$rules = explode(',', $row['rules']); $rules = explode(',', $row['rules']);
$nodeList = \app\admin\model\UserRule::getTreeList($rules); $nodeList = \app\admin\model\UserRule::getTreeList($rules);
$this->assign("nodeList", $nodeList); $this->assign("nodeList", $nodeList);

View File

@ -13,7 +13,6 @@ use fast\Tree;
class Rule extends Backend class Rule extends Backend
{ {
/** /**
* @var \app\admin\model\UserRule * @var \app\admin\model\UserRule
*/ */
@ -28,19 +27,18 @@ class Rule extends Backend
$this->view->assign("statusList", $this->model->getStatusList()); $this->view->assign("statusList", $this->model->getStatusList());
// 必须将结果集转换为数组 // 必须将结果集转换为数组
$ruleList = collection($this->model->order('weigh', 'desc')->select())->toArray(); $ruleList = collection($this->model->order('weigh', 'desc')->select())->toArray();
foreach ($ruleList as $k => &$v) foreach ($ruleList as $k => &$v) {
{
$v['title'] = __($v['title']); $v['title'] = __($v['title']);
$v['remark'] = __($v['remark']); $v['remark'] = __($v['remark']);
} }
unset($v); unset($v);
Tree::instance()->init($ruleList); Tree::instance()->init($ruleList)->icon = ['&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;'];
$this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title'); $this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
$ruledata = [0 => __('None')]; $ruledata = [0 => __('None')];
foreach ($this->rulelist as $k => &$v) foreach ($this->rulelist as $k => &$v) {
{ if (!$v['ismenu']) {
if (!$v['ismenu'])
continue; continue;
}
$ruledata[$v['id']] = $v['title']; $ruledata[$v['id']] = $v['title'];
} }
$this->view->assign('ruledata', $ruledata); $this->view->assign('ruledata', $ruledata);
@ -51,8 +49,7 @@ class Rule extends Backend
*/ */
public function index() public function index()
{ {
if ($this->request->isAjax()) if ($this->request->isAjax()) {
{
$list = $this->rulelist; $list = $this->rulelist;
$total = count($this->rulelist); $total = count($this->rulelist);
@ -63,22 +60,45 @@ class Rule extends Backend
return $this->view->fetch(); return $this->view->fetch();
} }
/**
* 添加
*/
public function add()
{
if ($this->request->isPost()) {
$this->token();
}
return parent::add();
}
/**
* 编辑
*/
public function edit($ids = null)
{
if ($this->request->isPost()) {
$this->token();
}
return parent::edit($ids);
}
/** /**
* 删除 * 删除
*/ */
public function del($ids = "") public function del($ids = "")
{ {
if ($ids) if (!$this->request->isPost()) {
{ $this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) {
$delIds = []; $delIds = [];
foreach (explode(',', $ids) as $k => $v) foreach (explode(',', $ids) as $k => $v) {
{ $delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, true));
$delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, TRUE));
} }
$delIds = array_unique($delIds); $delIds = array_unique($delIds);
$count = $this->model->where('id', 'in', $delIds)->delete(); $count = $this->model->where('id', 'in', $delIds)->delete();
if ($count) if ($count) {
{
$this->success(); $this->success();
} }
} }

View File

@ -3,6 +3,7 @@
namespace app\admin\controller\user; namespace app\admin\controller\user;
use app\common\controller\Backend; use app\common\controller\Backend;
use app\common\library\Auth;
/** /**
* 会员管理 * 会员管理
@ -13,7 +14,7 @@ class User extends Backend
{ {
protected $relationSearch = true; protected $relationSearch = true;
protected $searchFields = 'id,username,nickname';
/** /**
* @var \app\admin\model\User * @var \app\admin\model\User
@ -23,7 +24,7 @@ class User extends Backend
public function _initialize() public function _initialize()
{ {
parent::_initialize(); parent::_initialize();
$this->model = model('User'); $this->model = new \app\admin\model\User;
} }
/** /**
@ -32,44 +33,73 @@ class User extends Backend
public function index() public function index()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
//如果发送的来源是Selectpage则转发到Selectpage //如果发送的来源是Selectpage则转发到Selectpage
if ($this->request->request('keyField')) { if ($this->request->request('keyField')) {
return $this->selectpage(); return $this->selectpage();
} }
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->with('group')
->where($where)
->order($sort, $order)
->count();
$list = $this->model $list = $this->model
->with('group') ->with('group')
->where($where) ->where($where)
->order($sort, $order) ->order($sort, $order)
->limit($offset, $limit) ->paginate($limit);
->select();
foreach ($list as $k => $v) { foreach ($list as $k => $v) {
$v->avatar = $v->avatar ? cdnurl($v->avatar, true) : letter_avatar($v->nickname);
$v->hidden(['password', 'salt']); $v->hidden(['password', 'salt']);
} }
$result = array("total" => $total, "rows" => $list); $result = array("total" => $list->total(), "rows" => $list->items());
return json($result); return json($result);
} }
return $this->view->fetch(); return $this->view->fetch();
} }
/**
* 添加
*/
public function add()
{
if ($this->request->isPost()) {
$this->token();
}
return parent::add();
}
/** /**
* 编辑 * 编辑
*/ */
public function edit($ids = NULL) public function edit($ids = null)
{ {
if ($this->request->isPost()) {
$this->token();
}
$row = $this->model->get($ids); $row = $this->model->get($ids);
if (!$row) $this->modelValidate = true;
if (!$row) {
$this->error(__('No Results were found')); $this->error(__('No Results were found'));
}
$this->view->assign('groupList', build_select('row[group_id]', \app\admin\model\UserGroup::column('id,name'), $row['group_id'], ['class' => 'form-control selectpicker'])); $this->view->assign('groupList', build_select('row[group_id]', \app\admin\model\UserGroup::column('id,name'), $row['group_id'], ['class' => 'form-control selectpicker']));
return parent::edit($ids); return parent::edit($ids);
} }
/**
* 删除
*/
public function del($ids = "")
{
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
$row = $this->model->get($ids);
$this->modelValidate = true;
if (!$row) {
$this->error(__('No Results were found'));
}
Auth::instance()->delete($row['id']);
$this->success();
}
} }

View File

@ -4,10 +4,12 @@ return [
'User id' => '会员ID', 'User id' => '会员ID',
'Username' => '用户名', 'Username' => '用户名',
'Nickname' => '昵称', 'Nickname' => '昵称',
'Mobile' => '手机',
'Email' => '邮箱',
'Password' => '密码', 'Password' => '密码',
'Sign up' => '注 册', 'Sign up' => '注 册',
'Sign in' => '登 录', 'Sign in' => '登 录',
'Sign out' => '注 销', 'Sign out' => '退 出',
'Keep login' => '保持会话', 'Keep login' => '保持会话',
'Guest' => '游客', 'Guest' => '游客',
'Welcome' => '%s你好', 'Welcome' => '%s你好',
@ -69,7 +71,7 @@ return [
'Home' => '主页', 'Home' => '主页',
'Online' => '在线', 'Online' => '在线',
'Login' => '登录', 'Login' => '登录',
'Logout' => '注销', 'Logout' => '退出',
'Profile' => '个人资料', 'Profile' => '个人资料',
'Index' => '首页', 'Index' => '首页',
'Hot' => '热门', 'Hot' => '热门',
@ -96,6 +98,9 @@ return [
'End time' => '结束时间', 'End time' => '结束时间',
'Create time' => '创建时间', 'Create time' => '创建时间',
'Update time' => '更新时间', 'Update time' => '更新时间',
'Createtime' => '创建时间',
'Updatetime' => '更新时间',
'Deletetime' => '删除时间',
'Flag' => '标志', 'Flag' => '标志',
'Drag to sort' => '拖动进行排序', 'Drag to sort' => '拖动进行排序',
'Redirect now' => '立即跳转', 'Redirect now' => '立即跳转',
@ -111,8 +116,17 @@ return [
'%d week%s ago' => '%d周前', '%d week%s ago' => '%d周前',
'%d month%s ago' => '%d月前', '%d month%s ago' => '%d月前',
'%d year%s ago' => '%d年前', '%d year%s ago' => '%d年前',
'%d second%s after' => '%d秒后',
'%d minute%s after' => '%d分钟后',
'%d hour%s after' => '%d小时后',
'%d day%s after' => '%d天后',
'%d week%s after' => '%d周后',
'%d month%s after' => '%d月后',
'%d year%s after' => '%d年后',
'Set to normal' => '设为正常', 'Set to normal' => '设为正常',
'Set to hidden' => '设为隐藏', 'Set to hidden' => '设为隐藏',
'Set status to normal' => '设为正常',
'Set status to hidden' => '设为隐藏',
'Recycle bin' => '回收站', 'Recycle bin' => '回收站',
'Restore' => '还原', 'Restore' => '还原',
'Restore all' => '还原全部', 'Restore all' => '还原全部',
@ -143,10 +157,28 @@ return [
'Please enter your username' => '请输入你的用户名', 'Please enter your username' => '请输入你的用户名',
'Please enter your password' => '请输入你的密码', 'Please enter your password' => '请输入你的密码',
'Please login first' => '请登录后操作', 'Please login first' => '请登录后操作',
'Uploaded successful' => '上传成功',
'You can upload up to %d file%s' => '你最多还可以上传%d个文件', 'You can upload up to %d file%s' => '你最多还可以上传%d个文件',
'You can choose up to %d file%s' => '你最多还可以选择%d个文件', 'You can choose up to %d file%s' => '你最多还可以选择%d个文件',
'Chunk file write error' => '分片写入失败',
'Chunk file info error' => '分片文件错误',
'Chunk file merge error' => '分片合并错误',
'Chunk file disabled' => '未开启分片上传功能',
'Cancel upload' => '取消上传',
'Upload canceled' => '上传已取消',
'No file upload or server upload limit exceeded' => '未上传文件或超出服务器上传限制',
'Uploaded file format is limited' => '上传文件格式受限制',
'Uploaded file is not a valid image' => '上传文件不是有效的图片文件',
'Are you sure you want to cancel this upload?' => '确定取消上传?',
'Remove file' => '移除文件',
'You can only upload a maximum of %s files' => '你最多允许上传 %s 个文件',
'You can\'t upload files of this type' => '不允许上传的文件类型',
'Server responded with %s code' => '服务端响应(Code:%s)',
'File is too big (%sMiB), Max filesize: %sMiB' => '当前上传(%sM),最大允许上传文件大小:%sM',
'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中', 'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中',
'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转', 'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
'Click to uncheck all' => '点击取消全部',
'Multiple selection mode: %s checked' => '跨页选择模式,已选 %s 项',
//菜单 //菜单
'Dashboard' => '控制台', 'Dashboard' => '控制台',
'General' => '常规管理', 'General' => '常规管理',
@ -173,13 +205,19 @@ return [
'Third group 2' => '三级管理组2', 'Third group 2' => '三级管理组2',
'Dashboard tips' => '用于展示当前系统中的统计数据、统计报表及重要实时数据', 'Dashboard tips' => '用于展示当前系统中的统计数据、统计报表及重要实时数据',
'Config tips' => '可以在此增改系统的变量和分组,也可以自定义分组和变量', 'Config tips' => '可以在此增改系统的变量和分组,也可以自定义分组和变量',
'Category tips' => '用于统一管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加', 'Category tips' => '分类类型请在常规管理->系统配置->字典配置中添加',
'Attachment tips' => '主要用于管理上传到服务器或第三方存储的数据', 'Attachment tips' => '主要用于管理上传到服务器或第三方存储的数据',
'Addon tips' => '可在线安装、卸载、禁用、启用插件,同时支持添加本地插件。', 'Addon tips' => '可在线安装、卸载、禁用、启用、配置、升级插件,插件升级前请做好备份。',
'Admin tips' => '一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成', 'Admin tips' => '一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成',
'Admin log tips' => '管理员可以查看自己所拥有的权限的管理员日志', 'Admin log tips' => '管理员可以查看自己所拥有的权限的管理员日志',
'Group tips' => '角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别的下级角色组或管理员', 'Group tips' => '角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别的下级角色组或管理员',
'Rule tips' => '规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过命令行进行生成规则节点', 'Rule tips' => '菜单规则通常对应一个控制器的方法,同时菜单栏数据也从规则中获取',
'Access is allowed only to the super management group' => '仅超级管理组能访问', 'Access is allowed only to the super management group' => '仅超级管理组能访问',
'Local addon' => '本地插件', 'Local addon' => '本地插件',
// 前台菜单
'Frontend' => '前台',
'API Interface' => 'API接口',
'User Module' => '会员模块',
'Register' => '注册',
'User Center' => '会员中心',
]; ];

View File

@ -1,93 +1,114 @@
<?php <?php
return [ return [
'Id' => 'ID', 'Id' => 'ID',
'Title' => '插件名称', 'Title' => '名称',
'Value' => '配置值', 'Value' => '配置值',
'Array key' => '键', 'Array key' => '键',
'Array value' => '值', 'Array value' => '值',
'File' => '文件', 'File' => '文件',
'Donate' => '打赏作者', 'Donate' => '打赏作者',
'Warmtips' => '温馨提示', 'Warmtips' => '温馨提示',
'Pay now' => '立即支付', 'Pay now' => '立即支付',
'Offline install' => '离线安装', 'Local install' => '本地安装',
'Refresh addon cache' => '刷新插件缓存', 'Refresh addon cache' => '刷新插件缓存',
'Userinfo' => '会员信息', 'Userinfo' => '会员信息',
'Online store' => '在线商店', 'Reload authorization' => '刷新授权',
'Local addon' => '本地插件', 'Local addon' => '本地插件',
'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作', 'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作',
'Login tips' => '此处登录账号为<a href="https://www.fastadmin.net" target="_blank">FastAdmin官网账号</a>', 'Pay tips' => '扫码支付后如果仍然无法安装,请不要重复支付,请稍后再重试安装!',
'Logined tips' => '你好!%s<br />当前你已经登录,将同步保存你的购买记录', 'Pay successful tips' => '购买成功!请点击继续安装按钮完成安装!',
'Pay tips' => '扫码支付后如果仍然无法立即下载,请不要重复支付,请稍后再重试安装!', 'Pay click tips' => '请点击这里在新窗口中进行支付!',
'Pay click tips' => '请点击这里在新窗口中进行支付!', 'Pay new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!',
'Pay new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!', 'Upgrade tips' => '确认升级<b>《%s》</b><p class="text-danger">1、请务必做好代码和数据库备份备份备份<br>2、升级后如出现冗余数据请根据需要移除即可!<br>3、不建议在生产环境升级请在本地完成升级测试</p>如有重要数据请备份后再操作!',
'Uninstall tips' => '确认卸载<b>[%s]</b><p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!', 'Offline installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!',
'Upgrade tips' => '确认升级<b>[%s]</b><p class="text-danger">升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!', 'Online installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!',
'Offline installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', 'Please login and try to install' => '请登录FastAdmin后再进行本地安装',
'Online installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', 'Not installed tips' => '请安装后再访问插件前台页面!',
'Not login tips' => '你当前未登录FastAdmin登录后将同步已购买的记录下载时无需二次付费', 'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!',
'Not installed tips' => '请安装后再访问插件前台页面!', 'New version tips' => '发现新版本:%s 点击查看更新日志',
'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!', 'Testdata tips' => '你还可以继续导入测试数据!',
'New version tips' => '发现新版本:%s 点击查看更新日志', 'Import testdata' => '导入测试数据',
'Store now available tips' => '插件市场暂不可用,是否切换到本地插件?', 'Skip testdata' => '暂不导入',
'Switch to the local' => '切换到本地插件', 'Store not available tips' => '插件市场暂不可用,是否切换到本地插件?',
'try to reload' => '重新尝试加载', 'Switch to the local' => '切换到本地插件',
'Please disable addon first' => '请先禁用插件再进行升级', 'try to reload' => '重新尝试加载',
'Login now' => '立即登录', 'Please disable addon first' => '请先禁用插件再进行操作',
'Continue install' => '不登录,继续安装', 'Please disable the add before trying to upgrade' => '请先禁用插件再进行升级',
'View addon home page' => '查看插件介绍和帮助', 'Please disable the add before trying to uninstall' => '请先禁用插件再进行卸载',
'View addon index page' => '查看插件前台首页', 'Login now' => '立即登录',
'View addon screenshots' => '点击查看插件截图', 'Continue install' => '继续安装',
'Click to toggle status' => '点击切换插件状态', 'View addon home page' => '查看插件介绍和帮助',
'Click to contact developer' => '点击与插件开发者取得联系', 'View addon index page' => '查看插件前台首页',
'My addons' => '我购买的插件', 'View addon screenshots' => '点击查看插件截图',
'My posts' => '我发布的插件', 'Click to toggle status' => '点击切换插件状态',
'Index' => '前台', 'Click to contact developer' => '点击与插件开发者取得联系',
'All' => '全部', 'Continue installation' => '继续安装',
'Uncategoried' => '未归类', 'My addons' => '我购买的插件',
'Recommend' => '推荐', 'Index' => '前台',
'Hot' => '热门', 'All' => '全部',
'New' => '新', 'Uncategoried' => '未归类',
'Paying' => '付费', 'Recommend' => '推荐',
'Free' => '免费', 'Hot' => '热门',
'Sale' => '折扣', 'New' => '新',
'No image' => '暂无缩略图', 'Paying' => '付费',
'Price' => '价格', 'Free' => '免费',
'Downloads' => '下载', 'Sale' => '折扣',
'Author' => '作者', 'No image' => '暂无缩略图',
'Identify' => '标识', 'Price' => '价格',
'Homepage' => '主页', 'Downloads' => '下载',
'Intro' => '介绍', 'Author' => '作者',
'Version' => '版本', 'Identify' => '标识',
'New version' => '新版本', 'Homepage' => '主页',
'Createtime' => '添加时间', 'Intro' => '介绍',
'Releasetime' => '更新时间', 'Version' => '版本',
'Detail' => '插件详情', 'New version' => '新版本',
'Document' => '文档', 'Createtime' => '添加时间',
'Demo' => '演示', 'Releasetime' => '更新时间',
'Feedback' => '反馈BUG', 'Detail' => '插件详情',
'Install' => '安装', 'Document' => '文档',
'Uninstall' => '卸载', 'Demo' => '演示',
'Upgrade' => '升级', 'Feedback' => '反馈BUG',
'Setting' => '配置', 'Install' => '安装',
'Disable' => '禁用', 'Uninstall' => '卸载',
'Enable' => '启用', 'Upgrade' => '升级',
'Your username or email' => '你的手机号、用户名或邮箱', 'Setting' => '配置',
'Your password' => '你的密码', 'Disable' => '禁用',
'Login FastAdmin' => '登录', 'Enable' => '启用',
'Login' => '登录', 'Your username or email' => '你的手机号、用户名或邮箱',
'Logout' => '退出登录', 'Your password' => '你的密码',
'Register' => '注册账号', 'Login' => '登录',
'You\'re not login' => '当前未登录', 'Logout' => '退出登录',
'Continue uninstall' => '继续卸载', 'Register' => '注册账号',
'Continue operate' => '继续操作', 'You\'re not login' => '当前未登录',
'Install successful' => '安装成功', 'Continue uninstall' => '继续卸载',
'Uninstall successful' => '卸载成功', 'Continue operate' => '继续操作',
'Operate successful' => '操作成功', 'Install successful' => '安装成功',
'Addon name incorrect' => '插件名称不正确', 'Uninstall successful' => '卸载成功',
'Addon info file was not found' => '插件配置文件未找到', 'Operate successful' => '操作成功',
'Addon info file data incorrect' => '插件配置信息不正确', 'Import successful' => '导入测试数据成功!清除浏览器缓存和框架缓存后生效!',
'Addon already exists' => '上传的插件已经存在', 'Initialize successful' => '初始化成功',
'Unable to open the zip file' => '无法打开ZIP文件', 'Initialize template not found' => '初始化模板未找到',
'Unable to extract the file' => '无法解压ZIP文件', 'Addon name incorrect' => '插件名称不正确',
'Addon info file was not found' => '插件配置文件未找到',
'Addon info file data incorrect' => '插件配置信息不正确',
'Addon already exists' => '插件已经存在',
'Addon not exists' => '插件不存在',
'Addon package download failed' => '插件下载失败',
'Conflicting file found' => '发现冲突文件',
'Invalid addon package' => '未验证的插件',
'No initialize method' => '未找到初始化方法',
'No permission to write temporary files' => '没有权限写入临时文件',
'The addon file does not exist' => '插件主启动程序不存在',
'The configuration file content is incorrect' => '配置文件不完整',
'Unable to open the zip file' => '无法打开ZIP文件',
'Unable to extract the file' => '无法解压ZIP文件',
'Unable to open file \'%s\' for writing' => '文件(%s)没有写入权限',
'Are you sure you want to unstall %s?' => '确认卸载<b>《%s》</b>?',
'Are you sure you want to refresh authorization?' => '确认刷新应用插件授权?',
'Delete all the addon file and cannot be recovered!' => '卸载将会删除所有插件文件且不可找回!!!',
'Delete all the addon database and cannot be recovered!' => '删除所有插件相关数据表且不可找回!!!',
'Please backup important data manually before uninstall!' => '如有重要数据请备份后再操作!!!',
'The following data tables will be deleted' => '以下插件数据表将会被删除',
'The Addon did not create a data table' => '插件未创建任何数据表',
]; ];

View File

@ -1,8 +1,3 @@
<?php <?php
return [ return [];
'No file upload or server upload limit exceeded' => '未上传文件或超出服务器上传限制',
'Uploaded file format is limited' => '上传文件格式受限制',
'Uploaded file is not a valid image' => '上传文件不是有效的图片文件',
'Upload successful' => '上传成功',
];

View File

@ -1,9 +1,14 @@
<?php <?php
return [ return [
'Group' => '所属组别', 'Email' => '电子邮箱',
'Loginfailure' => '登录失败次数', 'Mobile' => '手机号',
'Login time' => '最后登录', 'Group' => '所属组别',
'Please input correct username' => '用户名只能由3-12位数字、字母、下划线组合', 'Loginfailure' => '登录失败次数',
'Please input correct password' => '密码长度必须在6-16位之间不能包含空格', 'Login time' => '最后登录',
'The parent group exceeds permission limit' => '父组别超出权限范围',
'Please input correct username' => '用户名只能由3-30位数字、字母、下划线组合',
'Username must be 3 to 30 characters' => '用户名只能由3-30位数字、字母、下划线组合',
'Please input correct password' => '密码长度必须在6-30位之间不能包含空格',
'Password must be 6 to 30 characters' => '密码长度必须在6-30位之间不能包含空格',
]; ];

View File

@ -5,7 +5,7 @@ return [
'The parent group can not found' => '父组别未找到', 'The parent group can not found' => '父组别未找到',
'Group not found' => '组别未找到', 'Group not found' => '组别未找到',
'Can not change the parent to child' => '父组别不能是它的子组别', 'Can not change the parent to child' => '父组别不能是它的子组别',
'Can not change the parent to self' => '父组别不能是它的子组别', 'Can not change the parent to self' => '父组别不能是它自己',
'You can not delete group that contain child group and administrators' => '你不能删除含有子组和管理员的组', 'You can not delete group that contain child group and administrators' => '你不能删除含有子组和管理员的组',
'The parent group exceeds permission limit' => '父组别超出权限范围', 'The parent group exceeds permission limit' => '父组别超出权限范围',
'The parent group can not be its own child or itself' => '父组别不能是它的子组别及本身', 'The parent group can not be its own child or itself' => '父组别不能是它的子组别及本身',

View File

@ -9,12 +9,20 @@ return [
'Name' => '规则', 'Name' => '规则',
'Controller/Action' => '控制器名/方法名', 'Controller/Action' => '控制器名/方法名',
'Ismenu' => '菜单', 'Ismenu' => '菜单',
'Menutype' => '菜单类型',
'Addtabs' => '选项卡(默认)',
'Dialog' => '弹窗',
'Ajax' => 'Ajax请求',
'Blank' => '链接',
'Extend' => '扩展属性',
'Search icon' => '搜索图标', 'Search icon' => '搜索图标',
'Toggle menu visible' => '点击切换菜单显示', 'Toggle menu visible' => '点击切换菜单显示',
'Toggle sub menu' => '点击切换子菜单', 'Toggle sub menu' => '点击切换子菜单',
'Menu tips' => '父级菜单无需匹配控制器和方法,子级菜单请使用控制器名', 'Menu tips' => '父级菜单无需匹配控制器和方法,子级菜单请使用控制器名',
'Node tips' => '控制器/方法名,如果有目录请使用 目录名/控制器名/方法名', 'Node tips' => '控制器/方法名,如果有目录请使用 目录名/控制器名/方法名',
'Url tips' => '一般情况下留空即可,如果是外部链接或相对链接请输入',
'The non-menu rule must have parent' => '非菜单规则节点必须有父级', 'The non-menu rule must have parent' => '非菜单规则节点必须有父级',
'Can not change the parent to child' => '父组别不能是它的子组别', 'Can not change the parent to child' => '父级不能是它的子级',
'Can not change the parent to self' => '父级不能是它自己',
'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成', 'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成',
]; ];

View File

@ -1,47 +1,50 @@
<?php <?php
return [ return [
'Custom' => '自定义', 'Custom' => '自定义',
'Pid' => '父ID', 'Pid' => '父ID',
'Type' => '栏目类型', 'Type' => '栏目类型',
'Image' => '图片', 'Image' => '图片',
'Total user' => '总会员数', 'Total user' => '总会员数',
'Total view' => '总访问数', 'Total addon' => '总插件数',
'Total order' => '总订单数', 'Total category' => '总分类数',
'Total order amount' => '总金额', 'Total attachment' => '总附件数',
'Today user signup' => '今日注册', 'Total admin' => '总管理员数',
'Today user login' => '今日登录', 'Today user signup' => '今日注册',
'Today order' => '今日订单', 'Today user login' => '今日登录',
'Unsettle order' => '未处理订单', 'Today order' => '今日订单',
'Seven dnu' => '七日新增', 'Unsettle order' => '未处理订单',
'Seven dau' => '七日活跃', 'Three dnu' => '三日新增',
'Custom zone' => '这里是你的自定义数据', 'Seven dnu' => '七日新增',
'Sales' => '成交数', 'Seven dau' => '七日活跃',
'Orders' => '订单数', 'Thirty dau' => '月活跃',
'Real time' => '实时', 'Custom zone' => '这里是你的自定义数据',
'Category count' => '分类统计', 'Register user' => '注册用户数',
'Category count tips' => '当前分类总记录数', 'Real time' => '实时',
'Attachment count' => '附件统计', 'Category count' => '分类统计',
'Attachment count tips' => '当前上传的附件数量', 'Working addon count' => '运行中的插件',
'Article count' => '文章统计', 'Category count tips' => '当前分类总记录数',
'News count' => '新闻统计', 'Working addon count tips' => '当前运行中的插件数',
'Comment count' => '评论次数', 'Database count' => '数据库统计',
'Like count' => '点赞次数', 'Database table nums' => '数据表数量',
'Recent news' => '最新新闻', 'Database size' => '占用空间',
'Recent discussion' => '最新发贴', 'Attachment count' => '附件统计',
'Server info' => '服务器信息', 'Attachment nums' => '附件数量',
'PHP version' => 'PHP版本', 'Attachment size' => '附件大小',
'Fastadmin version' => '主框架版本', 'Attachment count tips' => '当前上传的附件数量',
'Fastadmin addon version' => '插件版本', 'Picture count' => '图片统计',
'Thinkphp version' => 'ThinkPHP版本', 'Picture nums' => '图片数量',
'Sapi name' => '运行方式', 'Picture size' => '图片大小',
'Debug mode' => '调试模式', 'Server info' => '服务器信息',
'Software' => '环境信息', 'PHP version' => 'PHP版本',
'Upload mode' => '上传模式', 'Sapi name' => '运行方式',
'Upload url' => '上传URL', 'Debug mode' => '调试模式',
'Upload cdn url' => '上传CDN', 'Software' => '环境信息',
'Cdn url' => '静态资源CDN', 'Upload mode' => '上传模式',
'Timezone' => '时区', 'Upload url' => '上传URL',
'Language' => '语言', 'Upload cdn url' => '上传CDN',
'View more' => '查看更多', 'Cdn url' => '静态资源CDN',
'Timezone' => '时区',
'Language' => '语言',
'View more' => '查看更多',
]; ];

View File

@ -1,22 +1,41 @@
<?php <?php
return [ return [
'Id' => 'ID', 'Id' => 'ID',
'Admin_id' => '管理员ID', 'Admin_id' => '管理员ID',
'User_id' => '会员ID', 'User_id' => '会员ID',
'Url' => '物理路径', 'Url' => '物理路径',
'Imagewidth' => '宽度', 'Imagewidth' => '宽度',
'Imageheight' => '高度', 'Imageheight' => '高度',
'Imagetype' => '图片类型', 'Imagetype' => '图片类型',
'Imageframes' => '图片帧数', 'Imageframes' => '图片帧数',
'Preview' => '预览', 'Preview' => '预览',
'Filesize' => '文件大小', 'Filename' => '文件名',
'Mimetype' => 'Mime类型', 'Filesize' => '文件大小',
'Extparam' => '透传数据', 'Mimetype' => 'Mime类型',
'Createtime' => '创建日期', 'Image' => '图片',
'Uploadtime' => '上传时间', 'Audio' => '音频',
'Storage' => '存储引擎', 'Video' => '视频',
'Upload to third' => '上传到第三方', 'Text' => '文档',
'Upload to local' => '上传到本地', 'Application' => '应用',
'Upload from editor' => '从编辑器上传' 'Zip' => '压缩包',
'Extparam' => '透传数据',
'Createtime' => '创建日期',
'Uploadtime' => '上传时间',
'Storage' => '存储引擎',
'Category1' => '分类一',
'Category2' => '分类二',
'Custom' => '自定义',
'Unclassed' => '未归类',
'Category' => '类别',
'Classify' => '归类',
'Filter Type' => '类型筛选',
'Upload to third' => '上传到第三方',
'Upload to local' => '上传到本地',
'Upload to third by chunk' => '上传到第三方(分片模式)',
'Upload to local by chunk' => '上传到本地(分片模式)',
'Please enter a new name' => '请输入新的类别名称',
'Please select category' => '请选择一个类别',
'Category not found' => '指定的类别未找到',
'Upload from editor' => '从编辑器上传'
]; ];

View File

@ -1,66 +1,83 @@
<?php <?php
return [ return [
'Name' => '变量名', 'Name' => '变量名',
'Tip' => '提示信息', 'Tip' => '提示信息',
'Group' => '分组', 'Group' => '分组',
'Type' => '类型', 'Type' => '类型',
'Title' => '变量标题', 'Title' => '变量标题',
'Value' => '变量值', 'Value' => '变量值',
'Basic' => '基础配置', 'Basic' => '基础配置',
'Email' => '邮件配置', 'Email' => '邮件配置',
'Attachment' => '附件配置', 'Attachment' => '附件配置',
'Dictionary' => '字典配置', 'Dictionary' => '字典配置',
'User' => '会员配置', 'User' => '会员配置',
'Example' => '示例分组', 'Example' => '示例分组',
'Extend' => '扩展属性', 'Extend' => '扩展属性',
'String' => '字符', 'String' => '字符',
'Text' => '文本', 'Password' => '密码',
'Editor' => '编辑器', 'Text' => '文本',
'Number' => '数字', 'Editor' => '编辑器',
'Date' => '日期', 'Number' => '数字',
'Time' => '时间', 'Date' => '日期',
'Datetime' => '日期时间', 'Time' => '时间',
'Image' => '图片', 'Datetime' => '日期时间',
'Images' => '图片(多)', 'Datetimerange' => '日期时间区间',
'File' => '文件', 'Image' => '图片',
'Files' => '文件(多)', 'Images' => '图片(多)',
'Select' => '列表', 'File' => '文件',
'Selects' => '列表(多选)', 'Files' => '文件(多)',
'Switch' => '开关', 'Select' => '列表',
'Checkbox' => '复选', 'Selects' => '列表(多选)',
'Radio' => '单选', 'Switch' => '开关',
'Array' => '数组', 'Checkbox' => '复选',
'Array key' => '键名', 'Radio' => '单选',
'Array value' => '键值', 'Array' => '数组',
'Custom' => '自定义', 'Array key' => '键名',
'Content' => '数据列表', 'Array value' => '键值',
'Rule' => '校验规则', 'City' => '城市地区',
'Site name' => '站点名称', 'Selectpage' => '关联表',
'Beian' => '备案号', 'Selectpages' => '关联表(多选)',
'Cdn url' => 'CDN地址', 'Custom' => '自定义',
'Version' => '版本号', 'Please select table' => '关联表',
'Timezone' => '时区', 'Selectpage table' => '关联表',
'Forbidden ip' => '禁止IP', 'Selectpage primarykey' => '存储字段',
'Languages' => '语言', 'Selectpage field' => '显示字段',
'Fixed page' => '后台固定页', 'Selectpage conditions' => '筛选条件',
'Category type' => '分类类型', 'Field title' => '字段名',
'Config group' => '配置分组', 'Field value' => '字段值',
'Rule tips' => '校验规则使用请参考Nice-validator文档', 'Content' => '数据列表',
'Extend tips' => '扩展属性支持{id}、{name}、{group}、{title}、{value}、{content}、{rule}替换', 'Rule' => '校验规则',
'Mail type' => '邮件发送方式', 'Visible condition' => '可见条件',
'Mail smtp host' => 'SMTP服务器', 'Site name' => '站点名称',
'Mail smtp port' => 'SMTP端口', 'Beian' => '备案号',
'Mail smtp user' => 'SMTP用户名', 'Cdn url' => 'CDN地址',
'Mail smtp password' => 'SMTP密码', 'Version' => '版本号',
'Mail vertify type' => 'SMTP验证方式', 'Timezone' => '时区',
'Mail from' => '发件人邮箱', 'Forbidden ip' => '禁止IP',
'Site name incorrect' => '网站名称错误', 'Languages' => '语言',
'Name already exist' => '变量名称已经存在', 'Fixed page' => '后台固定页',
'Add new config' => '点击添加新的配置', 'Category type' => '分类类型',
'Send a test message' => '发送测试邮件', 'Config group' => '配置分组',
'This is a test mail content' => '这是一封来自FastAdmin校验邮件,用于校验邮件配置是否正常!', 'Attachment category' => '附件类别',
'This is a test mail' => '这是一封来自FastAdmin的邮件', 'Category1' => '分类一',
'Please input your email' => '请输入测试接收者邮箱', 'Category2' => '分类二',
'Please input correct email' => '请输入正确的邮箱地址', 'Rule tips' => '校验规则使用请参考Nice-validator文档',
'Extend tips' => '扩展属性支持{id}、{name}、{group}、{title}、{value}、{content}、{rule}替换',
'Mail type' => '邮件发送方式',
'Mail smtp host' => 'SMTP服务器',
'Mail smtp port' => 'SMTP端口',
'Mail smtp user' => 'SMTP用户名',
'Mail smtp password' => 'SMTP密码',
'Mail vertify type' => 'SMTP验证方式',
'Mail from' => '发件人邮箱',
'Site name incorrect' => '网站名称错误',
'Name already exist' => '变量名称已经存在',
'Add new config' => '点击添加新的配置',
'Send a test message' => '发送测试邮件',
'Only work at development environment' => '只允许在开发环境开操作',
'This is a test mail content' => '这是一封来自%s的校验邮件,用于校验邮件配置是否正常!',
'This is a test mail' => '这是一封来自%s的邮件',
'Please input your email' => '请输入测试接收者邮箱',
'Please input correct email' => '请输入正确的邮箱地址',
]; ];

View File

@ -2,12 +2,13 @@
return [ return [
'Url' => '链接', 'Url' => '链接',
'Userame' => '用户名', 'Username' => '用户名',
'Createtime' => '操作时间', 'Createtime' => '操作时间',
'Click to edit' => '点击编辑', 'Click to edit' => '点击编辑',
'Admin log' => '操作日志', 'Admin log' => '操作日志',
'Leave password blank if dont want to change' => '不修改密码请留空', 'Leave password blank if dont want to change' => '不修改密码请留空',
'Please input correct email' => '请输入正确的Email地址', 'Please input correct email' => '请输入正确的Email地址',
'Please input correct password' => '密码长度不正确', 'Please input correct password' => '密码长度必须在6-30位之间不能包含空格',
'Password must be 6 to 30 characters' => '密码长度必须在6-30位之间不能包含空格',
'Email already exists' => '邮箱已经存在', 'Email already exists' => '邮箱已经存在',
]; ];

View File

@ -8,19 +8,25 @@ return [
'You can\'t use fixed and boxed layouts together' => '盒子模型和固定布局不能同时启作用', 'You can\'t use fixed and boxed layouts together' => '盒子模型和固定布局不能同时启作用',
'Boxed Layout' => '盒子布局', 'Boxed Layout' => '盒子布局',
'Activate the boxed layout' => '盒子布局最大宽度将被限定为1250px', 'Activate the boxed layout' => '盒子布局最大宽度将被限定为1250px',
'Toggle Sidebar' => '切换菜单栏', 'Toggle Sidebar' => '收起菜单栏',
'Toggle the left sidebar\'s state (open or collapse)' => '切换菜单栏的展或收起', 'Toggle the left sidebar\'s state (open or collapse)' => '切换菜单栏的展或收起',
'Sidebar Expand on Hover' => '菜单栏自动展开', 'Sidebar Expand on Hover' => '菜单栏自动展开',
'Let the sidebar mini expand on hover' => '鼠标移到菜单栏自动展开', 'Let the sidebar mini expand on hover' => '鼠标移到菜单栏自动展开',
'Toggle Right Sidebar Slide' => '切换右侧操作栏', 'Toggle Right Sidebar Slide' => '切换右侧操作栏',
'Toggle between slide over content and push content effects' => '切换右侧操作栏覆盖或独占', 'Toggle between slide over content and push content effects' => '切换右侧操作栏覆盖或独占',
'Toggle Right Sidebar Skin' => '切换右侧操作栏背景', 'Toggle Right Sidebar Skin' => '切换右侧操作栏背景',
'Toggle between dark and light skins for the right sidebar' => '将右侧操作栏背景亮色或深色切换', 'Toggle between dark and light skins for the right sidebar' => '将右侧操作栏背景亮色或深色切换',
'Multiple nav' => '多级菜单导航',
'Toggle the top menu state (multiple or single)' => '切换顶部菜单为多级菜单导航模式',
'Multiple tab' => '多选项卡',
'Always show multiple tab when multiple nav is set' => '当配置为多级菜单导航时是否启用多选项卡',
'Show sub menu' => '显示菜单栏子菜单', 'Show sub menu' => '显示菜单栏子菜单',
'Always show sub menu' => '菜单栏子菜单将始终显示', 'Always show sub menu' => '菜单栏子菜单将始终显示',
'Disable top menu badge' => '禁用顶部彩色小角标', 'Disable top menu badge' => '禁用顶部彩色小角标',
'Disable top menu badge without left menu' => '左边菜单栏的彩色小角标不受影响', 'Disable top menu badge without left menu' => '左边菜单栏的彩色小角标不受影响',
'Skins' => '皮肤', 'Skins' => '皮肤',
'Username must be 3 to 30 characters' => '用户名只能由3-30位数字、字母、下划线组合',
'Password must be 6 to 30 characters' => '密码长度必须在6-30位之间不能包含空格',
'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' => '用户名或密码不正确',
@ -33,11 +39,13 @@ return [
'Verification code is incorrect' => '验证码不正确', 'Verification code is incorrect' => '验证码不正确',
'Wipe cache completed' => '清除缓存成功', 'Wipe cache completed' => '清除缓存成功',
'Wipe cache failed' => '清除缓存失败', 'Wipe cache failed' => '清除缓存失败',
'Wipe cache' => '清缓存', 'Wipe cache' => '清缓存',
'Wipe all cache' => '一键清除缓存', 'Wipe all cache' => '一键清除缓存',
'Wipe content cache' => '清内容缓存', 'Wipe content cache' => '清内容缓存',
'Wipe template cache' => '清除模板缓存', 'Wipe template cache' => '清除模板缓存',
'Wipe addons cache' => '清除插件缓存', 'Wipe addons cache' => '清除插件缓存',
'Wipe browser cache' => '清除浏览器缓存',
'Wipe browser cache tips' => '清除浏览器端静态JS、CSS、图片等资源',
'Check for updates' => '检测更新', 'Check for updates' => '检测更新',
'Discover new version' => '发现新版本', 'Discover new version' => '发现新版本',
'Go to download' => '去下载更新', 'Go to download' => '去下载更新',
@ -54,4 +62,6 @@ return [
'Forum' => '交流社区', 'Forum' => '交流社区',
'QQ qun' => 'QQ交流群', 'QQ qun' => 'QQ交流群',
'Captcha' => '验证码', 'Captcha' => '验证码',
'The duration of the session is %s hours' => '设定会话有效时长为%s小时',
'Security tips' => '<i class="fa fa-warning"></i> 安全提示为了你的后台安全请勿将后台管理入口设置为admin或admin.php',
]; ];

View File

@ -1,9 +1,10 @@
<?php <?php
return [ return [
'Name' => '组名', 'Name' => '组名',
'Rules' => '权限节点', 'Rules' => '权限节点',
'Createtime' => '添加时间', 'Change password' => '修改密码',
'Updatetime' => '更新时间', 'Createtime' => '添加时间',
'Status' => '状态' 'Updatetime' => '更新时间',
'Status' => '状态'
]; ];

View File

@ -1,15 +1,19 @@
<?php <?php
return [ return [
'Pid' => '父ID', 'Pid' => '父ID',
'Name' => '规则', 'Name' => '规则',
'Title' => '标题', 'Title' => '标题',
'Remark' => '备注', 'Remark' => '备注',
'Ismenu' => '是否菜单', 'Ismenu' => '是否菜单',
'Createtime' => '创建时间', 'Change password' => '修改密码',
'Updatetime' => '更新时间', 'Createtime' => '创建时间',
'Menu tips' => '规则任意,请不可重复,仅做层级显示,无需匹配控制器和方法', 'Updatetime' => '更新时间',
'Node tips' => '模块/控制器/方法名', 'Menu tips' => '规则任意,请不可重复,仅做层级显示,无需匹配控制器和方法',
'Weigh' => '权重', 'Node tips' => '模块/控制器/方法名',
'Status' => '状态' 'Weigh' => '权重',
'Status' => '状态',
'Toggle all' => '显示全部',
'Toggle menu visible' => '点击切换菜单显示',
'Toggle sub menu' => '点击切换子菜单',
]; ];

View File

@ -51,7 +51,7 @@ class Auth extends \fast\Auth
$this->setError('Please try again after 1 day'); $this->setError('Please try again after 1 day');
return false; return false;
} }
if ($admin->password != md5(md5($password) . $admin->salt)) { if ($admin->password != $this->getEncryptPassword($password, $admin->salt)) {
$admin->loginfailure++; $admin->loginfailure++;
$admin->save(); $admin->save();
$this->setError('Password is incorrect'); $this->setError('Password is incorrect');
@ -63,12 +63,13 @@ class Auth extends \fast\Auth
$admin->token = Random::uuid(); $admin->token = Random::uuid();
$admin->save(); $admin->save();
Session::set("admin", $admin->toArray()); Session::set("admin", $admin->toArray());
$this->keeplogin($keeptime); Session::set("admin.safecode", $this->getEncryptSafecode($admin));
$this->keeplogin($admin, $keeptime);
return true; return true;
} }
/** /**
* 注销登录 * 退出登录
*/ */
public function logout() public function logout()
{ {
@ -80,6 +81,7 @@ class Auth extends \fast\Auth
$this->logined = false; //重置登录状态 $this->logined = false; //重置登录状态
Session::delete("admin"); Session::delete("admin");
Cookie::delete("keeplogin"); Cookie::delete("keeplogin");
setcookie('fastadmin_userinfo', '', $_SERVER['REQUEST_TIME'] - 3600, rtrim(url("/" . request()->module(), '', false), '/'));
return true; return true;
} }
@ -100,7 +102,7 @@ class Auth extends \fast\Auth
return false; return false;
} }
//token有变更 //token有变更
if ($key != md5(md5($id) . md5($keeptime) . md5($expiretime) . $admin->token)) { if ($key != $this->getKeeploginKey($admin, $keeptime, $expiretime)) {
return false; return false;
} }
$ip = request()->ip(); $ip = request()->ip();
@ -109,8 +111,9 @@ class Auth extends \fast\Auth
return false; return false;
} }
Session::set("admin", $admin->toArray()); Session::set("admin", $admin->toArray());
Session::set("admin.safecode", $this->getEncryptSafecode($admin));
//刷新自动登录的时效 //刷新自动登录的时效
$this->keeplogin($keeptime); $this->keeplogin($admin, $keeptime);
return true; return true;
} else { } else {
return false; return false;
@ -123,18 +126,64 @@ class Auth extends \fast\Auth
* @param int $keeptime * @param int $keeptime
* @return boolean * @return boolean
*/ */
protected function keeplogin($keeptime = 0) protected function keeplogin($admin, $keeptime = 0)
{ {
if ($keeptime) { if ($keeptime) {
$expiretime = time() + $keeptime; $expiretime = time() + $keeptime;
$key = md5(md5($this->id) . md5($keeptime) . md5($expiretime) . $this->token); $key = $this->getKeeploginKey($admin, $keeptime, $expiretime);
$data = [$this->id, $keeptime, $expiretime, $key]; Cookie::set('keeplogin', implode('|', [$admin['id'], $keeptime, $expiretime, $key]), $keeptime);
Cookie::set('keeplogin', implode('|', $data), 86400 * 30);
return true; return true;
} }
return false; return false;
} }
/**
* 获取密码加密后的字符串
* @param string $password 密码
* @param string $salt 密码盐
* @return string
*/
public function getEncryptPassword($password, $salt = '')
{
return md5(md5($password) . $salt);
}
/**
* 获取密码加密后的自动登录码
* @param string $password 密码
* @param string $salt 密码盐
* @return string
*/
public function getEncryptKeeplogin($params, $keeptime)
{
$expiretime = time() + $keeptime;
$key = md5(md5($params['id']) . md5($keeptime) . md5($expiretime) . $params['token'] . config('token.key'));
return implode('|', [$this->id, $keeptime, $expiretime, $key]);
}
/**
* 获取自动登录Key
* @param $params
* @param $keeptime
* @param $expiretime
* @return string
*/
public function getKeeploginKey($params, $keeptime, $expiretime)
{
$key = md5(md5($params['id']) . md5($keeptime) . md5($expiretime) . $params['token'] . config('token.key'));
return $key;
}
/**
* 获取加密后的安全码
* @param $params
* @return string
*/
public function getEncryptSafecode($params)
{
return md5(md5($params['username']) . md5(substr($params['password'], 0, 6)) . config('token.key'));
}
public function check($name, $uid = '', $relation = 'or', $mode = 'url') public function check($name, $uid = '', $relation = 'or', $mode = 'url')
{ {
$uid = $uid ? $uid : $this->id; $uid = $uid ? $uid : $this->id;
@ -179,10 +228,18 @@ class Auth extends \fast\Auth
if (!$admin) { if (!$admin) {
return false; return false;
} }
$my = Admin::get($admin['id']);
if (!$my) {
return false;
}
//校验安全码,可用于判断关键信息发生了变更需要重新登录
if (!isset($admin['safecode']) || $this->getEncryptSafecode($my) !== $admin['safecode']) {
$this->logout();
return false;
}
//判断是否同一时间同一账号只能在一个地方登录 //判断是否同一时间同一账号只能在一个地方登录
if (Config::get('fastadmin.login_unique')) { if (Config::get('fastadmin.login_unique')) {
$my = Admin::get($admin['id']); if ($my['token'] != $admin['token']) {
if (!$my || $my['token'] != $admin['token']) {
$this->logout(); $this->logout();
return false; return false;
} }
@ -282,7 +339,7 @@ class Auth extends \fast\Auth
} }
} }
// 取出所有分组 // 取出所有分组
$groupList = \app\admin\model\AuthGroup::where(['status' => 'normal'])->select(); $groupList = \app\admin\model\AuthGroup::where($this->isSuperAdmin() ? '1=1' : ['status' => 'normal'])->select();
$objList = []; $objList = [];
foreach ($groups as $k => $v) { foreach ($groups as $k => $v) {
if ($v['rules'] === '*') { if ($v['rules'] === '*') {
@ -290,8 +347,8 @@ class Auth extends \fast\Auth
break; break;
} }
// 取出包含自己的所有子节点 // 取出包含自己的所有子节点
$childrenList = Tree::instance()->init($groupList)->getChildren($v['id'], true); $childrenList = Tree::instance()->init($groupList, 'pid')->getChildren($v['id'], true);
$obj = Tree::instance()->init($childrenList)->getTreeArray($v['pid']); $obj = Tree::instance()->init($childrenList, 'pid')->getTreeArray($v['pid']);
$objList = array_merge($objList, Tree::instance()->getTreeList($obj)); $objList = array_merge($objList, Tree::instance()->getTreeList($obj));
} }
$childrenGroupIds = []; $childrenGroupIds = [];
@ -314,8 +371,7 @@ 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:: $authGroupList = \app\admin\model\AuthGroupAccess::field('uid,group_id')
field('uid,group_id')
->where('group_id', 'in', $groupIds) ->where('group_id', 'in', $groupIds)
->select(); ->select();
foreach ($authGroupList as $k => $v) { foreach ($authGroupList as $k => $v) {
@ -361,7 +417,6 @@ class Auth extends \fast\Auth
$titleArr[$pathArr[$rule['name']]] = $rule['title']; $titleArr[$pathArr[$rule['name']]] = $rule['title'];
$menuArr[$pathArr[$rule['name']]] = $rule; $menuArr[$pathArr[$rule['name']]] = $rule;
} }
} }
ksort($menuArr); ksort($menuArr);
$this->breadcrumb = $menuArr; $this->breadcrumb = $menuArr;
@ -387,9 +442,9 @@ class Auth extends \fast\Auth
foreach ($params as $k => $v) { foreach ($params as $k => $v) {
$url = $k; $url = $k;
if (is_array($v)) { if (is_array($v)) {
$nums = isset($v[0]) ? $v[0] : 0; $nums = $v[0] ?? 0;
$color = isset($v[1]) ? $v[1] : $colorArr[(is_numeric($nums) ? $nums : strlen($nums)) % $colorNums]; $color = $v[1] ?? $colorArr[(is_numeric($nums) ? $nums : strlen($nums)) % $colorNums];
$class = isset($v[2]) ? $v[2] : 'label'; $class = $v[2] ?? 'label';
} else { } else {
$nums = $v; $nums = $v;
$color = $colorArr[(is_numeric($nums) ? $nums : strlen($nums)) % $colorNums]; $color = $colorArr[(is_numeric($nums) ? $nums : strlen($nums)) % $colorNums];
@ -405,7 +460,6 @@ class Auth extends \fast\Auth
$userRule = $this->getRuleList(); $userRule = $this->getRuleList();
$selected = $referer = []; $selected = $referer = [];
$refererUrl = Session::get('referer'); $refererUrl = Session::get('referer');
$pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader');
// 必须将结果集转换为数组 // 必须将结果集转换为数组
$ruleList = collection(\app\admin\model\AuthRule::where('status', 'normal') $ruleList = collection(\app\admin\model\AuthRule::where('status', 'normal')
->where('ismenu', 1) ->where('ismenu', 1)
@ -416,11 +470,9 @@ class Auth extends \fast\Auth
->where('ismenu', 0) ->where('ismenu', 0)
->where('name', 'like', '%/index') ->where('name', 'like', '%/index')
->column('name,pid'); ->column('name,pid');
$pidArr = array_filter(array_unique(array_map(function ($item) { $pidArr = array_unique(array_filter(array_column($ruleList, 'pid')));
return $item['pid'];
}, $ruleList)));
foreach ($ruleList as $k => &$v) { foreach ($ruleList as $k => &$v) {
if (!in_array($v['name'], $userRule)) { if (!in_array(strtolower($v['name']), $userRule)) {
unset($ruleList[$k]); unset($ruleList[$k]);
continue; continue;
} }
@ -430,30 +482,29 @@ class Auth extends \fast\Auth
continue; continue;
} }
$v['icon'] = $v['icon'] . ' fa-fw'; $v['icon'] = $v['icon'] . ' fa-fw';
$v['url'] = '/' . $module . '/' . $v['name']; $v['url'] = isset($v['url']) && $v['url'] ? $v['url'] : '/' . $module . '/' . $v['name'];
$v['badge'] = isset($badgeList[$v['name']]) ? $badgeList[$v['name']] : ''; $v['badge'] = $badgeList[$v['name']] ?? '';
$v['py'] = $pinyin->abbr($v['title'], '');
$v['pinyin'] = $pinyin->permalink($v['title'], '');
$v['title'] = __($v['title']); $v['title'] = __($v['title']);
$v['url'] = preg_match("/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i", $v['url']) ? $v['url'] : url($v['url']);
$v['menuclass'] = in_array($v['menutype'], ['dialog', 'ajax']) ? 'btn-' . $v['menutype'] : '';
$v['menutabs'] = !$v['menutype'] || in_array($v['menutype'], ['default', 'addtabs']) ? 'addtabs="' . $v['id'] . '"' : '';
$selected = $v['name'] == $fixedPage ? $v : $selected; $selected = $v['name'] == $fixedPage ? $v : $selected;
$referer = url($v['url']) == $refererUrl ? $v : $referer; $referer = $v['url'] == $refererUrl ? $v : $referer;
} }
$lastArr = array_diff($pidArr, array_filter(array_unique(array_map(function ($item) { $lastArr = array_unique(array_filter(array_column($ruleList, 'pid')));
return $item['pid']; $pidDiffArr = array_diff($pidArr, $lastArr);
}, $ruleList))));
foreach ($ruleList as $index => $item) { foreach ($ruleList as $index => $item) {
if (in_array($item['id'], $lastArr)) { if (in_array($item['id'], $pidDiffArr)) {
unset($ruleList[$index]); unset($ruleList[$index]);
} }
} }
if ($selected == $referer) { if ($selected == $referer) {
$referer = []; $referer = [];
} }
$selected && $selected['url'] = url($selected['url']);
$referer && $referer['url'] = url($referer['url']);
$select_id = $selected ? $selected['id'] : 0; $select_id = $referer ? $referer['id'] : ($selected ? $selected['id'] : 0);
$menu = $nav = ''; $menu = $nav = '';
$showSubmenu = config('fastadmin.show_submenu');
if (Config::get('fastadmin.multiplenav')) { if (Config::get('fastadmin.multiplenav')) {
$topList = []; $topList = [];
foreach ($ruleList as $index => $item) { foreach ($ruleList as $index => $item) {
@ -470,21 +521,21 @@ class Auth extends \fast\Auth
foreach ($topList as $index => $item) { foreach ($topList as $index => $item) {
$childList = Tree::instance()->getTreeMenu( $childList = Tree::instance()->getTreeMenu(
$item['id'], $item['id'],
'<li class="@class" pid="@pid"><a href="@url@addtabs" addtabs="@id" url="@url" py="@py" pinyin="@pinyin"><i class="@icon"></i> <span>@title</span> <span class="pull-right-container">@caret @badge</span></a> @childlist</li>', '<li class="@class" pid="@pid"><a @extend href="@url@addtabs" addtabs="@id" class="@menuclass" url="@url" py="@py" pinyin="@pinyin"><i class="@icon"></i> <span>@title</span> <span class="pull-right-container">@caret @badge</span></a> @childlist</li>',
$select_id, $select_id,
'', '',
'ul', 'ul',
'class="treeview-menu"' 'class="treeview-menu' . ($showSubmenu ? ' menu-open' : '') . '"'
); );
$current = in_array($item['id'], $selectParentIds); $current = in_array($item['id'], $selectParentIds);
$url = $childList ? 'javascript:;' : url($item['url']); $url = $childList ? 'javascript:;' : $item['url'];
$addtabs = $childList || !$url ? "" : (stripos($url, "?") !== false ? "&" : "?") . "ref=addtabs"; $addtabs = $childList || !$url ? "" : (stripos($url, "?") !== false ? "&" : "?") . "ref=" . ($item['menutype'] ? $item['menutype'] : 'addtabs');
$childList = str_replace( $childList = str_replace(
'" pid="' . $item['id'] . '"', '" pid="' . $item['id'] . '"',
' treeview ' . ($current ? '' : 'hidden') . '" pid="' . $item['id'] . '"', ' ' . ($current ? '' : 'hidden') . '" pid="' . $item['id'] . '"',
$childList $childList
); );
$nav .= '<li class="' . ($current ? 'active' : '') . '"><a href="' . $url . $addtabs . '" addtabs="' . $item['id'] . '" url="' . $url . '"><i class="' . $item['icon'] . '"></i> <span>' . $item['title'] . '</span> <span class="pull-right-container"> </span></a> </li>'; $nav .= '<li class="' . ($current ? 'active' : '') . '"><a ' . $item['extend'] . ' href="' . $url . $addtabs . '" ' . $item['menutabs'] . ' class="' . $item['menuclass'] . '" url="' . $url . '" title="' . $item['title'] . '"><i class="' . $item['icon'] . '"></i> <span>' . $item['title'] . '</span> <span class="pull-right-container"> </span></a> </li>';
$menu .= $childList; $menu .= $childList;
} }
} else { } else {
@ -492,11 +543,11 @@ class Auth extends \fast\Auth
Tree::instance()->init($ruleList); Tree::instance()->init($ruleList);
$menu = Tree::instance()->getTreeMenu( $menu = Tree::instance()->getTreeMenu(
0, 0,
'<li class="@class"><a href="@url@addtabs" addtabs="@id" url="@url" py="@py" pinyin="@pinyin"><i class="@icon"></i> <span>@title</span> <span class="pull-right-container">@caret @badge</span></a> @childlist</li>', '<li class="@class"><a @extend href="@url@addtabs" @menutabs class="@menuclass" url="@url" py="@py" pinyin="@pinyin"><i class="@icon"></i> <span>@title</span> <span class="pull-right-container">@caret @badge</span></a> @childlist</li>',
$select_id, $select_id,
'', '',
'ul', 'ul',
'class="treeview-menu"' 'class="treeview-menu' . ($showSubmenu ? ' menu-open' : '') . '"'
); );
if ($selected) { if ($selected) {
$nav .= '<li role="presentation" id="tab_' . $selected['id'] . '" class="' . ($referer ? '' : 'active') . '"><a href="#con_' . $selected['id'] . '" node-id="' . $selected['id'] . '" aria-controls="' . $selected['id'] . '" role="tab" data-toggle="tab"><i class="' . $selected['icon'] . ' fa-fw"></i> <span>' . $selected['title'] . '</span> </a></li>'; $nav .= '<li role="presentation" id="tab_' . $selected['id'] . '" class="' . ($referer ? '' : 'active') . '"><a href="#con_' . $selected['id'] . '" node-id="' . $selected['id'] . '" aria-controls="' . $selected['id'] . '" role="tab" data-toggle="tab"><i class="' . $selected['icon'] . ' fa-fw"></i> <span>' . $selected['title'] . '</span> </a></li>';

View File

@ -9,12 +9,16 @@ use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xls; use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Reader\Csv;
use think\Db; use think\Db;
use think\db\exception\BindParamException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
use think\exception\PDOException; use think\exception\PDOException;
use think\exception\ValidateException; use think\exception\ValidateException;
use think\response\Json;
trait Backend trait Backend
{ {
/** /**
* 排除前台提交过来的字段 * 排除前台提交过来的字段
* @param $params * @param $params
@ -24,127 +28,114 @@ trait Backend
{ {
if (is_array($this->excludeFields)) { if (is_array($this->excludeFields)) {
foreach ($this->excludeFields as $field) { foreach ($this->excludeFields as $field) {
if (key_exists($field, $params)) { if (array_key_exists($field, $params)) {
unset($params[$field]); unset($params[$field]);
} }
} }
} else { } else if (array_key_exists($this->excludeFields, $params)) {
if (key_exists($this->excludeFields, $params)) { unset($params[$this->excludeFields]);
unset($params[$this->excludeFields]);
}
} }
return $params; return $params;
} }
/** /**
* 查看 * 查看
*
* @return string|Json
* @throws \think\Exception
* @throws DbException
*/ */
public function index() public function index()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if (false === $this->request->isAjax()) {
//如果发送的来源是Selectpage则转发到Selectpage return $this->view->fetch();
if ($this->request->request('keyField')) {
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list);
return json($result);
} }
return $this->view->fetch(); //如果发送的来源是 Selectpage则转发到 Selectpage
if ($this->request->request('keyField')) {
return $this->selectpage();
}
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
$list = $this->model
->where($where)
->order($sort, $order)
->paginate($limit);
$result = ['total' => $list->total(), 'rows' => $list->items()];
return json($result);
} }
/** /**
* 回收站 * 回收站
*
* @return string|Json
* @throws \think\Exception
*/ */
public function recyclebin() public function recyclebin()
{ {
//设置过滤方法 //设置过滤方法
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if (false === $this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); return $this->view->fetch();
$total = $this->model
->onlyTrashed()
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->onlyTrashed()
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
$result = array("total" => $total, "rows" => $list);
return json($result);
} }
return $this->view->fetch(); [$where, $sort, $order, $offset, $limit] = $this->buildparams();
$list = $this->model
->onlyTrashed()
->where($where)
->order($sort, $order)
->paginate($limit);
$result = ['total' => $list->total(), 'rows' => $list->items()];
return json($result);
} }
/** /**
* 添加 * 添加
*
* @return string
* @throws \think\Exception
*/ */
public function add() public function add()
{ {
if ($this->request->isPost()) { if (false === $this->request->isPost()) {
$params = $this->request->post("row/a"); return $this->view->fetch();
if ($params) { }
$params = $this->preExcludeFields($params); $params = $this->request->post('row/a');
if (empty($params)) {
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
$this->model->validateFailException(true)->validate($validate);
}
$result = $this->model->allowField(true)->save($params);
Db::commit();
} catch (ValidateException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result !== false) {
$this->success();
} else {
$this->error(__('No rows were inserted'));
}
}
$this->error(__('Parameter %s can not be empty', '')); $this->error(__('Parameter %s can not be empty', ''));
} }
return $this->view->fetch(); $params = $this->preExcludeFields($params);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
$this->model->validateFailException()->validate($validate);
}
$result = $this->model->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success();
} }
/** /**
* 编辑 * 编辑
*
* @param $ids
* @return string
* @throws DbException
* @throws \think\Exception
*/ */
public function edit($ids = null) public function edit($ids = null)
{ {
@ -153,125 +144,93 @@ trait Backend
$this->error(__('No Results were found')); $this->error(__('No Results were found'));
} }
$adminIds = $this->getDataLimitAdminIds(); $adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) { if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
if (!in_array($row[$this->dataLimitField], $adminIds)) { $this->error(__('You have no permission'));
$this->error(__('You have no permission'));
}
} }
if ($this->request->isPost()) { if (false === $this->request->isPost()) {
$params = $this->request->post("row/a"); $this->view->assign('row', $row);
if ($params) { return $this->view->fetch();
$params = $this->preExcludeFields($params); }
$result = false; $params = $this->request->post('row/a');
Db::startTrans(); if (empty($params)) {
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
$row->validateFailException(true)->validate($validate);
}
$result = $row->allowField(true)->save($params);
Db::commit();
} catch (ValidateException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result !== false) {
$this->success();
} else {
$this->error(__('No rows were updated'));
}
}
$this->error(__('Parameter %s can not be empty', '')); $this->error(__('Parameter %s can not be empty', ''));
} }
$this->view->assign("row", $row); $params = $this->preExcludeFields($params);
return $this->view->fetch(); $result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
$row->validateFailException()->validate($validate);
}
$result = $row->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if (false === $result) {
$this->error(__('No rows were updated'));
}
$this->success();
} }
/** /**
* 删除 * 删除
*
* @param $ids
* @return void
* @throws DbException
* @throws DataNotFoundException
* @throws ModelNotFoundException
*/ */
public function del($ids = "") public function del($ids = null)
{ {
if ($ids) { if (false === $this->request->isPost()) {
$pk = $this->model->getPk(); $this->error(__("Invalid parameters"));
$adminIds = $this->getDataLimitAdminIds(); }
if (is_array($adminIds)) { $ids = $ids ?: $this->request->post("ids");
$this->model->where($this->dataLimitField, 'in', $adminIds); if (empty($ids)) {
} $this->error(__('Parameter %s can not be empty', 'ids'));
$list = $this->model->where($pk, 'in', $ids)->select();
$count = 0;
Db::startTrans();
try {
foreach ($list as $k => $v) {
$count += $v->delete();
}
Db::commit();
} catch (PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count) {
$this->success();
} else {
$this->error(__('No rows were deleted'));
}
} }
$this->error(__('Parameter %s can not be empty', 'ids'));
}
/**
* 真实删除
*/
public function destroy($ids = "")
{
$pk = $this->model->getPk(); $pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds(); $adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) { if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds); $this->model->where($this->dataLimitField, 'in', $adminIds);
} }
if ($ids) { $list = $this->model->where($pk, 'in', $ids)->select();
$this->model->where($pk, 'in', $ids);
}
$count = 0; $count = 0;
Db::startTrans(); Db::startTrans();
try { try {
$list = $this->model->onlyTrashed()->select(); foreach ($list as $item) {
foreach ($list as $k => $v) { $count += $item->delete();
$count += $v->delete(true);
} }
Db::commit(); Db::commit();
} catch (PDOException $e) { } catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback(); Db::rollback();
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
if ($count) { if ($count) {
$this->success(); $this->success();
} else {
$this->error(__('No rows were deleted'));
} }
$this->error(__('Parameter %s can not be empty', 'ids')); $this->error(__('No rows were deleted'));
} }
/** /**
* 还原 * 真实删除
*
* @param $ids
* @return void
*/ */
public function restore($ids = "") public function destroy($ids = null)
{ {
if (false === $this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ?: $this->request->post('ids');
$pk = $this->model->getPk(); $pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds(); $adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) { if (is_array($adminIds)) {
@ -284,14 +243,49 @@ trait Backend
Db::startTrans(); Db::startTrans();
try { try {
$list = $this->model->onlyTrashed()->select(); $list = $this->model->onlyTrashed()->select();
foreach ($list as $index => $item) { foreach ($list as $item) {
$count += $item->delete(true);
}
Db::commit();
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count) {
$this->success();
}
$this->error(__('No rows were deleted'));
}
/**
* 还原
*
* @param $ids
* @return void
*/
public function restore($ids = null)
{
if (false === $this->request->isPost()) {
$this->error(__('Invalid parameters'));
}
$ids = $ids ?: $this->request->post('ids');
$pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
if ($ids) {
$this->model->where($pk, 'in', $ids);
}
$count = 0;
Db::startTrans();
try {
$list = $this->model->onlyTrashed()->select();
foreach ($list as $item) {
$count += $item->restore(); $count += $item->restore();
} }
Db::commit(); Db::commit();
} catch (PDOException $e) { } catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback(); Db::rollback();
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
@ -303,49 +297,56 @@ trait Backend
/** /**
* 批量更新 * 批量更新
*
* @param $ids
* @return void
*/ */
public function multi($ids = "") public function multi($ids = null)
{ {
$ids = $ids ? $ids : $this->request->param("ids"); if (false === $this->request->isPost()) {
if ($ids) { $this->error(__('Invalid parameters'));
if ($this->request->has('params')) {
parse_str($this->request->post("params"), $values);
$values = $this->auth->isSuperAdmin() ? $values : array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
if ($values) {
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$count = 0;
Db::startTrans();
try {
$list = $this->model->where($this->model->getPk(), 'in', $ids)->select();
foreach ($list as $index => $item) {
$count += $item->allowField(true)->isUpdate(true)->save($values);
}
Db::commit();
} catch (PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count) {
$this->success();
} else {
$this->error(__('No rows were updated'));
}
} else {
$this->error(__('You have no permission'));
}
}
} }
$this->error(__('Parameter %s can not be empty', 'ids')); $ids = $ids ?: $this->request->post('ids');
if (empty($ids)) {
$this->error(__('Parameter %s can not be empty', 'ids'));
}
if (false === $this->request->has('params')) {
$this->error(__('No rows were updated'));
}
parse_str($this->request->post('params'), $values);
$values = $this->auth->isSuperAdmin() ? $values : array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
if (empty($values)) {
$this->error(__('You have no permission'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$count = 0;
Db::startTrans();
try {
$list = $this->model->where($this->model->getPk(), 'in', $ids)->select();
foreach ($list as $item) {
$count += $item->allowField(true)->isUpdate(true)->save($values);
}
Db::commit();
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count) {
$this->success();
}
$this->error(__('No rows were updated'));
} }
/** /**
* 导入 * 导入
*
* @return void
* @throws PDOException
* @throws BindParamException
*/ */
protected function import() protected function import()
{ {
@ -365,12 +366,12 @@ trait Backend
if ($ext === 'csv') { if ($ext === 'csv') {
$file = fopen($filePath, 'r'); $file = fopen($filePath, 'r');
$filePath = tempnam(sys_get_temp_dir(), 'import_csv'); $filePath = tempnam(sys_get_temp_dir(), 'import_csv');
$fp = fopen($filePath, "w"); $fp = fopen($filePath, 'w');
$n = 0; $n = 0;
while ($line = fgets($file)) { while ($line = fgets($file)) {
$line = rtrim($line, "\n\r\0"); $line = rtrim($line, "\n\r\0");
$encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']); $encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']);
if ($encoding != 'utf-8') { if ($encoding !== 'utf-8') {
$line = mb_convert_encoding($line, 'utf-8', $encoding); $line = mb_convert_encoding($line, 'utf-8', $encoding);
} }
if ($n == 0 || preg_match('/^".*"$/', $line)) { if ($n == 0 || preg_match('/^".*"$/', $line)) {
@ -398,6 +399,7 @@ trait Backend
$list = db()->query("SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?", [$table, $database]); $list = db()->query("SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?", [$table, $database]);
foreach ($list as $k => $v) { foreach ($list as $k => $v) {
if ($importHeadType == 'comment') { if ($importHeadType == 'comment') {
$v['COLUMN_COMMENT'] = explode(':', $v['COLUMN_COMMENT'])[0]; //字段备注有:时截取
$fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME']; $fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME'];
} else { } else {
$fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME']; $fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME'];
@ -458,7 +460,7 @@ trait Backend
if ($has_admin_id) { if ($has_admin_id) {
$auth = Auth::instance(); $auth = Auth::instance();
foreach ($insert as &$val) { foreach ($insert as &$val) {
if (!isset($val['admin_id']) || empty($val['admin_id'])) { if (empty($val['admin_id'])) {
$val['admin_id'] = $auth->isLogin() ? $auth->id : 0; $val['admin_id'] = $auth->isLogin() ? $auth->id : 0;
} }
} }

View File

@ -13,22 +13,20 @@ class Admin extends Model
// 定义时间戳字段名 // 定义时间戳字段名
protected $createTime = 'createtime'; protected $createTime = 'createtime';
protected $updateTime = 'updatetime'; protected $updateTime = 'updatetime';
protected $hidden = [
'password',
'salt'
];
/** public static function init()
* 重置用户密码
* @author baiyouwen
*/
public function resetPassword($uid, $NewPassword)
{ {
$passwd = $this->encryptPassword($NewPassword); self::beforeWrite(function ($row) {
$ret = $this->where(['id' => $uid])->update(['password' => $passwd]); $changed = $row->getChangedData();
return $ret; //如果修改了用户或或密码则需要重新登录
} if (isset($changed['username']) || isset($changed['password']) || isset($changed['salt'])) {
$row->token = '';
// 密码加密 }
protected function encryptPassword($password, $salt = '', $encrypt = 'md5') });
{
return $encrypt($password . $salt);
} }
} }

View File

@ -4,6 +4,7 @@ namespace app\admin\model;
use app\admin\library\Auth; use app\admin\library\Auth;
use think\Model; use think\Model;
use think\Loader;
class AdminLog extends Model class AdminLog extends Model
{ {
@ -17,6 +18,10 @@ class AdminLog extends Model
protected static $title = ''; protected static $title = '';
//自定义日志内容 //自定义日志内容
protected static $content = ''; protected static $content = '';
//忽略的链接正则列表
protected static $ignoreRegex = [
'/^(.*)\/(selectpage|index)$/i',
];
public static function setTitle($title) public static function setTitle($title)
{ {
@ -28,40 +33,83 @@ class AdminLog extends Model
self::$content = $content; self::$content = $content;
} }
public static function record($title = '') public static function setIgnoreRegex($regex = [])
{
$regex = is_array($regex) ? $regex : [$regex];
self::$ignoreRegex = array_merge(self::$ignoreRegex, $regex);
}
/**
* 记录日志
* @param string $title 日志标题
* @param string $content 日志内容
*/
public static function record($title = '', $content = '')
{ {
$auth = Auth::instance(); $auth = Auth::instance();
$admin_id = $auth->isLogin() ? $auth->id : 0; $admin_id = $auth->isLogin() ? $auth->id : 0;
$username = $auth->isLogin() ? $auth->username : __('Unknown'); $username = $auth->isLogin() ? $auth->username : __('Unknown');
$content = self::$content;
if (!$content) { // 设置过滤函数
$content = request()->param('', null, 'trim,strip_tags,htmlspecialchars'); request()->filter('trim,strip_tags,htmlspecialchars');
foreach ($content as $k => $v) {
if (is_string($v) && strlen($v) > 200 || stripos($k, 'password') !== false) { $controllername = Loader::parseName(request()->controller());
unset($content[$k]); $actionname = strtolower(request()->action());
$path = str_replace('.', '/', $controllername) . '/' . $actionname;
if (self::$ignoreRegex) {
foreach (self::$ignoreRegex as $index => $item) {
if (preg_match($item, $path)) {
return;
} }
} }
} }
$title = self::$title; $content = $content ?: self::$content;
if (!$content) {
$content = request()->param('') ?: file_get_contents("php://input");
$content = self::getPureContent($content);
}
$title = $title ?: self::$title;
if (!$title) { if (!$title) {
$title = []; $title = [];
$breadcrumb = Auth::instance()->getBreadcrumb(); $breadcrumb = Auth::instance()->getBreadcrumb($path);
foreach ($breadcrumb as $k => $v) { foreach ($breadcrumb as $k => $v) {
$title[] = $v['title']; $title[] = $v['title'];
} }
$title = implode(' ', $title); $title = implode(' / ', $title);
} }
self::create([ self::create([
'title' => $title, 'title' => $title,
'content' => !is_scalar($content) ? json_encode($content) : $content, 'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $content,
'url' => substr(request()->url(), 0, 1500), 'url' => substr(xss_clean(strip_tags(request()->url())), 0, 1500),
'admin_id' => $admin_id, 'admin_id' => $admin_id,
'username' => $username, 'username' => $username,
'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255), 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255),
'ip' => request()->ip() 'ip' => xss_clean(strip_tags(request()->ip()))
]); ]);
} }
/**
* 获取已屏蔽关键信息的数据
* @param $content
* @return array
*/
protected static function getPureContent($content)
{
if (!is_array($content)) {
return $content;
}
foreach ($content as $index => &$item) {
if (preg_match("/(password|salt|token)/i", $index)) {
$item = "***";
} else {
if (is_array($item)) {
$item = self::getPureContent($item);
}
}
}
return $content;
}
public function admin() public function admin()
{ {
return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0); return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0);

View File

@ -13,9 +13,22 @@ class AuthRule extends Model
// 定义时间戳字段名 // 定义时间戳字段名
protected $createTime = 'createtime'; protected $createTime = 'createtime';
protected $updateTime = 'updatetime'; protected $updateTime = 'updatetime';
// 数据自动完成字段
protected $insert = ['py', 'pinyin'];
protected $update = ['py', 'pinyin'];
// 拼音对象
protected static $pinyin = null;
protected static function init() protected static function init()
{ {
self::$pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader');
self::beforeWrite(function ($row) {
if (isset($_POST['row']) && is_array($_POST['row']) && isset($_POST['row']['condition'])) {
$originRow = $_POST['row'];
$row['condition'] = $originRow['condition'] ?? '';
}
});
self::afterWrite(function ($row) { self::afterWrite(function ($row) {
Cache::rm('__menu__'); Cache::rm('__menu__');
}); });
@ -26,4 +39,24 @@ class AuthRule extends Model
return __($value); return __($value);
} }
public function getMenutypeList()
{
return ['addtabs' => __('Addtabs'), 'dialog' => __('Dialog'), 'ajax' => __('Ajax'), 'blank' => __('Blank')];
}
public function setPyAttr($value, $data)
{
if (isset($data['title']) && $data['title']) {
return self::$pinyin->abbr(__($data['title']));
}
return '';
}
public function setPinyinAttr($value, $data)
{
if (isset($data['title']) && $data['title']) {
return self::$pinyin->permalink(__($data['title']), '');
}
return '';
}
} }

View File

@ -47,12 +47,11 @@ class User extends Model
self::beforeUpdate(function ($row) { self::beforeUpdate(function ($row) {
$changedata = $row->getChangedData(); $changedata = $row->getChangedData();
if (isset($changedata['money'])) { $origin = $row->getOriginData();
$origin = $row->getOriginData(); if (isset($changedata['money']) && (function_exists('bccomp') ? bccomp($changedata['money'], $origin['money'], 2) !== 0 : (double)$changedata['money'] !== (double)$origin['money'])) {
MoneyLog::create(['user_id' => $row['id'], 'money' => $changedata['money'] - $origin['money'], 'before' => $origin['money'], 'after' => $changedata['money'], 'memo' => '管理员变更金额']); MoneyLog::create(['user_id' => $row['id'], 'money' => $changedata['money'] - $origin['money'], 'before' => $origin['money'], 'after' => $changedata['money'], 'memo' => '管理员变更金额']);
} }
if (isset($changedata['score'])) { if (isset($changedata['score']) && (int)$changedata['score'] !== (int)$origin['score']) {
$origin = $row->getOriginData();
ScoreLog::create(['user_id' => $row['id'], 'score' => $changedata['score'] - $origin['score'], 'before' => $origin['score'], 'after' => $changedata['score'], 'memo' => '管理员变更积分']); ScoreLog::create(['user_id' => $row['id'], 'score' => $changedata['score'] - $origin['score'], 'before' => $origin['score'], 'after' => $changedata['score'], 'memo' => '管理员变更积分']);
} }
}); });
@ -68,21 +67,22 @@ class User extends Model
return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
} }
public function getPrevtimeTextAttr($value, $data) public function getPrevtimeTextAttr($value, $data)
{ {
$value = $value ? $value : $data['prevtime']; $value = $value ? $value : ($data['prevtime'] ?? "");
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;
} }
public function getLogintimeTextAttr($value, $data) public function getLogintimeTextAttr($value, $data)
{ {
$value = $value ? $value : $data['logintime']; $value = $value ? $value : ($data['logintime'] ?? "");
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;
} }
public function getJointimeTextAttr($value, $data) public function getJointimeTextAttr($value, $data)
{ {
$value = $value ? $value : $data['jointime']; $value = $value ? $value : ($data['jointime'] ?? "");
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;
} }
@ -101,6 +101,11 @@ class User extends Model
return $value && !is_numeric($value) ? strtotime($value) : $value; return $value && !is_numeric($value) ? strtotime($value) : $value;
} }
protected function setBirthdayAttr($value)
{
return $value ? $value : null;
}
public function group() public function group()
{ {
return $this->belongsTo('UserGroup', 'group_id', 'id', [], 'LEFT')->setEagerlyType(0); return $this->belongsTo('UserGroup', 'group_id', 'id', [], 'LEFT')->setEagerlyType(0);

View File

@ -28,7 +28,7 @@ class UserGroup extends Model
{ {
$value = $value ? $value : $data['status']; $value = $value ? $value : $data['status'];
$list = $this->getStatusList(); $list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : ''; return $list[$value] ?? '';
} }
} }

View File

@ -23,11 +23,18 @@ class UserRule extends Model
protected static function init() protected static function init()
{ {
self::afterInsert(function ($row) { self::afterInsert(function ($row) {
$pk = $row->getPk(); if (!$row['weigh']) {
$row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]); $pk = $row->getPk();
$row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]);
}
}); });
} }
public function getTitleAttr($value, $data)
{
return __($value);
}
public function getStatusList() public function getStatusList()
{ {
return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
@ -37,7 +44,7 @@ class UserRule extends Model
{ {
$value = $value ? $value : $data['status']; $value = $value ? $value : $data['status'];
$list = $this->getStatusList(); $list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : ''; return $list[$value] ?? '';
} }
public static function getTreeList($selected = []) public static function getTreeList($selected = [])

View File

@ -11,10 +11,11 @@ class Admin extends Validate
* 验证规则 * 验证规则
*/ */
protected $rule = [ protected $rule = [
'username' => 'require|regex:\w{3,12}|unique:admin', 'username' => 'require|regex:\w{3,30}|unique:admin',
'nickname' => 'require', 'nickname' => 'require',
'password' => 'require|regex:\S{32}', 'password' => 'require|regex:\S{32}',
'email' => 'require|email|unique:admin,email', 'email' => 'require|email|unique:admin,email',
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile',
]; ];
/** /**
@ -33,8 +34,8 @@ class Admin extends Validate
* 验证场景 * 验证场景
*/ */
protected $scene = [ protected $scene = [
'add' => ['username', 'email', 'nickname', 'password'], 'add' => ['username', 'email', 'nickname', 'password', 'mobile'],
'edit' => ['username', 'email', 'nickname', 'password'], 'edit' => ['username', 'email', 'nickname', 'password', 'mobile'],
]; ];
public function __construct(array $rules = [], $message = [], $field = []) public function __construct(array $rules = [], $message = [], $field = [])
@ -44,6 +45,7 @@ class Admin extends Validate
'nickname' => __('Nickname'), 'nickname' => __('Nickname'),
'password' => __('Password'), 'password' => __('Password'),
'email' => __('Email'), 'email' => __('Email'),
'mobile' => __('Mobile'),
]; ];
$this->message = array_merge($this->message, [ $this->message = array_merge($this->message, [
'username.regex' => __('Please input correct username'), 'username.regex' => __('Please input correct username'),

View File

@ -16,7 +16,7 @@ class AuthRule extends Validate
* 验证规则 * 验证规则
*/ */
protected $rule = [ protected $rule = [
'name' => 'require|format|unique:AuthRule', 'name' => 'require|unique:AuthRule',
'title' => 'require', 'title' => 'require',
]; ];

View File

@ -10,6 +10,17 @@ class User extends Validate
* 验证规则 * 验证规则
*/ */
protected $rule = [ protected $rule = [
'username' => 'require|regex:\w{3,30}|unique:user',
'nickname' => 'require|unique:user',
'password' => 'regex:\S{6,30}',
'email' => 'require|email|unique:user',
'mobile' => 'unique:user'
];
/**
* 字段描述
*/
protected $field = [
]; ];
/** /**
* 提示消息 * 提示消息
@ -21,7 +32,19 @@ class User extends Validate
*/ */
protected $scene = [ protected $scene = [
'add' => [], 'add' => [],
'edit' => [], 'edit' => ['username', 'nickname', 'password', 'email', 'mobile'],
]; ];
public function __construct(array $rules = [], $message = [], $field = [])
{
$this->field = [
'username' => __('Username'),
'nickname' => __('Nickname'),
'password' => __('Password'),
'email' => __('Email'),
'mobile' => __('Mobile')
];
parent::__construct($rules, $message, $field);
}
} }

View File

@ -1,108 +1,142 @@
<form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{if $addon.tips} {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}
<b>{$addon.tips.title}</b><br> <b>{$addon.tips.title}</b><br>
{/if}
{$addon.tips.value} {$addon.tips.value}
</div> </div>
{/if} {/if}
<table class="table table-striped">
<thead>
<tr>
<th width="15%">{:__('Title')}</th>
<th width="85%">{:__('Value')}</th>
</tr>
</thead>
<tbody>
{foreach $addon.config as $item}
<tr>
<td>{$item.title}</td>
<td>
<div class="row">
<div class="col-sm-8 col-xs-12">
{switch $item.type}
{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}"/>
{/case}
{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>
{/case}
{case array}
<dl class="fieldlist" data-name="row[{$item.name}]">
<dd>
<ins>{:__('Array key')}</ins>
<ins>{:__('Array value')}</ins>
</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>
</dl>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{case checkbox}
{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>
{/foreach}
{/case}
{case radio}
{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>
{/foreach}
{/case}
{case value="select" break="0"}{/case}
{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':''}>
{foreach name="item.content" item="vo"}
<option value="{$key}" {in name="key" value="$item.value" }selected{/in}>{$vo}</option>
{/foreach}
</select>
{/case}
{case value="image" break="0"}{/case}
{case value="images"}
<div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="35" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}">
<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="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>
<ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul>
</div>
{/case}
{case value="file" break="0"}{/case}
{case value="files"}
<div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="35" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}">
<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="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>
</div>
{/case}
{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}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label>
{/case}
{default /}{$item.value}
{/switch}
</div>
<div class="col-sm-4"></div>
</div>
</td> <div class="panel panel-default panel-intro">
</tr> {if count($groupList)>1}
{/foreach} <div class="panel-heading mb-3">
</tbody> <ul class="nav nav-tabs nav-group">
</table> <li class="active"><a href="#all" data-toggle="tab">全部</a></li>
<div class="form-group layer-footer"> {foreach name="groupList" id="tab"}
<label class="control-label col-xs-12 col-sm-2"></label> <li><a href="#tab-{$key}" title="{$tab}" data-toggle="tab">{$tab}</a></li>
<div class="col-xs-12 col-sm-8"> {/foreach}
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> </ul>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> </div>
{/if}
<div class="panel-body no-padding">
<div id="myTabContent" class="tab-content">
{foreach name="groupList" id="group" key="groupName"}
<div class="tab-pane fade active in" id="tab-{$groupName}">
<table class="table table-striped table-config mb-0">
<tbody>
{foreach name="$addon.config" id="item"}
{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}">
<td width="15%">{$item.title}</td>
<td>
<div class="row">
<div class="col-sm-8 col-xs-12">
{switch $item.type}
{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}"/>
{/case}
{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}"/>
{/case}
{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>
{/case}
{case array}
<dl class="fieldlist" data-name="row[{$item.name}]">
<dd>
<ins>{:__('Array key')}</ins>
<ins>{:__('Array value')}</ins>
</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>
</dl>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{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}"/>
{/case}
{case checkbox}
{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>
{/foreach}
<span class="msg-box n-right" for="row[{$item.name}]"></span>
{/case}
{case radio}
{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>
{/foreach}
<span class="msg-box n-right" for="row[{$item.name}]"></span>
{/case}
{case value="select" break="0"}{/case}
{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':''}>
{foreach name="item.content" item="vo"}
<option value="{$key}" {in name="key" value="$item.value" }selected{/in}>{$vo}</option>
{/foreach}
</select>
{/case}
{case value="image" break="0"}{/case}
{case value="images"}
<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}">
<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="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>
<ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul>
<span class="msg-box n-right" for="c-{$item.name}"></span>
</div>
{/case}
{case value="file" break="0"}{/case}
{case value="files"}
<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}">
<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="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 class="msg-box n-right" for="c-{$item.name}"></span>
</div>
{/case}
{case switch}
<input id="c-{$item.name}" name="row[{$item.name}]" 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">
<i class="fa fa-toggle-on text-success {if !$item.value}fa-flip-horizontal text-gray{/if} fa-2x"></i>
</a>
{/case}
{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}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label>
{/case}
{default /}{$item.value}
{/switch}
</div>
<div class="col-sm-4"></div>
</div>
</td>
</tr>
{/if}
{/foreach}
</tbody>
</table>
</div>
{/foreach}
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2" style="width:15%;"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</div>
</div> </div>
</div> </div>
</form> </form>

View File

@ -53,12 +53,19 @@
position: absolute; position: absolute;
box-shadow: 0px 0px 2px #f11414; box-shadow: 0px 0px 2px #f11414;
} }
.form-userinfo .breadcrumb { .form-userinfo .breadcrumb {
margin-bottom:10px; margin-bottom: 10px;
} }
.btn-toggle { .btn-toggle {
padding:0; padding: 0;
} }
.operate .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu {
bottom: inherit;
}
</style> </style>
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
<div class="panel-heading"> <div class="panel-heading">
@ -76,18 +83,18 @@
<div class="tab-pane fade active in" id="one"> <div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding"> <div class="widget-body no-padding">
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
{:build_toolbar('refresh')} <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" data-force-refresh="false"><i class="fa fa-refresh"></i> </a>
<button type="button" id="plupload-addon" class="btn btn-danger plupload" data-url="addon/local" data-mimetype="application/zip" data-multiple="false"><i class="fa fa-upload"></i>
{:__('Offline install')}
</button>
{if $Think.config.fastadmin.api_url} {if $Think.config.fastadmin.api_url}
<button type="button" id="faupload-addon" class="btn btn-danger faupload btn-mini-xs" data-url="addon/local" data-chunking="false" data-mimetype="zip,fastaddon" data-multiple="false"><i class="fa fa-upload"></i>
{:__('Local install')}
</button>
<div class="btn-group"> <div class="btn-group">
<a href="#" class="btn btn-info btn-switch active" data-type="all"><i class="fa fa-list"></i> {:__('All')}</a> <a href="#" class="btn btn-info btn-switch active btn-mini-xs" data-type="all"><i class="fa fa-list"></i> {:__('All')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="free"><i class="fa fa-gift"></i> {:__('Free')}</a> <a href="#" class="btn btn-info btn-switch btn-mini-xs" data-type="free"><i class="fa fa-gift"></i> {:__('Free')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="price"><i class="fa fa-rmb"></i> {:__('Paying')}</a> <a href="#" class="btn btn-info btn-switch btn-mini-xs" data-type="price"><i class="fa fa-rmb"></i> {:__('Paying')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="local" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a> <a href="#" class="btn btn-info btn-switch btn-mini-xs" data-type="local" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a>
</div> </div>
<a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a> <a class="btn btn-primary btn-userinfo btn-mini-xs" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a>
{/if} {/if}
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover" width="100%"> <table id="table" class="table table-striped table-bordered table-hover" width="100%">
@ -149,60 +156,20 @@
</div> </div>
</form> </form>
</script> </script>
<script id="logintpl" type="text/html"> <script id="uninstalltpl" type="text/html">
<div> <div class="">
<form class="form-horizontal"> <div class=""><%=#__("Are you sure you want to unstall %s?", addon['title'])%>
<fieldset> <p class="text-danger">{:__('Delete all the addon file and cannot be recovered!')} </p>
<div class="alert alert-dismissable alert-danger"> {if config('app_debug')}
<button type="button" class="close" data-dismiss="alert">×</button> <p class="text-danger"><input type="checkbox" name="droptables" id="droptables" data-name="<%=addon['name']%>"/> {:__('Delete all the addon database and cannot be recovered!')} </p>
<strong>{:__('Warning')}</strong><br/>{:__('Login tips')} {/if}
</div> <p class="text-danger">{:__('Please backup important data manually before uninstall!')}</p>
<div class="form-group"> </div>
<div class="col-lg-12">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<input type="text" class="form-control" id="inputAccount" value=""
placeholder="{:__('Your username or email')}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-12">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
<input type="password" class="form-control" id="inputPassword" value=""
placeholder="{:__('Your password')}">
</div>
</div>
</div>
</fieldset>
</form>
</div> </div>
</script> </script>
<script id="userinfotpl" type="text/html"> <script id="upgradetpl" type="text/html">
<div> <div class="">
<form class="form-horizontal form-userinfo"> <div class=""><%=#__("Upgrade tips", addon['title'])%></div>
<fieldset>
<div class="alert alert-dismissable alert-success">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{:__('Warning')}</strong><br/>{:__('Logined tips', '<%=username%>')}
</div>
</fieldset>
<div class="breadcrumb"><a href="https://www.fastadmin.net/user/myaddon.html" target="_blank"><i class="fa fa-money"></i> {:__('My addons')}</a></div>
<div class="breadcrumb"><a href="https://www.fastadmin.net/user/addon.html" target="_blank"><i class="fa fa-upload"></i> {:__('My posts')}</a></div>
</form>
</div>
</script>
<script id="paytpl" type="text/html">
<div class="payimg" style="background:url('<%=payimg%>') 0 0 no-repeat;background-size:cover;">
<%if(paycode){%>
<div class="alipaycode">
<%=paycode%>
</div>
<div class="wechatcode">
<%=paycode%>
</div>
<%}%>
</div> </div>
</script> </script>
<script id="conflicttpl" type="text/html"> <script id="conflicttpl" type="text/html">
@ -233,12 +200,12 @@
<% var label = labelarr[item.id % 5]; %> <% var label = labelarr[item.id % 5]; %>
<% var addon = item.addon; %> <% var addon = item.addon; %>
<div class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>"> <span class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>">
<% if(!addon){ %> <% if(!addon){ %>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%> <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<span class="btn-group"> <span class="btn-group">
<a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install" <a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install"
data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-type="<%=item.price<=0?'free':'price';%>"
data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a> data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a class="btn btn-xs btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;"> <a class="btn btn-xs btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
<span class="fa fa-caret-down"></span> <span class="fa fa-caret-down"></span>
@ -246,14 +213,13 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<% for(var j=0;j< item.releaselist.length;j++){ %> <% for(var j=0;j< item.releaselist.length;j++){ %>
<li><a href="javascript:;" class="btn-install" data-type="<%=item.price<=0?'free':'price';%>" <li><a href="javascript:;" class="btn-install" data-type="<%=item.price<=0?'free':'price';%>"
data-donateimage="<%=item.donateimage%>"
data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li> data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% } %> <% } %>
</ul> </ul>
</span> </span>
<% }else{%> <% }else if(typeof item.releaselist !="undefined" && item.releaselist.length>0){%>
<a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install" <a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install"
data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-type="<%=item.price<=0?'free':'price';%>"
data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a> data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<% } %> <% } %>
@ -262,6 +228,12 @@
<i class="fa fa-flash"></i> {:__('Demo')} <i class="fa fa-flash"></i> {:__('Demo')}
</a> </a>
<% } %> <% } %>
<% if(item.button){ %>
<a href="<%=item.url%>" class="btn btn-xs btn-primary btn-info" target="_blank">
<%=item.button%>
</a>
<% } %>
<% } else {%> <% } else {%>
<% if(addon.version!=item.version){%> <% if(addon.version!=item.version){%>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%> <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
@ -291,6 +263,6 @@
<a href="javascript:;" class="btn btn-xs btn-danger btn-uninstall" title="{:__('Uninstall')}"><i class="fa fa-times"></i> <a href="javascript:;" class="btn btn-xs btn-danger btn-uninstall" title="{:__('Uninstall')}"><i class="fa fa-times"></i>
{:__('Uninstall')}</a> {:__('Uninstall')}</a>
<% } %> <% } %>
</div> </span>
</script> </script>
<!--@formatter:on--> <!--@formatter:on-->

View File

@ -18,6 +18,12 @@
<input type="email" class="form-control" id="email" name="row[email]" value="" data-rule="required;email" /> <input type="email" class="form-control" id="email" name="row[email]" value="" data-rule="required;email" />
</div> </div>
</div> </div>
<div class="form-group">
<label for="mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="mobile" name="row[mobile]" value="" data-rule="mobile" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label> <label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -39,8 +45,8 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -18,6 +18,12 @@
<input type="email" class="form-control" id="email" name="row[email]" value="{$row.email|htmlentities}" data-rule="required;email" /> <input type="email" class="form-control" id="email" name="row[email]" value="{$row.email|htmlentities}" data-rule="required;email" />
</div> </div>
</div> </div>
<div class="form-group">
<label for="mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="mobile" name="row[mobile]" value="{$row.mobile|default=''|htmlentities}" data-rule="mobile" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label> <label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -33,7 +39,7 @@
<div class="form-group"> <div class="form-group">
<label for="loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label> <label for="loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="number" class="form-control" id="loginfailure" name="row[loginfailure]" value="{$row.loginfailure}" data-rule="required" /> <input type="number" class="form-control" id="loginfailure" name="row[loginfailure]" value="{$row.loginfailure|htmlentities}" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -45,8 +51,8 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -8,9 +8,9 @@
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
{:build_toolbar('refresh,add,delete')} {:build_toolbar('refresh,add,delete')}
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover" <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('auth/admin/edit')}" data-operate-edit="{:$auth->check('auth/admin/edit')}"
data-operate-del="{:$auth->check('auth/admin/del')}" data-operate-del="{:$auth->check('auth/admin/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>
@ -18,4 +18,4 @@
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,17 +1,22 @@
<table class="table table-striped"> <style>
.table-adminlog tr td {
word-break: break-all;
}
</style>
<table class="table table-striped table-adminlog">
<thead> <thead>
<tr> <tr>
<th>{:__('Title')}</th> <th width="100">{:__('Title')}</th>
<th>{:__('Content')}</th> <th>{:__('Content')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{volist name="row" id="vo" } {volist name="row" id="vo" }
<tr> <tr>
<td>{:__($key)}</td> <td>{:__($key)}</td>
<td>{if $key=='createtime'}{$vo|datetime}{else/}{$vo|htmlentities}{/if}</td> <td>{if $key=='createtime'}{$vo|datetime}{else/}{$vo|htmlentities}{/if}</td>
</tr> </tr>
{/volist} {/volist}
</tbody> </tbody>
</table> </table>
<div class="hide layer-footer"> <div class="hide layer-footer">

View File

@ -8,9 +8,9 @@
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
{:build_toolbar('refresh,delete')} {:build_toolbar('refresh,delete')}
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover" <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-detail="{:$auth->check('auth/adminlog/index')}" data-operate-detail="{:$auth->check('auth/adminlog/index')}"
data-operate-del="{:$auth->check('auth/adminlog/del')}" data-operate-del="{:$auth->check('auth/adminlog/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>
@ -18,4 +18,4 @@
</div> </div>
</div> </div>
</div> </div>

View File

@ -16,8 +16,8 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div> <div id="treeview"></div>
</div> </div>
@ -31,7 +31,7 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>

View File

@ -16,8 +16,8 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div> <div id="treeview"></div>
</div> </div>
@ -31,7 +31,7 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2 col-xs-2"></label> <label class="control-label col-xs-12 col-sm-2 col-xs-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>

View File

@ -8,9 +8,9 @@
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
{:build_toolbar('refresh,add,delete')} {:build_toolbar('refresh,add,delete')}
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover" <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('auth/group/edit')}" data-operate-edit="{:$auth->check('auth/group/edit')}"
data-operate-del="{:$auth->check('auth/group/del')}" data-operate-del="{:$auth->check('auth/group/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>

View File

@ -24,33 +24,52 @@
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" /> <input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="url" name="row[url]" value="" data-rule="" placeholder="{:__('Url tips')}" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label> <label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md"> <div class="input-group input-groupp-md">
<span class="input-group-addon"><i class="fa fa-circle-o" id="icon-style"></i></span>
<input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-circle-o" /> <input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-circle-o" />
<a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a> <a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label> <label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]"></textarea> <textarea class="form-control" id="condition" name="row[condition]"></textarea>
</div> </div>
</div> </div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Menutype')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[menutype]', $menutypeList)}
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Extend')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="extend" name="row[extend]"></textarea>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label> <label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]"></textarea> <textarea class="form-control" id="remark" name="row[remark]"></textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -60,9 +79,9 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<div class="col-xs-2"></div> <div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>
{include file="auth/rule/tpl" /} {include file="auth/rule/tpl" /}

View File

@ -24,31 +24,50 @@
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title|htmlentities}" data-rule="required" /> <input type="text" class="form-control" id="title" name="row[title]" value="{$row.title|htmlentities}" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="url" name="row[url]" value="{$row.url|htmlentities}" data-rule="" placeholder="{:__('Url tips')}" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label> <label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md"> <div class="input-group input-groupp-md">
<input type="text" class="form-control" id="icon" name="row[icon]" value="{$row.icon}" /> <span class="input-group-addon"><i class="{$row.icon|htmlentities}" id="icon-style"></i></span>
<input type="text" class="form-control" id="icon" name="row[icon]" value="{$row.icon|htmlentities}" />
<a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a> <a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label> <label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]">{$row.condition|htmlentities}</textarea> <textarea class="form-control" id="condition" name="row[condition]">{$row.condition|htmlentities}</textarea>
</div> </div>
</div> </div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Menutype')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[menutype]', $menutypeList, $row['menutype'])}
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Extend')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="extend" name="row[extend]">{$row.extend|htmlentities}</textarea>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label> <label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]">{$row.remark|htmlentities}</textarea> <textarea class="form-control" id="remark" name="row[remark]">{$row.remark|__|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh|htmlentities}" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -60,9 +79,9 @@
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<div class="col-xs-2"></div> <div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>
</form> </form>
{include file="auth/rule/tpl" /} {include file="auth/rule/tpl" /}

View File

@ -9,7 +9,7 @@
<div class="tab-pane fade active in" id="one"> <div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding"> <div class="widget-body no-padding">
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a> <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" data-force-refresh="false"><i class="fa fa-refresh"></i> </a>
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('auth/rule/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a> <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('auth/rule/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('auth/rule/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a> <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('auth/rule/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('auth/rule/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a> <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('auth/rule/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
@ -22,9 +22,9 @@
</div> </div>
<a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a> <a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a>
</div> </div>
<table id="table" class="table table-bordered table-hover" <table id="table" class="table table-bordered table-hover"
data-operate-edit="{:$auth->check('auth/rule/edit')}" data-operate-edit="{:$auth->check('auth/rule/edit')}"
data-operate-del="{:$auth->check('auth/rule/del')}" data-operate-del="{:$auth->check('auth/rule/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>

View File

@ -1,5 +1,5 @@
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{:token()}
<div class="alert alert-warning-light"> <div class="alert alert-warning-light">
{:__('Category warmtips')} {:__('Category warmtips')}
</div> </div>
@ -58,12 +58,12 @@
<div class="input-group"> <div class="input-group">
<input id="c-image" class="form-control" size="35" name="row[image]" type="text" value=""> <input id="c-image" class="form-control" size="35" name="row[image]" type="text" value="">
<div class="input-group-addon no-border no-padding"> <div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-image" class="btn btn-danger faupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div> </div>
<span class="msg-box n-right"></span> <span class="msg-box n-right"></span>
</div> </div>
<ul class="row list-inline plupload-preview" id="p-image"></ul> <ul class="row list-inline faupload-preview" id="p-image"></ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -93,7 +93,7 @@
<div class="form-group layer-footer"> <div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action=""> <form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{:token()}
<div class="form-group"> <div class="form-group">
<label for="c-type" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label> <label for="c-type" class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -52,14 +52,14 @@
<label for="c-image" class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label> <label for="c-image" class="control-label col-xs-12 col-sm-2">{:__('Image')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<div class="input-group"> <div class="input-group">
<input id="c-image" class="form-control" size="35" name="row[image]" type="text" value="{$row.image}"> <input id="c-image" class="form-control" size="35" name="row[image]" type="text" value="{$row.image|htmlentities}">
<div class="input-group-addon no-border no-padding"> <div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-image" class="btn btn-danger faupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div> </div>
<span class="msg-box n-right"></span> <span class="msg-box n-right"></span>
</div> </div>
<ul class="row list-inline plupload-preview" id="p-image"></ul> <ul class="row list-inline faupload-preview" id="p-image"></ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -77,7 +77,7 @@
<div class="form-group"> <div class="form-group">
<label for="c-weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> <label for="c-weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input id="c-weigh" class="form-control" name="row[weigh]" type="number" value="{$row.weigh}"> <input id="c-weigh" class="form-control" name="row[weigh]" type="number" value="{$row.weigh|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -89,7 +89,7 @@
<div class="form-group layer-footer"> <div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>

View File

@ -23,9 +23,9 @@
</ul> </ul>
</div> </div>
</div> </div>
<table id="table" class="table table-striped table-bordered table-hover" <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('category/edit')}" data-operate-edit="{:$auth->check('category/edit')}"
data-operate-del="{:$auth->check('category/del')}" data-operate-del="{:$auth->check('category/del')}"
width="100%"> width="100%">
</table> </table>
</div> </div>

View File

@ -5,6 +5,17 @@
.skin-list li a{ .skin-list li a{
display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4); display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4);
} }
.skin-list li a span{
display: block;
float:left;
}
.skin-list li.active a {
opacity: 1;
filter: alpha(opacity=100);
}
.skin-list li.active p {
color: #fff;
}
</style> </style>
<!-- Control Sidebar --> <!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark"> <aside class="control-sidebar control-sidebar-dark">
@ -19,28 +30,35 @@
<!-- Home tab content --> <!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-setting-tab"> <div class="tab-pane active" id="control-sidebar-setting-tab">
<h4 class="control-sidebar-heading">{:__('Layout Options')}</h4> <h4 class="control-sidebar-heading">{:__('Layout Options')}</h4>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="fixed" class="pull-right"> {:__('Fixed Layout')}</label><p>{:__("You can't use fixed and boxed layouts together")}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-config="multiplenav" {if $Think.config.fastadmin.multiplenav}checked{/if} class="pull-right"> {:__('Multiple Nav')}</label><p>{:__("Toggle the top menu state (multiple or single)")}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="layout-boxed" class="pull-right"> {:__('Boxed Layout')}</label><p>{:__('Activate the boxed layout')}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-config="multipletab" {if $Think.config.fastadmin.multipletab}checked{/if} class="pull-right"> {:__('Multiple Tab')}</label><p>{:__("Always show multiple tab when multiple nav is set")}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="sidebar-collapse" class="pull-right"> {:__('Toggle Sidebar')}</label><p>{:__("Toggle the left sidebar's state (open or collapse)")}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-layout="sidebar-collapse" class="pull-right"> {:__('Toggle Sidebar')}</label><p>{:__("Toggle the left sidebar's state (open or collapse)")}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-enable="expandOnHover" class="pull-right"> {:__('Sidebar Expand on Hover')}</label><p>{:__('Let the sidebar mini expand on hover')}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-enable="expandOnHover" class="pull-right"> {:__('Sidebar Expand on Hover')}</label><p>{:__('Let the sidebar mini expand on hover')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-menu="show-submenu" class="pull-right"> {:__('Show sub menu')}</label><p>{:__('Always show sub menu')}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-menu="show-submenu" class="pull-right"> {:__('Show sub menu')}</label><p>{:__('Always show sub menu')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-menu="disable-top-badge" class="pull-right"> {:__('Disable top menu badge')}</label><p>{:__('Disable top menu badge without left menu')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-controlsidebar="control-sidebar-open" class="pull-right"> {:__('Toggle Right Sidebar Slide')}</label><p>{:__('Toggle between slide over content and push content effects')}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-controlsidebar="control-sidebar-open" class="pull-right"> {:__('Toggle Right Sidebar Slide')}</label><p>{:__('Toggle between slide over content and push content effects')}</p></div>
<div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-sidebarskin="toggle" class="pull-right"> {:__('Toggle Right Sidebar Skin')}</label><p>{:__('Toggle between dark and light skins for the right sidebar')}</p></div> <div class="form-group"><label class="control-sidebar-subheading"><input type="checkbox" data-sidebarskin="toggle" class="pull-right"> {:__('Toggle Right Sidebar Skin')}</label><p>{:__('Toggle between dark and light skins for the right sidebar')}</p></div>
<h4 class="control-sidebar-heading">{:__('Skins')}</h4> <h4 class="control-sidebar-heading">{:__('Skins')}</h4>
<ul class="list-unstyled clearfix skin-list"> <ul class="list-unstyled clearfix skin-list">
<li><a href="javascript:;" data-skin="skin-blue" style="" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px; background: #367fa9;"></span><span class="bg-light-blue" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Blue</p></li> <li><a href="javascript:;" data-skin="skin-blue" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #4e73df;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Blue</p></li>
<li><a href="javascript:;" data-skin="skin-white" class="clearfix full-opacity-hover"><div style="box-shadow: 0 0 2px rgba(0,0,0,0.1)" class="clearfix"><span style="display:block; width: 20%; float: left; height: 7px; background: #fefefe;"></span><span style="display:block; width: 80%; float: left; height: 7px; background: #fefefe;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">White</p></li> <li><a href="javascript:;" data-skin="skin-black" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black</p></li>
<li><a href="javascript:;" data-skin="skin-purple" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-purple-active"></span><span class="bg-purple" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Purple</p></li> <li><a href="javascript:;" data-skin="skin-purple" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #605ca8;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Purple</p></li>
<li><a href="javascript:;" data-skin="skin-green" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Green</p></li> <li><a href="javascript:;" data-skin="skin-green" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Green</p></li>
<li><a href="javascript:;" data-skin="skin-red" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Red</p></li> <li><a href="javascript:;" data-skin="skin-red" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Red</p></li>
<li><a href="javascript:;" data-skin="skin-yellow" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #222d32;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Yellow</p></li> <li><a href="javascript:;" data-skin="skin-yellow" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Yellow</p></li>
<li><a href="javascript:;" data-skin="skin-blue-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px; background: #367fa9;"></span><span class="bg-light-blue" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Blue Light</p></li>
<li><a href="javascript:;" data-skin="skin-white-light" class="clearfix full-opacity-hover"><div style="box-shadow: 0 0 2px rgba(0,0,0,0.1)" class="clearfix"><span style="display:block; width: 20%; float: left; height: 7px; background: #fefefe;"></span><span style="display:block; width: 80%; float: left; height: 7px; background: #fefefe;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">White Light</p></li> <li><a href="javascript:;" data-skin="skin-blue-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #4e73df;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Blue Light</p></li>
<li><a href="javascript:;" data-skin="skin-purple-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-purple-active"></span><span class="bg-purple" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Purple Light</p></li> <li><a href="javascript:;" data-skin="skin-black-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #000;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Black Light</p></li>
<li><a href="javascript:;" data-skin="skin-green-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Green Light</p></li> <li><a href="javascript:;" data-skin="skin-purple-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #605ca8;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Purple Light</p></li>
<li><a href="javascript:;" data-skin="skin-red-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Red Light</p></li> <li><a href="javascript:;" data-skin="skin-green-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-green"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Green Light</p></li>
<li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="display:block; width: 20%; float: left; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="display:block; width: 80%; float: left; height: 7px;"></span></div><div><span style="display:block; width: 20%; float: left; height: 20px; background: #f9fafc;"></span><span style="display:block; width: 80%; float: left; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin" style="font-size: 12px;">Yellow Light</p></li> <li><a href="javascript:;" data-skin="skin-red-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-red"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Red Light</p></li>
<li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-yellow"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Yellow Light</p></li>
<li><a href="javascript:;" data-skin="skin-black-blue" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #4e73df;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Blue</p></li>
<li><a href="javascript:;" data-skin="skin-black-purple" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #605ca8;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Purple</p></li>
<li><a href="javascript:;" data-skin="skin-black-green" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-green"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Green</p></li>
<li><a href="javascript:;" data-skin="skin-black-red" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-red"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Red</p></li>
<li><a href="javascript:;" data-skin="skin-black-yellow" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-yellow"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Yellow</p></li>
<li><a href="javascript:;" data-skin="skin-black-pink" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #f5549f;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Pink</p></li>
</ul> </ul>
</div> </div>
<!-- /.tab-pane --> <!-- /.tab-pane -->
@ -56,4 +74,4 @@
<!-- /.tab-pane --> <!-- /.tab-pane -->
</div> </div>
</aside> </aside>
<!-- /.control-sidebar --> <!-- /.control-sidebar -->

View File

@ -3,7 +3,7 @@
<!-- 迷你模式下Logo的大小为50X50 --> <!-- 迷你模式下Logo的大小为50X50 -->
<span class="logo-mini">{$site.name|mb_substr=0,4,'utf-8'|mb_strtoupper='utf-8'|htmlentities}</span> <span class="logo-mini">{$site.name|mb_substr=0,4,'utf-8'|mb_strtoupper='utf-8'|htmlentities}</span>
<!-- 普通模式下Logo --> <!-- 普通模式下Logo -->
<span class="logo-lg"><b>{$site.name|mb_substr=0,4,'utf-8'|htmlentities}</b>{$site.name|mb_substr=4,null,'utf-8'|htmlentities}</span> <span class="logo-lg">{$site.name|htmlentities}</span>
</a> </a>
<!-- 顶部通栏样式 --> <!-- 顶部通栏样式 -->
@ -24,21 +24,24 @@
<div class="navbar-custom-menu"> <div class="navbar-custom-menu">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li> <li class="hidden-xs">
<a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i></a> <a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i> {:__('Home')}</a>
</li> </li>
<!-- 清除缓存 --> <!-- 清除缓存 -->
<li> <li class="hidden-xs">
<a href="javascript:;" data-toggle="dropdown" title="{:__('Wipe cache')}"> <a href="javascript:;" data-toggle="dropdown" title="{:__('Wipe cache')}">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i> {:__('Wipe cache')}
</a> </a>
<ul class="dropdown-menu wipecache"> <ul class="dropdown-menu wipecache">
<li><a href="javascript:;" data-type="all"><i class="fa fa-trash"></i> {:__('Wipe all cache')}</a></li> <li><a href="javascript:;" data-type="all"><i class="fa fa-trash fa-fw"></i> {:__('Wipe all cache')}</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="javascript:;" data-type="content"><i class="fa fa-file-text"></i> {:__('Wipe content cache')}</a></li> <li><a href="javascript:;" data-type="content"><i class="fa fa-file-text fa-fw"></i> {:__('Wipe content cache')}</a></li>
<li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o"></i> {:__('Wipe template cache')}</a></li> <li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o fa-fw"></i> {:__('Wipe template cache')}</a></li>
<li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket"></i> {:__('Wipe addons cache')}</a></li> <li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket fa-fw"></i> {:__('Wipe addons cache')}</a></li>
<li><a href="javascript:;" data-type="browser"><i class="fa fa-chrome fa-fw"></i> {:__('Wipe browser cache')}
<span data-toggle="tooltip" data-title="{:__('Wipe browser cache tips')}"><i class="fa fa-info-circle"></i></span>
</a></li>
</ul> </ul>
</li> </li>
@ -65,7 +68,7 @@
<!-- 账号信息下拉框 --> <!-- 账号信息下拉框 -->
<li class="dropdown user user-menu"> <li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{$admin.avatar|cdnurl|htmlentities}" class="user-image" alt="{$admin.nickname|htmlentities}"> <img src="{$admin.avatar|cdnurl|htmlentities}" class="user-image" alt="">
<span class="hidden-xs">{$admin.nickname|htmlentities}</span> <span class="hidden-xs">{$admin.nickname|htmlentities}</span>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@ -78,6 +81,16 @@
<small>{$admin.logintime|date="Y-m-d H:i:s",###}</small> <small>{$admin.logintime|date="Y-m-d H:i:s",###}</small>
</p> </p>
</li> </li>
<li class="user-body">
<div class="visible-xs">
<div class="pull-left">
<a href="__PUBLIC__" target="_blank"><i class="fa fa-home" style="font-size:14px;"></i> {:__('Home')}</a>
</div>
<div class="pull-right">
<a href="javascript:;" data-type="all" class="wipecache"><i class="fa fa-trash fa-fw"></i> {:__('Wipe all cache')}</a>
</div>
</div>
</li>
<!-- Menu Footer--> <!-- Menu Footer-->
<li class="user-footer"> <li class="user-footer">
<div class="pull-left"> <div class="pull-left">
@ -112,4 +125,4 @@
</ul> </ul>
</div> </div>
{/if} {/if}
</nav> </nav>

View File

@ -29,11 +29,11 @@
</div> </div>
<!--如果想始终显示子菜单,则给ul加上show-submenu类即可,当multiplenav开启的情况下默认为展开--> <!-- 左侧菜单栏 -->
<ul class="sidebar-menu {if $Think.config.fastadmin.multiplenav}show-submenu{/if}"> <ul class="sidebar-menu {if $Think.config.fastadmin.show_submenu}show-submenu{/if}">
<!-- 菜单可以在 后台管理->权限管理->菜单规则 中进行增删改排序 --> <!-- 菜单可以在 后台管理->权限管理->菜单规则 中进行增删改排序 -->
{$menulist} {$menulist}
</ul> </ul>
</section> </section>

View File

@ -2,11 +2,17 @@
<title>{$title|default=''}</title> <title>{$title|default=''}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<meta name="referrer" content="never">
<meta name="robots" content="noindex, nofollow">
<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}" rel="stylesheet">
{if $Think.config.fastadmin.adminskin}
<link href="__CDN__/assets/css/skins/{$Think.config.fastadmin.adminskin}.css?v={$Think.config.site.version}" rel="stylesheet">
{/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. -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="__CDN__/assets/js/html5shiv.js"></script> <script src="__CDN__/assets/js/html5shiv.js"></script>
@ -16,4 +22,4 @@
var require = { var require = {
config: {$config|json_encode} config: {$config|json_encode}
}; };
</script> </script>

View File

@ -6,8 +6,6 @@
-moz-border-radius: 3px; -moz-border-radius: 3px;
border-radius: 3px; border-radius: 3px;
margin-bottom: 20px; margin-bottom: 20px;
-webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.05);
} }
.sm-st-icon { .sm-st-icon {
@ -27,7 +25,6 @@
} }
.sm-st-info { .sm-st-info {
font-size: 12px;
padding-top: 2px; padding-top: 2px;
} }
@ -112,7 +109,6 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: inline-block; display: inline-block;
margin-right: 10px;
} }
.stat .value { .stat .value {
@ -126,6 +122,7 @@
.stat .name { .stat .name {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin: 5px 0;
} }
.stat.lg .value { .stat.lg .value {
@ -133,6 +130,9 @@
line-height: 28px; line-height: 28px;
} }
.stat-col {
margin:0 0 10px 0;
}
.stat.lg .name { .stat.lg .name {
font-size: 16px; font-size: 16px;
} }
@ -149,6 +149,15 @@
.item { .item {
padding: 30px 0; padding: 30px 0;
} }
#statistics .panel {
min-height: 150px;
}
#statistics .panel h5 {
font-size: 14px;
}
</style> </style>
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
<div class="panel-heading"> <div class="panel-heading">
@ -174,28 +183,28 @@
</div> </div>
<div class="col-sm-3 col-xs-6"> <div class="col-sm-3 col-xs-6">
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-violet"><i class="fa fa-book"></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>{$totalviews}</span> <span>{$totaladdon}</span>
{:__('Total view')} {:__('Total addon')}
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-3 col-xs-6"> <div class="col-sm-3 col-xs-6">
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-blue"><i class="fa fa-shopping-bag"></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>{$totalorder}</span> <span>{$attachmentnums}</span>
{:__('Total order')} {:__('Total attachment')}
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-3 col-xs-6"> <div class="col-sm-3 col-xs-6">
<div class="sm-st clearfix"> <div class="sm-st clearfix">
<span class="sm-st-icon st-green"><i class="fa fa-cny"></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>{$totalorderamount}</span> <span>{$totaladmin}</span>
{:__('Total order amount')} {:__('Total admin')}
</div> </div>
</div> </div>
</div> </div>
@ -203,7 +212,7 @@
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-lg-8">
<div id="echart" class="btn-refresh" style="height:200px;width:100%;"></div> <div id="echart" class="btn-refresh" style="height:300px;width:100%;"></div>
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card sameheight-item stats"> <div class="card sameheight-item stats">
@ -216,57 +225,57 @@
<div class="name"> {:__('Today user signup')}</div> <div class="name"> {:__('Today user signup')}</div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success" style="width: 30%"></div> <div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div> </div>
</div> </div>
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-shopping-cart"></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}</div>
<div class="name"> {:__('Today user login')}</div> <div class="name"> {:__('Today user login')}</div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success" style="width: 25%"></div> <div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div> </div>
</div> </div>
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-line-chart"></i></div> <div class="stat-icon"><i class="fa fa-calendar"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$todayorder}</div> <div class="value"> {$threednu}</div>
<div class="name"> {:__('Today order')}</div> <div class="name"> {:__('Three dnu')}</div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success" style="width: 25%"></div> <div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div> </div>
</div> </div>
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-users"></i></div> <div class="stat-icon"><i class="fa fa-calendar-plus-o"></i></div>
<div class="stat">
<div class="value"> {$unsettleorder}</div>
<div class="name"> {:__('Unsettle order')}</div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 25%"></div>
</div>
</div>
<div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-list-alt"></i></div>
<div class="stat"> <div class="stat">
<div class="value"> {$sevendnu}</div> <div class="value"> {$sevendnu}</div>
<div class="name"> {:__('Seven dnu')}</div> <div class="name"> {:__('Seven dnu')}</div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success" style="width: 25%"></div> <div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div> </div>
</div> </div>
<div class="col-xs-6 stat-col"> <div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-dollar"></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}</div>
<div class="name"> {:__('Seven dau')}</div> <div class="name"> {:__('Seven dau')}</div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-success" style="width: 25%"></div> <div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div>
</div>
<div class="col-xs-6 stat-col">
<div class="stat-icon"><i class="fa fa-user-circle-o"></i></div>
<div class="stat">
<div class="value"> {$thirtydau}</div>
<div class="name"> {:__('Thirty dau')}</div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
</div> </div>
</div> </div>
</div> </div>
@ -275,61 +284,23 @@
</div> </div>
</div> </div>
<div class="row" style="margin-top:15px;"> <div class="row" style="margin-top:15px;" id="statistics">
<div class="col-lg-12"> <div class="col-lg-12">
</div> </div>
<div class="col-xs-6 col-md-3"> <div class="col-xs-6 col-md-3">
<div class="panel bg-blue"> <div class="panel bg-blue-gradient no-border">
<div class="panel-body"> <div class="panel-body">
<div class="panel-title"> <div class="panel-title">
<span class="label label-success pull-right">{:__('Real time')}</span> <span class="label label-primary pull-right">{:__('Real time')}</span>
<h5>{:__('Category count')}</h5> <h5>{:__('Working addon count')}</h5>
</div> </div>
<div class="panel-content"> <div class="panel-content">
<h1 class="no-margins">1234</h1>
<div class="stat-percent font-bold text-gray"><i class="fa fa-commenting"></i> 1234</div>
<small>{:__('Category count tips')}</small>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-md-3">
<div class="panel bg-aqua-gradient">
<div class="panel-body">
<div class="ibox-title">
<span class="label label-info pull-right">{:__('Real time')}</span>
<h5>{:__('Attachment count')}</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins">1043</h1>
<div class="stat-percent font-bold text-gray"><i class="fa fa-modx"></i> 2592</div>
<small>{:__('Attachment count tips')}</small>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-md-3">
<div class="panel bg-purple-gradient">
<div class="panel-body">
<div class="ibox-title">
<span class="label label-primary pull-right">{:__('Real time')}</span>
<h5>{:__('Article count')}</h5>
</div>
<div class="ibox-content">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-12">
<h1 class="no-margins">1234</h1> <h1 class="no-margins">{$totalworkingaddon}</h1>
<div class="font-bold"><i class="fa fa-commenting"></i> <div class="font-bold"><i class="fa fa-magic"></i>
<small>{:__('Comment count')}</small> <small>{:__('Working addon count tips')}</small>
</div>
</div>
<div class="col-md-6">
<h1 class="no-margins">6754</h1>
<div class="font-bold"><i class="fa fa-heart"></i>
<small>{:__('Like count')}</small>
</div> </div>
</div> </div>
</div> </div>
@ -338,25 +309,79 @@
</div> </div>
</div> </div>
<div class="col-xs-6 col-md-3"> <div class="col-xs-6 col-md-3">
<div class="panel bg-green-gradient"> <div class="panel bg-teal-gradient no-border">
<div class="panel-body"> <div class="panel-body">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary pull-right">{:__('Real time')}</span> <span class="label label-primary pull-right">{:__('Real time')}</span>
<h5>{:__('News count')}</h5> <h5>{:__('Database count')}</h5>
</div>
<div class="ibox-content">
<div class="row">
<div class="col-md-6">
<h1 class="no-margins">{$dbtablenums}</h1>
<div class="font-bold"><i class="fa fa-database"></i>
<small>{:__('Database table nums')}</small>
</div>
</div>
<div class="col-md-6">
<h1 class="no-margins">{$dbsize|format_bytes=###,'',0}</h1>
<div class="font-bold"><i class="fa fa-filter"></i>
<small>{:__('Database size')}</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-md-3">
<div class="panel bg-purple-gradient no-border">
<div class="panel-body">
<div class="ibox-title">
<span class="label label-primary pull-right">{:__('Real time')}</span>
<h5>{:__('Attachment count')}</h5>
</div> </div>
<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">5302</h1> <h1 class="no-margins">{$attachmentnums}</h1>
<div class="font-bold"><i class="fa fa-commenting"></i> <div class="font-bold"><i class="fa fa-files-o"></i>
<small>{:__('Comment count')}</small> <small>{:__('Attachment nums')}</small>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<h1 class="no-margins">8205</h1> <h1 class="no-margins">{$attachmentsize|format_bytes=###,'',0}</h1>
<div class="font-bold"><i class="fa fa-user"></i> <div class="font-bold"><i class="fa fa-filter"></i>
<small>{:__('Like count')}</small> <small>{:__('Attachment size')}</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-md-3">
<div class="panel bg-green-gradient no-border">
<div class="panel-body">
<div class="ibox-title">
<span class="label label-primary pull-right">{:__('Real time')}</span>
<h5>{:__('Picture count')}</h5>
</div>
<div class="ibox-content">
<div class="row">
<div class="col-md-6">
<h1 class="no-margins">{$picturenums}</h1>
<div class="font-bold"><i class="fa fa-picture-o"></i>
<small>{:__('Picture nums')}</small>
</div>
</div>
<div class="col-md-6">
<h1 class="no-margins">{$picturesize|format_bytes=###,'',0}</h1>
<div class="font-bold"><i class="fa fa-filter"></i>
<small>{:__('Picture size')}</small>
</div> </div>
</div> </div>
</div> </div>
@ -376,10 +401,3 @@
</div> </div>
</div> </div>
</div> </div>
<script>
var Orderdata = {
column: {:json_encode(array_keys($paylist))},
paydata: {:json_encode(array_values($paylist))},
createdata: {:json_encode(array_values($createlist))},
};
</script>

View File

@ -1,40 +1,58 @@
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
{if $config.upload.cdnurl} {if $config.upload.cdnurl}
<div class="form-group"> <div class="form-group">
<label for="c-third" class="control-label col-xs-12 col-sm-2">{:__('Upload')}:</label> <label for="c-third" class="control-label col-xs-12 col-sm-2">{:__('Upload to third')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" name="row[third]" id="c-third" class="form-control" /> <input type="text" name="row[third]" id="c-third" class="form-control"/>
<ul class="row list-inline faupload-preview" id="p-third"></ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-third" class="control-label col-xs-12 col-sm-2"></label> <label for="c-third" class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button id="plupload-third" class="btn btn-danger plupload" data-multiple="true" data-input-id="c-third" ><i class="fa fa-upload"></i> {:__("Upload to third")}</button> <div style="width:180px;display:inline-block;">
<select name="category-third" id="category-third" class="form-control selectpicker">
<option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"}
<option value="{$key}">{$item}</option>
{/foreach}
</select>
</div>
<button type="button" id="faupload-third" class="btn btn-danger faupload" data-multiple="true" data-input-id="c-third" data-preview-id="p-third"><i class="fa fa-upload"></i> {:__("Upload to third")}</button>
{if $config.upload.chunking}
<button type="button" id="faupload-third-chunking" class="btn btn-danger faupload" data-chunking="true" data-maxsize="1gb" data-multiple="true" data-input-id="c-third" data-preview-id="p-third"><i class="fa fa-upload"></i> {:__("Upload to third by chunk")}</button>
{/if}
</div> </div>
</div> </div>
{/if} {/if}
<div class="form-group"> <div class="form-group">
<label for="c-local" class="control-label col-xs-12 col-sm-2">{:__('Upload')}:</label> <label for="c-local" class="control-label col-xs-12 col-sm-2">{:__('Upload to local')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" name="row[local]" id="c-local" class="form-control" /> <input type="text" name="row[local]" id="c-local" class="form-control"/>
<ul class="row list-inline faupload-preview" id="p-local"></ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-local" class="control-label col-xs-12 col-sm-2"></label> <label for="c-local" class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button id="plupload-local" class="btn btn-primary plupload" data-input-id="c-local" data-url="{:url('ajax/upload')}"><i class="fa fa-upload"></i> {:__("Upload to local")}</button> <div style="width:180px;display:inline-block;">
<select name="category-local" id="category-local" class="form-control selectpicker">
<option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"}
<option value="{$key}">{$item}</option>
{/foreach}
</select>
</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>
{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>
{/if}
</div> </div>
</div> </div>
<div class="form-group">
<label for="c-editor" class="control-label col-xs-12 col-sm-2">{:__('Upload from editor')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea name="row[editor]" id="c-editor" cols="60" rows="5" class="form-control editor"></textarea>
</div>
</div>
<div class="form-group hidden layer-footer"> <div class="form-group hidden layer-footer">
<div class="col-xs-2"></div> <div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">

View File

@ -1,5 +1,18 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="c-url" class="control-label col-xs-12 col-sm-2">{:__('Category')}:</label>
<div class="col-xs-12 col-sm-8">
<select name="row[category]" class="form-control">
<option value="">{:__('Please select category')}</option>
{foreach name="categoryList" id="item"}
<option value="{$key}" {if $key==$row.category}selected{/if}>{$item}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="c-url" class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label> <label for="c-url" class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -9,13 +22,13 @@
<div class="form-group"> <div class="form-group">
<label for="c-imagewidth" class="control-label col-xs-12 col-sm-2">{:__('Imagewidth')}:</label> <label for="c-imagewidth" class="control-label col-xs-12 col-sm-2">{:__('Imagewidth')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" name="row[imagewidth]" value="{$row.imagewidth}" id="c-imagewidth" class="form-control" required /> <input type="text" name="row[imagewidth]" value="{$row.imagewidth|htmlentities}" id="c-imagewidth" class="form-control" required />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-imageheight" class="control-label col-xs-12 col-sm-2">{:__('Imageheight')}:</label> <label for="c-imageheight" class="control-label col-xs-12 col-sm-2">{:__('Imageheight')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" name="row[imageheight]" value="{$row.imageheight}" id="c-imageheight" class="form-control" required /> <input type="text" name="row[imageheight]" value="{$row.imageheight|htmlentities}" id="c-imageheight" class="form-control" required />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -27,13 +40,19 @@
<div class="form-group"> <div class="form-group">
<label for="c-imageframes" class="control-label col-xs-12 col-sm-2">{:__('Imageframes')}:</label> <label for="c-imageframes" class="control-label col-xs-12 col-sm-2">{:__('Imageframes')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="number" name="row[imageframes]" value="{$row.imageframes}" id="c-imageframes" class="form-control" /> <input type="number" name="row[imageframes]" value="{$row.imageframes|htmlentities}" id="c-imageframes" class="form-control" />
</div>
</div>
<div class="form-group">
<label for="c-filename" class="control-label col-xs-12 col-sm-2">{:__('Filename')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" name="row[filename]" value="{$row.filename|htmlentities}" id="c-filename" class="form-control" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-filesize" class="control-label col-xs-12 col-sm-2">{:__('Filesize')}:</label> <label for="c-filesize" class="control-label col-xs-12 col-sm-2">{:__('Filesize')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="number" name="row[filesize]" value="{$row.filesize}" id="c-filesize" class="form-control" /> <input type="number" name="row[filesize]" value="{$row.filesize|htmlentities}" id="c-filesize" class="form-control" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -57,13 +76,13 @@
<div class="form-group"> <div class="form-group">
<label for="c-storage" class="control-label col-xs-12 col-sm-2">{:__('Storage')}:</label> <label for="c-storage" class="control-label col-xs-12 col-sm-2">{:__('Storage')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" name="row[storage]" value="{$row.storage}" id="c-storage" class="form-control" /> <input type="text" name="row[storage]" value="{$row.storage|htmlentities}" id="c-storage" class="form-control" />
</div> </div>
</div> </div>
<div class="form-group hide layer-footer"> <div class="form-group hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label> <label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button> <button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button> <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div> </div>
</div> </div>

Some files were not shown because too many files have changed in this diff Show More